From 4eaee734898f1ceb5787e1d07351334268fba791 Mon Sep 17 00:00:00 2001 From: Uncle Jam Date: Tue, 3 Apr 2018 22:57:54 -0500 Subject: [PATCH 0001/1653] Add draft Identity classes - Sign private key allows identity updates - Encryption private key allows decrypting secret and messages --- src/Makefile.am | 2 + src/identity.cpp | 47 ++++++++++++++ src/identity.h | 152 ++++++++++++++++++++++++++++++++++++++++++++ src/script/script.h | 105 ++++++++++++++++++++++-------- 4 files changed, 280 insertions(+), 26 deletions(-) create mode 100644 src/identity.cpp create mode 100644 src/identity.h diff --git a/src/Makefile.am b/src/Makefile.am index bc5fde7a37..c5d9dc7544 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -117,6 +117,7 @@ DYNAMIC_CORE_H = \ hdchain.h \ httprpc.h \ httpserver.h \ + identity.h \ indirectmap.h \ init.h \ instantsend.h \ @@ -233,6 +234,7 @@ libdynamic_server_a_SOURCES = \ governance-votedb.cpp \ httprpc.cpp \ httpserver.cpp \ + identity.cpp \ init.cpp \ instantsend.cpp \ merkleblock.cpp \ diff --git a/src/identity.cpp b/src/identity.cpp new file mode 100644 index 0000000000..5d848b64ca --- /dev/null +++ b/src/identity.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "identity.h" + +#include "fluid.h" +#include "validation.h" + +CIdentityDB *pIdentityDB = NULL; + +bool IsIdentityTransaction(CScript txOut) { + return (txOut.IsIdentityScript(IDENTITY_NEW_TX) + || txOut.IsIdentityScript(IDENTITY_UPDATE_TX) + || txOut.IsIdentityScript(IDENTITY_DELETE_TX) + || txOut.IsIdentityScript(IDENTITY_ACTIVATE_TX) + ); +} + +bool GetIdentityTransaction(int nHeight, const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams) +{ + if(nHeight < 0 || nHeight > chainActive.Height()) + return false; + CBlockIndex *pindexSlow = NULL; + LOCK(cs_main); + pindexSlow = chainActive[nHeight]; + if (pindexSlow) { + CBlock block; + if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { + BOOST_FOREACH(const CTransaction &tx, block.vtx) { + if (tx.GetHash() == hash) { + txOut = tx; + return true; + } + } + } + } + return false; +} + +/* +std::vector>> CIdentityParameters::InitialiseCoreIdentities() +{ + + +} +*/ \ No newline at end of file diff --git a/src/identity.h b/src/identity.h new file mode 100644 index 0000000000..789ac5f79d --- /dev/null +++ b/src/identity.h @@ -0,0 +1,152 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef IDENTITY_H +#define IDENTITY_H + +#include "consensus/params.h" +#include "dbwrapper.h" +#include "script/script.h" +#include "serialize.h" +#include "sync.h" + +class CTransaction; +class CDynamicAddress; + +static const unsigned int ACTIVATE_IDENTITY_HEIGHT = 10; +static const unsigned int MAX_IDENTITY_NAME_SIZE = 64; +static const unsigned int MAX_IDENTITY_DOMAIN_SIZE = 24; +static const unsigned int MAX_IDENTITY_UNIQUE_ID_SIZE = 72; +static const unsigned int MAX_PUBLIC_VALUE_LENGTH = 512; +static const unsigned int MAX_SECRET_VALUE_LENGTH = 512; +static const std::string DEFAULT_IDENTITY_DOMAIN = "core"; + +/** Configure Identity Framework */ +class CIdentityParameters { +public: + std::vector>> InitialiseCoreIdentities(); +}; + +class CIdentity { +public: + std::vector vchIdentityName; + std::vector vchIdentityDomain; + std::vector vchUniqueID; + + std::vector vchWalletAddress; + std::vector vchEncryptPublicKey; + std::vector vchEncryptPrivateKey; + std::vector vchSignPublicKey; + std::vector vchSignPrivateKey; + + uint256 txHash; + + unsigned int nHeight; + uint64_t nExpireTime; + + std::vector vchPublicData; + std::vector vchSecretData; + + CIdentity() { + SetNull(); + } + + CIdentity(const CTransaction &tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + vchIdentityName.clear(); + vchIdentityDomain.clear(); + vchUniqueID.clear(); + vchWalletAddress.clear(); + vchEncryptPublicKey.clear(); + vchEncryptPrivateKey.clear(); + vchSignPublicKey.clear(); + vchSignPrivateKey.clear(); + txHash.SetNull(); + nHeight = 0; + nExpireTime = 0; + vchPublicData.clear(); + vchSecretData.clear(); + } + + ADD_SERIALIZE_METHODS; + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(vchIdentityName); + READWRITE(vchIdentityDomain); + READWRITE(vchUniqueID); + READWRITE(vchWalletAddress); + READWRITE(vchEncryptPublicKey); + READWRITE(vchEncryptPrivateKey); + READWRITE(vchSignPublicKey); + READWRITE(vchSignPrivateKey); + READWRITE(txHash); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(vchPublicData); + READWRITE(vchSecretData); + } + + inline friend bool operator==(const CIdentity &a, const CIdentity &b) { + return (a.vchIdentityName == b.vchIdentityName && a.vchIdentityDomain == b.vchIdentityDomain && a.vchUniqueID == b.vchUniqueID); + } + + inline friend bool operator!=(const CIdentity &a, const CIdentity &b) { + return !(a == b); + } + + inline CIdentity operator=(const CIdentity &b) { + vchIdentityName = b.vchIdentityName; + vchIdentityDomain = b.vchIdentityDomain; + vchUniqueID = b.vchUniqueID; + vchWalletAddress = b.vchWalletAddress; + vchEncryptPublicKey = b.vchEncryptPublicKey; + vchEncryptPrivateKey = b.vchEncryptPrivateKey; + vchSignPublicKey = b.vchSignPublicKey; + vchSignPrivateKey = b.vchSignPrivateKey; + txHash = b.txHash; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + vchPublicData = b.vchPublicData; + vchSecretData = b.vchSecretData; + return *this; + } + + inline bool IsNull() const { return (vchIdentityName.empty()); } + bool UnserializeFromTx(const CTransaction &tx); + bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); + void Serialize(std::vector& vchData); + + CDynamicAddress WalletAddress(); +}; + +class CIdentityDB : public CDBWrapper { +public: + CIdentityDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "identities", nCacheSize, fMemory, fWipe) { + } + + bool ReadIdentity(); + + bool AddIdentity(); + + bool UpdateIdentity(); + + bool ExpireIdentity(); + + bool IdentityExists(); + + bool CleanupDatabase(); + + void WriteIdentityIndex(const CIdentity& identity, const int &op); + void WriteIdentityIndexHistory(const CIdentity& identity, const int &op); +}; + +extern CIdentityDB *pIdentityDB; + + +#endif // IDENTITY_H diff --git a/src/script/script.h b/src/script/script.h index 6203d20bae..0f4c524032 100755 --- a/src/script/script.h +++ b/src/script/script.h @@ -23,11 +23,18 @@ // Identification codes for Fluid Protocol Transactions enum ProtocolCodes { - MINT_TX = 1, - DYNODE_MODFIY_TX = 2, - MINING_MODIFY_TX = 3, - - NO_TX = 0 + MINT_TX = 1, + DYNODE_MODFIY_TX = 2, + MINING_MODIFY_TX = 3, + IDENTITY_NEW_TX = 4, + IDENTITY_UPDATE_TX = 5, + IDENTITY_DELETE_TX = 6, + IDENTITY_ACTIVATE_TX = 7, + CERTIFICATE_NEW_TX = 8, + CERTIFICATE_UPDATE_TX = 9, + CERTIFICATE_DELETE_TX = 10, + CERTIFICATE_ACTIVATE_TX = 11, + NO_TX = 0 }; // Maximum number of bytes pushable to the stack @@ -195,23 +202,27 @@ enum opcodetype OP_PUBKEYHASH = 0xfd, OP_PUBKEY = 0xfe, - // Fluid Autonomus Monetary Management System (FAM2S) + // Fluid Autonomus Monetary Management System (FAM2S) OP_MINT = 0xc0, - OP_REWARD_DYNODE = 0xc3, - OP_REWARD_MINING = 0xc4, + OP_REWARD_DYNODE = 0xc3, + OP_REWARD_MINING = 0xc4, OP_SWAP_SOVEREIGN_ADDRESS = 0xc5, OP_UPDATE_FEES = 0xc6, OP_FREEZE_ADDRESS = 0xc7, OP_RELEASE_ADDRESS = 0xc8, - // identity alias system + // identity and certificate system OP_IDENTITY_NEW = 0xd1, OP_IDENTITY_DELETE = 0xd2, OP_IDENTITY_PAYMENT = 0xd3, OP_IDENTITY_ACTIVATE = 0xd4, OP_IDENTITY_UPDATE = 0xd5, OP_IDENTITY_MULTISIG = 0xd6, - + OP_CERTIFICATE_NEW = 0xd7, + OP_CERTIFICATE_UPDATE = 0xd8, + OP_CERTIFICATE_DELETE = 0xd9, + OP_CERTIFICATE_ACTIVATE = 0xda, + OP_CERTIFICATE_MULTISIG = 0xdb, // dynamic extended reserved OP_DYNAMIC_EXTENDED = 0x10, @@ -670,22 +681,64 @@ class CScript : public CScriptBase return (size() > 0 && *begin() == OP_RETURN) || (size() > MAX_SCRIPT_SIZE); } - bool IsProtocolInstruction(ProtocolCodes code) const - { - switch(code) { - case MINT_TX: - return (size() > 0 && *begin() == OP_MINT); - break; - case DYNODE_MODFIY_TX: - return (size() > 0 && *begin() == OP_REWARD_DYNODE); - break; - case MINING_MODIFY_TX: - return (size() > 0 && *begin() == OP_REWARD_MINING); - break; - default: - throw std::runtime_error("Protocol code is invalid!"); - } - return false; + bool IsProtocolInstruction(ProtocolCodes code) const + { + switch(code) { + case MINT_TX: + return (size() > 0 && *begin() == OP_MINT); + break; + case DYNODE_MODFIY_TX: + return (size() > 0 && *begin() == OP_REWARD_DYNODE); + break; + case MINING_MODIFY_TX: + return (size() > 0 && *begin() == OP_REWARD_MINING); + break; + default: + throw std::runtime_error("Protocol code is invalid!"); + } + return false; + } + + bool IsIdentityScript(ProtocolCodes code) const + { + switch(code) { + case IDENTITY_NEW_TX: + return (size() > 0 && *begin() == OP_IDENTITY_NEW); + break; + case IDENTITY_UPDATE_TX: + return (size() > 0 && *begin() == OP_IDENTITY_UPDATE); + break; + case IDENTITY_DELETE_TX: + return (size() > 0 && *begin() == OP_IDENTITY_DELETE); + break; + case IDENTITY_ACTIVATE_TX: + return (size() > 0 && *begin() == OP_IDENTITY_ACTIVATE); + break; + default: + throw std::runtime_error("Identity code is invalid!"); + } + return false; + } + + bool IsCertificateScript(ProtocolCodes code) const + { + switch(code) { + case CERTIFICATE_NEW_TX: + return (size() > 0 && *begin() == OP_CERTIFICATE_NEW); + break; + case CERTIFICATE_UPDATE_TX: + return (size() > 0 && *begin() == OP_CERTIFICATE_UPDATE); + break; + case CERTIFICATE_DELETE_TX: + return (size() > 0 && *begin() == OP_CERTIFICATE_DELETE); + break; + case CERTIFICATE_ACTIVATE_TX: + return (size() > 0 && *begin() == OP_CERTIFICATE_ACTIVATE); + break; + default: + throw std::runtime_error("Certificate code is invalid!"); + } + return false; } void clear() From 238c2e886ea70766ff086af54ca2ea9652591b91 Mon Sep 17 00:00:00 2001 From: Adam Abrams Date: Tue, 10 Apr 2018 02:32:15 -0500 Subject: [PATCH 0002/1653] Refactor identity -> directory to support X.500 type hierarchical directories --- src/Makefile.am | 4 +- src/{identity.cpp => directory.cpp} | 18 +-- src/directory.h | 175 ++++++++++++++++++++++++++++ src/identity.h | 152 ------------------------ src/script/script.h | 42 +++---- src/script/standard.cpp | 4 - 6 files changed, 207 insertions(+), 188 deletions(-) rename src/{identity.cpp => directory.cpp} (62%) create mode 100644 src/directory.h delete mode 100644 src/identity.h diff --git a/src/Makefile.am b/src/Makefile.am index c5d9dc7544..098f2a5e94 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -98,6 +98,7 @@ DYNAMIC_CORE_H = \ consensus/validation.h \ core_io.h \ core_memusage.h \ + directory.h \ dbwrapper.h \ dynode.h \ dynode-payments.h \ @@ -117,7 +118,6 @@ DYNAMIC_CORE_H = \ hdchain.h \ httprpc.h \ httpserver.h \ - identity.h \ indirectmap.h \ init.h \ instantsend.h \ @@ -219,6 +219,7 @@ libdynamic_server_a_SOURCES = \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ + directory.cpp \ dbwrapper.cpp \ dynode.cpp \ dynode-payments.cpp\ @@ -234,7 +235,6 @@ libdynamic_server_a_SOURCES = \ governance-votedb.cpp \ httprpc.cpp \ httpserver.cpp \ - identity.cpp \ init.cpp \ instantsend.cpp \ merkleblock.cpp \ diff --git a/src/identity.cpp b/src/directory.cpp similarity index 62% rename from src/identity.cpp rename to src/directory.cpp index 5d848b64ca..1099554567 100644 --- a/src/identity.cpp +++ b/src/directory.cpp @@ -2,22 +2,22 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "identity.h" +#include "directory.h" #include "fluid.h" #include "validation.h" -CIdentityDB *pIdentityDB = NULL; +CDirectoryDB *pDirectoryDB = NULL; -bool IsIdentityTransaction(CScript txOut) { - return (txOut.IsIdentityScript(IDENTITY_NEW_TX) - || txOut.IsIdentityScript(IDENTITY_UPDATE_TX) - || txOut.IsIdentityScript(IDENTITY_DELETE_TX) - || txOut.IsIdentityScript(IDENTITY_ACTIVATE_TX) +bool IsDirectoryTransaction(CScript txOut) { + return (txOut.IsDirectoryScript(DIRECTORY_NEW_TX) + || txOut.IsDirectoryScript(DIRECTORY_UPDATE_TX) + || txOut.IsDirectoryScript(DIRECTORY_DELETE_TX) + || txOut.IsDirectoryScript(DIRECTORY_ACTIVATE_TX) ); } -bool GetIdentityTransaction(int nHeight, const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams) +bool GetDirectoryTransaction(int nHeight, const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams) { if(nHeight < 0 || nHeight > chainActive.Height()) return false; @@ -39,7 +39,7 @@ bool GetIdentityTransaction(int nHeight, const uint256 &hash, CTransaction &txOu } /* -std::vector>> CIdentityParameters::InitialiseCoreIdentities() +std::vector>> CIdentityParameters::InitialiseAdminOwners() { diff --git a/src/directory.h b/src/directory.h new file mode 100644 index 0000000000..dd9c6003cc --- /dev/null +++ b/src/directory.h @@ -0,0 +1,175 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DIRECTORY_H +#define DIRECTORY_H + +#include "consensus/params.h" +#include "dbwrapper.h" +#include "script/script.h" +#include "serialize.h" +#include "sync.h" + +class CTransaction; +class CDynamicAddress; + +static const unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) +static const unsigned int MAX_DOMAIN_NAME_SIZE = 32; +static const unsigned int MAX_ACCOUNT_NAME_SIZE = 32; +static const unsigned int MAX_TORRENT_NETWORK_LENGTH = 128; +static const unsigned int MAX_KEY_LENGTH = 156; +static const unsigned int MAX_PUBLIC_VALUE_LENGTH = 512; +static const unsigned int MAX_SECRET_VALUE_LENGTH = 49152; // Pay per byte for hosting on chain +static const std::string INTERNAL_DOMAIN_PREFIX = "#"; +static const std::string DEFAULT_ADMIN_DOMAIN = INTERNAL_DOMAIN_PREFIX + "admin"; +static const std::string DEFAULT_PUBLIC_DOMAIN = INTERNAL_DOMAIN_PREFIX + "public"; + +typedef std::vector CharString; + +/* Blockchain Directory Access Framework + + ***** Design Notes ***** +- Modeling after X.500 Directory and LDAP +- Top level domain objects do not have an ObjectName +- Sub level directory objects need permission from parent domain. +- Top level domain objects can run side chains, sub level can with permission from parent +- Torrent network link used to store and transmit sharded and encrypted data. +- Side chains secured by Proof of Stake tokens issued by directory domain owner/creator +- Top level domains require collateral and more expensive than +*/ + +class CDirectoryDefaultParameters { +public: + std::vector>> InitialiseAdminOwners(); +}; + +class CDirectory { +public: + std::vector DomainName; // required. controls child objects + CharString ObjectName; // blank for top level domain directories + unsigned int intObjectType; // 0 = root domain account, 1 = user account, 2 = device or computer account + CharString WalletAddress; // used to send collateral funds for this directory record. + unsigned int fPublicObject; // public and private visibility is relative to other objects in its domain directory + CharString EncryptPublicKey; // used to encrypt data to send to this directory record. + CharString EncryptPrivateKey; // used to decrypt messages and data for this directory record + CharString SignPublicKey; // used to verify authorized update transaction + CharString SignPrivateKey; // used for updating the Directory record. + CharString TorrentNetworkAddress; // used for temp storage and transmision of sharded and encrypted data. + + uint256 txHash; + + unsigned int nHeight; + uint64_t nExpireTime; + + CharString PublicCertificate; + CharString PrivateData; + + CDirectory() { + SetNull(); + } + + CDirectory(const CTransaction &tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + DomainName.clear(); + ObjectName.clear(); + intObjectType = 0; + WalletAddress.clear(); + fPublicObject = 0; // by default set to private. + EncryptPublicKey.clear(); + EncryptPrivateKey.clear(); + SignPublicKey.clear(); + SignPrivateKey.clear(); + TorrentNetworkAddress.clear(); + txHash.SetNull(); + nHeight = 0; + nExpireTime = 0; + PublicCertificate.clear(); + PrivateData.clear(); + } + + ADD_SERIALIZE_METHODS; + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(DomainName); + READWRITE(ObjectName); + READWRITE(VARINT(intObjectType)); + READWRITE(WalletAddress); + READWRITE(VARINT(fPublicObject)); + READWRITE(EncryptPublicKey); + READWRITE(EncryptPrivateKey); + READWRITE(SignPublicKey); + READWRITE(SignPrivateKey); + READWRITE(TorrentNetworkAddress); + READWRITE(txHash); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(PublicCertificate); + READWRITE(PrivateData); + } + + inline friend bool operator==(const CDirectory &a, const CDirectory &b) { + return (a.DomainName == b.DomainName && a.ObjectName == b.ObjectName); + } + + inline friend bool operator!=(const CDirectory &a, const CDirectory &b) { + return !(a == b); + } + + inline CDirectory operator=(const CDirectory &b) { + DomainName = b.DomainName; + ObjectName = b.ObjectName; + intObjectType = b.intObjectType; + WalletAddress = b.WalletAddress; + fPublicObject = b.fPublicObject; + EncryptPublicKey = b.EncryptPublicKey; + EncryptPrivateKey = b.EncryptPrivateKey; + SignPublicKey = b.SignPublicKey; + SignPrivateKey = b.SignPrivateKey; + TorrentNetworkAddress = b.TorrentNetworkAddress; + txHash = b.txHash; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + PublicCertificate = b.PublicCertificate; + PrivateData = b.PrivateData; + return *this; + } + + inline bool IsNull() const { return (DomainName.empty()); } + bool UnserializeFromTx(const CTransaction &tx); + bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); + void Serialize(std::vector& vchData); + + CDynamicAddress GetWalletAddress(); +}; + +class CDirectoryDB : public CDBWrapper { +public: + CDirectoryDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "directories", nCacheSize, fMemory, fWipe) { + } + + bool ReadDirectory(); + + bool AddDirectory(); + + bool UpdateDirectory(); + + bool ExpireDirectory(); + + bool DirectoryExists(); + + bool CleanupDirectoryDatabase(); + + void WriteDirectoryIndex(const CDirectory& directory, const int &op); + void WriteDirectoryIndexHistory(const CDirectory& directory, const int &op); +}; + +extern CDirectoryDB *pDirectoryDB; + + +#endif // DIRECTORY_H diff --git a/src/identity.h b/src/identity.h deleted file mode 100644 index 789ac5f79d..0000000000 --- a/src/identity.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2018 Duality Blockchain Solutions Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef IDENTITY_H -#define IDENTITY_H - -#include "consensus/params.h" -#include "dbwrapper.h" -#include "script/script.h" -#include "serialize.h" -#include "sync.h" - -class CTransaction; -class CDynamicAddress; - -static const unsigned int ACTIVATE_IDENTITY_HEIGHT = 10; -static const unsigned int MAX_IDENTITY_NAME_SIZE = 64; -static const unsigned int MAX_IDENTITY_DOMAIN_SIZE = 24; -static const unsigned int MAX_IDENTITY_UNIQUE_ID_SIZE = 72; -static const unsigned int MAX_PUBLIC_VALUE_LENGTH = 512; -static const unsigned int MAX_SECRET_VALUE_LENGTH = 512; -static const std::string DEFAULT_IDENTITY_DOMAIN = "core"; - -/** Configure Identity Framework */ -class CIdentityParameters { -public: - std::vector>> InitialiseCoreIdentities(); -}; - -class CIdentity { -public: - std::vector vchIdentityName; - std::vector vchIdentityDomain; - std::vector vchUniqueID; - - std::vector vchWalletAddress; - std::vector vchEncryptPublicKey; - std::vector vchEncryptPrivateKey; - std::vector vchSignPublicKey; - std::vector vchSignPrivateKey; - - uint256 txHash; - - unsigned int nHeight; - uint64_t nExpireTime; - - std::vector vchPublicData; - std::vector vchSecretData; - - CIdentity() { - SetNull(); - } - - CIdentity(const CTransaction &tx) { - SetNull(); - UnserializeFromTx(tx); - } - - inline void SetNull() - { - vchIdentityName.clear(); - vchIdentityDomain.clear(); - vchUniqueID.clear(); - vchWalletAddress.clear(); - vchEncryptPublicKey.clear(); - vchEncryptPrivateKey.clear(); - vchSignPublicKey.clear(); - vchSignPrivateKey.clear(); - txHash.SetNull(); - nHeight = 0; - nExpireTime = 0; - vchPublicData.clear(); - vchSecretData.clear(); - } - - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(vchIdentityName); - READWRITE(vchIdentityDomain); - READWRITE(vchUniqueID); - READWRITE(vchWalletAddress); - READWRITE(vchEncryptPublicKey); - READWRITE(vchEncryptPrivateKey); - READWRITE(vchSignPublicKey); - READWRITE(vchSignPrivateKey); - READWRITE(txHash); - READWRITE(VARINT(nHeight)); - READWRITE(VARINT(nExpireTime)); - READWRITE(vchPublicData); - READWRITE(vchSecretData); - } - - inline friend bool operator==(const CIdentity &a, const CIdentity &b) { - return (a.vchIdentityName == b.vchIdentityName && a.vchIdentityDomain == b.vchIdentityDomain && a.vchUniqueID == b.vchUniqueID); - } - - inline friend bool operator!=(const CIdentity &a, const CIdentity &b) { - return !(a == b); - } - - inline CIdentity operator=(const CIdentity &b) { - vchIdentityName = b.vchIdentityName; - vchIdentityDomain = b.vchIdentityDomain; - vchUniqueID = b.vchUniqueID; - vchWalletAddress = b.vchWalletAddress; - vchEncryptPublicKey = b.vchEncryptPublicKey; - vchEncryptPrivateKey = b.vchEncryptPrivateKey; - vchSignPublicKey = b.vchSignPublicKey; - vchSignPrivateKey = b.vchSignPrivateKey; - txHash = b.txHash; - nHeight = b.nHeight; - nExpireTime = b.nExpireTime; - vchPublicData = b.vchPublicData; - vchSecretData = b.vchSecretData; - return *this; - } - - inline bool IsNull() const { return (vchIdentityName.empty()); } - bool UnserializeFromTx(const CTransaction &tx); - bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); - void Serialize(std::vector& vchData); - - CDynamicAddress WalletAddress(); -}; - -class CIdentityDB : public CDBWrapper { -public: - CIdentityDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "identities", nCacheSize, fMemory, fWipe) { - } - - bool ReadIdentity(); - - bool AddIdentity(); - - bool UpdateIdentity(); - - bool ExpireIdentity(); - - bool IdentityExists(); - - bool CleanupDatabase(); - - void WriteIdentityIndex(const CIdentity& identity, const int &op); - void WriteIdentityIndexHistory(const CIdentity& identity, const int &op); -}; - -extern CIdentityDB *pIdentityDB; - - -#endif // IDENTITY_H diff --git a/src/script/script.h b/src/script/script.h index 0f4c524032..318093c4c0 100755 --- a/src/script/script.h +++ b/src/script/script.h @@ -26,10 +26,10 @@ enum ProtocolCodes { MINT_TX = 1, DYNODE_MODFIY_TX = 2, MINING_MODIFY_TX = 3, - IDENTITY_NEW_TX = 4, - IDENTITY_UPDATE_TX = 5, - IDENTITY_DELETE_TX = 6, - IDENTITY_ACTIVATE_TX = 7, + DIRECTORY_NEW_TX = 4, + DIRECTORY_UPDATE_TX = 5, + DIRECTORY_DELETE_TX = 6, + DIRECTORY_ACTIVATE_TX = 7, CERTIFICATE_NEW_TX = 8, CERTIFICATE_UPDATE_TX = 9, CERTIFICATE_DELETE_TX = 10, @@ -211,13 +211,13 @@ enum opcodetype OP_FREEZE_ADDRESS = 0xc7, OP_RELEASE_ADDRESS = 0xc8, - // identity and certificate system - OP_IDENTITY_NEW = 0xd1, - OP_IDENTITY_DELETE = 0xd2, - OP_IDENTITY_PAYMENT = 0xd3, - OP_IDENTITY_ACTIVATE = 0xd4, - OP_IDENTITY_UPDATE = 0xd5, - OP_IDENTITY_MULTISIG = 0xd6, + // directory access, user identity and certificate system + OP_DIRECTORY_NEW = 0xd1, + OP_DIRECTORY_DELETE = 0xd2, + OP_DIRECTORY_PAYMENT = 0xd3, + OP_DIRECTORY_ACTIVATE = 0xd4, + OP_DIRECTORY_UPDATE = 0xd5, + OP_DIRECTORY_MULTISIG = 0xd6, OP_CERTIFICATE_NEW = 0xd7, OP_CERTIFICATE_UPDATE = 0xd8, OP_CERTIFICATE_DELETE = 0xd9, @@ -699,23 +699,23 @@ class CScript : public CScriptBase return false; } - bool IsIdentityScript(ProtocolCodes code) const + bool IsDirectoryScript(ProtocolCodes code) const { switch(code) { - case IDENTITY_NEW_TX: - return (size() > 0 && *begin() == OP_IDENTITY_NEW); + case DIRECTORY_NEW_TX: + return (size() > 0 && *begin() == OP_DIRECTORY_NEW); break; - case IDENTITY_UPDATE_TX: - return (size() > 0 && *begin() == OP_IDENTITY_UPDATE); + case DIRECTORY_UPDATE_TX: + return (size() > 0 && *begin() == OP_DIRECTORY_UPDATE); break; - case IDENTITY_DELETE_TX: - return (size() > 0 && *begin() == OP_IDENTITY_DELETE); + case DIRECTORY_DELETE_TX: + return (size() > 0 && *begin() == OP_DIRECTORY_DELETE); break; - case IDENTITY_ACTIVATE_TX: - return (size() > 0 && *begin() == OP_IDENTITY_ACTIVATE); + case DIRECTORY_ACTIVATE_TX: + return (size() > 0 && *begin() == OP_DIRECTORY_ACTIVATE); break; default: - throw std::runtime_error("Identity code is invalid!"); + throw std::runtime_error("Directory code is invalid!"); } return false; } diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 78b4d06c3a..de933aeea9 100755 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -51,10 +51,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector Date: Tue, 10 Apr 2018 03:12:40 -0500 Subject: [PATCH 0003/1653] Remove old name OP code in script and wallet --- src/script/sign.cpp | 11 +---------- src/script/standard.cpp | 1 - src/script/standard.h | 3 +-- src/wallet/wallet_ismine.cpp | 1 - 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 2e9113a6c1..80efd19eca 100755 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -101,9 +101,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP switch (whichTypeRet) { case TX_NONSTANDARD: - case TX_NULL_DATA: - case TX_NAME: - return false; + case TX_NULL_DATA:; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, creator, scriptPubKey, scriptSigRet); @@ -245,11 +243,6 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatur { case TX_NONSTANDARD: case TX_NULL_DATA: - case TX_NAME: - // Don't know anything about this, assume bigger one is correct: - if (sigs1.size() >= sigs2.size()) - return PushAll(sigs1); - return PushAll(sigs2); case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: @@ -361,8 +354,6 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash { case TX_NONSTANDARD: case TX_NULL_DATA: - case TX_NAME: - return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index de933aeea9..e20269afb2 100755 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -29,7 +29,6 @@ const char* GetTxnOutputType(txnouttype t) case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; case TX_NULL_DATA: return "nulldata"; - case TX_NAME: return "name"; } return NULL; } diff --git a/src/script/standard.h b/src/script/standard.h index 6d4e1290a7..0b173137b6 100755 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -50,8 +50,7 @@ enum txnouttype TX_PUBKEYHASH, TX_SCRIPTHASH, TX_MULTISIG, - TX_NULL_DATA, - TX_NAME, //DDNS + TX_NULL_DATA }; class CNoDestination { diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp index b91085b901..f744016653 100755 --- a/src/wallet/wallet_ismine.cpp +++ b/src/wallet/wallet_ismine.cpp @@ -62,7 +62,6 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) return ISMINE_SPENDABLE; break; case TX_SCRIPTHASH: - case TX_NAME: { CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; From a263f22c6a713a58678a4988aaa071a8334f9d7d Mon Sep 17 00:00:00 2001 From: Adam Abrams Date: Thu, 12 Apr 2018 13:55:31 -0500 Subject: [PATCH 0004/1653] Adjust directory class before attempting read/write operations - Add canonical OID for hierarchical structure - Use directory object type enum - Use wallet address vector for signature, not pub/private keys - Add custom reg and transaction fees - Add number of signatures required for updating - Update directory class notes --- src/directory.h | 80 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/src/directory.h b/src/directory.h index dd9c6003cc..95bf81bbdb 100644 --- a/src/directory.h +++ b/src/directory.h @@ -5,6 +5,7 @@ #ifndef DIRECTORY_H #define DIRECTORY_H +#include "amount.h" #include "consensus/params.h" #include "dbwrapper.h" #include "script/script.h" @@ -26,37 +27,54 @@ static const std::string DEFAULT_ADMIN_DOMAIN = INTERNAL_DOMAIN_PREFIX + static const std::string DEFAULT_PUBLIC_DOMAIN = INTERNAL_DOMAIN_PREFIX + "public"; typedef std::vector CharString; +typedef std::vector vchCharString; + +enum DirectoryObjectType { + USER_ACCOUNT = 0, + DEVICE_ACCOUNT = 1, + GROUP = 2, + DOMAIN_CONTROLLER = 3, + ORGANIZATIONAL_UNIT = 4, + CERTIFICATE = 5, + CODE = 6 +}; /* Blockchain Directory Access Framework ***** Design Notes ***** -- Modeling after X.500 Directory and LDAP -- Top level domain objects do not have an ObjectName -- Sub level directory objects need permission from parent domain. +- Modeling after X.500 Directory and LDAP (RFC 4512): https://docs.ldap.com/specs/rfc4512.txt +- Top level domain objects do not have an ObjectName and are considered controlers. +- OID canonical identifiers like 1.23.456.7.89 +- Sub level directory objects need permission from parent domain object. - Top level domain objects can run side chains, sub level can with permission from parent - Torrent network link used to store and transmit sharded and encrypted data. - Side chains secured by Proof of Stake tokens issued by directory domain owner/creator -- Top level domains require collateral and more expensive than +- Top level domains require collateral and more expensive than +- Recommended to store lower level domain object data as encrypted shards on Torrent network and not on the chain. */ class CDirectoryDefaultParameters { public: - std::vector>> InitialiseAdminOwners(); + void InitialiseAdminOwners(); //DEFAULT_ADMIN_DOMAIN + void InitialisePublicDomain(); //DEFAULT_PUBLIC_DOMAIN }; class CDirectory { public: - std::vector DomainName; // required. controls child objects + static const int CURRENT_VERSION=1; + int nVersion; + CharString OID; // Object ID + vchCharString DomainName; // required. controls child objects CharString ObjectName; // blank for top level domain directories - unsigned int intObjectType; // 0 = root domain account, 1 = user account, 2 = device or computer account - CharString WalletAddress; // used to send collateral funds for this directory record. + DirectoryObjectType Type; // see enum above + CharString WalletAddress; // used to send collateral funds for this directory record. This is the multisig wallet address made from the SignWalletAddresses unsigned int fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. CharString EncryptPrivateKey; // used to decrypt messages and data for this directory record - CharString SignPublicKey; // used to verify authorized update transaction - CharString SignPrivateKey; // used for updating the Directory record. + vchCharString SignWalletAddresses; // used to verify authorized update transaction + unsigned int nSigaturesRequired; // number of SignWalletAddresses needed to sign a transaction. Default = 1 CharString TorrentNetworkAddress; // used for temp storage and transmision of sharded and encrypted data. - + uint256 txHash; unsigned int nHeight; @@ -64,6 +82,8 @@ class CDirectory { CharString PublicCertificate; CharString PrivateData; + CAmount transactionFee; + CAmount registrationFeePerDay; CDirectory() { SetNull(); @@ -76,45 +96,54 @@ class CDirectory { inline void SetNull() { + nVersion = CDirectory::CURRENT_VERSION; + OID.clear(); DomainName.clear(); ObjectName.clear(); - intObjectType = 0; + Type = DirectoryObjectType::USER_ACCOUNT; WalletAddress.clear(); - fPublicObject = 0; // by default set to private. + fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); EncryptPrivateKey.clear(); - SignPublicKey.clear(); - SignPrivateKey.clear(); + SignWalletAddresses.clear(); + nSigaturesRequired = 1; TorrentNetworkAddress.clear(); txHash.SetNull(); nHeight = 0; nExpireTime = 0; PublicCertificate.clear(); PrivateData.clear(); + transactionFee = 0; + registrationFeePerDay = 0; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(OID); READWRITE(DomainName); READWRITE(ObjectName); - READWRITE(VARINT(intObjectType)); + READWRITE(static_cast(Type)); READWRITE(WalletAddress); READWRITE(VARINT(fPublicObject)); READWRITE(EncryptPublicKey); READWRITE(EncryptPrivateKey); - READWRITE(SignPublicKey); - READWRITE(SignPrivateKey); + READWRITE(SignWalletAddresses); + READWRITE(VARINT(nSigaturesRequired)); READWRITE(TorrentNetworkAddress); - READWRITE(txHash); READWRITE(VARINT(nHeight)); + READWRITE(txHash); READWRITE(VARINT(nExpireTime)); - READWRITE(PublicCertificate); + READWRITE(PublicCertificate); READWRITE(PrivateData); + READWRITE(transactionFee); + READWRITE(registrationFeePerDay); } inline friend bool operator==(const CDirectory &a, const CDirectory &b) { - return (a.DomainName == b.DomainName && a.ObjectName == b.ObjectName); + return (a.OID == b.OID && a.DomainName == b.DomainName && a.ObjectName == b.ObjectName); } inline friend bool operator!=(const CDirectory &a, const CDirectory &b) { @@ -122,15 +151,16 @@ class CDirectory { } inline CDirectory operator=(const CDirectory &b) { + OID = b.OID; DomainName = b.DomainName; ObjectName = b.ObjectName; - intObjectType = b.intObjectType; + Type = b.Type; WalletAddress = b.WalletAddress; fPublicObject = b.fPublicObject; EncryptPublicKey = b.EncryptPublicKey; EncryptPrivateKey = b.EncryptPrivateKey; - SignPublicKey = b.SignPublicKey; - SignPrivateKey = b.SignPrivateKey; + SignWalletAddresses = b.SignWalletAddresses; + nSigaturesRequired = b.nSigaturesRequired; TorrentNetworkAddress = b.TorrentNetworkAddress; txHash = b.txHash; nHeight = b.nHeight; @@ -145,7 +175,7 @@ class CDirectory { bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); void Serialize(std::vector& vchData); - CDynamicAddress GetWalletAddress(); + CDynamicAddress GetWalletAddress(); }; class CDirectoryDB : public CDBWrapper { From 92b883b749f6d610c71859f4871a2377ecd8da9f Mon Sep 17 00:00:00 2001 From: amirabrams Date: Mon, 28 May 2018 19:42:11 -0500 Subject: [PATCH 0005/1653] [BDAP] Add first RPC command --- src/Makefile.am | 1 + src/directory.cpp | 168 +++++++++++++++++++++++++++++++++++- src/directory.h | 70 ++++++++++----- src/init.cpp | 6 ++ src/rpcdirectory.cpp | 60 +++++++++++++ src/rpcregister.h | 3 + src/validationinterface.cpp | 3 + src/validationinterface.h | 3 + 8 files changed, 293 insertions(+), 21 deletions(-) create mode 100644 src/rpcdirectory.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 098f2a5e94..eb490004f1 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -254,6 +254,7 @@ libdynamic_server_a_SOURCES = \ psnotificationinterface.cpp \ rest.cpp \ rpcblockchain.cpp \ + rpcdirectory.cpp \ rpcdynode.cpp \ rpcgovernance.cpp \ rpcmining.cpp \ diff --git a/src/directory.cpp b/src/directory.cpp index 1099554567..c4836174ec 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -5,7 +5,13 @@ #include "directory.h" #include "fluid.h" +#include "policy/policy.h" +#include "rpcclient.h" +#include "rpcserver.h" #include "validation.h" +#include "validationinterface.h" + +#include CDirectoryDB *pDirectoryDB = NULL; @@ -17,7 +23,16 @@ bool IsDirectoryTransaction(CScript txOut) { ); } -bool GetDirectoryTransaction(int nHeight, const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams) +bool IsDirectoryDataOutput(const CTxOut& out) { + txnouttype whichType; + if (!IsStandard(out.scriptPubKey, whichType)) + return false; + if (whichType == TX_NULL_DATA) + return true; + return false; +} + +bool GetDirectoryTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams) { if(nHeight < 0 || nHeight > chainActive.Height()) return false; @@ -38,7 +53,158 @@ bool GetDirectoryTransaction(int nHeight, const uint256 &hash, CTransaction &txO return false; } +std::string stringFromVch(const CharString& vch) { + std::string res; + std::vector::const_iterator vi = vch.begin(); + while (vi != vch.end()) { + res += (char) (*vi); + vi++; + } + return res; +} + +std::vector vchFromValue(const UniValue& value) { + std::string strName = value.get_str(); + unsigned char *strbeg = (unsigned char*) strName.c_str(); + return std::vector(strbeg, strbeg + strName.size()); +} + +int GetDirectoryDataOutput(const CTransaction& tx) { + for(unsigned int i = 0; i& vchData, std::vector& vchHash) +{ + CScript::const_iterator pc = scriptPubKey.begin(); + opcodetype opcode; + if (!scriptPubKey.GetOp(pc, opcode)) + return false; + if(opcode != OP_RETURN) + return false; + if (!scriptPubKey.GetOp(pc, opcode, vchData)) + return false; + if (!scriptPubKey.GetOp(pc, opcode, vchHash)) + return false; + return true; +} + +bool GetDirectoryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut) +{ + nOut = GetDirectoryDataOutput(tx); + if(nOut == -1) + return false; + + const CScript &scriptPubKey = tx.vout[nOut].scriptPubKey; + return GetDirectoryData(scriptPubKey, vchData, vchHash); +} + +bool CDirectory::UnserializeFromTx(const CTransaction& tx) { + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetDirectoryData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +void CDirectory::Serialize(std::vector& vchData) { + CDataStream dsBDAP(SER_NETWORK, PROTOCOL_VERSION); + dsBDAP << *this; + vchData = std::vector(dsBDAP.begin(), dsBDAP.end()); +} + +bool CDirectory::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) { + try { + CDataStream dsBDAP(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsBDAP >> *this; + + std::vector vchBDAPData; + Serialize(vchBDAPData); + const uint256 &calculatedHash = Hash(vchBDAPData.begin(), vchBDAPData.end()); + const std::vector &vchRandBDAP = vchFromValue(calculatedHash.GetHex()); + if(vchRandBDAP != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) { + UniValue oName(UniValue::VOBJ); + std::string domainName = stringFromVch(directory.DomainName); + oName.push_back(Pair("_id", domainName)); + //CDyamicAddress address(EncodeBase58(directory.vchAddress)); + oName.push_back(Pair("domain_name", domainName)); + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "add.directory"); + //WriteDirectoryIndexHistory(directory, op); +} + +bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) +{ + bool expired = false; + int64_t expired_time = 0; + int64_t nTime = 0; + oName.push_back(Pair("_id", stringFromVch(directory.OID))); + oName.push_back(Pair("version", directory.nVersion)); + oName.push_back(Pair("domain_name", stringFromVch(directory.DomainName))); + oName.push_back(Pair("object_name", stringFromVch(directory.ObjectName))); + oName.push_back(Pair("object_type", directory.ObjectType)); + oName.push_back(Pair("address", EncodeBase58(directory.WalletAddress))); + oName.push_back(Pair("public", (int)directory.fPublicObject)); + //loop SignWalletAddresses + //oName.push_back(Pair("sign address", EncodeBase58(directory.SignWalletAddresses))); + + oName.push_back(Pair("encryption_publickey", HexStr(directory.EncryptPublicKey))); + oName.push_back(Pair("encryption_privatekey", HexStr(directory.EncryptPrivateKey))); + //oName.push_back(Pair("sigatures_required", directory.nSigaturesRequired)); + oName.push_back(Pair("ipfs_address", stringFromVch(directory.IPFSAddress))); + oName.push_back(Pair("txid", directory.txHash.GetHex())); + if ((unsigned int)chainActive.Height() >= directory.nHeight-1) { + CBlockIndex *pindex = chainActive[directory.nHeight-1]; + if (pindex) { + nTime = pindex->GetMedianTimePast(); + } + } + oName.push_back(Pair("time", nTime)); + //oName.push_back(Pair("height", directory.nHeight)); + expired_time = directory.nExpireTime; + if(expired_time <= chainActive.Tip()->GetMedianTimePast()) + { + expired = true; + } + oName.push_back(Pair("expires_on", expired_time)); + oName.push_back(Pair("expired", expired)); + + oName.push_back(Pair("certificate", stringFromVch(directory.Certificate))); + oName.push_back(Pair("private_data", stringFromVch(directory.PrivateData))); + //oName.push_back(Pair("transaction_fee", directory.transactionFee); + //oName.push_back(Pair("registration_fee", directory.registrationFeePerDay); + // loop CheckpointHashes + return true; +} + /* +SignWalletAddresses.clear(); +transactionFee = 0; +registrationFeePerDay = 0; +CheckpointHashes.clear(); + std::vector>> CIdentityParameters::InitialiseAdminOwners() { diff --git a/src/directory.h b/src/directory.h index 95bf81bbdb..ae6bfa6ea8 100644 --- a/src/directory.h +++ b/src/directory.h @@ -12,8 +12,11 @@ #include "serialize.h" #include "sync.h" +#include + class CTransaction; class CDynamicAddress; +class CTxOut; static const unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) static const unsigned int MAX_DOMAIN_NAME_SIZE = 32; @@ -28,12 +31,13 @@ static const std::string DEFAULT_PUBLIC_DOMAIN = INTERNAL_DOMAIN_PREFIX + typedef std::vector CharString; typedef std::vector vchCharString; +typedef std::vector > vCheckPoints; // << height, block hash >> enum DirectoryObjectType { USER_ACCOUNT = 0, DEVICE_ACCOUNT = 1, GROUP = 2, - DOMAIN_CONTROLLER = 3, + DOMAIN_ACCOUNT = 3, ORGANIZATIONAL_UNIT = 4, CERTIFICATE = 5, CODE = 6 @@ -51,6 +55,8 @@ enum DirectoryObjectType { - Side chains secured by Proof of Stake tokens issued by directory domain owner/creator - Top level domains require collateral and more expensive than - Recommended to store lower level domain object data as encrypted shards on Torrent network and not on the chain. +- The basic operations of DAP: Bind, Read, List, Search, Compare, Modify, Add, Delete and ModifyRDN +- Implement file sharing using IPFS */ class CDirectoryDefaultParameters { @@ -63,27 +69,28 @@ class CDirectory { public: static const int CURRENT_VERSION=1; int nVersion; - CharString OID; // Object ID - vchCharString DomainName; // required. controls child objects + CharString OID; // Canonical Object ID + CharString DomainName; // required. controls child objects CharString ObjectName; // blank for top level domain directories - DirectoryObjectType Type; // see enum above + DirectoryObjectType ObjectType; // see enum above CharString WalletAddress; // used to send collateral funds for this directory record. This is the multisig wallet address made from the SignWalletAddresses unsigned int fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. CharString EncryptPrivateKey; // used to decrypt messages and data for this directory record vchCharString SignWalletAddresses; // used to verify authorized update transaction unsigned int nSigaturesRequired; // number of SignWalletAddresses needed to sign a transaction. Default = 1 - CharString TorrentNetworkAddress; // used for temp storage and transmision of sharded and encrypted data. + CharString IPFSAddress; // used for temp storage and transmision of sharded and encrypted data. uint256 txHash; unsigned int nHeight; uint64_t nExpireTime; - CharString PublicCertificate; + CharString Certificate; CharString PrivateData; CAmount transactionFee; CAmount registrationFeePerDay; + vCheckPoints CheckpointHashes; // used to store main chain hash checkpoints for added security CDirectory() { SetNull(); @@ -100,21 +107,22 @@ class CDirectory { OID.clear(); DomainName.clear(); ObjectName.clear(); - Type = DirectoryObjectType::USER_ACCOUNT; + ObjectType = DirectoryObjectType::DOMAIN_ACCOUNT; WalletAddress.clear(); fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); EncryptPrivateKey.clear(); SignWalletAddresses.clear(); nSigaturesRequired = 1; - TorrentNetworkAddress.clear(); + IPFSAddress.clear(); txHash.SetNull(); nHeight = 0; nExpireTime = 0; - PublicCertificate.clear(); + Certificate.clear(); PrivateData.clear(); transactionFee = 0; registrationFeePerDay = 0; + CheckpointHashes.clear(); } ADD_SERIALIZE_METHODS; @@ -125,21 +133,22 @@ class CDirectory { READWRITE(OID); READWRITE(DomainName); READWRITE(ObjectName); - READWRITE(static_cast(Type)); + //READWRITE(static_cast(ObjectType)); READWRITE(WalletAddress); READWRITE(VARINT(fPublicObject)); READWRITE(EncryptPublicKey); READWRITE(EncryptPrivateKey); READWRITE(SignWalletAddresses); READWRITE(VARINT(nSigaturesRequired)); - READWRITE(TorrentNetworkAddress); + READWRITE(IPFSAddress); READWRITE(VARINT(nHeight)); READWRITE(txHash); READWRITE(VARINT(nExpireTime)); - READWRITE(PublicCertificate); + READWRITE(Certificate); READWRITE(PrivateData); READWRITE(transactionFee); READWRITE(registrationFeePerDay); + READWRITE(CheckpointHashes); } inline friend bool operator==(const CDirectory &a, const CDirectory &b) { @@ -154,19 +163,20 @@ class CDirectory { OID = b.OID; DomainName = b.DomainName; ObjectName = b.ObjectName; - Type = b.Type; + ObjectType = b.ObjectType; WalletAddress = b.WalletAddress; fPublicObject = b.fPublicObject; EncryptPublicKey = b.EncryptPublicKey; EncryptPrivateKey = b.EncryptPrivateKey; SignWalletAddresses = b.SignWalletAddresses; nSigaturesRequired = b.nSigaturesRequired; - TorrentNetworkAddress = b.TorrentNetworkAddress; + IPFSAddress = b.IPFSAddress; txHash = b.txHash; nHeight = b.nHeight; nExpireTime = b.nExpireTime; - PublicCertificate = b.PublicCertificate; + Certificate = b.Certificate; PrivateData = b.PrivateData; + CheckpointHashes = b.CheckpointHashes; return *this; } @@ -180,12 +190,22 @@ class CDirectory { class CDirectoryDB : public CDBWrapper { public: - CDirectoryDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "directories", nCacheSize, fMemory, fWipe) { + CDirectoryDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "bdap", nCacheSize, fMemory, fWipe) { } - bool ReadDirectory(); + // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare + + bool AddDirectory(const CDirectory& directory, const int& op) { + bool writeState = Write(make_pair(std::string("domain_name"), directory.DomainName), directory) + && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.DomainName); + + AddDirectoryIndex(directory, op); + return writeState; + } - bool AddDirectory(); + void AddDirectoryIndex(const CDirectory& directory, const int& op); + + bool ReadDirectory(); bool UpdateDirectory(); @@ -194,11 +214,21 @@ class CDirectoryDB : public CDBWrapper { bool DirectoryExists(); bool CleanupDirectoryDatabase(); + - void WriteDirectoryIndex(const CDirectory& directory, const int &op); - void WriteDirectoryIndexHistory(const CDirectory& directory, const int &op); + void WriteDirectoryIndex(const CDirectory& directory, const int& op); + void WriteDirectoryIndexHistory(const CDirectory& directory, const int& op); }; +bool IsDirectoryDataOutput(const CTxOut& out); +int GetDirectoryDataOutput(const CTransaction& tx); +bool GetDirectoryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); +bool GetDirectoryData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash); +bool BuildBDAPJson(const CDirectory& directory, UniValue& oName); + +std::string stringFromVch(const CharString& vch); +std::vector vchFromValue(const UniValue& value); + extern CDirectoryDB *pDirectoryDB; diff --git a/src/init.cpp b/src/init.cpp index 511b28b968..1aa8f77cac 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -18,6 +18,7 @@ #include "chain.h" #include "chainparams.h" #include "checkpoints.h" +#include "directory.h" #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeconfig.h" @@ -1441,12 +1442,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) delete pcoinsdbview; delete pcoinscatcher; delete pblocktree; + // BDAP Services DB's + delete pDirectoryDB; pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); pcoinsTip = new CCoinsViewCache(pcoinscatcher); + // Init BDAP Services DB's + pDirectoryDB = new CDirectoryDB(nTotalCache * 35, false, fReindex); + if (fReindex) { pblocktree->WriteReindexing(true); //If we're reindexing in prune mode, wipe away unusable block files and all undo data files diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp new file mode 100644 index 0000000000..b5d36852c6 --- /dev/null +++ b/src/rpcdirectory.cpp @@ -0,0 +1,60 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "directory.h" + +#include "rpcprotocol.h" +#include "rpcserver.h" + +#include + + +UniValue directoryadd(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 1) { + throw std::runtime_error("directoryadd \nAdd directory to blockchain.\n"); + } + + std::vector vchDirectoryName = vchFromValue(params[0]); + CDirectory txDirectory; + if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_DIRECTORY_NEW)) + throw std::runtime_error("Failed to read from BDAP database"); + + UniValue oName(UniValue::VOBJ); + if(!BuildBDAPJson(txDirectory, oName)) + throw std::runtime_error("Failed to read from BDAP JSON object"); + + return oName; +} + +UniValue directorylist(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 1) { + throw std::runtime_error("directoryadd \nAdd directory to blockchain.\n"); + } + + std::vector vchDirectoryName = vchFromValue(params[0]); + CDirectory txDirectory; + if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_DIRECTORY_NEW)) + throw std::runtime_error("Failed to read from BDAP database"); + + UniValue oName(UniValue::VOBJ); + if(!BuildBDAPJson(txDirectory, oName)) + throw std::runtime_error("Failed to read from BDAP JSON object"); + + return oName; +} + +static const CRPCCommand commands[] = +{ // category name actor (function) okSafeMode +#ifdef ENABLE_WALLET + /* BDAP */ + { "bdap", "directoryadd", &directoryadd, true }, + { "bdap", "directorylist", &directorylist, true }, +#endif //ENABLE_WALLET +}; + +void RegisterDirectoryRPCCommands(CRPCTable &tableRPC) +{ + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); +} \ No newline at end of file diff --git a/src/rpcregister.h b/src/rpcregister.h index ac5d6cae3e..4adae52aff 100644 --- a/src/rpcregister.h +++ b/src/rpcregister.h @@ -26,6 +26,8 @@ void RegisterDynodeRPCCommands(CRPCTable &tableRPC); void RegisterGovernanceRPCCommands(CRPCTable &tableRPC); /** Register fluid RPC commands */ void RegisterFluidRPCCommands(CRPCTable &tableRPC); +/** Register BDAP RPC commands */ +void RegisterDirectoryRPCCommands(CRPCTable &tableRPC); static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) { RegisterBlockchainRPCCommands(tableRPC); @@ -36,6 +38,7 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) RegisterDynodeRPCCommands(tableRPC); RegisterGovernanceRPCCommands(tableRPC); RegisterFluidRPCCommands(tableRPC); + RegisterDirectoryRPCCommands(tableRPC); } #endif // DYNAMIC_RPCREGISTER_H \ No newline at end of file diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 03fff75c02..5873f972f4 100755 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -25,6 +25,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); + g_signals.NotifyBDAPUpdate.connect(boost::bind(&CValidationInterface::NotifyBDAPUpdate, pwalletIn, _1, _2)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { @@ -40,6 +41,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3)); g_signals.NotifyHeaderTip.disconnect(boost::bind(&CValidationInterface::NotifyHeaderTip, pwalletIn, _1, _2)); g_signals.AcceptedBlockHeader.disconnect(boost::bind(&CValidationInterface::AcceptedBlockHeader, pwalletIn, _1)); + g_signals.NotifyBDAPUpdate.disconnect(boost::bind(&CValidationInterface::NotifyBDAPUpdate, pwalletIn, _1, _2)); } void UnregisterAllValidationInterfaces() { @@ -55,4 +57,5 @@ void UnregisterAllValidationInterfaces() { g_signals.UpdatedBlockTip.disconnect_all_slots(); g_signals.NotifyHeaderTip.disconnect_all_slots(); g_signals.AcceptedBlockHeader.disconnect_all_slots(); + g_signals.NotifyBDAPUpdate.disconnect_all_slots(); } \ No newline at end of file diff --git a/src/validationinterface.h b/src/validationinterface.h index 36757c9bdd..be8186f619 100755 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -43,6 +43,7 @@ class CValidationInterface { virtual void BlockChecked(const CBlock&, const CValidationState&) {} virtual void GetScriptForMining(boost::shared_ptr&) {}; virtual void ResetRequestCount(const uint256 &hash) {}; + virtual void NotifyBDAPUpdate(const char *value, const char *action) {} friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); @@ -73,6 +74,8 @@ struct CMainSignals { boost::signals2::signal&)> ScriptForMining; /** Notifies listeners that a block has been successfully mined */ boost::signals2::signal BlockFound; + /** Notifies listeners of an updated BDAP action */ + boost::signals2::signal NotifyBDAPUpdate; }; CMainSignals& GetMainSignals(); From 1df3b085d938ed0aceeb4cd7d8e96e1af01584c6 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sat, 16 Jun 2018 22:22:22 -0500 Subject: [PATCH 0006/1653] [BDAP] Implementing addpublicname RPC command --- src/directory.cpp | 45 +++++++++++++++++++++--- src/directory.h | 30 +++++++++------- src/rpcdirectory.cpp | 82 +++++++++++++++++++++++++++++++++++++++----- src/script/script.h | 81 ++++++++++++++++++------------------------- 4 files changed, 163 insertions(+), 75 deletions(-) diff --git a/src/directory.cpp b/src/directory.cpp index c4836174ec..0da9173455 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -10,16 +10,20 @@ #include "rpcserver.h" #include "validation.h" #include "validationinterface.h" +#include "wallet/wallet.h" #include CDirectoryDB *pDirectoryDB = NULL; bool IsDirectoryTransaction(CScript txOut) { - return (txOut.IsDirectoryScript(DIRECTORY_NEW_TX) - || txOut.IsDirectoryScript(DIRECTORY_UPDATE_TX) - || txOut.IsDirectoryScript(DIRECTORY_DELETE_TX) - || txOut.IsDirectoryScript(DIRECTORY_ACTIVATE_TX) + return (txOut.IsDirectoryScript(BDAP_NEW_TX) + || txOut.IsDirectoryScript(BDAP_DELETE_TX) + || txOut.IsDirectoryScript(BDAP_ACTIVATE_TX) + || txOut.IsDirectoryScript(BDAP_MODIFY_TX) + || txOut.IsDirectoryScript(BDAP_MODIFY_RDN_TX) + || txOut.IsDirectoryScript(BDAP_EXECUTE_CODE_TX) + || txOut.IsDirectoryScript(BDAP_BIND_TX) ); } @@ -164,6 +168,7 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) oName.push_back(Pair("version", directory.nVersion)); oName.push_back(Pair("domain_name", stringFromVch(directory.DomainName))); oName.push_back(Pair("object_name", stringFromVch(directory.ObjectName))); + oName.push_back(Pair("object_full_path", stringFromVch(directory.ObjectName) + "@" + stringFromVch(directory.DomainName))); oName.push_back(Pair("object_type", directory.ObjectType)); oName.push_back(Pair("address", EncodeBase58(directory.WalletAddress))); oName.push_back(Pair("public", (int)directory.fPublicObject)); @@ -173,7 +178,7 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) oName.push_back(Pair("encryption_publickey", HexStr(directory.EncryptPublicKey))); oName.push_back(Pair("encryption_privatekey", HexStr(directory.EncryptPrivateKey))); //oName.push_back(Pair("sigatures_required", directory.nSigaturesRequired)); - oName.push_back(Pair("ipfs_address", stringFromVch(directory.IPFSAddress))); + oName.push_back(Pair("resource_pointer", stringFromVch(directory.ResourcePointer))); oName.push_back(Pair("txid", directory.txHash.GetHex())); if ((unsigned int)chainActive.Height() >= directory.nHeight-1) { CBlockIndex *pindex = chainActive[directory.nHeight-1]; @@ -199,6 +204,36 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) return true; } +void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient) +{ + CRecipient recp = {scriptPubKey, recipient.nAmount, false}; + recipient = recp; + CTxOut txout(recipient.nAmount, scriptPubKey); + size_t nSize = GetSerializeSize(txout, SER_DISK, 0) + 148u; + recipient.nAmount = 3 * minRelayTxFee.GetFee(nSize); +} + +void CreateFeeRecipient(CScript& scriptPubKey, const std::vector& data, CRecipient& recipient) +{ + // add hash to data output (must match hash in inputs check with the tx scriptpubkey hash) + uint256 hash = Hash(data.begin(), data.end()); + std::vector vchHashRand = vchFromValue(hash.GetHex()); + scriptPubKey << vchHashRand; + CRecipient recp = {scriptPubKey, 0, false}; + recipient = recp; +} + +CAmount GetDataFee(const CScript& scriptPubKey) +{ + CAmount nFee = 0; + CRecipient recp = {scriptPubKey, 0, false}; + CTxOut txout(0, scriptPubKey); + size_t nSize = GetSerializeSize(txout, SER_DISK,0)+148u; + nFee = CWallet::GetMinimumFee(nSize, nTxConfirmTarget, mempool); + recp.nAmount = nFee; + return recp.nAmount; +} + /* SignWalletAddresses.clear(); transactionFee = 0; diff --git a/src/directory.h b/src/directory.h index ae6bfa6ea8..c2dfca5b9c 100644 --- a/src/directory.h +++ b/src/directory.h @@ -14,10 +14,15 @@ #include -class CTransaction; class CDynamicAddress; +class CRecipient; +class CTransaction; class CTxOut; +typedef std::vector CharString; +typedef std::vector vchCharString; +typedef std::vector > vCheckPoints; // << height, block hash >> + static const unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) static const unsigned int MAX_DOMAIN_NAME_SIZE = 32; static const unsigned int MAX_ACCOUNT_NAME_SIZE = 32; @@ -25,13 +30,10 @@ static const unsigned int MAX_TORRENT_NETWORK_LENGTH = 128; static const unsigned int MAX_KEY_LENGTH = 156; static const unsigned int MAX_PUBLIC_VALUE_LENGTH = 512; static const unsigned int MAX_SECRET_VALUE_LENGTH = 49152; // Pay per byte for hosting on chain -static const std::string INTERNAL_DOMAIN_PREFIX = "#"; -static const std::string DEFAULT_ADMIN_DOMAIN = INTERNAL_DOMAIN_PREFIX + "admin"; -static const std::string DEFAULT_PUBLIC_DOMAIN = INTERNAL_DOMAIN_PREFIX + "public"; - -typedef std::vector CharString; -typedef std::vector vchCharString; -typedef std::vector > vCheckPoints; // << height, block hash >> +static const std::string INTERNAL_DOMAIN_PREFIX = "#"; +static const std::string DEFAULT_ADMIN_DOMAIN = "admin.bdap"; +static const std::string DEFAULT_PUBLIC_DOMAIN = "public.bdap"; +static const int BDAP_TX_VERSION = 0x3500; enum DirectoryObjectType { USER_ACCOUNT = 0, @@ -40,7 +42,8 @@ enum DirectoryObjectType { DOMAIN_ACCOUNT = 3, ORGANIZATIONAL_UNIT = 4, CERTIFICATE = 5, - CODE = 6 + CODE = 6, + BINDING = 7 }; /* Blockchain Directory Access Framework @@ -79,7 +82,7 @@ class CDirectory { CharString EncryptPrivateKey; // used to decrypt messages and data for this directory record vchCharString SignWalletAddresses; // used to verify authorized update transaction unsigned int nSigaturesRequired; // number of SignWalletAddresses needed to sign a transaction. Default = 1 - CharString IPFSAddress; // used for temp storage and transmision of sharded and encrypted data. + CharString ResourcePointer; // used for temp storage and transmision of sharded and encrypted data. uint256 txHash; @@ -114,7 +117,7 @@ class CDirectory { EncryptPrivateKey.clear(); SignWalletAddresses.clear(); nSigaturesRequired = 1; - IPFSAddress.clear(); + ResourcePointer.clear(); txHash.SetNull(); nHeight = 0; nExpireTime = 0; @@ -140,7 +143,7 @@ class CDirectory { READWRITE(EncryptPrivateKey); READWRITE(SignWalletAddresses); READWRITE(VARINT(nSigaturesRequired)); - READWRITE(IPFSAddress); + READWRITE(ResourcePointer); READWRITE(VARINT(nHeight)); READWRITE(txHash); READWRITE(VARINT(nExpireTime)); @@ -170,7 +173,7 @@ class CDirectory { EncryptPrivateKey = b.EncryptPrivateKey; SignWalletAddresses = b.SignWalletAddresses; nSigaturesRequired = b.nSigaturesRequired; - IPFSAddress = b.IPFSAddress; + ResourcePointer = b.ResourcePointer; txHash = b.txHash; nHeight = b.nHeight; nExpireTime = b.nExpireTime; @@ -228,6 +231,7 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName); std::string stringFromVch(const CharString& vch); std::vector vchFromValue(const UniValue& value); +void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); extern CDirectoryDB *pDirectoryDB; diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp index b5d36852c6..0a3f416dbe 100644 --- a/src/rpcdirectory.cpp +++ b/src/rpcdirectory.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Copyright (c) 2018 Duality Blockchain Solutions Developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,18 +6,81 @@ #include "rpcprotocol.h" #include "rpcserver.h" +#include "primitives/transaction.h" +#include "wallet/wallet.h" #include -UniValue directoryadd(const UniValue& params, bool fHelp) { +UniValue addpublicname(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) { - throw std::runtime_error("directoryadd \nAdd directory to blockchain.\n"); + throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); + } + CharString vchObjectName = vchFromValue(params[0]); + CharString vchPrefix(INTERNAL_DOMAIN_PREFIX.begin(), INTERNAL_DOMAIN_PREFIX.end()); + CharString domainName(DEFAULT_PUBLIC_DOMAIN.begin(), DEFAULT_PUBLIC_DOMAIN.end()); + + CDynamicAddress newAddress(); + + CDirectory txDirectory; + txDirectory.DomainName = domainName; + txDirectory.ObjectName = vchObjectName; + + // TODO: Add ability to pass in the wallet address and public key + CKey privKey; + privKey.MakeNewKey(true); + CPubKey pubKey = privKey.GetPubKey(); + CharString vchPriKey(privKey.begin(), privKey.end()); + CharString vchPubKey(pubKey.begin(), pubKey.end()); + CDynamicAddress addressBDAP(pubKey.GetID()); + if (pwalletMain && !pwalletMain->AddKeyPubKey(privKey, pubKey)) + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3501 - " + _("Error adding key to wallet")); + + std::string strAddress = addressBDAP.ToString(); + CharString walletAddress(strAddress.begin(), strAddress.end()); + txDirectory.WalletAddress = walletAddress; + txDirectory.EncryptPublicKey = vchPubKey; + txDirectory.EncryptPrivateKey = vchPriKey; + txDirectory.nVersion = BDAP_TX_VERSION; + if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) + throw std::runtime_error("Failed to read from BDAP database"); + + UniValue oName(UniValue::VOBJ); + + if(!BuildBDAPJson(txDirectory, oName)) + throw std::runtime_error("Failed to read from BDAP JSON object"); + + CharString data; //TODO put serialized CDirectory in data + CScript scriptPubKey; + scriptPubKey << CScript::EncodeOP_N(OP_BDAP_NEW) << vchObjectName << OP_2DROP; + + CScript scriptData; + scriptData << OP_RETURN << data; + + std::vector vecSend; + CRecipient recipient; + CreateRecipient(scriptPubKey, recipient); + CMutableTransaction tx; + tx.nVersion = BDAP_TX_VERSION; + tx.vin.clear(); + tx.vout.clear(); + + for (auto& recp : vecSend) { + tx.vout.push_back(CTxOut(recp.nAmount, recp.scriptPubKey)); + } + + // create BDAP OP_RETURN transaction + return oName; +} + +UniValue directorylist(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 1) { + throw std::runtime_error("directorylist \nAdd directory to blockchain.\n"); } std::vector vchDirectoryName = vchFromValue(params[0]); CDirectory txDirectory; - if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_DIRECTORY_NEW)) + if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) throw std::runtime_error("Failed to read from BDAP database"); UniValue oName(UniValue::VOBJ); @@ -27,16 +90,16 @@ UniValue directoryadd(const UniValue& params, bool fHelp) { return oName; } -UniValue directorylist(const UniValue& params, bool fHelp) { +UniValue directoryupdate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) { - throw std::runtime_error("directoryadd \nAdd directory to blockchain.\n"); + throw std::runtime_error("directoryupdate \nAdd directory to blockchain.\n"); } std::vector vchDirectoryName = vchFromValue(params[0]); CDirectory txDirectory; - if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_DIRECTORY_NEW)) + if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) throw std::runtime_error("Failed to read from BDAP database"); - + UniValue oName(UniValue::VOBJ); if(!BuildBDAPJson(txDirectory, oName)) throw std::runtime_error("Failed to read from BDAP JSON object"); @@ -48,8 +111,9 @@ static const CRPCCommand commands[] = { // category name actor (function) okSafeMode #ifdef ENABLE_WALLET /* BDAP */ - { "bdap", "directoryadd", &directoryadd, true }, + { "bdap", "addpublicname", &addpublicname, true }, { "bdap", "directorylist", &directorylist, true }, + { "bdap", "directoryupdate", &directoryupdate, true }, #endif //ENABLE_WALLET }; diff --git a/src/script/script.h b/src/script/script.h index 318093c4c0..aa9c587b31 100755 --- a/src/script/script.h +++ b/src/script/script.h @@ -26,14 +26,15 @@ enum ProtocolCodes { MINT_TX = 1, DYNODE_MODFIY_TX = 2, MINING_MODIFY_TX = 3, - DIRECTORY_NEW_TX = 4, - DIRECTORY_UPDATE_TX = 5, - DIRECTORY_DELETE_TX = 6, - DIRECTORY_ACTIVATE_TX = 7, - CERTIFICATE_NEW_TX = 8, - CERTIFICATE_UPDATE_TX = 9, - CERTIFICATE_DELETE_TX = 10, - CERTIFICATE_ACTIVATE_TX = 11, + BDAP_NEW_TX = 4, + BDAP_DELETE_TX = 5, + BDAP_ACTIVATE_TX = 6, + BDAP_MODIFY_TX = 7, + BDAP_MODIFY_RDN_TX = 8, + BDAP_EXECUTE_CODE_TX = 9, + BDAP_BIND_TX = 10, + BDAP_AUDIT_TX = 11, + BDAP_VERIFICATION_TX = 12, NO_TX = 0 }; @@ -212,18 +213,14 @@ enum opcodetype OP_RELEASE_ADDRESS = 0xc8, // directory access, user identity and certificate system - OP_DIRECTORY_NEW = 0xd1, - OP_DIRECTORY_DELETE = 0xd2, - OP_DIRECTORY_PAYMENT = 0xd3, - OP_DIRECTORY_ACTIVATE = 0xd4, - OP_DIRECTORY_UPDATE = 0xd5, - OP_DIRECTORY_MULTISIG = 0xd6, - OP_CERTIFICATE_NEW = 0xd7, - OP_CERTIFICATE_UPDATE = 0xd8, - OP_CERTIFICATE_DELETE = 0xd9, - OP_CERTIFICATE_ACTIVATE = 0xda, - OP_CERTIFICATE_MULTISIG = 0xdb, - // dynamic extended reserved + OP_BDAP_NEW = 0x01, + OP_BDAP_DELETE = 0x02, + OP_BDAP_ACTIVATE = 0x03, + OP_BDAP_MODIFY = 0x04, + OP_BDAP_MODIFY_RDN = 0x05, + OP_BDAP_EXECUTE_CODE = 0x06, + OP_BDAP_BIND = 0x07, + // dynamic extended reserved OP_DYNAMIC_EXTENDED = 0x10, // invalid operation code @@ -698,45 +695,33 @@ class CScript : public CScriptBase } return false; } - + bool IsDirectoryScript(ProtocolCodes code) const { switch(code) { - case DIRECTORY_NEW_TX: - return (size() > 0 && *begin() == OP_DIRECTORY_NEW); - break; - case DIRECTORY_UPDATE_TX: - return (size() > 0 && *begin() == OP_DIRECTORY_UPDATE); + case BDAP_NEW_TX: + return (size() > 0 && *begin() == OP_BDAP_NEW); break; - case DIRECTORY_DELETE_TX: - return (size() > 0 && *begin() == OP_DIRECTORY_DELETE); + case BDAP_DELETE_TX: + return (size() > 0 && *begin() == OP_BDAP_DELETE); break; - case DIRECTORY_ACTIVATE_TX: - return (size() > 0 && *begin() == OP_DIRECTORY_ACTIVATE); + case BDAP_ACTIVATE_TX: + return (size() > 0 && *begin() == OP_BDAP_ACTIVATE); break; - default: - throw std::runtime_error("Directory code is invalid!"); - } - return false; - } - - bool IsCertificateScript(ProtocolCodes code) const - { - switch(code) { - case CERTIFICATE_NEW_TX: - return (size() > 0 && *begin() == OP_CERTIFICATE_NEW); + case BDAP_MODIFY_TX: + return (size() > 0 && *begin() == OP_BDAP_MODIFY); break; - case CERTIFICATE_UPDATE_TX: - return (size() > 0 && *begin() == OP_CERTIFICATE_UPDATE); + case BDAP_MODIFY_RDN_TX: + return (size() > 0 && *begin() == OP_BDAP_MODIFY_RDN); break; - case CERTIFICATE_DELETE_TX: - return (size() > 0 && *begin() == OP_CERTIFICATE_DELETE); + case BDAP_EXECUTE_CODE_TX: + return (size() > 0 && *begin() == OP_BDAP_EXECUTE_CODE); break; - case CERTIFICATE_ACTIVATE_TX: - return (size() > 0 && *begin() == OP_CERTIFICATE_ACTIVATE); + case BDAP_BIND_TX: + return (size() > 0 && *begin() == OP_BDAP_BIND); break; default: - throw std::runtime_error("Certificate code is invalid!"); + throw std::runtime_error("BDAP code is invalid!"); } return false; } From 41ba18e83ffa486b61a82325c3290afcaa3d2c73 Mon Sep 17 00:00:00 2001 From: amirabrams Date: Mon, 18 Jun 2018 18:26:34 -0500 Subject: [PATCH 0007/1653] [BDAP] addpublicname continued work --- src/directory.cpp | 35 ++++++++++++++++---- src/directory.h | 37 +++++++++++---------- src/rpcdirectory.cpp | 76 ++++++++++++++++++++++++++++++++------------ 3 files changed, 105 insertions(+), 43 deletions(-) diff --git a/src/directory.cpp b/src/directory.cpp index 0da9173455..7e4467075d 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -170,14 +170,12 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) oName.push_back(Pair("object_name", stringFromVch(directory.ObjectName))); oName.push_back(Pair("object_full_path", stringFromVch(directory.ObjectName) + "@" + stringFromVch(directory.DomainName))); oName.push_back(Pair("object_type", directory.ObjectType)); - oName.push_back(Pair("address", EncodeBase58(directory.WalletAddress))); + oName.push_back(Pair("wallet_address", stringFromVch(directory.WalletAddress))); + oName.push_back(Pair("signature_address", stringFromVch(directory.SignWalletAddress))); oName.push_back(Pair("public", (int)directory.fPublicObject)); - //loop SignWalletAddresses - //oName.push_back(Pair("sign address", EncodeBase58(directory.SignWalletAddresses))); - oName.push_back(Pair("encryption_publickey", HexStr(directory.EncryptPublicKey))); - oName.push_back(Pair("encryption_privatekey", HexStr(directory.EncryptPrivateKey))); - //oName.push_back(Pair("sigatures_required", directory.nSigaturesRequired)); + oName.push_back(Pair("encryption_privatekey", stringFromVch(directory.EncryptPrivateKey))); + oName.push_back(Pair("sigatures_required", (int)directory.nSigaturesRequired)); oName.push_back(Pair("resource_pointer", stringFromVch(directory.ResourcePointer))); oName.push_back(Pair("txid", directory.txHash.GetHex())); if ((unsigned int)chainActive.Height() >= directory.nHeight-1) { @@ -234,6 +232,31 @@ CAmount GetDataFee(const CScript& scriptPubKey) return recp.nAmount; } +void ToLowerCase(CharString& vchValue) { + std::string strValue; + CharString::const_iterator vi = vchValue.begin(); + while (vi != vchValue.end()) + { + strValue += std::tolower(*vi); + vi++; + } + CharString vchNewValue(strValue.begin(), strValue.end()); + std::swap(vchValue, vchNewValue); +} + +void ToLowerCase(std::string& strValue) { + for(unsigned short loop=0;loop < strValue.size();loop++) + { + strValue[loop]=std::tolower(strValue[loop]); + } +} + +bool CheckIfNameExists(const CharString& vchObjectName, const CharString& vchDomainName) { + + + return false; +} + /* SignWalletAddresses.clear(); transactionFee = 0; diff --git a/src/directory.h b/src/directory.h index c2dfca5b9c..fbc35188bb 100644 --- a/src/directory.h +++ b/src/directory.h @@ -24,15 +24,15 @@ typedef std::vector vchCharString; typedef std::vector > vCheckPoints; // << height, block hash >> static const unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) -static const unsigned int MAX_DOMAIN_NAME_SIZE = 32; -static const unsigned int MAX_ACCOUNT_NAME_SIZE = 32; -static const unsigned int MAX_TORRENT_NETWORK_LENGTH = 128; +static const unsigned int MAX_DOMAIN_NAME_LENGTH = 128; +static const unsigned int MAX_OBJECT_NAME_LENGTH = 128; +static const unsigned int MAX_RESOURCE_POINTER_LENGTH = 128; static const unsigned int MAX_KEY_LENGTH = 156; static const unsigned int MAX_PUBLIC_VALUE_LENGTH = 512; -static const unsigned int MAX_SECRET_VALUE_LENGTH = 49152; // Pay per byte for hosting on chain -static const std::string INTERNAL_DOMAIN_PREFIX = "#"; -static const std::string DEFAULT_ADMIN_DOMAIN = "admin.bdap"; -static const std::string DEFAULT_PUBLIC_DOMAIN = "public.bdap"; +static const unsigned int MAX_SECRET_VALUE_LENGTH = 512; // Pay per byte for hosting on chain +static const unsigned int MAX_NUMBER_CHECKPOINTS = 1000; // Pay per byte for hosting on chain +static const std::string DEFAULT_ADMIN_DOMAIN = "admin.bdap.io"; +static const std::string DEFAULT_PUBLIC_DOMAIN = "public.bdap.io"; static const int BDAP_TX_VERSION = 0x3500; enum DirectoryObjectType { @@ -49,6 +49,7 @@ enum DirectoryObjectType { /* Blockchain Directory Access Framework ***** Design Notes ***** +- BDAP root DNS entry is bdap.io. It hosts the root public and admin domains for the BDAP system. - Modeling after X.500 Directory and LDAP (RFC 4512): https://docs.ldap.com/specs/rfc4512.txt - Top level domain objects do not have an ObjectName and are considered controlers. - OID canonical identifiers like 1.23.456.7.89 @@ -76,13 +77,13 @@ class CDirectory { CharString DomainName; // required. controls child objects CharString ObjectName; // blank for top level domain directories DirectoryObjectType ObjectType; // see enum above - CharString WalletAddress; // used to send collateral funds for this directory record. This is the multisig wallet address made from the SignWalletAddresses - unsigned int fPublicObject; // public and private visibility is relative to other objects in its domain directory + CharString WalletAddress; // used to send collateral funds for this directory record. + int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. CharString EncryptPrivateKey; // used to decrypt messages and data for this directory record - vchCharString SignWalletAddresses; // used to verify authorized update transaction - unsigned int nSigaturesRequired; // number of SignWalletAddresses needed to sign a transaction. Default = 1 - CharString ResourcePointer; // used for temp storage and transmision of sharded and encrypted data. + CharString SignWalletAddress; // used to verify authorized update transaction + unsigned int nSigaturesRequired; // number of signatures needed to approve a transaction. Default = 1 + CharString ResourcePointer; // used to point to a domain shared resource like a stream (video, audio, file sharing), P2P storage (BitTorrent or IPFS network), or private cloud storage uint256 txHash; @@ -115,7 +116,7 @@ class CDirectory { fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); EncryptPrivateKey.clear(); - SignWalletAddresses.clear(); + SignWalletAddress.clear(); nSigaturesRequired = 1; ResourcePointer.clear(); txHash.SetNull(); @@ -141,7 +142,7 @@ class CDirectory { READWRITE(VARINT(fPublicObject)); READWRITE(EncryptPublicKey); READWRITE(EncryptPrivateKey); - READWRITE(SignWalletAddresses); + READWRITE(SignWalletAddress); READWRITE(VARINT(nSigaturesRequired)); READWRITE(ResourcePointer); READWRITE(VARINT(nHeight)); @@ -171,7 +172,7 @@ class CDirectory { fPublicObject = b.fPublicObject; EncryptPublicKey = b.EncryptPublicKey; EncryptPrivateKey = b.EncryptPrivateKey; - SignWalletAddresses = b.SignWalletAddresses; + SignWalletAddress = b.SignWalletAddress; nSigaturesRequired = b.nSigaturesRequired; ResourcePointer = b.ResourcePointer; txHash = b.txHash; @@ -232,8 +233,10 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName); std::string stringFromVch(const CharString& vch); std::vector vchFromValue(const UniValue& value); void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); +void ToLowerCase(CharString& vchValue); +void ToLowerCase(std::string& strValue); +bool CheckIfNameExists(const CharString& vchObjectName, const CharString& vchDomainName); extern CDirectoryDB *pDirectoryDB; - -#endif // DIRECTORY_H +#endif // DIRECTORY_H \ No newline at end of file diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp index 0a3f416dbe..e3224ec194 100644 --- a/src/rpcdirectory.cpp +++ b/src/rpcdirectory.cpp @@ -11,42 +11,78 @@ #include +#include + +using namespace boost::xpressive; UniValue addpublicname(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) { throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); } + // Format object and domain names to lower case. + std::string strObjectName = params[0].get_str(); + ToLowerCase(strObjectName); CharString vchObjectName = vchFromValue(params[0]); - CharString vchPrefix(INTERNAL_DOMAIN_PREFIX.begin(), INTERNAL_DOMAIN_PREFIX.end()); - CharString domainName(DEFAULT_PUBLIC_DOMAIN.begin(), DEFAULT_PUBLIC_DOMAIN.end()); + ToLowerCase(vchObjectName); + CharString vchDomainName(DEFAULT_PUBLIC_DOMAIN.begin(), DEFAULT_PUBLIC_DOMAIN.end()); + ToLowerCase(vchDomainName); + + // Check if the new object and domain name are all alphanumeric, dash(-) or dot(.). dash and dot are not allowed as the first or last charactor. + sregex regexValidName = sregex::compile("^((?!-)[a-z0-9-]{2,128}(?AddKeyPubKey(privKey, pubKey)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3501 - " + _("Error adding key to wallet")); - - std::string strAddress = addressBDAP.ToString(); - CharString walletAddress(strAddress.begin(), strAddress.end()); - txDirectory.WalletAddress = walletAddress; - txDirectory.EncryptPublicKey = vchPubKey; - txDirectory.EncryptPrivateKey = vchPriKey; + CKey privWalletKey; + privWalletKey.MakeNewKey(true); + CPubKey pubWalletKey = privWalletKey.GetPubKey(); + CKeyID keyWalletID = pubWalletKey.GetID(); + + if (pwalletMain && !pwalletMain->AddKeyPubKey(privWalletKey, pubWalletKey)) + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Error adding receiving address key wo wallet for BDAP")); + + pwalletMain->SetAddressBook(keyWalletID, strObjectName, "receive"); + std::string strWalletAddress = CDynamicAddress(keyWalletID).ToString(); + CharString vchWalletAddress(strWalletAddress.begin(), strWalletAddress.end()); + txDirectory.WalletAddress = vchWalletAddress; + + CKey privEncryptKey; + privEncryptKey.MakeNewKey(true); + CPubKey pubEncryptKey = privEncryptKey.GetPubKey(); + std::string strPrivateEncryptKey = CDynamicSecret(privEncryptKey).ToString(); + CharString vchEncryptPriKey(strPrivateEncryptKey.begin(), strPrivateEncryptKey.end()); + CharString vchEncryptPubKey(pubEncryptKey.begin(), pubEncryptKey.end()); + if (pwalletMain && !pwalletMain->AddKeyPubKey(privEncryptKey, pubEncryptKey)) + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3503 - " + _("Error adding encrypt key to wallet for BDAP")); + + + txDirectory.EncryptPublicKey = vchEncryptPubKey; + txDirectory.EncryptPrivateKey = vchEncryptPriKey; + + CKey privSignKey; + privSignKey.MakeNewKey(true); + CPubKey pubSignKey = privSignKey.GetPubKey(); + CKeyID keySignID = pubSignKey.GetID(); + std::string strSignWalletAddress = CDynamicAddress(keySignID).ToString(); + CharString vchSignWalletAddress(strSignWalletAddress.begin(), strSignWalletAddress.end()); + + if (pwalletMain && !pwalletMain->AddKeyPubKey(privSignKey, pubSignKey)) + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3504 - " + _("Error adding signature key to wallet for BDAP")); + + txDirectory.SignWalletAddress = vchSignWalletAddress; + txDirectory.nVersion = BDAP_TX_VERSION; if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) throw std::runtime_error("Failed to read from BDAP database"); UniValue oName(UniValue::VOBJ); - if(!BuildBDAPJson(txDirectory, oName)) throw std::runtime_error("Failed to read from BDAP JSON object"); @@ -61,7 +97,7 @@ UniValue addpublicname(const UniValue& params, bool fHelp) { CRecipient recipient; CreateRecipient(scriptPubKey, recipient); CMutableTransaction tx; - tx.nVersion = BDAP_TX_VERSION; + tx.nVersion = txDirectory.nVersion; tx.vin.clear(); tx.vout.clear(); From b55deaa5d05a1aa380360a40645fb8eed4a7cd88 Mon Sep 17 00:00:00 2001 From: amirabrams Date: Wed, 20 Jun 2018 13:56:03 -0500 Subject: [PATCH 0008/1653] [BDAP] Add organizational unit and common name to class members --- src/directory.cpp | 34 +++++++++++++------ src/directory.h | 77 +++++++++++++++++++++++++++----------------- src/rpcdirectory.cpp | 53 ++++++++++++++++++------------ 3 files changed, 104 insertions(+), 60 deletions(-) diff --git a/src/directory.cpp b/src/directory.cpp index 7e4467075d..643a97c8b3 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -149,14 +149,25 @@ bool CDirectory::UnserializeFromData(const std::vector& vchData, return true; } +CDynamicAddress CDirectory::GetWalletAddress() const { + return CDynamicAddress(stringFromVch(WalletAddress)); +} + +std::string CDirectory::GetFullObjectPath() const { + return stringFromVch(ObjectID) + "@" + stringFromVch(OrganizationalUnit) + "." + stringFromVch(DomainComponent); +} + +std::vector CDirectory::vchFullObjectPath() const { + std::vector vchReturnValue(GetFullObjectPath().begin(), GetFullObjectPath().end()); + return vchReturnValue; +} + void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) { UniValue oName(UniValue::VOBJ); - std::string domainName = stringFromVch(directory.DomainName); - oName.push_back(Pair("_id", domainName)); - //CDyamicAddress address(EncodeBase58(directory.vchAddress)); - oName.push_back(Pair("domain_name", domainName)); - GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "add.directory"); - //WriteDirectoryIndexHistory(directory, op); + if (BuildBDAPJson(directory, oName)) { + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "add.directory"); + //WriteDirectoryIndexHistory(directory, op); //TODO: implement local leveldb storage. + } } bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) @@ -166,9 +177,12 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) int64_t nTime = 0; oName.push_back(Pair("_id", stringFromVch(directory.OID))); oName.push_back(Pair("version", directory.nVersion)); - oName.push_back(Pair("domain_name", stringFromVch(directory.DomainName))); - oName.push_back(Pair("object_name", stringFromVch(directory.ObjectName))); - oName.push_back(Pair("object_full_path", stringFromVch(directory.ObjectName) + "@" + stringFromVch(directory.DomainName))); + oName.push_back(Pair("domain_component", stringFromVch(directory.DomainComponent))); + oName.push_back(Pair("common_name", stringFromVch(directory.CommonName))); + oName.push_back(Pair("organizational_unit", stringFromVch(directory.OrganizationalUnit))); + oName.push_back(Pair("organization_name", stringFromVch(directory.DomainComponent))); + oName.push_back(Pair("object_id", stringFromVch(directory.ObjectID))); + oName.push_back(Pair("object_full_path", stringFromVch(directory.vchFullObjectPath()))); oName.push_back(Pair("object_type", directory.ObjectType)); oName.push_back(Pair("wallet_address", stringFromVch(directory.WalletAddress))); oName.push_back(Pair("signature_address", stringFromVch(directory.SignWalletAddress))); @@ -251,7 +265,7 @@ void ToLowerCase(std::string& strValue) { } } -bool CheckIfNameExists(const CharString& vchObjectName, const CharString& vchDomainName) { +bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrganizationalUnit, const CharString& vchDomainComponent) { return false; diff --git a/src/directory.h b/src/directory.h index fbc35188bb..8428586aaf 100644 --- a/src/directory.h +++ b/src/directory.h @@ -31,27 +31,19 @@ static const unsigned int MAX_KEY_LENGTH = 156; static const unsigned int MAX_PUBLIC_VALUE_LENGTH = 512; static const unsigned int MAX_SECRET_VALUE_LENGTH = 512; // Pay per byte for hosting on chain static const unsigned int MAX_NUMBER_CHECKPOINTS = 1000; // Pay per byte for hosting on chain -static const std::string DEFAULT_ADMIN_DOMAIN = "admin.bdap.io"; -static const std::string DEFAULT_PUBLIC_DOMAIN = "public.bdap.io"; +static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; +static const std::string DEFAULT_PUBLIC_OU = "public"; +static const std::string DEFAULT_ADMIN_OU = "admin"; +static const std::string DEFAULT_ORGANIZATION_NAME = "Duality Blockchain Solutions"; +static const std::string DEFAULT_OID_PREFIX = "0.0.0"; //TODO. Get a real OID prefix. static const int BDAP_TX_VERSION = 0x3500; -enum DirectoryObjectType { - USER_ACCOUNT = 0, - DEVICE_ACCOUNT = 1, - GROUP = 2, - DOMAIN_ACCOUNT = 3, - ORGANIZATIONAL_UNIT = 4, - CERTIFICATE = 5, - CODE = 6, - BINDING = 7 -}; - /* Blockchain Directory Access Framework ***** Design Notes ***** - BDAP root DNS entry is bdap.io. It hosts the root public and admin domains for the BDAP system. - Modeling after X.500 Directory and LDAP (RFC 4512): https://docs.ldap.com/specs/rfc4512.txt -- Top level domain objects do not have an ObjectName and are considered controlers. +- Top level domain objects do not have an ObjectID and are considered controlers. - OID canonical identifiers like 1.23.456.7.89 - Sub level directory objects need permission from parent domain object. - Top level domain objects can run side chains, sub level can with permission from parent @@ -69,13 +61,29 @@ class CDirectoryDefaultParameters { void InitialisePublicDomain(); //DEFAULT_PUBLIC_DOMAIN }; +enum DirectoryObjectType { + USER_ACCOUNT = 0, + DEVICE_ACCOUNT = 1, + GROUP = 2, + DOMAIN_ACCOUNT = 3, + ORGANIZATIONAL_UNIT = 4, + CERTIFICATE = 5, + CODE = 6, + BINDING = 7 +}; + +// See LDAP Distinguished Name class CDirectory { public: - static const int CURRENT_VERSION=1; + static const int CURRENT_VERSION=3; int nVersion; CharString OID; // Canonical Object ID - CharString DomainName; // required. controls child objects - CharString ObjectName; // blank for top level domain directories + //CN=John Smith,OU=Public,DC=BDAP,DC=IO, O=Duality Blockchain Solutions, UID=johnsmith21 + CharString DomainComponent; // DC. Like DC=bdap.io. required. controls child objects + CharString CommonName; // CN. Like CN=John Smith + CharString OrganizationalUnit; // OU. Like OU=sales. blank for top level domain directories + CharString OrganizationName; // O. Like Duality Blockchain Solutions + CharString ObjectID; // UID. Like johnsmith21. blank for top level domain directories DirectoryObjectType ObjectType; // see enum above CharString WalletAddress; // used to send collateral funds for this directory record. int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory @@ -109,8 +117,11 @@ class CDirectory { { nVersion = CDirectory::CURRENT_VERSION; OID.clear(); - DomainName.clear(); - ObjectName.clear(); + DomainComponent.clear(); + CommonName.clear(); + OrganizationalUnit.clear(); + OrganizationName.clear(); + ObjectID.clear(); ObjectType = DirectoryObjectType::DOMAIN_ACCOUNT; WalletAddress.clear(); fPublicObject = 0; // by default set to private visibility. @@ -135,8 +146,11 @@ class CDirectory { READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(OID); - READWRITE(DomainName); - READWRITE(ObjectName); + READWRITE(DomainComponent); + READWRITE(CommonName); + READWRITE(OrganizationalUnit); + READWRITE(OrganizationName); + READWRITE(ObjectID); //READWRITE(static_cast(ObjectType)); READWRITE(WalletAddress); READWRITE(VARINT(fPublicObject)); @@ -156,7 +170,7 @@ class CDirectory { } inline friend bool operator==(const CDirectory &a, const CDirectory &b) { - return (a.OID == b.OID && a.DomainName == b.DomainName && a.ObjectName == b.ObjectName); + return (a.OID == b.OID && a.DomainComponent == b.DomainComponent && a.OrganizationalUnit == b.OrganizationalUnit && a.ObjectID == b.ObjectID); } inline friend bool operator!=(const CDirectory &a, const CDirectory &b) { @@ -165,8 +179,11 @@ class CDirectory { inline CDirectory operator=(const CDirectory &b) { OID = b.OID; - DomainName = b.DomainName; - ObjectName = b.ObjectName; + DomainComponent = b.DomainComponent; + CommonName = b.CommonName; + OrganizationalUnit = b.OrganizationalUnit; + OrganizationName = b.OrganizationName; + ObjectID = b.ObjectID; ObjectType = b.ObjectType; WalletAddress = b.WalletAddress; fPublicObject = b.fPublicObject; @@ -184,12 +201,14 @@ class CDirectory { return *this; } - inline bool IsNull() const { return (DomainName.empty()); } + inline bool IsNull() const { return (DomainComponent.empty()); } bool UnserializeFromTx(const CTransaction &tx); bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); void Serialize(std::vector& vchData); - CDynamicAddress GetWalletAddress(); + CDynamicAddress GetWalletAddress() const; + std::string GetFullObjectPath() const; + std::vector vchFullObjectPath() const; }; class CDirectoryDB : public CDBWrapper { @@ -200,8 +219,8 @@ class CDirectoryDB : public CDBWrapper { // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare bool AddDirectory(const CDirectory& directory, const int& op) { - bool writeState = Write(make_pair(std::string("domain_name"), directory.DomainName), directory) - && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.DomainName); + bool writeState = Write(make_pair(std::string("domain_component"), directory.DomainComponent), directory) + && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.DomainComponent); AddDirectoryIndex(directory, op); return writeState; @@ -235,7 +254,7 @@ std::vector vchFromValue(const UniValue& value); void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); void ToLowerCase(CharString& vchValue); void ToLowerCase(std::string& strValue); -bool CheckIfNameExists(const CharString& vchObjectName, const CharString& vchDomainName); +bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrganizationalUnit, const CharString& vchDomainComponent); extern CDirectoryDB *pDirectoryDB; diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp index e3224ec194..deca5cd3a8 100644 --- a/src/rpcdirectory.cpp +++ b/src/rpcdirectory.cpp @@ -16,27 +16,38 @@ using namespace boost::xpressive; UniValue addpublicname(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 1) { - throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); + if (fHelp || params.size() != 2) { + throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); } - // Format object and domain names to lower case. - std::string strObjectName = params[0].get_str(); - ToLowerCase(strObjectName); - CharString vchObjectName = vchFromValue(params[0]); - ToLowerCase(vchObjectName); - CharString vchDomainName(DEFAULT_PUBLIC_DOMAIN.begin(), DEFAULT_PUBLIC_DOMAIN.end()); - ToLowerCase(vchDomainName); - - // Check if the new object and domain name are all alphanumeric, dash(-) or dot(.). dash and dot are not allowed as the first or last charactor. - sregex regexValidName = sregex::compile("^((?!-)[a-z0-9-]{2,128}(?AddKeyPubKey(privWalletKey, pubWalletKey)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Error adding receiving address key wo wallet for BDAP")); - pwalletMain->SetAddressBook(keyWalletID, strObjectName, "receive"); + pwalletMain->SetAddressBook(keyWalletID, strObjectID, "receive"); std::string strWalletAddress = CDynamicAddress(keyWalletID).ToString(); CharString vchWalletAddress(strWalletAddress.begin(), strWalletAddress.end()); txDirectory.WalletAddress = vchWalletAddress; @@ -62,7 +73,6 @@ UniValue addpublicname(const UniValue& params, bool fHelp) { if (pwalletMain && !pwalletMain->AddKeyPubKey(privEncryptKey, pubEncryptKey)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3503 - " + _("Error adding encrypt key to wallet for BDAP")); - txDirectory.EncryptPublicKey = vchEncryptPubKey; txDirectory.EncryptPrivateKey = vchEncryptPriKey; @@ -80,15 +90,16 @@ UniValue addpublicname(const UniValue& params, bool fHelp) { txDirectory.nVersion = BDAP_TX_VERSION; if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) - throw std::runtime_error("Failed to read from BDAP database"); + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3505 - " + _("Failed to read from BDAP database")); UniValue oName(UniValue::VOBJ); if(!BuildBDAPJson(txDirectory, oName)) - throw std::runtime_error("Failed to read from BDAP JSON object"); + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3506 - " + _("Failed to read from BDAP JSON object")); CharString data; //TODO put serialized CDirectory in data CScript scriptPubKey; - scriptPubKey << CScript::EncodeOP_N(OP_BDAP_NEW) << vchObjectName << OP_2DROP; + std::vector vchFullObjectPath = txDirectory.vchFullObjectPath(); + scriptPubKey << CScript::EncodeOP_N(OP_BDAP_NEW) << vchFullObjectPath << OP_2DROP; CScript scriptData; scriptData << OP_RETURN << data; From 35056fefeac42d5559d947e7787a0d2712d0c2e6 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 24 Jun 2018 00:49:13 -0500 Subject: [PATCH 0009/1653] [BDAP] Fix serialize and univalue build errrors --- src/directory.h | 6 +++--- src/rpcdirectory.cpp | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/directory.h b/src/directory.h index 8428586aaf..f816fbe3a7 100644 --- a/src/directory.h +++ b/src/directory.h @@ -5,11 +5,11 @@ #ifndef DIRECTORY_H #define DIRECTORY_H +#include "serialize.h" #include "amount.h" #include "consensus/params.h" #include "dbwrapper.h" #include "script/script.h" -#include "serialize.h" #include "sync.h" #include @@ -141,10 +141,10 @@ class CDirectory { } ADD_SERIALIZE_METHODS; + template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); - nVersion = this->nVersion; READWRITE(OID); READWRITE(DomainComponent); READWRITE(CommonName); diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp index deca5cd3a8..3990a01583 100644 --- a/src/rpcdirectory.cpp +++ b/src/rpcdirectory.cpp @@ -15,13 +15,13 @@ using namespace boost::xpressive; -UniValue addpublicname(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 2) { +UniValue addpublicname(const JSONRPCRequest& request) { + if (request.params.size() != 2) { throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); } // Adds a new name to channel zero. OID = 0.0.block-height.tx-ordinal.0.0.0.0 // Format object and domain names to lower case. - std::string strObjectID = params[0].get_str(); + std::string strObjectID = request.params[0].get_str(); ToLowerCase(strObjectID); // Check if the object name is valid. sregex regexValidName = sregex::compile("^((?!-)[a-z0-9-]{2,64}(?\nAdd directory to blockchain.\n"); } - std::vector vchDirectoryName = vchFromValue(params[0]); + std::vector vchDirectoryName = vchFromValue(request.params[0]); CDirectory txDirectory; if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) throw std::runtime_error("Failed to read from BDAP database"); @@ -137,12 +137,12 @@ UniValue directorylist(const UniValue& params, bool fHelp) { return oName; } -UniValue directoryupdate(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 1) { +UniValue directoryupdate(const JSONRPCRequest& request) { + if (request.params.size() != 1) { throw std::runtime_error("directoryupdate \nAdd directory to blockchain.\n"); } - std::vector vchDirectoryName = vchFromValue(params[0]); + std::vector vchDirectoryName = vchFromValue(request.params[0]); CDirectory txDirectory; if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) throw std::runtime_error("Failed to read from BDAP database"); From b0d8cbf5bfbf231220239e10d91db6c9c80ec358 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 24 Jun 2018 02:00:42 -0500 Subject: [PATCH 0010/1653] [BDAP] Move transaction version BDAP_TX_VERSION to policy --- src/directory.h | 1 - src/policy/policy.h | 2 ++ src/rpcdirectory.cpp | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/directory.h b/src/directory.h index f816fbe3a7..13860e87f9 100644 --- a/src/directory.h +++ b/src/directory.h @@ -36,7 +36,6 @@ static const std::string DEFAULT_PUBLIC_OU = "public"; static const std::string DEFAULT_ADMIN_OU = "admin"; static const std::string DEFAULT_ORGANIZATION_NAME = "Duality Blockchain Solutions"; static const std::string DEFAULT_OID_PREFIX = "0.0.0"; //TODO. Get a real OID prefix. -static const int BDAP_TX_VERSION = 0x3500; /* Blockchain Directory Access Framework diff --git a/src/policy/policy.h b/src/policy/policy.h index cffcd9fe8d..78c0a70a35 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -49,6 +49,8 @@ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_ /** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */ static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST; +/** Used for BDAP transactions. */ +static const int BDAP_TX_VERSION = 0x3500; bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); /** diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp index 3990a01583..447bd0fef9 100644 --- a/src/rpcdirectory.cpp +++ b/src/rpcdirectory.cpp @@ -88,7 +88,6 @@ UniValue addpublicname(const JSONRPCRequest& request) { txDirectory.SignWalletAddress = vchSignWalletAddress; - txDirectory.nVersion = BDAP_TX_VERSION; if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3505 - " + _("Failed to read from BDAP database")); From b946c6e222e5ac28aae137a64de377fcc2a82b7c Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 24 Jun 2018 02:10:06 -0500 Subject: [PATCH 0011/1653] [BDAP] Rework and cleanup addpublicname RPC call --- src/directory.cpp | 11 ++++++++++ src/directory.h | 1 + src/rpcdirectory.cpp | 46 +++++++++++++++++++++++----------------- src/rpcfluid.cpp | 6 +++--- src/wallet/rpcwallet.cpp | 2 +- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/directory.cpp b/src/directory.cpp index 643a97c8b3..9e357c65cd 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -271,6 +271,17 @@ bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrgan return false; } +CAmount GetBDAPFee(const CScript& scriptPubKey) +{ + CAmount nFee = 0; + CRecipient recp = {scriptPubKey, 0, false}; + CTxOut txout(0, scriptPubKey); + size_t nSize = GetSerializeSize(txout, SER_DISK,0)+148u; + nFee = CWallet::GetMinimumFee(nSize, nTxConfirmTarget, mempool); + recp.nAmount = nFee; + return recp.nAmount; +} + /* SignWalletAddresses.clear(); transactionFee = 0; diff --git a/src/directory.h b/src/directory.h index 13860e87f9..e0b71242da 100644 --- a/src/directory.h +++ b/src/directory.h @@ -254,6 +254,7 @@ void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); void ToLowerCase(CharString& vchValue); void ToLowerCase(std::string& strValue); bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrganizationalUnit, const CharString& vchDomainComponent); +CAmount GetBDAPFee(const CScript& scriptPubKey); extern CDirectoryDB *pDirectoryDB; diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp index 447bd0fef9..d74fd0c16d 100644 --- a/src/rpcdirectory.cpp +++ b/src/rpcdirectory.cpp @@ -15,10 +15,15 @@ using namespace boost::xpressive; +extern void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false, bool fIsBDAP=false); + UniValue addpublicname(const JSONRPCRequest& request) { if (request.params.size() != 2) { throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); } + + EnsureWalletIsUnlocked(); + // Adds a new name to channel zero. OID = 0.0.block-height.tx-ordinal.0.0.0.0 // Format object and domain names to lower case. std::string strObjectID = request.params[0].get_str(); @@ -60,7 +65,8 @@ UniValue addpublicname(const JSONRPCRequest& request) { throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Error adding receiving address key wo wallet for BDAP")); pwalletMain->SetAddressBook(keyWalletID, strObjectID, "receive"); - std::string strWalletAddress = CDynamicAddress(keyWalletID).ToString(); + CDynamicAddress payWallet = CDynamicAddress(keyWalletID); + std::string strWalletAddress = payWallet.ToString(); CharString vchWalletAddress(strWalletAddress.begin(), strWalletAddress.end()); txDirectory.WalletAddress = vchWalletAddress; @@ -82,7 +88,7 @@ UniValue addpublicname(const JSONRPCRequest& request) { CKeyID keySignID = pubSignKey.GetID(); std::string strSignWalletAddress = CDynamicAddress(keySignID).ToString(); CharString vchSignWalletAddress(strSignWalletAddress.begin(), strSignWalletAddress.end()); - + if (pwalletMain && !pwalletMain->AddKeyPubKey(privSignKey, pubSignKey)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3504 - " + _("Error adding signature key to wallet for BDAP")); @@ -91,31 +97,31 @@ UniValue addpublicname(const JSONRPCRequest& request) { if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3505 - " + _("Failed to read from BDAP database")); - UniValue oName(UniValue::VOBJ); - if(!BuildBDAPJson(txDirectory, oName)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3506 - " + _("Failed to read from BDAP JSON object")); - - CharString data; //TODO put serialized CDirectory in data + CharString data; + txDirectory.Serialize(data); + + // Create BDAP OP_RETURN Signature Scripts CScript scriptPubKey; std::vector vchFullObjectPath = txDirectory.vchFullObjectPath(); scriptPubKey << CScript::EncodeOP_N(OP_BDAP_NEW) << vchFullObjectPath << OP_2DROP; - + CScript scriptDestination; + scriptDestination = GetScriptForDestination(payWallet.Get()); + scriptPubKey += scriptDestination; + CScript scriptData; scriptData << OP_RETURN << data; + scriptPubKey += scriptData; - std::vector vecSend; - CRecipient recipient; - CreateRecipient(scriptPubKey, recipient); - CMutableTransaction tx; - tx.nVersion = txDirectory.nVersion; - tx.vin.clear(); - tx.vout.clear(); + // Send the transaction + float fYears = 1.0; //TODO use a variable for registration years. + CWalletTx wtx; + SendCustomTransaction(scriptPubKey, wtx, GetBDAPFee(scriptPubKey) * powf(3.1, fYears), true); + txDirectory.txHash = wtx.GetHash(); + + UniValue oName(UniValue::VOBJ); + if(!BuildBDAPJson(txDirectory, oName)) + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3506 - " + _("Failed to read from BDAP JSON object")); - for (auto& recp : vecSend) { - tx.vout.push_back(CTxOut(recp.nAmount, recp.scriptPubKey)); - } - - // create BDAP OP_RETURN transaction return oName; } diff --git a/src/rpcfluid.cpp b/src/rpcfluid.cpp index 9f83768fdb..a3489804d9 100644 --- a/src/rpcfluid.cpp +++ b/src/rpcfluid.cpp @@ -20,7 +20,7 @@ #include extern bool EnsureWalletIsAvailable(bool avoidException); -extern void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false); +extern void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false, bool fIsBDAP=false); opcodetype getOpcodeFromString(std::string input) { if (input == "OP_MINT") return OP_MINT; @@ -126,7 +126,7 @@ UniValue burndynamic(const UniValue& params, bool fHelp) CScript destroyScript = CScript() << OP_RETURN << ParseHex(result); - SendCustomTransaction(destroyScript, wtx, nAmount); + SendCustomTransaction(destroyScript, wtx, nAmount, false); return wtx.GetHash().GetHex(); } @@ -170,7 +170,7 @@ UniValue sendfluidtransaction(const JSONRPCRequest& request) if (opcode == OP_MINT || opcode == OP_REWARD_MINING || opcode == OP_REWARD_DYNODE) { CWalletTx wtx; - SendCustomTransaction(finalScript, wtx, fluid.FLUID_TRANSACTION_COST); + SendCustomTransaction(finalScript, wtx, fluid.FLUID_TRANSACTION_COST, false); return wtx.GetHash().GetHex(); } else { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e425c80206..0f1e302a1d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -405,7 +405,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr } } -void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false) +void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false, bool fIsBDAP=false) { CAmount curBalance = pwalletMain->GetBalance(); From 627ef1443a4545bfbbed8868b50a1ee3cb2400c0 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 24 Jun 2018 02:22:58 -0500 Subject: [PATCH 0012/1653] [BDAP] Update IsStandard functions to accept large BDAP txs --- src/policy/policy.cpp | 10 ++++++++-- src/script/standard.h | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index ce17395e9d..80d5746b23 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -47,7 +47,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) if (m < 1 || m > n) return false; } else if (whichType == TX_NULL_DATA && - (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) + (!fAcceptDatacarrier || scriptPubKey.size() > MAX_BDAP_RELAY)) return false; return whichType != TX_NONSTANDARD; @@ -97,8 +97,14 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason) return false; } - if (whichType == TX_NULL_DATA) + if (whichType == TX_NULL_DATA) { + // if this null data tx is not a BDAP and is larger than the max datacarrier, then return a non-standard transaction + if (tx.nVersion != BDAP_TX_VERSION && txout.scriptPubKey.size() > nMaxDatacarrierBytes) { + reason = "scriptpubkey"; + return false; + } nDataOut++; + } else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) { reason = "bare-multisig"; return false; diff --git a/src/script/standard.h b/src/script/standard.h index 889141ed5b..c888b933d8 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -27,7 +27,8 @@ class CScriptID : public uint160 CScriptID(const uint160& in) : uint160(in) {} }; -static const unsigned int MAX_OP_RETURN_RELAY = 2051; //! bytes (+1 for OP_RETURN, +2 for the pushdata opcodes, +2048 for BDAP data) +static const unsigned int MAX_OP_RETURN_RELAY = 83; //! bytes (+1 for OP_RETURN, +2 for the push data opcodes) +static const unsigned int MAX_BDAP_RELAY = 2051; //! bytes (+1 for OP_RETURN, +2 for the push data opcodes and +2048) extern bool fAcceptDatacarrier; extern unsigned nMaxDatacarrierBytes; From 8cf35dc5ad17315c7cfe45582d6d284437ba8b14 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 24 Jun 2018 02:29:56 -0500 Subject: [PATCH 0013/1653] [BDAP] Add revoke op code OP_BDAP_REVOKE --- src/directory.cpp | 1 + src/script/script.h | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/directory.cpp b/src/directory.cpp index 9e357c65cd..171847a366 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -24,6 +24,7 @@ bool IsDirectoryTransaction(CScript txOut) { || txOut.IsDirectoryScript(BDAP_MODIFY_RDN_TX) || txOut.IsDirectoryScript(BDAP_EXECUTE_CODE_TX) || txOut.IsDirectoryScript(BDAP_BIND_TX) + || txOut.IsDirectoryScript(BDAP_REVOKE_TX) ); } diff --git a/src/script/script.h b/src/script/script.h index aa9c587b31..79f588fa20 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -21,7 +21,7 @@ #include #include -// Identification codes for Fluid Protocol Transactions +// Identification codes for Fluid and BDAP Transactions enum ProtocolCodes { MINT_TX = 1, DYNODE_MODFIY_TX = 2, @@ -35,6 +35,7 @@ enum ProtocolCodes { BDAP_BIND_TX = 10, BDAP_AUDIT_TX = 11, BDAP_VERIFICATION_TX = 12, + BDAP_REVOKE_TX = 13, NO_TX = 0 }; @@ -220,6 +221,7 @@ enum opcodetype OP_BDAP_MODIFY_RDN = 0x05, OP_BDAP_EXECUTE_CODE = 0x06, OP_BDAP_BIND = 0x07, + OP_BDAP_REVOKE = 0x08, // dynamic extended reserved OP_DYNAMIC_EXTENDED = 0x10, @@ -720,6 +722,9 @@ class CScript : public CScriptBase case BDAP_BIND_TX: return (size() > 0 && *begin() == OP_BDAP_BIND); break; + case BDAP_REVOKE_TX: + return (size() > 0 && *begin() == OP_BDAP_REVOKE); + break; default: throw std::runtime_error("BDAP code is invalid!"); } From fa0c5a1528b6e080bda8df4ba8c5c71d3273418f Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 24 Jun 2018 03:06:08 -0500 Subject: [PATCH 0014/1653] [BDAP] Use special version when creating BDAP transactions --- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 6 +++++- src/wallet/wallet.h | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0f1e302a1d..f9539c7f51 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -431,7 +431,7 @@ void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAm vecSend.push_back(recipient); if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, - strError, NULL, true, ALL_COINS, false)) { + strError, NULL, true, ALL_COINS, false, fIsBDAP)) { if (nValue + nFeeRequired > pwalletMain->GetBalance()) strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b044ee4825..90b74622db 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3259,7 +3259,7 @@ bool CWallet::ConvertList(std::vector vecTxIn, std::vector& vecA } bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, - int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign, AvailableCoinsType nCoinType, bool fUseInstantSend) + int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign, AvailableCoinsType nCoinType, bool fUseInstantSend, bool fIsBDAP) { CAmount nFeePay = fUseInstantSend ? CTxLockRequest().GetMinFee() : 0; @@ -3287,6 +3287,10 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT wtxNew.BindWallet(this); CMutableTransaction txNew; + // Use special version number when creating a BDAP transaction + if (fIsBDAP) + txNew.nVersion = BDAP_TX_VERSION; + // Discourage fee sniping. // // For a large miner the value of the transactions in the best block and diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4bfb9b6fc4..128d50c124 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -820,7 +820,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface * selected by SelectCoins(); Also create the change output, when needed */ bool CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, - std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend=false); + std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend=false, bool fIsBDAP=false); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state, const std::string& strCommand="tx"); bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason); From 908318c8de93300e2a418e4345582ad8510aa3ed Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 24 Jun 2018 03:50:55 -0500 Subject: [PATCH 0015/1653] [BDAP] Remove OP_RETURN script from BDAP transactions in Solver --- src/script/script.cpp | 73 +++++++++++++++++++++++++++++++++++++++++ src/script/script.h | 6 ++++ src/script/standard.cpp | 12 ++++++- 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/script/script.cpp b/src/script/script.cpp index 514656301f..1a0d1eede1 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -249,3 +249,76 @@ bool CScript::IsPushOnly() const { return this->IsPushOnly(begin()); } + +bool IsDirectoryOp(int op) +{ + return op == OP_BDAP_NEW + || op == OP_BDAP_DELETE + || op == OP_BDAP_ACTIVATE + || op == OP_BDAP_MODIFY + || op == OP_BDAP_MODIFY_RDN + || op == OP_BDAP_EXECUTE_CODE + || op == OP_BDAP_BIND + || op == OP_BDAP_REVOKE; +} + +bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch, CScript::const_iterator& pc) +{ + opcodetype opcode; + vvch.clear(); + if (!script.GetOp(pc, opcode)) + return false; + if (opcode < OP_1 || opcode > OP_16) + return false; + op = CScript::DecodeOP_N(opcode); + if (op != OP_BDAP_NEW) + return false; + if (!script.GetOp(pc, opcode)) + return false; + if (opcode < OP_1 || opcode > OP_16) + return false; + op = CScript::DecodeOP_N(opcode); + if (!IsDirectoryOp(op)) + return false; + bool found = false; + for (;;) { + std::vector vch; + if (!script.GetOp(pc, opcode, vch)) + return false; + if (opcode == OP_DROP || opcode == OP_2DROP) + { + found = true; + break; + } + if (!(opcode >= 0 && opcode <= OP_PUSHDATA4)) + return false; + vvch.push_back(vch); + } + + // move the pc to after any DROP or NOP + while (opcode == OP_DROP || opcode == OP_2DROP) { + if (!script.GetOp(pc, opcode)) + break; + } + + pc--; + return found; +} + +bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch) +{ + CScript::const_iterator pc = script.begin(); + return DecodeBDAPScript(script, op, vvch, pc); +} + +bool RemoveBDAPScript(const CScript& scriptIn, CScript& scriptOut) +{ + int op; + std::vector > vvch; + CScript::const_iterator pc = scriptIn.begin(); + + if (!DecodeBDAPScript(scriptIn, op, vvch, pc)) + return false; + scriptOut = CScript(pc, scriptIn.end()); + return true; +} \ No newline at end of file diff --git a/src/script/script.h b/src/script/script.h index 79f588fa20..bd085f0ed0 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -747,4 +747,10 @@ class CReserveScript virtual ~CReserveScript() {} }; +// TODO: Use a seperate code file for these BDAP functions +bool IsDirectoryOp(int op); +bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch, CScript::const_iterator& pc); +bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch); +bool RemoveBDAPScript(const CScript& scriptIn, CScript& scriptOut); + #endif // DYNAMIC_SCRIPT_SCRIPT_H diff --git a/src/script/standard.cpp b/src/script/standard.cpp index e20269afb2..dfa1e00024 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -36,7 +36,7 @@ const char* GetTxnOutputType(txnouttype t) /** * Return public keys or hashes from scriptPubKey, for 'standard' transaction types. */ -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet) +bool Solver(const CScript& scriptPubKeyIn, txnouttype& typeRet, std::vector >& vSolutionsRet) { // Templates static std::multimap mTemplates; @@ -54,6 +54,16 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector Date: Sun, 24 Jun 2018 04:45:01 -0500 Subject: [PATCH 0016/1653] [BDAP] Fix full object path vector --- src/directory.cpp | 3 ++- src/directory.h | 2 +- src/script/standard.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/directory.cpp b/src/directory.cpp index 171847a366..0b338cebff 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -159,7 +159,8 @@ std::string CDirectory::GetFullObjectPath() const { } std::vector CDirectory::vchFullObjectPath() const { - std::vector vchReturnValue(GetFullObjectPath().begin(), GetFullObjectPath().end()); + std::string strFullObjectPath = GetFullObjectPath(); + std::vector vchReturnValue(strFullObjectPath.begin(), strFullObjectPath.end()); return vchReturnValue; } diff --git a/src/directory.h b/src/directory.h index e0b71242da..3aa1d9d812 100644 --- a/src/directory.h +++ b/src/directory.h @@ -5,11 +5,11 @@ #ifndef DIRECTORY_H #define DIRECTORY_H -#include "serialize.h" #include "amount.h" #include "consensus/params.h" #include "dbwrapper.h" #include "script/script.h" +#include "serialize.h" #include "sync.h" #include diff --git a/src/script/standard.h b/src/script/standard.h index c888b933d8..25ac67450f 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -71,7 +71,7 @@ typedef boost::variant CTxDestination; const char* GetTxnOutputType(txnouttype t); -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet); +bool Solver(const CScript& scriptPubKeyIn, txnouttype& typeRet, std::vector >& vSolutionsRet); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); From ce9faedb7833935fa0078f6f67581fdc60e1c0a0 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 24 Jun 2018 17:45:11 -0500 Subject: [PATCH 0017/1653] [BDAP] Fix parameters when calling SendCustomTransaction for BDAP txs --- src/rpcdirectory.cpp | 2 +- src/rpcfluid.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp index d74fd0c16d..9e1fa58755 100644 --- a/src/rpcdirectory.cpp +++ b/src/rpcdirectory.cpp @@ -115,7 +115,7 @@ UniValue addpublicname(const JSONRPCRequest& request) { // Send the transaction float fYears = 1.0; //TODO use a variable for registration years. CWalletTx wtx; - SendCustomTransaction(scriptPubKey, wtx, GetBDAPFee(scriptPubKey) * powf(3.1, fYears), true); + SendCustomTransaction(scriptPubKey, wtx, GetBDAPFee(scriptPubKey) * powf(3.1, fYears), false, true); txDirectory.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); diff --git a/src/rpcfluid.cpp b/src/rpcfluid.cpp index a3489804d9..4745ecd479 100644 --- a/src/rpcfluid.cpp +++ b/src/rpcfluid.cpp @@ -126,7 +126,7 @@ UniValue burndynamic(const UniValue& params, bool fHelp) CScript destroyScript = CScript() << OP_RETURN << ParseHex(result); - SendCustomTransaction(destroyScript, wtx, nAmount, false); + SendCustomTransaction(destroyScript, wtx, nAmount, false, false); return wtx.GetHash().GetHex(); } @@ -170,7 +170,7 @@ UniValue sendfluidtransaction(const JSONRPCRequest& request) if (opcode == OP_MINT || opcode == OP_REWARD_MINING || opcode == OP_REWARD_DYNODE) { CWalletTx wtx; - SendCustomTransaction(finalScript, wtx, fluid.FLUID_TRANSACTION_COST, false); + SendCustomTransaction(finalScript, wtx, fluid.FLUID_TRANSACTION_COST, false, false); return wtx.GetHash().GetHex(); } else { From 3a8ff6362164396b5438615ba4dddad16ca2b5f4 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Sun, 24 Jun 2018 19:58:52 -0500 Subject: [PATCH 0018/1653] [BDAP] Allow BDAP version transactions in mem pool validation --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 2d62a5af62..087f394715 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -625,7 +625,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // sure that such transactions will be mined (unless we're on // -testnet/-regtest). const CChainParams& chainparams = Params(); - if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) { + if (fRequireStandard && tx.nVersion >= 2 && tx.nVersion != BDAP_TX_VERSION && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) { return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx"); } From b0df80a51b1c30b2b1880aeefb6d6df5402bd427 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Mon, 25 Jun 2018 17:40:45 -0500 Subject: [PATCH 0019/1653] [BDAP] Add version check to IsStandardTx --- src/policy/policy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 80d5746b23..512edbfdd5 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -55,7 +55,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) bool IsStandardTx(const CTransaction& tx, std::string& reason) { - if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) { + if ((tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) && tx.nVersion != BDAP_TX_VERSION) { reason = "version"; return false; } From d4edc0469065836ff8049b9ed3ce3d20f1a1ceb8 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Tue, 26 Jun 2018 12:35:32 -0500 Subject: [PATCH 0020/1653] [BDAP] Add op codes to GetOpName --- src/script/script.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/script/script.cpp b/src/script/script.cpp index 1a0d1eede1..85c1bb6865 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -148,6 +148,16 @@ const char* GetOpName(opcodetype opcode) case OP_FREEZE_ADDRESS : return "OP_FREEZE_ADDRESS"; case OP_RELEASE_ADDRESS : return "OP_RELEASE_ADDRESS"; + // BDAP, directory access, user identity and certificate system + case OP_BDAP_NEW : return "OP_BDAP_NEW"; + case OP_BDAP_DELETE : return "OP_BDAP_DELETE"; + case OP_BDAP_ACTIVATE : return "OP_BDAP_ACTIVATE"; + case OP_BDAP_MODIFY : return "OP_BDAP_MODIFY"; + case OP_BDAP_MODIFY_RDN : return "OP_BDAP_MODIFY_RDN"; + case OP_BDAP_EXECUTE_CODE : return "OP_BDAP_EXECUTE_CODE"; + case OP_BDAP_BIND : return "OP_BDAP_BIND"; + case OP_BDAP_REVOKE : return "OP_BDAP_REVOKE"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; // Note: From 2dcf6bfb423db306c18cb61de1d0e940479328c2 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Tue, 26 Jun 2018 20:40:37 -0500 Subject: [PATCH 0021/1653] [BDAP] Add start op code for DBAP --- src/directory.cpp | 3 ++- src/script/script.cpp | 6 ++++-- src/script/script.h | 41 +++++++++++++++++++++++------------------ 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/directory.cpp b/src/directory.cpp index 0b338cebff..7924ac4250 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -17,7 +17,8 @@ CDirectoryDB *pDirectoryDB = NULL; bool IsDirectoryTransaction(CScript txOut) { - return (txOut.IsDirectoryScript(BDAP_NEW_TX) + return (txOut.IsDirectoryScript(BDAP_START) + || txOut.IsDirectoryScript(BDAP_NEW_TX) || txOut.IsDirectoryScript(BDAP_DELETE_TX) || txOut.IsDirectoryScript(BDAP_ACTIVATE_TX) || txOut.IsDirectoryScript(BDAP_MODIFY_TX) diff --git a/src/script/script.cpp b/src/script/script.cpp index 85c1bb6865..ff854c2f08 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -149,6 +149,7 @@ const char* GetOpName(opcodetype opcode) case OP_RELEASE_ADDRESS : return "OP_RELEASE_ADDRESS"; // BDAP, directory access, user identity and certificate system + case OP_BDAP : return "OP_BDAP"; case OP_BDAP_NEW : return "OP_BDAP_NEW"; case OP_BDAP_DELETE : return "OP_BDAP_DELETE"; case OP_BDAP_ACTIVATE : return "OP_BDAP_ACTIVATE"; @@ -262,7 +263,8 @@ bool CScript::IsPushOnly() const bool IsDirectoryOp(int op) { - return op == OP_BDAP_NEW + return op == OP_BDAP + || op == OP_BDAP_NEW || op == OP_BDAP_DELETE || op == OP_BDAP_ACTIVATE || op == OP_BDAP_MODIFY @@ -281,7 +283,7 @@ bool DecodeBDAPScript(const CScript& script, int& op, std::vector OP_16) return false; op = CScript::DecodeOP_N(opcode); - if (op != OP_BDAP_NEW) + if (op != OP_BDAP) return false; if (!script.GetOp(pc, opcode)) return false; diff --git a/src/script/script.h b/src/script/script.h index bd085f0ed0..0d8848397f 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -26,16 +26,17 @@ enum ProtocolCodes { MINT_TX = 1, DYNODE_MODFIY_TX = 2, MINING_MODIFY_TX = 3, - BDAP_NEW_TX = 4, - BDAP_DELETE_TX = 5, - BDAP_ACTIVATE_TX = 6, - BDAP_MODIFY_TX = 7, - BDAP_MODIFY_RDN_TX = 8, - BDAP_EXECUTE_CODE_TX = 9, - BDAP_BIND_TX = 10, - BDAP_AUDIT_TX = 11, - BDAP_VERIFICATION_TX = 12, - BDAP_REVOKE_TX = 13, + BDAP_START = 4, + BDAP_NEW_TX = 5, + BDAP_DELETE_TX = 6, + BDAP_ACTIVATE_TX = 7, + BDAP_MODIFY_TX = 8, + BDAP_MODIFY_RDN_TX = 9, + BDAP_EXECUTE_CODE_TX = 10, + BDAP_BIND_TX = 11, + BDAP_AUDIT_TX = 12, + BDAP_VERIFICATION_TX = 13, + BDAP_REVOKE_TX = 14, NO_TX = 0 }; @@ -214,14 +215,15 @@ enum opcodetype OP_RELEASE_ADDRESS = 0xc8, // directory access, user identity and certificate system - OP_BDAP_NEW = 0x01, - OP_BDAP_DELETE = 0x02, - OP_BDAP_ACTIVATE = 0x03, - OP_BDAP_MODIFY = 0x04, - OP_BDAP_MODIFY_RDN = 0x05, - OP_BDAP_EXECUTE_CODE = 0x06, - OP_BDAP_BIND = 0x07, - OP_BDAP_REVOKE = 0x08, + OP_BDAP = 0x01, + OP_BDAP_NEW = 0x02, + OP_BDAP_DELETE = 0x03, + OP_BDAP_ACTIVATE = 0x04, + OP_BDAP_MODIFY = 0x05, + OP_BDAP_MODIFY_RDN = 0x06, + OP_BDAP_EXECUTE_CODE = 0x07, + OP_BDAP_BIND = 0x08, + OP_BDAP_REVOKE = 0x09, // dynamic extended reserved OP_DYNAMIC_EXTENDED = 0x10, @@ -701,6 +703,9 @@ class CScript : public CScriptBase bool IsDirectoryScript(ProtocolCodes code) const { switch(code) { + case BDAP_START: + return (size() > 0 && *begin() == OP_BDAP); + break; case BDAP_NEW_TX: return (size() > 0 && *begin() == OP_BDAP_NEW); break; From 5c2305824e04e8761fe77def751f95612b32d1d0 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Tue, 26 Jun 2018 22:19:23 -0500 Subject: [PATCH 0022/1653] [BDAP] Add custom function to send BDAP txs --- src/rpcdirectory.cpp | 11 ++++++---- src/rpcfluid.cpp | 6 +++--- src/wallet/rpcwallet.cpp | 43 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/rpcdirectory.cpp b/src/rpcdirectory.cpp index 9e1fa58755..186f16d00b 100644 --- a/src/rpcdirectory.cpp +++ b/src/rpcdirectory.cpp @@ -15,7 +15,7 @@ using namespace boost::xpressive; -extern void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false, bool fIsBDAP=false); +extern void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdapOPScript, CWalletTx& wtxNew, CAmount nOPValue, CAmount nDataValue); UniValue addpublicname(const JSONRPCRequest& request) { if (request.params.size() != 2) { @@ -54,6 +54,7 @@ UniValue addpublicname(const JSONRPCRequest& request) { txDirectory.OrganizationName = vchOrganizationName; txDirectory.ObjectID = vchObjectID; txDirectory.fPublicObject = 1; //make entry public + txDirectory.transactionFee = 100; // TODO: Add ability to pass in the wallet address and public key CKey privWalletKey; @@ -103,19 +104,21 @@ UniValue addpublicname(const JSONRPCRequest& request) { // Create BDAP OP_RETURN Signature Scripts CScript scriptPubKey; std::vector vchFullObjectPath = txDirectory.vchFullObjectPath(); - scriptPubKey << CScript::EncodeOP_N(OP_BDAP_NEW) << vchFullObjectPath << OP_2DROP; + scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_NEW) << vchFullObjectPath << OP_2DROP << OP_DROP; + CScript scriptDestination; scriptDestination = GetScriptForDestination(payWallet.Get()); scriptPubKey += scriptDestination; CScript scriptData; scriptData << OP_RETURN << data; - scriptPubKey += scriptData; // Send the transaction float fYears = 1.0; //TODO use a variable for registration years. CWalletTx wtx; - SendCustomTransaction(scriptPubKey, wtx, GetBDAPFee(scriptPubKey) * powf(3.1, fYears), false, true); + CAmount nOperationFee = GetBDAPFee(scriptPubKey) * powf(3.1, fYears); + CAmount nDataFee = GetBDAPFee(scriptData) * powf(3.1, fYears); + SendBDAPTransaction(scriptData, scriptPubKey, wtx, nOperationFee, nDataFee); txDirectory.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); diff --git a/src/rpcfluid.cpp b/src/rpcfluid.cpp index 4745ecd479..458428e16e 100644 --- a/src/rpcfluid.cpp +++ b/src/rpcfluid.cpp @@ -20,7 +20,7 @@ #include extern bool EnsureWalletIsAvailable(bool avoidException); -extern void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false, bool fIsBDAP=false); +extern void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false); opcodetype getOpcodeFromString(std::string input) { if (input == "OP_MINT") return OP_MINT; @@ -126,7 +126,7 @@ UniValue burndynamic(const UniValue& params, bool fHelp) CScript destroyScript = CScript() << OP_RETURN << ParseHex(result); - SendCustomTransaction(destroyScript, wtx, nAmount, false, false); + SendCustomTransaction(destroyScript, wtx, nAmount, false); return wtx.GetHash().GetHex(); } @@ -170,7 +170,7 @@ UniValue sendfluidtransaction(const JSONRPCRequest& request) if (opcode == OP_MINT || opcode == OP_REWARD_MINING || opcode == OP_REWARD_DYNODE) { CWalletTx wtx; - SendCustomTransaction(finalScript, wtx, fluid.FLUID_TRANSACTION_COST, false, false); + SendCustomTransaction(finalScript, wtx, fluid.FLUID_TRANSACTION_COST, false); return wtx.GetHash().GetHex(); } else { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f9539c7f51..34707d06a9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -405,7 +405,46 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr } } -void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false, bool fIsBDAP=false) +void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdapOPScript, CWalletTx& wtxNew, CAmount nOPValue, CAmount nDataValue) +{ + CAmount curBalance = pwalletMain->GetBalance(); + + // Check amount + if (nOPValue <= 0 || nDataValue <= 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); + + if (nOPValue + nDataValue > curBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); + + // Create and send the transaction + CReserveKey reservekey(pwalletMain); + CAmount nFeeRequired; + std::string strError; + std::vector vecSend; + int nChangePosInOut = 0; + + LogPrintf("Sending BDAP Data Script: %s\n", ScriptToAsmStr(bdapDataScript)); + LogPrintf("Sending BDAP OP Script: %s\n", ScriptToAsmStr(bdapOPScript)); + + CRecipient recDataScript = {bdapDataScript, nDataValue, false}; + vecSend.push_back(recDataScript); + CRecipient recOPScript = {bdapOPScript, nOPValue, false}; + vecSend.push_back(recOPScript); + + if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosInOut, + strError, NULL, true, ALL_COINS, false, true)) { + if (nOPValue + nDataValue + nFeeRequired > pwalletMain->GetBalance()) + strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); + throw JSONRPCError(RPC_WALLET_ERROR, strError); + } + CValidationState state; + if (!pwalletMain->CommitTransaction(wtxNew, reservekey, g_connman.get(), state, NetMsgType::TX)) { + strError = strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()); + throw JSONRPCError(RPC_WALLET_ERROR, strError); + } +} + +void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAmount nValue, bool fUseInstantSend=false) { CAmount curBalance = pwalletMain->GetBalance(); @@ -431,7 +470,7 @@ void SendCustomTransaction(const CScript generatedScript, CWalletTx& wtxNew, CAm vecSend.push_back(recipient); if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, - strError, NULL, true, ALL_COINS, false, fIsBDAP)) { + strError, NULL, true, ALL_COINS, false)) { if (nValue + nFeeRequired > pwalletMain->GetBalance()) strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); From bd5194767745071cc0ddc4514ced71ad7faad39f Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 27 Jun 2018 16:19:07 -0500 Subject: [PATCH 0023/1653] [BDAP] Show directory transactions in Qt UI --- src/qt/dynamic.qrc | 1 + src/qt/res/icons/drk/bdap.png | Bin 0 -> 2328 bytes src/qt/transactionfilterproxy.h | 2 +- src/qt/transactionrecord.cpp | 18 ++++++++++++++++-- src/qt/transactionrecord.h | 1 + src/qt/transactiontablemodel.cpp | 8 +++++++- src/qt/transactionview.cpp | 1 + 7 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 src/qt/res/icons/drk/bdap.png diff --git a/src/qt/dynamic.qrc b/src/qt/dynamic.qrc index fd385970c5..e4830b8548 100644 --- a/src/qt/dynamic.qrc +++ b/src/qt/dynamic.qrc @@ -53,6 +53,7 @@ res/icons/drk/clock4.png res/icons/drk/clock5.png res/icons/drk/tx_mined.png + res/icons/drk/bdap.png res/icons/drk/tx_input.png res/icons/drk/tx_output.png res/icons/drk/tx_inout.png diff --git a/src/qt/res/icons/drk/bdap.png b/src/qt/res/icons/drk/bdap.png new file mode 100644 index 0000000000000000000000000000000000000000..4ce366cacf753850421837559074630c87b9a307 GIT binary patch literal 2328 zcmcImYdn-`AD+mulv4-wR%4K|jX5yG%+5HD!^og9Nu~6dd4`EO?93Ar6``bqXGnMxJ(7xaHxqr`n`u(r#fBg?1?qok74?W#g zx(Eb9kM2oh!fTxB*VcsRdIz8pUQ8gjK*(Rng`xm4h;ZfzLqH^*4}^kD5a8_p;W0=- zAk;VTSb8mVn!Y#A9)G7%TyUC8Du7GS;4q$05IbDA=2r z!zD9m?q7VtCn_oof<$BtCMqh*I?BdcC=SKoNF)*li^t&cXxIWR*)M{liO8;E5P*bYmQWZmpGChgAtaQ92}MX(S5?;R zksBBQn<88k3)8GCOKp6UGR2zA`ypkvv;<&b)k`P zG@6SG0qg8;GmoVS+57mQ0Gh{g{=(Y)EmqYKd=c!K28wx+Aje%S3&9>| zXHT$mhxrKK*76z4`G%IySbOZ>Vll87jHgJ!(q$=gvacq75^|ynARFg<8rBZ1!bDQ!+LmTl=jpUU9-Br8GCYJY1 zGmYKoE96BV!V3lNdOd|fB>^k)S1gu&430Cr&>V{ru^Q;T)!GH;CuD+LZD~Nm)-}RX zzUE?9fgqs5*{^}^DM#l`_d9eBPi%9^D9(<{Ay*7dmima67f`zoOaAjZU)Eegeu%y` zzKKG__vfX}{MNr0-})gFiS-R~98&rhp8HFSSV zeB?G+x9cLle6gU%xs7M5ld;e(c;OTEv7Ln}m1vKG8?hYJ@$grJM&DV~br$Ph0fw%B zq!hDJl>W_OAdq&=D#&JFJD_d+$dYM{Uefn8FLqh)S@?{NzGhh4UYPGDyLx?hjg zU9eJbpOr7;I)`1Bvy?H*xdWXyrCi>uSG%x#2r+WR;h; zEBjqoJMQmL%eogaDoeSWn=>0mYud|AXpK32~r(}$Ki3a_?^;kkcDRKMl<_A%2FJ(3Y- zK#8Nr@r6%EARqT;%`9})hs$egw9oZqQx6YJBUS@edhTeVZKhX z+F#wb)*dw6vW3C$Hu-T;&I}d79j_srkCw6^*|uD$t2-R_v{db`^* zAKtN;sVKL^7AxdT^*1*RpxZTOSqSpUp>RZX#tw7iI=g7^#CLBwgMFuv%=C$#n+C{` z^@q2HeIINTWYDzZ{4CfWfp4s>3XM^lTYOh{u7ilGRlFbt?{z7?>mG~y-9JAkCULH{ z(aCy5XT&hC!AI{9Xt+v@?n|{lp=kvcTFSJHr!Ie_^!8UyR+>kDFrcVPk--g1#SW2)N3fbRn53r7Vb&zT) z=@{?4@AIaTynBX&wVFQmwvT5wc$6Qsp(}MZO^?;*07>d&d5@nLAv<}sr zo-{pA_ql4N+4Z69YVM^_$C;49gp3%q=7p7W?S2VmT}m~s)9S8*b-$FS&O9r8=y0JV z9jkMG8tEi6AIq&8-4I!h!!H{W@%Zo8ZZZNR(*AgPOMPjw=8N$7cS_-FsowKmY3CBu^V*D7V-4Wm8S=wOvbR?iF+g)YtqM zpL)P|&%k!nln9q|LmAO=W3&Xw*mzJucs95D(Z{o1a_ITa)RtMr5k$h}oylXpM;#3k j;0MV+HBu96G*%*hVs(zJn&?=gdaKagd}yUEd*c5Des!P_ literal 0 HcmV?d00001 diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 0424aff056..2087bc033b 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -28,7 +28,7 @@ class TransactionFilterProxy : public QSortFilterProxyModel /** Type filter bit field (all types) */ static const quint32 ALL_TYPES = 0xFFFFFFFF; /** Type filter bit field (all types but PrivateSend-SPAM) */ - static const quint32 COMMON_TYPES = 4223; + static const quint32 COMMON_TYPES = 4223; //TODO Change this bit filter to include BDAP as a common type static quint32 TYPE(int type) { return 1< TransactionRecord::decomposeTransaction(const CWallet * // Generated sub.type = TransactionRecord::Generated; } + if (IsDirectoryDataOutput(txout)) + { + // BDAP type + sub.type = TransactionRecord::BDAP; + } parts.append(sub); } @@ -128,7 +134,6 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // Payment to self by default sub.type = TransactionRecord::SendToSelf; sub.address = ""; - if(mapValue["PS"] == "1") { sub.type = TransactionRecord::PrivateSend; @@ -150,7 +155,11 @@ QList TransactionRecord::decomposeTransaction(const CWallet * { const CTxOut& txout = wtx.vout[nOut]; sub.idx = parts.size(); - + if (IsDirectoryDataOutput(txout)) + { + // BDAP type + sub.type = TransactionRecord::BDAP; + } if(CPrivateSend::IsCollateralAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendMakeCollaterals; if(CPrivateSend::IsDenominatedAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendCreateDenominations; if(nDebit - wtx.GetValueOut() == CPrivateSend::GetCollateralAmount()) sub.type = TransactionRecord::PrivateSendCollateralPayment; @@ -204,6 +213,11 @@ QList TransactionRecord::decomposeTransaction(const CWallet * sub.type = TransactionRecord::PrivateSend; } + if(IsDirectoryDataOutput(txout)) + { + sub.type = TransactionRecord::BDAP; + } + CAmount nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 0e774dcc51..d7b0bca716 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -84,6 +84,7 @@ class TransactionRecord RecvWithAddress, RecvFromOther, SendToSelf, + BDAP, RecvWithPrivateSend, PrivateSendDenominate, PrivateSendCollateralPayment, diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index d5b9688efd..273f6bf6e0 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -384,7 +384,8 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const return tr("Payment to yourself"); case TransactionRecord::Generated: return tr("Mined"); - + case TransactionRecord::BDAP: + return tr("BDAP"); case TransactionRecord::PrivateSendDenominate: return tr("PrivateSend Denominate"); case TransactionRecord::PrivateSendCollateralPayment: @@ -415,6 +416,8 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx case TransactionRecord::SendToAddress: case TransactionRecord::SendToOther: return QIcon(":/icons/" + theme + "/tx_output"); + case TransactionRecord::BDAP: + return QIcon(":/icons/" + theme + "/tx_bdap"); default: return QIcon(":/icons/" + theme + "/tx_inout"); } @@ -440,6 +443,8 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b return lookupAddress(wtx->address, tooltip) + watchAddress; case TransactionRecord::SendToOther: return QString::fromStdString(wtx->address) + watchAddress; + case TransactionRecord::BDAP: + return tr("Directory Entry"); //TODO: Add BDAP Name and Operation Type here case TransactionRecord::SendToSelf: default: return tr("(n/a)") + watchAddress; @@ -456,6 +461,7 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const case TransactionRecord::Generated: case TransactionRecord::PrivateSend: case TransactionRecord::RecvWithPrivateSend: + case TransactionRecord::BDAP: { QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address)); if(label.isEmpty()) diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 6bdf91d666..f8bfb83a34 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -103,6 +103,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa typeWidget->addItem(tr("PrivateSend Collateral Payment"), TransactionFilterProxy::TYPE(TransactionRecord::PrivateSendCollateralPayment)); typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf)); typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); + typeWidget->addItem(tr("BDAP"), TransactionFilterProxy::TYPE(TransactionRecord::BDAP)); typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other)); typeWidget->setCurrentIndex(settings.value("transactionType").toInt()); From 17beaea69167f8998436493abb4d480a2d4113db Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 27 Jun 2018 17:19:44 -0500 Subject: [PATCH 0024/1653] [BDAP] Move directory code to it's own directory --- src/Makefile.am | 8 ++++---- src/{ => bdap}/directory.cpp | 2 +- src/{ => bdap}/directory.h | 0 src/{ => bdap}/rpcdirectory.cpp | 4 ++-- src/init.cpp | 2 +- src/qt/transactionrecord.cpp | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) rename src/{ => bdap}/directory.cpp (99%) rename src/{ => bdap}/directory.h (100%) rename src/{ => bdap}/rpcdirectory.cpp (98%) diff --git a/src/Makefile.am b/src/Makefile.am index 7d8352d95e..4e105a8e60 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -DIST_SUBDIRS = secp256k1 univalue +DIST_SUBDIRS = secp256k1 univalue bdap AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(HARDENED_CXXFLAGS) @@ -97,7 +97,7 @@ DYNAMIC_CORE_H = \ consensus/validation.h \ core_io.h \ core_memusage.h \ - directory.h \ + bdap/directory.h \ dbwrapper.h \ dynode.h \ dynode-payments.h \ @@ -220,7 +220,7 @@ libdynamic_server_a_SOURCES = \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ - directory.cpp \ + bdap/directory.cpp \ dbwrapper.cpp \ dynode.cpp \ dynode-payments.cpp\ @@ -255,7 +255,7 @@ libdynamic_server_a_SOURCES = \ psnotificationinterface.cpp \ rest.cpp \ rpcblockchain.cpp \ - rpcdirectory.cpp \ + bdap/rpcdirectory.cpp \ rpcdynode.cpp \ rpcgovernance.cpp \ rpcmining.cpp \ diff --git a/src/directory.cpp b/src/bdap/directory.cpp similarity index 99% rename from src/directory.cpp rename to src/bdap/directory.cpp index 7924ac4250..578c53d6c5 100644 --- a/src/directory.cpp +++ b/src/bdap/directory.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "directory.h" +#include "bdap/directory.h" #include "fluid.h" #include "policy/policy.h" diff --git a/src/directory.h b/src/bdap/directory.h similarity index 100% rename from src/directory.h rename to src/bdap/directory.h diff --git a/src/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp similarity index 98% rename from src/rpcdirectory.cpp rename to src/bdap/rpcdirectory.cpp index 186f16d00b..94c4cde874 100644 --- a/src/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "directory.h" +#include "bdap/directory.h" #include "rpcprotocol.h" #include "rpcserver.h" @@ -118,7 +118,7 @@ UniValue addpublicname(const JSONRPCRequest& request) { CWalletTx wtx; CAmount nOperationFee = GetBDAPFee(scriptPubKey) * powf(3.1, fYears); CAmount nDataFee = GetBDAPFee(scriptData) * powf(3.1, fYears); - SendBDAPTransaction(scriptData, scriptPubKey, wtx, nOperationFee, nDataFee); + SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); txDirectory.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); diff --git a/src/init.cpp b/src/init.cpp index c228bb97d1..2b44e02e2f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -18,7 +18,7 @@ #include "chain.h" #include "chainparams.h" #include "checkpoints.h" -#include "directory.h" +#include "bdap/directory.h" #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeconfig.h" diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 32dffd41fa..89c6f96c2f 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -9,7 +9,7 @@ #include "base58.h" #include "consensus/consensus.h" -#include "directory.h" +#include "bdap/directory.h" #include "instantsend.h" #include "validation.h" #include "privatesend.h" From c5b6a795e2d587a806be4b0943dd840f5308894a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Sat, 23 Jun 2018 11:29:36 +0200 Subject: [PATCH 0025/1653] [GPU] Mining with autotune Contains fixes by Spencer Lievens. --- .gitignore | 34 + .travis.yml | 7 +- configure.ac | 24 +- contrib/argon2-gpu/CMakeLists.txt | 119 + contrib/argon2-gpu/LICENSE | 22 + .../include/argon2-cuda/cuda-exception.h | 68 + .../argon2-gpu/include/argon2-cuda/device.h | 82 + .../include/argon2-cuda/global-context.h | 52 + .../argon2-gpu/include/argon2-cuda/kernels.h | 87 + .../include/argon2-cuda/processing-unit.h | 101 + .../include/argon2-cuda/program-context.h | 82 + .../argon2-gpu/include/argon2-gpu/blake2b.h | 57 + .../argon2-gpu/include/argon2-gpu/common.h | 96 + .../argon2-gpu/include/argon2-opencl/cl.hpp | 13086 ++++++++++++++++ .../argon2-gpu/include/argon2-opencl/device.h | 61 + .../include/argon2-opencl/global-context.h | 45 + .../include/argon2-opencl/kernel-loader.h | 42 + .../include/argon2-opencl/kernel-runner.h | 77 + .../argon2-gpu/include/argon2-opencl/opencl.h | 37 + .../include/argon2-opencl/processing-unit.h | 59 + .../include/argon2-opencl/program-context.h | 60 + contrib/argon2-gpu/src/argon2-cuda/device.cpp | 44 + .../src/argon2-cuda/global-context.cpp | 40 + contrib/argon2-gpu/src/argon2-cuda/kernels.cu | 1216 ++ .../src/argon2-cuda/processing-unit.cpp | 183 + .../src/argon2-cuda/program-context.cpp | 37 + contrib/argon2-gpu/src/argon2-gpu/blake2b.cpp | 234 + contrib/argon2-gpu/src/argon2-gpu/common.cpp | 235 + contrib/argon2-gpu/src/argon2-gpu/empty.cpp | 18 + .../argon2-gpu/src/argon2-opencl/device.cpp | 245 + .../src/argon2-opencl/global-context.cpp | 51 + .../src/argon2-opencl/kernel-loader.cpp | 72 + .../src/argon2-opencl/kernel-runner.cpp | 227 + .../argon2-gpu/src/argon2-opencl/kernel.cl | 932 ++ .../src/argon2-opencl/processing-unit.cpp | 165 + .../src/argon2-opencl/program-context.cpp | 45 + src/Makefile.am | 16 +- src/Makefile.qt.include | 3 + src/init.cpp | 17 +- src/leveldb/port/port_posix.cc | 10 - src/leveldb/port/port_posix.h | 1 - src/leveldb/util/crc32c.cc | 4 - src/miner-gpu.h | 72 + src/miner.cpp | 255 +- src/miner.h | 21 +- src/qt/forms/miningpage.ui | 1023 +- src/qt/guiutil.cpp | 14 +- src/qt/guiutil.h | 1 - src/qt/hashrategraphwidget.cpp | 14 +- src/qt/hashrategraphwidget.h | 5 +- src/qt/locale/dynamic_ko.ts | 484 +- src/qt/miningpage.cpp | 329 +- src/qt/miningpage.h | 23 +- src/rpcmining.cpp | 72 +- src/test/miner_tests.cpp | 25 + src/txdb.h | 4 +- src/validation.cpp | 6 +- src/validation.h | 2 +- 58 files changed, 19748 insertions(+), 695 deletions(-) create mode 100644 contrib/argon2-gpu/CMakeLists.txt create mode 100644 contrib/argon2-gpu/LICENSE create mode 100644 contrib/argon2-gpu/include/argon2-cuda/cuda-exception.h create mode 100644 contrib/argon2-gpu/include/argon2-cuda/device.h create mode 100644 contrib/argon2-gpu/include/argon2-cuda/global-context.h create mode 100644 contrib/argon2-gpu/include/argon2-cuda/kernels.h create mode 100644 contrib/argon2-gpu/include/argon2-cuda/processing-unit.h create mode 100644 contrib/argon2-gpu/include/argon2-cuda/program-context.h create mode 100644 contrib/argon2-gpu/include/argon2-gpu/blake2b.h create mode 100644 contrib/argon2-gpu/include/argon2-gpu/common.h create mode 100644 contrib/argon2-gpu/include/argon2-opencl/cl.hpp create mode 100644 contrib/argon2-gpu/include/argon2-opencl/device.h create mode 100644 contrib/argon2-gpu/include/argon2-opencl/global-context.h create mode 100644 contrib/argon2-gpu/include/argon2-opencl/kernel-loader.h create mode 100644 contrib/argon2-gpu/include/argon2-opencl/kernel-runner.h create mode 100644 contrib/argon2-gpu/include/argon2-opencl/opencl.h create mode 100644 contrib/argon2-gpu/include/argon2-opencl/processing-unit.h create mode 100644 contrib/argon2-gpu/include/argon2-opencl/program-context.h create mode 100644 contrib/argon2-gpu/src/argon2-cuda/device.cpp create mode 100644 contrib/argon2-gpu/src/argon2-cuda/global-context.cpp create mode 100644 contrib/argon2-gpu/src/argon2-cuda/kernels.cu create mode 100644 contrib/argon2-gpu/src/argon2-cuda/processing-unit.cpp create mode 100644 contrib/argon2-gpu/src/argon2-cuda/program-context.cpp create mode 100644 contrib/argon2-gpu/src/argon2-gpu/blake2b.cpp create mode 100644 contrib/argon2-gpu/src/argon2-gpu/common.cpp create mode 100644 contrib/argon2-gpu/src/argon2-gpu/empty.cpp create mode 100644 contrib/argon2-gpu/src/argon2-opencl/device.cpp create mode 100644 contrib/argon2-gpu/src/argon2-opencl/global-context.cpp create mode 100644 contrib/argon2-gpu/src/argon2-opencl/kernel-loader.cpp create mode 100644 contrib/argon2-gpu/src/argon2-opencl/kernel-runner.cpp create mode 100644 contrib/argon2-gpu/src/argon2-opencl/kernel.cl create mode 100644 contrib/argon2-gpu/src/argon2-opencl/processing-unit.cpp create mode 100644 contrib/argon2-gpu/src/argon2-opencl/program-context.cpp create mode 100644 src/miner-gpu.h diff --git a/.gitignore b/.gitignore index 6e7cc0f8c1..647a348b09 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,37 @@ dynamic-cli dynamicd dynamic-qt make + +# Compiled Object files +*.slo +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.lib + +# Executables +*.out +*.app + +# CMake +CMakeFiles/ +*.cmake +CMakeCache.txt +install_manifest.txt + +# Qt Creator +*.user diff --git a/.travis.yml b/.travis.yml index d613fde9b6..ba1bee70d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,15 +5,16 @@ sudo: required dist: trusty install: - sudo apt-get -qq update + - sudo apt-get install -y ocl-icd-opencl-dev - sudo apt-get install -y build-essential libtool autotools-dev autoconf pkg-config libssl-dev libboost-all-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler libcrypto++-dev libevent-dev - - sudo add-apt-repository -y ppa:silknetwork/silknetwork + - sudo add-apt-repository -y ppa:bitcoin/bitcoin - sudo apt-get update -y && sudo apt-get install -y libdb4.8-dev libdb4.8++-dev script: - - ./autogen.sh && ./configure --with-gui=qt5 && make + - ./autogen.sh && ./configure --with-gui=qt5 --enable-gpu && make deploy: provider: releases file: "dynamic-qt" skip_cleanup: true on: - tags: true +tags: true diff --git a/configure.ac b/configure.ac index 8a6d0d3289..f44ab58134 100644 --- a/configure.ac +++ b/configure.ac @@ -91,6 +91,13 @@ AC_ARG_ENABLE([wallet], [enable_wallet=$enableval], [enable_wallet=yes]) +# TODO: enable by default if CUDA is found +# Enable GPU mining +AC_ARG_ENABLE([gpu], + AS_HELP_STRING([--enable-gpu],[enable GPU mining (disabled by default)]), + [enable_gpu=$enableval], + [enable_gpu=yes]) + AC_ARG_WITH([miniupnpc], [AS_HELP_STRING([--with-miniupnpc], [enable UPNP (default is yes if libminiupnpc is found)])], @@ -205,6 +212,10 @@ AC_ARG_ENABLE([debug], AC_LANG_PUSH([C++]) AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""]) +if test x$enable_gpu_mining != xno; then + AC_SUBST(ENABLE_GPU, 1) +fi + if test "x$enable_debug" = xyes; then CPPFLAGS="$CPPFLAGS -DDEBUG" if test "x$GCC" = xyes; then @@ -255,6 +266,14 @@ AC_ARG_WITH([daemon], [build_dynamicd=$withval], [build_dynamicd=yes]) +# AC_ARG_WITH([gpu], +# [AS_HELP_STRING([--enable-gpu], +# [enable GPU optimizations (defaults is yes)])], +# AC_SUBST(HAVE_CUDA, 1), +# AC_SUBST(ENABLE_GPU, 1), +# [have_gpu=${enableval}], +# [have_gpu=yes]) + use_pkgconfig=yes case $host in *mingw*) @@ -528,7 +547,7 @@ fi AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h]) AC_CHECK_DECLS([strnlen]) - + # Check for daemon(3), unrelated to --with-daemon (although used by it) AC_CHECK_DECLS([daemon]) @@ -922,6 +941,8 @@ else AC_MSG_RESULT(no) fi +AC_DEFINE_UNQUOTED([ENABLE_GPU],[1],[Define to 1 to enable gpu functions]) + dnl enable upnp support AC_MSG_CHECKING([whether to build with support for UPnP]) if test x$have_miniupnpc = xno; then @@ -1014,6 +1035,7 @@ fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) +AM_CONDITIONAL([ENABLE_GPU],[test x$enable_gpu = xyes]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$dynamic_enable_qt = xyes]) diff --git a/contrib/argon2-gpu/CMakeLists.txt b/contrib/argon2-gpu/CMakeLists.txt new file mode 100644 index 0000000000..0247c71e44 --- /dev/null +++ b/contrib/argon2-gpu/CMakeLists.txt @@ -0,0 +1,119 @@ +cmake_minimum_required(VERSION 3.5) + +project(argon2-gpu CXX) +set(BINARY_INSTALL_DIR /usr/local/bin) +set(LIBRARY_INSTALL_DIR /usr/local/lib) +set(INCLUDE_INSTALL_DIR /usr/local/include) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +enable_testing() + +set(CUDA_FOUND FALSE) + +if(NOT NO_CUDA) + find_package(CUDA) +endif() + +if(CUDA_FOUND) + message("INFO: Using CUDA version ${CUDA_VERSION}") + add_definitions(-DHAVE_CUDA=1) +else() + message("INFO: Building without CUDA support") + add_definitions(-DHAVE_CUDA=0) +endif() + +if(CUDA_FOUND) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS}; + -std=c++11;-O3;--ptxas-options=-v;-arch sm_30;-lineinfo + ) +endif() + +add_library(argon2-gpu SHARED + src/argon2-gpu/common.cpp + src/argon2-gpu/blake2b.cpp +) +target_include_directories(argon2-gpu INTERFACE + $ + $ +) +target_include_directories(argon2-gpu PRIVATE + include/ + src/argon2-gpu +) + +if(CUDA_FOUND) + cuda_add_library(argon2-cuda SHARED + src/argon2-cuda/device.cpp + src/argon2-cuda/global-context.cpp + src/argon2-cuda/kernels.cu + src/argon2-cuda/processing-unit.cpp + src/argon2-cuda/program-context.cpp + ) +else() + add_library(argon2-cuda SHARED + src/argon2-gpu/empty.cpp + ) +endif() + +target_include_directories(argon2-cuda PRIVATE + include/ + src/argon2-cuda +) +target_include_directories(argon2-cuda INTERFACE + $ + $ +) +target_link_libraries(argon2-cuda argon2-gpu) + +add_library(argon2-opencl SHARED + src/argon2-opencl/device.cpp + src/argon2-opencl/global-context.cpp + src/argon2-opencl/kernel-loader.cpp + src/argon2-opencl/kernel-runner.cpp + src/argon2-opencl/processing-unit.cpp + src/argon2-opencl/program-context.cpp +) +target_include_directories(argon2-opencl INTERFACE + $ + $ +) +target_include_directories(argon2-opencl PRIVATE + include/argon2-opencl + src/argon2-opencl +) +if (APPLE) + target_link_libraries(argon2-opencl argon2-gpu "-framework OpenCL") +else() + target_link_libraries(argon2-opencl argon2-gpu) +endif(APPLE) +install( + TARGETS argon2-gpu argon2-opencl argon2-cuda + DESTINATION ${LIBRARY_INSTALL_DIR} +) +install(FILES + include/argon2-cuda/cuda-exception.h + include/argon2-cuda/device.h + include/argon2-cuda/global-context.h + include/argon2-cuda/kernels.h + include/argon2-cuda/processing-unit.h + include/argon2-cuda/program-context.h + DESTINATION ${INCLUDE_INSTALL_DIR}/argon2-cuda +) + +install(FILES + include/argon2-gpu/blake2b.h + include/argon2-gpu/common.h + DESTINATION ${INCLUDE_INSTALL_DIR}/argon2-gpu +) + +install(FILES + include/argon2-opencl/cl.hpp + include/argon2-opencl/device.h + include/argon2-opencl/global-context.h + include/argon2-opencl/kernel-loader.h + include/argon2-opencl/kernel-runner.h + include/argon2-opencl/opencl.h + include/argon2-opencl/processing-unit.h + include/argon2-opencl/program-context.h + DESTINATION ${INCLUDE_INSTALL_DIR}/argon2-opencl +) diff --git a/contrib/argon2-gpu/LICENSE b/contrib/argon2-gpu/LICENSE new file mode 100644 index 0000000000..48f0970194 --- /dev/null +++ b/contrib/argon2-gpu/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2017-2018 Łukasz Kurowski +Copyright (c) 2016 Ondrej Mosnáček + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/contrib/argon2-gpu/include/argon2-cuda/cuda-exception.h b/contrib/argon2-gpu/include/argon2-cuda/cuda-exception.h new file mode 100644 index 0000000000..d6e47b9916 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-cuda/cuda-exception.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015, Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_CUDA_CUDAEXCEPTION_H +#define ARGON2_CUDA_CUDAEXCEPTION_H + +#if HAVE_CUDA +#include +#endif + +#include + +namespace argon2gpu +{ +namespace cuda +{ + +#if HAVE_CUDA + +class CudaException : public std::exception +{ + private: + cudaError_t res; + + public: + CudaException(cudaError_t res) : res(res) {} + + const char *what() const noexcept override + { + return cudaGetErrorString(res); + } + + static void check(cudaError_t res) + { + if (res != cudaSuccess) + { + throw CudaException(res); + } + } +}; + +#else + +class CudaException : public std::exception +{ +}; + +#endif + +} // namespace cuda +} // namespace argon2gpu + +#endif // ARGON2_CUDA_CUDAEXCEPTION_H diff --git a/contrib/argon2-gpu/include/argon2-cuda/device.h b/contrib/argon2-gpu/include/argon2-cuda/device.h new file mode 100644 index 0000000000..1f0edc19a2 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-cuda/device.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015 Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_CUDA_DEVICE_H +#define ARGON2_CUDA_DEVICE_H + +#include + +namespace argon2gpu +{ +namespace cuda +{ + +#if HAVE_CUDA + +class Device +{ + private: + int deviceIndex; + + public: + std::string getName() const; + std::string getInfo() const; + + int getDeviceIndex() const { return deviceIndex; } + + /** + * @brief Empty constructor. + * NOTE: Calling methods other than the destructor on an instance initialized + * with empty constructor results in undefined behavior. + */ + Device() {} + + Device(int deviceIndex) : deviceIndex(deviceIndex) + { + } + + Device(const Device &) = default; + Device(Device &&) = default; + + Device &operator=(const Device &) = default; +}; + +#else + +class Device +{ + public: + std::string getName() const { return {}; } + std::string getInfo() const { return {}; } + + int getDeviceIndex() const { return 0; } + + Device() {} + + Device(const Device &) = default; + Device(Device &&) = default; + + Device &operator=(const Device &) = default; +}; + +#endif /* HAVE_CUDA */ + +} // namespace cuda +} // namespace argon2gpu + +#endif // ARGON2_CUDA_DEVICE_H diff --git a/contrib/argon2-gpu/include/argon2-cuda/global-context.h b/contrib/argon2-gpu/include/argon2-cuda/global-context.h new file mode 100644 index 0000000000..e2fd850854 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-cuda/global-context.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015, Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_CUDA_GLOBALCONTEXT_H +#define ARGON2_CUDA_GLOBALCONTEXT_H + +#include "device.h" + +#include +#include + +namespace argon2gpu +{ +namespace cuda +{ + +class GlobalContext +{ + private: + std::vector devices; + + public: + const std::vector &getAllDevices() const { return devices; } + +#if HAVE_CUDA + GlobalContext(); +#else + GlobalContext() : devices() + { + } +#endif /* HAVE_CUDA */ +}; + +} // namespace cuda +} // namespace argon2gpu + +#endif // ARGON2_CUDA_GLOBALCONTEXT_H diff --git a/contrib/argon2-gpu/include/argon2-cuda/kernels.h b/contrib/argon2-gpu/include/argon2-cuda/kernels.h new file mode 100644 index 0000000000..861039a478 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-cuda/kernels.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015 Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_CUDA_KERNELS_H +#define ARGON2_CUDA_KERNELS_H + +#if HAVE_CUDA + +#include +#include + +/* workaround weird CMake/CUDA bug: */ +#ifdef argon2 +#undef argon2 +#endif + +namespace argon2gpu +{ +namespace cuda +{ + +class KernelRunner +{ + private: + std::uint32_t type, version; + std::uint32_t passes, lanes, segmentBlocks; + std::uint32_t batchSize; + bool bySegment; + bool precompute; + int deviceIndex; + + cudaEvent_t start, end; + cudaStream_t stream; + void *memory; + void *refs; + + void precomputeRefs(); + + void runKernelSegment(std::uint32_t lanesPerBlock, + std::uint32_t jobsPerBlock, + std::uint32_t pass, std::uint32_t slice); + void runKernelOneshot(std::uint32_t lanesPerBlock, + std::uint32_t jobsPerBlock); + + public: + std::uint32_t getMinLanesPerBlock() const { return bySegment ? 1 : lanes; } + std::uint32_t getMaxLanesPerBlock() const { return lanes; } + + std::uint32_t getMinJobsPerBlock() const { return 1; } + std::uint32_t getMaxJobsPerBlock() const { return batchSize; } + + std::uint32_t getBatchSize() const { return batchSize; } + + KernelRunner(std::uint32_t type, std::uint32_t version, + std::uint32_t passes, std::uint32_t lanes, + std::uint32_t segmentBlocks, std::uint32_t batchSize, + bool bySegment, bool precompute, int deviceIndex); + ~KernelRunner(); + + void writeInputMemory(std::uint32_t jobId, const void *buffer); + void readOutputMemory(std::uint32_t jobId, void *buffer); + + void run(std::uint32_t lanesPerBlock, std::uint32_t jobsPerBlock); + float finish(); +}; + +} // namespace cuda +} // namespace argon2gpu + +#endif /* HAVE_CUDA */ + +#endif // ARGON2_CUDA_KERNELS_H diff --git a/contrib/argon2-gpu/include/argon2-cuda/processing-unit.h b/contrib/argon2-gpu/include/argon2-cuda/processing-unit.h new file mode 100644 index 0000000000..2fdf9e6bc8 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-cuda/processing-unit.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015 Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_CUDA_PROCESSINGUNIT_H +#define ARGON2_CUDA_PROCESSINGUNIT_H + +#if HAVE_CUDA + +#include + +#include "program-context.h" +#include "kernels.h" +#include "argon2-gpu/common.h" + +namespace argon2gpu +{ +namespace cuda +{ + +class ProcessingUnit +{ + private: + const ProgramContext *programContext; + const Argon2Params *params; + const Device *device; + + KernelRunner runner; + std::uint32_t bestLanesPerBlock; + std::uint32_t bestJobsPerBlock; + + public: + std::size_t getBatchSize() const { return runner.getBatchSize(); } + + ProcessingUnit( + const ProgramContext *programContext, const Argon2Params *params, + const Device *device, std::size_t batchSize, + bool bySegment = true, bool precomputeRefs = false); + + void setInputAndSalt(std::size_t index, const void *input, const std::size_t inputSize); + void getHash(std::size_t index, void *hash); + + void beginProcessing(); + void endProcessing(); +}; + +} // namespace cuda +} // namespace argon2gpu + +#else + +#include + +#include "program-context.h" +#include "argon2-gpu/common.h" + +namespace argon2gpu +{ +namespace cuda +{ + +class ProcessingUnit +{ + public: + std::size_t getBatchSize() const { return 0; } + + ProcessingUnit( + const ProgramContext *programContext, const Argon2Params *params, + const Device *device, std::size_t batchSize, + bool bySegment = true, bool precomputeRefs = false) + { + } + + void setInputAndSalt(std::size_t index, const void *input, std::size_t inputSize) {} + + void getHash(std::size_t index, void *hash) {} + + void beginProcessing() {} + void endProcessing() {} +}; + +} // namespace cuda +} // namespace argon2gpu + +#endif /* HAVE_CUDA */ + +#endif // ARGON2_CUDA_PROCESSINGUNIT_H diff --git a/contrib/argon2-gpu/include/argon2-cuda/program-context.h b/contrib/argon2-gpu/include/argon2-cuda/program-context.h new file mode 100644 index 0000000000..643a990a2c --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-cuda/program-context.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015 Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_CUDA_PROGRAMCONTEXT_H +#define ARGON2_CUDA_PROGRAMCONTEXT_H + +#include "global-context.h" +#include "argon2-gpu/common.h" + +namespace argon2gpu +{ +namespace cuda +{ + +#if HAVE_CUDA + +class ProgramContext +{ + private: + const GlobalContext *globalContext; + + Type type; + Version version; + + public: + const GlobalContext *getGlobalContext() const { return globalContext; } + + Type getArgon2Type() const { return type; } + Version getArgon2Version() const { return version; } + + ProgramContext( + const GlobalContext *globalContext, + const std::vector &devices, + Type type, Version version); +}; + +#else + +class ProgramContext +{ + private: + const GlobalContext *globalContext; + + Type type; + Version version; + + public: + const GlobalContext *getGlobalContext() const { return globalContext; } + + Type getArgon2Type() const { return type; } + Version getArgon2Version() const { return version; } + + ProgramContext( + const GlobalContext *globalContext, + const std::vector &devices, + Type type, Version version) + : globalContext(globalContext), type(type), version(version) + { + } +}; + +#endif /* HAVE_CUDA */ + +} // namespace cuda +} // namespace argon2gpu + +#endif // ARGON2_CUDA_PROGRAMCONTEXT_H diff --git a/contrib/argon2-gpu/include/argon2-gpu/blake2b.h b/contrib/argon2-gpu/include/argon2-gpu/blake2b.h new file mode 100644 index 0000000000..809ee39392 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-gpu/blake2b.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015 Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_BLAKE2B_H +#define ARGON2_BLAKE2B_H + +#include + +#include + +namespace argon2gpu +{ + +class Blake2b +{ + public: + enum + { + BLOCK_BYTES = 128, + OUT_BYTES = 64, + }; + + private: + std::uint64_t h[8]; + std::uint64_t t[2]; + std::uint8_t buf[BLOCK_BYTES]; + size_t bufLen; + + void compress(const void *block, std::uint64_t f0); + void incrementCounter(std::uint64_t inc); + + public: + Blake2b() : h(), t(), buf(), bufLen(0) {} + + void init(size_t outlen); + void update(const void *in, size_t inLen); + void final(void *out, size_t outLen); +}; + +} // namespace argon2gpu + +#endif // ARGON2_BLAKE2B_H diff --git a/contrib/argon2-gpu/include/argon2-gpu/common.h b/contrib/argon2-gpu/include/argon2-gpu/common.h new file mode 100644 index 0000000000..72b3898b21 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-gpu/common.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015 Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2COMMON_H +#define ARGON2COMMON_H + +#include + +#include + +namespace argon2gpu +{ + +#ifndef ARGON2_SYNC_POINTS +#define ARGON2_SYNC_POINTS 4 +#endif + +enum +{ + ARGON2_BLOCK_SIZE = 1024, + // ARGON2_SYNC_POINTS = 4, + ARGON2_PREHASH_DIGEST_LENGTH = 64, + ARGON2_PREHASH_SEED_LENGTH = 72 +}; + +enum Type +{ + ARGON2_D = 0, + ARGON2_I = 1, + ARGON2_ID = 2 +}; + +enum Version +{ + ARGON2_VERSION_10 = 0x10, + ARGON2_VERSION_13 = 0x13 +}; + +class Argon2Params +{ + private: + std::uint32_t outLen; + std::uint32_t t_cost, m_cost, lanes; + + std::uint32_t segmentBlocks; + + static void digestLong(void *out, size_t outLen, + const void *in, size_t inLen); + + void initialHash(void *out, const void *input, size_t inputLen, + Type type, Version version) const; + + public: + std::uint32_t getOutputLength() const { return outLen; } + + std::uint32_t getTimeCost() const { return t_cost; } + std::uint32_t getMemoryCost() const { return m_cost; } + std::uint32_t getLanes() const { return lanes; } + + std::uint32_t getSegmentBlocks() const { return segmentBlocks; } + std::uint32_t getLaneBlocks() const + { + return segmentBlocks * ARGON2_SYNC_POINTS; + } + std::uint32_t getMemoryBlocks() const { return getLaneBlocks() * lanes; } + size_t getMemorySize() const + { + return static_cast(getMemoryBlocks()) * ARGON2_BLOCK_SIZE; + } + + Argon2Params(size_t outLen, size_t t_cost, size_t m_cost, size_t lanes); + + void fillFirstBlocks(void *memory, const void *pwd, size_t pwdLen, + Type type, Version version) const; + + void finalize(void *out, const void *memory) const; +}; + +} // namespace argon2gpu + +#endif // ARGON2COMMON_H diff --git a/contrib/argon2-gpu/include/argon2-opencl/cl.hpp b/contrib/argon2-gpu/include/argon2-opencl/cl.hpp new file mode 100644 index 0000000000..e7d86da4fe --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-opencl/cl.hpp @@ -0,0 +1,13086 @@ +/******************************************************************************* + * Copyright (c) 2008-2015 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/*! \file + * + * \brief C++ bindings for OpenCL 1.0 (rev 48), OpenCL 1.1 (rev 33) and + * OpenCL 1.2 (rev 15) + * \author Benedict R. Gaster, Laurent Morichetti and Lee Howes + * + * Additions and fixes from: + * Brian Cole, March 3rd 2010 and April 2012 + * Matt Gruenke, April 2012. + * Bruce Merry, February 2013. + * Tom Deakin and Simon McIntosh-Smith, July 2013 + * + * \version 1.2.8 + * \date October 2015 + * + * Optional extension support + * + * cl + * cl_ext_device_fission + * #define USE_CL_DEVICE_FISSION + */ + +/*! \mainpage + * \section intro Introduction + * For many large applications C++ is the language of choice and so it seems + * reasonable to define C++ bindings for OpenCL. + * + * + * The interface is contained with a single C++ header file \em cl.hpp and all + * definitions are contained within the namespace \em cl. There is no additional + * requirement to include \em cl.h and to use either the C++ or original C + * bindings it is enough to simply include \em cl.hpp. + * + * The bindings themselves are lightweight and correspond closely to the + * underlying C API. Using the C++ bindings introduces no additional execution + * overhead. + * + * For detail documentation on the bindings see: + * + * The OpenCL C++ Wrapper API 1.2 (revision 09) + * http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.2.pdf + * + * \section example Example + * + * The following example shows a general use case for the C++ + * bindings, including support for the optional exception feature and + * also the supplied vector and string classes, see following sections for + * decriptions of these features. + * + * \code + * #define __CL_ENABLE_EXCEPTIONS + * + * #if defined(__APPLE__) || defined(__MACOSX) + * #include + * #else + * #include + * #endif + * #include + * #include + * #include + * + * const char * helloStr = "__kernel void " + * "hello(void) " + * "{ " + * " " + * "} "; + * + * int + * main(void) + * { + * cl_int err = CL_SUCCESS; + * try { + * + * std::vector platforms; + * cl::Platform::get(&platforms); + * if (platforms.size() == 0) { + * std::cout << "Platform size 0\n"; + * return -1; + * } + * + * cl_context_properties properties[] = + * { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; + * cl::Context context(CL_DEVICE_TYPE_CPU, properties); + * + * std::vector devices = context.getInfo(); + * + * cl::Program::Sources source(1, + * std::make_pair(helloStr,strlen(helloStr))); + * cl::Program program_ = cl::Program(context, source); + * program_.build(devices); + * + * cl::Kernel kernel(program_, "hello", &err); + * + * cl::Event event; + * cl::CommandQueue queue(context, devices[0], 0, &err); + * queue.enqueueNDRangeKernel( + * kernel, + * cl::NullRange, + * cl::NDRange(4,4), + * cl::NullRange, + * NULL, + * &event); + * + * event.wait(); + * } + * catch (cl::Error err) { + * std::cerr + * << "ERROR: " + * << err.what() + * << "(" + * << err.err() + * << ")" + * << std::endl; + * } + * + * return EXIT_SUCCESS; + * } + * + * \endcode + * + */ +#ifndef CL_HPP_ +#define CL_HPP_ + +#ifdef _WIN32 + +#include + +#if defined(USE_DX_INTEROP) +#include +#include +#endif +#endif // _WIN32 + +#if defined(_MSC_VER) +#include +#endif // _MSC_VER + +// +#if defined(USE_CL_DEVICE_FISSION) +#include +#endif + +#if defined(__APPLE__) || defined(__MACOSX) +#include +#else +#include +#endif // !__APPLE__ + +#if (_MSC_VER >= 1700) || (__cplusplus >= 201103L) +#define CL_HPP_RVALUE_REFERENCES_SUPPORTED +#define CL_HPP_CPP11_ATOMICS_SUPPORTED +#include +#endif + +#if (__cplusplus >= 201103L) +#define CL_HPP_NOEXCEPT noexcept +#else +#define CL_HPP_NOEXCEPT +#endif + +// To avoid accidentally taking ownership of core OpenCL types +// such as cl_kernel constructors are made explicit +// under OpenCL 1.2 +#if defined(CL_VERSION_1_2) && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define __CL_EXPLICIT_CONSTRUCTORS explicit +#else // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define __CL_EXPLICIT_CONSTRUCTORS +#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + +// Define deprecated prefixes and suffixes to ensure compilation +// in case they are not pre-defined +#if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) +#define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED +#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) +#if !defined(CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED) +#define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED +#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) + +#if !defined(CL_CALLBACK) +#define CL_CALLBACK +#endif //CL_CALLBACK + +#include +#include +#include + +#if defined(__CL_ENABLE_EXCEPTIONS) +#include +#endif // #if defined(__CL_ENABLE_EXCEPTIONS) + +#if !defined(__NO_STD_VECTOR) +#include +#endif + +#if !defined(__NO_STD_STRING) +#include +#endif + +#if defined(__ANDROID__) || defined(linux) || defined(__APPLE__) || defined(__MACOSX) +#include +#endif // linux + +#include + +/*! \namespace cl + * + * \brief The OpenCL C++ bindings are defined within this namespace. + * + */ +namespace cl +{ + +class Memory; + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +#define __INIT_CL_EXT_FCN_PTR(name) \ + if (!pfn_##name) \ + { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddress(#name); \ + if (!pfn_##name) \ + { \ + } \ + } +#endif // #if defined(CL_VERSION_1_1) + +#if defined(CL_VERSION_1_2) +#define __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, name) \ + if (!pfn_##name) \ + { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddressForPlatform(platform, #name); \ + if (!pfn_##name) \ + { \ + } \ + } +#endif // #if defined(CL_VERSION_1_1) + +class Program; +class Device; +class Context; +class CommandQueue; +class Memory; +class Buffer; + +#if defined(__CL_ENABLE_EXCEPTIONS) +/*! \brief Exception class + * + * This may be thrown by API functions when __CL_ENABLE_EXCEPTIONS is defined. + */ +class Error : public std::exception +{ + private: + cl_int err_; + const char *errStr_; + + public: + /*! \brief Create a new CL error exception for a given error code + * and corresponding message. + * + * \param err error code value. + * + * \param errStr a descriptive string that must remain in scope until + * handling of the exception has concluded. If set, it + * will be returned by what(). + */ + Error(cl_int err, const char *errStr = NULL) : err_(err), errStr_(errStr) + { + } + + ~Error() throw() {} + + /*! \brief Get error string associated with exception + * + * \return A memory pointer to the error message string. + */ + virtual const char *what() const throw() + { + if (errStr_ == NULL) + { + return "empty"; + } + else + { + return errStr_; + } + } + + /*! \brief Get error code associated with exception + * + * \return The error code. + */ + cl_int err(void) const { return err_; } +}; + +#define __ERR_STR(x) #x +#else +#define __ERR_STR(x) NULL +#endif // __CL_ENABLE_EXCEPTIONS + +namespace detail +{ +#if defined(__CL_ENABLE_EXCEPTIONS) +static inline cl_int errHandler( + cl_int err, + const char *errStr = NULL) +{ + if (err != CL_SUCCESS) + { + throw Error(err, errStr); + } + return err; +} +#else +static inline cl_int errHandler(cl_int err, const char *errStr = NULL) +{ + (void)errStr; // suppress unused variable warning + return err; +} +#endif // __CL_ENABLE_EXCEPTIONS +} // namespace detail + +//! \cond DOXYGEN_DETAIL +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#define __GET_DEVICE_INFO_ERR __ERR_STR(clGetDeviceInfo) +#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) +#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) +#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) +#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) +#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) +#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) +#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) +#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) +#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) +#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) +#if defined(CL_VERSION_1_2) +#define __GET_KERNEL_ARG_INFO_ERR __ERR_STR(clGetKernelArgInfo) +#endif // #if defined(CL_VERSION_1_2) +#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) +#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) +#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) +#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) + +#define __CREATE_CONTEXT_ERR __ERR_STR(clCreateContext) +#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) +#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) + +#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) +#define __COPY_ERR __ERR_STR(cl::copy) +#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) +#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __CREATE_GL_RENDER_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) +#if defined(CL_VERSION_1_2) +#define __CREATE_IMAGE_ERR __ERR_STR(clCreateImage) +#define __CREATE_GL_TEXTURE_ERR __ERR_STR(clCreateFromGLTexture) +#define __IMAGE_DIMENSION_ERR __ERR_STR(Incorrect image dimensions) +#endif // #if defined(CL_VERSION_1_2) +#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) +#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) + +#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) +#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) +#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) +#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) + +#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) +#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) +#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) +#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) +#if defined(CL_VERSION_1_2) +#define __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR __ERR_STR(clCreateProgramWithBuiltInKernels) +#endif // #if defined(CL_VERSION_1_2) +#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) +#if defined(CL_VERSION_1_2) +#define __COMPILE_PROGRAM_ERR __ERR_STR(clCompileProgram) +#define __LINK_PROGRAM_ERR __ERR_STR(clLinkProgram) +#endif // #if defined(CL_VERSION_1_2) +#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) + +#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) +#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) +#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) +#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) +#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) +#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) +#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) +#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) +#define __ENQUEUE_FILL_BUFFER_ERR __ERR_STR(clEnqueueFillBuffer) +#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) +#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) +#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) +#define __ENQUEUE_FILL_IMAGE_ERR __ERR_STR(clEnqueueFillImage) +#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) +#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) +#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) +#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) +#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) +#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) +#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) +#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) +#if defined(CL_VERSION_1_2) +#define __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR __ERR_STR(clEnqueueMigrateMemObjects) +#endif // #if defined(CL_VERSION_1_2) + +#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) +#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) + +#define __RETAIN_ERR __ERR_STR(Retain Object) +#define __RELEASE_ERR __ERR_STR(Release Object) +#define __FLUSH_ERR __ERR_STR(clFlush) +#define __FINISH_ERR __ERR_STR(clFinish) +#define __VECTOR_CAPACITY_ERR __ERR_STR(Vector capacity error) + +/** + * CL 1.2 version that uses device fission. + */ +#if defined(CL_VERSION_1_2) +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevices) +#else +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) +#endif // #if defined(CL_VERSION_1_2) + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) +#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) +#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) +#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) +#define __CREATE_GL_TEXTURE_2D_ERR __ERR_STR(clCreateFromGLTexture2D) +#define __CREATE_GL_TEXTURE_3D_ERR __ERR_STR(clCreateFromGLTexture3D) +#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) +#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) +#endif // #if defined(CL_VERSION_1_1) + +#endif // __CL_USER_OVERRIDE_ERROR_STRINGS +//! \endcond + +/** + * CL 1.2 marker and barrier commands + */ +#if defined(CL_VERSION_1_2) +#define __ENQUEUE_MARKER_WAIT_LIST_ERR __ERR_STR(clEnqueueMarkerWithWaitList) +#define __ENQUEUE_BARRIER_WAIT_LIST_ERR __ERR_STR(clEnqueueBarrierWithWaitList) +#endif // #if defined(CL_VERSION_1_2) + +#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) +typedef std::string STRING_CLASS; +#elif !defined(__USE_DEV_STRING) + +/*! \class string + * \brief Simple string class, that provides a limited subset of std::string + * functionality but avoids many of the issues that come with that class. + + * \note Deprecated. Please use std::string as default or + * re-define the string class to match the std::string + * interface by defining STRING_CLASS + */ +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED string CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED +{ + private: + ::size_t size_; + char *str_; + + public: + //! \brief Constructs an empty string, allocating no memory. + string(void) : size_(0), str_(NULL) + { + } + + /*! \brief Constructs a string populated from an arbitrary value of + * specified size. + * + * An extra '\0' is added, in case none was contained in str. + * + * \param str the initial value of the string instance. Note that '\0' + * characters receive no special treatment. If NULL, + * the string is left empty, with a size of 0. + * + * \param size the number of characters to copy from str. + */ + string(const char *str, ::size_t size) : size_(size), + str_(NULL) + { + if (size > 0) + { + str_ = new char[size_ + 1]; + if (str_ != NULL) + { + memcpy(str_, str, size_ * sizeof(char)); + str_[size_] = '\0'; + } + else + { + size_ = 0; + } + } + } + + /*! \brief Constructs a string populated from a null-terminated value. + * + * \param str the null-terminated initial value of the string instance. + * If NULL, the string is left empty, with a size of 0. + */ + string(const char *str) : size_(0), + str_(NULL) + { + if (str) + { + size_ = ::strlen(str); + } + if (size_ > 0) + { + str_ = new char[size_ + 1]; + if (str_ != NULL) + { + memcpy(str_, str, (size_ + 1) * sizeof(char)); + } + } + } + + void resize(::size_t n) + { + if (size_ == n) + { + return; + } + if (n == 0) + { + if (str_) + { + delete[] str_; + } + str_ = NULL; + size_ = 0; + } + else + { + char *newString = new char[n + 1]; + ::size_t copySize = n; + if (size_ < n) + { + copySize = size_; + } + size_ = n; + + if (str_) + { + memcpy(newString, str_, (copySize + 1) * sizeof(char)); + } + if (copySize < size_) + { + memset(newString + copySize, 0, size_ - copySize); + } + newString[size_] = '\0'; + + delete[] str_; + str_ = newString; + } + } + + const char &operator[](::size_t pos) const + { + return str_[pos]; + } + + char &operator[](::size_t pos) + { + return str_[pos]; + } + + /*! \brief Copies the value of another string to this one. + * + * \param rhs the string to copy. + * + * \returns a reference to the modified instance. + */ + string &operator=(const string &rhs) + { + if (this == &rhs) + { + return *this; + } + + if (str_ != NULL) + { + delete[] str_; + str_ = NULL; + size_ = 0; + } + + if (rhs.size_ == 0 || rhs.str_ == NULL) + { + str_ = NULL; + size_ = 0; + } + else + { + str_ = new char[rhs.size_ + 1]; + size_ = rhs.size_; + + if (str_ != NULL) + { + memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); + } + else + { + size_ = 0; + } + } + + return *this; + } + + /*! \brief Constructs a string by copying the value of another instance. + * + * \param rhs the string to copy. + */ + string(const string &rhs) : size_(0), + str_(NULL) + { + *this = rhs; + } + + //! \brief Destructor - frees memory used to hold the current value. + ~string() + { + delete[] str_; + str_ = NULL; + } + + //! \brief Queries the length of the string, excluding any added '\0's. + ::size_t size(void) const { return size_; } + + //! \brief Queries the length of the string, excluding any added '\0's. + ::size_t length(void) const { return size(); } + + /*! \brief Returns a pointer to the private copy held by this instance, + * or "" if empty/unset. + */ + const char *c_str(void) const { return (str_) ? str_ : ""; } +}; +typedef cl::string STRING_CLASS; +#endif // #elif !defined(__USE_DEV_STRING) + +#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) +#define VECTOR_CLASS std::vector +#elif !defined(__USE_DEV_VECTOR) +#define VECTOR_CLASS cl::vector + +#if !defined(__MAX_DEFAULT_VECTOR_SIZE) +#define __MAX_DEFAULT_VECTOR_SIZE 10 +#endif + +/*! \class vector + * \brief Fixed sized vector implementation that mirroring + * + * \note Deprecated. Please use std::vector as default or + * re-define the vector class to match the std::vector + * interface by defining VECTOR_CLASS + + * \note Not recommended for use with custom objects as + * current implementation will construct N elements + * + * std::vector functionality. + * \brief Fixed sized vector compatible with std::vector. + * + * \note + * This differs from std::vector<> not just in memory allocation, + * but also in terms of when members are constructed, destroyed, + * and assigned instead of being copy constructed. + * + * \param T type of element contained in the vector. + * + * \param N maximum size of the vector. + */ +template +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED vector +{ + private: + T data_[N]; + unsigned int size_; + + public: + //! \brief Constructs an empty vector with no memory allocated. + vector() : size_(static_cast(0)) + { + } + + //! \brief Deallocates the vector's memory and destroys all of its elements. + ~vector() + { + clear(); + } + + //! \brief Returns the number of elements currently contained. + unsigned int size(void) const + { + return size_; + } + + /*! \brief Empties the vector of all elements. + * \note + * This does not deallocate memory but will invoke destructors + * on contained elements. + */ + void clear() + { + while (!empty()) + { + pop_back(); + } + } + + /*! \brief Appends an element after the last valid element. + * Calling this on a vector that has reached capacity will throw an + * exception if exceptions are enabled. + */ + void push_back(const T &x) + { + if (size() < N) + { + new (&data_[size_]) T(x); + size_++; + } + else + { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + } + + /*! \brief Removes the last valid element from the vector. + * Calling this on an empty vector will throw an exception + * if exceptions are enabled. + */ + void pop_back(void) + { + if (size_ != 0) + { + --size_; + data_[size_].~T(); + } + else + { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + } + + /*! \brief Constructs with a value copied from another. + * + * \param vec the vector to copy. + */ + vector(const vector &vec) : size_(vec.size_) + { + if (size_ != 0) + { + assign(vec.begin(), vec.end()); + } + } + + /*! \brief Constructs with a specified number of initial elements. + * + * \param size number of initial elements. + * + * \param val value of initial elements. + */ + vector(unsigned int size, const T &val = T()) : size_(0) + { + for (unsigned int i = 0; i < size; i++) + { + push_back(val); + } + } + + /*! \brief Overwrites the current content with that copied from another + * instance. + * + * \param rhs vector to copy. + * + * \returns a reference to this. + */ + vector &operator=(const vector &rhs) + { + if (this == &rhs) + { + return *this; + } + + if (rhs.size_ != 0) + { + assign(rhs.begin(), rhs.end()); + } + else + { + clear(); + } + + return *this; + } + + /*! \brief Tests equality against another instance. + * + * \param vec the vector against which to compare. + */ + bool operator==(vector &vec) + { + if (size() != vec.size()) + { + return false; + } + + for (unsigned int i = 0; i < size(); ++i) + { + if (operator[](i) != vec[i]) + { + return false; + } + } + return true; + } + + //! \brief Conversion operator to T*. + operator T *() { return data_; } + + //! \brief Conversion operator to const T*. + operator const T *() const { return data_; } + + //! \brief Tests whether this instance has any elements. + bool empty(void) const + { + return size_ == 0; + } + + //! \brief Returns the maximum number of elements this instance can hold. + unsigned int max_size(void) const + { + return N; + } + + //! \brief Returns the maximum number of elements this instance can hold. + unsigned int capacity() const + { + return N; + } + + //! \brief Resizes the vector to the given size + void resize(unsigned int newSize, T fill = T()) + { + if (newSize > N) + { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + else + { + while (size_ < newSize) + { + new (&data_[size_]) T(fill); + size_++; + } + while (size_ > newSize) + { + --size_; + data_[size_].~T(); + } + } + } + + /*! \brief Returns a reference to a given element. + * + * \param index which element to access. * + * \note + * The caller is responsible for ensuring index is >= 0 and < size(). + */ + T &operator[](int index) + { + return data_[index]; + } + + /*! \brief Returns a const reference to a given element. + * + * \param index which element to access. + * + * \note + * The caller is responsible for ensuring index is >= 0 and < size(). + */ + const T &operator[](int index) const + { + return data_[index]; + } + + /*! \brief Assigns elements of the vector based on a source iterator range. + * + * \param start Beginning iterator of source range + * \param end Enditerator of source range + * + * \note + * Will throw an exception if exceptions are enabled and size exceeded. + */ + template + void assign(I start, I end) + { + clear(); + while (start != end) + { + push_back(*start); + start++; + } + } + + /*! \class iterator + * \brief Const iterator class for vectors + */ + class iterator + { + private: + const vector *vec_; + int index_; + + /** + * Internal iterator constructor to capture reference + * to the vector it iterates over rather than taking + * the vector by copy. + */ + iterator(const vector &vec, int index) : vec_(&vec) + { + if (!vec.empty()) + { + index_ = index; + } + else + { + index_ = -1; + } + } + + public: + iterator(void) : index_(-1), + vec_(NULL) + { + } + + iterator(const iterator &rhs) : vec_(rhs.vec_), + index_(rhs.index_) + { + } + + ~iterator(void) {} + + static iterator begin(const cl::vector &vec) + { + iterator i(vec, 0); + + return i; + } + + static iterator end(const cl::vector &vec) + { + iterator i(vec, vec.size()); + + return i; + } + + bool operator==(iterator i) + { + return ((vec_ == i.vec_) && + (index_ == i.index_)); + } + + bool operator!=(iterator i) + { + return (!(*this == i)); + } + + iterator &operator++() + { + ++index_; + return *this; + } + + iterator operator++(int) + { + iterator retVal(*this); + ++index_; + return retVal; + } + + iterator &operator--() + { + --index_; + return *this; + } + + iterator operator--(int) + { + iterator retVal(*this); + --index_; + return retVal; + } + + const T &operator*() const + { + return (*vec_)[index_]; + } + }; + + iterator begin(void) + { + return iterator::begin(*this); + } + + iterator begin(void) const + { + return iterator::begin(*this); + } + + iterator end(void) + { + return iterator::end(*this); + } + + iterator end(void) const + { + return iterator::end(*this); + } + + T &front(void) + { + return data_[0]; + } + + T &back(void) + { + return data_[size_]; + } + + const T &front(void) const + { + return data_[0]; + } + + const T &back(void) const + { + return data_[size_ - 1]; + } +} CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +#endif // #if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) + +namespace detail +{ +#define __DEFAULT_NOT_INITIALIZED 1 +#define __DEFAULT_BEING_INITIALIZED 2 +#define __DEFAULT_INITIALIZED 4 + +/* + * Compare and exchange primitives are needed for handling of defaults + */ + +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +inline int compare_exchange(std::atomic *dest, int exchange, int comparand) +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +inline int compare_exchange(volatile int *dest, int exchange, int comparand) +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +{ +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + std::atomic_compare_exchange_strong(dest, &comparand, exchange); + return comparand; +#elif _MSC_VER + return (int)(_InterlockedCompareExchange( + (volatile long *)dest, + (long)exchange, + (long)comparand)); +#else // !_MSC_VER && !CL_HPP_CPP11_ATOMICS_SUPPORTED + return (__sync_val_compare_and_swap( + dest, + comparand, + exchange)); +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +} + +inline void fence() +{ +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + std::atomic_thread_fence(std::memory_order_seq_cst); +#elif _MSC_VER // !CL_HPP_CPP11_ATOMICS_SUPPORTED + _ReadWriteBarrier(); +#else // !_MSC_VER && !CL_HPP_CPP11_ATOMICS_SUPPORTED + __sync_synchronize(); +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +} +} // namespace detail + +/*! \brief class used to interface between C++ and + * OpenCL C calls that require arrays of size_t values, whose + * size is known statically. + */ +template +class size_t +{ + private: + ::size_t data_[N]; + + public: + //! \brief Initialize size_t to all 0s + size_t() + { + for (int i = 0; i < N; ++i) + { + data_[i] = 0; + } + } + + ::size_t &operator[](int index) + { + return data_[index]; + } + + const ::size_t &operator[](int index) const + { + return data_[index]; + } + + //! \brief Conversion operator to T*. + operator ::size_t *() { return data_; } + + //! \brief Conversion operator to const T*. + operator const ::size_t *() const { return data_; } +}; + +namespace detail +{ + +// Generic getInfoHelper. The final parameter is used to guide overload +// resolution: the actual parameter passed is an int, which makes this +// a worse conversion sequence than a specialization that declares the +// parameter as an int. +template +inline cl_int getInfoHelper(Functor f, cl_uint name, T *param, long) +{ + return f(name, sizeof(T), param, NULL); +} + +// Specialized getInfoHelper for VECTOR_CLASS params +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS *param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + T *value = (T *)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + + param->assign(&value[0], &value[required / sizeof(T)]); + return CL_SUCCESS; +} + +/* Specialization for reference-counted types. This depends on the + * existence of Wrapper::cl_type, and none of the other types having the + * cl_type member. Note that simplify specifying the parameter as Wrapper + * does not work, because when using a derived type (e.g. Context) the generic + * template will provide a better match. + */ +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS *param, int, typename T::cl_type = 0) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + typename T::cl_type *value = (typename T::cl_type *)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + + ::size_t elements = required / sizeof(typename T::cl_type); + param->assign(&value[0], &value[elements]); + for (::size_t i = 0; i < elements; i++) + { + if (value[i] != NULL) + { + err = (*param)[i].retain(); + if (err != CL_SUCCESS) + { + return err; + } + } + } + return CL_SUCCESS; +} + +// Specialized for getInfo +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS *param, int) +{ + cl_int err = f(name, param->size() * sizeof(char *), &(*param)[0], NULL); + + if (err != CL_SUCCESS) + { + return err; + } + + return CL_SUCCESS; +} + +// Specialized GetInfoHelper for STRING_CLASS params +template +inline cl_int getInfoHelper(Func f, cl_uint name, STRING_CLASS *param, long) +{ +#if defined(__NO_STD_VECTOR) || defined(__NO_STD_STRING) + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + char *value = (char *)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + + *param = value; + return CL_SUCCESS; +#else + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + // std::string has a constant data member + // a char vector does not + VECTOR_CLASS value(required); + err = f(name, required, value.data(), NULL); + if (err != CL_SUCCESS) + { + return err; + } + if (param) + { + param->assign(value.begin(), value.end()); + } +#endif + return CL_SUCCESS; +} + +// Specialized GetInfoHelper for cl::size_t params +template +inline cl_int getInfoHelper(Func f, cl_uint name, size_t *param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) + { + return err; + } + + ::size_t *value = (::size_t *)alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + + for (int i = 0; i < N; ++i) + { + (*param)[i] = value[i]; + } + + return CL_SUCCESS; +} + +template +struct ReferenceHandler; + +/* Specialization for reference-counted types. This depends on the + * existence of Wrapper::cl_type, and none of the other types having the + * cl_type member. Note that simplify specifying the parameter as Wrapper + * does not work, because when using a derived type (e.g. Context) the generic + * template will provide a better match. + */ +template +inline cl_int getInfoHelper(Func f, cl_uint name, T *param, int, typename T::cl_type = 0) +{ + typename T::cl_type value; + cl_int err = f(name, sizeof(value), &value, NULL); + if (err != CL_SUCCESS) + { + return err; + } + *param = value; + if (value != NULL) + { + err = param->retain(); + if (err != CL_SUCCESS) + { + return err; + } + } + return CL_SUCCESS; +} + +#define __PARAM_NAME_INFO_1_0(F) \ + F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ + F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS<::size_t>) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ + F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ + F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ + F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ + F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ + F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ + F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ + F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ + F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ + F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ + F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ + \ + F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ + F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ + F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ + F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_int) \ + \ + F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ + \ + F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ + F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ + F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ + F(cl_mem_info, CL_MEM_HOST_PTR, void *) \ + F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ + \ + F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ + F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ + F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ + F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ + F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ + \ + F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ + F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ + F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_bool) \ + F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_addressing_mode) \ + F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_filter_mode) \ + \ + F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ + F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ + F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ + F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ + F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ + F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS<::size_t>) \ + F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ + \ + F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ + F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ + F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ + F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ + \ + F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ + F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ + F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ + F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) + +#if defined(CL_VERSION_1_1) +#define __PARAM_NAME_INFO_1_1(F) \ + F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ + F(cl_device_info, CL_DEVICE_OPENCL_C_VERSION, STRING_CLASS) \ + \ + F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ + F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ + \ + F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) +#endif // CL_VERSION_1_1 + +#if defined(CL_VERSION_1_2) +#define __PARAM_NAME_INFO_1_2(F) \ + F(cl_image_info, CL_IMAGE_BUFFER, cl::Buffer) \ + \ + F(cl_program_info, CL_PROGRAM_NUM_KERNELS, ::size_t) \ + F(cl_program_info, CL_PROGRAM_KERNEL_NAMES, STRING_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BINARY_TYPE, cl_program_binary_type) \ + \ + F(cl_kernel_info, CL_KERNEL_ATTRIBUTES, STRING_CLASS) \ + \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_ACCESS_QUALIFIER, cl_kernel_arg_access_qualifier) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_NAME, STRING_CLASS) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, STRING_CLASS) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_QUALIFIER, cl_kernel_arg_type_qualifier) \ + \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPE, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, ::size_t) \ + F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \ + F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, STRING_CLASS) +#endif // #if defined(CL_VERSION_1_2) + +#if defined(USE_CL_DEVICE_FISSION) +#define __PARAM_NAME_DEVICE_FISSION(F) \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) +#endif // USE_CL_DEVICE_FISSION + +template +struct param_traits +{ +}; + +#define __CL_DECLARE_PARAM_TRAITS(token, param_name, T) \ + struct token; \ + template <> \ + struct param_traits \ + { \ + enum \ + { \ + value = param_name \ + }; \ + typedef T param_type; \ + }; + +__PARAM_NAME_INFO_1_0(__CL_DECLARE_PARAM_TRAITS) +#if defined(CL_VERSION_1_1) +__PARAM_NAME_INFO_1_1(__CL_DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 +#if defined(CL_VERSION_1_2) +__PARAM_NAME_INFO_1_2(__CL_DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 + +#if defined(USE_CL_DEVICE_FISSION) +__PARAM_NAME_DEVICE_FISSION(__CL_DECLARE_PARAM_TRAITS); +#endif // USE_CL_DEVICE_FISSION + +#ifdef CL_PLATFORM_ICD_SUFFIX_KHR +__CL_DECLARE_PARAM_TRAITS(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, STRING_CLASS) +#endif + +#ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong) +#endif + +#ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, VECTOR_CLASS<::size_t>) +#endif +#ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_SIMD_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_WAVEFRONT_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WAVEFRONT_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_BANKS_AMD, cl_uint) +#endif + +#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint) +#endif +#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, cl_uint) +#endif +#ifdef CL_DEVICE_REGISTERS_PER_BLOCK_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_REGISTERS_PER_BLOCK_NV, cl_uint) +#endif +#ifdef CL_DEVICE_WARP_SIZE_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WARP_SIZE_NV, cl_uint) +#endif +#ifdef CL_DEVICE_GPU_OVERLAP_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GPU_OVERLAP_NV, cl_bool) +#endif +#ifdef CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, cl_bool) +#endif +#ifdef CL_DEVICE_INTEGRATED_MEMORY_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool) +#endif + +// Convenience functions + +template +inline cl_int +getInfo(Func f, cl_uint name, T *param) +{ + return getInfoHelper(f, name, param, 0); +} + +template +struct GetInfoFunctor0 +{ + Func f_; + const Arg0 &arg0_; + cl_int operator()( + cl_uint param, ::size_t size, void *value, ::size_t *size_ret) + { + return f_(arg0_, param, size, value, size_ret); + } +}; + +template +struct GetInfoFunctor1 +{ + Func f_; + const Arg0 &arg0_; + const Arg1 &arg1_; + cl_int operator()( + cl_uint param, ::size_t size, void *value, ::size_t *size_ret) + { + return f_(arg0_, arg1_, param, size, value, size_ret); + } +}; + +template +inline cl_int +getInfo(Func f, const Arg0 &arg0, cl_uint name, T *param) +{ + GetInfoFunctor0 f0 = {f, arg0}; + return getInfoHelper(f0, name, param, 0); +} + +template +inline cl_int +getInfo(Func f, const Arg0 &arg0, const Arg1 &arg1, cl_uint name, T *param) +{ + GetInfoFunctor1 f0 = {f, arg0, arg1}; + return getInfoHelper(f0, name, param, 0); +} + +template +struct ReferenceHandler +{ +}; + +#if defined(CL_VERSION_1_2) +/** + * OpenCL 1.2 devices do have retain/release. + */ +template <> +struct ReferenceHandler +{ + /** + * Retain the device. + * \param device A valid device created using createSubDevices + * \return + * CL_SUCCESS if the function executed successfully. + * CL_INVALID_DEVICE if device was not a valid subdevice + * CL_OUT_OF_RESOURCES + * CL_OUT_OF_HOST_MEMORY + */ + static cl_int retain(cl_device_id device) + { + return ::clRetainDevice(device); + } + /** + * Retain the device. + * \param device A valid device created using createSubDevices + * \return + * CL_SUCCESS if the function executed successfully. + * CL_INVALID_DEVICE if device was not a valid subdevice + * CL_OUT_OF_RESOURCES + * CL_OUT_OF_HOST_MEMORY + */ + static cl_int release(cl_device_id device) + { + return ::clReleaseDevice(device); + } +}; +#else // #if defined(CL_VERSION_1_2) +/** + * OpenCL 1.1 devices do not have retain/release. + */ +template <> +struct ReferenceHandler +{ + // cl_device_id does not have retain(). + static cl_int retain(cl_device_id) + { + return CL_SUCCESS; + } + // cl_device_id does not have release(). + static cl_int release(cl_device_id) + { + return CL_SUCCESS; + } +}; +#endif // #if defined(CL_VERSION_1_2) + +template <> +struct ReferenceHandler +{ + // cl_platform_id does not have retain(). + static cl_int retain(cl_platform_id) + { + return CL_SUCCESS; + } + // cl_platform_id does not have release(). + static cl_int release(cl_platform_id) + { + return CL_SUCCESS; + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_context context) + { + return ::clRetainContext(context); + } + static cl_int release(cl_context context) + { + return ::clReleaseContext(context); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_command_queue queue) + { + return ::clRetainCommandQueue(queue); + } + static cl_int release(cl_command_queue queue) + { + return ::clReleaseCommandQueue(queue); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_mem memory) + { + return ::clRetainMemObject(memory); + } + static cl_int release(cl_mem memory) + { + return ::clReleaseMemObject(memory); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_sampler sampler) + { + return ::clRetainSampler(sampler); + } + static cl_int release(cl_sampler sampler) + { + return ::clReleaseSampler(sampler); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_program program) + { + return ::clRetainProgram(program); + } + static cl_int release(cl_program program) + { + return ::clReleaseProgram(program); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_kernel kernel) + { + return ::clRetainKernel(kernel); + } + static cl_int release(cl_kernel kernel) + { + return ::clReleaseKernel(kernel); + } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_event event) + { + return ::clRetainEvent(event); + } + static cl_int release(cl_event event) + { + return ::clReleaseEvent(event); + } +}; + +// Extracts version number with major in the upper 16 bits, minor in the lower 16 +static cl_uint getVersion(const char *versionInfo) +{ + int highVersion = 0; + int lowVersion = 0; + int index = 7; + while (versionInfo[index] != '.') + { + highVersion *= 10; + highVersion += versionInfo[index] - '0'; + ++index; + } + ++index; + while (versionInfo[index] != ' ' && versionInfo[index] != '\0') + { + lowVersion *= 10; + lowVersion += versionInfo[index] - '0'; + ++index; + } + return (highVersion << 16) | lowVersion; +} + +static cl_uint getPlatformVersion(cl_platform_id platform) +{ + ::size_t size = 0; + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL, &size); + char *versionInfo = (char *)alloca(size); + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size, &versionInfo[0], &size); + return getVersion(versionInfo); +} + +static cl_uint getDevicePlatformVersion(cl_device_id device) +{ + cl_platform_id platform; + clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(platform), &platform, NULL); + return getPlatformVersion(platform); +} + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +static cl_uint getContextPlatformVersion(cl_context context) +{ + // The platform cannot be queried directly, so we first have to grab a + // device and obtain its context + ::size_t size = 0; + clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size); + if (size == 0) + return 0; + cl_device_id *devices = (cl_device_id *)alloca(size); + clGetContextInfo(context, CL_CONTEXT_DEVICES, size, devices, NULL); + return getDevicePlatformVersion(devices[0]); +} +#endif // #if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + +template +class Wrapper +{ + public: + typedef T cl_type; + + protected: + cl_type object_; + + public: + Wrapper() : object_(NULL) {} + + Wrapper(const cl_type &obj) : object_(obj) {} + + ~Wrapper() + { + if (object_ != NULL) + { + release(); + } + } + + Wrapper(const Wrapper &rhs) + { + object_ = rhs.object_; + if (object_ != NULL) + { + detail::errHandler(retain(), __RETAIN_ERR); + } + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper(Wrapper &&rhs) CL_HPP_NOEXCEPT + { + object_ = rhs.object_; + rhs.object_ = NULL; + } +#endif + + Wrapper &operator=(const Wrapper &rhs) + { + if (this != &rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs.object_; + if (object_ != NULL) + { + detail::errHandler(retain(), __RETAIN_ERR); + } + } + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper &operator=(Wrapper &&rhs) + { + if (this != &rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs.object_; + rhs.object_ = NULL; + } + return *this; + } +#endif + + Wrapper &operator=(const cl_type &rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs; + return *this; + } + + cl_type operator()() const { return object_; } + + cl_type &operator()() { return object_; } + + protected: + template + friend inline cl_int getInfoHelper(Func, cl_uint, U *, int, typename U::cl_type); + + cl_int retain() const + { + return ReferenceHandler::retain(object_); + } + + cl_int release() const + { + return ReferenceHandler::release(object_); + } +}; + +template <> +class Wrapper +{ + public: + typedef cl_device_id cl_type; + + protected: + cl_type object_; + bool referenceCountable_; + + static bool isReferenceCountable(cl_device_id device) + { + bool retVal = false; + if (device != NULL) + { + int version = getDevicePlatformVersion(device); + if (version > ((1 << 16) + 1)) + { + retVal = true; + } + } + return retVal; + } + + public: + Wrapper() : object_(NULL), referenceCountable_(false) + { + } + + Wrapper(const cl_type &obj) : object_(obj), referenceCountable_(false) + { + referenceCountable_ = isReferenceCountable(obj); + } + + ~Wrapper() + { + if (object_ != NULL) + { + release(); + } + } + + Wrapper(const Wrapper &rhs) + { + object_ = rhs.object_; + referenceCountable_ = isReferenceCountable(object_); + if (object_ != NULL) + { + detail::errHandler(retain(), __RETAIN_ERR); + } + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper(Wrapper &&rhs) CL_HPP_NOEXCEPT + { + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + rhs.object_ = NULL; + rhs.referenceCountable_ = false; + } +#endif + + Wrapper &operator=(const Wrapper &rhs) + { + if (this != &rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + if (object_ != NULL) + { + detail::errHandler(retain(), __RETAIN_ERR); + } + } + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper &operator=(Wrapper &&rhs) + { + if (this != &rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + rhs.object_ = NULL; + rhs.referenceCountable_ = false; + } + return *this; + } +#endif + + Wrapper &operator=(const cl_type &rhs) + { + if (object_ != NULL) + { + detail::errHandler(release(), __RELEASE_ERR); + } + object_ = rhs; + referenceCountable_ = isReferenceCountable(object_); + return *this; + } + + cl_type operator()() const { return object_; } + + cl_type &operator()() { return object_; } + + protected: + template + friend inline cl_int getInfoHelper(Func, cl_uint, U *, int, typename U::cl_type); + + template + friend inline cl_int getInfoHelper(Func, cl_uint, VECTOR_CLASS *, int, typename U::cl_type); + + cl_int retain() const + { + if (referenceCountable_) + { + return ReferenceHandler::retain(object_); + } + else + { + return CL_SUCCESS; + } + } + + cl_int release() const + { + if (referenceCountable_) + { + return ReferenceHandler::release(object_); + } + else + { + return CL_SUCCESS; + } + } +}; + +} // namespace detail +//! \endcond + +/*! \stuct ImageFormat + * \brief Adds constructors and member functions for cl_image_format. + * + * \see cl_image_format + */ +struct ImageFormat : public cl_image_format +{ + //! \brief Default constructor - performs no initialization. + ImageFormat() {} + + //! \brief Initializing constructor. + ImageFormat(cl_channel_order order, cl_channel_type type) + { + image_channel_order = order; + image_channel_data_type = type; + } + + //! \brief Assignment operator. + ImageFormat &operator=(const ImageFormat &rhs) + { + if (this != &rhs) + { + this->image_channel_data_type = rhs.image_channel_data_type; + this->image_channel_order = rhs.image_channel_order; + } + return *this; + } +}; + +/*! \brief Class interface for cl_device_id. + * + * \note Copies of these objects are inexpensive, since they don't 'own' + * any underlying resources or data structures. + * + * \see cl_device_id + */ +class Device : public detail::Wrapper +{ + public: + //! \brief Default constructor - initializes to NULL. + Device() : detail::Wrapper() {} + + /*! \brief Constructor from cl_device_id. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + __CL_EXPLICIT_CONSTRUCTORS Device(const cl_device_id &device) : detail::Wrapper(device) {} + + /*! \brief Returns the first device on the default context. + * + * \see Context::getDefault() + */ + static Device getDefault(cl_int *err = NULL); + + /*! \brief Assignment operator from cl_device_id. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + Device &operator=(const cl_device_id &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Device(const Device &dev) : detail::Wrapper(dev) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Device &operator=(const Device &dev) + { + detail::Wrapper::operator=(dev); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Device(Device &&dev) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(dev)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Device &operator=(Device &&dev) + { + detail::Wrapper::operator=(std::move(dev)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetDeviceInfo(). + template + cl_int getInfo(cl_device_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetDeviceInfo, object_, name, param), + __GET_DEVICE_INFO_ERR); + } + + //! \brief Wrapper for clGetDeviceInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_device_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + /** + * CL 1.2 version + */ +#if defined(CL_VERSION_1_2) + //! \brief Wrapper for clCreateSubDevicesEXT(). + cl_int createSubDevices( + const cl_device_partition_property *properties, + VECTOR_CLASS *devices) + { + cl_uint n = 0; + cl_int err = clCreateSubDevices(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id *ids = (cl_device_id *)alloca(n * sizeof(cl_device_id)); + err = clCreateSubDevices(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif // #if defined(CL_VERSION_1_2) + +/** + * CL 1.1 version that uses device fission. + */ +#if defined(CL_VERSION_1_1) +#if defined(USE_CL_DEVICE_FISSION) + cl_int createSubDevices( + const cl_device_partition_property_ext *properties, + VECTOR_CLASS *devices) + { + typedef CL_API_ENTRY cl_int(CL_API_CALL * PFN_clCreateSubDevicesEXT)( + cl_device_id /*in_device*/, + const cl_device_partition_property_ext * /* properties */, + cl_uint /*num_entries*/, + cl_device_id * /*out_devices*/, + cl_uint * /*num_devices*/) CL_EXT_SUFFIX__VERSION_1_1; + + static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; + __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); + + cl_uint n = 0; + cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id *ids = (cl_device_id *)alloca(n * sizeof(cl_device_id)); + err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif // #if defined(USE_CL_DEVICE_FISSION) +#endif // #if defined(CL_VERSION_1_1) +}; + +/*! \brief Class interface for cl_platform_id. + * + * \note Copies of these objects are inexpensive, since they don't 'own' + * any underlying resources or data structures. + * + * \see cl_platform_id + */ +class Platform : public detail::Wrapper +{ + public: + //! \brief Default constructor - initializes to NULL. + Platform() : detail::Wrapper() {} + + /*! \brief Constructor from cl_platform_id. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + __CL_EXPLICIT_CONSTRUCTORS Platform(const cl_platform_id &platform) : detail::Wrapper(platform) {} + + /*! \brief Assignment operator from cl_platform_id. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + Platform &operator=(const cl_platform_id &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetPlatformInfo(). + cl_int getInfo(cl_platform_info name, STRING_CLASS *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetPlatformInfo, object_, name, param), + __GET_PLATFORM_INFO_ERR); + } + + //! \brief Wrapper for clGetPlatformInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_platform_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + /*! \brief Gets a list of devices for this platform. + * + * Wraps clGetDeviceIDs(). + */ + cl_int getDevices( + cl_device_type type, + VECTOR_CLASS *devices) const + { + cl_uint n = 0; + if (devices == NULL) + { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); + } + cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id *ids = (cl_device_id *)alloca(n * sizeof(cl_device_id)); + err = ::clGetDeviceIDs(object_, type, n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + +#if defined(USE_DX_INTEROP) + /*! \brief Get the list of available D3D10 devices. + * + * \param d3d_device_source. + * + * \param d3d_object. + * + * \param d3d_device_set. + * + * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device + * values returned in devices can be used to identify a specific OpenCL + * device. If \a devices argument is NULL, this argument is ignored. + * + * \return One of the following values: + * - CL_SUCCESS if the function is executed successfully. + * + * The application can query specific capabilities of the OpenCL device(s) + * returned by cl::getDevices. This can be used by the application to + * determine which device(s) to use. + * + * \note In the case that exceptions are enabled and a return value + * other than CL_SUCCESS is generated, then cl::Error exception is + * generated. + */ + cl_int getDevices( + cl_d3d10_device_source_khr d3d_device_source, + void *d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + VECTOR_CLASS *devices) const + { + typedef CL_API_ENTRY cl_int(CL_API_CALL * PFN_clGetDeviceIDsFromD3D10KHR)( + cl_platform_id platform, + cl_d3d10_device_source_khr d3d_device_source, + void *d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + cl_uint num_entries, + cl_device_id *devices, + cl_uint *num_devices); + + if (devices == NULL) + { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); + } + + static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; + __INIT_CL_EXT_FCN_PTR_PLATFORM(object_, clGetDeviceIDsFromD3D10KHR); + + cl_uint n = 0; + cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + 0, + NULL, + &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id *ids = (cl_device_id *)alloca(n * sizeof(cl_device_id)); + err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + n, + ids, + NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif + + /*! \brief Gets a list of available platforms. + * + * Wraps clGetPlatformIDs(). + */ + static cl_int get( + VECTOR_CLASS *platforms) + { + cl_uint n = 0; + + if (platforms == NULL) + { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); + } + + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id *ids = (cl_platform_id *)alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + platforms->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + + /*! \brief Gets the first available platform. + * + * Wraps clGetPlatformIDs(), returning the first result. + */ + static cl_int get( + Platform *platform) + { + cl_uint n = 0; + + if (platform == NULL) + { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); + } + + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id *ids = (cl_platform_id *)alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + *platform = ids[0]; + return CL_SUCCESS; + } + + /*! \brief Gets the first available platform, returning it by value. + * + * Wraps clGetPlatformIDs(), returning the first result. + */ + static Platform get( + cl_int *errResult = NULL) + { + Platform platform; + cl_uint n = 0; + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) + { + detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + if (errResult != NULL) + { + *errResult = err; + } + return Platform(); + } + + cl_platform_id *ids = (cl_platform_id *)alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + + if (err != CL_SUCCESS) + { + detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + if (errResult != NULL) + { + *errResult = err; + } + return Platform(); + } + + return Platform(ids[0]); + } + + static Platform getDefault( + cl_int *errResult = NULL) + { + return get(errResult); + } + +#if defined(CL_VERSION_1_2) + //! \brief Wrapper for clUnloadCompiler(). + cl_int + unloadCompiler() + { + return ::clUnloadPlatformCompiler(object_); + } +#endif // #if defined(CL_VERSION_1_2) +}; // class Platform + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +/** + * Unload the OpenCL compiler. + * \note Deprecated for OpenCL 1.2. Use Platform::unloadCompiler instead. + */ +inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int +UnloadCompiler() CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +inline cl_int +UnloadCompiler() +{ + return ::clUnloadCompiler(); +} +#endif // #if defined(CL_VERSION_1_1) + +/*! \brief Class interface for cl_context. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_context as the original. For details, see + * clRetainContext() and clReleaseContext(). + * + * \see cl_context + */ +class Context + : public detail::Wrapper +{ + private: +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + static std::atomic default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static volatile int default_initialized_; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static Context default_; + static volatile cl_int default_error_; + + public: + /*! \brief Constructs a context including a list of specified devices. + * + * Wraps clCreateContext(). + */ + Context( + const VECTOR_CLASS &devices, + cl_context_properties *properties = NULL, + void(CL_CALLBACK *notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void *data = NULL, + cl_int *err = NULL) + { + cl_int error; + + ::size_t numDevices = devices.size(); + cl_device_id *deviceIDs = (cl_device_id *)alloca(numDevices * sizeof(cl_device_id)); + for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) + { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + object_ = ::clCreateContext( + properties, (cl_uint)numDevices, + deviceIDs, + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + if (err != NULL) + { + *err = error; + } + } + + Context( + const Device &device, + cl_context_properties *properties = NULL, + void(CL_CALLBACK *notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void *data = NULL, + cl_int *err = NULL) + { + cl_int error; + + cl_device_id deviceID = device(); + + object_ = ::clCreateContext( + properties, 1, + &deviceID, + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Constructs a context including all or a subset of devices of a specified type. + * + * Wraps clCreateContextFromType(). + */ + Context( + cl_device_type type, + cl_context_properties *properties = NULL, + void(CL_CALLBACK *notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void *data = NULL, + cl_int *err = NULL) + { + cl_int error; + +#if !defined(__APPLE__) && !defined(__MACOS) + cl_context_properties prop[4] = {CL_CONTEXT_PLATFORM, 0, 0, 0}; + + if (properties == NULL) + { + // Get a valid platform ID as we cannot send in a blank one + VECTOR_CLASS platforms; + error = Platform::get(&platforms); + if (error != CL_SUCCESS) + { + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) + { + *err = error; + } + return; + } + + // Check the platforms we found for a device of our specified type + cl_context_properties platform_id = 0; + for (unsigned int i = 0; i < platforms.size(); i++) + { + + VECTOR_CLASS devices; + +#if defined(__CL_ENABLE_EXCEPTIONS) + try + { +#endif + + error = platforms[i].getDevices(type, &devices); + +#if defined(__CL_ENABLE_EXCEPTIONS) + } + catch (Error) + { + } + // Catch if exceptions are enabled as we don't want to exit if first platform has no devices of type + // We do error checking next anyway, and can throw there if needed +#endif + + // Only squash CL_SUCCESS and CL_DEVICE_NOT_FOUND + if (error != CL_SUCCESS && error != CL_DEVICE_NOT_FOUND) + { + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) + { + *err = error; + } + } + + if (devices.size() > 0) + { + platform_id = (cl_context_properties)platforms[i](); + break; + } + } + + if (platform_id == 0) + { + detail::errHandler(CL_DEVICE_NOT_FOUND, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) + { + *err = CL_DEVICE_NOT_FOUND; + } + return; + } + + prop[1] = platform_id; + properties = &prop[0]; + } +#endif + object_ = ::clCreateContextFromType( + properties, type, notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Context(const Context &ctx) : detail::Wrapper(ctx) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Context &operator=(const Context &ctx) + { + detail::Wrapper::operator=(ctx); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Context(Context &&ctx) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(ctx)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Context &operator=(Context &&ctx) + { + detail::Wrapper::operator=(std::move(ctx)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + /*! \brief Returns a singleton context including all devices of CL_DEVICE_TYPE_DEFAULT. + * + * \note All calls to this function return the same cl_context as the first. + */ + static Context getDefault(cl_int *err = NULL) + { + int state = detail::compare_exchange( + &default_initialized_, + __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); + + if (state & __DEFAULT_INITIALIZED) + { + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + if (state & __DEFAULT_BEING_INITIALIZED) + { + // Assume writes will propagate eventually... + while (default_initialized_ != __DEFAULT_INITIALIZED) + { + detail::fence(); + } + + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + cl_int error; + default_ = Context( + CL_DEVICE_TYPE_DEFAULT, + NULL, + NULL, + NULL, + &error); + + detail::fence(); + + default_error_ = error; + // Assume writes will propagate eventually... + default_initialized_ = __DEFAULT_INITIALIZED; + + detail::fence(); + + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + //! \brief Default constructor - initializes to NULL. + Context() : detail::Wrapper() {} + + /*! \brief Constructor from cl_context - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_context + * into the new Context object. + */ + __CL_EXPLICIT_CONSTRUCTORS Context(const cl_context &context) : detail::Wrapper(context) {} + + /*! \brief Assignment operator from cl_context - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseContext() on the value previously held by this instance. + */ + Context &operator=(const cl_context &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetContextInfo(). + template + cl_int getInfo(cl_context_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetContextInfo, object_, name, param), + __GET_CONTEXT_INFO_ERR); + } + + //! \brief Wrapper for clGetContextInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_context_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + /*! \brief Gets a list of supported image formats. + * + * Wraps clGetSupportedImageFormats(). + */ + cl_int getSupportedImageFormats( + cl_mem_flags flags, + cl_mem_object_type type, + VECTOR_CLASS *formats) const + { + cl_uint numEntries; + + if (!formats) + { + return CL_SUCCESS; + } + + cl_int err = ::clGetSupportedImageFormats( + object_, + flags, + type, + 0, + NULL, + &numEntries); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + if (numEntries > 0) + { + ImageFormat *value = (ImageFormat *) + alloca(numEntries * sizeof(ImageFormat)); + err = ::clGetSupportedImageFormats( + object_, + flags, + type, + numEntries, + (cl_image_format *)value, + NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + formats->assign(&value[0], &value[numEntries]); + } + else + { + formats->clear(); + } + return CL_SUCCESS; + } +}; + +inline Device Device::getDefault(cl_int *err) +{ + cl_int error; + Device device; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) + { + *err = error; + } + } + else + { + device = context.getInfo()[0]; + if (err != NULL) + { + *err = CL_SUCCESS; + } + } + + return device; +} + +#ifdef _WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) std::atomic Context::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) Context Context::default_; +__declspec(selectany) volatile cl_int Context::default_error_ = CL_SUCCESS; +#else // !_WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) std::atomic Context::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) Context Context::default_; +__attribute__((weak)) volatile cl_int Context::default_error_ = CL_SUCCESS; +#endif // !_WIN32 + +/*! \brief Class interface for cl_event. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_event as the original. For details, see + * clRetainEvent() and clReleaseEvent(). + * + * \see cl_event + */ +class Event : public detail::Wrapper +{ + public: + //! \brief Default constructor - initializes to NULL. + Event() : detail::Wrapper() {} + + /*! \brief Constructor from cl_event - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_event + * into the new Event object. + */ + __CL_EXPLICIT_CONSTRUCTORS Event(const cl_event &event) : detail::Wrapper(event) {} + + /*! \brief Assignment operator from cl_event - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseEvent() on the value previously held by this instance. + */ + Event &operator=(const cl_event &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetEventInfo(). + template + cl_int getInfo(cl_event_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetEventInfo, object_, name, param), + __GET_EVENT_INFO_ERR); + } + + //! \brief Wrapper for clGetEventInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_event_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + //! \brief Wrapper for clGetEventProfilingInfo(). + template + cl_int getProfilingInfo(cl_profiling_info name, T *param) const + { + return detail::errHandler(detail::getInfo( + &::clGetEventProfilingInfo, object_, name, param), + __GET_EVENT_PROFILE_INFO_ERR); + } + + //! \brief Wrapper for clGetEventProfilingInfo() that returns by value. + template + typename detail::param_traits::param_type + getProfilingInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_profiling_info, name>::param_type param; + cl_int result = getProfilingInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + /*! \brief Blocks the calling thread until this event completes. + * + * Wraps clWaitForEvents(). + */ + cl_int wait() const + { + return detail::errHandler( + ::clWaitForEvents(1, &object_), + __WAIT_FOR_EVENTS_ERR); + } + +#if defined(CL_VERSION_1_1) + /*! \brief Registers a user callback function for a specific command execution status. + * + * Wraps clSetEventCallback(). + */ + cl_int setCallback( + cl_int type, + void(CL_CALLBACK *pfn_notify)(cl_event, cl_int, void *), + void *user_data = NULL) + { + return detail::errHandler( + ::clSetEventCallback( + object_, + type, + pfn_notify, + user_data), + __SET_EVENT_CALLBACK_ERR); + } +#endif + + /*! \brief Blocks the calling thread until every event specified is complete. + * + * Wraps clWaitForEvents(). + */ + static cl_int + waitForEvents(const VECTOR_CLASS &events) + { + return detail::errHandler( + ::clWaitForEvents( + (cl_uint)events.size(), (events.size() > 0) ? (cl_event *)&events.front() : NULL), + __WAIT_FOR_EVENTS_ERR); + } +}; + +#if defined(CL_VERSION_1_1) +/*! \brief Class interface for user events (a subset of cl_event's). + * + * See Event for details about copy semantics, etc. + */ +class UserEvent : public Event +{ + public: + /*! \brief Constructs a user event on a given context. + * + * Wraps clCreateUserEvent(). + */ + UserEvent( + const Context &context, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateUserEvent( + context(), + &error); + + detail::errHandler(error, __CREATE_USER_EVENT_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + UserEvent() : Event() {} + + /*! \brief Sets the execution status of a user event object. + * + * Wraps clSetUserEventStatus(). + */ + cl_int setStatus(cl_int status) + { + return detail::errHandler( + ::clSetUserEventStatus(object_, status), + __SET_USER_EVENT_STATUS_ERR); + } +}; +#endif + +/*! \brief Blocks the calling thread until every event specified is complete. + * + * Wraps clWaitForEvents(). + */ +inline static cl_int +WaitForEvents(const VECTOR_CLASS &events) +{ + return detail::errHandler( + ::clWaitForEvents( + (cl_uint)events.size(), (events.size() > 0) ? (cl_event *)&events.front() : NULL), + __WAIT_FOR_EVENTS_ERR); +} + +/*! \brief Class interface for cl_mem. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_mem as the original. For details, see + * clRetainMemObject() and clReleaseMemObject(). + * + * \see cl_mem + */ +class Memory : public detail::Wrapper +{ + public: + //! \brief Default constructor - initializes to NULL. + Memory() : detail::Wrapper() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_mem + * into the new Memory object. + */ + __CL_EXPLICIT_CONSTRUCTORS Memory(const cl_mem &memory) : detail::Wrapper(memory) {} + + /*! \brief Assignment operator from cl_mem - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseMemObject() on the value previously held by this instance. + */ + Memory &operator=(const cl_mem &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Memory(const Memory &mem) : detail::Wrapper(mem) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Memory &operator=(const Memory &mem) + { + detail::Wrapper::operator=(mem); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Memory(Memory &&mem) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(mem)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Memory &operator=(Memory &&mem) + { + detail::Wrapper::operator=(std::move(mem)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetMemObjectInfo(). + template + cl_int getInfo(cl_mem_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetMemObjectInfo, object_, name, param), + __GET_MEM_OBJECT_INFO_ERR); + } + + //! \brief Wrapper for clGetMemObjectInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_mem_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_1) + /*! \brief Registers a callback function to be called when the memory object + * is no longer needed. + * + * Wraps clSetMemObjectDestructorCallback(). + * + * Repeated calls to this function, for a given cl_mem value, will append + * to the list of functions called (in reverse order) when memory object's + * resources are freed and the memory object is deleted. + * + * \note + * The registered callbacks are associated with the underlying cl_mem + * value - not the Memory class instance. + */ + cl_int setDestructorCallback( + void(CL_CALLBACK *pfn_notify)(cl_mem, void *), + void *user_data = NULL) + { + return detail::errHandler( + ::clSetMemObjectDestructorCallback( + object_, + pfn_notify, + user_data), + __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); + } +#endif +}; + +// Pre-declare copy functions +class Buffer; +template +cl_int copy(IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer); +template +cl_int copy(const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator); +template +cl_int copy(const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer); +template +cl_int copy(const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator); + +/*! \brief Class interface for Buffer Memory Objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Buffer : public Memory +{ + public: + /*! \brief Constructs a Buffer in a specified context. + * + * Wraps clCreateBuffer(). + * + * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was + * specified. Note alignment & exclusivity requirements. + */ + Buffer( + const Context &context, + cl_mem_flags flags, + ::size_t size, + void *host_ptr = NULL, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Constructs a Buffer in the default context. + * + * Wraps clCreateBuffer(). + * + * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was + * specified. Note alignment & exclusivity requirements. + * + * \see Context::getDefault() + */ + Buffer( + cl_mem_flags flags, + ::size_t size, + void *host_ptr = NULL, + cl_int *err = NULL) + { + cl_int error; + + Context context = Context::getDefault(err); + + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! + * \brief Construct a Buffer from a host container via iterators. + * IteratorType must be random access. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template + Buffer( + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr = false, + cl_int *err = NULL) + { + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if (readOnly) + { + flags |= CL_MEM_READ_ONLY; + } + else + { + flags |= CL_MEM_READ_WRITE; + } + if (useHostPtr) + { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType) * (endIterator - startIterator); + + Context context = Context::getDefault(err); + + if (useHostPtr) + { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } + else + { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + if (!useHostPtr) + { + error = cl::copy(startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + } + + /*! + * \brief Construct a Buffer from a host container via iterators using a specified context. + * IteratorType must be random access. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template + Buffer(const Context &context, IteratorType startIterator, IteratorType endIterator, + bool readOnly, bool useHostPtr = false, cl_int *err = NULL); + + /*! + * \brief Construct a Buffer from a host container via iterators using a specified queue. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template + Buffer(const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, + bool readOnly, bool useHostPtr = false, cl_int *err = NULL); + + //! \brief Default constructor - initializes to NULL. + Buffer() : Memory() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Buffer(const cl_mem &buffer) : Memory(buffer) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Buffer &operator=(const cl_mem &rhs) + { + Memory::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Buffer(const Buffer &buf) : Memory(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Buffer &operator=(const Buffer &buf) + { + Memory::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Buffer(Buffer &&buf) CL_HPP_NOEXCEPT : Memory(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Buffer &operator=(Buffer &&buf) + { + Memory::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + +#if defined(CL_VERSION_1_1) + /*! \brief Creates a new buffer object from this. + * + * Wraps clCreateSubBuffer(). + */ + Buffer createSubBuffer( + cl_mem_flags flags, + cl_buffer_create_type buffer_create_type, + const void *buffer_create_info, + cl_int *err = NULL) + { + Buffer result; + cl_int error; + result.object_ = ::clCreateSubBuffer( + object_, + flags, + buffer_create_type, + buffer_create_info, + &error); + + detail::errHandler(error, __CREATE_SUBBUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + return result; + } +#endif +}; + +#if defined(USE_DX_INTEROP) +/*! \brief Class interface for creating OpenCL buffers from ID3D10Buffer's. + * + * This is provided to facilitate interoperability with Direct3D. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferD3D10 : public Buffer +{ + public: + typedef CL_API_ENTRY cl_mem(CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)( + cl_context context, cl_mem_flags flags, ID3D10Buffer *buffer, + cl_int *errcode_ret); + + /*! \brief Constructs a BufferD3D10, in a specified context, from a + * given ID3D10Buffer. + * + * Wraps clCreateFromD3D10BufferKHR(). + */ + BufferD3D10( + const Context &context, + cl_mem_flags flags, + ID3D10Buffer *bufobj, + cl_int *err = NULL) + { + static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; + +#if defined(CL_VERSION_1_2) + vector props = context.getInfo(); + cl_platform platform = -1; + for (int i = 0; i < props.size(); ++i) + { + if (props[i] == CL_CONTEXT_PLATFORM) + { + platform = props[i + 1]; + } + } + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clCreateFromD3D10BufferKHR); +#endif +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); +#endif + + cl_int error; + object_ = pfn_clCreateFromD3D10BufferKHR( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferD3D10() : Buffer() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferD3D10(const cl_mem &buffer) : Buffer(buffer) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferD3D10 &operator=(const cl_mem &rhs) + { + Buffer::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10(const BufferD3D10 &buf) : Buffer(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10 &operator=(const BufferD3D10 &buf) + { + Buffer::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10(BufferD3D10 &&buf) CL_HPP_NOEXCEPT : Buffer(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10 &operator=(BufferD3D10 &&buf) + { + Buffer::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif + +/*! \brief Class interface for GL Buffer Memory Objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferGL : public Buffer +{ + public: + /*! \brief Constructs a BufferGL in a specified context, from a given + * GL buffer. + * + * Wraps clCreateFromGLBuffer(). + */ + BufferGL( + const Context &context, + cl_mem_flags flags, + cl_GLuint bufobj, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLBuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferGL() : Buffer() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferGL(const cl_mem &buffer) : Buffer(buffer) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferGL &operator=(const cl_mem &rhs) + { + Buffer::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferGL(const BufferGL &buf) : Buffer(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferGL &operator=(const BufferGL &buf) + { + Buffer::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferGL(BufferGL &&buf) CL_HPP_NOEXCEPT : Buffer(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferGL &operator=(BufferGL &&buf) + { + Buffer::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetGLObjectInfo(). + cl_int getObjectInfo( + cl_gl_object_type *type, + cl_GLuint *gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_, type, gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \brief C++ base class for Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image : public Memory +{ + protected: + //! \brief Default constructor - initializes to NULL. + Image() : Memory() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image(const cl_mem &image) : Memory(image) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image &operator=(const cl_mem &rhs) + { + Memory::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image(const Image &img) : Memory(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image &operator=(const Image &img) + { + Memory::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image(Image &&img) CL_HPP_NOEXCEPT : Memory(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image &operator=(Image &&img) + { + Memory::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + public: + //! \brief Wrapper for clGetImageInfo(). + template + cl_int getImageInfo(cl_image_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetImageInfo, object_, name, param), + __GET_IMAGE_INFO_ERR); + } + + //! \brief Wrapper for clGetImageInfo() that returns by value. + template + typename detail::param_traits::param_type + getImageInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_image_info, name>::param_type param; + cl_int result = getImageInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } +}; + +#if defined(CL_VERSION_1_2) +/*! \brief Class interface for 1D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image1D : public Image +{ + public: + /*! \brief Constructs a 1D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image1D( + const Context &context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + void *host_ptr = NULL, + cl_int *err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE1D, + width, + 0, 0, 0, 0, 0, 0, 0, 0}; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image1D() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image1D(const cl_mem &image1D) : Image(image1D) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image1D &operator=(const cl_mem &rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1D(const Image1D &img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1D &operator=(const Image1D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1D(Image1D &&img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1D &operator=(Image1D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +/*! \class Image1DBuffer + * \brief Image interface for 1D buffer images. + */ +class Image1DBuffer : public Image +{ + public: + Image1DBuffer( + const Context &context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + const Buffer &buffer, + cl_int *err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE1D_BUFFER, + width, + 0, 0, 0, 0, 0, 0, 0, + buffer()}; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + NULL, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } + + Image1DBuffer() {} + + __CL_EXPLICIT_CONSTRUCTORS Image1DBuffer(const cl_mem &image1D) : Image(image1D) {} + + Image1DBuffer &operator=(const cl_mem &rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer(const Image1DBuffer &img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer &operator=(const Image1DBuffer &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer(Image1DBuffer &&img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer &operator=(Image1DBuffer &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +/*! \class Image1DArray + * \brief Image interface for arrays of 1D images. + */ +class Image1DArray : public Image +{ + public: + Image1DArray( + const Context &context, + cl_mem_flags flags, + ImageFormat format, + ::size_t arraySize, + ::size_t width, + ::size_t rowPitch, + void *host_ptr = NULL, + cl_int *err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE1D_ARRAY, + width, + 0, 0, // height, depth (unused) + arraySize, + rowPitch, + 0, 0, 0, 0}; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } + + Image1DArray() {} + + __CL_EXPLICIT_CONSTRUCTORS Image1DArray(const cl_mem &imageArray) : Image(imageArray) {} + + Image1DArray &operator=(const cl_mem &rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DArray(const Image1DArray &img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DArray &operator=(const Image1DArray &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DArray(Image1DArray &&img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DArray &operator=(Image1DArray &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for 2D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image2D : public Image +{ + public: + /*! \brief Constructs a 1D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image2D( + const Context &context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t row_pitch = 0, + void *host_ptr = NULL, + cl_int *err = NULL) + { + cl_int error; + bool useCreateImage; + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + // Run-time decision based on the actual platform + { + cl_uint version = detail::getContextPlatformVersion(context()); + useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above + } +#elif defined(CL_VERSION_1_2) + useCreateImage = true; +#else + useCreateImage = false; +#endif + +#if defined(CL_VERSION_1_2) + if (useCreateImage) + { + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE2D, + width, + height, + 0, 0, // depth, array size (unused) + row_pitch, + 0, 0, 0, 0}; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) +#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + if (!useCreateImage) + { + object_ = ::clCreateImage2D( + context(), flags, &format, width, height, row_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE2D_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + } + + //! \brief Default constructor - initializes to NULL. + Image2D() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image2D(const cl_mem &image2D) : Image(image2D) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image2D &operator=(const cl_mem &rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2D(const Image2D &img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2D &operator=(const Image2D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2D(Image2D &&img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2D &operator=(Image2D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +#if !defined(CL_VERSION_1_2) +/*! \brief Class interface for GL 2D Image Memory objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + * \note Deprecated for OpenCL 1.2. Please use ImageGL instead. + */ +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED : public Image2D +{ + public: + /*! \brief Constructs an Image2DGL in a specified context, from a given + * GL Texture. + * + * Wraps clCreateFromGLTexture2D(). + */ + Image2DGL( + const Context &context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture2D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_2D_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image2DGL() : Image2D() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image2DGL(const cl_mem &image) : Image2D(image) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image2DGL &operator=(const cl_mem &rhs) + { + Image2D::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DGL(const Image2DGL &img) : Image2D(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DGL &operator=(const Image2DGL &img) + { + Image2D::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DGL(Image2DGL &&img) CL_HPP_NOEXCEPT : Image2D(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DGL &operator=(Image2DGL &&img) + { + Image2D::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if !defined(CL_VERSION_1_2) + +#if defined(CL_VERSION_1_2) +/*! \class Image2DArray + * \brief Image interface for arrays of 2D images. + */ +class Image2DArray : public Image +{ + public: + Image2DArray( + const Context &context, + cl_mem_flags flags, + ImageFormat format, + ::size_t arraySize, + ::size_t width, + ::size_t height, + ::size_t rowPitch, + ::size_t slicePitch, + void *host_ptr = NULL, + cl_int *err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE2D_ARRAY, + width, + height, + 0, // depth (unused) + arraySize, + rowPitch, + slicePitch, + 0, 0, 0}; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } + + Image2DArray() {} + + __CL_EXPLICIT_CONSTRUCTORS Image2DArray(const cl_mem &imageArray) : Image(imageArray) {} + + Image2DArray &operator=(const cl_mem &rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DArray(const Image2DArray &img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DArray &operator=(const Image2DArray &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DArray(Image2DArray &&img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DArray &operator=(Image2DArray &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for 3D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image3D : public Image +{ + public: + /*! \brief Constructs a 3D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image3D( + const Context &context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t depth, + ::size_t row_pitch = 0, + ::size_t slice_pitch = 0, + void *host_ptr = NULL, + cl_int *err = NULL) + { + cl_int error; + bool useCreateImage; + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + // Run-time decision based on the actual platform + { + cl_uint version = detail::getContextPlatformVersion(context()); + useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above + } +#elif defined(CL_VERSION_1_2) + useCreateImage = true; +#else + useCreateImage = false; +#endif + +#if defined(CL_VERSION_1_2) + if (useCreateImage) + { + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE3D, + width, + height, + depth, + 0, // array size (unused) + row_pitch, + slice_pitch, + 0, 0, 0}; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) +#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + if (!useCreateImage) + { + object_ = ::clCreateImage3D( + context(), flags, &format, width, height, depth, row_pitch, + slice_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE3D_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + } + + //! \brief Default constructor - initializes to NULL. + Image3D() : Image() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image3D(const cl_mem &image3D) : Image(image3D) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image3D &operator=(const cl_mem &rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3D(const Image3D &img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3D &operator=(const Image3D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3D(Image3D &&img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3D &operator=(Image3D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +#if !defined(CL_VERSION_1_2) +/*! \brief Class interface for GL 3D Image Memory objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image3DGL : public Image3D +{ + public: + /*! \brief Constructs an Image3DGL in a specified context, from a given + * GL Texture. + * + * Wraps clCreateFromGLTexture3D(). + */ + Image3DGL( + const Context &context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture3D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_3D_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image3DGL() : Image3D() {} + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image3DGL(const cl_mem &image) : Image3D(image) {} + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image3DGL &operator=(const cl_mem &rhs) + { + Image3D::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3DGL(const Image3DGL &img) : Image3D(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3DGL &operator=(const Image3DGL &img) + { + Image3D::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3DGL(Image3DGL &&img) CL_HPP_NOEXCEPT : Image3D(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3DGL &operator=(Image3DGL &&img) + { + Image3D::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if !defined(CL_VERSION_1_2) + +#if defined(CL_VERSION_1_2) +/*! \class ImageGL + * \brief general image interface for GL interop. + * We abstract the 2D and 3D GL images into a single instance here + * that wraps all GL sourced images on the grounds that setup information + * was performed by OpenCL anyway. + */ +class ImageGL : public Image +{ + public: + ImageGL( + const Context &context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_ERR); + if (err != NULL) + { + *err = error; + } + } + + ImageGL() : Image() {} + + __CL_EXPLICIT_CONSTRUCTORS ImageGL(const cl_mem &image) : Image(image) {} + + ImageGL &operator=(const cl_mem &rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + ImageGL(const ImageGL &img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + ImageGL &operator=(const ImageGL &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + ImageGL(ImageGL &&img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + ImageGL &operator=(ImageGL &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for GL Render Buffer Memory Objects. +* +* This is provided to facilitate interoperability with OpenGL. +* +* See Memory for details about copy semantics, etc. +* +* \see Memory +*/ +class BufferRenderGL : +#if defined(CL_VERSION_1_2) + public ImageGL +#else // #if defined(CL_VERSION_1_2) + public Image2DGL +#endif //#if defined(CL_VERSION_1_2) +{ + public: + /*! \brief Constructs a BufferRenderGL in a specified context, from a given + * GL Renderbuffer. + * + * Wraps clCreateFromGLRenderbuffer(). + */ + BufferRenderGL( + const Context &context, + cl_mem_flags flags, + cl_GLuint bufobj, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLRenderbuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_RENDER_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. +#if defined(CL_VERSION_1_2) + BufferRenderGL() : ImageGL(){}; +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL() : Image2DGL(){}; +#endif //#if defined(CL_VERSION_1_2) + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ +#if defined(CL_VERSION_1_2) + __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem &buffer) : ImageGL(buffer) + { + } +#else // #if defined(CL_VERSION_1_2) + __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem &buffer) : Image2DGL(buffer) + { + } +#endif //#if defined(CL_VERSION_1_2) + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferRenderGL &operator=(const cl_mem &rhs) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(rhs); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(rhs); +#endif //#if defined(CL_VERSION_1_2) + + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ +#if defined(CL_VERSION_1_2) + BufferRenderGL(const BufferRenderGL &buf) : ImageGL(buf) + { + } +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL(const BufferRenderGL &buf) : Image2DGL(buf) + { + } +#endif //#if defined(CL_VERSION_1_2) + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferRenderGL &operator=(const BufferRenderGL &rhs) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(rhs); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(rhs); +#endif //#if defined(CL_VERSION_1_2) + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ +#if defined(CL_VERSION_1_2) + BufferRenderGL(BufferRenderGL &&buf) CL_HPP_NOEXCEPT : ImageGL(std::move(buf)) + { + } +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL(BufferRenderGL &&buf) CL_HPP_NOEXCEPT : Image2DGL(std::move(buf)) + { + } +#endif //#if defined(CL_VERSION_1_2) + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferRenderGL &operator=(BufferRenderGL &&buf) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(std::move(buf)); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(std::move(buf)); +#endif //#if defined(CL_VERSION_1_2) + + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetGLObjectInfo(). + cl_int getObjectInfo( + cl_gl_object_type *type, + cl_GLuint *gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_, type, gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \brief Class interface for cl_sampler. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_sampler as the original. For details, see + * clRetainSampler() and clReleaseSampler(). + * + * \see cl_sampler + */ +class Sampler : public detail::Wrapper +{ + public: + //! \brief Default constructor - initializes to NULL. + Sampler() {} + + /*! \brief Constructs a Sampler in a specified context. + * + * Wraps clCreateSampler(). + */ + Sampler( + const Context &context, + cl_bool normalized_coords, + cl_addressing_mode addressing_mode, + cl_filter_mode filter_mode, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateSampler( + context(), + normalized_coords, + addressing_mode, + filter_mode, + &error); + + detail::errHandler(error, __CREATE_SAMPLER_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Constructor from cl_sampler - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_sampler + * into the new Sampler object. + */ + __CL_EXPLICIT_CONSTRUCTORS Sampler(const cl_sampler &sampler) : detail::Wrapper(sampler) {} + + /*! \brief Assignment operator from cl_sampler - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseSampler() on the value previously held by this instance. + */ + Sampler &operator=(const cl_sampler &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Sampler(const Sampler &sam) : detail::Wrapper(sam) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Sampler &operator=(const Sampler &sam) + { + detail::Wrapper::operator=(sam); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Sampler(Sampler &&sam) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(sam)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Sampler &operator=(Sampler &&sam) + { + detail::Wrapper::operator=(std::move(sam)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetSamplerInfo(). + template + cl_int getInfo(cl_sampler_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetSamplerInfo, object_, name, param), + __GET_SAMPLER_INFO_ERR); + } + + //! \brief Wrapper for clGetSamplerInfo() that returns by value. + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_sampler_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } +}; + +class Program; +class CommandQueue; +class Kernel; + +//! \brief Class interface for specifying NDRange values. +class NDRange +{ + private: + size_t<3> sizes_; + cl_uint dimensions_; + + public: + //! \brief Default constructor - resulting range has zero dimensions. + NDRange() + : dimensions_(0) + { + } + + //! \brief Constructs one-dimensional range. + NDRange(::size_t size0) + : dimensions_(1) + { + sizes_[0] = size0; + } + + //! \brief Constructs two-dimensional range. + NDRange(::size_t size0, ::size_t size1) + : dimensions_(2) + { + sizes_[0] = size0; + sizes_[1] = size1; + } + + //! \brief Constructs three-dimensional range. + NDRange(::size_t size0, ::size_t size1, ::size_t size2) + : dimensions_(3) + { + sizes_[0] = size0; + sizes_[1] = size1; + sizes_[2] = size2; + } + + /*! \brief Conversion operator to const ::size_t *. + * + * \returns a pointer to the size of the first dimension. + */ + operator const ::size_t *() const + { + return (const ::size_t *)sizes_; + } + + //! \brief Queries the number of dimensions in the range. + ::size_t dimensions() const { return dimensions_; } +}; + +//! \brief A zero-dimensional range. +static const NDRange NullRange; + +//! \brief Local address wrapper for use with Kernel::setArg +struct LocalSpaceArg +{ + ::size_t size_; +}; + +namespace detail +{ + +template +struct KernelArgumentHandler +{ + static ::size_t size(const T &) { return sizeof(T); } + static const T *ptr(const T &value) { return &value; } +}; + +template <> +struct KernelArgumentHandler +{ + static ::size_t size(const LocalSpaceArg &value) { return value.size_; } + static const void *ptr(const LocalSpaceArg &) { return NULL; } +}; + +} // namespace detail +//! \endcond + +/*! __local + * \brief Helper function for generating LocalSpaceArg objects. + * Deprecated. Replaced with Local. + */ +inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED LocalSpaceArg +__local(::size_t size) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +inline LocalSpaceArg +__local(::size_t size) +{ + LocalSpaceArg ret = {size}; + return ret; +} + +/*! Local + * \brief Helper function for generating LocalSpaceArg objects. + */ +inline LocalSpaceArg +Local(::size_t size) +{ + LocalSpaceArg ret = {size}; + return ret; +} + +//class KernelFunctor; + +/*! \brief Class interface for cl_kernel. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_kernel as the original. For details, see + * clRetainKernel() and clReleaseKernel(). + * + * \see cl_kernel + */ +class Kernel : public detail::Wrapper +{ + public: + inline Kernel(const Program &program, const char *name, cl_int *err = NULL); + + //! \brief Default constructor - initializes to NULL. + Kernel() {} + + /*! \brief Constructor from cl_kernel - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_kernel + * into the new Kernel object. + */ + __CL_EXPLICIT_CONSTRUCTORS Kernel(const cl_kernel &kernel) : detail::Wrapper(kernel) {} + + /*! \brief Assignment operator from cl_kernel - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseKernel() on the value previously held by this instance. + */ + Kernel &operator=(const cl_kernel &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Kernel(const Kernel &kernel) : detail::Wrapper(kernel) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Kernel &operator=(const Kernel &kernel) + { + detail::Wrapper::operator=(kernel); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Kernel(Kernel &&kernel) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(kernel)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Kernel &operator=(Kernel &&kernel) + { + detail::Wrapper::operator=(std::move(kernel)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + template + cl_int getInfo(cl_kernel_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelInfo, object_, name, param), + __GET_KERNEL_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_2) + template + cl_int getArgInfo(cl_uint argIndex, cl_kernel_arg_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelArgInfo, object_, argIndex, name, param), + __GET_KERNEL_ARG_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getArgInfo(cl_uint argIndex, cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_arg_info, name>::param_type param; + cl_int result = getArgInfo(argIndex, name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } +#endif // #if defined(CL_VERSION_1_2) + + template + cl_int getWorkGroupInfo( + const Device &device, cl_kernel_work_group_info name, T *param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetKernelWorkGroupInfo, object_, device(), name, param), + __GET_KERNEL_WORK_GROUP_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getWorkGroupInfo(const Device &device, cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_work_group_info, name>::param_type param; + cl_int result = getWorkGroupInfo(device, name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + template + cl_int setArg(cl_uint index, const T &value) + { + return detail::errHandler( + ::clSetKernelArg( + object_, + index, + detail::KernelArgumentHandler::size(value), + detail::KernelArgumentHandler::ptr(value)), + __SET_KERNEL_ARGS_ERR); + } + + cl_int setArg(cl_uint index, ::size_t size, const void *argPtr) + { + return detail::errHandler( + ::clSetKernelArg(object_, index, size, argPtr), + __SET_KERNEL_ARGS_ERR); + } +}; + +/*! \class Program + * \brief Program interface that implements cl_program. + */ +class Program : public detail::Wrapper +{ + public: + typedef VECTOR_CLASS> Binaries; + typedef VECTOR_CLASS> Sources; + + Program( + const STRING_CLASS &source, + bool build = false, + cl_int *err = NULL) + { + cl_int error; + + const char *strings = source.c_str(); + const ::size_t length = source.size(); + + Context context = Context::getDefault(err); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS && build) + { + + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) + { + *err = error; + } + } + + Program( + const Context &context, + const STRING_CLASS &source, + bool build = false, + cl_int *err = NULL) + { + cl_int error; + + const char *strings = source.c_str(); + const ::size_t length = source.size(); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS && build) + { + + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) + { + *err = error; + } + } + + Program( + const Context &context, + const Sources &sources, + cl_int *err = NULL) + { + cl_int error; + + const ::size_t n = (::size_t)sources.size(); + ::size_t *lengths = (::size_t *)alloca(n * sizeof(::size_t)); + const char **strings = (const char **)alloca(n * sizeof(const char *)); + + for (::size_t i = 0; i < n; ++i) + { + strings[i] = sources[(int)i].first; + lengths[i] = sources[(int)i].second; + } + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)n, strings, lengths, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + if (err != NULL) + { + *err = error; + } + } + + /** + * Construct a program object from a list of devices and a per-device list of binaries. + * \param context A valid OpenCL context in which to construct the program. + * \param devices A vector of OpenCL device objects for which the program will be created. + * \param binaries A vector of pairs of a pointer to a binary object and its length. + * \param binaryStatus An optional vector that on completion will be resized to + * match the size of binaries and filled with values to specify if each binary + * was successfully loaded. + * Set to CL_SUCCESS if the binary was successfully loaded. + * Set to CL_INVALID_VALUE if the length is 0 or the binary pointer is NULL. + * Set to CL_INVALID_BINARY if the binary provided is not valid for the matching device. + * \param err if non-NULL will be set to CL_SUCCESS on successful operation or one of the following errors: + * CL_INVALID_CONTEXT if context is not a valid context. + * CL_INVALID_VALUE if the length of devices is zero; or if the length of binaries does not match the length of devices; + * or if any entry in binaries is NULL or has length 0. + * CL_INVALID_DEVICE if OpenCL devices listed in devices are not in the list of devices associated with context. + * CL_INVALID_BINARY if an invalid program binary was encountered for any device. binaryStatus will return specific status for each device. + * CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required by the OpenCL implementation on the host. + */ + Program( + const Context &context, + const VECTOR_CLASS &devices, + const Binaries &binaries, + VECTOR_CLASS *binaryStatus = NULL, + cl_int *err = NULL) + { + cl_int error; + + const ::size_t numDevices = devices.size(); + + // Catch size mismatch early and return + if (binaries.size() != numDevices) + { + error = CL_INVALID_VALUE; + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) + { + *err = error; + } + return; + } + + ::size_t *lengths = (::size_t *)alloca(numDevices * sizeof(::size_t)); + const unsigned char **images = (const unsigned char **)alloca(numDevices * sizeof(const unsigned char **)); + + for (::size_t i = 0; i < numDevices; ++i) + { + images[i] = (const unsigned char *)binaries[i].first; + lengths[i] = binaries[(int)i].second; + } + + cl_device_id *deviceIDs = (cl_device_id *)alloca(numDevices * sizeof(cl_device_id)); + for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) + { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + if (binaryStatus) + { + binaryStatus->resize(numDevices); + } + + object_ = ::clCreateProgramWithBinary( + context(), (cl_uint)devices.size(), + deviceIDs, + lengths, images, (binaryStatus != NULL && numDevices > 0) ? &binaryStatus->front() : NULL, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) + { + *err = error; + } + } + +#if defined(CL_VERSION_1_2) + /** + * Create program using builtin kernels. + * \param kernelNames Semi-colon separated list of builtin kernel names + */ + Program( + const Context &context, + const VECTOR_CLASS &devices, + const STRING_CLASS &kernelNames, + cl_int *err = NULL) + { + cl_int error; + + ::size_t numDevices = devices.size(); + cl_device_id *deviceIDs = (cl_device_id *)alloca(numDevices * sizeof(cl_device_id)); + for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) + { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + object_ = ::clCreateProgramWithBuiltInKernels( + context(), + (cl_uint)devices.size(), + deviceIDs, + kernelNames.c_str(), + &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR); + if (err != NULL) + { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) + + Program() + { + } + + __CL_EXPLICIT_CONSTRUCTORS Program(const cl_program &program) : detail::Wrapper(program) {} + + Program &operator=(const cl_program &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Program(const Program &program) : detail::Wrapper(program) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Program &operator=(const Program &program) + { + detail::Wrapper::operator=(program); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Program(Program &&program) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(program)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Program &operator=(Program &&program) + { + detail::Wrapper::operator=(std::move(program)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + cl_int build( + const VECTOR_CLASS &devices, + const char *options = NULL, + void(CL_CALLBACK *notifyFptr)(cl_program, void *) = NULL, + void *data = NULL) const + { + ::size_t numDevices = devices.size(); + cl_device_id *deviceIDs = (cl_device_id *)alloca(numDevices * sizeof(cl_device_id)); + for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) + { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + return detail::errHandler( + ::clBuildProgram( + object_, + (cl_uint) + devices.size(), + deviceIDs, + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + + cl_int build( + const char *options = NULL, + void(CL_CALLBACK *notifyFptr)(cl_program, void *) = NULL, + void *data = NULL) const + { + return detail::errHandler( + ::clBuildProgram( + object_, + 0, + NULL, + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + +#if defined(CL_VERSION_1_2) + cl_int compile( + const char *options = NULL, + void(CL_CALLBACK *notifyFptr)(cl_program, void *) = NULL, + void *data = NULL) const + { + return detail::errHandler( + ::clCompileProgram( + object_, + 0, + NULL, + options, + 0, + NULL, + NULL, + notifyFptr, + data), + __COMPILE_PROGRAM_ERR); + } +#endif + + template + cl_int getInfo(cl_program_info name, T *param) const + { + return detail::errHandler( + detail::getInfo(&::clGetProgramInfo, object_, name, param), + __GET_PROGRAM_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_program_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + template + cl_int getBuildInfo( + const Device &device, cl_program_build_info name, T *param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetProgramBuildInfo, object_, device(), name, param), + __GET_PROGRAM_BUILD_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getBuildInfo(const Device &device, cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_program_build_info, name>::param_type param; + cl_int result = getBuildInfo(device, name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + cl_int createKernels(VECTOR_CLASS *kernels) + { + cl_uint numKernels; + cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + Kernel *value = (Kernel *)alloca(numKernels * sizeof(Kernel)); + err = ::clCreateKernelsInProgram( + object_, numKernels, (cl_kernel *)value, NULL); + if (err != CL_SUCCESS) + { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + kernels->assign(&value[0], &value[numKernels]); + return CL_SUCCESS; + } +}; + +#if defined(CL_VERSION_1_2) +inline Program linkProgram( + Program input1, + Program input2, + const char *options = NULL, + void(CL_CALLBACK *notifyFptr)(cl_program, void *) = NULL, + void *data = NULL, + cl_int *err = NULL) +{ + cl_int error_local = CL_SUCCESS; + + cl_program programs[2] = {input1(), input2()}; + + Context ctx = input1.getInfo(&error_local); + if (error_local != CL_SUCCESS) + { + detail::errHandler(error_local, __LINK_PROGRAM_ERR); + } + + cl_program prog = ::clLinkProgram( + ctx(), + 0, + NULL, + options, + 2, + programs, + notifyFptr, + data, + &error_local); + + detail::errHandler(error_local, __COMPILE_PROGRAM_ERR); + if (err != NULL) + { + *err = error_local; + } + + return Program(prog); +} + +inline Program linkProgram( + VECTOR_CLASS inputPrograms, + const char *options = NULL, + void(CL_CALLBACK *notifyFptr)(cl_program, void *) = NULL, + void *data = NULL, + cl_int *err = NULL) +{ + cl_int error_local = CL_SUCCESS; + + cl_program *programs = (cl_program *)alloca(inputPrograms.size() * sizeof(cl_program)); + + if (programs != NULL) + { + for (unsigned int i = 0; i < inputPrograms.size(); i++) + { + programs[i] = inputPrograms[i](); + } + } + + Context ctx; + if (inputPrograms.size() > 0) + { + ctx = inputPrograms[0].getInfo(&error_local); + if (error_local != CL_SUCCESS) + { + detail::errHandler(error_local, __LINK_PROGRAM_ERR); + } + } + cl_program prog = ::clLinkProgram( + ctx(), + 0, + NULL, + options, + (cl_uint)inputPrograms.size(), + programs, + notifyFptr, + data, + &error_local); + + detail::errHandler(error_local, __COMPILE_PROGRAM_ERR); + if (err != NULL) + { + *err = error_local; + } + + return Program(prog); +} +#endif + +template <> +inline VECTOR_CLASS cl::Program::getInfo(cl_int *err) const +{ + VECTOR_CLASS<::size_t> sizes = getInfo(); + VECTOR_CLASS binaries; + for (VECTOR_CLASS<::size_t>::iterator s = sizes.begin(); s != sizes.end(); ++s) + { + char *ptr = NULL; + if (*s != 0) + ptr = new char[*s]; + binaries.push_back(ptr); + } + + cl_int result = getInfo(CL_PROGRAM_BINARIES, &binaries); + if (err != NULL) + { + *err = result; + } + return binaries; +} + +inline Kernel::Kernel(const Program &program, const char *name, cl_int *err) +{ + cl_int error; + + object_ = ::clCreateKernel(program(), name, &error); + detail::errHandler(error, __CREATE_KERNEL_ERR); + + if (err != NULL) + { + *err = error; + } +} + +/*! \class CommandQueue + * \brief CommandQueue interface for cl_command_queue. + */ +class CommandQueue : public detail::Wrapper +{ + private: +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + static std::atomic default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static volatile int default_initialized_; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static CommandQueue default_; + static volatile cl_int default_error_; + + public: + CommandQueue( + cl_command_queue_properties properties, + cl_int *err = NULL) + { + cl_int error; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) + { + *err = error; + } + } + else + { + Device device = context.getInfo()[0]; + + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) + { + *err = error; + } + } + } + /*! + * \brief Constructs a CommandQueue for an implementation defined device in the given context + */ + explicit CommandQueue( + const Context &context, + cl_command_queue_properties properties = 0, + cl_int *err = NULL) + { + cl_int error; + VECTOR_CLASS devices; + error = context.getInfo(CL_CONTEXT_DEVICES, &devices); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) + { + *err = error; + } + return; + } + + object_ = ::clCreateCommandQueue(context(), devices[0](), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (err != NULL) + { + *err = error; + } + } + + CommandQueue( + const Context &context, + const Device &device, + cl_command_queue_properties properties = 0, + cl_int *err = NULL) + { + cl_int error; + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) + { + *err = error; + } + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + CommandQueue(const CommandQueue &queue) : detail::Wrapper(queue) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + CommandQueue &operator=(const CommandQueue &queue) + { + detail::Wrapper::operator=(queue); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + CommandQueue(CommandQueue &&queue) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(queue)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + CommandQueue &operator=(CommandQueue &&queue) + { + detail::Wrapper::operator=(std::move(queue)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + static CommandQueue getDefault(cl_int *err = NULL) + { + int state = detail::compare_exchange( + &default_initialized_, + __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); + + if (state & __DEFAULT_INITIALIZED) + { + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + if (state & __DEFAULT_BEING_INITIALIZED) + { + // Assume writes will propagate eventually... + while (default_initialized_ != __DEFAULT_INITIALIZED) + { + detail::fence(); + } + + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + cl_int error; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) + { + *err = error; + } + } + else + { + Device device = context.getInfo()[0]; + + default_ = CommandQueue(context, device, 0, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) + { + *err = error; + } + } + + detail::fence(); + + default_error_ = error; + // Assume writes will propagate eventually... + default_initialized_ = __DEFAULT_INITIALIZED; + + detail::fence(); + + if (err != NULL) + { + *err = default_error_; + } + return default_; + } + + CommandQueue() {} + + __CL_EXPLICIT_CONSTRUCTORS CommandQueue(const cl_command_queue &commandQueue) : detail::Wrapper(commandQueue) {} + + CommandQueue &operator=(const cl_command_queue &rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + template + cl_int getInfo(cl_command_queue_info name, T *param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetCommandQueueInfo, object_, name, param), + __GET_COMMAND_QUEUE_INFO_ERR); + } + + template + typename detail::param_traits::param_type + getInfo(cl_int *err = NULL) const + { + typename detail::param_traits< + detail::cl_command_queue_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) + { + *err = result; + } + return param; + } + + cl_int enqueueReadBuffer( + const Buffer &buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteBuffer( + const Buffer &buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBuffer( + const Buffer &src, + const Buffer &dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBuffer( + object_, src(), dst(), src_offset, dst_offset, size, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQEUE_COPY_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReadBufferRect( + const Buffer &buffer, + cl_bool blocking, + const size_t<3> &buffer_offset, + const size_t<3> &host_offset, + const size_t<3> ®ion, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteBufferRect( + const Buffer &buffer, + cl_bool blocking, + const size_t<3> &buffer_offset, + const size_t<3> &host_offset, + const size_t<3> ®ion, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBufferRect( + const Buffer &src, + const Buffer &dst, + const size_t<3> &src_origin, + const size_t<3> &dst_origin, + const size_t<3> ®ion, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBufferRect( + object_, + src(), + dst(), + (const ::size_t *)src_origin, + (const ::size_t *)dst_origin, + (const ::size_t *)region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQEUE_COPY_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueue a command to fill a buffer object with a pattern + * of a given size. The pattern is specified a as vector. + * \tparam PatternType The datatype of the pattern field. + * The pattern type must be an accepted OpenCL data type. + */ + template + cl_int enqueueFillBuffer( + const Buffer &buffer, + PatternType pattern, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillBuffer( + object_, + buffer(), + static_cast(&pattern), + sizeof(PatternType), + offset, + size, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueReadImage( + const Image &image, + cl_bool blocking, + const size_t<3> &origin, + const size_t<3> ®ion, + ::size_t row_pitch, + ::size_t slice_pitch, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadImage( + object_, image(), blocking, (const ::size_t *)origin, + (const ::size_t *)region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteImage( + const Image &image, + cl_bool blocking, + const size_t<3> &origin, + const size_t<3> ®ion, + ::size_t row_pitch, + ::size_t slice_pitch, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteImage( + object_, image(), blocking, (const ::size_t *)origin, + (const ::size_t *)region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyImage( + const Image &src, + const Image &dst, + const size_t<3> &src_origin, + const size_t<3> &dst_origin, + const size_t<3> ®ion, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyImage( + object_, src(), dst(), (const ::size_t *)src_origin, + (const ::size_t *)dst_origin, (const ::size_t *)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA floating-point color value if + * the image channel data type is not an unnormalized signed or + * unsigned data type. + */ + cl_int enqueueFillImage( + const Image &image, + cl_float4 fillColor, + const size_t<3> &origin, + const size_t<3> ®ion, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *)origin, + (const ::size_t *)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA signed integer color value if + * the image channel data type is an unnormalized signed integer + * type. + */ + cl_int enqueueFillImage( + const Image &image, + cl_int4 fillColor, + const size_t<3> &origin, + const size_t<3> ®ion, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *)origin, + (const ::size_t *)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA unsigned integer color value if + * the image channel data type is an unnormalized unsigned integer + * type. + */ + cl_int enqueueFillImage( + const Image &image, + cl_uint4 fillColor, + const size_t<3> &origin, + const size_t<3> ®ion, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *)origin, + (const ::size_t *)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueCopyImageToBuffer( + const Image &src, + const Buffer &dst, + const size_t<3> &src_origin, + const size_t<3> ®ion, + ::size_t dst_offset, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyImageToBuffer( + object_, src(), dst(), (const ::size_t *)src_origin, + (const ::size_t *)region, dst_offset, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBufferToImage( + const Buffer &src, + const Image &dst, + ::size_t src_offset, + const size_t<3> &dst_origin, + const size_t<3> ®ion, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBufferToImage( + object_, src(), dst(), src_offset, + (const ::size_t *)dst_origin, (const ::size_t *)region, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + void *enqueueMapBuffer( + const Buffer &buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS *events = NULL, + Event *event = NULL, + cl_int *err = NULL) const + { + cl_event tmp; + cl_int error; + void *result = ::clEnqueueMapBuffer( + object_, buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + if (event != NULL && error == CL_SUCCESS) + *event = tmp; + + return result; + } + + void *enqueueMapImage( + const Image &buffer, + cl_bool blocking, + cl_map_flags flags, + const size_t<3> &origin, + const size_t<3> ®ion, + ::size_t *row_pitch, + ::size_t *slice_pitch, + const VECTOR_CLASS *events = NULL, + Event *event = NULL, + cl_int *err = NULL) const + { + cl_event tmp; + cl_int error; + void *result = ::clEnqueueMapImage( + object_, buffer(), blocking, flags, + (const ::size_t *)origin, (const ::size_t *)region, + row_pitch, slice_pitch, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); + if (err != NULL) + { + *err = error; + } + if (event != NULL && error == CL_SUCCESS) + *event = tmp; + return result; + } + + cl_int enqueueUnmapMemObject( + const Memory &memory, + void *mapped_ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueUnmapMemObject( + object_, memory(), mapped_ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueues a marker command which waits for either a list of events to complete, + * or all previously enqueued commands to complete. + * + * Enqueues a marker command which waits for either a list of events to complete, + * or if the list is empty it waits for all commands previously enqueued in command_queue + * to complete before it completes. This command returns an event which can be waited on, + * i.e. this event can be waited on to insure that all events either in the event_wait_list + * or all previously enqueued commands, queued before this command to command_queue, + * have completed. + */ + cl_int enqueueMarkerWithWaitList( + const VECTOR_CLASS *events = 0, + Event *event = 0) + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueMarkerWithWaitList( + object_, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_MARKER_WAIT_LIST_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * A synchronization point that enqueues a barrier operation. + * + * Enqueues a barrier command which waits for either a list of events to complete, + * or if the list is empty it waits for all commands previously enqueued in command_queue + * to complete before it completes. This command blocks command execution, that is, any + * following commands enqueued after it do not execute until it completes. This command + * returns an event which can be waited on, i.e. this event can be waited on to insure that + * all events either in the event_wait_list or all previously enqueued commands, queued + * before this command to command_queue, have completed. + */ + cl_int enqueueBarrierWithWaitList( + const VECTOR_CLASS *events = 0, + Event *event = 0) + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueBarrierWithWaitList( + object_, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_BARRIER_WAIT_LIST_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueues a command to indicate with which device a set of memory objects + * should be associated. + */ + cl_int enqueueMigrateMemObjects( + const VECTOR_CLASS &memObjects, + cl_mem_migration_flags flags, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) + { + cl_event tmp; + + cl_mem *localMemObjects = static_cast(alloca(memObjects.size() * sizeof(cl_mem))); + for (int i = 0; i < (int)memObjects.size(); ++i) + { + localMemObjects[i] = memObjects[i](); + } + + cl_int err = detail::errHandler( + ::clEnqueueMigrateMemObjects( + object_, + (cl_uint)memObjects.size(), + static_cast(localMemObjects), + flags, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueNDRangeKernel( + const Kernel &kernel, + const NDRange &offset, + const NDRange &global, + const NDRange &local = NullRange, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueNDRangeKernel( + object_, kernel(), (cl_uint)global.dimensions(), + offset.dimensions() != 0 ? (const ::size_t *)offset : NULL, + (const ::size_t *)global, + local.dimensions() != 0 ? (const ::size_t *)local : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_NDRANGE_KERNEL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueTask( + const Kernel &kernel, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueTask( + object_, kernel(), + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_TASK_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueNativeKernel( + void(CL_CALLBACK *userFptr)(void *), + std::pair args, + const VECTOR_CLASS *mem_objects = NULL, + const VECTOR_CLASS *mem_locs = NULL, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_mem *mems = (mem_objects != NULL && mem_objects->size() > 0) + ? (cl_mem *)alloca(mem_objects->size() * sizeof(cl_mem)) + : NULL; + + if (mems != NULL) + { + for (unsigned int i = 0; i < mem_objects->size(); i++) + { + mems[i] = ((*mem_objects)[i])(); + } + } + + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueNativeKernel( + object_, userFptr, args.first, args.second, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + mems, + (mem_locs != NULL && mem_locs->size() > 0) ? (const void **)&mem_locs->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_NATIVE_KERNEL); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueMarker(Event *event = NULL) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueMarker( + object_, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_MARKER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueWaitForEvents(const VECTOR_CLASS &events) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueWaitForEvents( + object_, + (cl_uint)events.size(), + events.size() > 0 ? (const cl_event *)&events.front() : NULL), + __ENQUEUE_WAIT_FOR_EVENTS_ERR); + } +#endif // #if defined(CL_VERSION_1_1) + + cl_int enqueueAcquireGLObjects( + const VECTOR_CLASS *mem_objects = NULL, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueAcquireGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *)&mem_objects->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_ACQUIRE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReleaseGLObjects( + const VECTOR_CLASS *mem_objects = NULL, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReleaseGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *)&mem_objects->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_RELEASE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(USE_DX_INTEROP) + typedef CL_API_ENTRY cl_int(CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem *mem_objects, cl_uint num_events_in_wait_list, + const cl_event *event_wait_list, cl_event *event); + typedef CL_API_ENTRY cl_int(CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem *mem_objects, cl_uint num_events_in_wait_list, + const cl_event *event_wait_list, cl_event *event); + + cl_int enqueueAcquireD3D10Objects( + const VECTOR_CLASS *mem_objects = NULL, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; +#if defined(CL_VERSION_1_2) + cl_context context = getInfo(); + cl::Device device(getInfo()); + cl_platform_id platform = device.getInfo(); + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueAcquireD3D10ObjectsKHR); +#endif +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); +#endif + + cl_event tmp; + cl_int err = detail::errHandler( + pfn_clEnqueueAcquireD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *)&mem_objects->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_ACQUIRE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReleaseD3D10Objects( + const VECTOR_CLASS *mem_objects = NULL, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) const + { + static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; +#if defined(CL_VERSION_1_2) + cl_context context = getInfo(); + cl::Device device(getInfo()); + cl_platform_id platform = device.getInfo(); + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueReleaseD3D10ObjectsKHR); +#endif // #if defined(CL_VERSION_1_2) +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); +#endif // #if defined(CL_VERSION_1_1) + + cl_event tmp; + cl_int err = detail::errHandler( + pfn_clEnqueueReleaseD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *)&mem_objects->front() : NULL, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_RELEASE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueBarrier() const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueBarrier(object_), + __ENQUEUE_BARRIER_ERR); + } +#endif // #if defined(CL_VERSION_1_1) + + cl_int flush() const + { + return detail::errHandler(::clFlush(object_), __FLUSH_ERR); + } + + cl_int finish() const + { + return detail::errHandler(::clFinish(object_), __FINISH_ERR); + } +}; + +#ifdef _WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) std::atomic CommandQueue::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) CommandQueue CommandQueue::default_; +__declspec(selectany) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; +#else // !_WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) std::atomic CommandQueue::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) CommandQueue CommandQueue::default_; +__attribute__((weak)) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; +#endif // !_WIN32 + +template +Buffer::Buffer( + const Context &context, + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr, + cl_int *err) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if (readOnly) + { + flags |= CL_MEM_READ_ONLY; + } + else + { + flags |= CL_MEM_READ_WRITE; + } + if (useHostPtr) + { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType) * (endIterator - startIterator); + + if (useHostPtr) + { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } + else + { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + if (!useHostPtr) + { + CommandQueue queue(context, 0, &error); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + error = cl::copy(queue, startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } +} + +template +Buffer::Buffer( + const CommandQueue &queue, + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr, + cl_int *err) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if (readOnly) + { + flags |= CL_MEM_READ_ONLY; + } + else + { + flags |= CL_MEM_READ_WRITE; + } + if (useHostPtr) + { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType) * (endIterator - startIterator); + + Context context = queue.getInfo(); + + if (useHostPtr) + { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } + else + { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + if (!useHostPtr) + { + error = cl::copy(queue, startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + } +} + +inline cl_int enqueueReadBuffer( + const Buffer &buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueReadBuffer(buffer, blocking, offset, size, ptr, events, event); +} + +inline cl_int enqueueWriteBuffer( + const Buffer &buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueWriteBuffer(buffer, blocking, offset, size, ptr, events, event); +} + +inline void *enqueueMapBuffer( + const Buffer &buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS *events = NULL, + Event *event = NULL, + cl_int *err = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + + void *result = ::clEnqueueMapBuffer( + queue(), buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (cl_event *)event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) + { + *err = error; + } + return result; +} + +inline cl_int enqueueUnmapMemObject( + const Memory &memory, + void *mapped_ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (error != CL_SUCCESS) + { + return error; + } + + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueUnmapMemObject( + queue(), memory(), mapped_ptr, + (events != NULL) ? (cl_uint)events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event *)&events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; +} + +inline cl_int enqueueCopyBuffer( + const Buffer &src, + const Buffer &dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyBuffer(src, dst, src_offset, dst_offset, size, events, event); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Host to Device. + * Uses default command queue. + */ +template +inline cl_int copy(IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + if (error != CL_SUCCESS) + return error; + + return cl::copy(queue, startIterator, endIterator, buffer); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Device to Host. + * Uses default command queue. + */ +template +inline cl_int copy(const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + if (error != CL_SUCCESS) + return error; + + return cl::copy(queue, buffer, startIterator, endIterator); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Host to Device. + * Uses specified queue. + */ +template +inline cl_int copy(const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + ::size_t length = endIterator - startIterator; + ::size_t byteLength = length * sizeof(DataType); + + DataType *pointer = + static_cast(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_WRITE, 0, byteLength, 0, 0, &error)); + // if exceptions enabled, enqueueMapBuffer will throw + if (error != CL_SUCCESS) + { + return error; + } +#if defined(_MSC_VER) + std::copy( + startIterator, + endIterator, + stdext::checked_array_iterator( + pointer, length)); +#else + std::copy(startIterator, endIterator, pointer); +#endif + Event endEvent; + error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); + // if exceptions enabled, enqueueUnmapMemObject will throw + if (error != CL_SUCCESS) + { + return error; + } + endEvent.wait(); + return CL_SUCCESS; +} + +/** + * Blocking copy operation between iterators and a buffer. + * Device to Host. + * Uses specified queue. + */ +template +inline cl_int copy(const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + ::size_t length = endIterator - startIterator; + ::size_t byteLength = length * sizeof(DataType); + + DataType *pointer = + static_cast(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_READ, 0, byteLength, 0, 0, &error)); + // if exceptions enabled, enqueueMapBuffer will throw + if (error != CL_SUCCESS) + { + return error; + } + std::copy(pointer, pointer + length, startIterator); + Event endEvent; + error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); + // if exceptions enabled, enqueueUnmapMemObject will throw + if (error != CL_SUCCESS) + { + return error; + } + endEvent.wait(); + return CL_SUCCESS; +} + +#if defined(CL_VERSION_1_1) +inline cl_int enqueueReadBufferRect( + const Buffer &buffer, + cl_bool blocking, + const size_t<3> &buffer_offset, + const size_t<3> &host_offset, + const size_t<3> ®ion, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueReadBufferRect( + buffer, + blocking, + buffer_offset, + host_offset, + region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueWriteBufferRect( + const Buffer &buffer, + cl_bool blocking, + const size_t<3> &buffer_offset, + const size_t<3> &host_offset, + const size_t<3> ®ion, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueWriteBufferRect( + buffer, + blocking, + buffer_offset, + host_offset, + region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueCopyBufferRect( + const Buffer &src, + const Buffer &dst, + const size_t<3> &src_origin, + const size_t<3> &dst_origin, + const size_t<3> ®ion, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyBufferRect( + src, + dst, + src_origin, + dst_origin, + region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + events, + event); +} +#endif + +inline cl_int enqueueReadImage( + const Image &image, + cl_bool blocking, + const size_t<3> &origin, + const size_t<3> ®ion, + ::size_t row_pitch, + ::size_t slice_pitch, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueReadImage( + image, + blocking, + origin, + region, + row_pitch, + slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueWriteImage( + const Image &image, + cl_bool blocking, + const size_t<3> &origin, + const size_t<3> ®ion, + ::size_t row_pitch, + ::size_t slice_pitch, + void *ptr, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueWriteImage( + image, + blocking, + origin, + region, + row_pitch, + slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueCopyImage( + const Image &src, + const Image &dst, + const size_t<3> &src_origin, + const size_t<3> &dst_origin, + const size_t<3> ®ion, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyImage( + src, + dst, + src_origin, + dst_origin, + region, + events, + event); +} + +inline cl_int enqueueCopyImageToBuffer( + const Image &src, + const Buffer &dst, + const size_t<3> &src_origin, + const size_t<3> ®ion, + ::size_t dst_offset, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyImageToBuffer( + src, + dst, + src_origin, + region, + dst_offset, + events, + event); +} + +inline cl_int enqueueCopyBufferToImage( + const Buffer &src, + const Image &dst, + ::size_t src_offset, + const size_t<3> &dst_origin, + const size_t<3> ®ion, + const VECTOR_CLASS *events = NULL, + Event *event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.enqueueCopyBufferToImage( + src, + dst, + src_offset, + dst_origin, + region, + events, + event); +} + +inline cl_int flush(void) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.flush(); +} + +inline cl_int finish(void) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) + { + return error; + } + + return queue.finish(); +} + +// Kernel Functor support +// New interface as of September 2011 +// Requires the C++11 std::tr1::function (note do not support TR1) +// Visual Studio 2010 and GCC 4.2 + +struct EnqueueArgs +{ + CommandQueue queue_; + const NDRange offset_; + const NDRange global_; + const NDRange local_; + VECTOR_CLASS events_; + + EnqueueArgs(NDRange global) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange) + { + } + + EnqueueArgs(NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local) + { + } + + EnqueueArgs(NDRange offset, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local) + { + } + + EnqueueArgs(Event e, NDRange global) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange) + { + events_.push_back(e); + } + + EnqueueArgs(Event e, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(Event e, NDRange offset, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange global) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange), + events_(events) + { + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local), + events_(events) + { + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local), + events_(events) + { + } + + EnqueueArgs(CommandQueue &queue, NDRange global) : queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange) + { + } + + EnqueueArgs(CommandQueue &queue, NDRange global, NDRange local) : queue_(queue), + offset_(NullRange), + global_(global), + local_(local) + { + } + + EnqueueArgs(CommandQueue &queue, NDRange offset, NDRange global, NDRange local) : queue_(queue), + offset_(offset), + global_(global), + local_(local) + { + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange global) : queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange global, NDRange local) : queue_(queue), + offset_(NullRange), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange offset, NDRange global, NDRange local) : queue_(queue), + offset_(offset), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global) : queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange), + events_(events) + { + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global, NDRange local) : queue_(queue), + offset_(NullRange), + global_(global), + local_(local), + events_(events) + { + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : queue_(queue), + offset_(offset), + global_(global), + local_(local), + events_(events) + { + } +}; + +namespace detail +{ + +class NullType +{ +}; + +template +struct SetArg +{ + static void set(Kernel kernel, T0 arg) + { + kernel.setArg(index, arg); + } +}; + +template +struct SetArg +{ + static void set(Kernel, NullType) + { + } +}; + +template < + typename T0, typename T1, typename T2, typename T3, + typename T4, typename T5, typename T6, typename T7, + typename T8, typename T9, typename T10, typename T11, + typename T12, typename T13, typename T14, typename T15, + typename T16, typename T17, typename T18, typename T19, + typename T20, typename T21, typename T22, typename T23, + typename T24, typename T25, typename T26, typename T27, + typename T28, typename T29, typename T30, typename T31> +class KernelFunctorGlobal +{ + private: + Kernel kernel_; + + public: + KernelFunctorGlobal( + Kernel kernel) : kernel_(kernel) + { + } + + KernelFunctorGlobal( + const Program &program, + const STRING_CLASS name, + cl_int *err = NULL) : kernel_(program, name.c_str(), err) + { + } + + Event operator()( + const EnqueueArgs &args, + T0 t0, + T1 t1 = NullType(), + T2 t2 = NullType(), + T3 t3 = NullType(), + T4 t4 = NullType(), + T5 t5 = NullType(), + T6 t6 = NullType(), + T7 t7 = NullType(), + T8 t8 = NullType(), + T9 t9 = NullType(), + T10 t10 = NullType(), + T11 t11 = NullType(), + T12 t12 = NullType(), + T13 t13 = NullType(), + T14 t14 = NullType(), + T15 t15 = NullType(), + T16 t16 = NullType(), + T17 t17 = NullType(), + T18 t18 = NullType(), + T19 t19 = NullType(), + T20 t20 = NullType(), + T21 t21 = NullType(), + T22 t22 = NullType(), + T23 t23 = NullType(), + T24 t24 = NullType(), + T25 t25 = NullType(), + T26 t26 = NullType(), + T27 t27 = NullType(), + T28 t28 = NullType(), + T29 t29 = NullType(), + T30 t30 = NullType(), + T31 t31 = NullType()) + { + Event event; + SetArg<0, T0>::set(kernel_, t0); + SetArg<1, T1>::set(kernel_, t1); + SetArg<2, T2>::set(kernel_, t2); + SetArg<3, T3>::set(kernel_, t3); + SetArg<4, T4>::set(kernel_, t4); + SetArg<5, T5>::set(kernel_, t5); + SetArg<6, T6>::set(kernel_, t6); + SetArg<7, T7>::set(kernel_, t7); + SetArg<8, T8>::set(kernel_, t8); + SetArg<9, T9>::set(kernel_, t9); + SetArg<10, T10>::set(kernel_, t10); + SetArg<11, T11>::set(kernel_, t11); + SetArg<12, T12>::set(kernel_, t12); + SetArg<13, T13>::set(kernel_, t13); + SetArg<14, T14>::set(kernel_, t14); + SetArg<15, T15>::set(kernel_, t15); + SetArg<16, T16>::set(kernel_, t16); + SetArg<17, T17>::set(kernel_, t17); + SetArg<18, T18>::set(kernel_, t18); + SetArg<19, T19>::set(kernel_, t19); + SetArg<20, T20>::set(kernel_, t20); + SetArg<21, T21>::set(kernel_, t21); + SetArg<22, T22>::set(kernel_, t22); + SetArg<23, T23>::set(kernel_, t23); + SetArg<24, T24>::set(kernel_, t24); + SetArg<25, T25>::set(kernel_, t25); + SetArg<26, T26>::set(kernel_, t26); + SetArg<27, T27>::set(kernel_, t27); + SetArg<28, T28>::set(kernel_, t28); + SetArg<29, T29>::set(kernel_, t29); + SetArg<30, T30>::set(kernel_, t30); + SetArg<31, T31>::set(kernel_, t31); + + args.queue_.enqueueNDRangeKernel( + kernel_, + args.offset_, + args.global_, + args.local_, + &args.events_, + &event); + + return event; + } +}; + +//------------------------------------------------------------------------------------------------------ + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29, + typename T30, + typename T31> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + T31> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 32)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + T31); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29, + T30 arg30, + T31 arg31) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29, + arg30, + arg31); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29, + typename T30> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 31)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29, + T30 arg30) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29, + arg30); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 30)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 29)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 28)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 27)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 26)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 25)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 24)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 23)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 22)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 21)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 20)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 19)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 18)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 17)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 16)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 15)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 14)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 13)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 12)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 11)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 10)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 9)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 8)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 7)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5, + T6); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 6)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4, + T5); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3, + typename T4> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 5)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3, + T4); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4); + } +}; + +template < + typename T0, + typename T1, + typename T2, + typename T3> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 4)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2, + T3); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3); + } +}; + +template < + typename T0, + typename T1, + typename T2> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 3)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1, + T2); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2); + } +}; + +template < + typename T0, + typename T1> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 2)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0, + T1); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0, + T1 arg1) + { + return functor_( + enqueueArgs, + arg0, + arg1); + } +}; + +template < + typename T0> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> + FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : functor_(functor) + { + +#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 1)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); +#endif + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs &, + T0); + + Event operator()( + const EnqueueArgs &enqueueArgs, + T0 arg0) + { + return functor_( + enqueueArgs, + arg0); + } +}; + +} // namespace detail + +//---------------------------------------------------------------------------------------------- + +template < + typename T0, typename T1 = detail::NullType, typename T2 = detail::NullType, + typename T3 = detail::NullType, typename T4 = detail::NullType, + typename T5 = detail::NullType, typename T6 = detail::NullType, + typename T7 = detail::NullType, typename T8 = detail::NullType, + typename T9 = detail::NullType, typename T10 = detail::NullType, + typename T11 = detail::NullType, typename T12 = detail::NullType, + typename T13 = detail::NullType, typename T14 = detail::NullType, + typename T15 = detail::NullType, typename T16 = detail::NullType, + typename T17 = detail::NullType, typename T18 = detail::NullType, + typename T19 = detail::NullType, typename T20 = detail::NullType, + typename T21 = detail::NullType, typename T22 = detail::NullType, + typename T23 = detail::NullType, typename T24 = detail::NullType, + typename T25 = detail::NullType, typename T26 = detail::NullType, + typename T27 = detail::NullType, typename T28 = detail::NullType, + typename T29 = detail::NullType, typename T30 = detail::NullType, + typename T31 = detail::NullType> +struct make_kernel : public detail::functionImplementation_< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31> +{ + public: + typedef detail::KernelFunctorGlobal< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31> + FunctorType; + + make_kernel( + const Program &program, + const STRING_CLASS name, + cl_int *err = NULL) : detail::functionImplementation_( + FunctorType(program, name, err)) + { + } + + make_kernel( + const Kernel kernel) : detail::functionImplementation_( + FunctorType(kernel)) + { + } +}; + +//---------------------------------------------------------------------------------------------------------------------- + +#undef __ERR_STR +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#undef __GET_DEVICE_INFO_ERR +#undef __GET_PLATFORM_INFO_ERR +#undef __GET_DEVICE_IDS_ERR +#undef __GET_CONTEXT_INFO_ERR +#undef __GET_EVENT_INFO_ERR +#undef __GET_EVENT_PROFILE_INFO_ERR +#undef __GET_MEM_OBJECT_INFO_ERR +#undef __GET_IMAGE_INFO_ERR +#undef __GET_SAMPLER_INFO_ERR +#undef __GET_KERNEL_INFO_ERR +#undef __GET_KERNEL_ARG_INFO_ERR +#undef __GET_KERNEL_WORK_GROUP_INFO_ERR +#undef __GET_PROGRAM_INFO_ERR +#undef __GET_PROGRAM_BUILD_INFO_ERR +#undef __GET_COMMAND_QUEUE_INFO_ERR + +#undef __CREATE_CONTEXT_ERR +#undef __CREATE_CONTEXT_FROM_TYPE_ERR +#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR + +#undef __CREATE_BUFFER_ERR +#undef __CREATE_SUBBUFFER_ERR +#undef __CREATE_IMAGE2D_ERR +#undef __CREATE_IMAGE3D_ERR +#undef __CREATE_SAMPLER_ERR +#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR + +#undef __CREATE_USER_EVENT_ERR +#undef __SET_USER_EVENT_STATUS_ERR +#undef __SET_EVENT_CALLBACK_ERR +#undef __SET_PRINTF_CALLBACK_ERR + +#undef __WAIT_FOR_EVENTS_ERR + +#undef __CREATE_KERNEL_ERR +#undef __SET_KERNEL_ARGS_ERR +#undef __CREATE_PROGRAM_WITH_SOURCE_ERR +#undef __CREATE_PROGRAM_WITH_BINARY_ERR +#undef __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR +#undef __BUILD_PROGRAM_ERR +#undef __CREATE_KERNELS_IN_PROGRAM_ERR + +#undef __CREATE_COMMAND_QUEUE_ERR +#undef __SET_COMMAND_QUEUE_PROPERTY_ERR +#undef __ENQUEUE_READ_BUFFER_ERR +#undef __ENQUEUE_WRITE_BUFFER_ERR +#undef __ENQUEUE_READ_BUFFER_RECT_ERR +#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR +#undef __ENQEUE_COPY_BUFFER_ERR +#undef __ENQEUE_COPY_BUFFER_RECT_ERR +#undef __ENQUEUE_READ_IMAGE_ERR +#undef __ENQUEUE_WRITE_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR +#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR +#undef __ENQUEUE_MAP_BUFFER_ERR +#undef __ENQUEUE_MAP_IMAGE_ERR +#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR +#undef __ENQUEUE_NDRANGE_KERNEL_ERR +#undef __ENQUEUE_TASK_ERR +#undef __ENQUEUE_NATIVE_KERNEL + +#undef __CL_EXPLICIT_CONSTRUCTORS + +#undef __UNLOAD_COMPILER_ERR +#endif //__CL_USER_OVERRIDE_ERROR_STRINGS + +#undef __CL_FUNCTION_TYPE + +// Extensions +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_VERSION_1_1) +#undef __INIT_CL_EXT_FCN_PTR +#endif // #if defined(CL_VERSION_1_1) +#undef __CREATE_SUB_DEVICES + +#if defined(USE_CL_DEVICE_FISSION) +#undef __PARAM_NAME_DEVICE_FISSION +#endif // USE_CL_DEVICE_FISSION + +#undef __DEFAULT_NOT_INITIALIZED +#undef __DEFAULT_BEING_INITIALIZED +#undef __DEFAULT_INITIALIZED + +#undef CL_HPP_RVALUE_REFERENCES_SUPPORTED +#undef CL_HPP_NOEXCEPT + +} // namespace cl + +#endif // CL_HPP_ diff --git a/contrib/argon2-gpu/include/argon2-opencl/device.h b/contrib/argon2-gpu/include/argon2-opencl/device.h new file mode 100644 index 0000000000..522ab02e8c --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-opencl/device.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017-2018 Łukasz Kurowski + * Copyright (C) 2015 Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_OPENCL_DEVICE_H +#define ARGON2_OPENCL_DEVICE_H + +#include "argon2-opencl/opencl.h" + +namespace argon2gpu +{ +namespace opencl +{ + +class Device +{ + private: + cl::Device device; + + public: + std::string getName() const; + std::string getInfo() const; + + const cl::Device &getCLDevice() const { return device; } + + /** + * @brief Empty constructor. + * NOTE: Calling methods other than the destructor on an instance initialized + * with empty constructor results in undefined behavior. + */ + Device() {} + + Device(const cl::Device &device) + : device(device) + { + } + + Device(const Device &) = default; + Device(Device &&) = default; + + Device &operator=(const Device &) = default; +}; + +} // namespace opencl +} // namespace argon2gpu + +#endif // ARGON2_OPENCL_DEVICE_H diff --git a/contrib/argon2-gpu/include/argon2-opencl/global-context.h b/contrib/argon2-gpu/include/argon2-opencl/global-context.h new file mode 100644 index 0000000000..9108b63f56 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-opencl/global-context.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_OPENCL_GLOBALCONTEXT_H +#define ARGON2_OPENCL_GLOBALCONTEXT_H + +#include "argon2-opencl/device.h" + +#include +#include + +namespace argon2gpu +{ +namespace opencl +{ + +class GlobalContext +{ + private: + std::vector devices; + + public: + const std::vector &getAllDevices() const { return devices; } + + GlobalContext(); +}; + +} // namespace opencl +} // namespace argon2gpu + +#endif // ARGON2_OPENCL_GLOBALCONTEXT_H diff --git a/contrib/argon2-gpu/include/argon2-opencl/kernel-loader.h b/contrib/argon2-gpu/include/argon2-opencl/kernel-loader.h new file mode 100644 index 0000000000..ef59877fa3 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-opencl/kernel-loader.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_OPENCL_KERNELLOADER_H +#define ARGON2_OPENCL_KERNELLOADER_H + +#include "argon2-opencl/opencl.h" +#include "argon2-gpu/common.h" + +#include + +namespace argon2gpu +{ +namespace opencl +{ + +namespace KernelLoader +{ +cl::Program loadArgon2Program( + const cl::Context &context, + const std::string &sourceDirectory, + Type type, Version version, bool debug = false); +}; + +} // namespace opencl +} // namespace argon2gpu + +#endif // ARGON2_OPENCL_KERNELLOADER_H diff --git a/contrib/argon2-gpu/include/argon2-opencl/kernel-runner.h b/contrib/argon2-gpu/include/argon2-opencl/kernel-runner.h new file mode 100644 index 0000000000..d778cde115 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-opencl/kernel-runner.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_OPENCL_KERNELRUNNER_H +#define ARGON2_OPENCL_KERNELRUNNER_H + +#include "argon2-opencl/program-context.h" +#include "argon2-gpu/common.h" + +namespace argon2gpu +{ +namespace opencl +{ + +class KernelRunner +{ + private: + const ProgramContext *programContext; + const Argon2Params *params; + + std::uint32_t batchSize; + bool bySegment; + bool precompute; + + cl::CommandQueue queue; + cl::Kernel kernel; + cl::Buffer memoryBuffer, refsBuffer; + cl::Event start, end; + + std::size_t memorySize; + + void precomputeRefs(); + + public: + std::uint32_t getMinLanesPerBlock() const + { + return bySegment ? 1 : params->getLanes(); + } + std::uint32_t getMaxLanesPerBlock() const { return params->getLanes(); } + + std::uint32_t getMinJobsPerBlock() const { return 1; } + std::uint32_t getMaxJobsPerBlock() const { return batchSize; } + + std::uint32_t getBatchSize() const { return batchSize; } + + KernelRunner(const ProgramContext *programContext, + const Argon2Params *params, const Device *device, + std::uint32_t batchSize, bool bySegment, bool precompute); + + void *mapInputMemory(std::uint32_t jobId); + void unmapInputMemory(void *memory); + + void *mapOutputMemory(std::uint32_t jobId); + void unmapOutputMemory(void *memory); + + void run(std::uint32_t lanesPerBlock, std::uint32_t jobsPerBlock); + float finish(); +}; + +} // namespace opencl +} // namespace argon2gpu + +#endif // ARGON2_OPENCL_KERNELRUNNER_H diff --git a/contrib/argon2-gpu/include/argon2-opencl/opencl.h b/contrib/argon2-gpu/include/argon2-opencl/opencl.h new file mode 100644 index 0000000000..ee1bad2117 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-opencl/opencl.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OPENCL_H +#define OPENCL_H + +/* Some compatibility hacks: */ +#define CL_USE_DEPRECATED_OPENCL_1_1_APIS +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS +#if defined(__APPLE__) || defined(__MACOSX) +#include +#else +#include +#endif +#undef CL_VERSION_2_0 + +/* Throw exceptions on errors: */ +#define __CL_ENABLE_EXCEPTIONS +/* Include local version of + * because not all platforms ship with it: */ +#include "cl.hpp" + +#endif // OPENCL_H diff --git a/contrib/argon2-gpu/include/argon2-opencl/processing-unit.h b/contrib/argon2-gpu/include/argon2-opencl/processing-unit.h new file mode 100644 index 0000000000..565cefc377 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-opencl/processing-unit.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_OPENCL_PROCESSINGUNIT_H +#define ARGON2_OPENCL_PROCESSINGUNIT_H + +#include + +#include "argon2-opencl/kernel-runner.h" + +namespace argon2gpu +{ +namespace opencl +{ + +class ProcessingUnit +{ + private: + const ProgramContext *programContext; + const Argon2Params *params; + const Device *device; + + KernelRunner runner; + std::uint32_t bestLanesPerBlock; + std::uint32_t bestJobsPerBlock; + + public: + std::size_t getBatchSize() const { return runner.getBatchSize(); } + + ProcessingUnit( + const ProgramContext *programContext, const Argon2Params *params, + const Device *device, std::size_t batchSize, + bool bySegment = true, bool precomputeRefs = false); + + void setInputAndSalt(std::size_t index, const void *input, std::size_t inputSize); + void getHash(std::size_t index, void *hash); + + void beginProcessing(); + void endProcessing(); +}; + +} // namespace opencl +} // namespace argon2gpu + +#endif // ARGON2_OPENCL_PROCESSINGUNIT_H diff --git a/contrib/argon2-gpu/include/argon2-opencl/program-context.h b/contrib/argon2-gpu/include/argon2-opencl/program-context.h new file mode 100644 index 0000000000..af31b8a6c8 --- /dev/null +++ b/contrib/argon2-gpu/include/argon2-opencl/program-context.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ARGON2_OPENCL_PROGRAMCONTEXT_H +#define ARGON2_OPENCL_PROGRAMCONTEXT_H + +#include "argon2-opencl/global-context.h" +#include "argon2-gpu/common.h" + +namespace argon2gpu +{ +namespace opencl +{ + +class ProgramContext +{ + private: + const GlobalContext *globalContext; + + std::vector devices; + cl::Context context; + cl::Program program; + + Type type; + Version version; + + public: + const GlobalContext *getGlobalContext() const { return globalContext; } + + const std::vector &getDevices() const { return devices; } + const cl::Context &getContext() const { return context; } + const cl::Program &getProgram() const { return program; } + + Type getArgon2Type() const { return type; } + Version getArgon2Version() const { return version; } + + ProgramContext( + const GlobalContext *globalContext, + const std::vector &devices, + Type type, Version version); +}; + +} // namespace opencl +} // namespace argon2gpu + +#endif // ARGON2_OPENCL_PROGRAMCONTEXT_H diff --git a/contrib/argon2-gpu/src/argon2-cuda/device.cpp b/contrib/argon2-gpu/src/argon2-cuda/device.cpp new file mode 100644 index 0000000000..1b79746546 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-cuda/device.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "argon2-cuda/device.h" +#include "argon2-cuda/cuda-exception.h" + +namespace argon2gpu +{ +namespace cuda +{ + +std::string Device::getName() const +{ + cudaDeviceProp prop; + CudaException::check(cudaGetDeviceProperties(&prop, deviceIndex)); + return "CUDA Device '" + std::string(prop.name) + "'"; +} + +std::string Device::getInfo() const +{ + /* FIXME: show some more stuff here: */ + cudaDeviceProp prop; + CudaException::check(cudaGetDeviceProperties(&prop, deviceIndex)); + return "CUDA Device '" + std::string(prop.name) + "'"; +} + +} // namespace cuda +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-cuda/global-context.cpp b/contrib/argon2-gpu/src/argon2-cuda/global-context.cpp new file mode 100644 index 0000000000..0127d18361 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-cuda/global-context.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-cuda/global-context.h" +#include "argon2-cuda/cuda-exception.h" + +namespace argon2gpu +{ +namespace cuda +{ + +GlobalContext::GlobalContext() + : devices() +{ + int count; + CudaException::check(cudaGetDeviceCount(&count)); + + devices.reserve(count); + for (int i = 0; i < count; i++) + { + devices.emplace_back(i); + } +} + +} // namespace cuda +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-cuda/kernels.cu b/contrib/argon2-gpu/src/argon2-cuda/kernels.cu new file mode 100644 index 0000000000..26c318890c --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-cuda/kernels.cu @@ -0,0 +1,1216 @@ +/* For IDE: */ +#ifndef __CUDACC__ +#define __CUDACC__ +#endif + +#include "argon2-cuda/kernels.h" +#include "argon2-cuda/cuda-exception.h" + +#include +#ifndef NDEBUG +#include +#endif + +#define ARGON2_D 0 +#define ARGON2_I 1 +#define ARGON2_ID 2 + +#define ARGON2_VERSION_10 0x10 +#define ARGON2_VERSION_13 0x13 + +#define ARGON2_BLOCK_SIZE 1024 +#define ARGON2_QWORDS_IN_BLOCK (ARGON2_BLOCK_SIZE / 8) +#define ARGON2_SYNC_POINTS 4 + +#define THREADS_PER_LANE 32 +#define QWORDS_PER_THREAD (ARGON2_QWORDS_IN_BLOCK / 32) + +namespace argon2gpu +{ +namespace cuda +{ + +using namespace std; + +__device__ uint64_t u64_build(uint32_t hi, uint32_t lo) +{ + return ((uint64_t)hi << 32) | (uint64_t)lo; +} + +__device__ uint32_t u64_lo(uint64_t x) +{ + return (uint32_t)x; +} + +__device__ uint32_t u64_hi(uint64_t x) +{ + return (uint32_t)(x >> 32); +} + +__device__ uint64_t u64_shuffle(uint64_t v, uint32_t thread) +{ + uint32_t lo = u64_lo(v); + uint32_t hi = u64_hi(v); + lo = __shfl(lo, thread); + hi = __shfl(hi, thread); + return u64_build(hi, lo); +} + +struct block_g +{ + uint64_t data[ARGON2_QWORDS_IN_BLOCK]; +}; + +struct block_th +{ + uint64_t a, b, c, d; +}; + +__device__ uint64_t cmpeq_mask(uint32_t test, uint32_t ref) +{ + uint32_t x = -(uint32_t)(test == ref); + return u64_build(x, x); +} + +__device__ uint64_t block_th_get(const struct block_th *b, uint32_t idx) +{ + uint64_t res = 0; + res ^= cmpeq_mask(idx, 0) & b->a; + res ^= cmpeq_mask(idx, 1) & b->b; + res ^= cmpeq_mask(idx, 2) & b->c; + res ^= cmpeq_mask(idx, 3) & b->d; + return res; +} + +__device__ void block_th_set(struct block_th *b, uint32_t idx, uint64_t v) +{ + b->a ^= cmpeq_mask(idx, 0) & (v ^ b->a); + b->b ^= cmpeq_mask(idx, 1) & (v ^ b->b); + b->c ^= cmpeq_mask(idx, 2) & (v ^ b->c); + b->d ^= cmpeq_mask(idx, 3) & (v ^ b->d); +} + +__device__ void move_block(struct block_th *dst, const struct block_th *src) +{ + *dst = *src; +} + +__device__ void xor_block(struct block_th *dst, const struct block_th *src) +{ + dst->a ^= src->a; + dst->b ^= src->b; + dst->c ^= src->c; + dst->d ^= src->d; +} + +__device__ void load_block(struct block_th *dst, const struct block_g *src, + uint32_t thread) +{ + dst->a = src->data[0 * THREADS_PER_LANE + thread]; + dst->b = src->data[1 * THREADS_PER_LANE + thread]; + dst->c = src->data[2 * THREADS_PER_LANE + thread]; + dst->d = src->data[3 * THREADS_PER_LANE + thread]; +} + +__device__ void load_block_xor(struct block_th *dst, const struct block_g *src, + uint32_t thread) +{ + dst->a ^= src->data[0 * THREADS_PER_LANE + thread]; + dst->b ^= src->data[1 * THREADS_PER_LANE + thread]; + dst->c ^= src->data[2 * THREADS_PER_LANE + thread]; + dst->d ^= src->data[3 * THREADS_PER_LANE + thread]; +} + +__device__ void store_block(struct block_g *dst, const struct block_th *src, + uint32_t thread) +{ + dst->data[0 * THREADS_PER_LANE + thread] = src->a; + dst->data[1 * THREADS_PER_LANE + thread] = src->b; + dst->data[2 * THREADS_PER_LANE + thread] = src->c; + dst->data[3 * THREADS_PER_LANE + thread] = src->d; +} + +__device__ uint64_t rotr64(uint64_t x, uint32_t n) +{ + return (x >> n) | (x << (64 - n)); +} + +__device__ uint64_t f(uint64_t x, uint64_t y) +{ + uint32_t xlo = u64_lo(x); + uint32_t ylo = u64_lo(y); + return x + y + 2 * u64_build(__umulhi(xlo, ylo), xlo * ylo); +} + +__device__ void g(struct block_th *block) +{ + uint64_t a, b, c, d; + a = block->a; + b = block->b; + c = block->c; + d = block->d; + + a = f(a, b); + d = rotr64(d ^ a, 32); + c = f(c, d); + b = rotr64(b ^ c, 24); + a = f(a, b); + d = rotr64(d ^ a, 16); + c = f(c, d); + b = rotr64(b ^ c, 63); + + block->a = a; + block->b = b; + block->c = c; + block->d = d; +} + +template +__device__ void apply_shuffle(struct block_th *block, uint32_t thread) +{ + for (uint32_t i = 0; i < QWORDS_PER_THREAD; i++) + { + uint32_t src_thr = shuffle::apply(thread, i); + + uint64_t v = block_th_get(block, i); + v = u64_shuffle(v, src_thr); + block_th_set(block, i, v); + } +} + +__device__ void transpose(struct block_th *block, uint32_t thread) +{ + uint32_t thread_group = (thread & 0x0C) >> 2; + for (uint32_t i = 1; i < QWORDS_PER_THREAD; i++) + { + uint32_t thr = (i << 2) ^ thread; + uint32_t idx = thread_group ^ i; + + uint64_t v = block_th_get(block, idx); + v = u64_shuffle(v, thr); + block_th_set(block, idx, v); + } +} + +struct identity_shuffle +{ + __device__ static uint32_t apply(uint32_t thread, uint32_t idx) + { + return thread; + } +}; + +struct shift1_shuffle +{ + __device__ static uint32_t apply(uint32_t thread, uint32_t idx) + { + return (thread & 0x1c) | ((thread + idx) & 0x3); + } +}; + +struct unshift1_shuffle +{ + __device__ static uint32_t apply(uint32_t thread, uint32_t idx) + { + idx = (QWORDS_PER_THREAD - idx) % QWORDS_PER_THREAD; + + return (thread & 0x1c) | ((thread + idx) & 0x3); + } +}; + +struct shift2_shuffle +{ + __device__ static uint32_t apply(uint32_t thread, uint32_t idx) + { + uint32_t lo = (thread & 0x1) | ((thread & 0x10) >> 3); + lo = (lo + idx) & 0x3; + return ((lo & 0x2) << 3) | (thread & 0xe) | (lo & 0x1); + } +}; + +struct unshift2_shuffle +{ + __device__ static uint32_t apply(uint32_t thread, uint32_t idx) + { + idx = (QWORDS_PER_THREAD - idx) % QWORDS_PER_THREAD; + + uint32_t lo = (thread & 0x1) | ((thread & 0x10) >> 3); + lo = (lo + idx) & 0x3; + return ((lo & 0x2) << 3) | (thread & 0xe) | (lo & 0x1); + } +}; + +__device__ void shuffle_block(struct block_th *block, uint32_t thread) +{ + transpose(block, thread); + + g(block); + + apply_shuffle(block, thread); + + g(block); + + apply_shuffle(block, thread); + transpose(block, thread); + + g(block); + + apply_shuffle(block, thread); + + g(block); + + apply_shuffle(block, thread); +} + +__device__ void next_addresses(struct block_th *addr, struct block_th *tmp, + uint32_t thread_input, uint32_t thread) +{ + addr->a = u64_build(0, thread_input); + addr->b = 0; + addr->c = 0; + addr->d = 0; + + shuffle_block(addr, thread); + + addr->a ^= u64_build(0, thread_input); + move_block(tmp, addr); + + shuffle_block(addr, thread); + + xor_block(addr, tmp); +} + +__device__ void compute_ref_pos( + uint32_t lanes, uint32_t segment_blocks, + uint32_t pass, uint32_t lane, uint32_t slice, uint32_t offset, + uint32_t *ref_lane, uint32_t *ref_index) +{ + uint32_t lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + *ref_lane = *ref_lane % lanes; + + uint32_t base; + if (pass != 0) + { + base = lane_blocks - segment_blocks; + } + else + { + if (slice == 0) + { + *ref_lane = lane; + } + base = slice * segment_blocks; + } + + uint32_t ref_area_size = base + offset - 1; + if (*ref_lane != lane) + { + ref_area_size = min(ref_area_size, base); + } + + *ref_index = __umulhi(*ref_index, *ref_index); + *ref_index = ref_area_size - 1 - __umulhi(ref_area_size, *ref_index); + + if (pass != 0 && slice != ARGON2_SYNC_POINTS - 1) + { + *ref_index += (slice + 1) * segment_blocks; + if (*ref_index >= lane_blocks) + { + *ref_index -= lane_blocks; + } + } +} + +struct ref +{ + uint32_t ref_lane; + uint32_t ref_index; +}; + +/* + * Refs hierarchy: + * lanes -> passes -> slices -> blocks + */ +template +__global__ void argon2_precompute_kernel( + struct ref *refs, uint32_t passes, uint32_t lanes, + uint32_t segment_blocks) +{ + uint32_t block_id = blockIdx.y * blockDim.y + threadIdx.y; + uint32_t thread = threadIdx.x; + + uint32_t segment_addr_blocks = (segment_blocks + ARGON2_QWORDS_IN_BLOCK - 1) / ARGON2_QWORDS_IN_BLOCK; + uint32_t block = block_id % segment_addr_blocks; + uint32_t segment = block_id / segment_addr_blocks; + + uint32_t slice, pass, pass_id, lane; + if (type == ARGON2_ID) + { + slice = segment % (ARGON2_SYNC_POINTS / 2); + lane = segment / (ARGON2_SYNC_POINTS / 2); + pass_id = pass = 0; + } + else + { + slice = segment % ARGON2_SYNC_POINTS; + pass_id = segment / ARGON2_SYNC_POINTS; + + pass = pass_id % passes; + lane = pass_id / passes; + } + + struct block_th addr, tmp; + + uint32_t thread_input; + switch (thread) + { + case 0: + thread_input = pass; + break; + case 1: + thread_input = lane; + break; + case 2: + thread_input = slice; + break; + case 3: + thread_input = lanes * segment_blocks * ARGON2_SYNC_POINTS; + break; + case 4: + thread_input = passes; + break; + case 5: + thread_input = type; + break; + case 6: + thread_input = block + 1; + break; + default: + thread_input = 0; + break; + } + + next_addresses(&addr, &tmp, thread_input, thread); + + refs += segment * segment_blocks; + + for (uint32_t i = 0; i < QWORDS_PER_THREAD; i++) + { + uint32_t pos = i * THREADS_PER_LANE + thread; + uint32_t offset = block * ARGON2_QWORDS_IN_BLOCK + pos; + if (offset < segment_blocks) + { + uint64_t v = block_th_get(&addr, i); + uint32_t ref_index = u64_lo(v); + uint32_t ref_lane = u64_hi(v); + + compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, + &ref_lane, &ref_index); + + refs[offset].ref_index = ref_index; + refs[offset].ref_lane = ref_lane; + } + } +} + +template +__device__ void argon2_core( + struct block_g *memory, struct block_g *mem_curr, + struct block_th *prev, struct block_th *tmp, + uint32_t lanes, uint32_t thread, uint32_t pass, + uint32_t ref_index, uint32_t ref_lane) +{ + struct block_g *mem_ref = memory + ref_index * lanes + ref_lane; + + if (version != ARGON2_VERSION_10 && pass != 0) + { + load_block(tmp, mem_curr, thread); + load_block_xor(prev, mem_ref, thread); + xor_block(tmp, prev); + } + else + { + load_block_xor(prev, mem_ref, thread); + move_block(tmp, prev); + } + + shuffle_block(prev, thread); + + xor_block(prev, tmp); + + store_block(mem_curr, prev, thread); +} + +template +__device__ void argon2_step_precompute( + struct block_g *memory, struct block_g *mem_curr, + struct block_th *prev, struct block_th *tmp, const struct ref **refs, + uint32_t lanes, uint32_t segment_blocks, uint32_t thread, + uint32_t lane, uint32_t pass, uint32_t slice, uint32_t offset) +{ + uint32_t ref_index, ref_lane; + if (type == ARGON2_I || (type == ARGON2_ID && pass == 0 && + slice < ARGON2_SYNC_POINTS / 2)) + { + ref_index = (*refs)->ref_index; + ref_lane = (*refs)->ref_lane; + (*refs)++; + } + else + { + uint64_t v = u64_shuffle(prev->a, 0); + ref_index = u64_lo(v); + ref_lane = u64_hi(v); + + compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, + &ref_lane, &ref_index); + } + + argon2_core(memory, mem_curr, prev, tmp, lanes, thread, pass, + ref_index, ref_lane); +} + +template +__global__ void argon2_kernel_segment_precompute( + struct block_g *memory, const struct ref *refs, + uint32_t passes, uint32_t lanes, uint32_t segment_blocks, + uint32_t pass, uint32_t slice) +{ + uint32_t job_id = blockIdx.z * blockDim.z + threadIdx.z; + uint32_t lane = blockIdx.y * blockDim.y + threadIdx.y; + uint32_t thread = threadIdx.x; + + uint32_t lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + /* select job's memory region: */ + memory += (size_t)job_id * lanes * lane_blocks; + + struct block_th prev, tmp; + + struct block_g *mem_segment = + memory + slice * segment_blocks * lanes + lane; + struct block_g *mem_prev, *mem_curr; + uint32_t start_offset = 0; + if (pass == 0) + { + if (slice == 0) + { + mem_prev = mem_segment + 1 * lanes; + mem_curr = mem_segment + 2 * lanes; + start_offset = 2; + } + else + { + mem_prev = mem_segment - lanes; + mem_curr = mem_segment; + } + } + else + { + mem_prev = mem_segment + (slice == 0 ? lane_blocks * lanes : 0) - lanes; + mem_curr = mem_segment; + } + + load_block(&prev, mem_prev, thread); + + if (type == ARGON2_ID) + { + if (pass == 0 && slice < ARGON2_SYNC_POINTS / 2) + { + refs += lane * (lane_blocks / 2) + slice * segment_blocks; + refs += start_offset; + } + } + else + { + refs += (lane * passes + pass) * lane_blocks + slice * segment_blocks; + refs += start_offset; + } + + for (uint32_t offset = start_offset; offset < segment_blocks; ++offset) + { + argon2_step_precompute( + memory, mem_curr, &prev, &tmp, &refs, lanes, segment_blocks, + thread, lane, pass, slice, offset); + + mem_curr += lanes; + } +} + +template +__global__ void argon2_kernel_oneshot_precompute( + struct block_g *memory, const struct ref *refs, uint32_t passes, + uint32_t lanes, uint32_t segment_blocks) +{ + uint32_t job_id = blockIdx.z * blockDim.z + threadIdx.z; + uint32_t lane = threadIdx.y; + uint32_t thread = threadIdx.x; + + uint32_t lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + /* select job's memory region: */ + memory += (size_t)job_id * lanes * lane_blocks; + + struct block_th prev, tmp; + + struct block_g *mem_lane = memory + lane; + struct block_g *mem_prev = mem_lane + 1 * lanes; + struct block_g *mem_curr = mem_lane + 2 * lanes; + + load_block(&prev, mem_prev, thread); + + if (type == ARGON2_ID) + { + refs += lane * (lane_blocks / 2) + 2; + } + else + { + refs += lane * passes * lane_blocks + 2; + } + + uint32_t skip = 2; + for (uint32_t pass = 0; pass < passes; ++pass) + { + for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; ++slice) + { + for (uint32_t offset = 0; offset < segment_blocks; ++offset) + { + if (skip > 0) + { + --skip; + continue; + } + + argon2_step_precompute( + memory, mem_curr, &prev, &tmp, &refs, lanes, + segment_blocks, thread, lane, pass, slice, offset); + + mem_curr += lanes; + } + + __syncthreads(); + } + + mem_curr = mem_lane; + } +} + +template +__device__ void argon2_step( + struct block_g *memory, struct block_g *mem_curr, + struct block_th *prev, struct block_th *tmp, struct block_th *addr, + uint32_t lanes, uint32_t segment_blocks, uint32_t thread, + uint32_t *thread_input, uint32_t lane, uint32_t pass, uint32_t slice, + uint32_t offset) +{ + uint32_t ref_index, ref_lane; + + if (type == ARGON2_I || (type == ARGON2_ID && pass == 0 && + slice < ARGON2_SYNC_POINTS / 2)) + { + uint32_t addr_index = offset % ARGON2_QWORDS_IN_BLOCK; + if (addr_index == 0) + { + if (thread == 6) + { + ++*thread_input; + } + next_addresses(addr, tmp, *thread_input, thread); + } + + uint32_t thr = addr_index % THREADS_PER_LANE; + uint32_t idx = addr_index / THREADS_PER_LANE; + + uint64_t v = block_th_get(addr, idx); + v = u64_shuffle(v, thr); + ref_index = u64_lo(v); + ref_lane = u64_hi(v); + } + else + { + uint64_t v = u64_shuffle(prev->a, 0); + ref_index = u64_lo(v); + ref_lane = u64_hi(v); + } + + compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, + &ref_lane, &ref_index); + + argon2_core(memory, mem_curr, prev, tmp, lanes, thread, pass, + ref_index, ref_lane); +} + +template +__global__ void argon2_kernel_segment( + struct block_g *memory, uint32_t passes, uint32_t lanes, + uint32_t segment_blocks, uint32_t pass, uint32_t slice) +{ + uint32_t job_id = blockIdx.z * blockDim.z + threadIdx.z; + uint32_t lane = blockIdx.y * blockDim.y + threadIdx.y; + uint32_t thread = threadIdx.x; + + uint32_t lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + /* select job's memory region: */ + memory += (size_t)job_id * lanes * lane_blocks; + + struct block_th prev, addr, tmp; + uint32_t thread_input; + + if (type == ARGON2_I || type == ARGON2_ID) + { + switch (thread) + { + case 0: + thread_input = pass; + break; + case 1: + thread_input = lane; + break; + case 2: + thread_input = slice; + break; + case 3: + thread_input = lanes * lane_blocks; + break; + case 4: + thread_input = passes; + break; + case 5: + thread_input = type; + break; + default: + thread_input = 0; + break; + } + + if (pass == 0 && slice == 0 && segment_blocks > 2) + { + if (thread == 6) + { + ++thread_input; + } + next_addresses(&addr, &tmp, thread_input, thread); + } + } + + struct block_g *mem_segment = + memory + slice * segment_blocks * lanes + lane; + struct block_g *mem_prev, *mem_curr; + uint32_t start_offset = 0; + if (pass == 0) + { + if (slice == 0) + { + mem_prev = mem_segment + 1 * lanes; + mem_curr = mem_segment + 2 * lanes; + start_offset = 2; + } + else + { + mem_prev = mem_segment - lanes; + mem_curr = mem_segment; + } + } + else + { + mem_prev = mem_segment + (slice == 0 ? lane_blocks * lanes : 0) - lanes; + mem_curr = mem_segment; + } + + load_block(&prev, mem_prev, thread); + + for (uint32_t offset = start_offset; offset < segment_blocks; ++offset) + { + argon2_step( + memory, mem_curr, &prev, &tmp, &addr, lanes, segment_blocks, + thread, &thread_input, lane, pass, slice, offset); + + mem_curr += lanes; + } +} + +template +__global__ void argon2_kernel_oneshot( + struct block_g *memory, uint32_t passes, uint32_t lanes, + uint32_t segment_blocks) +{ + uint32_t job_id = blockIdx.z * blockDim.z + threadIdx.z; + uint32_t lane = threadIdx.y; + uint32_t thread = threadIdx.x; + + uint32_t lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + /* select job's memory region: */ + memory += (size_t)job_id * lanes * lane_blocks; + + struct block_th prev, addr, tmp; + uint32_t thread_input; + + if (type == ARGON2_I || type == ARGON2_ID) + { + switch (thread) + { + case 1: + thread_input = lane; + break; + case 3: + thread_input = lanes * lane_blocks; + break; + case 4: + thread_input = passes; + break; + case 5: + thread_input = type; + break; + default: + thread_input = 0; + break; + } + + if (segment_blocks > 2) + { + if (thread == 6) + { + ++thread_input; + } + next_addresses(&addr, &tmp, thread_input, thread); + } + } + + struct block_g *mem_lane = memory + lane; + struct block_g *mem_prev = mem_lane + 1 * lanes; + struct block_g *mem_curr = mem_lane + 2 * lanes; + + load_block(&prev, mem_prev, thread); + + uint32_t skip = 2; + for (uint32_t pass = 0; pass < passes; ++pass) + { + for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; ++slice) + { + for (uint32_t offset = 0; offset < segment_blocks; ++offset) + { + if (skip > 0) + { + --skip; + continue; + } + + argon2_step( + memory, mem_curr, &prev, &tmp, &addr, lanes, + segment_blocks, thread, &thread_input, lane, pass, + slice, offset); + + mem_curr += lanes; + } + + __syncthreads(); + + if (type == ARGON2_I || type == ARGON2_ID) + { + if (thread == 2) + { + ++thread_input; + } + if (thread == 6) + { + thread_input = 0; + } + } + } + if (type == ARGON2_I) + { + if (thread == 0) + { + ++thread_input; + } + if (thread == 2) + { + thread_input = 0; + } + } + mem_curr = mem_lane; + } +} + + +static void setCudaDevice(int deviceIndex) +{ + int currentIndex = -1; + CudaException::check(cudaGetDevice(¤tIndex)); + if (currentIndex != deviceIndex) + { + CudaException::check(cudaSetDevice(deviceIndex)); + } +} + +KernelRunner::KernelRunner(uint32_t type, uint32_t version, uint32_t passes, + uint32_t lanes, uint32_t segmentBlocks, + uint32_t batchSize, bool bySegment, bool precompute, int deviceIndex) + : type(type), version(version), passes(passes), lanes(lanes), + segmentBlocks(segmentBlocks), batchSize(batchSize), bySegment(bySegment), deviceIndex(deviceIndex), + precompute(precompute), stream(nullptr), memory(nullptr), + refs(nullptr), start(nullptr), end(nullptr) +{ + setCudaDevice(deviceIndex); + + // FIXME: check overflow: + size_t memorySize = static_cast(lanes) * segmentBlocks * ARGON2_SYNC_POINTS * ARGON2_BLOCK_SIZE * batchSize; + +#ifndef NDEBUG + std::cerr << "[INFO] Allocating " << memorySize << " bytes for memory..." + << std::endl; +#endif + + CudaException::check(cudaMalloc(&memory, memorySize)); + + CudaException::check(cudaEventCreate(&start)); + CudaException::check(cudaEventCreate(&end)); + + CudaException::check(cudaStreamCreate(&stream)); + + if ((type == ARGON2_I || type == ARGON2_ID) && precompute) + { + uint32_t segments = + type == ARGON2_ID + ? lanes * (ARGON2_SYNC_POINTS / 2) + : passes * lanes * ARGON2_SYNC_POINTS; + + size_t refsSize = segments * segmentBlocks * sizeof(struct ref); + +#ifndef NDEBUG + std::cerr << "[INFO] Allocating " << refsSize << " bytes for refs..." + << std::endl; +#endif + + CudaException::check(cudaMalloc(&refs, refsSize)); + + precomputeRefs(); + CudaException::check(cudaStreamSynchronize(stream)); + } +} + +void KernelRunner::precomputeRefs() +{ + struct ref *refs = (struct ref *)this->refs; + + uint32_t segmentAddrBlocks = (segmentBlocks + ARGON2_QWORDS_IN_BLOCK - 1) / ARGON2_QWORDS_IN_BLOCK; + uint32_t segments = + type == ARGON2_ID + ? lanes * (ARGON2_SYNC_POINTS / 2) + : passes * lanes * ARGON2_SYNC_POINTS; + + dim3 blocks = dim3(1, segments * segmentAddrBlocks); + dim3 threads = dim3(THREADS_PER_LANE); + + if (type == ARGON2_I) + { + argon2_precompute_kernel + <<>>( + refs, passes, lanes, segmentBlocks); + } + else + { + argon2_precompute_kernel + <<>>( + refs, passes, lanes, segmentBlocks); + } +} + +KernelRunner::~KernelRunner() +{ + if (start != nullptr) + { + cudaEventDestroy(start); + } + if (end != nullptr) + { + cudaEventDestroy(end); + } + if (stream != nullptr) + { + cudaStreamDestroy(stream); + } + if (memory != nullptr) + { + cudaFree(memory); + } + if (refs != nullptr) + { + cudaFree(refs); + } +} + +void KernelRunner::writeInputMemory(uint32_t jobId, const void *buffer) +{ + std::size_t memorySize = static_cast(lanes) * segmentBlocks * ARGON2_SYNC_POINTS * ARGON2_BLOCK_SIZE; + std::size_t size = static_cast(lanes) * 2 * ARGON2_BLOCK_SIZE; + std::size_t offset = memorySize * jobId; + auto mem = static_cast(memory) + offset; + CudaException::check(cudaMemcpyAsync(mem, buffer, size, + cudaMemcpyHostToDevice, stream)); + CudaException::check(cudaStreamSynchronize(stream)); +} + +void KernelRunner::readOutputMemory(uint32_t jobId, void *buffer) +{ + std::size_t memorySize = static_cast(lanes) * segmentBlocks * ARGON2_SYNC_POINTS * ARGON2_BLOCK_SIZE; + std::size_t size = static_cast(lanes) * ARGON2_BLOCK_SIZE; + std::size_t offset = memorySize * (jobId + 1) - size; + auto mem = static_cast(memory) + offset; + CudaException::check(cudaMemcpyAsync(buffer, mem, size, + cudaMemcpyDeviceToHost, stream)); + CudaException::check(cudaStreamSynchronize(stream)); +} + +void KernelRunner::runKernelSegment(uint32_t lanesPerBlock, + uint32_t jobsPerBlock, + uint32_t pass, uint32_t slice) +{ + if (lanesPerBlock > lanes || lanes % lanesPerBlock != 0) + { + throw std::logic_error("Invalid lanesPerBlock!"); + } + + if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) + { + throw std::logic_error("Invalid jobsPerBlock!"); + } + + struct block_g *memory_blocks = (struct block_g *)memory; + dim3 blocks = dim3(1, lanes / lanesPerBlock, batchSize / jobsPerBlock); + dim3 threads = dim3(THREADS_PER_LANE, lanesPerBlock, jobsPerBlock); + if (type == ARGON2_I) + { + if (precompute) + { + struct ref *refs = (struct ref *)this->refs; + if (version == ARGON2_VERSION_10) + { + argon2_kernel_segment_precompute + <<>>( + memory_blocks, refs, passes, lanes, segmentBlocks, + pass, slice); + } + else + { + argon2_kernel_segment_precompute + <<>>( + memory_blocks, refs, passes, lanes, segmentBlocks, + pass, slice); + } + } + else + { + if (version == ARGON2_VERSION_10) + { + argon2_kernel_segment + <<>>( + memory_blocks, passes, lanes, segmentBlocks, + pass, slice); + } + else + { + argon2_kernel_segment + <<>>( + memory_blocks, passes, lanes, segmentBlocks, + pass, slice); + } + } + } + else if (type == ARGON2_ID) + { + if (precompute) + { + struct ref *refs = (struct ref *)this->refs; + if (version == ARGON2_VERSION_10) + { + argon2_kernel_segment_precompute + <<>>( + memory_blocks, refs, passes, lanes, segmentBlocks, + pass, slice); + } + else + { + argon2_kernel_segment_precompute + <<>>( + memory_blocks, refs, passes, lanes, segmentBlocks, + pass, slice); + } + } + else + { + if (version == ARGON2_VERSION_10) + { + argon2_kernel_segment + <<>>( + memory_blocks, passes, lanes, segmentBlocks, + pass, slice); + } + else + { + argon2_kernel_segment + <<>>( + memory_blocks, passes, lanes, segmentBlocks, + pass, slice); + } + } + } + else + { + if (version == ARGON2_VERSION_10) + { + argon2_kernel_segment + <<>>( + memory_blocks, passes, lanes, segmentBlocks, + pass, slice); + } + else + { + argon2_kernel_segment + <<>>( + memory_blocks, passes, lanes, segmentBlocks, + pass, slice); + } + } +} + +void KernelRunner::runKernelOneshot(uint32_t lanesPerBlock, + uint32_t jobsPerBlock) +{ + if (lanesPerBlock != lanes) + { + throw std::logic_error("Invalid lanesPerBlock!"); + } + + if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) + { + throw std::logic_error("Invalid jobsPerBlock!"); + } + + struct block_g *memory_blocks = (struct block_g *)memory; + dim3 blocks = dim3(1, 1, batchSize / jobsPerBlock); + dim3 threads = dim3(THREADS_PER_LANE, lanes, jobsPerBlock); + if (type == ARGON2_I) + { + if (precompute) + { + struct ref *refs = (struct ref *)this->refs; + if (version == ARGON2_VERSION_10) + { + argon2_kernel_oneshot_precompute + <<>>( + memory_blocks, refs, passes, lanes, segmentBlocks); + } + else + { + argon2_kernel_oneshot_precompute + <<>>( + memory_blocks, refs, passes, lanes, segmentBlocks); + } + } + else + { + if (version == ARGON2_VERSION_10) + { + argon2_kernel_oneshot + <<>>( + memory_blocks, passes, lanes, segmentBlocks); + } + else + { + argon2_kernel_oneshot + <<>>( + memory_blocks, passes, lanes, segmentBlocks); + } + } + } + else if (type == ARGON2_ID) + { + if (precompute) + { + struct ref *refs = (struct ref *)this->refs; + if (version == ARGON2_VERSION_10) + { + argon2_kernel_oneshot_precompute + <<>>( + memory_blocks, refs, passes, lanes, segmentBlocks); + } + else + { + argon2_kernel_oneshot_precompute + <<>>( + memory_blocks, refs, passes, lanes, segmentBlocks); + } + } + else + { + if (version == ARGON2_VERSION_10) + { + argon2_kernel_oneshot + <<>>( + memory_blocks, passes, lanes, segmentBlocks); + } + else + { + argon2_kernel_oneshot + <<>>( + memory_blocks, passes, lanes, segmentBlocks); + } + } + } + else + { + if (version == ARGON2_VERSION_10) + { + argon2_kernel_oneshot + <<>>( + memory_blocks, passes, lanes, segmentBlocks); + } + else + { + argon2_kernel_oneshot + <<>>( + memory_blocks, passes, lanes, segmentBlocks); + } + } +} + +void KernelRunner::run(uint32_t lanesPerBlock, uint32_t jobsPerBlock) +{ + setCudaDevice(deviceIndex); + CudaException::check(cudaEventRecord(start, stream)); + + if (bySegment) + { + for (uint32_t pass = 0; pass < passes; pass++) + { + for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; slice++) + { + runKernelSegment(lanesPerBlock, jobsPerBlock, pass, slice); + } + } + } + else + { + runKernelOneshot(lanesPerBlock, jobsPerBlock); + } + + CudaException::check(cudaGetLastError()); + + CudaException::check(cudaEventRecord(end, stream)); +} + +float KernelRunner::finish() +{ + CudaException::check(cudaStreamSynchronize(stream)); + + float time = 0.0; + CudaException::check(cudaEventElapsedTime(&time, start, end)); + return time; +} + +} // namespace cuda +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-cuda/processing-unit.cpp b/contrib/argon2-gpu/src/argon2-cuda/processing-unit.cpp new file mode 100644 index 0000000000..91c49e438d --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-cuda/processing-unit.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-cuda/processing-unit.h" +#include "argon2-cuda/cuda-exception.h" + +#include +#ifndef NDEBUG +#include +#endif + +namespace argon2gpu +{ +namespace cuda +{ + +static void setCudaDevice(int deviceIndex) +{ + int currentIndex = -1; + CudaException::check(cudaGetDevice(¤tIndex)); + if (currentIndex != deviceIndex) + { + CudaException::check(cudaSetDevice(deviceIndex)); + } +} + +static bool isPowerOfTwo(std::uint32_t x) +{ + return (x & (x - 1)) == 0; +} + +ProcessingUnit::ProcessingUnit( + const ProgramContext *programContext, const Argon2Params *params, + const Device *device, std::size_t batchSize, bool bySegment, + bool precomputeRefs) + : programContext(programContext), params(params), device(device), + runner(programContext->getArgon2Type(), + programContext->getArgon2Version(), params->getTimeCost(), + params->getLanes(), params->getSegmentBlocks(), batchSize, + bySegment, precomputeRefs, device->getDeviceIndex()), + bestLanesPerBlock(runner.getMinLanesPerBlock()), + bestJobsPerBlock(runner.getMinJobsPerBlock()) +{ + setCudaDevice(device->getDeviceIndex()); + + /* pre-fill first blocks with pseudo-random data: */ + for (std::size_t i = 0; i < batchSize; i++) + { + setInputAndSalt(i, NULL, 0); + } + + if (runner.getMaxLanesPerBlock() > runner.getMinLanesPerBlock() && isPowerOfTwo(runner.getMaxLanesPerBlock())) + { +#ifndef NDEBUG + std::cerr << "[INFO] Tuning lanes per block..." << std::endl; +#endif + + float bestTime = std::numeric_limits::infinity(); + for (std::uint32_t lpb = 1; lpb <= runner.getMaxLanesPerBlock(); + lpb *= 2) + { + float time; + try + { + runner.run(lpb, bestJobsPerBlock); + time = runner.finish(); + } + catch (CudaException &ex) + { +#ifndef NDEBUG + std::cerr << "[WARN] CUDA error on " << lpb + << " lanes per block: " << ex.what() << std::endl; +#endif + break; + } + +#ifndef NDEBUG + std::cerr << "[INFO] " << lpb << " lanes per block: " + << time << " ms" << std::endl; +#endif + + if (time < bestTime) + { + bestTime = time; + bestLanesPerBlock = lpb; + } + } +#ifndef NDEBUG + std::cerr << "[INFO] Picked " << bestLanesPerBlock + << " lanes per block." << std::endl; +#endif + } + + /* Only tune jobs per block if we hit maximum lanes per block: */ + if (bestLanesPerBlock == runner.getMaxLanesPerBlock() && runner.getMaxJobsPerBlock() > runner.getMinJobsPerBlock() && isPowerOfTwo(runner.getMaxJobsPerBlock())) + { +#ifndef NDEBUG + std::cerr << "[INFO] Tuning jobs per block..." << std::endl; +#endif + + float bestTime = std::numeric_limits::infinity(); + for (std::uint32_t jpb = 1; jpb <= runner.getMaxJobsPerBlock(); + jpb *= 2) + { + float time; + try + { + runner.run(bestLanesPerBlock, jpb); + time = runner.finish(); + } + catch (CudaException &ex) + { +#ifndef NDEBUG + std::cerr << "[WARN] CUDA error on " << jpb + << " jobs per block: " << ex.what() << std::endl; +#endif + break; + } + +#ifndef NDEBUG + std::cerr << "[INFO] " << jpb << " jobs per block: " + << time << " ms" << std::endl; +#endif + + if (time < bestTime) + { + bestTime = time; + bestJobsPerBlock = jpb; + } + } +#ifndef NDEBUG + std::cerr << "[INFO] Picked " << bestJobsPerBlock + << " jobs per block." << std::endl; +#endif + } +} + +void ProcessingUnit::setInputAndSalt(std::size_t index, const void *pw, + const std::size_t pwSize) +{ + std::size_t size = params->getLanes() * 2 * ARGON2_BLOCK_SIZE; + auto buffer = std::unique_ptr(new uint8_t[size]); + params->fillFirstBlocks(buffer.get(), pw, pwSize, + programContext->getArgon2Type(), + programContext->getArgon2Version()); + runner.writeInputMemory(index, buffer.get()); +} + +void ProcessingUnit::getHash(std::size_t index, void *hash) +{ + std::size_t size = params->getLanes() * ARGON2_BLOCK_SIZE; + auto buffer = std::unique_ptr(new uint8_t[size]); + runner.readOutputMemory(index, buffer.get()); + params->finalize(hash, buffer.get()); +} + +void ProcessingUnit::beginProcessing() +{ + setCudaDevice(device->getDeviceIndex()); + runner.run(bestLanesPerBlock, bestJobsPerBlock); +} + +void ProcessingUnit::endProcessing() +{ + runner.finish(); +} + +} // namespace cuda +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-cuda/program-context.cpp b/contrib/argon2-gpu/src/argon2-cuda/program-context.cpp new file mode 100644 index 0000000000..620b97284e --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-cuda/program-context.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-cuda/kernels.h" +#include "argon2-cuda/program-context.h" + +#define THREADS_PER_LANE 32 + +namespace argon2gpu +{ +namespace cuda +{ + +ProgramContext::ProgramContext( + const GlobalContext *globalContext, + const std::vector &devices, + Type type, Version version) + : globalContext(globalContext), type(type), version(version) +{ +} + +} // namespace cuda +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-gpu/blake2b.cpp b/contrib/argon2-gpu/src/argon2-gpu/blake2b.cpp new file mode 100644 index 0000000000..a0f04ed899 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-gpu/blake2b.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-gpu/blake2b.h" + +#include + +namespace argon2gpu +{ + +static const std::uint64_t blake2b_IV[8] = { + UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179)}; + +static const unsigned int blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, +}; + +#define rotr64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) + +#define G(m, r, i, a, b, c, d) \ + do \ + { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define ROUND(m, v, r) \ + do \ + { \ + G(m, r, 0, v[0], v[4], v[8], v[12]); \ + G(m, r, 1, v[1], v[5], v[9], v[13]); \ + G(m, r, 2, v[2], v[6], v[10], v[14]); \ + G(m, r, 3, v[3], v[7], v[11], v[15]); \ + G(m, r, 4, v[0], v[5], v[10], v[15]); \ + G(m, r, 5, v[1], v[6], v[11], v[12]); \ + G(m, r, 6, v[2], v[7], v[8], v[13]); \ + G(m, r, 7, v[3], v[4], v[9], v[14]); \ + } while ((void)0, 0) + +static std::uint64_t load64(const void *src) +{ + auto in = static_cast(src); + std::uint64_t res = *in++; + res |= static_cast(*in++) << 8; + res |= static_cast(*in++) << 16; + res |= static_cast(*in++) << 24; + res |= static_cast(*in++) << 32; + res |= static_cast(*in++) << 40; + res |= static_cast(*in++) << 48; + res |= static_cast(*in++) << 56; + return res; +} + +static void store64(void *dst, std::uint64_t v) +{ + auto out = static_cast(dst); + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); +} + +void Blake2b::init(std::size_t outlen) +{ + t[1] = t[0] = 0; + bufLen = 0; + + std::memcpy(h, blake2b_IV, sizeof(h)); + + h[0] ^= static_cast(outlen) | + (UINT64_C(1) << 16) | (UINT64_C(1) << 24); +} + +void Blake2b::compress(const void *block, std::uint64_t f0) +{ + std::uint64_t m[16]; + std::uint64_t v[16]; + + auto in = static_cast(block); + + m[0] = load64(in + 0); + m[1] = load64(in + 1); + m[2] = load64(in + 2); + m[3] = load64(in + 3); + m[4] = load64(in + 4); + m[5] = load64(in + 5); + m[6] = load64(in + 6); + m[7] = load64(in + 7); + m[8] = load64(in + 8); + m[9] = load64(in + 9); + m[10] = load64(in + 10); + m[11] = load64(in + 11); + m[12] = load64(in + 12); + m[13] = load64(in + 13); + m[14] = load64(in + 14); + m[15] = load64(in + 15); + + v[0] = h[0]; + v[1] = h[1]; + v[2] = h[2]; + v[3] = h[3]; + v[4] = h[4]; + v[5] = h[5]; + v[6] = h[6]; + v[7] = h[7]; + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ t[0]; + v[13] = blake2b_IV[5] ^ t[1]; + v[14] = blake2b_IV[6] ^ f0; + v[15] = blake2b_IV[7]; + + ROUND(m, v, 0); + ROUND(m, v, 1); + ROUND(m, v, 2); + ROUND(m, v, 3); + ROUND(m, v, 4); + ROUND(m, v, 5); + ROUND(m, v, 6); + ROUND(m, v, 7); + ROUND(m, v, 8); + ROUND(m, v, 9); + ROUND(m, v, 10); + ROUND(m, v, 11); + + h[0] ^= v[0] ^ v[8]; + h[1] ^= v[1] ^ v[9]; + h[2] ^= v[2] ^ v[10]; + h[3] ^= v[3] ^ v[11]; + h[4] ^= v[4] ^ v[12]; + h[5] ^= v[5] ^ v[13]; + h[6] ^= v[6] ^ v[14]; + h[7] ^= v[7] ^ v[15]; +} + +void Blake2b::incrementCounter(std::uint64_t inc) +{ + t[0] += inc; + t[1] += (t[0] < inc); +} + +void Blake2b::update(const void *in, std::size_t inLen) +{ + auto bin = static_cast(in); + + if (bufLen + inLen > BLOCK_BYTES) + { + std::size_t have = bufLen; + std::size_t left = BLOCK_BYTES - have; + std::memcpy(buf + have, bin, left); + + incrementCounter(BLOCK_BYTES); + compress(buf, 0); + + bufLen = 0; + inLen -= left; + bin += left; + + while (inLen > BLOCK_BYTES) + { + incrementCounter(BLOCK_BYTES); + compress(bin, 0); + inLen -= BLOCK_BYTES; + bin += BLOCK_BYTES; + } + } + std::memcpy(buf + bufLen, bin, inLen); + bufLen += inLen; +} + +void Blake2b::final(void *out, std::size_t outLen) +{ + std::uint8_t buffer[OUT_BYTES] = {0}; + + incrementCounter(bufLen); + std::memset(buf + bufLen, 0, BLOCK_BYTES - bufLen); + compress(buf, UINT64_C(0xFFFFFFFFFFFFFFFF)); + + for (unsigned int i = 0; i < 8; i++) + { + store64(buffer + i * sizeof(std::uint64_t), h[i]); + } + + std::memcpy(out, buffer, outLen); +} + +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-gpu/common.cpp b/contrib/argon2-gpu/src/argon2-gpu/common.cpp new file mode 100644 index 0000000000..78d690c30a --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-gpu/common.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-gpu/common.h" +#include "argon2-gpu/blake2b.h" + +#include +#include + +#include + +#ifdef DEBUG +#include +#endif + +namespace argon2gpu +{ + +static void store32(void *dst, std::uint32_t v) +{ + auto out = static_cast(dst); + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); + v >>= 8; + *out++ = static_cast(v); +} + +Argon2Params::Argon2Params(std::size_t outLen, std::size_t t_cost, std::size_t m_cost, std::size_t lanes) + : outLen(outLen), t_cost(t_cost), m_cost(m_cost), lanes(lanes) +{ + // TODO validate inputs + std::size_t segments = lanes * ARGON2_SYNC_POINTS; + segmentBlocks = std::max(m_cost, 2 * segments) / segments; +} + +void Argon2Params::digestLong(void *out, std::size_t outLen, + const void *in, std::size_t inLen) +{ + auto bout = static_cast(out); + std::uint8_t outlen_bytes[sizeof(std::uint32_t)]; + Blake2b blake; + + store32(outlen_bytes, static_cast(outLen)); + if (outLen <= Blake2b::OUT_BYTES) + { + blake.init(outLen); + blake.update(outlen_bytes, sizeof(outlen_bytes)); + blake.update(in, inLen); + blake.final(out, outLen); + } + else + { + std::uint8_t out_buffer[Blake2b::OUT_BYTES]; + + blake.init(Blake2b::OUT_BYTES); + blake.update(outlen_bytes, sizeof(outlen_bytes)); + blake.update(in, inLen); + blake.final(out_buffer, Blake2b::OUT_BYTES); + + std::memcpy(bout, out_buffer, Blake2b::OUT_BYTES / 2); + bout += Blake2b::OUT_BYTES / 2; + + std::size_t toProduce = outLen - Blake2b::OUT_BYTES / 2; + while (toProduce > Blake2b::OUT_BYTES) + { + blake.init(Blake2b::OUT_BYTES); + blake.update(out_buffer, Blake2b::OUT_BYTES); + blake.final(out_buffer, Blake2b::OUT_BYTES); + + std::memcpy(bout, out_buffer, Blake2b::OUT_BYTES / 2); + bout += Blake2b::OUT_BYTES / 2; + toProduce -= Blake2b::OUT_BYTES / 2; + } + + blake.init(toProduce); + blake.update(out_buffer, Blake2b::OUT_BYTES); + blake.final(bout, toProduce); + } +} + +void Argon2Params::initialHash( + void *out, const void *input, std::size_t inputLen, + Type type, Version version) const +{ + Blake2b blake; + std::uint8_t value[sizeof(std::uint32_t)]; + + blake.init(ARGON2_PREHASH_DIGEST_LENGTH); + + store32(value, lanes); + blake.update(value, sizeof(value)); + store32(value, outLen); + blake.update(value, sizeof(value)); + store32(value, m_cost); + blake.update(value, sizeof(value)); + store32(value, t_cost); + blake.update(value, sizeof(value)); + store32(value, version); + blake.update(value, sizeof(value)); + store32(value, type); + blake.update(value, sizeof(value)); + store32(value, inputLen); + blake.update(value, sizeof(value)); + blake.update(input, inputLen); + store32(value, inputLen); + blake.update(value, sizeof(value)); // saltLen + blake.update(input, inputLen); // salt, saltLen + store32(value, 0); + blake.update(value, sizeof(value)); + blake.update(NULL, 0); + store32(value, 0); + blake.update(value, sizeof(value)); + blake.update(NULL, 0); + + blake.final(out, ARGON2_PREHASH_DIGEST_LENGTH); +} + +void Argon2Params::fillFirstBlocks( + void *memory, const void *input, std::size_t inputLen, + Type type, Version version) const +{ + std::uint8_t initHash[ARGON2_PREHASH_SEED_LENGTH]; + initialHash(initHash, input, inputLen, type, version); + +#ifdef DEBUG + std::fprintf(stderr, "Initial hash: "); + for (std::size_t i = 0; i < ARGON2_PREHASH_DIGEST_LENGTH; i++) + { + std::fprintf(stderr, "%02x", (unsigned int)initHash[i]); + } + std::fprintf(stderr, "\n"); +#endif + + auto bmemory = static_cast(memory); + + store32(initHash + ARGON2_PREHASH_DIGEST_LENGTH, 0); + for (std::uint32_t l = 0; l < lanes; l++) + { + store32(initHash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + digestLong(bmemory, ARGON2_BLOCK_SIZE, initHash, sizeof(initHash)); + +#ifdef DEBUG + std::fprintf(stderr, "Initial block 0 for lane %u: {\n", (unsigned)l); + for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) + { + std::fprintf(stderr, " 0x"); + for (std::size_t k = 0; k < 8; k++) + { + std::fprintf(stderr, "%02x", (unsigned)bmemory[i * 8 + 7 - k]); + } + std::fprintf(stderr, "UL,\n"); + } + std::fprintf(stderr, "}\n"); +#endif + + bmemory += ARGON2_BLOCK_SIZE; + } + + store32(initHash + ARGON2_PREHASH_DIGEST_LENGTH, 1); + for (std::uint32_t l = 0; l < lanes; l++) + { + store32(initHash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + digestLong(bmemory, ARGON2_BLOCK_SIZE, initHash, sizeof(initHash)); + +#ifdef DEBUG + std::fprintf(stderr, "Initial block 1 for lane %u: {\n", (unsigned)l); + for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) + { + std::fprintf(stderr, " 0x"); + for (std::size_t k = 0; k < 8; k++) + { + std::fprintf(stderr, "%02x", (unsigned)bmemory[i * 8 + 7 - k]); + } + std::fprintf(stderr, "UL,\n"); + } + std::fprintf(stderr, "}\n"); +#endif + + bmemory += ARGON2_BLOCK_SIZE; + } +} + +void Argon2Params::finalize(void *out, const void *memory) const +{ + /* TODO: nicify this (or move it into the kernel (I mean, we currently + * have all lanes in one work-group...) */ + struct block + { + std::uint64_t v[ARGON2_BLOCK_SIZE / 8]; + }; + + auto cursor = static_cast(memory); +#ifdef DEBUG + for (std::size_t l = 0; l < getLanes(); l++) + { + for (std::size_t k = 0; k < ARGON2_BLOCK_SIZE / 8; k++) + { + std::fprintf(stderr, "Block %04u [%3u]: %016llx\n", + (unsigned)i, (unsigned)k, + (unsigned long long)cursor[l].v[k]); + } + } +#endif + + block xored = *cursor; + for (std::uint32_t l = 1; l < lanes; l++) + { + ++cursor; + for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) + { + xored.v[i] ^= cursor->v[i]; + } + } + + digestLong(out, outLen, &xored, ARGON2_BLOCK_SIZE); +} + +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-gpu/empty.cpp b/contrib/argon2-gpu/src/argon2-gpu/empty.cpp new file mode 100644 index 0000000000..d2eb12753b --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-gpu/empty.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// Used when there is no CUDA available diff --git a/contrib/argon2-gpu/src/argon2-opencl/device.cpp b/contrib/argon2-gpu/src/argon2-opencl/device.cpp new file mode 100644 index 0000000000..05c4d03da6 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-opencl/device.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-opencl/device.h" + +#include +#include +#include + +namespace argon2gpu +{ +namespace opencl +{ + +std::string Device::getName() const +{ + return "OpenCL Device '" + device.getInfo() + "' (" + device.getInfo() + ")"; +} + +template +static std::ostream &printBitfield(std::ostream &out, T value, + const std::vector> &lookup) +{ + bool first = true; + for (auto &entry : lookup) + { + if (value & entry.first) + { + if (!first) + { + out << " | "; + } + first = false; + out << entry.second; + } + } + return out; +} + +template +static std::ostream &printEnum(std::ostream &out, T value, + const std::unordered_map &lookup) +{ + try + { + return out << lookup.at(value); + } + catch (const std::out_of_range &) + { + return out << ""; + } +} + +template +std::ostream &operator<<(std::ostream &out, const std::vector &vec) +{ + out << "["; + bool first = true; + for (T value : vec) + { + if (!first) + { + out << ", "; + } + first = false; + out << value; + } + return out << "]"; +} + +std::string Device::getInfo() const +{ + std::ostringstream out; + out << "OpenCL Device '" << device.getInfo() << "':" << std::endl; + out << " Type: "; + printBitfield(out, device.getInfo(), { + {CL_DEVICE_TYPE_CPU, "CPU"}, + {CL_DEVICE_TYPE_GPU, "GPU"}, + {CL_DEVICE_TYPE_ACCELERATOR, "Accelerator"}, + {CL_DEVICE_TYPE_DEFAULT, "Default"}, + }) + << std::endl; + out << " Available: " + << device.getInfo() << std::endl; + out << " Compiler available: " + << device.getInfo() << std::endl; + out << std::endl; + + out << " Version: " + << device.getInfo() << std::endl; + out << " OpenCL C Version: " + << device.getInfo() << std::endl; + out << " Extensions: " + << device.getInfo() << std::endl; + out << std::endl; + + out << " Vendor: " + << device.getInfo() << std::endl; + out << " Vendor ID: " + << device.getInfo() << std::endl; + out << std::endl; + + cl::Platform platform(device.getInfo()); + out << " Platform name: " + << platform.getInfo() << std::endl; + out << " Platform vendor: " + << platform.getInfo() << std::endl; + out << " Platform version: " + << platform.getInfo() << std::endl; + out << " Platform extensions: " + << platform.getInfo() << std::endl; + out << std::endl; + + out << " Driver version: " + << device.getInfo() << std::endl; + out << " Little-endian: " + << device.getInfo() << std::endl; + out << std::endl; + + out << " Max compute units: " + << device.getInfo() << std::endl; + out << " Max work-item dimensions: " + << device.getInfo() << std::endl; + out << " Max work-item sizes: " + << device.getInfo() << std::endl; + out << std::endl; + + out << " Max clock frequency: " + << device.getInfo() << " MHz" << std::endl; + out << std::endl; + + out << " Address bits: " + << device.getInfo() << std::endl; + out << " Max memory allocation size: " + << device.getInfo() << " bytes" << std::endl; + out << " Max parameter size: " + << device.getInfo() << " bytes" << std::endl; + out << " Memory base address alignment: " + << device.getInfo() << " bits" << std::endl; + out << " Min data type alignment: " + << device.getInfo() << " bytes" << std::endl; + out << std::endl; + + out << " Unified memory: " + << device.getInfo() << std::endl; + out << " Global memory cache type: "; + printEnum(out, device.getInfo(), {{CL_NONE, "None"}, {CL_READ_ONLY_CACHE, "Read-only"}, {CL_READ_WRITE_CACHE, "Read-write"}}) << std::endl; + out << " Global memory cacheline size: " + << device.getInfo() << " bytes" << std::endl; + out << " Global memory cache size: " + << device.getInfo() << " bytes" << std::endl; + out << " Global memory size: " + << device.getInfo() << " bytes" << std::endl; + out << std::endl; + + out << " Max constant buffer size: " + << device.getInfo() << " bytes" << std::endl; + out << " Max constant arguments: " + << device.getInfo() << std::endl; + out << std::endl; + + out << " Local memory type: "; + printEnum(out, device.getInfo(), { + {CL_LOCAL, "Dedicated"}, + {CL_GLOBAL, "Global"}, + }) + << std::endl; + out << " Local memory size: " + << device.getInfo() << " bytes" << std::endl; + out << std::endl; + + out << " Preferred vector width (char): " + << device.getInfo() + << " (native: " + << device.getInfo() + << ")" << std::endl; + out << " Preferred vector width (short): " + << device.getInfo() + << " (native: " + << device.getInfo() + << ")" << std::endl; + out << " Preferred vector width (int): " + << device.getInfo() + << " (native: " + << device.getInfo() + << ")" << std::endl; + out << " Preferred vector width (long): " + << device.getInfo() + << " (native: " + << device.getInfo() + << ")" << std::endl; + out << " Preferred vector width (float): " + << device.getInfo() + << " (native: " + << device.getInfo() + << ")" << std::endl; + out << " Preferred vector width (double): " + << device.getInfo() + << " (native: " + << device.getInfo() + << ")" << std::endl; + out << " Preferred vector width (half): " + << device.getInfo() + << " (native: " + << device.getInfo() + << ")" << std::endl; + out << std::endl; + + out << " Error correction supported: " + << device.getInfo() << std::endl; + out << " Profiling timer resolution: " + << device.getInfo() << " ns" << std::endl; + out << std::endl; + + out << " Execution capabilites: "; + printBitfield(out, device.getInfo(), { + {CL_EXEC_KERNEL, "OpenCL kernels"}, + {CL_EXEC_NATIVE_KERNEL, "Native kernels"}, + }) + << std::endl; + out << " Command queue properties: "; + printBitfield(out, device.getInfo(), { + {CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, "Out-of-order execution"}, + {CL_QUEUE_PROFILING_ENABLE, "Profiling"}, + }) + << std::endl; + return std::move(out.str()); +} + +} // namespace opencl +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-opencl/global-context.cpp b/contrib/argon2-gpu/src/argon2-opencl/global-context.cpp new file mode 100644 index 0000000000..6f15c5c1f8 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-opencl/global-context.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-opencl/global-context.h" + +#include + +namespace argon2gpu +{ +namespace opencl +{ + +GlobalContext::GlobalContext() + : devices() +{ + std::vector platforms; + cl::Platform::get(&platforms); + + std::vector clDevices; + for (cl::Platform platform : platforms) + { + try + { + platform.getDevices(CL_DEVICE_TYPE_ALL, &clDevices); + devices.insert(devices.end(), clDevices.begin(), clDevices.end()); + } + catch (const cl::Error &err) + { + std::cerr << "WARNING: Unable to get devices for platform '" + << platform.getInfo() + << "' - error " << err.err() << std::endl; + } + } +} + +} // namespace opencl +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-opencl/kernel-loader.cpp b/contrib/argon2-gpu/src/argon2-opencl/kernel-loader.cpp new file mode 100644 index 0000000000..9224cd2356 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-opencl/kernel-loader.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-opencl/kernel-loader.h" + +#include +#include +#include + +namespace argon2gpu +{ +namespace opencl +{ + +cl::Program KernelLoader::loadArgon2Program( + const cl::Context &context, + const std::string &sourceDirectory, + Type type, Version version, bool debug) +{ + std::string sourcePath = sourceDirectory + "/kernel.cl"; + std::string sourceText; + std::stringstream buildOpts; + { + std::ifstream sourceFile{sourcePath}; + sourceText = { + std::istreambuf_iterator(sourceFile), + std::istreambuf_iterator()}; + } + + if (debug) + { + buildOpts << "-g -s \"" << sourcePath << "\"" + << " "; + } + buildOpts << "-DARGON2_TYPE=" << type << " "; + buildOpts << "-DARGON2_VERSION=" << version << " "; + + cl::Program prog(context, sourceText); + try + { + std::string opts = buildOpts.str(); + prog.build(opts.c_str()); + } + catch (const cl::Error &err) + { + std::cerr << "ERROR: Failed to build program:" << std::endl; + for (cl::Device &device : context.getInfo()) + { + std::cerr << " Build log from device '" << device.getInfo() << "':" << std::endl; + std::cerr << prog.getBuildInfo(device); + } + throw; + } + return prog; +} + +} // namespace opencl +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-opencl/kernel-runner.cpp b/contrib/argon2-gpu/src/argon2-opencl/kernel-runner.cpp new file mode 100644 index 0000000000..d675d7d836 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-opencl/kernel-runner.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-opencl/kernel-runner.h" + +#include + +#ifndef NDEBUG +#include +#endif + +#define THREADS_PER_LANE 32 + +namespace argon2gpu +{ +namespace opencl +{ + +enum +{ + ARGON2_REFS_PER_BLOCK = ARGON2_BLOCK_SIZE / (2 * sizeof(cl_uint)), +}; + +KernelRunner::KernelRunner(const ProgramContext *programContext, + const Argon2Params *params, const Device *device, + std::uint32_t batchSize, bool bySegment, bool precompute) + : programContext(programContext), params(params), batchSize(batchSize), + bySegment(bySegment), precompute(precompute), + memorySize(params->getMemorySize() * static_cast(batchSize)) +{ + auto context = programContext->getContext(); + std::uint32_t passes = params->getTimeCost(); + std::uint32_t lanes = params->getLanes(); + std::uint32_t segmentBlocks = params->getSegmentBlocks(); + + queue = cl::CommandQueue(context, device->getCLDevice(), + CL_QUEUE_PROFILING_ENABLE); + +#ifndef NDEBUG + std::cerr << "[INFO] Allocating " << memorySize << " bytes for memory..." + << std::endl; +#endif + + memoryBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, memorySize); + + Type type = programContext->getArgon2Type(); + if ((type == ARGON2_I || type == ARGON2_ID) && precompute) + { + std::uint32_t segments = + type == ARGON2_ID + ? lanes * (ARGON2_SYNC_POINTS / 2) + : passes * lanes * ARGON2_SYNC_POINTS; + + std::size_t refsSize = segments * segmentBlocks * sizeof(cl_uint) * 2; + +#ifndef NDEBUG + std::cerr << "[INFO] Allocating " << refsSize << " bytes for refs..." + << std::endl; +#endif + + refsBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, refsSize); + + precomputeRefs(); + } + + static const char *KERNEL_NAMES[2][2] = { + { + "argon2_kernel_oneshot", + "argon2_kernel_segment", + }, + { + "argon2_kernel_oneshot_precompute", + "argon2_kernel_segment_precompute", + }}; + + kernel = cl::Kernel(programContext->getProgram(), + KERNEL_NAMES[precompute][bySegment]); + kernel.setArg(1, memoryBuffer); + if (precompute) + { + kernel.setArg(2, refsBuffer); + kernel.setArg(3, passes); + kernel.setArg(4, lanes); + kernel.setArg(5, segmentBlocks); + } + else + { + kernel.setArg(2, passes); + kernel.setArg(3, lanes); + kernel.setArg(4, segmentBlocks); + } +} + +void KernelRunner::precomputeRefs() +{ + std::uint32_t passes = params->getTimeCost(); + std::uint32_t lanes = params->getLanes(); + std::uint32_t segmentBlocks = params->getSegmentBlocks(); + std::uint32_t segmentAddrBlocks = + (segmentBlocks + ARGON2_REFS_PER_BLOCK - 1) / ARGON2_REFS_PER_BLOCK; + std::uint32_t segments = programContext->getArgon2Type() == ARGON2_ID + ? lanes * (ARGON2_SYNC_POINTS / 2) + : passes * lanes * ARGON2_SYNC_POINTS; + + std::size_t shmemSize = THREADS_PER_LANE * sizeof(cl_uint) * 2; + + cl::Kernel kernel = cl::Kernel(programContext->getProgram(), + "argon2_precompute_kernel"); + kernel.setArg(0, {shmemSize}); + kernel.setArg(1, refsBuffer); + kernel.setArg(2, passes); + kernel.setArg(3, lanes); + kernel.setArg(4, segmentBlocks); + + cl::NDRange globalRange{THREADS_PER_LANE * segments * segmentAddrBlocks}; + cl::NDRange localRange{THREADS_PER_LANE}; + queue.enqueueNDRangeKernel(kernel, cl::NullRange, globalRange, localRange); + queue.finish(); +} + +void *KernelRunner::mapInputMemory(std::uint32_t jobId) +{ + std::size_t memorySize = params->getMemorySize(); + std::size_t mappedSize = params->getLanes() * 2 * ARGON2_BLOCK_SIZE; + return queue.enqueueMapBuffer(memoryBuffer, true, CL_MAP_WRITE, + memorySize * jobId, mappedSize); +} + +void KernelRunner::unmapInputMemory(void *memory) +{ + queue.enqueueUnmapMemObject(memoryBuffer, memory); +} + +void *KernelRunner::mapOutputMemory(std::uint32_t jobId) +{ + std::size_t memorySize = params->getMemorySize(); + std::size_t mappedSize = static_cast(params->getLanes()) * ARGON2_BLOCK_SIZE; + std::size_t mappedOffset = memorySize * (jobId + 1) - mappedSize; + return queue.enqueueMapBuffer(memoryBuffer, true, CL_MAP_READ, + mappedOffset, mappedSize); +} + +void KernelRunner::unmapOutputMemory(void *memory) +{ + queue.enqueueUnmapMemObject(memoryBuffer, memory); +} + +void KernelRunner::run(std::uint32_t lanesPerBlock, std::uint32_t jobsPerBlock) +{ + std::uint32_t lanes = params->getLanes(); + std::uint32_t passes = params->getTimeCost(); + + if (bySegment) + { + if (lanesPerBlock > lanes || lanes % lanesPerBlock != 0) + { + throw std::logic_error("Invalid lanesPerBlock!"); + } + } + else + { + if (lanesPerBlock != lanes) + { + throw std::logic_error("Invalid lanesPerBlock!"); + } + } + + if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) + { + throw std::logic_error("Invalid jobsPerBlock!"); + } + + cl::NDRange globalRange{THREADS_PER_LANE * lanes, batchSize}; + cl::NDRange localRange{THREADS_PER_LANE * lanesPerBlock, jobsPerBlock}; + + queue.enqueueMarker(&start); + + std::size_t shmemSize = THREADS_PER_LANE * lanesPerBlock * jobsPerBlock * sizeof(cl_uint) * 2; + kernel.setArg(0, {shmemSize}); + if (bySegment) + { + for (std::uint32_t pass = 0; pass < passes; pass++) + { + for (std::uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; slice++) + { + kernel.setArg(precompute ? 6 : 5, pass); + kernel.setArg(precompute ? 7 : 6, slice); + queue.enqueueNDRangeKernel(kernel, cl::NullRange, + globalRange, localRange); + } + } + } + else + { + queue.enqueueNDRangeKernel(kernel, cl::NullRange, + globalRange, localRange); + } + + queue.enqueueMarker(&end); +} + +float KernelRunner::finish() +{ + end.wait(); + + cl_ulong nsStart = start.getProfilingInfo(); + cl_ulong nsEnd = end.getProfilingInfo(); + + return (nsEnd - nsStart) / (1000.0F * 1000.0F); +} + +} // namespace opencl +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-opencl/kernel.cl b/contrib/argon2-gpu/src/argon2-opencl/kernel.cl new file mode 100644 index 0000000000..e9806b4a29 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-opencl/kernel.cl @@ -0,0 +1,932 @@ +/* C compatibility For dumb IDEs: */ +#ifndef __OPENCL_VERSION__ +#ifndef __cplusplus +typedef int bool; +#endif +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned long size_t; +typedef long ptrdiff_t; +typedef size_t uintptr_t; +typedef ptrdiff_t intptr_t; +#ifndef __kernel +#define __kernel +#endif +#ifndef __global +#define __global +#endif +#ifndef __private +#define __private +#endif +#ifndef __local +#define __local +#endif +#ifndef __constant +#define __constant const +#endif +#endif /* __OPENCL_VERSION__ */ + +#define ARGON2_D 0 +#define ARGON2_I 1 +#define ARGON2_ID 2 + +#define ARGON2_VERSION_10 0x10 +#define ARGON2_VERSION_13 0x13 + +#define ARGON2_BLOCK_SIZE 1024 +#define ARGON2_QWORDS_IN_BLOCK (ARGON2_BLOCK_SIZE / 8) +#define ARGON2_SYNC_POINTS 4 + +#define THREADS_PER_LANE 32 +#define QWORDS_PER_THREAD (ARGON2_QWORDS_IN_BLOCK / 32) + +#ifndef ARGON2_VERSION +#define ARGON2_VERSION ARGON2_VERSION_13 +#endif + +#ifndef ARGON2_TYPE +#define ARGON2_TYPE ARGON2_I +#endif + +ulong u64_build(uint hi, uint lo) +{ + return upsample(hi, lo); +} + +uint u64_lo(ulong x) +{ + return (uint)x; +} + +uint u64_hi(ulong x) +{ + return (uint)(x >> 32); +} + +struct u64_shuffle_buf +{ + uint lo[THREADS_PER_LANE]; + uint hi[THREADS_PER_LANE]; +}; + +ulong u64_shuffle(ulong v, uint thread_src, uint thread, + __local struct u64_shuffle_buf *buf) +{ + uint lo = u64_lo(v); + uint hi = u64_hi(v); + + buf->lo[thread] = lo; + buf->hi[thread] = hi; + + barrier(CLK_LOCAL_MEM_FENCE); + + lo = buf->lo[thread_src]; + hi = buf->hi[thread_src]; + + return u64_build(hi, lo); +} + +struct block_g +{ + ulong data[ARGON2_QWORDS_IN_BLOCK]; +}; + +struct block_th +{ + ulong a, b, c, d; +}; + +ulong cmpeq_mask(uint test, uint ref) +{ + uint x = -(uint)(test == ref); + return u64_build(x, x); +} + +ulong block_th_get(const struct block_th *b, uint idx) +{ + ulong res = 0; + res ^= cmpeq_mask(idx, 0) & b->a; + res ^= cmpeq_mask(idx, 1) & b->b; + res ^= cmpeq_mask(idx, 2) & b->c; + res ^= cmpeq_mask(idx, 3) & b->d; + return res; +} + +void block_th_set(struct block_th *b, uint idx, ulong v) +{ + b->a ^= cmpeq_mask(idx, 0) & (v ^ b->a); + b->b ^= cmpeq_mask(idx, 1) & (v ^ b->b); + b->c ^= cmpeq_mask(idx, 2) & (v ^ b->c); + b->d ^= cmpeq_mask(idx, 3) & (v ^ b->d); +} + +void move_block(struct block_th *dst, const struct block_th *src) +{ + *dst = *src; +} + +void xor_block(struct block_th *dst, const struct block_th *src) +{ + dst->a ^= src->a; + dst->b ^= src->b; + dst->c ^= src->c; + dst->d ^= src->d; +} + +void load_block(struct block_th *dst, __global const struct block_g *src, + uint thread) +{ + dst->a = src->data[0 * THREADS_PER_LANE + thread]; + dst->b = src->data[1 * THREADS_PER_LANE + thread]; + dst->c = src->data[2 * THREADS_PER_LANE + thread]; + dst->d = src->data[3 * THREADS_PER_LANE + thread]; +} + +void load_block_xor(struct block_th *dst, __global const struct block_g *src, + uint thread) +{ + dst->a ^= src->data[0 * THREADS_PER_LANE + thread]; + dst->b ^= src->data[1 * THREADS_PER_LANE + thread]; + dst->c ^= src->data[2 * THREADS_PER_LANE + thread]; + dst->d ^= src->data[3 * THREADS_PER_LANE + thread]; +} + +void store_block(__global struct block_g *dst, const struct block_th *src, + uint thread) +{ + dst->data[0 * THREADS_PER_LANE + thread] = src->a; + dst->data[1 * THREADS_PER_LANE + thread] = src->b; + dst->data[2 * THREADS_PER_LANE + thread] = src->c; + dst->data[3 * THREADS_PER_LANE + thread] = src->d; +} + +#ifdef cl_amd_media_ops +#pragma OPENCL EXTENSION cl_amd_media_ops : enable + +ulong rotr64(ulong x, ulong n) +{ + uint lo = u64_lo(x); + uint hi = u64_hi(x); + uint r_lo, r_hi; + if (n < 32) + { + r_lo = amd_bitalign(hi, lo, (uint)n); + r_hi = amd_bitalign(lo, hi, (uint)n); + } + else + { + r_lo = amd_bitalign(lo, hi, (uint)n - 32); + r_hi = amd_bitalign(hi, lo, (uint)n - 32); + } + return u64_build(r_hi, r_lo); +} +#else +ulong rotr64(ulong x, ulong n) +{ + return rotate(x, 64 - n); +} +#endif + +ulong f(ulong x, ulong y) +{ + uint xlo = u64_lo(x); + uint ylo = u64_lo(y); + return x + y + 2 * u64_build(mul_hi(xlo, ylo), xlo * ylo); +} + +void g(struct block_th *block) +{ + ulong a, b, c, d; + a = block->a; + b = block->b; + c = block->c; + d = block->d; + + a = f(a, b); + d = rotr64(d ^ a, 32); + c = f(c, d); + b = rotr64(b ^ c, 24); + a = f(a, b); + d = rotr64(d ^ a, 16); + c = f(c, d); + b = rotr64(b ^ c, 63); + + block->a = a; + block->b = b; + block->c = c; + block->d = d; +} + +uint apply_shuffle_shift1(uint thread, uint idx) +{ + return (thread & 0x1c) | ((thread + idx) & 0x3); +} + +uint apply_shuffle_unshift1(uint thread, uint idx) +{ + idx = (QWORDS_PER_THREAD - idx) % QWORDS_PER_THREAD; + + return apply_shuffle_shift1(thread, idx); +} + +uint apply_shuffle_shift2(uint thread, uint idx) +{ + uint lo = (thread & 0x1) | ((thread & 0x10) >> 3); + lo = (lo + idx) & 0x3; + return ((lo & 0x2) << 3) | (thread & 0xe) | (lo & 0x1); +} + +uint apply_shuffle_unshift2(uint thread, uint idx) +{ + idx = (QWORDS_PER_THREAD - idx) % QWORDS_PER_THREAD; + + return apply_shuffle_shift2(thread, idx); +} + +void shuffle_shift1(struct block_th *block, uint thread, + __local struct u64_shuffle_buf *buf) +{ + for (uint i = 0; i < QWORDS_PER_THREAD; i++) + { + uint src_thr = apply_shuffle_shift1(thread, i); + + ulong v = block_th_get(block, i); + v = u64_shuffle(v, src_thr, thread, buf); + block_th_set(block, i, v); + } +} + +void shuffle_unshift1(struct block_th *block, uint thread, + __local struct u64_shuffle_buf *buf) +{ + for (uint i = 0; i < QWORDS_PER_THREAD; i++) + { + uint src_thr = apply_shuffle_unshift1(thread, i); + + ulong v = block_th_get(block, i); + v = u64_shuffle(v, src_thr, thread, buf); + block_th_set(block, i, v); + } +} + +void shuffle_shift2(struct block_th *block, uint thread, + __local struct u64_shuffle_buf *buf) +{ + for (uint i = 0; i < QWORDS_PER_THREAD; i++) + { + uint src_thr = apply_shuffle_shift2(thread, i); + + ulong v = block_th_get(block, i); + v = u64_shuffle(v, src_thr, thread, buf); + block_th_set(block, i, v); + } +} + +void shuffle_unshift2(struct block_th *block, uint thread, + __local struct u64_shuffle_buf *buf) +{ + for (uint i = 0; i < QWORDS_PER_THREAD; i++) + { + uint src_thr = apply_shuffle_unshift2(thread, i); + + ulong v = block_th_get(block, i); + v = u64_shuffle(v, src_thr, thread, buf); + block_th_set(block, i, v); + } +} + +void transpose(struct block_th *block, uint thread, + __local struct u64_shuffle_buf *buf) +{ + uint thread_group = (thread & 0x0C) >> 2; + for (uint i = 1; i < QWORDS_PER_THREAD; i++) + { + uint thr = (i << 2) ^ thread; + uint idx = thread_group ^ i; + + ulong v = block_th_get(block, idx); + v = u64_shuffle(v, thr, thread, buf); + block_th_set(block, idx, v); + } +} + +void shuffle_block(struct block_th *block, uint thread, + __local struct u64_shuffle_buf *buf) +{ + transpose(block, thread, buf); + + g(block); + + shuffle_shift1(block, thread, buf); + + g(block); + + shuffle_unshift1(block, thread, buf); + transpose(block, thread, buf); + + g(block); + + shuffle_shift2(block, thread, buf); + + g(block); + + shuffle_unshift2(block, thread, buf); +} + +void compute_ref_pos(uint lanes, uint segment_blocks, + uint pass, uint lane, uint slice, uint offset, + uint *ref_lane, uint *ref_index) +{ + uint lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + *ref_lane = *ref_lane % lanes; + + uint base; + if (pass != 0) + { + base = lane_blocks - segment_blocks; + } + else + { + if (slice == 0) + { + *ref_lane = lane; + } + base = slice * segment_blocks; + } + + uint ref_area_size = base + offset - 1; + if (*ref_lane != lane) + { + ref_area_size = min(ref_area_size, base); + } + + *ref_index = mul_hi(*ref_index, *ref_index); + *ref_index = ref_area_size - 1 - mul_hi(ref_area_size, *ref_index); + + if (pass != 0 && slice != ARGON2_SYNC_POINTS - 1) + { + *ref_index += (slice + 1) * segment_blocks; + if (*ref_index >= lane_blocks) + { + *ref_index -= lane_blocks; + } + } +} + +void argon2_core( + __global struct block_g *memory, __global struct block_g *mem_curr, + struct block_th *prev, struct block_th *tmp, + __local struct u64_shuffle_buf *shuffle_buf, uint lanes, + uint thread, uint pass, uint ref_index, uint ref_lane) +{ + __global struct block_g *mem_ref; + mem_ref = memory + ref_index * lanes + ref_lane; + +#if ARGON2_VERSION == ARGON2_VERSION_10 + load_block_xor(prev, mem_ref, thread); + move_block(tmp, prev); +#else + if (pass != 0) + { + load_block(tmp, mem_curr, thread); + load_block_xor(prev, mem_ref, thread); + xor_block(tmp, prev); + } + else + { + load_block_xor(prev, mem_ref, thread); + move_block(tmp, prev); + } +#endif + + shuffle_block(prev, thread, shuffle_buf); + + xor_block(prev, tmp); + + store_block(mem_curr, prev, thread); +} + +void next_addresses(struct block_th *addr, struct block_th *tmp, + uint thread_input, uint thread, + __local struct u64_shuffle_buf *buf) +{ + addr->a = u64_build(0, thread_input); + addr->b = 0; + addr->c = 0; + addr->d = 0; + + shuffle_block(addr, thread, buf); + + addr->a ^= u64_build(0, thread_input); + move_block(tmp, addr); + + shuffle_block(addr, thread, buf); + + xor_block(addr, tmp); +} + +#if ARGON2_TYPE == ARGON2_I || ARGON2_TYPE == ARGON2_ID +struct ref +{ + uint ref_lane; + uint ref_index; +}; + +/* + * Refs hierarchy: + * lanes -> passes -> slices -> blocks + */ +__kernel void argon2_precompute_kernel( + __local struct u64_shuffle_buf *shuffle_bufs, __global struct ref *refs, + uint passes, uint lanes, uint segment_blocks) +{ + uint block_id = get_global_id(0) / THREADS_PER_LANE; + uint warp = get_local_id(0) / THREADS_PER_LANE; + uint thread = get_local_id(0) % THREADS_PER_LANE; + + __local struct u64_shuffle_buf *shuffle_buf = &shuffle_bufs[warp]; + + uint segment_addr_blocks = (segment_blocks + ARGON2_QWORDS_IN_BLOCK - 1) / ARGON2_QWORDS_IN_BLOCK; + uint block = block_id % segment_addr_blocks; + uint segment = block_id / segment_addr_blocks; + + uint slice, pass, lane; +#if ARGON2_TYPE == ARGON2_ID + slice = segment % (ARGON2_SYNC_POINTS / 2); + lane = segment / (ARGON2_SYNC_POINTS / 2); + pass = 0; +#else + uint pass_id; + + slice = segment % ARGON2_SYNC_POINTS; + pass_id = segment / ARGON2_SYNC_POINTS; + + pass = pass_id % passes; + lane = pass_id / passes; +#endif + + struct block_th addr, tmp; + + uint thread_input; + switch (thread) + { + case 0: + thread_input = pass; + break; + case 1: + thread_input = lane; + break; + case 2: + thread_input = slice; + break; + case 3: + thread_input = lanes * segment_blocks * ARGON2_SYNC_POINTS; + break; + case 4: + thread_input = passes; + break; + case 5: + thread_input = ARGON2_TYPE; + break; + case 6: + thread_input = block + 1; + break; + default: + thread_input = 0; + break; + } + + next_addresses(&addr, &tmp, thread_input, thread, shuffle_buf); + + refs += segment * segment_blocks; + + for (uint i = 0; i < QWORDS_PER_THREAD; i++) + { + uint pos = i * THREADS_PER_LANE + thread; + uint offset = block * ARGON2_QWORDS_IN_BLOCK + pos; + if (offset < segment_blocks) + { + ulong v = block_th_get(&addr, i); + uint ref_index = u64_lo(v); + uint ref_lane = u64_hi(v); + + compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, + &ref_lane, &ref_index); + + refs[offset].ref_index = ref_index; + refs[offset].ref_lane = ref_lane; + } + } +} + +void argon2_step_precompute( + __global struct block_g *memory, __global struct block_g *mem_curr, + struct block_th *prev, struct block_th *tmp, + __local struct u64_shuffle_buf *shuffle_buf, + __global const struct ref **refs, + uint lanes, uint segment_blocks, uint thread, + uint lane, uint pass, uint slice, uint offset) +{ + uint ref_index, ref_lane; + bool data_independent; +#if ARGON2_TYPE == ARGON2_I + data_independent = true; +#elif ARGON2_TYPE == ARGON2_ID + data_independent = pass == 0 && slice < ARGON2_SYNC_POINTS / 2; +#else + data_independent = false; +#endif + if (data_independent) + { + ref_index = (*refs)->ref_index; + ref_lane = (*refs)->ref_lane; + (*refs)++; + } + else + { + ulong v = u64_shuffle(prev->a, 0, thread, shuffle_buf); + ref_index = u64_lo(v); + ref_lane = u64_hi(v); + + compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, + &ref_lane, &ref_index); + } + + argon2_core(memory, mem_curr, prev, tmp, shuffle_buf, lanes, thread, pass, + ref_index, ref_lane); +} + +__kernel void argon2_kernel_segment_precompute( + __local struct u64_shuffle_buf *shuffle_bufs, + __global struct block_g *memory, __global const struct ref *refs, + uint passes, uint lanes, uint segment_blocks, + uint pass, uint slice) +{ + uint job_id = get_global_id(1); + uint lane = get_global_id(0) / THREADS_PER_LANE; + uint warp = get_local_id(0) / THREADS_PER_LANE; + uint thread = get_local_id(0) % THREADS_PER_LANE; + + __local struct u64_shuffle_buf *shuffle_buf = &shuffle_bufs[warp]; + + uint lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + /* select job's memory region: */ + memory += (size_t)job_id * lanes * lane_blocks; + + struct block_th prev, tmp; + + __global struct block_g *mem_segment = + memory + slice * segment_blocks * lanes + lane; + __global struct block_g *mem_prev, *mem_curr; + uint start_offset = 0; + if (pass == 0) + { + if (slice == 0) + { + mem_prev = mem_segment + 1 * lanes; + mem_curr = mem_segment + 2 * lanes; + start_offset = 2; + } + else + { + mem_prev = mem_segment - lanes; + mem_curr = mem_segment; + } + } + else + { + mem_prev = mem_segment + (slice == 0 ? lane_blocks * lanes : 0) - lanes; + mem_curr = mem_segment; + } + + load_block(&prev, mem_prev, thread); + +#if ARGON2_TYPE == ARGON2_ID + if (pass == 0 && slice < ARGON2_SYNC_POINTS / 2) + { + refs += lane * (lane_blocks / 2) + slice * segment_blocks; + refs += start_offset; + } +#else + refs += (lane * passes + pass) * lane_blocks + slice * segment_blocks; + refs += start_offset; +#endif + + for (uint offset = start_offset; offset < segment_blocks; ++offset) + { + argon2_step_precompute( + memory, mem_curr, &prev, &tmp, shuffle_buf, &refs, lanes, + segment_blocks, thread, lane, pass, slice, offset); + + mem_curr += lanes; + } +} + +__kernel void argon2_kernel_oneshot_precompute( + __local struct u64_shuffle_buf *shuffle_bufs, + __global struct block_g *memory, __global const struct ref *refs, + uint passes, uint lanes, uint segment_blocks) +{ + uint job_id = get_global_id(1); + uint lane = get_global_id(0) / THREADS_PER_LANE; + uint warp = get_local_id(0) / THREADS_PER_LANE; + uint thread = get_local_id(0) % THREADS_PER_LANE; + + __local struct u64_shuffle_buf *shuffle_buf = &shuffle_bufs[warp]; + + uint lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + /* select job's memory region: */ + memory += (size_t)job_id * lanes * lane_blocks; + + struct block_th prev, tmp; + + __global struct block_g *mem_lane = memory + lane; + __global struct block_g *mem_prev = mem_lane + 1 * lanes; + __global struct block_g *mem_curr = mem_lane + 2 * lanes; + + load_block(&prev, mem_prev, thread); + +#if ARGON2_TYPE == ARGON2_ID + refs += lane * (lane_blocks / 2) + 2; +#else + refs += lane * passes * lane_blocks + 2; +#endif + + uint skip = 2; + for (uint pass = 0; pass < passes; ++pass) + { + for (uint slice = 0; slice < ARGON2_SYNC_POINTS; ++slice) + { + for (uint offset = 0; offset < segment_blocks; ++offset) + { + if (skip > 0) + { + --skip; + continue; + } + + argon2_step_precompute( + memory, mem_curr, &prev, &tmp, shuffle_buf, &refs, + lanes, segment_blocks, thread, + lane, pass, slice, offset); + + mem_curr += lanes; + } + + barrier(CLK_LOCAL_MEM_FENCE); + } + + mem_curr = mem_lane; + } +} +#endif /* ARGON2_TYPE == ARGON2_I || ARGON2_TYPE == ARGON2_ID */ + +void argon2_step( + __global struct block_g *memory, __global struct block_g *mem_curr, + struct block_th *prev, struct block_th *tmp, struct block_th *addr, + __local struct u64_shuffle_buf *shuffle_buf, + uint lanes, uint segment_blocks, uint thread, uint *thread_input, + uint lane, uint pass, uint slice, uint offset) +{ + uint ref_index, ref_lane; + bool data_independent; +#if ARGON2_TYPE == ARGON2_I + data_independent = true; +#elif ARGON2_TYPE == ARGON2_ID + data_independent = pass == 0 && slice < ARGON2_SYNC_POINTS / 2; +#else + data_independent = false; +#endif + if (data_independent) + { + uint addr_index = offset % ARGON2_QWORDS_IN_BLOCK; + if (addr_index == 0) + { + if (thread == 6) + { + ++*thread_input; + } + next_addresses(addr, tmp, *thread_input, thread, shuffle_buf); + } + + uint thr = addr_index % THREADS_PER_LANE; + uint idx = addr_index / THREADS_PER_LANE; + + ulong v = block_th_get(addr, idx); + v = u64_shuffle(v, thr, thread, shuffle_buf); + ref_index = u64_lo(v); + ref_lane = u64_hi(v); + } + else + { + ulong v = u64_shuffle(prev->a, 0, thread, shuffle_buf); + ref_index = u64_lo(v); + ref_lane = u64_hi(v); + } + + compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, + &ref_lane, &ref_index); + + argon2_core(memory, mem_curr, prev, tmp, shuffle_buf, lanes, thread, pass, + ref_index, ref_lane); +} + +__kernel void argon2_kernel_segment( + __local struct u64_shuffle_buf *shuffle_bufs, + __global struct block_g *memory, uint passes, uint lanes, + uint segment_blocks, uint pass, uint slice) +{ + uint job_id = get_global_id(1); + uint lane = get_global_id(0) / THREADS_PER_LANE; + uint warp = get_local_id(0) / THREADS_PER_LANE; + uint thread = get_local_id(0) % THREADS_PER_LANE; + + __local struct u64_shuffle_buf *shuffle_buf = &shuffle_bufs[warp]; + + uint lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + /* select job's memory region: */ + memory += (size_t)job_id * lanes * lane_blocks; + + struct block_th prev, addr, tmp; + uint thread_input; + +#if ARGON2_TYPE == ARGON2_I || ARGON2_TYPE == ARGON2_ID + switch (thread) + { + case 0: + thread_input = pass; + break; + case 1: + thread_input = lane; + break; + case 2: + thread_input = slice; + break; + case 3: + thread_input = lanes * lane_blocks; + break; + case 4: + thread_input = passes; + break; + case 5: + thread_input = ARGON2_TYPE; + break; + default: + thread_input = 0; + break; + } + + if (pass == 0 && slice == 0 && segment_blocks > 2) + { + if (thread == 6) + { + ++thread_input; + } + next_addresses(&addr, &tmp, thread_input, thread, shuffle_buf); + } +#endif + + __global struct block_g *mem_segment = + memory + slice * segment_blocks * lanes + lane; + __global struct block_g *mem_prev, *mem_curr; + uint start_offset = 0; + if (pass == 0) + { + if (slice == 0) + { + mem_prev = mem_segment + 1 * lanes; + mem_curr = mem_segment + 2 * lanes; + start_offset = 2; + } + else + { + mem_prev = mem_segment - lanes; + mem_curr = mem_segment; + } + } + else + { + mem_prev = mem_segment + (slice == 0 ? lane_blocks * lanes : 0) - lanes; + mem_curr = mem_segment; + } + + load_block(&prev, mem_prev, thread); + + for (uint offset = start_offset; offset < segment_blocks; ++offset) + { + argon2_step(memory, mem_curr, &prev, &tmp, &addr, shuffle_buf, + lanes, segment_blocks, thread, &thread_input, + lane, pass, slice, offset); + + mem_curr += lanes; + } +} + +__kernel void argon2_kernel_oneshot( + __local struct u64_shuffle_buf *shuffle_bufs, + __global struct block_g *memory, uint passes, uint lanes, + uint segment_blocks) +{ + uint job_id = get_global_id(1); + uint lane = get_global_id(0) / THREADS_PER_LANE; + uint warp = get_local_id(0) / THREADS_PER_LANE; + uint thread = get_local_id(0) % THREADS_PER_LANE; + + __local struct u64_shuffle_buf *shuffle_buf = &shuffle_bufs[warp]; + + uint lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; + + /* select job's memory region: */ + memory += (size_t)job_id * lanes * lane_blocks; + + struct block_th prev, addr, tmp; + uint thread_input; + +#if ARGON2_TYPE == ARGON2_I || ARGON2_TYPE == ARGON2_ID + switch (thread) + { + case 1: + thread_input = lane; + break; + case 3: + thread_input = lanes * lane_blocks; + break; + case 4: + thread_input = passes; + break; + case 5: + thread_input = ARGON2_TYPE; + break; + default: + thread_input = 0; + break; + } + + if (segment_blocks > 2) + { + if (thread == 6) + { + ++thread_input; + } + next_addresses(&addr, &tmp, thread_input, thread, shuffle_buf); + } +#endif + + __global struct block_g *mem_lane = memory + lane; + __global struct block_g *mem_prev = mem_lane + 1 * lanes; + __global struct block_g *mem_curr = mem_lane + 2 * lanes; + + load_block(&prev, mem_prev, thread); + + uint skip = 2; + for (uint pass = 0; pass < passes; ++pass) + { + for (uint slice = 0; slice < ARGON2_SYNC_POINTS; ++slice) + { + for (uint offset = 0; offset < segment_blocks; ++offset) + { + if (skip > 0) + { + --skip; + continue; + } + + argon2_step(memory, mem_curr, &prev, &tmp, &addr, shuffle_buf, + lanes, segment_blocks, thread, &thread_input, + lane, pass, slice, offset); + + mem_curr += lanes; + } + + barrier(CLK_LOCAL_MEM_FENCE); + +#if ARGON2_TYPE == ARGON2_I || ARGON2_TYPE == ARGON2_ID + if (thread == 2) + { + ++thread_input; + } + if (thread == 6) + { + thread_input = 0; + } +#endif + } +#if ARGON2_TYPE == ARGON2_I + if (thread == 0) + { + ++thread_input; + } + if (thread == 2) + { + thread_input = 0; + } +#endif + mem_curr = mem_lane; + } +} diff --git a/contrib/argon2-gpu/src/argon2-opencl/processing-unit.cpp b/contrib/argon2-gpu/src/argon2-opencl/processing-unit.cpp new file mode 100644 index 0000000000..0eba814cd1 --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-opencl/processing-unit.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-opencl/processing-unit.h" + +#include +#ifndef NDEBUG +#include +#endif + +namespace argon2gpu +{ +namespace opencl +{ + +static bool isPowerOfTwo(std::uint32_t x) +{ + return (x & (x - 1)) == 0; +} + +ProcessingUnit::ProcessingUnit( + const ProgramContext *programContext, const Argon2Params *params, + const Device *device, std::size_t batchSize, + bool bySegment, bool precomputeRefs) + : programContext(programContext), params(params), device(device), + runner(programContext, params, device, batchSize, bySegment, + precomputeRefs), + bestLanesPerBlock(runner.getMinLanesPerBlock()), + bestJobsPerBlock(runner.getMinJobsPerBlock()) +{ + /* pre-fill first blocks with pseudo-random data: */ + for (std::size_t i = 0; i < batchSize; i++) + { + setInputAndSalt(i, NULL, 0); + } + + if (runner.getMaxLanesPerBlock() > runner.getMinLanesPerBlock() && isPowerOfTwo(runner.getMaxLanesPerBlock())) + { +#ifndef NDEBUG + std::cerr << "[INFO] Tuning lanes per block..." << std::endl; +#endif + + float bestTime = std::numeric_limits::infinity(); + for (std::uint32_t lpb = 1; lpb <= runner.getMaxLanesPerBlock(); + lpb *= 2) + { + float time; + try + { + runner.run(lpb, bestJobsPerBlock); + time = runner.finish(); + } + catch (cl::Error &ex) + { +#ifndef NDEBUG + std::cerr << "[WARN] OpenCL error on " << lpb + << " lanes per block: " << ex.what() << std::endl; +#endif + break; + } + +#ifndef NDEBUG + std::cerr << "[INFO] " << lpb << " lanes per block: " + << time << " ms" << std::endl; +#endif + + if (time < bestTime) + { + bestTime = time; + bestLanesPerBlock = lpb; + } + } +#ifndef NDEBUG + std::cerr << "[INFO] Picked " << bestLanesPerBlock + << " lanes per block." << std::endl; +#endif + } + + /* Only tune jobs per block if we hit maximum lanes per block: */ + if (bestLanesPerBlock == runner.getMaxLanesPerBlock() && runner.getMaxJobsPerBlock() > runner.getMinJobsPerBlock() && isPowerOfTwo(runner.getMaxJobsPerBlock())) + { +#ifndef NDEBUG + std::cerr << "[INFO] Tuning jobs per block..." << std::endl; +#endif + + float bestTime = std::numeric_limits::infinity(); + for (std::uint32_t jpb = 1; jpb <= runner.getMaxJobsPerBlock(); + jpb *= 2) + { + float time; + try + { + runner.run(bestLanesPerBlock, jpb); + time = runner.finish(); + } + catch (cl::Error &ex) + { +#ifndef NDEBUG + std::cerr << "[WARN] OpenCL error on " << jpb + << " jobs per block: " << ex.what() << std::endl; +#endif + break; + } + +#ifndef NDEBUG + std::cerr << "[INFO] " << jpb << " jobs per block: " + << time << " ms" << std::endl; +#endif + + if (time < bestTime) + { + bestTime = time; + bestJobsPerBlock = jpb; + } + } +#ifndef NDEBUG + std::cerr << "[INFO] Picked " << bestJobsPerBlock + << " jobs per block." << std::endl; +#endif + } +} + +void ProcessingUnit::setInputAndSalt(std::size_t index, const void *pw, + std::size_t pwSize) +{ + void *memory = runner.mapInputMemory(index); + params->fillFirstBlocks(memory, pw, pwSize, + programContext->getArgon2Type(), + programContext->getArgon2Version()); + runner.unmapInputMemory(memory); +} + +void ProcessingUnit::getHash(std::size_t index, void *hash) +{ + void *memory = runner.mapOutputMemory(index); + params->finalize(hash, memory); + runner.unmapOutputMemory(memory); +} + +void ProcessingUnit::beginProcessing() +{ + runner.run(bestLanesPerBlock, bestJobsPerBlock); +} + +void ProcessingUnit::endProcessing() +{ + runner.finish(); +} + +} // namespace opencl +} // namespace argon2gpu diff --git a/contrib/argon2-gpu/src/argon2-opencl/program-context.cpp b/contrib/argon2-gpu/src/argon2-opencl/program-context.cpp new file mode 100644 index 0000000000..4ae414ebfc --- /dev/null +++ b/contrib/argon2-gpu/src/argon2-opencl/program-context.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "argon2-opencl/program-context.h" +#include "argon2-opencl/kernel-loader.h" + +namespace argon2gpu +{ +namespace opencl +{ + +ProgramContext::ProgramContext( + const GlobalContext *globalContext, + const std::vector &devices, + Type type, Version version) + : globalContext(globalContext), devices(), type(type), version(version) +{ + this->devices.reserve(devices.size()); + for (auto &device : devices) + { + this->devices.push_back(device.getCLDevice()); + } + context = cl::Context(this->devices); + + program = KernelLoader::loadArgon2Program( + // FIXME path: + context, "./src/argon2-opencl", type, version); +} + +} // namespace opencl +} // namespace argon2gpu diff --git a/src/Makefile.am b/src/Makefile.am index 8c74037eb2..fbed49a237 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ DIST_SUBDIRS = secp256k1 univalue -AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) +AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) -L/usr/lib/x86_64-linux-gnu -L/usr/local/cuda-9.2/lib64 AM_CXXFLAGS = $(HARDENED_CXXFLAGS) AM_CPPFLAGS = $(HARDENED_CPPFLAGS) EXTRA_LIBRARIES = @@ -8,6 +8,7 @@ EXTRA_LIBRARIES = DYNAMIC_CONFIG_INCLUDES=-I$(builddir)/config DYNAMIC_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) +DYNAMIC_INCLUDES += -I$(top_srcdir)/contrib/argon2-gpu/include -I/usr/local/cuda-9.2/include DYNAMIC_INCLUDES += -I$(srcdir)/secp256k1/include DYNAMIC_INCLUDES += -I$(srcdir)/univalue/include @@ -21,6 +22,12 @@ LIBDYNAMICQT=qt/libdynamicqt.a LIBSECP256K1=secp256k1/libsecp256k1.la LIBUNIVALUE=univalue/libunivalue.la +argon2GPULIBS = \ + -largon2 \ + -largon2-gpu \ + -largon2-opencl \ + -largon2-cuda + $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) @@ -126,6 +133,7 @@ DYNAMIC_CORE_H = \ memusage.h \ merkleblock.h \ messagesigner.h \ + miner-gpu.h \ miner.h \ net.h \ net_processing.h \ @@ -411,7 +419,7 @@ nodist_libdynamic_util_a_SOURCES = $(srcdir)/obj/build.h dynamicd_SOURCES = dynamicd.cpp dynamicd_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) dynamicd_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -dynamicd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +dynamicd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -Wl,-rpath=/usr/local/cuda-9.2/lib64 if TARGET_WINDOWS dynamicd_SOURCES += dynamicd-res.rc @@ -436,6 +444,10 @@ if ENABLE_WALLET dynamicd_LDADD += libdynamic_wallet.a endif +if ENABLE_GPU +dynamicd_LDADD += -L/usr/local/cuda-9.2/lib64 -L/usr/lib/x86_64-linux-gnu -lOpenCL $(argon2GPULIBS) +endif + dynamicd_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) # dynamic-cli binary # diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 9b7337fecd..7cf9b99dd7 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -369,6 +369,9 @@ qt_dynamic_qt_LDADD = qt/libdynamicqt.a $(LIBDYNAMIC_SERVER) if ENABLE_WALLET qt_dynamic_qt_LDADD += $(LIBDYNAMIC_WALLET) endif +if ENABLE_GPU +qt_dynamic_qt_LDADD += -L/usr/local/cuda-9.2/lib64 -L/usr/lib/x86_64-linux-gnu -lOpenCL $(argon2GPULIBS) +endif if ENABLE_ZMQ qt_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif diff --git a/src/init.cpp b/src/init.cpp index 03c71ec6b5..e17978b3a3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -501,16 +501,25 @@ std::string HelpMessage(HelpMessageMode mode) std::string debugCategories1 = "addrman, alert, bench, coindb, db, http, leveldb, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq, Dynamic "; // Don't translate these and qt below std::string debugCategories2 = "gobject, instantsend, keepass, dynode, dnpayments, dnsync, privatesend, spork"; // Don't translate these and qt below std::string debugCategories3 = ""; // Don't translate these and qt below - if (mode == HMM_DYNAMIC_QT) + + if (mode == HMM_DYNAMIC_QT) + { debugCategories3 = ", qt"; // Don't translate this strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional). If is not supplied or if = 1, output all debugging information. can be: %u (or specifically: %u)%u."), 0, debugCategories1, debugCategories2, debugCategories3)); + } if (showDebug) + { strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0"); + strUsage += HelpMessageOpt("-autotune", _("Autotune threads per device (default: false)")); strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), DEFAULT_GENERATE)); - strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS)); + strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS_CPU)); +#if ENABLE_GPU + strUsage += HelpMessageOpt("-genproclimit-gpu=", strprintf(_("Set the number of threads per GPU for coin generation if enabled (default: %d)"), DEFAULT_GENERATE_THREADS_GPU)); +#endif strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)")); strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), DEFAULT_LOGIPS)); strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), DEFAULT_LOGTIMESTAMPS)); + } if (showDebug) { strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS)); @@ -1823,7 +1832,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(strNodeError); // Generate coins in the background - GenerateDynamics(GetBoolArg("-gen", DEFAULT_GENERATE), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), chainparams, connman); + if (GetBoolArg("-gen", DEFAULT_GENERATE)) { + GenerateDynamics(GetArg("-genproclimit", DEFAULT_GENERATE_THREADS_CPU), GetArg("-genproclimit-gpu", DEFAULT_GENERATE_THREADS_GPU), chainparams, connman, GetBoolArg("-autotune", false)); + } // ********************************************************* Step 13: finished diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc index ec39e92195..28ecf5f05b 100755 --- a/src/leveldb/port/port_posix.cc +++ b/src/leveldb/port/port_posix.cc @@ -53,15 +53,5 @@ void InitOnce(OnceType* once, void (*initializer)()) { PthreadCall("once", pthread_once(once, initializer)); } -bool HasAcceleratedCRC32C() { -#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) - unsigned int eax, ebx, ecx, edx; - __get_cpuid(1, &eax, &ebx, &ecx, &edx); - return (ecx & (1 << 20)) != 0; -#else - return false; -#endif -} - } // namespace port } // namespace leveldb diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h index d85fa5d63f..7e8213b22e 100755 --- a/src/leveldb/port/port_posix.h +++ b/src/leveldb/port/port_posix.h @@ -152,7 +152,6 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { return false; } -bool HasAcceleratedCRC32C(); uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); } // namespace port diff --git a/src/leveldb/util/crc32c.cc b/src/leveldb/util/crc32c.cc index b3f40eeeed..edd61cfd6f 100755 --- a/src/leveldb/util/crc32c.cc +++ b/src/leveldb/util/crc32c.cc @@ -288,10 +288,6 @@ static inline uint32_t LE_LOAD32(const uint8_t *p) { // Determine if the CPU running this program can accelerate the CRC32C // calculation. static bool CanAccelerateCRC32C() { - if (!port::HasAcceleratedCRC32C()) - return false; - - // Double-check that the accelerated implementation functions correctly. // port::AcceleretedCRC32C returns zero when unable to accelerate. static const char kTestCRCBuffer[] = "TestCRCBuffer"; static const char kBufSize = sizeof(kTestCRCBuffer) - 1; diff --git a/src/miner-gpu.h b/src/miner-gpu.h new file mode 100644 index 0000000000..9b752508ea --- /dev/null +++ b/src/miner-gpu.h @@ -0,0 +1,72 @@ +// Copyright (c) 2018 Łukassz Kurowski + +#ifndef DYNAMIC_ARGON2_GPU +#define DYNAMIC_ARGON2_GPU + +#ifdef ENABLE_GPU +#define HAVE_CUDA 1 +#define ARGON2_GPU_CUDA cuda +#define ARGON2_GPU_OPENCL opencl + +#define ARGON2_GPU ARGON2_GPU_CUDA + +#include +#include "argon2-cuda/cuda-exception.h" +#include "argon2-cuda/processing-unit.h" +#include "argon2-gpu/common.h" +#include "argon2-opencl/processing-unit.h" + +using Argon2GPUParams = argon2gpu::Argon2Params; + +#if ARGON2_GPU == ARGON2_GPU_CUDA +using Argon2GPU = argon2gpu::cuda::ProcessingUnit; +using Argon2GPUDevice = argon2gpu::cuda::Device; +using Argon2GPUContext = argon2gpu::cuda::GlobalContext; +using Argon2GPUProgramContext = argon2gpu::cuda::ProgramContext; +#elif ARGON2_GPU == ARGON2_GPU_OPENCL +using Argon2GPU = argon2gpu::opencl::ProcessingUnit; +using Argon2GPUDevice = argon2gpu::opencl::Device; +using Argon2GPUContext = argon2gpu::opencl::GlobalContext; +using Argon2GPUProgramContext = argon2gpu::opencl::ProgramContext; +#endif + +static std::size_t GetGPUDeviceCount() +{ + static Argon2GPUContext global; + return global.getAllDevices().size(); +} + +static Argon2GPU GetGPUProcessingUnit(const std::size_t deviceIndex) +{ + Argon2GPUContext global; + auto& devices = global.getAllDevices(); + auto& device = devices[deviceIndex]; + Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); + Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); + Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); + return processingUnit; +} + +template +inline uint256 GetBlockHashGPU(const CBlockHeader* block, const Pu& pu) +{ + static unsigned char pblank[1]; + const auto pBegin = BEGIN(block->nVersion); + const auto pEnd = END(block->nNonce); + const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); + + uint256 hashResult; + pu->setInputAndSalt(0, (const void*)input, INPUT_BYTES); + pu->beginProcessing(); + pu->endProcessing(); + pu->getHash(0, (uint8_t*)&hashResult); + return hashResult; +} +#else +static std::size_t GetGPUDeviceCount() +{ + return 0; +} +#endif // ENABLE_GPU + +#endif // DYNAMIC_ARGON2_GPU diff --git a/src/miner.cpp b/src/miner.cpp index f4d0165b03..47704ac1ce 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -40,6 +40,8 @@ #include #include +#include "miner-gpu.h" + ////////////////////////////////////////////////////////////////////////////// // // DynamicMiner @@ -408,9 +410,29 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned // Internal miner // // -double dHashesPerSec = 0.0; +double dCPUHashesPerSec = 0.0; +double dGPUHashesPerSec = 0.0; int64_t nHPSTimerStart = 0; +int64_t GetHashRate() +{ + return GetCPUHashRate() + GetGPUHashRate(); +} + +int64_t GetCPUHashRate() +{ + if (GetTimeMillis() - nHPSTimerStart > 8000) + return (int64_t)0; + return (int64_t)(dCPUHashesPerSec); +} + +int64_t GetGPUHashRate() +{ + if (GetTimeMillis() - nHPSTimerStart > 8000) + return (int64_t)0; + return (int64_t)(dGPUHashesPerSec); +} + // ScanHash scans nonces looking for a hash with at least some zero bits. // The nonce is usually preserved between calls, but periodically or if the // nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at @@ -466,18 +488,45 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar return true; } -// ***TODO*** that part changed in bitcoin, we are using a mix with old one here for now -void static DynamicMiner(const CChainParams& chainparams, CConnman& connman) +static void WaitForNetworkInit(const CChainParams& chainparams, CConnman& connman) { - LogPrintf("DynamicMiner -- started\n"); + if (chainparams.MiningRequiresPeers()) { + // Busy-wait for the network to come online so we don't waste time mining + // on an obsolete chain. In regtest mode we expect to fly solo. + while (true) { + bool fvNodesEmpty = connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0; + if (!fvNodesEmpty && !IsInitialBlockDownload()) { + break; + } + MilliSleep(1000); + } + } +} + +// TODO: that part changed in bitcoin, we are using a mix with old one here for now +static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex, bool fGPU) +{ + std::string dev = fGPU ? "GPU" : "CPU"; + LogPrintf("DynamicMiner -- started #%u@%s\n", nDeviceIndex, dev); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("dynamic-miner"); + double* dHashesPerSec = fGPU ? &dGPUHashesPerSec : &dCPUHashesPerSec; unsigned int nExtraNonce = 0; boost::shared_ptr coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); - + +#ifdef ENABLE_GPU + // Argon2GPU processingUnit = GetGPUProcessingUnit(nDeviceIndex); + Argon2GPUContext global; + auto& devices = global.getAllDevices(); + auto& device = devices[nDeviceIndex]; + Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); + Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); + Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); +#endif // ENABLE_GPU + try { // Throw an error if no script was provided. This can happen // due to some internal error but also if the keypool is empty. @@ -486,17 +535,8 @@ void static DynamicMiner(const CChainParams& chainparams, CConnman& connman) throw std::runtime_error("No coinbase script available (mining requires a wallet)"); while (true) { - if (chainparams.MiningRequiresPeers()) { - // Busy-wait for the network to come online so we don't waste time mining - // on an obsolete chain. In regtest mode we expect to fly solo. - do { - bool fvNodesEmpty = connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0; - if (!fvNodesEmpty && !IsInitialBlockDownload() && dynodeSync.IsSynced() && dynodeSync.IsBlockchainSynced()) - break; - MilliSleep(1000); - } while (true); - } - + // Wait for blocks if required + WaitForNetworkInit(chainparams, connman); // // Create new block @@ -510,13 +550,13 @@ void static DynamicMiner(const CChainParams& chainparams, CConnman& connman) if (!pblocktemplate.get()) { - LogPrintf("DynamicMiner -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); + LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", dev); return; } CBlock *pblock = &pblocktemplate->block; IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - LogPrintf("DynamicMiner -- Running miner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), + LogPrintf("DynamicMiner%s -- Running miner with %u transactions in block (%u bytes)\n", dev, pblock->vtx.size(), ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); // @@ -530,10 +570,17 @@ void static DynamicMiner(const CChainParams& chainparams, CConnman& connman) unsigned int nHashesDone = 0; uint256 hash; - while (true) - { + while (true) { +#ifdef ENABLE_GPU + if (fGPU) { + hash = GetBlockHashGPU(pblock, &processingUnit); + } else { + hash = pblock->GetHash(); + } +#else hash = pblock->GetHash(); - +#endif // ENABLE_GPU + if (UintToArith256(hash) <= hashTarget) { // Found a solution @@ -541,7 +588,7 @@ void static DynamicMiner(const CChainParams& chainparams, CConnman& connman) //assert(hash == pblock->GetHash()); SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("DynamicMiner:\n proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); + LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", dev, hash.GetHex(), hashTarget.GetHex()); ProcessBlockFound(pblock, chainparams, &connman); SetThreadPriority(THREAD_PRIORITY_LOWEST); coinbaseScript->KeepScript(); @@ -576,13 +623,13 @@ void static DynamicMiner(const CChainParams& chainparams, CConnman& connman) LOCK(cs); if (GetTimeMillis() - nHPSTimerStart > 4000) { - dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); + *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); nHPSTimerStart = GetTimeMillis(); nHashCounter = 0; if (GetTime() - nLogTime > 30 * 60) { nLogTime = GetTime(); - LogPrintf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); + LogPrintf("hashmeter %6.0f khash/s\n", *dHashesPerSec / 1000.0); } } } @@ -624,25 +671,155 @@ void static DynamicMiner(const CChainParams& chainparams, CConnman& connman) } } -void GenerateDynamics(bool fGenerate, int nThreads, const CChainParams& chainparams, CConnman& connman) +static boost::thread_group* GetCPUMinerThreads(bool fInit = true, bool fRestart = true) +{ + static boost::thread_group* minerThreadsCPU = NULL; + if (fRestart && minerThreadsCPU != NULL) { + minerThreadsCPU->interrupt_all(); + delete minerThreadsCPU; + minerThreadsCPU = NULL; + } + if (fInit && minerThreadsCPU == NULL) { + minerThreadsCPU = new boost::thread_group(); + } + return minerThreadsCPU; +} + +static boost::thread_group* GetGPUMinerThreads(bool fInit = true, bool fRestart = true) { - static boost::thread_group* minerThreads = NULL; + static boost::thread_group* minerThreadsGPU = NULL; + if (fRestart && minerThreadsGPU != NULL) { + minerThreadsGPU->interrupt_all(); + delete minerThreadsGPU; + minerThreadsGPU = NULL; + } + if (fInit && minerThreadsGPU == NULL) { + minerThreadsGPU = new boost::thread_group(); + } + return minerThreadsGPU; +} - if (nThreads < 0) - nThreads = GetNumCores(); // Uses std::thread::hardwareconcurrency to detect available cores - // Return the number of cores available on the current system. - // @note This does count virtual cores, such as those provided by HyperThreading. - if (minerThreads != NULL) - { - minerThreads->interrupt_all(); - delete minerThreads; - minerThreads = NULL; +static boost::thread_group* GetMinerThreads(bool fGPU = false, bool fInit = true, bool fRestart = true) +{ + if (fGPU) { + return GetGPUMinerThreads(fInit, fRestart); + } + return GetCPUMinerThreads(fInit, fRestart); +} + +void AutoTuneDeviceThreads(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex = -1, bool fGPU = false) +{ + // Threads + boost::thread* lastThread = NULL; + boost::thread_group* minerThreads = GetMinerThreads(fGPU); + + // Metrics + double nLastHashesPerSec = 0.0; + double* dHashesPerSec = fGPU ? &dGPUHashesPerSec : &dCPUHashesPerSec; + + // Device name + std::string dev = fGPU ? "GPU" : "CPU"; + + LogPrintf("Autotune hashmeter: %6.0f\n", *dHashesPerSec / 1000.0); + + // Start Dynamin miner threads on device + while (true) { + LogPrintf("Starting %s Miner thread #%u %6.0f khash/s\n", dev, minerThreads->size(), *dHashesPerSec / 1000.0); + std::size_t nThread = minerThreads->size(); + std::size_t device = nDeviceIndex == -1 ? nThread : nDeviceIndex; + lastThread = minerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), boost::cref(device), boost::cref(fGPU))); + MilliSleep(10000); + + if (*dHashesPerSec > nLastHashesPerSec) { + nLastHashesPerSec = *dHashesPerSec; + continue; + } + + LogPrintf("Removing %s Miner thread #%u %6.0f khash/s\n", dev, minerThreads->size(), *dHashesPerSec / 1000.0); + minerThreads->remove_thread(lastThread); + break; + } + + LogPrintf("Autotune %s finished with hashrate %6.0f\n khash/s", dev, *dHashesPerSec / 1000.0); +} + +void GenerateAutoTuneDevice(const CChainParams& chainparams, CConnman& connman, bool fGPU) +{ + if (!fGPU) { + AutoTuneDeviceThreads(chainparams, connman); + } else { + // Start GPU threads + for (std::size_t device = 0; device < GetGPUDeviceCount(); device++) { + AutoTuneDeviceThreads(chainparams, connman, device, true); + } + } +} + +void GenerateDynamicsAutoTune(const CChainParams& chainparams, CConnman& connman) +{ + // Wait for blocks if required + WaitForNetworkInit(chainparams, connman); + MilliSleep(30000); + + GenerateAutoTuneDevice(chainparams, connman, false); + GenerateAutoTuneDevice(chainparams, connman, true); +} + +void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman, bool fAutotune) +{ + if (fAutotune) { + return GenerateDynamicsAutoTune(chainparams, connman); } - if (nThreads == 0 || !fGenerate) + std::size_t devices = GetGPUDeviceCount(); +#ifdef ENABLE_GPU + LogPrintf("DynamicMiner -- GPU Devices: %u\n", devices); +#else + LogPrintf("DynamicMiner -- GPU no support\n"); +#endif + + if (nCPUThreads == 0 && (devices == 0 || nGPUThreads == 0)) { + LogPrintf("DynamicMiner -- disabled -- CPU Threads set to zero\n"); return; + } + + boost::thread_group* minerThreads = GetCPUMinerThreads(); + + if (nCPUThreads < 0) + nCPUThreads = GetNumCores(); + + // Start CPU threads + while (minerThreads->size() < nCPUThreads) { + std::size_t nThread = minerThreads->size(); + LogPrintf("Starting CPU Miner thread #%u\n", nThread); + minerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), nThread, false)); + } + + if (nGPUThreads < 0) + nGPUThreads = 1; + + // Start GPU threads + minerThreads = GetGPUMinerThreads(); + for (std::size_t device = 0; device < devices; device++) { + for (int i = 0; i < nGPUThreads; i++) { + LogPrintf("Starting GPU Miner thread %u on device %u\n", i, device); + minerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), device, true)); + } + } +} + +void ShutdownCPUMiners() +{ + GetCPUMinerThreads(false); +} - minerThreads = new boost::thread_group(); - for (int i = 0; i < nThreads; i++) - minerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman))); +void ShutdownGPUMiners() +{ + GetGPUMinerThreads(false); +} + +void ShutdownMiners() +{ + ShutdownCPUMiners(); + ShutdownGPUMiners(); } diff --git a/src/miner.h b/src/miner.h index 197093472e..d212015cc7 100644 --- a/src/miner.h +++ b/src/miner.h @@ -24,7 +24,9 @@ class CWallet; namespace Consensus { struct Params; }; static const bool DEFAULT_GENERATE = false; -static const int DEFAULT_GENERATE_THREADS = 1; +static const int DEFAULT_GENERATE_THREADS_CPU = -1; +// TODO(crackcom): Set to -1 after autotune tests +static const int DEFAULT_GENERATE_THREADS_GPU = 1; static const bool DEFAULT_PRINTPRIORITY = false; @@ -40,14 +42,27 @@ struct CBlockTemplate bool CheckWork(const CChainParams& chainparams, CBlock* pblock, CWallet& wallet, CReserveKey& reservekey, CConnman* connman); #endif //ENABLE_WALLET /** Run the miner threads */ -void GenerateDynamics(bool fGenerate, int nThreads, const CChainParams& chainparams, CConnman& connman); +void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman, bool fAutotune = false); +/** Shuts down all miner threads */ +void ShutdownMiners(); +/** Shuts down all CPU miner threads */ +void ShutdownCPUMiners(); +/** Shuts down all GPU miner threads */ +void ShutdownGPUMiners(); /** Generate a new block, without valid proof-of-work */ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce); int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); +/** Gets combined hash rate of GPU and CPU */ +int64_t GetHashRate(); +/** Gets hash rate of CPU */ +int64_t GetCPUHashRate(); +/** Gets hash rate of GPU */ +int64_t GetGPUHashRate(); -extern double dHashesPerSec; +extern double dCPUHashesPerSec; +extern double dGPUHashesPerSec; extern int64_t nHPSTimerStart; #endif // DYNAMIC_MINER_H diff --git a/src/qt/forms/miningpage.ui b/src/qt/forms/miningpage.ui index 808c5403b3..0e6c5a51aa 100644 --- a/src/qt/forms/miningpage.ui +++ b/src/qt/forms/miningpage.ui @@ -13,33 +13,74 @@ Form + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + - - - - - - - - - 4 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 250 - 0 - - - - QSlider::groove:horizontal { + + + #bgWidget { background: rgba(0,0,0,220); } + + + 0 + + + + true + + + + 0 + 0 + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + CPU + + + + + 0 + 0 + 631 + 102 + + + + + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + 4 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 250 + 0 + + + + QSlider::groove:horizontal { border: 1px solid #bbb; background: white; height: 10px; @@ -95,170 +136,251 @@ background: #eee; border: 1px solid #aaa; border-radius: 4px; } - - - Qt::Horizontal - - - - - - - - - Average spacing between your blocks: - - - - - - - Your hashrate (built-in miner): - - - - - - - Network hashrate: - - - - - - - Number of threads to use: - - - - - - - 0 - - - - - - - ? - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - Start mining - + + + Qt::Horizontal + + + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Average spacing between your blocks: + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Your hashrate (built-in miner): + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Network hashrate: + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Number of threads to use: + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + 0 + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + ? + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - - - Qt::Vertical - - - - 20 - 100 - - - - - - - - Show Hash Meter Graph + + + + 0 + 100 + 631 + 64 + + + + + + QPushButton { /* Global Button Style */ +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); +border:0; +border-radius:3px; +color:#ffffff; +font-size:12px; +font-weight:bold; +padding-left:25px; +padding-right:25px; +padding-top:5px; +padding-bottom:5px; +} + +QPushButton:hover { +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #BA77D4, stop: .1 #9F2DCC, stop: .95 #9F2DCC, stop: 1 #7400A1); +} + +QPushButton:focus { +border:none; +outline:none; +} + +QPushButton:pressed { +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); +border:1px solid #520072; +} + + + Start mining + + + + + + + Qt::Vertical + + + + 20 + 100 + + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Show Hash Meter Graph + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 0 - + + + + 0 + 174 + 631 + 154 + + + + + + + 0 + 0 + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + + + + + Qt::Vertical + + + + 10 + 200 + + + + + - - - - - Qt::Vertical - - - - 10 - 200 - - - - - - - - - - - - - 250 - 0 - + + + + 0 + 338 + 631 + 34 + - - QSlider::groove:horizontal { + + + + + + 250 + 0 + + + + QSlider::groove:horizontal { border: 1px solid #bbb; background: white; height: 10px; @@ -314,50 +436,511 @@ border-radius: 4px; border: 1px solid #aaa; border-radius: 4px; } + + + Qt::Horizontal + + + + + + + + + Qt::Vertical + + + + 10 + 20 + + + + + + + + + + + 75 + true + + + + 5 m + + + + + + + Clear + + + + + + layoutWidget + layoutWidget + layoutWidget + layoutWidget + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + GPU + + + + + 0 + 0 + 631 + 102 + - - Qt::Horizontal - + + + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + 4 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 250 + 0 + + + + QSlider::groove:horizontal { +border: 1px solid #bbb; +background: white; +height: 10px; +border-radius: 4px; +} + +QSlider::sub-page:horizontal { +background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #66e, stop: 1 #bbf); +background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1, + stop: 0 #bbf, stop: 1 #520072); +border: 1px solid #777; +height: 10px; +border-radius: 4px; +} + +QSlider::add-page:horizontal { +background: #fff; +border: 1px solid #777; +height: 10px; +border-radius: 4px; +} + +QSlider::handle:horizontal { +background: qlineargradient(x1:0, y1:0, x2:1, y2:1, + stop:0 #eee, stop:1 #520072); +border: 1px solid #777; +width: 13px; +margin-top: -2px; +margin-bottom: -2px; +border-radius: 4px; +} + +QSlider::handle:horizontal:hover { +background: qlineargradient(x1:0, y1:0, x2:1, y2:1, + stop:0 #fff, stop:1 #ddd); +border: 1px solid #444; +border-radius: 4px; +} + +QSlider::sub-page:horizontal:disabled { +background: #bbb; +border-color: #999; +} + +QSlider::add-page:horizontal:disabled { +background: #eee; +border-color: #999; +} + +QSlider::handle:horizontal:disabled { +background: #eee; +border: 1px solid #aaa; +border-radius: 4px; +} + + + Qt::Horizontal + + + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Average spacing between your blocks: + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Your hashrate (built-in miner): + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Network hashrate: + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Number of threads to use: + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + 0 + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + ? + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - - - - - Qt::Vertical - - - - 10 - 20 - - - - - - - - - - - 75 - true - + + + + 0 + 174 + 631 + 154 + - - 5 m + + + + + + 0 + 0 + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + + + + + Qt::Vertical + + + + 10 + 200 + + + + + + + + + + 0 + 338 + 631 + 34 + + + + + + + 250 + 0 + + + + QSlider::groove:horizontal { + border: 1px solid #bbb; + background: white; + height: 10px; + border-radius: 4px; + } + + QSlider::sub-page:horizontal { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #66e, stop: 1 #bbf); + background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1, + stop: 0 #bbf, stop: 1 #520072); + border: 1px solid #777; + height: 10px; + border-radius: 4px; + } + + QSlider::add-page:horizontal { + background: #fff; + border: 1px solid #777; + height: 10px; + border-radius: 4px; + } + + QSlider::handle:horizontal { + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, + stop:0 #eee, stop:1 #520072); + border: 1px solid #777; + width: 13px; + margin-top: -2px; + margin-bottom: -2px; + border-radius: 4px; + } + + QSlider::handle:horizontal:hover { + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, + stop:0 #fff, stop:1 #ddd); + border: 1px solid #444; + border-radius: 4px; + } + + QSlider::sub-page:horizontal:disabled { + background: #bbb; + border-color: #999; + } + + QSlider::add-page:horizontal:disabled { + background: #eee; + border-color: #999; + } + + QSlider::handle:horizontal:disabled { + background: #eee; + border: 1px solid #aaa; + border-radius: 4px; + } + + + Qt::Horizontal + + + + + + + + + Qt::Vertical + + + + 10 + 20 + + + + + + + + + + + 75 + true + + + + 5 m + + + + + + + Clear + + + + - - - - - Clear + + + + 0 + 100 + 631 + 64 + + + + + + QPushButton { /* Global Button Style */ +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); +border:0; +border-radius:3px; +color:#ffffff; +font-size:12px; +font-weight:bold; +padding-left:25px; +padding-right:25px; +padding-top:5px; +padding-bottom:5px; +} + +QPushButton:hover { +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #BA77D4, stop: .1 #9F2DCC, stop: .95 #9F2DCC, stop: 1 #7400A1); +} + +QPushButton:focus { +border:none; +outline:none; +} + +QPushButton:pressed { +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); +border:1px solid #520072; +} + + + Start mining + + + + + + + Qt::Vertical + + + + 20 + 100 + + + + + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + Show Hash Meter Graph + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - + + + + + + + + + diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 96453ff9ab..0ddd360f6e 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1092,20 +1092,12 @@ int MaxThreads() { int nThreads = boost::thread::hardware_concurrency(); int nUseThreads = GetArg("-genproclimit", -1); - if (nUseThreads < 0) + if (nUseThreads < 0) { nUseThreads = nThreads; - - return nUseThreads; -} - -int64_t GetHashRate() { - - if (GetTimeMillis() - nHPSTimerStart > 8000) - return (int64_t)0; - return (int64_t)dHashesPerSec; + } + return nUseThreads; } - QString FormatHashRate(qint64 n) { if (n == 0) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 899d0e1c60..238e66f37c 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -265,7 +265,6 @@ namespace GUIUtil // utility functions for mining UI int MaxThreads(); - int64_t GetHashRate(); QString FormatHashRate(qint64 n); int64_t GetNetworkHashPS(int lookup, int height); QString FormatTimeInterval(arith_uint256 time); diff --git a/src/qt/hashrategraphwidget.cpp b/src/qt/hashrategraphwidget.cpp index 5370e9efe9..e0a214f3fe 100644 --- a/src/qt/hashrategraphwidget.cpp +++ b/src/qt/hashrategraphwidget.cpp @@ -53,6 +53,18 @@ void HashRateGraphWidget::initGraph(QPainter& painter) } } +int64_t HashRateGraphWidget::getHashRate() +{ + switch (graphType) { + case GraphType::MINER_CPU_HASHRATE: + return GetCPUHashRate(); + case GraphType::MINER_GPU_HASHRATE: + return GetGPUHashRate(); + default: + return GetHashRate(); + } +} + void HashRateGraphWidget::drawHashRate(QPainter& painter) { QPainterPath path; @@ -105,7 +117,7 @@ void HashRateGraphWidget::updateHashRateGraph() { int64_t iCurrentHashRate = 0; if (graphType == MINER_HASHRATE) { - iCurrentHashRate = GUIUtil::GetHashRate(); + iCurrentHashRate = getHashRate(); } else if (graphType == NETWORK_HASHRATE) { iCurrentHashRate = GUIUtil::GetNetworkHashPS(120, -1); diff --git a/src/qt/hashrategraphwidget.h b/src/qt/hashrategraphwidget.h index 9d464946d3..3af7847d0f 100644 --- a/src/qt/hashrategraphwidget.h +++ b/src/qt/hashrategraphwidget.h @@ -24,7 +24,9 @@ class HashRateGraphWidget : public QWidget enum GraphType { MINER_HASHRATE = 0, - NETWORK_HASHRATE + NETWORK_HASHRATE, + MINER_CPU_HASHRATE, + MINER_GPU_HASHRATE }; enum SampleTime @@ -52,6 +54,7 @@ public Q_SLOTS: void initGraph(QPainter& painter); void drawHashRate(QPainter& painter); void truncateSampleQueue(); + int64_t getHashRate(); unsigned int iDesiredSamples; int64_t iMaxHashRate; diff --git a/src/qt/locale/dynamic_ko.ts b/src/qt/locale/dynamic_ko.ts index 26ec1de66b..3d82cc75e3 100644 --- a/src/qt/locale/dynamic_ko.ts +++ b/src/qt/locale/dynamic_ko.ts @@ -1,9 +1,11 @@ - + + + AddressBookPage Right-click to edit address or label - 주소 및 라벨을 수정하려면 마우스 오른쪽 버튼을 클릭해주세요. + 주소 및 라벨을 수정하려면 마우스 오른쪽 버튼을 클릭해주세요 Create a new address @@ -15,7 +17,7 @@ Copy the currently selected address to the system clipboard - 현재 선택된 주소를 복사합니다. + 현재 선택된 주소를 복사합니다 &Copy @@ -23,7 +25,7 @@ Delete the currently selected address from the list - 현재 선택된 주소를 목록에서 삭제합니다. + 현재 선택된 주소를 목록에서 삭제합니다 &Delete @@ -43,11 +45,11 @@ Choose the address to send coins to - 전송할 주소를 선택해주세요. + 전송할 주소를 선택해주세요 Choose the address to receive coins with - 전송 받을 주소를 선택해주세요. + 전송 받을 주소를 선택해주세요 C&hoose @@ -131,10 +133,6 @@ Repeat new passphrase 새로운 암호 확인 - - Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. - 운영체제 계정이 손상되었을 때 일반적인 송금을 비활성화 합니다. 실질적인 보안을 제공하지 않습니다. - For anonymization only 익명 전용 @@ -340,7 +338,7 @@ &Backup Wallet... - &지갑 백업 + &지갑 백업 ... Backup wallet to another location @@ -372,7 +370,7 @@ Sign messages with your Dynamic addresses to prove you own them - Dynamic 주소로 메시지에 서명하여 소유하고 있음을 증명하십시오. + Dynamic 주소로 메시지에 서명하여 소유하고 있음을 증명하십시오 &Verify message... @@ -380,7 +378,7 @@ Verify messages to ensure they were signed with specified Dynamic addresses - 메시지가 지정된 Dynamic 주소로 서명되었는지 확인합니다. + 메시지가 지정된 Dynamic 주소로 서명되었는지 확인합니다 &Information @@ -442,10 +440,6 @@ Open &Configuration File &구성 파일 열기 - - Open configuration file - 구성 파일 열기 - Show Automatic &Backups 자동 &백업 폴더 열기 @@ -496,7 +490,9 @@ Processed %n block(s) of transaction history. - %n 블록의 거래내역 확인됨. + + %n 블록의 거래내역 확인됨. + Synchronizing additional data: %p% @@ -528,7 +524,9 @@ %n active connection(s) to Dynamic network - %n 개의 Dynamic 네트웍에 연결됨 + + %n 개의 Dynamic 네트웍에 연결됨 + Synchronizing with network... @@ -552,15 +550,21 @@ %n hour(s) - %n 시간 + + %n 시간 + %n day(s) - %n 일 + + %n 일 + %n week(s) - %n 주 + + %n 주 + %1 and %2 @@ -568,7 +572,9 @@ %n year(s) - %n 년 + + %n 년 + %1 behind @@ -618,10 +624,6 @@ Address: %4 주소: %4 - - Processed %n block(s) of transaction history. - %n 블록의 거래내역 확인됨. - HD key generation is <b>enabled</b> HD 키 생성이 <b>사용됨</b> @@ -632,15 +634,15 @@ Address: %4 Wallet is <b>encrypted</b> and currently <b>unlocked</b> - 현재 지갑은 <b>암호화되어 <b>잠금해제되었습니다. + 현재 지갑은 <b>암호화되어 <b>잠금해제되었습니다 Wallet is <b>encrypted</b> and currently <b>unlocked</b> for anonimization only - 현재 지갑은 <b>암호화</b> 되어 <b>잠긴</b> 상태로 익명의 전용모드로 안전하게 구동중입니다. + 현재 지갑은 <b>암호화</b> 되어 <b>잠긴</b> 상태로 익명의 전용모드로 안전하게 구동중입니다 Wallet is <b>encrypted</b> and currently <b>locked</b> - 지갑은 <b>암호화</ b>되어 있으며 현재 <b>잠겨 있습니다</ b>. + 지갑은 <b>암호화</b>되어 있으며 현재 <b>잠겨 있습니다</b> @@ -798,8 +800,8 @@ Address: %4 변경 복사 - Please switch to 'List mode' to use this function. - 이 기능을 사용하려면 '목록 모드' 로 전환하십시오. + Please switch to 'List mode' to use this function. + 이 기능을 사용하려면 '목록 모드' 로 전환하십시오. Non-anonymized input selected. <b>PrivateSend will be disabled.</b><br><br>If you still want to use PrivateSend, please deselect all non-anonymized inputs first and then check PrivateSend checkbox again. @@ -823,7 +825,7 @@ Address: %4 Can vary +/- %1 satoshi(s) per input. - 입력당 +/- 1 satoshi 조절 가능. + 입력당 +/- %1 satoshi 조절 가능. N/A @@ -865,6 +867,10 @@ Address: %4 no 아니오 + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + 수신자가 현재 먼지 임계 값보다 작은 양을 수신하면이 레이블이 빨간색으로 바뀝니다. + This label turns red, if the transaction size is greater than 1000 bytes. 트랜잭션 크기가 1000 byte 보다 클 경우 라벨이 빨간색으로 변경됩니다. @@ -882,8 +888,8 @@ Address: %4 우선 순위가 높은 트랜잭션이 블록에 포함 될 확률이 높아집니다. - This label turns red, if the priority is smaller than "medium". - 우선 순위가 "중간" 보다 낮으면 라벨이 빨간색으로 변경됩니다. + This label turns red, if the priority is smaller than "medium". + 우선 순위가 "중간" 보다 낮으면 라벨이 빨간색으로 변경됩니다. This label turns red, if any recipient receives an amount smaller than %1. @@ -926,23 +932,23 @@ Address: %4 Use 2 separate Dynodes to mix funds up to 1000 DYN - 2 개의 별도 다이 노드 Dynodes 를 사용하여 최대 1000 DYN까지 자금을 섞으십시오. + 2 개의 별도 다이 노드 Dynodes 를 사용하여 최대 1000 DYN까지 자금을 섞으십시오 Use 8 separate Dynodes to mix funds up to 1000 DYN - 8 개의 별도 다이 노드 Dynodes를 사용하여 최대 1000 DYN까지 자금을 섞으십시오. + 8 개의 별도 다이 노드 Dynodes를 사용하여 최대 1000 DYN까지 자금을 섞으십시오 Use 16 separate Dynodes to mix funds up to 1000 DYN - 16 개의 별도 다이 노드 Dynodes를 사용하여 최대 1000 DYN까지 자금을 섞으십시오. + 16 개의 별도 다이 노드 Dynodes를 사용하여 최대 1000 DYN까지 자금을 섞으십시오 This option is the quickest and will cost about ~0.025 DYN to anonymize 1000 DYN - 이 옵션은 가장 빠르며 1000 DYN을 익명화하려면 ~ 0.025 DYN 정도 소요됩니다. + 이 옵션은 가장 빠르며 1000 DYN을 익명화하려면 ~ 0.025 DYN 정도 소요됩니다 This option is moderately fast and will cost about 0.05 DYN to anonymize 1000 DYN - 이 옵션은 적당히 빠르며 1000 DYN을 익명화하기 위해 약 0.05 DYN의 비용이 소요됩니다. + 이 옵션은 적당히 빠르며 1000 DYN을 익명화하기 위해 약 0.05 DYN의 비용이 소요됩니다 0.1 DYN per 1000 DYN you anonymize. @@ -950,23 +956,23 @@ Address: %4 This is the slowest and most secure option. Using maximum anonymity will cost - 이것은 가장 느리고 가장 안전한 옵션입니다. 최대 익명 성을 사용하면 비용이 발생합니다. + 이것은 가장 느리고 가장 안전한 옵션입니다. 최대 익명 성을 사용하면 비용이 발생합니다 PrivateSend Configuration PrivateSend 구성 - PrivateSend was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening Dynamic's configuration screen. - PrivateSend가 기본 (% 1 및 2 라운드)으로 설정되었습니다. Dynamic의 설정 화면을 열어 언제든지 변경할 수 있습니다. + PrivateSend was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening Dynamic's configuration screen. + PrivateSend가 기본 (%1 및 2 라운드)으로 설정되었습니다. Dynamic의 설정 화면을 열어 언제든지 변경할 수 있습니다. - PrivateSend was successfully set to high (%1 and 8 rounds). You can change this at any time by opening Dynamic's configuration screen. - PrivateSend가 성공적으로 높게 설정되었습니다 (% 1 및 8 라운드). Dynamic의 구성 화면을 열어 언제든지이를 변경할 수 있습니다. + PrivateSend was successfully set to high (%1 and 8 rounds). You can change this at any time by opening Dynamic's configuration screen. + PrivateSend가 성공적으로 높게 설정되었습니다 (%1 및 8 라운드). Dynamic의 구성 화면을 열어 언제든지이를 변경할 수 있습니다. - PrivateSend was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening Dynamic's configuration screen. - PrivateSend가 최대 (% 1 및 16 라운드)로 설정되었습니다. Dynamic의 구성 화면을 열어 언제든지이를 변경할 수 있습니다. + PrivateSend was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening Dynamic's configuration screen. + PrivateSend가 최대 (%1 및 16 라운드)로 설정되었습니다. Dynamic의 구성 화면을 열어 언제든지이를 변경할 수 있습니다. @@ -1008,12 +1014,12 @@ Address: %4 보내는 주소 수정 - The entered address "%1" is not a valid Dynamic address. - 입력된 주소 "%1"는 올바른 Dynamic 주소가 아닙니다. + The entered address "%1" is not a valid Dynamic address. + 입력된 주소 "%1"는 올바른 Dynamic 주소가 아닙니다. - The entered address "%1" is already in the address book. - 입력한 주소 "%1"는 이미 주소록에 등록 되있습니다. + The entered address "%1" is already in the address book. + 입력한 주소 "%1"는 이미 주소록에 등록 되있습니다. Could not unlock wallet. @@ -1079,15 +1085,15 @@ Address: %4 UI options - UI 옵션: + UI 옵션 Choose data directory on startup (default: 0) 데이터 디렉토리 선택 (기본: %u) - Set language, for example "de_DE" (default: system locale) - 언어 설정 예시 "de_DE" (기본값: 시스템 언어) + Set language, for example "de_DE" (default: system locale) + 언어 설정 예시 "de_DE" (기본값: 시스템 언어) Start minimized @@ -1101,6 +1107,51 @@ Address: %4 Show splash screen on startup (default: 1) 실행시 초기화면 표시 (기본: %u) + + PrivateSend information + 정보를 PrivateSend + + + PrivateSend-LongText + + <h3>기초 PrivateSend</h3> + PrivateSend는 자금의 기원을 불명료하게하여 진정한 금융 정보를 제공합니다. + 귀하의 지갑에있는 모든 Dynamic은 별도의 이산 동전로 생각할 수있는 다양한 \"입력으로\" 구성되어 있습니다.<br> + PrivateSend는 혁신적인 프로세스를 사용하여 동전을 지갑에서 지우지 않고 입력 물과 다른 두 사람의 의견을 섞습니다. + 항상 돈 관리권을 유지합니다.<hr> + <b>PrivateSend 프로세스는 다음과 같이 작동합니다:</b> + <ol type=\"1\"> + <li>PrivateSend는 거래 입력을 표준 단위로 나누는 것으로 시작됩니다. + 이 금액은 0.01 DYN, 0.1 DYN, 1 DYN, 10 DYN입니다. 매일 사용하는 지폐와 비슷합니다.</li> + <li>그런 다음 지갑은 네트워크의 특수하게 구성된 소프트웨어 노드에 요청을 전송합니다 \"Dynodes.\" + 이러한 Dynodes는 특정 종파를 혼합하는 데 관심이 있다는 사실을 알립니다. + 식별 가능한 정보는 다이 노드로 전송되지 \"않으므로\" 사용자가.</li> + <li>다른 두 사람이 비슷한 메시지를 보내면 동일한 명칭을 혼합하려고한다는 것을 나타내며 믹싱 세션이 시작됩니다. + Dynode는 입력을 혼합하여 3 명의 모든 사용자에게' 이제는 변환 된 입력 값을 지불하기 위해 지갑을 사용하십시오. + 귀하의 지갑은 해당 액면가를 직접 지불하지만 다른 주소 (변경 주소라고 함)에 있습니다.</li> + <li>자금을 완전히 모호하게하기 위해 지갑은 각 종파마다이 과정을 여러 번 반복해야합니다. + 프로세스가 완료 될 때마다, \"라운드라고합니다.\" PrivateSend의 각 라운드는 자금 출처를 기하 급수적으로 판별하기가 더 어려워집니다.</li> + <li>이 믹싱 프로세스는 사용자의 개입없이 백그라운드에서 발생합니다. 거래를 할 때 + 자금은 이미 익명 처리됩니다. 추가 대기는 필요하지 않습니다.</li> + </ol> <hr> + <b>중대한:</b> 지갑에는 2000 개의 변경 주소 \"만 있습니다.\" 믹싱 이벤트가 발생할 때마다 최대 9 개의 주소가 사용됩니다. + 이것은 2000 개의 주소가 약 200 개의 믹싱 이벤트에 대해 지속된다는 것을 의미합니다. 1900 개가 사용되면 지갑에서 더 많은 주소를 만들어야합니다. + 그러나 자동 백업을 사용하도록 설정 한 경우에만이 작업을 수행 할 수 있습니다.<br> + 따라서 백업이 비활성화 된 사용자는 PrivateSend도 비활성화됩니다. <hr> + + + + Choose data directory on startup (default: %n) + 시작시 데이터 디렉토리 선택 (기본값: %n) + + + Show splash screen on startup (default: %u) + 시작시 스플래시 화면 표시 (기본값: %u) + + + Reset all settings changes made over the GUI + GUI를 통해 이루어진 모든 설정 변경 재설정 + Intro @@ -1133,8 +1184,8 @@ Address: %4 Dynamic - Error: Specified data directory "%1" cannot be created. - 오류: 지정된 데이터 디렉토리 "%1"을 생성할 수 없습니다. + Error: Specified data directory "%1" cannot be created. + 오류: 지정된 데이터 디렉토리 "%1"을 생성할 수 없습니다. Error @@ -1215,7 +1266,7 @@ Address: %4 익명화를 유지할 Dynamic 양 - This amount acts as a threshold to turn off PrivateSend once it's reached. + This amount acts as a threshold to turn off PrivateSend once it's reached. 이 금액은 일단 도달하면 PrivateSend를 끄는 임계 값 역할을합니다. @@ -1312,18 +1363,10 @@ https://www.transifex.com/projects/p/dynamic/ Whether to use experimental PrivateSend mode with multiple mixing sessions per block.<br/>Note: You must use this feature carefully.<br/>Make sure you always have recent wallet (auto)backup in a safe place! 실험적인 PrivateSend 모드를 블록 당 여러 개의 혼합 세션과 함께 사용할지 여부.<br/>참고:이 기능을 신중하게 사용해야합니다.<br/>항상 안전한 장소에 최근 지갑 (자동) 백업을했는지 확인하십시오! - - PrivateSend rounds to use - PrivateSend 라운드 사용 - &Spend unconfirmed change &확인되지 않은 변경사항 전송 - - This amount acts as a threshold to turn off PrivateSend once it's reached. - 이 양은 일단 도달하면 PrivateSend를 끄는 임계 값 역할을합니다. - &Network &네트워크 @@ -1548,7 +1591,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ keys left: %1 왼쪽 키: %1 - + Completion: 완성: @@ -1618,8 +1661,8 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/PrivateSend 및 믹싱에 대한 정보 - Reset the current status of PrivateSend (can interrupt PrivateSend if it's in the process of Mixing, which can cost you money!) - Privendsend의 현재 상태를 리셋합니다 (믹싱 중일 경우 PrivateSend를 방해 할 수 있습니다. 비용이들 수도 있습니다). + Reset the current status of PrivateSend (can interrupt PrivateSend if it's in the process of Mixing, which can cost you money!) + Privendsend의 현재 상태를 리셋합니다 (믹싱 중일 경우 PrivateSend를 방해 할 수 있습니다. 비용이들 수도 있습니다) Reset @@ -1643,16 +1686,18 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ No inputs detected - 입력이 없습니다. + 입력이 없습니다 %n Rounds - %n 한바퀴%n 한바퀴 + + %n 한바퀴 + - Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead - 익명화 할 수있는 호환 입력이 충분하지 않습니다 <span style='color:red;'>%1</span>,<br/> -대신 <span style='color:red;'>%2</span> 익명화됩니다 + Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead + 익명화 할 수있는 호환 입력이 충분하지 않습니다 <span style='color:red;'>%1</span>,<br/> +대신 <span style='color:red;'>%2</span> 익명화됩니다 Overall progress @@ -1668,7 +1713,9 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Denominated inputs have %5 of %n rounds on average - 지정 입력에는 평균 %5 라운드 중 %n 라운드가 있습니다지정 입력에는 평균 %5 라운드 중 %n 라운드가 있습니다 + + 지정 입력에는 평균 %5 라운드 중 %n 라운드가 있습니다 + Found enough compatible inputs to anonymize %1 @@ -1695,12 +1742,12 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/PrivateSend 가 성공적으로 재설정되었습니다. - If you don't want to see internal PrivateSend fees/transactions select "Most Common" as Type on the "Transactions" tab. - 내부 Privendsend 수수료 / 거래를보고 싶지 않으면 "거래"탭에서 유형으로 "가장 일반적"을 선택하십시오. + If you don't want to see internal PrivateSend fees/transactions select "Most Common" as Type on the "Transactions" tab. + 내부 Privendsend 수수료 / 거래를보고 싶지 않으면 "거래"탭에서 유형으로 "가장 일반적"을 선택하십시오. PrivateSend requires at least %1 to use. - PrivateSend는 적어도 % 1을 (를) 사용하도록 요구합니다. + PrivateSend는 적어도 %1을 (를) 사용하도록 요구합니다. Wallet is locked and user declined to unlock. Disabling PrivateSend. @@ -1715,8 +1762,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Cannot start dynamic: click-to-pay handler - dynamic을 시작할 수 없습니다: 지불하려면 클릭하십시오 처리기 - + dynamic 를 시작할 수 없습니다.: 클릭 투 결제 핸들러 URI handling @@ -1747,7 +1793,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/결제 요청이 거부되었습니다 - Payment request network doesn't match client network. + Payment request network doesn't match client network. 지불 요청 네트워크가 클라이언트 네트워크와 일치하지 않습니다. @@ -1772,7 +1818,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Payment request %1 is too large (%2 bytes, allowed %3 bytes). - 지불 요청 %1 이 (%2 바이트, 바이트 허용) 너무 큽니다. + 지불 요청 %1이 (%2 바이트, %3 바이트 허용) 너무 큽니다. Payment request DoS protection @@ -1953,7 +1999,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Memory usage 메모리 사용량 - + Debug log file 디버그 로그 파일 @@ -1981,7 +2027,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Datadir 데이터 디렉토리 - + Block chain 블록 체인 @@ -2008,7 +2054,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Totals - 합계: + 합계 Received @@ -2243,7 +2289,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ &Amount: - &양 + &양: Request InstantSend @@ -2275,7 +2321,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Remove the selected entries from the list - 선택한 항목을 목록에서 제거하십시오. + 선택한 항목을 목록에서 제거하십시오 Remove @@ -2481,7 +2527,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Hide 숨는 장소 - + collapse fee-settings 축소비 설정 @@ -2491,12 +2537,12 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/최소화 - If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee,<br />while "at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte. - 관례 요금이 1000 satoshis로 설정되고 거래가 단지 250 바이트 인 경우 "킬로바이트 당"은 수수료 250 원만 지불합니다,,<br /> "적어도"1000 표는 지불합니다. 1 킬로바이트보다 큰 거래의 경우 모두 킬로바이트 단위로 지불합니다. + If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee,<br />while "at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte. + 관례 요금이 1000 satoshis로 설정되고 거래가 단지 250 바이트 인 경우 "킬로바이트 당"은 수수료 250 원만 지불합니다,,<br /> "적어도"1000 표는 지불합니다. 1 킬로바이트보다 큰 거래의 경우 모두 킬로바이트 단위로 지불합니다. - If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee,<br />while "total at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte. - 관례 요금이 1000 satoshis로 설정되고 거래가 단지 250 바이트 인 경우 "킬로바이트 당"은 수수료 250 원만 지불합니다,<br /> "적어도 총"은 1000 개를 지불합니다. 1 킬로바이트보다 큰 거래의 경우 모두 킬로바이트 단위로 지불합니다. + If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee,<br />while "total at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte. + 관례 요금이 1000 satoshis로 설정되고 거래가 단지 250 바이트 인 경우 "킬로바이트 당"은 수수료 250 원만 지불합니다,<br /> "적어도 총"은 1000 개를 지불합니다. 1 킬로바이트보다 큰 거래의 경우 모두 킬로바이트 단위로 지불합니다. Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks.<br />But be aware that this can end up in a never confirming transaction once there is more demand for Dynamic transactions than the network can process. @@ -2540,7 +2586,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Send as zero-fee transaction if possible - 가능한 경우 제로 수수료 거래로 전송하십시오. + 가능한 경우 제로 수수료 거래로 전송하십시오 (confirmation may take longer) @@ -2660,7 +2706,9 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Estimated to begin confirmation within %n block(s). - %n 개의 블록 내에서 확인을 시작할 것으로 추정됩니다. + + %n 개의 블록 내에서 확인을 시작할 것으로 추정됩니다. + The recipient address is not valid, please recheck. @@ -2779,16 +2827,12 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee,<br />while "at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte. - 관례 요금이 1000의 satoshis에 세트되고 거래가 단지 250 바이트 인 경우에, "적어도"는 1000의 satoshis를 지불하는 그러나, "킬로바이트 당"는 요금에서 250의 satoshis 만 지불한다. 1 킬로바이트보다 큰 거래의 경우 모두 킬로바이트 단위로 지불합니다. + 관례 요금이 1000의 satoshis에 세트되고 거래가 단지 250 바이트 인 경우에, "적어도"는 1000의 satoshis를 지불하는 그러나, "킬로바이트 당"는 요금에서 250의 satoshis 만 지불한다. 1 킬로바이트보다 큰 거래의 경우 모두 킬로바이트 단위로 지불합니다. This is an unverified payment request. 확인되지 않은 지불 요청입니다. - - Pay &To: - 에 &지불하다: - Memo: 메모: @@ -2914,8 +2958,8 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/모든 확인 메시지 필드 재설정 - Click "Sign Message" to generate signature - "메시지 서명"를 클릭하여 서명 생성 + Click "Sign Message" to generate signature + "메시지 서명"를 클릭하여 서명 생성 The entered address is invalid. @@ -3000,7 +3044,9 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/TransactionDesc Open for %n more block(s) - %n 개의 추가 블록 열기%n 개의 추가 블록 열기 + + %n 개의 추가 블록 열기 + Open until %1 @@ -3064,7 +3110,9 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ , broadcast through %n node(s) - , %n 노드를 통해 브로드 캐스트, %n 노드를 통해 브로드 캐스트 + + , %n 노드를 통해 브로드 캐스트 + Date @@ -3108,7 +3156,9 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ matures in %n more block(s) - %n 개의 블록이 더 이상 만기됩니다%n 개의 블록이 더 이상 만기됩니다 + + %n 개의 블록이 더 이상 만기됩니다 + not accepted @@ -3159,8 +3209,8 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/상인 - Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. - 생성 된 동전은 사용하기 전에 %1 블록을 성숙해야합니다. 이 블록을 생성하면 네트워크에 브로드 캐스팅되어 블록 체인에 추가됩니다. 사슬에 빠지면 상태가 "받아 들여지지 않음"으로 바뀌며 쓸모가 없습니다. 다른 노드가 몇 초 내에 블록을 생성하는 경우 가끔 이런 일이 발생할 수 있습니다. + Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + 생성 된 동전은 사용하기 전에 %1 블록을 성숙해야합니다. 이 블록을 생성하면 네트워크에 브로드 캐스팅되어 블록 체인에 추가됩니다. 사슬에 빠지면 상태가 "받아 들여지지 않음"으로 바뀌며 쓸모가 없습니다. 다른 노드가 몇 초 내에 블록을 생성하는 경우 가끔 이런 일이 발생할 수 있습니다. Debug information @@ -3222,7 +3272,9 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Open for %n more block(s) - %n 개의 추가 블록 열기%n 개의 추가 블록 열기 + + %n 개의 추가 블록 열기 + Open until %1 @@ -3531,8 +3583,8 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/모든 Dynodes - Note: Status of your Dynodes in local wallet can potentially be slightly incorrect.<br />Always wait for wallet to sync additional data and then double check from another node<br />if your Dynode should be running but you still do not see "ENABLED" in "Status" field. - 참고: 로컬 지갑의 Dynode 상태가 약간 잘못 될 수 있습니다.<br /> 추가 데이터를 동기화하려면 항상 Wallet을 기다린 다음 Dynode가<br />실행되어야하지만 "ENABLED" 필드에 "터" 가 표시되지 않으면<br />다른 노드에서 다시 확인하십시오. + Note: Status of your Dynodes in local wallet can potentially be slightly incorrect.<br />Always wait for wallet to sync additional data and then double check from another node<br />if your Dynode should be running but you still do not see "ENABLED" in "Status" field. + 참고: 로컬 지갑의 Dynode 상태가 약간 잘못 될 수 있습니다.<br /> 추가 데이터를 동기화하려면 항상 Wallet을 기다린 다음 Dynode가<br />실행되어야하지만 "ENABLED" 필드에 "터" 가 표시되지 않으면<br />다른 노드에서 다시 확인하십시오. Start &all @@ -3607,8 +3659,8 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/현재 명령을 사용할 수 없습니다 - You can't use this command until Dynode list is synced - Dynode 목록이 동기화 될 때까지이 명령을 사용할 수 없습니다. + You can't use this command until Dynode list is synced + Dynode 목록이 동기화 될 때까지이 명령을 사용할 수 없습니다 Confirm Dynode start @@ -3628,7 +3680,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Successfully started Dynode. - Dynode를 성공적으로 시작했습니다... + Dynode를 성공적으로 시작했습니다. Successfully started %d Dynodes, failed to start %d, total %d @@ -3677,10 +3729,6 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/Clear 제거하다 - - Clear - 제거하다 - Use the slider to select the amount of CPU threads to use 슬라이더를 사용하여 사용할 CPU 스레드 수를 선택하십시오 @@ -3702,12 +3750,12 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/Blockchain/Dynodes가 동기화되지 않았습니다. 광산 전에 완전히 동기화 될 때까지 기다려주세요! - Click 'Start mining' to begin mining! - 마이닝을 시작하려면 '채광 시작' 을 클릭하십시오! + Click 'Start mining' to begin mining! + 마이닝을 시작하려면 '채광 시작' 을 클릭하십시오! - Click 'Stop mining' to finish mining! - 마이닝을 시작하려면 '마이닝 중지' 을 클릭하십시오! + Click 'Stop mining' to finish mining! + 마이닝을 시작하려면 '마이닝 중지' 을 클릭하십시오! Stopping @@ -3723,7 +3771,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ - HashRateGraphWidget + HashRateGraphWidget 5 minutes 5 분 @@ -3774,7 +3822,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/동전 보내기 - InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DYN. + InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DYN. InstantSend는 아직 높은 값을 보내는 것을 지원하지 않습니다. 트랜잭션은 현재 %1 DYN으로 제한됩니다. @@ -3806,7 +3854,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ There was an error trying to save the wallet data to %1. - 1% 에 지갑 데이터를 저장하는 동안 오류가 발생했습니다. + %1 에 지갑 데이터를 저장하는 동안 오류가 발생했습니다. Backup Successful @@ -3814,7 +3862,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ The wallet data was successfully saved to %1. - 지갑 데이터가 1% 에 성공적으로 저장되었습니다. + 지갑 데이터가 %1 에 성공적으로 저장되었습니다. @@ -3849,7 +3897,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) - 지갑 트랜잭션이 변경되면 명령을 실행합니다 (cmd의 %s 는 TxID로 바뀜). + 지갑 트랜잭션이 변경되면 명령을 실행합니다 (cmd의 %s 는 TxID로 바뀜) Execute command when the best block changes (%s in cmd is replaced by block hash) @@ -3865,7 +3913,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Name to construct url for KeePass entry that stores the wallet passphrase - 지갑 패스 프레이즈를 저장하는 KeePass 항목의 URL을 구성하는 이름입니다. + 지갑 패스 프레이즈를 저장하는 KeePass 항목의 URL을 구성하는 이름입니다 Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) @@ -3881,7 +3929,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ This is a pre-release test build - use at your own risk - do not use for mining or merchant applications - 시험판입니다. - 위험에 따라 사용하십시오. - 광산 또는 상인 응용 프로그램에는 사용하지 마십시오. + 시험판입니다. - 위험에 따라 사용하십시오. - 광산 또는 상인 응용 프로그램에는 사용하지 마십시오 Unable to bind to %s on this computer. Dynamic is probably already running. @@ -3945,14 +3993,14 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Attempt to recover private keys from a corrupt wallet.dat - 손상된 wallet.dat에서 개인 키를 복구하려고 시도합니다. + 손상된 wallet.dat에서 개인 키를 복구하려고 시도합니다 Block creation options: 차단 생성 옵션: - Can't denominate: no compatible inputs left. + Can't denominate: no compatible inputs left. 연결할 수 없습니다: 호환 가능한 입력이 없습니다. @@ -3960,12 +4008,12 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/지갑을 다운 그레이드 할 수 없습니다 - Cannot resolve -bind address: '%s' - -bind 주소를 확인할 수 없습니다: '%s' + Cannot resolve -bind address: '%s' + -bind 주소를 확인할 수 없습니다: '%s' - Cannot resolve -externalip address: '%s' - -externalip 주소를 확인할 수 없습니다: '%s' + Cannot resolve -externalip address: '%s' + -externalip 주소를 확인할 수 없습니다: '%s' Cannot write default address @@ -4005,7 +4053,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Do not load the wallet and disable wallet RPC calls - 지갑을로드하지 말고 지갑 RPC 호출을 비활성화하십시오. + 지갑을로드하지 말고 지갑 RPC 호출을 비활성화하십시오 Do you want to rebuild the block database now? @@ -4065,12 +4113,12 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Error: You already have pending entries in the PrivateSend pool - 오류: 이미 Privendsend 풀에 보류중인 항목이 있습니다. + 오류: 이미 Privendsend 풀에 보류중인 항목이 있습니다 Failed to listen on any port. Use -listen=0 if you want this. 모든 포트에서 수신 대기하지 못했습니다. 이것을 원한다면 -listen=0 을 사용하십시오. - + Failed to read block 블록을 읽지 못했습니다 @@ -4085,7 +4133,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times - 지정된 소스에서 JSON-RPC 연결을 허용합니다. 유효한 <IP> 단일 IP (예: 1.2.3.4), 네트워크 / 넷 마스크 (예: 1.2.3.4/255.255.255.0) 또는 네트워크 / CIDR (예: 1.2.3.4/24)입니다. 이 옵션은 여러 번 지정할 수 있습니다. + 지정된 소스에서 JSON-RPC 연결을 허용합니다. 유효한 <IP> 단일 IP (예: 1.2.3.4), 네트워크 / 넷 마스크 (예: 1.2.3.4/255.255.255.0) 또는 네트워크 / CIDR (예: 1.2.3.4/24)입니다. 이 옵션은 여러 번 지정할 수 있습니다 An error occurred while setting up the RPC address %s port %u for listening: %s @@ -4097,7 +4145,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) - 주어진 주소에 바인드하여 JSON-RPC 연결을 기다립니다. IPv6의 경우 [host]:port 표기법을 사용하십시오. 이 옵션은 여러 번 지정할 수 있습니다 (기본값: 모든 인터페이스에 바인드). + 주어진 주소에 바인드하여 JSON-RPC 연결을 기다립니다. IPv6의 경우 [host]:port 표기법을 사용하십시오. 이 옵션은 여러 번 지정할 수 있습니다 (기본값: 모든 인터페이스에 바인드) Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto) @@ -4113,7 +4161,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup - 모든 지갑 트랜잭션을 삭제하고 시작시 -rescan을 통해 블록 체인의 해당 부분 만 복구하십시오. + 모든 지갑 트랜잭션을 삭제하고 시작시 -rescan을 통해 블록 체인의 해당 부분 만 복구하십시오 Disable all Dynamic specific functionality (Dynodes, PrivateSend, InstantSend, Budgeting) (0-1, default: %u) @@ -4132,7 +4180,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/이 지갑에 저장된 자금에 대한 자동화 된 PrivateSend 사용 (0-1, 기본값: %u) - Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. 오류: 지원되지 않는 인수 -socks가 발견되었습니다. SOCKS 버전 설정은 더 이상 가능하지 않으며 SOCKS5 프록시 만 지원됩니다. @@ -4156,8 +4204,8 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/paytxfee가 설정되지 않은 경우 거래가 n 블록 (평균: %u) 내에서 평균 확인을 시작하기에 충분한 수수료를 포함하십시오. - Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - -maxtxfee=<금액>: '%s' 의 금액이 잘못되었습니다 (적어도 거래가 발생하지 않도록 %s 의 minrelay 수수료가되어야합니다) + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + -maxtxfee=<금액>: '%s' 의 금액이 잘못되었습니다 (적어도 거래가 발생하지 않도록 %s 의 minrelay 수수료가되어야합니다) Log transaction priority and fee per kB when mining blocks (default: %u) @@ -4165,7 +4213,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u) - getrawtransaction rpc 호출에서 사용되는 전체 트랜잭션 색인을 유지 관리합니다 (기본값: %u). + getrawtransaction rpc 호출에서 사용되는 전체 트랜잭션 색인을 유지 관리합니다 (기본값: %u) Maximum size of data in data carrier transactions we relay and mine (default: %u) @@ -4173,7 +4221,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s) - 단일 월렛 거래에 사용할 최대 총 수수료입니다. 너무 낮게 설정하면 큰 거래가 중단 될 수 있습니다 (기본값: %s). + 단일 월렛 거래에 사용할 최대 총 수수료입니다. 너무 낮게 설정하면 큰 거래가 중단 될 수 있습니다 (기본값: %s) Number of seconds to keep misbehaving peers from reconnecting (default: %u) @@ -4189,7 +4237,7 @@ https://www.transifex.com/duality-blockchain-solutions-llc/dynamic-dyn/ Require high priority for relaying free or low-fee transactions (default:%u) - 무료 또는 저렴한 요금의 거래를 중계하기 위해 높은 우선 순위를 요구합니다 (기본값: %u). + 무료 또는 저렴한 요금의 거래를 중계하기 위해 높은 우선 순위를 요구합니다 (기본값: %u) Send trace/debug info to console instead of debug.log file (default: %u) @@ -4217,7 +4265,7 @@ rpcpassword=%s The username and password MUST NOT be the same. If the file does not exist, create it with owner-readable-only file permissions. It is also recommended to set alertnotify so you are notified of problems; -for example: alertnotify=echo %%s | mail -s "Dynamic Alert" admin@foo.com +for example: alertnotify=echo %%s | mail -s "Dynamic Alert" admin@foo.com dynamicd 또는 dynamic-qt에 -server 옵션을 사용하려면 구성 파일에 rpcpassword를 설정해야합니다. %에스 @@ -4228,7 +4276,7 @@ rpcpassword=%s 사용자 이름과 비밀번호는 동일하지 않아야합니다. 파일이 없으면 소유자가 읽을 수있는 파일 권한으로 파일을 만듭니다. 또한 문제 알림을받을 수 있도록 alertnotify를 설정하는 것이 좋습니다. -예: alertnotify=echo %%s | mail -s "동적 경고" admin@foo.com +예: alertnotify=echo %%s | mail -s "동적 경고" admin@foo.com @@ -4244,7 +4292,7 @@ rpcpassword=%s 경고: -maxtxfee가 매우 높게 설정되었습니다! 이 금액은 단일 거래로 지불 할 수 있습니다. - Warning: Please check that your computer's date and time are correct! If your clock is wrong Dynamic will not work properly. + Warning: Please check that your computer's date and time are correct! If your clock is wrong Dynamic will not work properly. 경고: 컴퓨터의 날짜와 시간이 올바른지 확인하십시오! 시계가 틀리면 Dynamic이 제대로 작동하지 않습니다. @@ -4271,7 +4319,7 @@ rpcpassword=%s Accept public REST requests (default: %u) - 공개 REST 요청을 수락합니다 (기본값: %u). + 공개 REST 요청을 수락합니다 (기본값: %u) Acceptable ciphers (default: %s) @@ -4279,11 +4327,11 @@ rpcpassword=%s Always query for peer addresses via DNS lookup (default: %u) - DNS 검색을 통해 피어 주소를 항상 쿼리합니다 (기본값: %u). + DNS 검색을 통해 피어 주소를 항상 쿼리합니다 (기본값: %u) - Cannot resolve -whitebind address: '%s' - -whitebind 주소를 확인할 수 없습니다: '%s' + Cannot resolve -whitebind address: '%s' + -whitebind 주소를 확인할 수 없습니다: '%s' Connect through SOCKS5 proxy @@ -4335,11 +4383,11 @@ rpcpassword=%s Error: A fatal internal error occured, see debug.log for details - 오류: 치명적인 내부 오류가 발생했습니다. 자세한 내용은 debug.log를 참조하십시오. + 오류: 치명적인 내부 오류가 발생했습니다. 자세한 내용은 debug.log를 참조하십시오 - Error: Can't select current denominated inputs - 오류: 현재 표시된 입력을 선택할 수 없습니다. + Error: Can't select current denominated inputs + 오류: 현재 표시된 입력을 선택할 수 없습니다 Error: Unsupported argument -tor found, use -onion. @@ -4418,32 +4466,32 @@ rpcpassword=%s 불충분 한 자금. - Invalid -onion address: '%s' - 잘못된 -onion 주소: '%s' + Invalid -onion address: '%s' + 잘못된 -onion 주소: '%s' - Invalid -proxy address: '%s' - 잘못된 -proxy 주소: '%s' + Invalid -proxy address: '%s' + 잘못된 -proxy 주소: '%s' - Invalid amount for -maxtxfee=<amount>: '%s' - -maxtxfee=<금액>: '%s'의 금액이 잘못되었습니다. + Invalid amount for -maxtxfee=<amount>: '%s' + -maxtxfee=<금액>: '%s'의 금액이 잘못되었습니다. - Invalid amount for -minrelaytxfee=<amount>: '%s' - -minrelaytxfee=<금액>: '%s'의 금액이 잘못되었습니다. + Invalid amount for -minrelaytxfee=<amount>: '%s' + -minrelaytxfee=<금액>: '%s'의 금액이 잘못되었습니다. - Invalid amount for -mintxfee=<amount>: '%s' - -mintxfee=<금액>: '%s'의 금액이 잘못되었습니다. + Invalid amount for -mintxfee=<amount>: '%s' + -mintxfee=<금액>: '%s'의 금액이 잘못되었습니다. - Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - -paytxfee=<금액>: '%s'의 금액이 잘못되었습니다 (%s 이상이어야합니다). + Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) + -paytxfee=<금액>: '%s'의 금액이 잘못되었습니다 (%s 이상이어야합니다). - Invalid amount for -paytxfee=<amount>: '%s' - -paytxfee=<금액>: '%s'의 금액이 잘못되었습니다. + Invalid amount for -paytxfee=<amount>: '%s' + -paytxfee=<금액>: '%s'의 금액이 잘못되었습니다. Last successful PrivateSend action was too recent. @@ -4471,7 +4519,7 @@ rpcpassword=%s Loading Dynode payment cache... - Dynode 지불 캐시로드 중 + Dynode 결제 캐시로드 중 ... Loading governance cache... @@ -4506,8 +4554,8 @@ rpcpassword=%s 믹싱 진행 중... - Need to specify a port with -whitebind: '%s' - -whitebind: '%s'을 (를) 사용하여 포트를 지정해야합니다. + Need to specify a port with -whitebind: '%s' + -whitebind: '%s'을 (를) 사용하여 포트를 지정해야합니다. No Dynodes detected. @@ -4535,19 +4583,19 @@ rpcpassword=%s Prepend debug output with timestamp (default: %u) - 타임 스탬프로 디버그 출력을 앞에 추가합니다 (기본값: %u). + 타임 스탬프로 디버그 출력을 앞에 추가합니다 (기본값: %u) Run a thread to flush wallet periodically (default: %u) - 정기적으로 지갑을 플러시하도록 스레드를 실행하십시오 (기본값: %u). + 정기적으로 지갑을 플러시하도록 스레드를 실행하십시오 (기본값: %u) Send trace/debug info to debug.log file (default: %u) - debug.log 파일에 추적 / 디버그 정보를 보냅니다 (기본값: %u). + debug.log 파일에 추적 / 디버그 정보를 보냅니다 (기본값: %u) Send transactions as zero-fee transactions if possible (default: %u) - 가능한 경우 거래를 제로 수수료 거래로 보냅니다 (기본값: %u). + 가능한 경우 거래를 제로 수수료 거래로 보냅니다 (기본값: %u) Server certificate file (default: %s) @@ -4623,7 +4671,7 @@ rpcpassword=%s Synchronization finished - 동기화가 완료되었습니다. + 동기화가 완료되었습니다 Synchronizing budgets... @@ -4694,11 +4742,11 @@ rpcpassword=%s (메인 네트의 경우 33300이어야 함) - Can't find random Dynode. + Can't find random Dynode. 랜덤 다이 노스를 찾을 수 없습니다. - Can't mix while sync in progress. + Can't mix while sync in progress. 진행중인 동기화 중에는 혼합 할 수 없습니다. @@ -4706,8 +4754,8 @@ rpcpassword=%s dynode.conf를 분석 할 수 없습니다 - Invalid netmask specified in -whitelist: '%s' - 잘못된 넷 마스크가에서 지정되었습니다 -whitelist: '%s' + Invalid netmask specified in -whitelist: '%s' + 잘못된 넷 마스크가에서 지정되었습니다 -whitelist: '%s' Invalid port detected in dynode.conf @@ -4870,8 +4918,8 @@ rpcpassword=%s <n> 시간 (기본값: %u)보다 긴 트랜잭션을 메모리 풀에 유지하지 마십시오 - Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - 오래된 블록을 정리 (삭제)하여 스토리지 요구 사항을 줄입니다. 이 모드는 -txindex 및 -rescan과 호환되지 않습니다. 경고 :이 설정을 되돌리려면 전체 블록 체인을 다시 다운로드해야합니다. (기본값 : 0 = 잘라내 기 블록 사용 안 함,> %u = 블록 파일에 사용할 MiB의 대상 크기) + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + 오래된 블록을 정리 (삭제)하여 스토리지 요구 사항을 줄입니다. 이 모드는 -txindex 및 -rescan과 호환되지 않습니다. 경고 :이 설정을 되돌리려면 전체 블록 체인을 다시 다운로드해야합니다. (기본값 : 0 = 잘라내 기 블록 사용 안 함,> %u = 블록 파일에 사용할 MiB의 대상 크기) Rebuild chain state from the currently indexed blocks @@ -4879,7 +4927,7 @@ rpcpassword=%s Rebuild chain state and block index from the blk*.dat files on disk - 디스크의 blk*.dat 파일에서 체인 상태를 재구성하고 인덱스를 차단합니다. + 디스크의 blk*.dat 파일에서 체인 상태를 재구성하고 인덱스를 차단합니다 Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses (default: %u) @@ -4895,11 +4943,11 @@ rpcpassword=%s Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections - 지정된 노드에만 연결하십시오. 자동 연결을 사용하지 않으려면 -noconnect 또는 -connect = 0을 단독으로 사용하십시오. + 지정된 노드에만 연결하십시오. 자동 연결을 사용하지 않으려면 -noconnect 또는 -connect = 0을 단독으로 사용하십시오 Discover own IP addresses (default: 1 when listening and no -externalip or -proxy) - 자신의 IP 주소를 찾습니다 (기본값: 수신시 1, -externalip 또는 -proxy 없음). + 자신의 IP 주소를 찾습니다 (기본값: 수신시 1, -externalip 또는 -proxy 없음) Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect) @@ -4907,11 +4955,11 @@ rpcpassword=%s Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect) - 외부에서 연결을 허용합니다 (기본값: -proxy 또는 -connect/-noconnect가없는 경우 1). + 외부에서 연결을 허용합니다 (기본값: -proxy 또는 -connect/-noconnect가없는 경우 1) Automatically create Tor hidden service (default: %d) - 자동으로 Tor 숨김 서비스를 생성합니다 (기본값: %d). + 자동으로 Tor 숨김 서비스를 생성합니다 (기본값: %d) Maintain at most <n> connections to peers (temporary service connections excluded) (default: %u) @@ -4956,7 +5004,7 @@ rpcpassword=%s Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) 이보다 작은 수수료 (%s/Kb)는 거래 생성을위한 제로 수수료로 간주됩니다 (기본값: %s) - + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) 이것보다 작은 수수료 (%s/kB 단위)는 중계, 광업 및 거래 생성을위한 제로 수수료로 간주됩니다 (기본값: %s) @@ -5037,10 +5085,6 @@ rpcpassword=%s Use N separate Dynodes for each denominated input to mix funds (2-16, default: %u) 자금을 혼합하기 위해 각 입력에 대해 N 개의 개별 Dynode를 사용하십시오 (기본값: %u) - - Provide liquidity to PrivateSend by infrequently mixing coins on a continual basis (0-100, default: %u, 1=very frequent, high fees, 100=very infrequent, low fees) - 빈번하게 동전을 혼합하여 (0-100, 기본값: %u, 1 =매우 자주, 높은 수수료, 100= 매우 드물게, 낮은 수수료) PrivateSend에 유동성을 제공하십시오. - Enable InstantSend, show confirmations for locked transactions (0-1, default: %u) InstantSend 사용, 잠긴 트랜잭션에 대한 확인 표시 (0-1, default: %u) @@ -5194,8 +5238,8 @@ rpcpassword=%s spork 메시지에 서명 할 수 없습니다. 잘못된 키입니까? - Unknown network specified in -onlynet: '%s' - 에 지정된 알 수없는 네트워크 -onlynet: '%s' + Unknown network specified in -onlynet: '%s' + 에 지정된 알 수없는 네트워크 -onlynet: '%s' Unknown state: id = %u @@ -5235,7 +5279,7 @@ rpcpassword=%s Wallet %s resides outside data directory %s - 월렛 %s 이 (가) 데이터 디렉토리 %s 외부에 있습니다. + 월렛 %s 이 (가) 데이터 디렉토리 %s 외부에 있습니다 Wallet is locked. @@ -5283,7 +5327,7 @@ rpcpassword=%s -ModalOverlay + ModalOverlay The displayed information may be out of date. Your wallet automatically synchronizes with the Dynamic network after a connection is established, but this process has not completed yet. This means that recent transactions will not be visible, and the balance will not be up-to-date until this process has completed. 표시된 정보가 오래되었을 수 있습니다. 연결이 설정되면 지갑이 자동으로 Dynamic 네트워크와 동기화되지만이 프로세스는 아직 완료되지 않았습니다. 즉, 최근 거래가 표시되지 않고이 프로세스가 완료 될 때까지 잔액이 최신 상태가 아님을 의미합니다. @@ -5337,52 +5381,4 @@ rpcpassword=%s 숨는 장소 - - HelpMessageDialog - - PrivateSend information - 정보를 PrivateSend - - - PrivateSend-LongText - - <h3>기초 PrivateSend</h3> - PrivateSend는 자금의 기원을 불명료하게하여 진정한 금융 정보를 제공합니다. - 귀하의 지갑에있는 모든 Dynamic은 별도의 이산 동전로 생각할 수있는 다양한 \"입력으로\" 구성되어 있습니다.<br> - PrivateSend는 혁신적인 프로세스를 사용하여 동전을 지갑에서 지우지 않고 입력 물과 다른 두 사람의 의견을 섞습니다. - 항상 돈 관리권을 유지합니다.<hr> - <b>PrivateSend 프로세스는 다음과 같이 작동합니다:</b> - <ol type=\"1\"> - <li>PrivateSend는 거래 입력을 표준 단위로 나누는 것으로 시작됩니다. - 이 금액은 0.01 DYN, 0.1 DYN, 1 DYN, 10 DYN입니다. 매일 사용하는 지폐와 비슷합니다.</li> - <li>그런 다음 지갑은 네트워크의 특수하게 구성된 소프트웨어 노드에 요청을 전송합니다 \"Dynodes.\" - 이러한 Dynodes는 특정 종파를 혼합하는 데 관심이 있다는 사실을 알립니다. - 식별 가능한 정보는 다이 노드로 전송되지 \"않으므로\" 사용자가.</li> - <li>다른 두 사람이 비슷한 메시지를 보내면 동일한 명칭을 혼합하려고한다는 것을 나타내며 믹싱 세션이 시작됩니다. - Dynode는 입력을 혼합하여 3 명의 모든 사용자에게' 이제는 변환 된 입력 값을 지불하기 위해 지갑을 사용하십시오. - 귀하의 지갑은 해당 액면가를 직접 지불하지만 다른 주소 (변경 주소라고 함)에 있습니다.</li> - <li>자금을 완전히 모호하게하기 위해 지갑은 각 종파마다이 과정을 여러 번 반복해야합니다. - 프로세스가 완료 될 때마다, \"라운드라고합니다.\" PrivateSend의 각 라운드는 자금 출처를 기하 급수적으로 판별하기가 더 어려워집니다.</li> - <li>이 믹싱 프로세스는 사용자의 개입없이 백그라운드에서 발생합니다. 거래를 할 때 - 자금은 이미 익명 처리됩니다. 추가 대기는 필요하지 않습니다.</li> - </ol> <hr> - <b>중대한:</b> 지갑에는 2000 개의 변경 주소 \"만 있습니다.\" 믹싱 이벤트가 발생할 때마다 최대 9 개의 주소가 사용됩니다. - 이것은 2000 개의 주소가 약 200 개의 믹싱 이벤트에 대해 지속된다는 것을 의미합니다. 1900 개가 사용되면 지갑에서 더 많은 주소를 만들어야합니다. - 그러나 자동 백업을 사용하도록 설정 한 경우에만이 작업을 수행 할 수 있습니다.<br> - 따라서 백업이 비활성화 된 사용자는 PrivateSend도 비활성화됩니다. <hr> - - - - Choose data directory on startup (default: %n) - 시작시 데이터 디렉토리 선택 (기본값: %n) - - - Show splash screen on startup (default: %u) - 시작시 스플래시 화면 표시 (기본값: %u) - - - Reset all settings changes made over the GUI - GUI를 통해 이루어진 모든 설정 변경 재설정 - - diff --git a/src/qt/miningpage.cpp b/src/qt/miningpage.cpp index 0fe029598c..d0fd40d6a2 100644 --- a/src/qt/miningpage.cpp +++ b/src/qt/miningpage.cpp @@ -36,28 +36,50 @@ MiningPage::MiningPage(const PlatformStyle *platformStyle, QWidget *parent) : } } - ui->sliderCores->setMinimum(0); - ui->sliderCores->setMaximum(nMaxUseThreads); - ui->sliderCores->setValue(nMaxUseThreads); - ui->labelNCores->setText(QString("%1").arg(nMaxUseThreads)); - ui->sliderGraphSampleTime->setMaximum(0); - ui->sliderGraphSampleTime->setMaximum(6); - - ui->sliderCores->setToolTip(tr("Use the slider to select the amount of CPU threads to use")); - ui->labelNetHashRate->setToolTip(tr("This shows the overall hashrate of the Dynamic network")); - ui->labelMinerHashRate->setToolTip(tr("This shows the hashrate of your CPU whilst mining")); - ui->labelNextBlock->setToolTip(tr("This shows the average time between the blocks you have mined")); - - connect(ui->sliderCores, SIGNAL(valueChanged(int)), this, SLOT(changeNumberOfCores(int))); - connect(ui->sliderGraphSampleTime, SIGNAL(valueChanged(int)), this, SLOT(changeSampleTime(int))); - connect(ui->pushSwitchMining, SIGNAL(clicked()), this, SLOT(switchMining())); - connect(ui->pushButtonClearData, SIGNAL(clicked()), this, SLOT(clearHashRateData())); - connect(ui->checkBoxShowGraph, SIGNAL(stateChanged(int)), this, SLOT(showHashRate(int))); - // - ui->minerHashRateWidget->graphType = HashRateGraphWidget::GraphType::MINER_HASHRATE; - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::FIVE_MINUTES); - - showHashMeterControls(false); + ui->sliderCPUCores->setMinimum(0); + ui->sliderCPUCores->setMaximum(nMaxUseThreads); + ui->sliderCPUCores->setValue(nMaxUseThreads); + ui->labelNCPUCores->setText(QString("%1").arg(nMaxUseThreads)); + + ui->sliderGPUCores->setMinimum(0); + ui->sliderGPUCores->setMaximum(nMaxUseThreads); + ui->sliderGPUCores->setValue(nMaxUseThreads); + ui->labelNGPUCores->setText(QString("%1").arg(nMaxUseThreads)); + + ui->sliderCPUGraphSampleTime->setMaximum(0); + ui->sliderCPUGraphSampleTime->setMaximum(6); + + ui->sliderGPUGraphSampleTime->setMaximum(0); + ui->sliderGPUGraphSampleTime->setMaximum(6); + + ui->sliderCPUCores->setToolTip(tr("Use the slider to select the amount of CPU threads to use")); + ui->sliderGPUCores->setToolTip(tr("Use the slider to select the amount of GPU threads to use")); + ui->labelCPUMinerHashRate->setToolTip(tr("This shows the hashrate of your CPU whilst mining")); + ui->labelGPUMinerHashRate->setToolTip(tr("This shows the hashrate of your GPU whilst mining")); + ui->labelNetHashRateCPU->setToolTip(tr("This shows the overall hashrate of the Dynamic network")); + ui->labelNetHashRateGPU->setToolTip(tr("This shows the overall hashrate of the Dynamic network")); + ui->labelNextCPUBlock->setToolTip(tr("This shows the average time between the blocks you have mined")); + ui->labelNextGPUBlock->setToolTip(tr("This shows the average time between the blocks you have mined")); + + connect(ui->sliderCPUCores, SIGNAL(valueChanged(int)), this, SLOT(changeNumberOfCPUThreads(int))); + connect(ui->sliderGPUCores, SIGNAL(valueChanged(int)), this, SLOT(changeNumberOfGPUThreads(int))); + connect(ui->sliderCPUGraphSampleTime, SIGNAL(valueChanged(int)), this, SLOT(changeCPUSampleTime(int))); + connect(ui->sliderGPUGraphSampleTime, SIGNAL(valueChanged(int)), this, SLOT(changeGPUSampleTime(int))); + connect(ui->pushSwitchCPUMining, SIGNAL(clicked()), this, SLOT(switchCPUMining())); + connect(ui->pushSwitchGPUMining, SIGNAL(clicked()), this, SLOT(switchGPUMining())); + connect(ui->pushButtonClearCPUData, SIGNAL(clicked()), this, SLOT(clearCPUHashRateData())); + connect(ui->pushButtonClearGPUData, SIGNAL(clicked()), this, SLOT(clearGPUHashRateData())); + connect(ui->checkBoxShowCPUGraph, SIGNAL(stateChanged(int)), this, SLOT(showCPUHashRate(int))); + connect(ui->checkBoxShowGPUGraph, SIGNAL(stateChanged(int)), this, SLOT(showGPUHashRate(int))); + + ui->minerCPUHashRateWidget->graphType = HashRateGraphWidget::GraphType::MINER_CPU_HASHRATE; + ui->minerCPUHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::FIVE_MINUTES); + + ui->minerGPUHashRateWidget->graphType = HashRateGraphWidget::GraphType::MINER_GPU_HASHRATE; + ui->minerGPUHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::FIVE_MINUTES); + + showHashMeterControls(false, false); + showHashMeterControls(false, true); updateUI(); startTimer(3511); } @@ -74,82 +96,113 @@ void MiningPage::setModel(WalletModel *model) void MiningPage::updateUI() { - qint64 NetworkHashrate = GUIUtil::GetNetworkHashPS(120, -1); - qint64 Hashrate = GUIUtil::GetHashRate(); + qint64 networkHashrate = GUIUtil::GetNetworkHashPS(120, -1); + qint64 hashrate = GetHashRate(); - ui->labelNetHashRate->setText(GUIUtil::FormatHashRate(NetworkHashrate)); - ui->labelMinerHashRate->setText(GUIUtil::FormatHashRate(Hashrate)); - - QString NextBlockTime; - if (Hashrate == 0) - NextBlockTime = QChar(L'∞'); - else - { - arith_uint256 Target; - Target.SetCompact(chainActive.Tip()->nBits); - arith_uint256 ExpectedTime = (arith_uint256(1) << 256)/(Target*Hashrate); - NextBlockTime = GUIUtil::FormatTimeInterval(ExpectedTime); + ui->labelNetHashRateCPU->setText(GUIUtil::FormatHashRate(networkHashrate)); + ui->labelNetHashRateGPU->setText(GUIUtil::FormatHashRate(networkHashrate)); + ui->labelCPUMinerHashRate->setText(GUIUtil::FormatHashRate(GetCPUHashRate())); + ui->labelGPUMinerHashRate->setText(GUIUtil::FormatHashRate(GetGPUHashRate())); + + QString nextBlockTime; + if (hashrate == 0) { + nextBlockTime = QChar(L'∞'); + } else { + arith_uint256 target; + target.SetCompact(chainActive.Tip()->nBits); + arith_uint256 expectedTime = (arith_uint256(1) << 256) / (target * hashrate); + nextBlockTime = GUIUtil::FormatTimeInterval(expectedTime); } - - ui->labelNextBlock->setText(NextBlockTime); + ui->labelNextCPUBlock->setText(nextBlockTime); + ui->labelNextGPUBlock->setText(nextBlockTime); + + updatePushSwitch(true); + updatePushSwitch(false); +} + +void MiningPage::updatePushSwitch(bool fGPU) +{ + QPushButton* pushSwitch = fGPU ? ui->pushSwitchGPUMining : ui->pushSwitchCPUMining; if (!dynodeSync.IsSynced() || !dynodeSync.IsBlockchainSynced()) { - ui->pushSwitchMining->setToolTip(tr("Blockchain/Dynodes are not synced, please wait until fully synced before mining!")); - ui->pushSwitchMining->setText(tr("Disabled")); - ui->pushSwitchMining->setEnabled(false); - } - else if (dynodeSync.IsSynced() && dynodeSync.IsBlockchainSynced() && GUIUtil::GetHashRate() == 0) { - ui->pushSwitchMining->setToolTip(tr("Click 'Start mining' to begin mining!")); - ui->pushSwitchMining->setText(tr("Start mining")); - ui->pushSwitchMining->setEnabled(true); - } - else { - ui->pushSwitchMining->setToolTip(tr("Click 'Stop mining' to finish mining!")); - ui->pushSwitchMining->setText(tr("Stop mining")); - ui->pushSwitchMining->setEnabled(true); + pushSwitch->setToolTip(tr("Blockchain/Dynodes are not synced, please wait until fully synced before mining!")); + pushSwitch->setText(tr("Disabled")); + pushSwitch->setEnabled(false); + } else if (dynodeSync.IsSynced() && dynodeSync.IsBlockchainSynced() && GetHashRate() == 0) { + pushSwitch->setToolTip(tr("Click 'Start mining' to begin mining!")); + pushSwitch->setText(tr("Start mining")); + pushSwitch->setEnabled(true); + } else { + pushSwitch->setToolTip(tr("Click 'Stop mining' to finish mining!")); + pushSwitch->setText(tr("Stop mining")); + pushSwitch->setEnabled(true); } } void MiningPage::StartMiner() { - int nThreads = (int)ui->sliderCores->value(); - GenerateDynamics(true, nThreads, Params(), *g_connman); + int nCPUThreads = (int)ui->sliderCPUCores->value(); + int nGPUThreads = (int)ui->sliderGPUCores->value(); + GenerateDynamics(nCPUThreads, nGPUThreads, Params(), *g_connman); updateUI(); } -void MiningPage::StopMiner() +void MiningPage::StopMiner(bool fGPU) { - GenerateDynamics(false, 0, Params(), *g_connman); + if (fGPU) { + ShutdownGPUMiners(); + } else { + ShutdownCPUMiners(); + } updateUI(); } -void MiningPage::changeNumberOfCores(int i) +void MiningPage::changeNumberOfCPUThreads(int i) { - ui->labelNCores->setText(QString("%1").arg(i)); + ui->labelNCPUCores->setText(QString("%1").arg(i)); if (i == 0) { - StopMiner(); + StopMiner(false); + } else if (i > 0 && GetCPUHashRate() <= 0) { + StartMiner(); } - else if (i > 0 && GUIUtil::GetHashRate() > 0) { +} + +void MiningPage::changeNumberOfGPUThreads(int i) +{ + ui->labelNGPUCores->setText(QString("%1").arg(i)); + if (i == 0) { + StopMiner(true); + } else if (i > 0 && GetGPUHashRate() <= 0) { StartMiner(); } } -void MiningPage::switchMining() +void MiningPage::switchCPUMining() +{ + switchMining(false); +} + +void MiningPage::switchGPUMining() { - int64_t hashRate = GUIUtil::GetHashRate(); - int nThreads = (int)ui->sliderCores->value(); - + switchMining(true); +} + +void MiningPage::switchMining(bool fGPU) +{ + QPushButton* pushSwitch = fGPU ? ui->pushSwitchGPUMining : ui->pushSwitchCPUMining; + QSlider* coreSlider = fGPU ? ui->sliderGPUCores : ui->sliderCPUCores; + int nThreads = (int)(fGPU ? ui->sliderGPUCores->value() : ui->sliderCPUCores->value()); + int64_t hashRate = fGPU ? GetGPUHashRate() : GetCPUHashRate(); + if (hashRate > 0) { - ui->pushSwitchMining->setText(tr("Stopping")); - StopMiner(); - } - else if (nThreads == 0 && hashRate == 0){ - ui->sliderCores->setValue(1); - ui->pushSwitchMining->setText(tr("Starting")); + pushSwitch->setText(tr("Stopping")); + StopMiner(fGPU); + } else if (nThreads == 0 && hashRate == 0) { + coreSlider->setValue(1); + pushSwitch->setText(tr("Starting")); StartMiner(); - } - else { - ui->pushSwitchMining->setText(tr("Starting")); + } else { + pushSwitch->setText(tr("Starting")); StartMiner(); } } @@ -159,69 +212,97 @@ void MiningPage::timerEvent(QTimerEvent *) updateUI(); } -void MiningPage::showHashRate(int i) +void MiningPage::showCPUHashRate(int i) { - if (i == 0) { - ui->minerHashRateWidget->StopHashMeter(); - showHashMeterControls(false); - } - else { - ui->minerHashRateWidget->StartHashMeter(); - showHashMeterControls(true); - } + showHashRate(i, false); } -void MiningPage::showHashMeterControls(bool show) +void MiningPage::showGPUHashRate(int i) { - if (show == false) { - ui->sliderGraphSampleTime->setVisible(false); - ui->labelGraphSampleSize->setVisible(false); - ui->pushButtonClearData->setVisible(false); - } - else { - ui->sliderGraphSampleTime->setVisible(true); - ui->labelGraphSampleSize->setVisible(true); - ui->pushButtonClearData->setVisible(true); - } + showHashRate(i, true); } -void MiningPage::changeSampleTime(int i) +void MiningPage::showHashRate(int i, bool fGPU) { + HashRateGraphWidget* widget = fGPU ? ui->minerGPUHashRateWidget : ui->minerCPUHashRateWidget; if (i == 0) { - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::FIVE_MINUTES); - ui->labelGraphSampleSize->setText(QString("5 minutes")); - } - else if (i == 1) { - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::TEN_MINUTES); - ui->labelGraphSampleSize->setText(QString("10 minutes")); + widget->StopHashMeter(); + showHashMeterControls(false, fGPU); + } else { + widget->StartHashMeter(); + showHashMeterControls(true, fGPU); } - else if (i == 2) { - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::THIRTY_MINUTES); - ui->labelGraphSampleSize->setText(QString("30 minutes")); - } - else if (i == 3) { - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::ONE_HOUR); - ui->labelGraphSampleSize->setText(QString("1 hour")); - } - else if (i == 4) { - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::EIGHT_HOURS); - ui->labelGraphSampleSize->setText(QString("8 hours")); - } - else if (i == 5) { - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::TWELVE_HOURS); - ui->labelGraphSampleSize->setText(QString("12 hours")); - } - else if (i == 6) { - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::ONE_DAY); - ui->labelGraphSampleSize->setText(QString("1 day")); +} + +void MiningPage::showHashMeterControls(bool show, bool fGPU) +{ + if (fGPU) { + ui->sliderGPUGraphSampleTime->setVisible(show); + ui->labelGPUGraphSampleSize->setVisible(show); + ui->pushButtonClearGPUData->setVisible(show); + } else { + ui->sliderCPUGraphSampleTime->setVisible(show); + ui->labelCPUGraphSampleSize->setVisible(show); + ui->pushButtonClearCPUData->setVisible(show); } - else { - ui->minerHashRateWidget->UpdateSampleTime(HashRateGraphWidget::SampleTime::ONE_DAY); - ui->labelGraphSampleSize->setText(QString("1 day")); +} + +void MiningPage::changeCPUSampleTime(int i) +{ + changeSampleTime(i, false); +} + +void MiningPage::changeGPUSampleTime(int i) +{ + changeSampleTime(i, true); +} + +void MiningPage::changeSampleTime(int i, bool fGPU) +{ + QLabel* labelSize = fGPU ? ui->labelGPUGraphSampleSize : ui->labelCPUGraphSampleSize; + HashRateGraphWidget* hashRate = fGPU ? ui->minerGPUHashRateWidget : ui->minerCPUHashRateWidget; + switch (i) { + case 0: + hashRate->UpdateSampleTime(HashRateGraphWidget::SampleTime::FIVE_MINUTES); + labelSize->setText(QString("5 minutes")); + break; + case 1: + hashRate->UpdateSampleTime(HashRateGraphWidget::SampleTime::TEN_MINUTES); + labelSize->setText(QString("10 minutes")); + break; + case 2: + hashRate->UpdateSampleTime(HashRateGraphWidget::SampleTime::THIRTY_MINUTES); + labelSize->setText(QString("30 minutes")); + break; + case 3: + hashRate->UpdateSampleTime(HashRateGraphWidget::SampleTime::ONE_HOUR); + labelSize->setText(QString("1 hour")); + break; + case 4: + hashRate->UpdateSampleTime(HashRateGraphWidget::SampleTime::EIGHT_HOURS); + labelSize->setText(QString("8 hours")); + break; + case 5: + hashRate->UpdateSampleTime(HashRateGraphWidget::SampleTime::TWELVE_HOURS); + labelSize->setText(QString("12 hours")); + break; + case 6: + hashRate->UpdateSampleTime(HashRateGraphWidget::SampleTime::ONE_DAY); + labelSize->setText(QString("1 day")); + break; + default: + hashRate->UpdateSampleTime(HashRateGraphWidget::SampleTime::ONE_DAY); + labelSize->setText(QString("1 day")); + break; } } -void MiningPage::clearHashRateData() +void MiningPage::clearCPUHashRateData() +{ + ui->minerCPUHashRateWidget->clear(); +} + +void MiningPage::clearGPUHashRateData() { - ui->minerHashRateWidget->clear(); -} \ No newline at end of file + ui->minerGPUHashRateWidget->clear(); +} diff --git a/src/qt/miningpage.h b/src/qt/miningpage.h index bd84da1568..46d422fd44 100644 --- a/src/qt/miningpage.h +++ b/src/qt/miningpage.h @@ -38,16 +38,25 @@ class MiningPage : public QWidget void timerEvent(QTimerEvent *event); void updateUI(); void StartMiner(); - void StopMiner(); - void showHashMeterControls(bool show); + void StopMiner(bool fGPU); + void showHashMeterControls(bool show, bool fGPU); + void updatePushSwitch(bool fGPU); private Q_SLOTS: - void changeNumberOfCores(int i); - void switchMining(); - void showHashRate(int i); - void changeSampleTime(int i); - void clearHashRateData(); + void changeNumberOfCPUThreads(int i); + void changeNumberOfGPUThreads(int i); + void switchMining(bool fGPU); + void switchCPUMining(); + void switchGPUMining(); + void showCPUHashRate(int i); + void showGPUHashRate(int i); + void showHashRate(int i, bool fGPU); + void changeCPUSampleTime(int i); + void changeGPUSampleTime(int i); + void changeSampleTime(int i, bool fGPU); + void clearCPUHashRateData(); + void clearGPUHashRateData(); }; #endif // MININGPAGE_H diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 54bdc8878b..2b65dbfa5e 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -295,15 +295,16 @@ UniValue generatetoaddress(const JSONRPCRequest& request) UniValue setgenerate(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) + if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "setgenerate generate ( genproclimit )\n" + "setgenerate generate genproclimit (genproclimit-gpu)\n" "\nSet 'generate' true or false to turn generation on or off.\n" "Generation is limited to 'genproclimit' processors, -1 is unlimited.\n" "See the getgenerate call for the current setting.\n" "\nArguments:\n" "1. generate (boolean, required) Set to true to turn on generation, false to turn off.\n" "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" + "3. genproclimit-gpu (numeric, optional) Set the GPU thread limit for when generation is on. Can be -1 for unlimited.\n" "\nExamples:\n" "\nSet the generation on with a limit of one processor\n" + HelpExampleCli("setgenerate", "true 1") + @@ -322,17 +323,21 @@ UniValue setgenerate(const JSONRPCRequest& request) if (request.params.size() > 0) fGenerate = request.params[0].get_bool(); - int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS); + int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS_CPU); if (request.params.size() > 1) - { nGenProcLimit = request.params[1].get_int(); - if (nGenProcLimit == 0) - fGenerate = false; - } + + int nGenProcLimitGPU = GetArg("-genproclimit-gpu", DEFAULT_GENERATE_THREADS_GPU); + if (request.params.size() > 1) + nGenProcLimitGPU = request.params[2].get_int(); + + if (nGenProcLimit == 0 && nGenProcLimitGPU == 0) + fGenerate = false; GetArg("-gen", "") = (fGenerate ? "1" : "0"); GetArg("-genproclimit", "") = itostr(nGenProcLimit); - GenerateDynamics(fGenerate, nGenProcLimit, Params(), *g_connman); + GetArg("-genproclimit-gpu", "") = itostr(nGenProcLimitGPU); + GenerateDynamics(nGenProcLimit, nGenProcLimitGPU, Params(), *g_connman); return NullUniValue; } @@ -351,9 +356,43 @@ UniValue gethashespersec(const JSONRPCRequest& request) + HelpExampleRpc("gethashespersec", "") ); - if (GetTimeMillis() - nHPSTimerStart > 8000) - return (int64_t)0; - return (int64_t)dHashesPerSec; + return GetHashRate(); +} + + +UniValue getcpuhashespersec(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 0) + throw std::runtime_error( + "getcpuhashespersec\n" + "\nReturns a recent CPU hashes per second performance measurement while generating.\n" + "See the getgenerate and setgenerate calls to turn generation on and off.\n" + "\nResult:\n" + "n (numeric) The recent CPU hashes per second when generation is on (will return 0 if generation is off)\n" + "\nExamples:\n" + + HelpExampleCli("getcpuhashespersec", "") + + HelpExampleRpc("getcpuhashespersec", "") + ); + + return GetCPUHashRate(); +} + + +UniValue getgpuhashespersec(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 0) + throw std::runtime_error( + "getgpuhashespersec\n" + "\nReturns a recent GPU hashes per second performance measurement while generating.\n" + "See the getgenerate and setgenerate calls to turn generation on and off.\n" + "\nResult:\n" + "n (numeric) The recent GPU hashes per second when generation is on (will return 0 if generation is off)\n" + "\nExamples:\n" + + HelpExampleCli("getgpuhashespersec", "") + + HelpExampleRpc("getgpuhashespersec", "") + ); + + return GetGPUHashRate(); } UniValue getmininginfo(const JSONRPCRequest& request) @@ -373,6 +412,9 @@ UniValue getmininginfo(const JSONRPCRequest& request) " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" " \"pooledtx\": n (numeric) The size of the mempool\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" + " \"hashespersec\": n (numeric) The recent hashes per second when generation is on (will return 0 if generation is off)\n" + " \"cpuhashespersec\": n (numeric) The recent CPU hashes per second when generation is on (will return 0 if generation is off)\n" + " \"gpuhashespersec\": n (numeric) The recent GPU hashes per second when generation is on (will return 0 if generation is off)\n" "}\n" "\nExamples:\n" + HelpExampleCli("getmininginfo", "") @@ -388,12 +430,15 @@ UniValue getmininginfo(const JSONRPCRequest& request) obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); - obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS))); + obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS_CPU))); + obj.push_back(Pair("genproclimit-gpu", (int)GetArg("-genproclimit-gpu", DEFAULT_GENERATE_THREADS_GPU))); obj.push_back(Pair("networkhashps", getnetworkhashps(request))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("generate", getgenerate(request))); obj.push_back(Pair("hashespersec", gethashespersec(request))); + obj.push_back(Pair("cpuhashespersec", getcpuhashespersec(request))); + obj.push_back(Pair("gpuhashespersec", getgpuhashespersec(request))); return obj; } @@ -1096,6 +1141,8 @@ static const CRPCCommand commands[] = { "generating", "generate", &generate, true }, { "generating", "generatetoaddress", &generatetoaddress, true }, { "generating", "gethashespersec", &gethashespersec, true }, + { "generating", "getcpuhashespersec", &getcpuhashespersec, true }, + { "generating", "getgpuhashespersec", &getgpuhashespersec, true }, { "util", "estimatefee", &estimatefee, true }, { "util", "estimatepriority", &estimatepriority, true }, @@ -1108,4 +1155,3 @@ void RegisterMiningRPCCommands(CRPCTable &tableRPC) for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); } - diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 1c78792aff..87cad5bf10 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -74,6 +74,31 @@ bool TestSequenceLocks(const CTransaction &tx, int flags) return CheckSequenceLocks(tx, flags); } + +#ifdef ENABLE_GPU +#include "miner-gpu.h" + +BOOST_AUTO_TEST_CASE(GetHashGPU_check) +{ + Argon2Context global; + auto& devices = global.getAllDevices(); + auto& device = devices[0]; + ProgramContext progCtx(&global, {device}, argon2::ARGON2_D, argon2::ARGON2_VERSION_10); + Argon2Params params((std::size_t)OUTPUT_BYTES, 2, 500, 8); + ProcessingUnit pu(&progCtx, ¶ms, &device, 1, false, false); + + // Random real block (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6) + // With 4 txes + CBlock block; + CDataStream stream(ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), SER_NETWORK, PROTOCOL_VERSION); + stream >> block; + + + BOOST_CHECK(block.GetHash() == GetBlockHashGPU(&block, &pu)); +} +#endif //ENABLE_GPU + + // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { diff --git a/src/txdb.h b/src/txdb.h index a7fcac2118..420a32c035 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -24,10 +24,8 @@ class CBlockIndex; class CCoinsViewDBCursor; class uint256; - //! Compensate for extra memory peak (x1.5-x1.9) at flush time. -static constexpr int DB_PEAK_USAGE_FACTOR = 2; //! No need to periodic flush if at least this much space still available. -static constexpr int MAX_BLOCK_COINSDB_USAGE = 10 * DB_PEAK_USAGE_FACTOR; +static constexpr int MAX_BLOCK_COINSDB_USAGE = 10; //! -dbcache default (MiB) static const int64_t nDefaultDbCache = 512; //! max. -dbcache (MiB) diff --git a/src/validation.cpp b/src/validation.cpp index 2d62a5af62..e946cbcdc2 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -85,7 +85,7 @@ bool fRequireStandard = true; unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; bool fCheckBlockIndex = false; bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; -int64_t nCoinCacheUsage = 5000 * 300; +size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; bool fAlerts = DEFAULT_ALERTS; bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; @@ -2355,12 +2355,12 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { nLastSetChain = nNow; } int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; - int64_t cacheSize = pcoinsTip->DynamicMemoryUsage() * DB_PEAK_USAGE_FACTOR; + int64_t cacheSize = pcoinsTip->DynamicMemoryUsage(); int64_t nTotalSpace = nCoinCacheUsage + std::max(nMempoolSizeMax - nMempoolUsage, 0); // The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing). bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024); // The cache is over the limit, we have to write now. - bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage; + bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nTotalSpace; // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. diff --git a/src/validation.h b/src/validation.h index 3bdff08052..ac9a32fbcb 100644 --- a/src/validation.h +++ b/src/validation.h @@ -182,7 +182,7 @@ extern bool fRequireStandard; extern unsigned int nBytesPerSigOp; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; -extern int64_t nCoinCacheUsage; +extern size_t nCoinCacheUsage; /** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */ extern CFeeRate minRelayTxFee; /** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */ From 03259a3c225f072bf1016c7865c0296164ae32d6 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Wed, 4 Jul 2018 04:49:22 +0200 Subject: [PATCH 0026/1653] [GPU] Fix GenerateDynamics and DynamicMiner - fix cpu thread loop so it doesn't lookup a gpu device - change miner-gpu header to build with OpenCL - still need to define HAVE_CUDA in configure if CUDA installed --- src/miner-gpu.h | 17 ++++++------ src/miner.cpp | 71 ++++++++++++++++++++++++++++------------------- src/rpcmining.cpp | 9 ++++-- 3 files changed, 58 insertions(+), 39 deletions(-) diff --git a/src/miner-gpu.h b/src/miner-gpu.h index 9b752508ea..204dfa1007 100644 --- a/src/miner-gpu.h +++ b/src/miner-gpu.h @@ -4,26 +4,27 @@ #define DYNAMIC_ARGON2_GPU #ifdef ENABLE_GPU -#define HAVE_CUDA 1 -#define ARGON2_GPU_CUDA cuda -#define ARGON2_GPU_OPENCL opencl - -#define ARGON2_GPU ARGON2_GPU_CUDA +#define HAVE_CUDA #include + +#include "argon2-gpu/common.h" +#ifndef HAVE_CUDA #include "argon2-cuda/cuda-exception.h" #include "argon2-cuda/processing-unit.h" -#include "argon2-gpu/common.h" +#else +#include "argon2-opencl/opencl.h" #include "argon2-opencl/processing-unit.h" +#endif using Argon2GPUParams = argon2gpu::Argon2Params; -#if ARGON2_GPU == ARGON2_GPU_CUDA +#ifndef HAVE_CUDA using Argon2GPU = argon2gpu::cuda::ProcessingUnit; using Argon2GPUDevice = argon2gpu::cuda::Device; using Argon2GPUContext = argon2gpu::cuda::GlobalContext; using Argon2GPUProgramContext = argon2gpu::cuda::ProgramContext; -#elif ARGON2_GPU == ARGON2_GPU_OPENCL +#else using Argon2GPU = argon2gpu::opencl::ProcessingUnit; using Argon2GPUDevice = argon2gpu::opencl::Device; using Argon2GPUContext = argon2gpu::opencl::GlobalContext; diff --git a/src/miner.cpp b/src/miner.cpp index 47704ac1ce..0d096d03f9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -503,30 +503,45 @@ static void WaitForNetworkInit(const CChainParams& chainparams, CConnman& connma } } -// TODO: that part changed in bitcoin, we are using a mix with old one here for now -static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex, bool fGPU) -{ +#ifdef ENABLE_GPU +static Argon2GPU GetProcessingUnit(std::size_t nDeviceIndex, bool fGPU) { + if (!fGPU) { + Argon2GPU processingUnit(nullptr, nullptr, nullptr, 1, false, false); + return processingUnit; + } + else { + // Argon2GPU processingUnit = GetGPUProcessingUnit(nDeviceIndex); + Argon2GPUContext global; + auto& devices = global.getAllDevices(); + auto& device = devices[nDeviceIndex]; + Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); + Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); + Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); + return processingUnit; + } +} +#endif // ENABLE_GPU + +static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex, bool fGPU) { + std::string dev = fGPU ? "GPU" : "CPU"; LogPrintf("DynamicMiner -- started #%u@%s\n", nDeviceIndex, dev); SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread("dynamic-miner"); + if (fGPU) { + RenameThread("dynamic-gpu-miner"); + } + else { + RenameThread("dynamic-cpu-miner"); + } double* dHashesPerSec = fGPU ? &dGPUHashesPerSec : &dCPUHashesPerSec; unsigned int nExtraNonce = 0; boost::shared_ptr coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); - #ifdef ENABLE_GPU - // Argon2GPU processingUnit = GetGPUProcessingUnit(nDeviceIndex); - Argon2GPUContext global; - auto& devices = global.getAllDevices(); - auto& device = devices[nDeviceIndex]; - Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); - Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); - Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); + Argon2GPU processingUnit = GetProcessingUnit(nDeviceIndex, fGPU); #endif // ENABLE_GPU - try { // Throw an error if no script was provided. This can happen // due to some internal error but also if the keypool is empty. @@ -572,15 +587,13 @@ static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std uint256 hash; while (true) { #ifdef ENABLE_GPU - if (fGPU) { + if (fGPU) hash = GetBlockHashGPU(pblock, &processingUnit); - } else { + else hash = pblock->GetHash(); - } #else hash = pblock->GetHash(); #endif // ENABLE_GPU - if (UintToArith256(hash) <= hashTarget) { // Found a solution @@ -770,9 +783,9 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai if (fAutotune) { return GenerateDynamicsAutoTune(chainparams, connman); } - - std::size_t devices = GetGPUDeviceCount(); + std::size_t devices = 0; #ifdef ENABLE_GPU + devices = GetGPUDeviceCount(); LogPrintf("DynamicMiner -- GPU Devices: %u\n", devices); #else LogPrintf("DynamicMiner -- GPU no support\n"); @@ -783,29 +796,29 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai return; } - boost::thread_group* minerThreads = GetCPUMinerThreads(); + boost::thread_group* cpuMinerThreads = GetCPUMinerThreads(); if (nCPUThreads < 0) nCPUThreads = GetNumCores(); // Start CPU threads - while (minerThreads->size() < nCPUThreads) { - std::size_t nThread = minerThreads->size(); + while (cpuMinerThreads->size() < nCPUThreads) { + std::size_t nThread = cpuMinerThreads->size() -1; LogPrintf("Starting CPU Miner thread #%u\n", nThread); - minerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), nThread, false)); + cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), nThread, false)); } if (nGPUThreads < 0) nGPUThreads = 1; // Start GPU threads - minerThreads = GetGPUMinerThreads(); - for (std::size_t device = 0; device < devices; device++) { - for (int i = 0; i < nGPUThreads; i++) { - LogPrintf("Starting GPU Miner thread %u on device %u\n", i, device); - minerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), device, true)); + boost::thread_group* gpuMinerThreads = GetGPUMinerThreads(); + //for (std::size_t device = 0; device < devices; device++) { + for (std::size_t i = 0; i < nGPUThreads || i < devices; i++) { + LogPrintf("Starting GPU Miner thread %u on device %u\n", i, i); + gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), i, true)); } - } + //} } void ShutdownCPUMiners() diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 2b65dbfa5e..e77e603baf 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -306,8 +306,12 @@ UniValue setgenerate(const JSONRPCRequest& request) "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" "3. genproclimit-gpu (numeric, optional) Set the GPU thread limit for when generation is on. Can be -1 for unlimited.\n" "\nExamples:\n" - "\nSet the generation on with a limit of one processor\n" + "\nSet the generation on with a limit of one CPU processor\n" + HelpExampleCli("setgenerate", "true 1") + +#if ENABLE_GPU + "\nSet the generation on with a limit of one GPU\n" + + HelpExampleCli("setgenerate", "true 0 1") + +#endif "\nCheck the setting\n" + HelpExampleCli("getgenerate", "") + "\nTurn off generation\n" @@ -328,7 +332,7 @@ UniValue setgenerate(const JSONRPCRequest& request) nGenProcLimit = request.params[1].get_int(); int nGenProcLimitGPU = GetArg("-genproclimit-gpu", DEFAULT_GENERATE_THREADS_GPU); - if (request.params.size() > 1) + if (request.params.size() > 2) nGenProcLimitGPU = request.params[2].get_int(); if (nGenProcLimit == 0 && nGenProcLimitGPU == 0) @@ -337,6 +341,7 @@ UniValue setgenerate(const JSONRPCRequest& request) GetArg("-gen", "") = (fGenerate ? "1" : "0"); GetArg("-genproclimit", "") = itostr(nGenProcLimit); GetArg("-genproclimit-gpu", "") = itostr(nGenProcLimitGPU); + LogPrintf("setgenerate cpu = %u, gpu = %u \n", nGenProcLimit, nGenProcLimitGPU); GenerateDynamics(nGenProcLimit, nGenProcLimitGPU, Params(), *g_connman); return NullUniValue; From de64c096858a9f6699064ec25b43dbc23882717b Mon Sep 17 00:00:00 2001 From: crackcomm Date: Sun, 8 Jul 2018 10:13:06 +0200 Subject: [PATCH 0027/1653] [GPU] Build autoconf script --- configure.ac | 35 +- contrib/argon2-gpu/CMakeLists.txt | 119 ---- contrib/argon2-gpu/LICENSE | 22 - contrib/argon2-gpu/src/argon2-gpu/empty.cpp | 18 - src/Makefile.am | 16 +- src/Makefile.gpu.include | 57 ++ src/Makefile.qt.include | 2 +- src/Makefile.qttest.include | 3 + src/Makefile.test.include | 3 + .../crypto/argon2gpu}/blake2b.cpp | 36 +- .../crypto/argon2gpu}/blake2b.h | 0 .../crypto/argon2gpu}/common.cpp | 88 ++- .../crypto/argon2gpu}/common.h | 7 +- .../crypto/argon2gpu/cuda}/cuda-exception.h | 0 .../crypto/argon2gpu/cuda}/device.cpp | 5 +- .../crypto/argon2gpu/cuda}/device.h | 0 .../crypto/argon2gpu/cuda}/global-context.cpp | 8 +- .../crypto/argon2gpu/cuda}/global-context.h | 2 +- .../crypto/argon2gpu/cuda}/kernels.cu | 621 +++++++----------- .../crypto/argon2gpu/cuda}/kernels.h | 0 .../argon2gpu/cuda}/processing-unit.cpp | 70 +- .../crypto/argon2gpu/cuda}/processing-unit.h | 50 +- .../argon2gpu/cuda}/program-context.cpp | 12 +- .../crypto/argon2gpu/cuda}/program-context.h | 35 +- .../crypto/argon2gpu/opencl}/cl.hpp | 0 .../crypto/argon2gpu/opencl}/device.cpp | 35 +- .../crypto/argon2gpu/opencl}/device.h | 17 +- .../argon2gpu/opencl}/global-context.cpp | 16 +- .../crypto/argon2gpu/opencl}/global-context.h | 9 +- .../argon2gpu/opencl}/kernel-loader.cpp | 26 +- .../crypto/argon2gpu/opencl}/kernel-loader.h | 13 +- .../argon2gpu/opencl}/kernel-runner.cpp | 86 +-- .../crypto/argon2gpu/opencl}/kernel-runner.h | 30 +- .../crypto/argon2gpu/opencl}/kernel.cl | 0 .../crypto/argon2gpu/opencl}/opencl.h | 2 +- .../argon2gpu/opencl}/processing-unit.cpp | 63 +- .../argon2gpu/opencl}/processing-unit.h | 28 +- .../argon2gpu/opencl}/program-context.cpp | 17 +- .../argon2gpu/opencl}/program-context.h | 26 +- src/miner-gpu.h | 43 +- src/miner.cpp | 21 +- src/net_processing.cpp | 44 +- src/test/miner_tests.cpp | 27 +- src/validation.cpp | 17 +- src/validation.h | 2 +- 45 files changed, 736 insertions(+), 995 deletions(-) delete mode 100644 contrib/argon2-gpu/CMakeLists.txt delete mode 100644 contrib/argon2-gpu/LICENSE delete mode 100644 contrib/argon2-gpu/src/argon2-gpu/empty.cpp create mode 100644 src/Makefile.gpu.include rename {contrib/argon2-gpu/src/argon2-gpu => src/crypto/argon2gpu}/blake2b.cpp (88%) rename {contrib/argon2-gpu/include/argon2-gpu => src/crypto/argon2gpu}/blake2b.h (100%) rename {contrib/argon2-gpu/src/argon2-gpu => src/crypto/argon2gpu}/common.cpp (77%) rename {contrib/argon2-gpu/include/argon2-gpu => src/crypto/argon2gpu}/common.h (96%) rename {contrib/argon2-gpu/include/argon2-cuda => src/crypto/argon2gpu/cuda}/cuda-exception.h (100%) rename {contrib/argon2-gpu/src/argon2-cuda => src/crypto/argon2gpu/cuda}/device.cpp (93%) rename {contrib/argon2-gpu/include/argon2-cuda => src/crypto/argon2gpu/cuda}/device.h (100%) rename {contrib/argon2-gpu/src/argon2-cuda => src/crypto/argon2gpu/cuda}/global-context.cpp (88%) rename {contrib/argon2-gpu/include/argon2-cuda => src/crypto/argon2gpu/cuda}/global-context.h (96%) rename {contrib/argon2-gpu/src/argon2-cuda => src/crypto/argon2gpu/cuda}/kernels.cu (69%) rename {contrib/argon2-gpu/include/argon2-cuda => src/crypto/argon2gpu/cuda}/kernels.h (100%) rename {contrib/argon2-gpu/src/argon2-cuda => src/crypto/argon2gpu/cuda}/processing-unit.cpp (78%) rename {contrib/argon2-gpu/include/argon2-cuda => src/crypto/argon2gpu/cuda}/processing-unit.h (62%) rename {contrib/argon2-gpu/src/argon2-cuda => src/crypto/argon2gpu/cuda}/program-context.cpp (82%) rename {contrib/argon2-gpu/include/argon2-cuda => src/crypto/argon2gpu/cuda}/program-context.h (71%) rename {contrib/argon2-gpu/include/argon2-opencl => src/crypto/argon2gpu/opencl}/cl.hpp (100%) rename {contrib/argon2-gpu/src/argon2-opencl => src/crypto/argon2gpu/opencl}/device.cpp (93%) rename {contrib/argon2-gpu/include/argon2-opencl => src/crypto/argon2gpu/opencl}/device.h (82%) rename {contrib/argon2-gpu/src/argon2-opencl => src/crypto/argon2gpu/opencl}/global-context.cpp (81%) rename {contrib/argon2-gpu/include/argon2-opencl => src/crypto/argon2gpu/opencl}/global-context.h (89%) rename {contrib/argon2-gpu/src/argon2-opencl => src/crypto/argon2gpu/opencl}/kernel-loader.cpp (85%) rename {contrib/argon2-gpu/include/argon2-opencl => src/crypto/argon2gpu/opencl}/kernel-loader.h (83%) rename {contrib/argon2-gpu/src/argon2-opencl => src/crypto/argon2gpu/opencl}/kernel-runner.cpp (78%) rename {contrib/argon2-gpu/include/argon2-opencl => src/crypto/argon2gpu/opencl}/kernel-runner.h (75%) rename {contrib/argon2-gpu/src/argon2-opencl => src/crypto/argon2gpu/opencl}/kernel.cl (100%) rename {contrib/argon2-gpu/include/argon2-opencl => src/crypto/argon2gpu/opencl}/opencl.h (96%) rename {contrib/argon2-gpu/src/argon2-opencl => src/crypto/argon2gpu/opencl}/processing-unit.cpp (78%) rename {contrib/argon2-gpu/include/argon2-opencl => src/crypto/argon2gpu/opencl}/processing-unit.h (72%) rename {contrib/argon2-gpu/src/argon2-opencl => src/crypto/argon2gpu/opencl}/program-context.cpp (78%) rename {contrib/argon2-gpu/include/argon2-opencl => src/crypto/argon2gpu/opencl}/program-context.h (70%) diff --git a/configure.ac b/configure.ac index f44ab58134..fecc7cc41c 100644 --- a/configure.ac +++ b/configure.ac @@ -98,6 +98,11 @@ AC_ARG_ENABLE([gpu], [enable_gpu=$enableval], [enable_gpu=yes]) +AC_ARG_WITH([cuda], + [AS_HELP_STRING([--with-cuda],[prefix of the CUDA installation, e.g. /usr/local/cuda])], + [cuda_prefix=$withval], + [cuda_prefix="/usr/local/cuda"]) + AC_ARG_WITH([miniupnpc], [AS_HELP_STRING([--with-miniupnpc], [enable UPNP (default is yes if libminiupnpc is found)])], @@ -266,14 +271,6 @@ AC_ARG_WITH([daemon], [build_dynamicd=$withval], [build_dynamicd=yes]) -# AC_ARG_WITH([gpu], -# [AS_HELP_STRING([--enable-gpu], -# [enable GPU optimizations (defaults is yes)])], -# AC_SUBST(HAVE_CUDA, 1), -# AC_SUBST(ENABLE_GPU, 1), -# [have_gpu=${enableval}], -# [have_gpu=yes]) - use_pkgconfig=yes case $host in *mingw*) @@ -942,6 +939,27 @@ else fi AC_DEFINE_UNQUOTED([ENABLE_GPU],[1],[Define to 1 to enable gpu functions]) +AC_DEFINE_UNQUOTED([HAVE_CUDA],[1],[Define to 1 to enable CUDA]) + +dnl Checking for nvcc +AC_MSG_CHECKING([nvcc in $cuda_prefix/bin]) +if test -x "$cuda_prefix/bin/nvcc"; then + AC_MSG_RESULT([found]) + AC_SUBST(HAVE_CUDA, 1) + AC_DEFINE_UNQUOTED([NVCC_PATH], ["$cuda_prefix/bin/nvcc"], [path to nvcc binary]) + HAVE_CUDA="1" + CUDA_CFLAGS="-I$cuda_prefix/include" + CUDA_LDFLAGS="-L$cuda_prefix/lib64 -L/usr/lib/x86_64-linux-gnu" + CUDA_NVCC_FLAGS="$CUDA_NVCC_FLAGS;-std=c++11;-O3;--ptxas-options=-v;-arch sm_30;-lineinfo" +else + AC_MSG_RESULT([not found!]) + AC_MSG_WARN([nvcc was not found in $cuda_prefix/bin]) +fi + +dnl if cuda has been found check the header and the lib +if test "$HAVE_CUDA" == "1"; then + AC_CHECK_HEADER([cuda_runtime.h],, AC_MSG_ERROR(libcuda headers missing),) +fi dnl enable upnp support AC_MSG_CHECKING([whether to build with support for UPnP]) @@ -1048,6 +1066,7 @@ AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reo AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) AM_CONDITIONAL([ENABLE_SSE42],[test x$enable_sse42 = xyes]) +AM_CONDITIONAL([HAVE_CUDA], [test "${HAVE_CUDA}" = "1"]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) diff --git a/contrib/argon2-gpu/CMakeLists.txt b/contrib/argon2-gpu/CMakeLists.txt deleted file mode 100644 index 0247c71e44..0000000000 --- a/contrib/argon2-gpu/CMakeLists.txt +++ /dev/null @@ -1,119 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -project(argon2-gpu CXX) -set(BINARY_INSTALL_DIR /usr/local/bin) -set(LIBRARY_INSTALL_DIR /usr/local/lib) -set(INCLUDE_INSTALL_DIR /usr/local/include) -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -enable_testing() - -set(CUDA_FOUND FALSE) - -if(NOT NO_CUDA) - find_package(CUDA) -endif() - -if(CUDA_FOUND) - message("INFO: Using CUDA version ${CUDA_VERSION}") - add_definitions(-DHAVE_CUDA=1) -else() - message("INFO: Building without CUDA support") - add_definitions(-DHAVE_CUDA=0) -endif() - -if(CUDA_FOUND) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS}; - -std=c++11;-O3;--ptxas-options=-v;-arch sm_30;-lineinfo - ) -endif() - -add_library(argon2-gpu SHARED - src/argon2-gpu/common.cpp - src/argon2-gpu/blake2b.cpp -) -target_include_directories(argon2-gpu INTERFACE - $ - $ -) -target_include_directories(argon2-gpu PRIVATE - include/ - src/argon2-gpu -) - -if(CUDA_FOUND) - cuda_add_library(argon2-cuda SHARED - src/argon2-cuda/device.cpp - src/argon2-cuda/global-context.cpp - src/argon2-cuda/kernels.cu - src/argon2-cuda/processing-unit.cpp - src/argon2-cuda/program-context.cpp - ) -else() - add_library(argon2-cuda SHARED - src/argon2-gpu/empty.cpp - ) -endif() - -target_include_directories(argon2-cuda PRIVATE - include/ - src/argon2-cuda -) -target_include_directories(argon2-cuda INTERFACE - $ - $ -) -target_link_libraries(argon2-cuda argon2-gpu) - -add_library(argon2-opencl SHARED - src/argon2-opencl/device.cpp - src/argon2-opencl/global-context.cpp - src/argon2-opencl/kernel-loader.cpp - src/argon2-opencl/kernel-runner.cpp - src/argon2-opencl/processing-unit.cpp - src/argon2-opencl/program-context.cpp -) -target_include_directories(argon2-opencl INTERFACE - $ - $ -) -target_include_directories(argon2-opencl PRIVATE - include/argon2-opencl - src/argon2-opencl -) -if (APPLE) - target_link_libraries(argon2-opencl argon2-gpu "-framework OpenCL") -else() - target_link_libraries(argon2-opencl argon2-gpu) -endif(APPLE) -install( - TARGETS argon2-gpu argon2-opencl argon2-cuda - DESTINATION ${LIBRARY_INSTALL_DIR} -) -install(FILES - include/argon2-cuda/cuda-exception.h - include/argon2-cuda/device.h - include/argon2-cuda/global-context.h - include/argon2-cuda/kernels.h - include/argon2-cuda/processing-unit.h - include/argon2-cuda/program-context.h - DESTINATION ${INCLUDE_INSTALL_DIR}/argon2-cuda -) - -install(FILES - include/argon2-gpu/blake2b.h - include/argon2-gpu/common.h - DESTINATION ${INCLUDE_INSTALL_DIR}/argon2-gpu -) - -install(FILES - include/argon2-opencl/cl.hpp - include/argon2-opencl/device.h - include/argon2-opencl/global-context.h - include/argon2-opencl/kernel-loader.h - include/argon2-opencl/kernel-runner.h - include/argon2-opencl/opencl.h - include/argon2-opencl/processing-unit.h - include/argon2-opencl/program-context.h - DESTINATION ${INCLUDE_INSTALL_DIR}/argon2-opencl -) diff --git a/contrib/argon2-gpu/LICENSE b/contrib/argon2-gpu/LICENSE deleted file mode 100644 index 48f0970194..0000000000 --- a/contrib/argon2-gpu/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2017-2018 Łukasz Kurowski -Copyright (c) 2016 Ondrej Mosnáček - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/contrib/argon2-gpu/src/argon2-gpu/empty.cpp b/contrib/argon2-gpu/src/argon2-gpu/empty.cpp deleted file mode 100644 index d2eb12753b..0000000000 --- a/contrib/argon2-gpu/src/argon2-gpu/empty.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2015-2018 Łukasz Kurowski , Ondrej Mosnacek - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation: either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// Used when there is no CUDA available diff --git a/src/Makefile.am b/src/Makefile.am index fbed49a237..55e62d59d0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,6 @@ EXTRA_LIBRARIES = DYNAMIC_CONFIG_INCLUDES=-I$(builddir)/config DYNAMIC_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) -DYNAMIC_INCLUDES += -I$(top_srcdir)/contrib/argon2-gpu/include -I/usr/local/cuda-9.2/include DYNAMIC_INCLUDES += -I$(srcdir)/secp256k1/include DYNAMIC_INCLUDES += -I$(srcdir)/univalue/include @@ -22,12 +21,6 @@ LIBDYNAMICQT=qt/libdynamicqt.a LIBSECP256K1=secp256k1/libsecp256k1.la LIBUNIVALUE=univalue/libunivalue.la -argon2GPULIBS = \ - -largon2 \ - -largon2-gpu \ - -largon2-opencl \ - -largon2-cuda - $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) @@ -294,7 +287,6 @@ libdynamic_zmq_a_SOURCES = \ zmq/zmqpublishnotifier.cpp endif - # wallet: shared between dynamicd and dynamic-qt, but only linked # when wallet enabled libdynamic_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) @@ -444,10 +436,6 @@ if ENABLE_WALLET dynamicd_LDADD += libdynamic_wallet.a endif -if ENABLE_GPU -dynamicd_LDADD += -L/usr/local/cuda-9.2/lib64 -L/usr/lib/x86_64-linux-gnu -lOpenCL $(argon2GPULIBS) -endif - dynamicd_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) # dynamic-cli binary # @@ -570,6 +558,10 @@ if EMBEDDED_LEVELDB include Makefile.leveldb.include endif +if ENABLE_GPU +include Makefile.gpu.include +endif + if ENABLE_TESTS include Makefile.test.include endif diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include new file mode 100644 index 0000000000..88da792e0e --- /dev/null +++ b/src/Makefile.gpu.include @@ -0,0 +1,57 @@ +# +# Argon2 GPU miner +# + +LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a + +DYNAMIC_INCLUDES += $(CUDA_CFLAGS) +EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) + +LIBDYNAMIC_GPU_LDADD = $(CUDA_LDFLAGS) $(LIBDYNAMIC_GPU) + +if TARGET_DARWIN + LIBDYNAMIC_GPU_LDADD += "-framework OpenCL" +else + LIBDYNAMIC_GPU_LDADD += -lOpenCL +endif + +crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) +crypto_argon2gpu_libdynamic_gpu_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_argon2gpu_libdynamic_gpu_a_SOURCES = \ + crypto/argon2gpu/blake2b.h \ + crypto/argon2gpu/common.h \ + crypto/argon2gpu/common.cpp \ + crypto/argon2gpu/blake2b.cpp + +if HAVE_CUDA + crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ + crypto/argon2gpu/cuda/cuda-exception.h \ + crypto/argon2gpu/cuda/device.h \ + crypto/argon2gpu/cuda/global-context.h \ + crypto/argon2gpu/cuda/kernels.h \ + crypto/argon2gpu/cuda/processing-unit.h \ + crypto/argon2gpu/cuda/program-context.h \ + crypto/argon2gpu/cuda/device.cpp \ + crypto/argon2gpu/cuda/global-context.cpp \ + crypto/argon2gpu/cuda/kernels.cu \ + crypto/argon2gpu/cuda/processing-unit.cpp \ + crypto/argon2gpu/cuda/program-context.cpp +else + crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ + crypto/argon2gpu/opencl/cl.hpp \ + crypto/argon2gpu/opencl/device.h \ + crypto/argon2gpu/opencl/global-context.h \ + crypto/argon2gpu/opencl/kernel-loader.h \ + crypto/argon2gpu/opencl/kernel-runner.h \ + crypto/argon2gpu/opencl/opencl.h \ + crypto/argon2gpu/opencl/processing-unit.h \ + crypto/argon2gpu/opencl/program-context.h \ + crypto/argon2gpu/opencl/device.cpp \ + crypto/argon2gpu/opencl/global-context.cpp \ + crypto/argon2gpu/opencl/kernel-loader.cpp \ + crypto/argon2gpu/opencl/kernel-runner.cpp \ + crypto/argon2gpu/opencl/processing-unit.cpp \ + crypto/argon2gpu/opencl/program-context.cpp +endif + +dynamicd_LDADD += $(LIBDYNAMIC_GPU_LDADD) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 7cf9b99dd7..31b174f675 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -370,7 +370,7 @@ if ENABLE_WALLET qt_dynamic_qt_LDADD += $(LIBDYNAMIC_WALLET) endif if ENABLE_GPU -qt_dynamic_qt_LDADD += -L/usr/local/cuda-9.2/lib64 -L/usr/lib/x86_64-linux-gnu -lOpenCL $(argon2GPULIBS) +qt_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD) endif if ENABLE_ZMQ qt_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 39a616a8a1..a6a4cab4b6 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -43,6 +43,9 @@ endif if ENABLE_ZMQ qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif +if ENABLE_GPU +qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD) +endif qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c8222f3447..d591076592 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -121,6 +121,9 @@ test_test_dynamic_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -s if ENABLE_ZMQ test_test_dynamic_LDADD += $(ZMQ_LIBS) endif +if ENABLE_GPU +test_test_dynamic_LDADD += $(LIBDYNAMIC_GPU_LDADD) +endif nodist_test_test_dynamic_SOURCES = $(GENERATED_TEST_FILES) diff --git a/contrib/argon2-gpu/src/argon2-gpu/blake2b.cpp b/src/crypto/argon2gpu/blake2b.cpp similarity index 88% rename from contrib/argon2-gpu/src/argon2-gpu/blake2b.cpp rename to src/crypto/argon2gpu/blake2b.cpp index a0f04ed899..5e2f649567 100644 --- a/contrib/argon2-gpu/src/argon2-gpu/blake2b.cpp +++ b/src/crypto/argon2gpu/blake2b.cpp @@ -15,13 +15,12 @@ * along with this program. If not, see . */ -#include "argon2-gpu/blake2b.h" +#include "crypto/argon2gpu/blake2b.h" #include namespace argon2gpu { - static const std::uint64_t blake2b_IV[8] = { UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), @@ -46,8 +45,7 @@ static const unsigned int blake2b_sigma[12][16] = { #define rotr64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) #define G(m, r, i, a, b, c, d) \ - do \ - { \ + do { \ a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ d = rotr64(d ^ a, 32); \ c = c + d; \ @@ -59,8 +57,7 @@ static const unsigned int blake2b_sigma[12][16] = { } while ((void)0, 0) #define ROUND(m, v, r) \ - do \ - { \ + do { \ G(m, r, 0, v[0], v[4], v[8], v[12]); \ G(m, r, 1, v[1], v[5], v[9], v[13]); \ G(m, r, 2, v[2], v[6], v[10], v[14]); \ @@ -71,9 +68,9 @@ static const unsigned int blake2b_sigma[12][16] = { G(m, r, 7, v[3], v[4], v[9], v[14]); \ } while ((void)0, 0) -static std::uint64_t load64(const void *src) +static std::uint64_t load64(const void* src) { - auto in = static_cast(src); + auto in = static_cast(src); std::uint64_t res = *in++; res |= static_cast(*in++) << 8; res |= static_cast(*in++) << 16; @@ -85,9 +82,9 @@ static std::uint64_t load64(const void *src) return res; } -static void store64(void *dst, std::uint64_t v) +static void store64(void* dst, std::uint64_t v) { - auto out = static_cast(dst); + auto out = static_cast(dst); *out++ = static_cast(v); v >>= 8; *out++ = static_cast(v); @@ -116,12 +113,12 @@ void Blake2b::init(std::size_t outlen) (UINT64_C(1) << 16) | (UINT64_C(1) << 24); } -void Blake2b::compress(const void *block, std::uint64_t f0) +void Blake2b::compress(const void* block, std::uint64_t f0) { std::uint64_t m[16]; std::uint64_t v[16]; - auto in = static_cast(block); + auto in = static_cast(block); m[0] = load64(in + 0); m[1] = load64(in + 1); @@ -186,12 +183,11 @@ void Blake2b::incrementCounter(std::uint64_t inc) t[1] += (t[0] < inc); } -void Blake2b::update(const void *in, std::size_t inLen) +void Blake2b::update(const void* in, std::size_t inLen) { - auto bin = static_cast(in); + auto bin = static_cast(in); - if (bufLen + inLen > BLOCK_BYTES) - { + if (bufLen + inLen > BLOCK_BYTES) { std::size_t have = bufLen; std::size_t left = BLOCK_BYTES - have; std::memcpy(buf + have, bin, left); @@ -203,8 +199,7 @@ void Blake2b::update(const void *in, std::size_t inLen) inLen -= left; bin += left; - while (inLen > BLOCK_BYTES) - { + while (inLen > BLOCK_BYTES) { incrementCounter(BLOCK_BYTES); compress(bin, 0); inLen -= BLOCK_BYTES; @@ -215,7 +210,7 @@ void Blake2b::update(const void *in, std::size_t inLen) bufLen += inLen; } -void Blake2b::final(void *out, std::size_t outLen) +void Blake2b::final(void* out, std::size_t outLen) { std::uint8_t buffer[OUT_BYTES] = {0}; @@ -223,8 +218,7 @@ void Blake2b::final(void *out, std::size_t outLen) std::memset(buf + bufLen, 0, BLOCK_BYTES - bufLen); compress(buf, UINT64_C(0xFFFFFFFFFFFFFFFF)); - for (unsigned int i = 0; i < 8; i++) - { + for (unsigned int i = 0; i < 8; i++) { store64(buffer + i * sizeof(std::uint64_t), h[i]); } diff --git a/contrib/argon2-gpu/include/argon2-gpu/blake2b.h b/src/crypto/argon2gpu/blake2b.h similarity index 100% rename from contrib/argon2-gpu/include/argon2-gpu/blake2b.h rename to src/crypto/argon2gpu/blake2b.h diff --git a/contrib/argon2-gpu/src/argon2-gpu/common.cpp b/src/crypto/argon2gpu/common.cpp similarity index 77% rename from contrib/argon2-gpu/src/argon2-gpu/common.cpp rename to src/crypto/argon2gpu/common.cpp index 78d690c30a..29e524aee0 100644 --- a/contrib/argon2-gpu/src/argon2-gpu/common.cpp +++ b/src/crypto/argon2gpu/common.cpp @@ -15,11 +15,11 @@ * along with this program. If not, see . */ -#include "argon2-gpu/common.h" -#include "argon2-gpu/blake2b.h" +#include "crypto/argon2gpu/blake2b.h" +#include "crypto/argon2gpu/common.h" -#include #include +#include #include @@ -29,10 +29,9 @@ namespace argon2gpu { - -static void store32(void *dst, std::uint32_t v) +static void store32(void* dst, std::uint32_t v) { - auto out = static_cast(dst); + auto out = static_cast(dst); *out++ = static_cast(v); v >>= 8; *out++ = static_cast(v); @@ -50,23 +49,19 @@ Argon2Params::Argon2Params(std::size_t outLen, std::size_t t_cost, std::size_t m segmentBlocks = std::max(m_cost, 2 * segments) / segments; } -void Argon2Params::digestLong(void *out, std::size_t outLen, - const void *in, std::size_t inLen) +void Argon2Params::digestLong(void* out, std::size_t outLen, const void* in, std::size_t inLen) { - auto bout = static_cast(out); + auto bout = static_cast(out); std::uint8_t outlen_bytes[sizeof(std::uint32_t)]; Blake2b blake; store32(outlen_bytes, static_cast(outLen)); - if (outLen <= Blake2b::OUT_BYTES) - { + if (outLen <= Blake2b::OUT_BYTES) { blake.init(outLen); blake.update(outlen_bytes, sizeof(outlen_bytes)); blake.update(in, inLen); blake.final(out, outLen); - } - else - { + } else { std::uint8_t out_buffer[Blake2b::OUT_BYTES]; blake.init(Blake2b::OUT_BYTES); @@ -78,8 +73,7 @@ void Argon2Params::digestLong(void *out, std::size_t outLen, bout += Blake2b::OUT_BYTES / 2; std::size_t toProduce = outLen - Blake2b::OUT_BYTES / 2; - while (toProduce > Blake2b::OUT_BYTES) - { + while (toProduce > Blake2b::OUT_BYTES) { blake.init(Blake2b::OUT_BYTES); blake.update(out_buffer, Blake2b::OUT_BYTES); blake.final(out_buffer, Blake2b::OUT_BYTES); @@ -96,8 +90,11 @@ void Argon2Params::digestLong(void *out, std::size_t outLen, } void Argon2Params::initialHash( - void *out, const void *input, std::size_t inputLen, - Type type, Version version) const + void* out, + const void* input, + std::size_t inputLen, + Type type, + Version version) const { Blake2b blake; std::uint8_t value[sizeof(std::uint32_t)]; @@ -121,7 +118,7 @@ void Argon2Params::initialHash( blake.update(input, inputLen); store32(value, inputLen); blake.update(value, sizeof(value)); // saltLen - blake.update(input, inputLen); // salt, saltLen + blake.update(input, inputLen); // salt, saltLen store32(value, 0); blake.update(value, sizeof(value)); blake.update(NULL, 0); @@ -133,36 +130,35 @@ void Argon2Params::initialHash( } void Argon2Params::fillFirstBlocks( - void *memory, const void *input, std::size_t inputLen, - Type type, Version version) const + void* memory, + const void* input, + std::size_t inputLen, + Type type, + Version version) const { std::uint8_t initHash[ARGON2_PREHASH_SEED_LENGTH]; initialHash(initHash, input, inputLen, type, version); #ifdef DEBUG std::fprintf(stderr, "Initial hash: "); - for (std::size_t i = 0; i < ARGON2_PREHASH_DIGEST_LENGTH; i++) - { + for (std::size_t i = 0; i < ARGON2_PREHASH_DIGEST_LENGTH; i++) { std::fprintf(stderr, "%02x", (unsigned int)initHash[i]); } std::fprintf(stderr, "\n"); #endif - auto bmemory = static_cast(memory); + auto bmemory = static_cast(memory); store32(initHash + ARGON2_PREHASH_DIGEST_LENGTH, 0); - for (std::uint32_t l = 0; l < lanes; l++) - { + for (std::uint32_t l = 0; l < lanes; l++) { store32(initHash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); digestLong(bmemory, ARGON2_BLOCK_SIZE, initHash, sizeof(initHash)); #ifdef DEBUG std::fprintf(stderr, "Initial block 0 for lane %u: {\n", (unsigned)l); - for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) - { + for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) { std::fprintf(stderr, " 0x"); - for (std::size_t k = 0; k < 8; k++) - { + for (std::size_t k = 0; k < 8; k++) { std::fprintf(stderr, "%02x", (unsigned)bmemory[i * 8 + 7 - k]); } std::fprintf(stderr, "UL,\n"); @@ -174,18 +170,15 @@ void Argon2Params::fillFirstBlocks( } store32(initHash + ARGON2_PREHASH_DIGEST_LENGTH, 1); - for (std::uint32_t l = 0; l < lanes; l++) - { + for (std::uint32_t l = 0; l < lanes; l++) { store32(initHash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); digestLong(bmemory, ARGON2_BLOCK_SIZE, initHash, sizeof(initHash)); #ifdef DEBUG std::fprintf(stderr, "Initial block 1 for lane %u: {\n", (unsigned)l); - for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) - { + for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) { std::fprintf(stderr, " 0x"); - for (std::size_t k = 0; k < 8; k++) - { + for (std::size_t k = 0; k < 8; k++) { std::fprintf(stderr, "%02x", (unsigned)bmemory[i * 8 + 7 - k]); } std::fprintf(stderr, "UL,\n"); @@ -197,34 +190,29 @@ void Argon2Params::fillFirstBlocks( } } -void Argon2Params::finalize(void *out, const void *memory) const +void Argon2Params::finalize(void* out, const void* memory) const { /* TODO: nicify this (or move it into the kernel (I mean, we currently * have all lanes in one work-group...) */ - struct block - { + struct block { std::uint64_t v[ARGON2_BLOCK_SIZE / 8]; }; - auto cursor = static_cast(memory); + auto cursor = static_cast(memory); #ifdef DEBUG - for (std::size_t l = 0; l < getLanes(); l++) - { - for (std::size_t k = 0; k < ARGON2_BLOCK_SIZE / 8; k++) - { + for (std::size_t l = 0; l < getLanes(); l++) { + for (std::size_t k = 0; k < ARGON2_BLOCK_SIZE / 8; k++) { std::fprintf(stderr, "Block %04u [%3u]: %016llx\n", - (unsigned)i, (unsigned)k, - (unsigned long long)cursor[l].v[k]); + (unsigned)i, (unsigned)k, + (unsigned long long)cursor[l].v[k]); } } #endif block xored = *cursor; - for (std::uint32_t l = 1; l < lanes; l++) - { + for (std::uint32_t l = 1; l < lanes; l++) { ++cursor; - for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) - { + for (std::size_t i = 0; i < ARGON2_BLOCK_SIZE / 8; i++) { xored.v[i] ^= cursor->v[i]; } } diff --git a/contrib/argon2-gpu/include/argon2-gpu/common.h b/src/crypto/argon2gpu/common.h similarity index 96% rename from contrib/argon2-gpu/include/argon2-gpu/common.h rename to src/crypto/argon2gpu/common.h index 72b3898b21..2c17779af0 100644 --- a/contrib/argon2-gpu/include/argon2-gpu/common.h +++ b/src/crypto/argon2gpu/common.h @@ -23,17 +23,14 @@ #include +#include "crypto/argon2d/argon2.h" + namespace argon2gpu { -#ifndef ARGON2_SYNC_POINTS -#define ARGON2_SYNC_POINTS 4 -#endif - enum { ARGON2_BLOCK_SIZE = 1024, - // ARGON2_SYNC_POINTS = 4, ARGON2_PREHASH_DIGEST_LENGTH = 64, ARGON2_PREHASH_SEED_LENGTH = 72 }; diff --git a/contrib/argon2-gpu/include/argon2-cuda/cuda-exception.h b/src/crypto/argon2gpu/cuda/cuda-exception.h similarity index 100% rename from contrib/argon2-gpu/include/argon2-cuda/cuda-exception.h rename to src/crypto/argon2gpu/cuda/cuda-exception.h diff --git a/contrib/argon2-gpu/src/argon2-cuda/device.cpp b/src/crypto/argon2gpu/cuda/device.cpp similarity index 93% rename from contrib/argon2-gpu/src/argon2-cuda/device.cpp rename to src/crypto/argon2gpu/cuda/device.cpp index 1b79746546..b2764317a8 100644 --- a/contrib/argon2-gpu/src/argon2-cuda/device.cpp +++ b/src/crypto/argon2gpu/cuda/device.cpp @@ -17,14 +17,13 @@ #include -#include "argon2-cuda/device.h" -#include "argon2-cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/device.h" namespace argon2gpu { namespace cuda { - std::string Device::getName() const { cudaDeviceProp prop; diff --git a/contrib/argon2-gpu/include/argon2-cuda/device.h b/src/crypto/argon2gpu/cuda/device.h similarity index 100% rename from contrib/argon2-gpu/include/argon2-cuda/device.h rename to src/crypto/argon2gpu/cuda/device.h diff --git a/contrib/argon2-gpu/src/argon2-cuda/global-context.cpp b/src/crypto/argon2gpu/cuda/global-context.cpp similarity index 88% rename from contrib/argon2-gpu/src/argon2-cuda/global-context.cpp rename to src/crypto/argon2gpu/cuda/global-context.cpp index 0127d18361..f57599f56e 100644 --- a/contrib/argon2-gpu/src/argon2-cuda/global-context.cpp +++ b/src/crypto/argon2gpu/cuda/global-context.cpp @@ -15,14 +15,13 @@ * along with this program. If not, see . */ -#include "argon2-cuda/global-context.h" -#include "argon2-cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/global-context.h" namespace argon2gpu { namespace cuda { - GlobalContext::GlobalContext() : devices() { @@ -30,8 +29,7 @@ GlobalContext::GlobalContext() CudaException::check(cudaGetDeviceCount(&count)); devices.reserve(count); - for (int i = 0; i < count; i++) - { + for (int i = 0; i < count; i++) { devices.emplace_back(i); } } diff --git a/contrib/argon2-gpu/include/argon2-cuda/global-context.h b/src/crypto/argon2gpu/cuda/global-context.h similarity index 96% rename from contrib/argon2-gpu/include/argon2-cuda/global-context.h rename to src/crypto/argon2gpu/cuda/global-context.h index e2fd850854..5ff699dace 100644 --- a/contrib/argon2-gpu/include/argon2-cuda/global-context.h +++ b/src/crypto/argon2gpu/cuda/global-context.h @@ -19,7 +19,7 @@ #ifndef ARGON2_CUDA_GLOBALCONTEXT_H #define ARGON2_CUDA_GLOBALCONTEXT_H -#include "device.h" +#include "crypto/argon2gpu/cuda/device.h" #include #include diff --git a/contrib/argon2-gpu/src/argon2-cuda/kernels.cu b/src/crypto/argon2gpu/cuda/kernels.cu similarity index 69% rename from contrib/argon2-gpu/src/argon2-cuda/kernels.cu rename to src/crypto/argon2gpu/cuda/kernels.cu index 26c318890c..b1c1bf49c0 100644 --- a/contrib/argon2-gpu/src/argon2-cuda/kernels.cu +++ b/src/crypto/argon2gpu/cuda/kernels.cu @@ -3,8 +3,8 @@ #define __CUDACC__ #endif -#include "argon2-cuda/kernels.h" -#include "argon2-cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/kernels.h" #include #ifndef NDEBUG @@ -29,7 +29,6 @@ namespace argon2gpu { namespace cuda { - using namespace std; __device__ uint64_t u64_build(uint32_t hi, uint32_t lo) @@ -56,13 +55,11 @@ __device__ uint64_t u64_shuffle(uint64_t v, uint32_t thread) return u64_build(hi, lo); } -struct block_g -{ +struct block_g { uint64_t data[ARGON2_QWORDS_IN_BLOCK]; }; -struct block_th -{ +struct block_th { uint64_t a, b, c, d; }; @@ -72,7 +69,7 @@ __device__ uint64_t cmpeq_mask(uint32_t test, uint32_t ref) return u64_build(x, x); } -__device__ uint64_t block_th_get(const struct block_th *b, uint32_t idx) +__device__ uint64_t block_th_get(const struct block_th* b, uint32_t idx) { uint64_t res = 0; res ^= cmpeq_mask(idx, 0) & b->a; @@ -82,7 +79,7 @@ __device__ uint64_t block_th_get(const struct block_th *b, uint32_t idx) return res; } -__device__ void block_th_set(struct block_th *b, uint32_t idx, uint64_t v) +__device__ void block_th_set(struct block_th* b, uint32_t idx, uint64_t v) { b->a ^= cmpeq_mask(idx, 0) & (v ^ b->a); b->b ^= cmpeq_mask(idx, 1) & (v ^ b->b); @@ -90,12 +87,12 @@ __device__ void block_th_set(struct block_th *b, uint32_t idx, uint64_t v) b->d ^= cmpeq_mask(idx, 3) & (v ^ b->d); } -__device__ void move_block(struct block_th *dst, const struct block_th *src) +__device__ void move_block(struct block_th* dst, const struct block_th* src) { *dst = *src; } -__device__ void xor_block(struct block_th *dst, const struct block_th *src) +__device__ void xor_block(struct block_th* dst, const struct block_th* src) { dst->a ^= src->a; dst->b ^= src->b; @@ -103,8 +100,7 @@ __device__ void xor_block(struct block_th *dst, const struct block_th *src) dst->d ^= src->d; } -__device__ void load_block(struct block_th *dst, const struct block_g *src, - uint32_t thread) +__device__ void load_block(struct block_th* dst, const struct block_g* src, uint32_t thread) { dst->a = src->data[0 * THREADS_PER_LANE + thread]; dst->b = src->data[1 * THREADS_PER_LANE + thread]; @@ -112,8 +108,7 @@ __device__ void load_block(struct block_th *dst, const struct block_g *src, dst->d = src->data[3 * THREADS_PER_LANE + thread]; } -__device__ void load_block_xor(struct block_th *dst, const struct block_g *src, - uint32_t thread) +__device__ void load_block_xor(struct block_th* dst, const struct block_g* src, uint32_t thread) { dst->a ^= src->data[0 * THREADS_PER_LANE + thread]; dst->b ^= src->data[1 * THREADS_PER_LANE + thread]; @@ -121,8 +116,7 @@ __device__ void load_block_xor(struct block_th *dst, const struct block_g *src, dst->d ^= src->data[3 * THREADS_PER_LANE + thread]; } -__device__ void store_block(struct block_g *dst, const struct block_th *src, - uint32_t thread) +__device__ void store_block(struct block_g* dst, const struct block_th* src, uint32_t thread) { dst->data[0 * THREADS_PER_LANE + thread] = src->a; dst->data[1 * THREADS_PER_LANE + thread] = src->b; @@ -142,7 +136,7 @@ __device__ uint64_t f(uint64_t x, uint64_t y) return x + y + 2 * u64_build(__umulhi(xlo, ylo), xlo * ylo); } -__device__ void g(struct block_th *block) +__device__ void g(struct block_th* block) { uint64_t a, b, c, d; a = block->a; @@ -166,10 +160,9 @@ __device__ void g(struct block_th *block) } template -__device__ void apply_shuffle(struct block_th *block, uint32_t thread) +__device__ void apply_shuffle(struct block_th* block, uint32_t thread) { - for (uint32_t i = 0; i < QWORDS_PER_THREAD; i++) - { + for (uint32_t i = 0; i < QWORDS_PER_THREAD; i++) { uint32_t src_thr = shuffle::apply(thread, i); uint64_t v = block_th_get(block, i); @@ -178,11 +171,10 @@ __device__ void apply_shuffle(struct block_th *block, uint32_t thread) } } -__device__ void transpose(struct block_th *block, uint32_t thread) +__device__ void transpose(struct block_th* block, uint32_t thread) { uint32_t thread_group = (thread & 0x0C) >> 2; - for (uint32_t i = 1; i < QWORDS_PER_THREAD; i++) - { + for (uint32_t i = 1; i < QWORDS_PER_THREAD; i++) { uint32_t thr = (i << 2) ^ thread; uint32_t idx = thread_group ^ i; @@ -192,24 +184,21 @@ __device__ void transpose(struct block_th *block, uint32_t thread) } } -struct identity_shuffle -{ +struct identity_shuffle { __device__ static uint32_t apply(uint32_t thread, uint32_t idx) { return thread; } }; -struct shift1_shuffle -{ +struct shift1_shuffle { __device__ static uint32_t apply(uint32_t thread, uint32_t idx) { return (thread & 0x1c) | ((thread + idx) & 0x3); } }; -struct unshift1_shuffle -{ +struct unshift1_shuffle { __device__ static uint32_t apply(uint32_t thread, uint32_t idx) { idx = (QWORDS_PER_THREAD - idx) % QWORDS_PER_THREAD; @@ -218,8 +207,7 @@ struct unshift1_shuffle } }; -struct shift2_shuffle -{ +struct shift2_shuffle { __device__ static uint32_t apply(uint32_t thread, uint32_t idx) { uint32_t lo = (thread & 0x1) | ((thread & 0x10) >> 3); @@ -228,8 +216,7 @@ struct shift2_shuffle } }; -struct unshift2_shuffle -{ +struct unshift2_shuffle { __device__ static uint32_t apply(uint32_t thread, uint32_t idx) { idx = (QWORDS_PER_THREAD - idx) % QWORDS_PER_THREAD; @@ -240,7 +227,7 @@ struct unshift2_shuffle } }; -__device__ void shuffle_block(struct block_th *block, uint32_t thread) +__device__ void shuffle_block(struct block_th* block, uint32_t thread) { transpose(block, thread); @@ -262,8 +249,7 @@ __device__ void shuffle_block(struct block_th *block, uint32_t thread) apply_shuffle(block, thread); } -__device__ void next_addresses(struct block_th *addr, struct block_th *tmp, - uint32_t thread_input, uint32_t thread) +__device__ void next_addresses(struct block_th* addr, struct block_th* tmp, uint32_t thread_input, uint32_t thread) { addr->a = u64_build(0, thread_input); addr->b = 0; @@ -281,49 +267,46 @@ __device__ void next_addresses(struct block_th *addr, struct block_th *tmp, } __device__ void compute_ref_pos( - uint32_t lanes, uint32_t segment_blocks, - uint32_t pass, uint32_t lane, uint32_t slice, uint32_t offset, - uint32_t *ref_lane, uint32_t *ref_index) + uint32_t lanes, + uint32_t segment_blocks, + uint32_t pass, + uint32_t lane, + uint32_t slice, + uint32_t offset, + uint32_t* ref_lane, + uint32_t* ref_index) { uint32_t lane_blocks = ARGON2_SYNC_POINTS * segment_blocks; *ref_lane = *ref_lane % lanes; uint32_t base; - if (pass != 0) - { + if (pass != 0) { base = lane_blocks - segment_blocks; - } - else - { - if (slice == 0) - { + } else { + if (slice == 0) { *ref_lane = lane; } base = slice * segment_blocks; } uint32_t ref_area_size = base + offset - 1; - if (*ref_lane != lane) - { + if (*ref_lane != lane) { ref_area_size = min(ref_area_size, base); } *ref_index = __umulhi(*ref_index, *ref_index); *ref_index = ref_area_size - 1 - __umulhi(ref_area_size, *ref_index); - if (pass != 0 && slice != ARGON2_SYNC_POINTS - 1) - { + if (pass != 0 && slice != ARGON2_SYNC_POINTS - 1) { *ref_index += (slice + 1) * segment_blocks; - if (*ref_index >= lane_blocks) - { + if (*ref_index >= lane_blocks) { *ref_index -= lane_blocks; } } } -struct ref -{ +struct ref { uint32_t ref_lane; uint32_t ref_index; }; @@ -334,7 +317,9 @@ struct ref */ template __global__ void argon2_precompute_kernel( - struct ref *refs, uint32_t passes, uint32_t lanes, + struct ref* refs, + uint32_t passes, + uint32_t lanes, uint32_t segment_blocks) { uint32_t block_id = blockIdx.y * blockDim.y + threadIdx.y; @@ -345,14 +330,11 @@ __global__ void argon2_precompute_kernel( uint32_t segment = block_id / segment_addr_blocks; uint32_t slice, pass, pass_id, lane; - if (type == ARGON2_ID) - { + if (type == ARGON2_ID) { slice = segment % (ARGON2_SYNC_POINTS / 2); lane = segment / (ARGON2_SYNC_POINTS / 2); pass_id = pass = 0; - } - else - { + } else { slice = segment % ARGON2_SYNC_POINTS; pass_id = segment / ARGON2_SYNC_POINTS; @@ -363,8 +345,7 @@ __global__ void argon2_precompute_kernel( struct block_th addr, tmp; uint32_t thread_input; - switch (thread) - { + switch (thread) { case 0: thread_input = pass; break; @@ -395,18 +376,16 @@ __global__ void argon2_precompute_kernel( refs += segment * segment_blocks; - for (uint32_t i = 0; i < QWORDS_PER_THREAD; i++) - { + for (uint32_t i = 0; i < QWORDS_PER_THREAD; i++) { uint32_t pos = i * THREADS_PER_LANE + thread; uint32_t offset = block * ARGON2_QWORDS_IN_BLOCK + pos; - if (offset < segment_blocks) - { + if (offset < segment_blocks) { uint64_t v = block_th_get(&addr, i); uint32_t ref_index = u64_lo(v); uint32_t ref_lane = u64_hi(v); compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, - &ref_lane, &ref_index); + &ref_lane, &ref_index); refs[offset].ref_index = ref_index; refs[offset].ref_lane = ref_lane; @@ -416,21 +395,23 @@ __global__ void argon2_precompute_kernel( template __device__ void argon2_core( - struct block_g *memory, struct block_g *mem_curr, - struct block_th *prev, struct block_th *tmp, - uint32_t lanes, uint32_t thread, uint32_t pass, - uint32_t ref_index, uint32_t ref_lane) + struct block_g* memory, + struct block_g* mem_curr, + struct block_th* prev, + struct block_th* tmp, + uint32_t lanes, + uint32_t thread, + uint32_t pass, + uint32_t ref_index, + uint32_t ref_lane) { - struct block_g *mem_ref = memory + ref_index * lanes + ref_lane; + struct block_g* mem_ref = memory + ref_index * lanes + ref_lane; - if (version != ARGON2_VERSION_10 && pass != 0) - { + if (version != ARGON2_VERSION_10 && pass != 0) { load_block(tmp, mem_curr, thread); load_block_xor(prev, mem_ref, thread); xor_block(tmp, prev); - } - else - { + } else { load_block_xor(prev, mem_ref, thread); move_block(tmp, prev); } @@ -444,38 +425,47 @@ __device__ void argon2_core( template __device__ void argon2_step_precompute( - struct block_g *memory, struct block_g *mem_curr, - struct block_th *prev, struct block_th *tmp, const struct ref **refs, - uint32_t lanes, uint32_t segment_blocks, uint32_t thread, - uint32_t lane, uint32_t pass, uint32_t slice, uint32_t offset) + struct block_g* memory, + struct block_g* mem_curr, + struct block_th* prev, + struct block_th* tmp, + const struct ref** refs, + uint32_t lanes, + uint32_t segment_blocks, + uint32_t thread, + uint32_t lane, + uint32_t pass, + uint32_t slice, + uint32_t offset) { uint32_t ref_index, ref_lane; if (type == ARGON2_I || (type == ARGON2_ID && pass == 0 && - slice < ARGON2_SYNC_POINTS / 2)) - { + slice < ARGON2_SYNC_POINTS / 2)) { ref_index = (*refs)->ref_index; ref_lane = (*refs)->ref_lane; (*refs)++; - } - else - { + } else { uint64_t v = u64_shuffle(prev->a, 0); ref_index = u64_lo(v); ref_lane = u64_hi(v); compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, - &ref_lane, &ref_index); + &ref_lane, &ref_index); } argon2_core(memory, mem_curr, prev, tmp, lanes, thread, pass, - ref_index, ref_lane); + ref_index, ref_lane); } template __global__ void argon2_kernel_segment_precompute( - struct block_g *memory, const struct ref *refs, - uint32_t passes, uint32_t lanes, uint32_t segment_blocks, - uint32_t pass, uint32_t slice) + struct block_g* memory, + const struct ref* refs, + uint32_t passes, + uint32_t lanes, + uint32_t segment_blocks, + uint32_t pass, + uint32_t slice) { uint32_t job_id = blockIdx.z * blockDim.z + threadIdx.z; uint32_t lane = blockIdx.y * blockDim.y + threadIdx.y; @@ -488,48 +478,37 @@ __global__ void argon2_kernel_segment_precompute( struct block_th prev, tmp; - struct block_g *mem_segment = + struct block_g* mem_segment = memory + slice * segment_blocks * lanes + lane; struct block_g *mem_prev, *mem_curr; uint32_t start_offset = 0; - if (pass == 0) - { - if (slice == 0) - { + if (pass == 0) { + if (slice == 0) { mem_prev = mem_segment + 1 * lanes; mem_curr = mem_segment + 2 * lanes; start_offset = 2; - } - else - { + } else { mem_prev = mem_segment - lanes; mem_curr = mem_segment; } - } - else - { + } else { mem_prev = mem_segment + (slice == 0 ? lane_blocks * lanes : 0) - lanes; mem_curr = mem_segment; } load_block(&prev, mem_prev, thread); - if (type == ARGON2_ID) - { - if (pass == 0 && slice < ARGON2_SYNC_POINTS / 2) - { + if (type == ARGON2_ID) { + if (pass == 0 && slice < ARGON2_SYNC_POINTS / 2) { refs += lane * (lane_blocks / 2) + slice * segment_blocks; refs += start_offset; } - } - else - { + } else { refs += (lane * passes + pass) * lane_blocks + slice * segment_blocks; refs += start_offset; } - for (uint32_t offset = start_offset; offset < segment_blocks; ++offset) - { + for (uint32_t offset = start_offset; offset < segment_blocks; ++offset) { argon2_step_precompute( memory, mem_curr, &prev, &tmp, &refs, lanes, segment_blocks, thread, lane, pass, slice, offset); @@ -540,8 +519,11 @@ __global__ void argon2_kernel_segment_precompute( template __global__ void argon2_kernel_oneshot_precompute( - struct block_g *memory, const struct ref *refs, uint32_t passes, - uint32_t lanes, uint32_t segment_blocks) + struct block_g* memory, + const struct ref* refs, + uint32_t passes, + uint32_t lanes, + uint32_t segment_blocks) { uint32_t job_id = blockIdx.z * blockDim.z + threadIdx.z; uint32_t lane = threadIdx.y; @@ -554,30 +536,23 @@ __global__ void argon2_kernel_oneshot_precompute( struct block_th prev, tmp; - struct block_g *mem_lane = memory + lane; - struct block_g *mem_prev = mem_lane + 1 * lanes; - struct block_g *mem_curr = mem_lane + 2 * lanes; + struct block_g* mem_lane = memory + lane; + struct block_g* mem_prev = mem_lane + 1 * lanes; + struct block_g* mem_curr = mem_lane + 2 * lanes; load_block(&prev, mem_prev, thread); - if (type == ARGON2_ID) - { + if (type == ARGON2_ID) { refs += lane * (lane_blocks / 2) + 2; - } - else - { + } else { refs += lane * passes * lane_blocks + 2; } uint32_t skip = 2; - for (uint32_t pass = 0; pass < passes; ++pass) - { - for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; ++slice) - { - for (uint32_t offset = 0; offset < segment_blocks; ++offset) - { - if (skip > 0) - { + for (uint32_t pass = 0; pass < passes; ++pass) { + for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; ++slice) { + for (uint32_t offset = 0; offset < segment_blocks; ++offset) { + if (skip > 0) { --skip; continue; } @@ -598,22 +573,27 @@ __global__ void argon2_kernel_oneshot_precompute( template __device__ void argon2_step( - struct block_g *memory, struct block_g *mem_curr, - struct block_th *prev, struct block_th *tmp, struct block_th *addr, - uint32_t lanes, uint32_t segment_blocks, uint32_t thread, - uint32_t *thread_input, uint32_t lane, uint32_t pass, uint32_t slice, + struct block_g* memory, + struct block_g* mem_curr, + struct block_th* prev, + struct block_th* tmp, + struct block_th* addr, + uint32_t lanes, + uint32_t segment_blocks, + uint32_t thread, + uint32_t* thread_input, + uint32_t lane, + uint32_t pass, + uint32_t slice, uint32_t offset) { uint32_t ref_index, ref_lane; if (type == ARGON2_I || (type == ARGON2_ID && pass == 0 && - slice < ARGON2_SYNC_POINTS / 2)) - { + slice < ARGON2_SYNC_POINTS / 2)) { uint32_t addr_index = offset % ARGON2_QWORDS_IN_BLOCK; - if (addr_index == 0) - { - if (thread == 6) - { + if (addr_index == 0) { + if (thread == 6) { ++*thread_input; } next_addresses(addr, tmp, *thread_input, thread); @@ -626,25 +606,27 @@ __device__ void argon2_step( v = u64_shuffle(v, thr); ref_index = u64_lo(v); ref_lane = u64_hi(v); - } - else - { + } else { uint64_t v = u64_shuffle(prev->a, 0); ref_index = u64_lo(v); ref_lane = u64_hi(v); } compute_ref_pos(lanes, segment_blocks, pass, lane, slice, offset, - &ref_lane, &ref_index); + &ref_lane, &ref_index); argon2_core(memory, mem_curr, prev, tmp, lanes, thread, pass, - ref_index, ref_lane); + ref_index, ref_lane); } template __global__ void argon2_kernel_segment( - struct block_g *memory, uint32_t passes, uint32_t lanes, - uint32_t segment_blocks, uint32_t pass, uint32_t slice) + struct block_g* memory, + uint32_t passes, + uint32_t lanes, + uint32_t segment_blocks, + uint32_t pass, + uint32_t slice) { uint32_t job_id = blockIdx.z * blockDim.z + threadIdx.z; uint32_t lane = blockIdx.y * blockDim.y + threadIdx.y; @@ -658,10 +640,8 @@ __global__ void argon2_kernel_segment( struct block_th prev, addr, tmp; uint32_t thread_input; - if (type == ARGON2_I || type == ARGON2_ID) - { - switch (thread) - { + if (type == ARGON2_I || type == ARGON2_ID) { + switch (thread) { case 0: thread_input = pass; break; @@ -685,44 +665,35 @@ __global__ void argon2_kernel_segment( break; } - if (pass == 0 && slice == 0 && segment_blocks > 2) - { - if (thread == 6) - { + if (pass == 0 && slice == 0 && segment_blocks > 2) { + if (thread == 6) { ++thread_input; } next_addresses(&addr, &tmp, thread_input, thread); } } - struct block_g *mem_segment = + struct block_g* mem_segment = memory + slice * segment_blocks * lanes + lane; struct block_g *mem_prev, *mem_curr; uint32_t start_offset = 0; - if (pass == 0) - { - if (slice == 0) - { + if (pass == 0) { + if (slice == 0) { mem_prev = mem_segment + 1 * lanes; mem_curr = mem_segment + 2 * lanes; start_offset = 2; - } - else - { + } else { mem_prev = mem_segment - lanes; mem_curr = mem_segment; } - } - else - { + } else { mem_prev = mem_segment + (slice == 0 ? lane_blocks * lanes : 0) - lanes; mem_curr = mem_segment; } load_block(&prev, mem_prev, thread); - for (uint32_t offset = start_offset; offset < segment_blocks; ++offset) - { + for (uint32_t offset = start_offset; offset < segment_blocks; ++offset) { argon2_step( memory, mem_curr, &prev, &tmp, &addr, lanes, segment_blocks, thread, &thread_input, lane, pass, slice, offset); @@ -733,7 +704,9 @@ __global__ void argon2_kernel_segment( template __global__ void argon2_kernel_oneshot( - struct block_g *memory, uint32_t passes, uint32_t lanes, + struct block_g* memory, + uint32_t passes, + uint32_t lanes, uint32_t segment_blocks) { uint32_t job_id = blockIdx.z * blockDim.z + threadIdx.z; @@ -748,10 +721,8 @@ __global__ void argon2_kernel_oneshot( struct block_th prev, addr, tmp; uint32_t thread_input; - if (type == ARGON2_I || type == ARGON2_ID) - { - switch (thread) - { + if (type == ARGON2_I || type == ARGON2_ID) { + switch (thread) { case 1: thread_input = lane; break; @@ -769,31 +740,25 @@ __global__ void argon2_kernel_oneshot( break; } - if (segment_blocks > 2) - { - if (thread == 6) - { + if (segment_blocks > 2) { + if (thread == 6) { ++thread_input; } next_addresses(&addr, &tmp, thread_input, thread); } } - struct block_g *mem_lane = memory + lane; - struct block_g *mem_prev = mem_lane + 1 * lanes; - struct block_g *mem_curr = mem_lane + 2 * lanes; + struct block_g* mem_lane = memory + lane; + struct block_g* mem_prev = mem_lane + 1 * lanes; + struct block_g* mem_curr = mem_lane + 2 * lanes; load_block(&prev, mem_prev, thread); uint32_t skip = 2; - for (uint32_t pass = 0; pass < passes; ++pass) - { - for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; ++slice) - { - for (uint32_t offset = 0; offset < segment_blocks; ++offset) - { - if (skip > 0) - { + for (uint32_t pass = 0; pass < passes; ++pass) { + for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; ++slice) { + for (uint32_t offset = 0; offset < segment_blocks; ++offset) { + if (skip > 0) { --skip; continue; } @@ -808,26 +773,20 @@ __global__ void argon2_kernel_oneshot( __syncthreads(); - if (type == ARGON2_I || type == ARGON2_ID) - { - if (thread == 2) - { + if (type == ARGON2_I || type == ARGON2_ID) { + if (thread == 2) { ++thread_input; } - if (thread == 6) - { + if (thread == 6) { thread_input = 0; } } } - if (type == ARGON2_I) - { - if (thread == 0) - { + if (type == ARGON2_I) { + if (thread == 0) { ++thread_input; } - if (thread == 2) - { + if (thread == 2) { thread_input = 0; } } @@ -840,15 +799,12 @@ static void setCudaDevice(int deviceIndex) { int currentIndex = -1; CudaException::check(cudaGetDevice(¤tIndex)); - if (currentIndex != deviceIndex) - { + if (currentIndex != deviceIndex) { CudaException::check(cudaSetDevice(deviceIndex)); } } -KernelRunner::KernelRunner(uint32_t type, uint32_t version, uint32_t passes, - uint32_t lanes, uint32_t segmentBlocks, - uint32_t batchSize, bool bySegment, bool precompute, int deviceIndex) +KernelRunner::KernelRunner(uint32_t type, uint32_t version, uint32_t passes, uint32_t lanes, uint32_t segmentBlocks, uint32_t batchSize, bool bySegment, bool precompute, int deviceIndex) : type(type), version(version), passes(passes), lanes(lanes), segmentBlocks(segmentBlocks), batchSize(batchSize), bySegment(bySegment), deviceIndex(deviceIndex), precompute(precompute), stream(nullptr), memory(nullptr), @@ -871,12 +827,9 @@ KernelRunner::KernelRunner(uint32_t type, uint32_t version, uint32_t passes, CudaException::check(cudaStreamCreate(&stream)); - if ((type == ARGON2_I || type == ARGON2_ID) && precompute) - { + if ((type == ARGON2_I || type == ARGON2_ID) && precompute) { uint32_t segments = - type == ARGON2_ID - ? lanes * (ARGON2_SYNC_POINTS / 2) - : passes * lanes * ARGON2_SYNC_POINTS; + type == ARGON2_ID ? lanes * (ARGON2_SYNC_POINTS / 2) : passes * lanes * ARGON2_SYNC_POINTS; size_t refsSize = segments * segmentBlocks * sizeof(struct ref); @@ -894,183 +847,146 @@ KernelRunner::KernelRunner(uint32_t type, uint32_t version, uint32_t passes, void KernelRunner::precomputeRefs() { - struct ref *refs = (struct ref *)this->refs; + struct ref* refs = (struct ref*)this->refs; uint32_t segmentAddrBlocks = (segmentBlocks + ARGON2_QWORDS_IN_BLOCK - 1) / ARGON2_QWORDS_IN_BLOCK; uint32_t segments = - type == ARGON2_ID - ? lanes * (ARGON2_SYNC_POINTS / 2) - : passes * lanes * ARGON2_SYNC_POINTS; + type == ARGON2_ID ? lanes * (ARGON2_SYNC_POINTS / 2) : passes * lanes * ARGON2_SYNC_POINTS; dim3 blocks = dim3(1, segments * segmentAddrBlocks); dim3 threads = dim3(THREADS_PER_LANE); - if (type == ARGON2_I) - { + if (type == ARGON2_I) { argon2_precompute_kernel - <<>>( + << > >( refs, passes, lanes, segmentBlocks); - } - else - { + } else { argon2_precompute_kernel - <<>>( + << > >( refs, passes, lanes, segmentBlocks); } } KernelRunner::~KernelRunner() { - if (start != nullptr) - { + if (start != nullptr) { cudaEventDestroy(start); } - if (end != nullptr) - { + if (end != nullptr) { cudaEventDestroy(end); } - if (stream != nullptr) - { + if (stream != nullptr) { cudaStreamDestroy(stream); } - if (memory != nullptr) - { + if (memory != nullptr) { cudaFree(memory); } - if (refs != nullptr) - { + if (refs != nullptr) { cudaFree(refs); } } -void KernelRunner::writeInputMemory(uint32_t jobId, const void *buffer) +void KernelRunner::writeInputMemory(uint32_t jobId, const void* buffer) { std::size_t memorySize = static_cast(lanes) * segmentBlocks * ARGON2_SYNC_POINTS * ARGON2_BLOCK_SIZE; std::size_t size = static_cast(lanes) * 2 * ARGON2_BLOCK_SIZE; std::size_t offset = memorySize * jobId; - auto mem = static_cast(memory) + offset; + auto mem = static_cast(memory) + offset; CudaException::check(cudaMemcpyAsync(mem, buffer, size, - cudaMemcpyHostToDevice, stream)); + cudaMemcpyHostToDevice, stream)); CudaException::check(cudaStreamSynchronize(stream)); } -void KernelRunner::readOutputMemory(uint32_t jobId, void *buffer) +void KernelRunner::readOutputMemory(uint32_t jobId, void* buffer) { std::size_t memorySize = static_cast(lanes) * segmentBlocks * ARGON2_SYNC_POINTS * ARGON2_BLOCK_SIZE; std::size_t size = static_cast(lanes) * ARGON2_BLOCK_SIZE; std::size_t offset = memorySize * (jobId + 1) - size; - auto mem = static_cast(memory) + offset; + auto mem = static_cast(memory) + offset; CudaException::check(cudaMemcpyAsync(buffer, mem, size, - cudaMemcpyDeviceToHost, stream)); + cudaMemcpyDeviceToHost, stream)); CudaException::check(cudaStreamSynchronize(stream)); } void KernelRunner::runKernelSegment(uint32_t lanesPerBlock, - uint32_t jobsPerBlock, - uint32_t pass, uint32_t slice) + uint32_t jobsPerBlock, + uint32_t pass, + uint32_t slice) { - if (lanesPerBlock > lanes || lanes % lanesPerBlock != 0) - { + if (lanesPerBlock > lanes || lanes % lanesPerBlock != 0) { throw std::logic_error("Invalid lanesPerBlock!"); } - if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) - { + if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) { throw std::logic_error("Invalid jobsPerBlock!"); } - struct block_g *memory_blocks = (struct block_g *)memory; + struct block_g* memory_blocks = (struct block_g*)memory; dim3 blocks = dim3(1, lanes / lanesPerBlock, batchSize / jobsPerBlock); dim3 threads = dim3(THREADS_PER_LANE, lanesPerBlock, jobsPerBlock); - if (type == ARGON2_I) - { - if (precompute) - { - struct ref *refs = (struct ref *)this->refs; - if (version == ARGON2_VERSION_10) - { + if (type == ARGON2_I) { + if (precompute) { + struct ref* refs = (struct ref*)this->refs; + if (version == ARGON2_VERSION_10) { argon2_kernel_segment_precompute - <<>>( + << > >( memory_blocks, refs, passes, lanes, segmentBlocks, pass, slice); - } - else - { + } else { argon2_kernel_segment_precompute - <<>>( + << > >( memory_blocks, refs, passes, lanes, segmentBlocks, pass, slice); } - } - else - { - if (version == ARGON2_VERSION_10) - { + } else { + if (version == ARGON2_VERSION_10) { argon2_kernel_segment - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks, pass, slice); - } - else - { + } else { argon2_kernel_segment - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } } - } - else if (type == ARGON2_ID) - { - if (precompute) - { - struct ref *refs = (struct ref *)this->refs; - if (version == ARGON2_VERSION_10) - { + } else if (type == ARGON2_ID) { + if (precompute) { + struct ref* refs = (struct ref*)this->refs; + if (version == ARGON2_VERSION_10) { argon2_kernel_segment_precompute - <<>>( + << > >( memory_blocks, refs, passes, lanes, segmentBlocks, pass, slice); - } - else - { + } else { argon2_kernel_segment_precompute - <<>>( + << > >( memory_blocks, refs, passes, lanes, segmentBlocks, pass, slice); } - } - else - { - if (version == ARGON2_VERSION_10) - { + } else { + if (version == ARGON2_VERSION_10) { argon2_kernel_segment - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks, pass, slice); - } - else - { + } else { argon2_kernel_segment - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } } - } - else - { - if (version == ARGON2_VERSION_10) - { + } else { + if (version == ARGON2_VERSION_10) { argon2_kernel_segment - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks, pass, slice); - } - else - { + } else { argon2_kernel_segment - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } @@ -1078,101 +994,73 @@ void KernelRunner::runKernelSegment(uint32_t lanesPerBlock, } void KernelRunner::runKernelOneshot(uint32_t lanesPerBlock, - uint32_t jobsPerBlock) + uint32_t jobsPerBlock) { - if (lanesPerBlock != lanes) - { + if (lanesPerBlock != lanes) { throw std::logic_error("Invalid lanesPerBlock!"); } - if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) - { + if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) { throw std::logic_error("Invalid jobsPerBlock!"); } - struct block_g *memory_blocks = (struct block_g *)memory; + struct block_g* memory_blocks = (struct block_g*)memory; dim3 blocks = dim3(1, 1, batchSize / jobsPerBlock); dim3 threads = dim3(THREADS_PER_LANE, lanes, jobsPerBlock); - if (type == ARGON2_I) - { - if (precompute) - { - struct ref *refs = (struct ref *)this->refs; - if (version == ARGON2_VERSION_10) - { + if (type == ARGON2_I) { + if (precompute) { + struct ref* refs = (struct ref*)this->refs; + if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot_precompute - <<>>( + << > >( memory_blocks, refs, passes, lanes, segmentBlocks); - } - else - { + } else { argon2_kernel_oneshot_precompute - <<>>( + << > >( memory_blocks, refs, passes, lanes, segmentBlocks); } - } - else - { - if (version == ARGON2_VERSION_10) - { + } else { + if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks); - } - else - { + } else { argon2_kernel_oneshot - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks); } } - } - else if (type == ARGON2_ID) - { - if (precompute) - { - struct ref *refs = (struct ref *)this->refs; - if (version == ARGON2_VERSION_10) - { + } else if (type == ARGON2_ID) { + if (precompute) { + struct ref* refs = (struct ref*)this->refs; + if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot_precompute - <<>>( + << > >( memory_blocks, refs, passes, lanes, segmentBlocks); - } - else - { + } else { argon2_kernel_oneshot_precompute - <<>>( + << > >( memory_blocks, refs, passes, lanes, segmentBlocks); } - } - else - { - if (version == ARGON2_VERSION_10) - { + } else { + if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks); - } - else - { + } else { argon2_kernel_oneshot - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks); } } - } - else - { - if (version == ARGON2_VERSION_10) - { + } else { + if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks); - } - else - { + } else { argon2_kernel_oneshot - <<>>( + << > >( memory_blocks, passes, lanes, segmentBlocks); } } @@ -1183,18 +1071,13 @@ void KernelRunner::run(uint32_t lanesPerBlock, uint32_t jobsPerBlock) setCudaDevice(deviceIndex); CudaException::check(cudaEventRecord(start, stream)); - if (bySegment) - { - for (uint32_t pass = 0; pass < passes; pass++) - { - for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; slice++) - { + if (bySegment) { + for (uint32_t pass = 0; pass < passes; pass++) { + for (uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; slice++) { runKernelSegment(lanesPerBlock, jobsPerBlock, pass, slice); } } - } - else - { + } else { runKernelOneshot(lanesPerBlock, jobsPerBlock); } diff --git a/contrib/argon2-gpu/include/argon2-cuda/kernels.h b/src/crypto/argon2gpu/cuda/kernels.h similarity index 100% rename from contrib/argon2-gpu/include/argon2-cuda/kernels.h rename to src/crypto/argon2gpu/cuda/kernels.h diff --git a/contrib/argon2-gpu/src/argon2-cuda/processing-unit.cpp b/src/crypto/argon2gpu/cuda/processing-unit.cpp similarity index 78% rename from contrib/argon2-gpu/src/argon2-cuda/processing-unit.cpp rename to src/crypto/argon2gpu/cuda/processing-unit.cpp index 91c49e438d..f22b1b12ed 100644 --- a/contrib/argon2-gpu/src/argon2-cuda/processing-unit.cpp +++ b/src/crypto/argon2gpu/cuda/processing-unit.cpp @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -#include "argon2-cuda/processing-unit.h" -#include "argon2-cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/processing-unit.h" #include #ifndef NDEBUG @@ -27,13 +27,11 @@ namespace argon2gpu { namespace cuda { - static void setCudaDevice(int deviceIndex) { int currentIndex = -1; CudaException::check(cudaGetDevice(¤tIndex)); - if (currentIndex != deviceIndex) - { + if (currentIndex != deviceIndex) { CudaException::check(cudaSetDevice(deviceIndex)); } } @@ -44,43 +42,45 @@ static bool isPowerOfTwo(std::uint32_t x) } ProcessingUnit::ProcessingUnit( - const ProgramContext *programContext, const Argon2Params *params, - const Device *device, std::size_t batchSize, bool bySegment, + const ProgramContext* programContext, + const Argon2Params* params, + const Device* device, + std::size_t batchSize, + bool bySegment, bool precomputeRefs) : programContext(programContext), params(params), device(device), runner(programContext->getArgon2Type(), - programContext->getArgon2Version(), params->getTimeCost(), - params->getLanes(), params->getSegmentBlocks(), batchSize, - bySegment, precomputeRefs, device->getDeviceIndex()), + programContext->getArgon2Version(), + params->getTimeCost(), + params->getLanes(), + params->getSegmentBlocks(), + batchSize, + bySegment, + precomputeRefs, + device->getDeviceIndex()), bestLanesPerBlock(runner.getMinLanesPerBlock()), bestJobsPerBlock(runner.getMinJobsPerBlock()) { setCudaDevice(device->getDeviceIndex()); /* pre-fill first blocks with pseudo-random data: */ - for (std::size_t i = 0; i < batchSize; i++) - { + for (std::size_t i = 0; i < batchSize; i++) { setInputAndSalt(i, NULL, 0); } - if (runner.getMaxLanesPerBlock() > runner.getMinLanesPerBlock() && isPowerOfTwo(runner.getMaxLanesPerBlock())) - { + if (runner.getMaxLanesPerBlock() > runner.getMinLanesPerBlock() && isPowerOfTwo(runner.getMaxLanesPerBlock())) { #ifndef NDEBUG std::cerr << "[INFO] Tuning lanes per block..." << std::endl; #endif float bestTime = std::numeric_limits::infinity(); for (std::uint32_t lpb = 1; lpb <= runner.getMaxLanesPerBlock(); - lpb *= 2) - { + lpb *= 2) { float time; - try - { + try { runner.run(lpb, bestJobsPerBlock); time = runner.finish(); - } - catch (CudaException &ex) - { + } catch (CudaException& ex) { #ifndef NDEBUG std::cerr << "[WARN] CUDA error on " << lpb << " lanes per block: " << ex.what() << std::endl; @@ -93,8 +93,7 @@ ProcessingUnit::ProcessingUnit( << time << " ms" << std::endl; #endif - if (time < bestTime) - { + if (time < bestTime) { bestTime = time; bestLanesPerBlock = lpb; } @@ -106,24 +105,19 @@ ProcessingUnit::ProcessingUnit( } /* Only tune jobs per block if we hit maximum lanes per block: */ - if (bestLanesPerBlock == runner.getMaxLanesPerBlock() && runner.getMaxJobsPerBlock() > runner.getMinJobsPerBlock() && isPowerOfTwo(runner.getMaxJobsPerBlock())) - { + if (bestLanesPerBlock == runner.getMaxLanesPerBlock() && runner.getMaxJobsPerBlock() > runner.getMinJobsPerBlock() && isPowerOfTwo(runner.getMaxJobsPerBlock())) { #ifndef NDEBUG std::cerr << "[INFO] Tuning jobs per block..." << std::endl; #endif float bestTime = std::numeric_limits::infinity(); for (std::uint32_t jpb = 1; jpb <= runner.getMaxJobsPerBlock(); - jpb *= 2) - { + jpb *= 2) { float time; - try - { + try { runner.run(bestLanesPerBlock, jpb); time = runner.finish(); - } - catch (CudaException &ex) - { + } catch (CudaException& ex) { #ifndef NDEBUG std::cerr << "[WARN] CUDA error on " << jpb << " jobs per block: " << ex.what() << std::endl; @@ -136,8 +130,7 @@ ProcessingUnit::ProcessingUnit( << time << " ms" << std::endl; #endif - if (time < bestTime) - { + if (time < bestTime) { bestTime = time; bestJobsPerBlock = jpb; } @@ -149,18 +142,17 @@ ProcessingUnit::ProcessingUnit( } } -void ProcessingUnit::setInputAndSalt(std::size_t index, const void *pw, - const std::size_t pwSize) +void ProcessingUnit::setInputAndSalt(std::size_t index, const void* pw, const std::size_t pwSize) { std::size_t size = params->getLanes() * 2 * ARGON2_BLOCK_SIZE; auto buffer = std::unique_ptr(new uint8_t[size]); params->fillFirstBlocks(buffer.get(), pw, pwSize, - programContext->getArgon2Type(), - programContext->getArgon2Version()); + programContext->getArgon2Type(), + programContext->getArgon2Version()); runner.writeInputMemory(index, buffer.get()); } -void ProcessingUnit::getHash(std::size_t index, void *hash) +void ProcessingUnit::getHash(std::size_t index, void* hash) { std::size_t size = params->getLanes() * ARGON2_BLOCK_SIZE; auto buffer = std::unique_ptr(new uint8_t[size]); diff --git a/contrib/argon2-gpu/include/argon2-cuda/processing-unit.h b/src/crypto/argon2gpu/cuda/processing-unit.h similarity index 62% rename from contrib/argon2-gpu/include/argon2-cuda/processing-unit.h rename to src/crypto/argon2gpu/cuda/processing-unit.h index 2fdf9e6bc8..6a093ae32c 100644 --- a/contrib/argon2-gpu/include/argon2-cuda/processing-unit.h +++ b/src/crypto/argon2gpu/cuda/processing-unit.h @@ -23,36 +23,38 @@ #include -#include "program-context.h" -#include "kernels.h" -#include "argon2-gpu/common.h" +#include "crypto/argon2gpu/common.h" +#include "crypto/argon2gpu/cuda/program-context.h" +#include "crypto/argon2gpu/cuda/kernels.h" namespace argon2gpu { namespace cuda { - class ProcessingUnit { - private: - const ProgramContext *programContext; - const Argon2Params *params; - const Device *device; +private: + const ProgramContext* programContext; + const Argon2Params* params; + const Device* device; KernelRunner runner; std::uint32_t bestLanesPerBlock; std::uint32_t bestJobsPerBlock; - public: +public: std::size_t getBatchSize() const { return runner.getBatchSize(); } ProcessingUnit( - const ProgramContext *programContext, const Argon2Params *params, - const Device *device, std::size_t batchSize, - bool bySegment = true, bool precomputeRefs = false); + const ProgramContext* programContext, + const Argon2Params* params, + const Device* device, + std::size_t batchSize, + bool bySegment = true, + bool precomputeRefs = false); - void setInputAndSalt(std::size_t index, const void *input, const std::size_t inputSize); - void getHash(std::size_t index, void *hash); + void setInputAndSalt(std::size_t index, const void* input, const std::size_t inputSize); + void getHash(std::size_t index, void* hash); void beginProcessing(); void endProcessing(); @@ -65,29 +67,31 @@ class ProcessingUnit #include -#include "program-context.h" -#include "argon2-gpu/common.h" +#include "crypto/argon2gpu/common.h" +#include "crypto/argon2gpu/cuda/program-context.h" namespace argon2gpu { namespace cuda { - class ProcessingUnit { - public: +public: std::size_t getBatchSize() const { return 0; } ProcessingUnit( - const ProgramContext *programContext, const Argon2Params *params, - const Device *device, std::size_t batchSize, - bool bySegment = true, bool precomputeRefs = false) + const ProgramContext* programContext, + const Argon2Params* params, + const Device* device, + std::size_t batchSize, + bool bySegment = true, + bool precomputeRefs = false) { } - void setInputAndSalt(std::size_t index, const void *input, std::size_t inputSize) {} + void setInputAndSalt(std::size_t index, const void* input, std::size_t inputSize) {} - void getHash(std::size_t index, void *hash) {} + void getHash(std::size_t index, void* hash) {} void beginProcessing() {} void endProcessing() {} diff --git a/contrib/argon2-gpu/src/argon2-cuda/program-context.cpp b/src/crypto/argon2gpu/cuda/program-context.cpp similarity index 82% rename from contrib/argon2-gpu/src/argon2-cuda/program-context.cpp rename to src/crypto/argon2gpu/cuda/program-context.cpp index 620b97284e..f9c278a137 100644 --- a/contrib/argon2-gpu/src/argon2-cuda/program-context.cpp +++ b/src/crypto/argon2gpu/cuda/program-context.cpp @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -#include "argon2-cuda/kernels.h" -#include "argon2-cuda/program-context.h" +#include "crypto/argon2gpu/cuda/program-context.h" +#include "crypto/argon2gpu/cuda/kernels.h" #define THREADS_PER_LANE 32 @@ -24,11 +24,11 @@ namespace argon2gpu { namespace cuda { - ProgramContext::ProgramContext( - const GlobalContext *globalContext, - const std::vector &devices, - Type type, Version version) + const GlobalContext* globalContext, + const std::vector& devices, + Type type, + Version version) : globalContext(globalContext), type(type), version(version) { } diff --git a/contrib/argon2-gpu/include/argon2-cuda/program-context.h b/src/crypto/argon2gpu/cuda/program-context.h similarity index 71% rename from contrib/argon2-gpu/include/argon2-cuda/program-context.h rename to src/crypto/argon2gpu/cuda/program-context.h index 643a990a2c..66bb4cffbd 100644 --- a/contrib/argon2-gpu/include/argon2-cuda/program-context.h +++ b/src/crypto/argon2gpu/cuda/program-context.h @@ -19,56 +19,57 @@ #ifndef ARGON2_CUDA_PROGRAMCONTEXT_H #define ARGON2_CUDA_PROGRAMCONTEXT_H -#include "global-context.h" -#include "argon2-gpu/common.h" +#include "crypto/argon2gpu/common.h" +#include "crypto/argon2gpu/cuda/global-context.h" namespace argon2gpu { namespace cuda { - #if HAVE_CUDA class ProgramContext { - private: - const GlobalContext *globalContext; +private: + const GlobalContext* globalContext; Type type; Version version; - public: - const GlobalContext *getGlobalContext() const { return globalContext; } +public: + const GlobalContext* getGlobalContext() const { return globalContext; } Type getArgon2Type() const { return type; } Version getArgon2Version() const { return version; } ProgramContext( - const GlobalContext *globalContext, - const std::vector &devices, - Type type, Version version); + const GlobalContext* globalContext, + const std::vector& devices, + Type type, + Version version); }; #else class ProgramContext { - private: - const GlobalContext *globalContext; +private: + const GlobalContext* globalContext; Type type; Version version; - public: - const GlobalContext *getGlobalContext() const { return globalContext; } +public: + const GlobalContext* getGlobalContext() const { return globalContext; } Type getArgon2Type() const { return type; } Version getArgon2Version() const { return version; } ProgramContext( - const GlobalContext *globalContext, - const std::vector &devices, - Type type, Version version) + const GlobalContext* globalContext, + const std::vector& devices, + Type type, + Version version) : globalContext(globalContext), type(type), version(version) { } diff --git a/contrib/argon2-gpu/include/argon2-opencl/cl.hpp b/src/crypto/argon2gpu/opencl/cl.hpp similarity index 100% rename from contrib/argon2-gpu/include/argon2-opencl/cl.hpp rename to src/crypto/argon2gpu/opencl/cl.hpp diff --git a/contrib/argon2-gpu/src/argon2-opencl/device.cpp b/src/crypto/argon2gpu/opencl/device.cpp similarity index 93% rename from contrib/argon2-gpu/src/argon2-opencl/device.cpp rename to src/crypto/argon2gpu/opencl/device.cpp index 05c4d03da6..aa05d7ffbf 100644 --- a/contrib/argon2-gpu/src/argon2-opencl/device.cpp +++ b/src/crypto/argon2gpu/opencl/device.cpp @@ -15,33 +15,28 @@ * along with this program. If not, see . */ -#include "argon2-opencl/device.h" +#include "crypto/argon2gpu/opencl/device.h" #include -#include #include +#include namespace argon2gpu { namespace opencl { - std::string Device::getName() const { return "OpenCL Device '" + device.getInfo() + "' (" + device.getInfo() + ")"; } template -static std::ostream &printBitfield(std::ostream &out, T value, - const std::vector> &lookup) +static std::ostream& printBitfield(std::ostream& out, T value, const std::vector >& lookup) { bool first = true; - for (auto &entry : lookup) - { - if (value & entry.first) - { - if (!first) - { + for (auto& entry : lookup) { + if (value & entry.first) { + if (!first) { out << " | "; } first = false; @@ -52,28 +47,22 @@ static std::ostream &printBitfield(std::ostream &out, T value, } template -static std::ostream &printEnum(std::ostream &out, T value, - const std::unordered_map &lookup) +static std::ostream& printEnum(std::ostream& out, T value, const std::unordered_map& lookup) { - try - { + try { return out << lookup.at(value); - } - catch (const std::out_of_range &) - { + } catch (const std::out_of_range&) { return out << ""; } } template -std::ostream &operator<<(std::ostream &out, const std::vector &vec) +std::ostream& operator<<(std::ostream& out, const std::vector& vec) { out << "["; bool first = true; - for (T value : vec) - { - if (!first) - { + for (T value : vec) { + if (!first) { out << ", "; } first = false; diff --git a/contrib/argon2-gpu/include/argon2-opencl/device.h b/src/crypto/argon2gpu/opencl/device.h similarity index 82% rename from contrib/argon2-gpu/include/argon2-opencl/device.h rename to src/crypto/argon2gpu/opencl/device.h index 522ab02e8c..928757497e 100644 --- a/contrib/argon2-gpu/include/argon2-opencl/device.h +++ b/src/crypto/argon2gpu/opencl/device.h @@ -19,23 +19,22 @@ #ifndef ARGON2_OPENCL_DEVICE_H #define ARGON2_OPENCL_DEVICE_H -#include "argon2-opencl/opencl.h" +#include "crypto/argon2gpu/opencl/opencl.h" namespace argon2gpu { namespace opencl { - class Device { - private: +private: cl::Device device; - public: +public: std::string getName() const; std::string getInfo() const; - const cl::Device &getCLDevice() const { return device; } + const cl::Device& getCLDevice() const { return device; } /** * @brief Empty constructor. @@ -44,15 +43,15 @@ class Device */ Device() {} - Device(const cl::Device &device) + Device(const cl::Device& device) : device(device) { } - Device(const Device &) = default; - Device(Device &&) = default; + Device(const Device&) = default; + Device(Device&&) = default; - Device &operator=(const Device &) = default; + Device& operator=(const Device&) = default; }; } // namespace opencl diff --git a/contrib/argon2-gpu/src/argon2-opencl/global-context.cpp b/src/crypto/argon2gpu/opencl/global-context.cpp similarity index 81% rename from contrib/argon2-gpu/src/argon2-opencl/global-context.cpp rename to src/crypto/argon2gpu/opencl/global-context.cpp index 6f15c5c1f8..8742cc1743 100644 --- a/contrib/argon2-gpu/src/argon2-opencl/global-context.cpp +++ b/src/crypto/argon2gpu/opencl/global-context.cpp @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -#include "argon2-opencl/global-context.h" +#include "crypto/argon2gpu/opencl/global-context.h" #include @@ -23,23 +23,21 @@ namespace argon2gpu { namespace opencl { - GlobalContext::GlobalContext() : devices() { + std::clog << "globalcontextinit <" << std::endl; std::vector platforms; + std::clog << "cl::Platform::get <" << std::endl; cl::Platform::get(&platforms); + std::clog << "cl::Platform::get >" << std::endl; std::vector clDevices; - for (cl::Platform platform : platforms) - { - try - { + for (cl::Platform platform : platforms) { + try { platform.getDevices(CL_DEVICE_TYPE_ALL, &clDevices); devices.insert(devices.end(), clDevices.begin(), clDevices.end()); - } - catch (const cl::Error &err) - { + } catch (const cl::Error& err) { std::cerr << "WARNING: Unable to get devices for platform '" << platform.getInfo() << "' - error " << err.err() << std::endl; diff --git a/contrib/argon2-gpu/include/argon2-opencl/global-context.h b/src/crypto/argon2gpu/opencl/global-context.h similarity index 89% rename from contrib/argon2-gpu/include/argon2-opencl/global-context.h rename to src/crypto/argon2gpu/opencl/global-context.h index 9108b63f56..5e823f1e3a 100644 --- a/contrib/argon2-gpu/include/argon2-opencl/global-context.h +++ b/src/crypto/argon2gpu/opencl/global-context.h @@ -18,7 +18,7 @@ #ifndef ARGON2_OPENCL_GLOBALCONTEXT_H #define ARGON2_OPENCL_GLOBALCONTEXT_H -#include "argon2-opencl/device.h" +#include "crypto/argon2gpu/opencl/device.h" #include #include @@ -27,14 +27,13 @@ namespace argon2gpu { namespace opencl { - class GlobalContext { - private: +private: std::vector devices; - public: - const std::vector &getAllDevices() const { return devices; } +public: + const std::vector& getAllDevices() const { return devices; } GlobalContext(); }; diff --git a/contrib/argon2-gpu/src/argon2-opencl/kernel-loader.cpp b/src/crypto/argon2gpu/opencl/kernel-loader.cpp similarity index 85% rename from contrib/argon2-gpu/src/argon2-opencl/kernel-loader.cpp rename to src/crypto/argon2gpu/opencl/kernel-loader.cpp index 9224cd2356..7abfec63fe 100644 --- a/contrib/argon2-gpu/src/argon2-opencl/kernel-loader.cpp +++ b/src/crypto/argon2gpu/opencl/kernel-loader.cpp @@ -15,21 +15,22 @@ * along with this program. If not, see . */ -#include "argon2-opencl/kernel-loader.h" +#include "crypto/argon2gpu/opencl/kernel-loader.h" #include -#include #include +#include namespace argon2gpu { namespace opencl { - cl::Program KernelLoader::loadArgon2Program( - const cl::Context &context, - const std::string &sourceDirectory, - Type type, Version version, bool debug) + const cl::Context& context, + const std::string& sourceDirectory, + Type type, + Version version, + bool debug) { std::string sourcePath = sourceDirectory + "/kernel.cl"; std::string sourceText; @@ -41,8 +42,7 @@ cl::Program KernelLoader::loadArgon2Program( std::istreambuf_iterator()}; } - if (debug) - { + if (debug) { buildOpts << "-g -s \"" << sourcePath << "\"" << " "; } @@ -50,16 +50,12 @@ cl::Program KernelLoader::loadArgon2Program( buildOpts << "-DARGON2_VERSION=" << version << " "; cl::Program prog(context, sourceText); - try - { + try { std::string opts = buildOpts.str(); prog.build(opts.c_str()); - } - catch (const cl::Error &err) - { + } catch (const cl::Error& err) { std::cerr << "ERROR: Failed to build program:" << std::endl; - for (cl::Device &device : context.getInfo()) - { + for (cl::Device& device : context.getInfo()) { std::cerr << " Build log from device '" << device.getInfo() << "':" << std::endl; std::cerr << prog.getBuildInfo(device); } diff --git a/contrib/argon2-gpu/include/argon2-opencl/kernel-loader.h b/src/crypto/argon2gpu/opencl/kernel-loader.h similarity index 83% rename from contrib/argon2-gpu/include/argon2-opencl/kernel-loader.h rename to src/crypto/argon2gpu/opencl/kernel-loader.h index ef59877fa3..e2614460f4 100644 --- a/contrib/argon2-gpu/include/argon2-opencl/kernel-loader.h +++ b/src/crypto/argon2gpu/opencl/kernel-loader.h @@ -18,8 +18,8 @@ #ifndef ARGON2_OPENCL_KERNELLOADER_H #define ARGON2_OPENCL_KERNELLOADER_H -#include "argon2-opencl/opencl.h" -#include "argon2-gpu/common.h" +#include "crypto/argon2gpu/common.h" +#include "crypto/argon2gpu/opencl/opencl.h" #include @@ -27,13 +27,14 @@ namespace argon2gpu { namespace opencl { - namespace KernelLoader { cl::Program loadArgon2Program( - const cl::Context &context, - const std::string &sourceDirectory, - Type type, Version version, bool debug = false); + const cl::Context& context, + const std::string& sourceDirectory, + Type type, + Version version, + bool debug = false); }; } // namespace opencl diff --git a/contrib/argon2-gpu/src/argon2-opencl/kernel-runner.cpp b/src/crypto/argon2gpu/opencl/kernel-runner.cpp similarity index 78% rename from contrib/argon2-gpu/src/argon2-opencl/kernel-runner.cpp rename to src/crypto/argon2gpu/opencl/kernel-runner.cpp index d675d7d836..313374616b 100644 --- a/contrib/argon2-gpu/src/argon2-opencl/kernel-runner.cpp +++ b/src/crypto/argon2gpu/opencl/kernel-runner.cpp @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -#include "argon2-opencl/kernel-runner.h" +#include "crypto/argon2gpu/opencl/kernel-runner.h" #include @@ -29,15 +29,16 @@ namespace argon2gpu { namespace opencl { - -enum -{ +enum { ARGON2_REFS_PER_BLOCK = ARGON2_BLOCK_SIZE / (2 * sizeof(cl_uint)), }; -KernelRunner::KernelRunner(const ProgramContext *programContext, - const Argon2Params *params, const Device *device, - std::uint32_t batchSize, bool bySegment, bool precompute) +KernelRunner::KernelRunner(const ProgramContext* programContext, + const Argon2Params* params, + const Device* device, + std::uint32_t batchSize, + bool bySegment, + bool precompute) : programContext(programContext), params(params), batchSize(batchSize), bySegment(bySegment), precompute(precompute), memorySize(params->getMemorySize() * static_cast(batchSize)) @@ -48,7 +49,7 @@ KernelRunner::KernelRunner(const ProgramContext *programContext, std::uint32_t segmentBlocks = params->getSegmentBlocks(); queue = cl::CommandQueue(context, device->getCLDevice(), - CL_QUEUE_PROFILING_ENABLE); + CL_QUEUE_PROFILING_ENABLE); #ifndef NDEBUG std::cerr << "[INFO] Allocating " << memorySize << " bytes for memory..." @@ -58,12 +59,9 @@ KernelRunner::KernelRunner(const ProgramContext *programContext, memoryBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, memorySize); Type type = programContext->getArgon2Type(); - if ((type == ARGON2_I || type == ARGON2_ID) && precompute) - { + if ((type == ARGON2_I || type == ARGON2_ID) && precompute) { std::uint32_t segments = - type == ARGON2_ID - ? lanes * (ARGON2_SYNC_POINTS / 2) - : passes * lanes * ARGON2_SYNC_POINTS; + type == ARGON2_ID ? lanes * (ARGON2_SYNC_POINTS / 2) : passes * lanes * ARGON2_SYNC_POINTS; std::size_t refsSize = segments * segmentBlocks * sizeof(cl_uint) * 2; @@ -77,7 +75,7 @@ KernelRunner::KernelRunner(const ProgramContext *programContext, precomputeRefs(); } - static const char *KERNEL_NAMES[2][2] = { + static const char* KERNEL_NAMES[2][2] = { { "argon2_kernel_oneshot", "argon2_kernel_segment", @@ -88,17 +86,14 @@ KernelRunner::KernelRunner(const ProgramContext *programContext, }}; kernel = cl::Kernel(programContext->getProgram(), - KERNEL_NAMES[precompute][bySegment]); + KERNEL_NAMES[precompute][bySegment]); kernel.setArg(1, memoryBuffer); - if (precompute) - { + if (precompute) { kernel.setArg(2, refsBuffer); kernel.setArg(3, passes); kernel.setArg(4, lanes); kernel.setArg(5, segmentBlocks); - } - else - { + } else { kernel.setArg(2, passes); kernel.setArg(3, lanes); kernel.setArg(4, segmentBlocks); @@ -112,14 +107,12 @@ void KernelRunner::precomputeRefs() std::uint32_t segmentBlocks = params->getSegmentBlocks(); std::uint32_t segmentAddrBlocks = (segmentBlocks + ARGON2_REFS_PER_BLOCK - 1) / ARGON2_REFS_PER_BLOCK; - std::uint32_t segments = programContext->getArgon2Type() == ARGON2_ID - ? lanes * (ARGON2_SYNC_POINTS / 2) - : passes * lanes * ARGON2_SYNC_POINTS; + std::uint32_t segments = programContext->getArgon2Type() == ARGON2_ID ? lanes * (ARGON2_SYNC_POINTS / 2) : passes * lanes * ARGON2_SYNC_POINTS; std::size_t shmemSize = THREADS_PER_LANE * sizeof(cl_uint) * 2; cl::Kernel kernel = cl::Kernel(programContext->getProgram(), - "argon2_precompute_kernel"); + "argon2_precompute_kernel"); kernel.setArg(0, {shmemSize}); kernel.setArg(1, refsBuffer); kernel.setArg(2, passes); @@ -132,29 +125,29 @@ void KernelRunner::precomputeRefs() queue.finish(); } -void *KernelRunner::mapInputMemory(std::uint32_t jobId) +void* KernelRunner::mapInputMemory(std::uint32_t jobId) { std::size_t memorySize = params->getMemorySize(); std::size_t mappedSize = params->getLanes() * 2 * ARGON2_BLOCK_SIZE; return queue.enqueueMapBuffer(memoryBuffer, true, CL_MAP_WRITE, - memorySize * jobId, mappedSize); + memorySize * jobId, mappedSize); } -void KernelRunner::unmapInputMemory(void *memory) +void KernelRunner::unmapInputMemory(void* memory) { queue.enqueueUnmapMemObject(memoryBuffer, memory); } -void *KernelRunner::mapOutputMemory(std::uint32_t jobId) +void* KernelRunner::mapOutputMemory(std::uint32_t jobId) { std::size_t memorySize = params->getMemorySize(); std::size_t mappedSize = static_cast(params->getLanes()) * ARGON2_BLOCK_SIZE; std::size_t mappedOffset = memorySize * (jobId + 1) - mappedSize; return queue.enqueueMapBuffer(memoryBuffer, true, CL_MAP_READ, - mappedOffset, mappedSize); + mappedOffset, mappedSize); } -void KernelRunner::unmapOutputMemory(void *memory) +void KernelRunner::unmapOutputMemory(void* memory) { queue.enqueueUnmapMemObject(memoryBuffer, memory); } @@ -164,23 +157,17 @@ void KernelRunner::run(std::uint32_t lanesPerBlock, std::uint32_t jobsPerBlock) std::uint32_t lanes = params->getLanes(); std::uint32_t passes = params->getTimeCost(); - if (bySegment) - { - if (lanesPerBlock > lanes || lanes % lanesPerBlock != 0) - { + if (bySegment) { + if (lanesPerBlock > lanes || lanes % lanesPerBlock != 0) { throw std::logic_error("Invalid lanesPerBlock!"); } - } - else - { - if (lanesPerBlock != lanes) - { + } else { + if (lanesPerBlock != lanes) { throw std::logic_error("Invalid lanesPerBlock!"); } } - if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) - { + if (jobsPerBlock > batchSize || batchSize % jobsPerBlock != 0) { throw std::logic_error("Invalid jobsPerBlock!"); } @@ -191,23 +178,18 @@ void KernelRunner::run(std::uint32_t lanesPerBlock, std::uint32_t jobsPerBlock) std::size_t shmemSize = THREADS_PER_LANE * lanesPerBlock * jobsPerBlock * sizeof(cl_uint) * 2; kernel.setArg(0, {shmemSize}); - if (bySegment) - { - for (std::uint32_t pass = 0; pass < passes; pass++) - { - for (std::uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; slice++) - { + if (bySegment) { + for (std::uint32_t pass = 0; pass < passes; pass++) { + for (std::uint32_t slice = 0; slice < ARGON2_SYNC_POINTS; slice++) { kernel.setArg(precompute ? 6 : 5, pass); kernel.setArg(precompute ? 7 : 6, slice); queue.enqueueNDRangeKernel(kernel, cl::NullRange, - globalRange, localRange); + globalRange, localRange); } } - } - else - { + } else { queue.enqueueNDRangeKernel(kernel, cl::NullRange, - globalRange, localRange); + globalRange, localRange); } queue.enqueueMarker(&end); diff --git a/contrib/argon2-gpu/include/argon2-opencl/kernel-runner.h b/src/crypto/argon2gpu/opencl/kernel-runner.h similarity index 75% rename from contrib/argon2-gpu/include/argon2-opencl/kernel-runner.h rename to src/crypto/argon2gpu/opencl/kernel-runner.h index d778cde115..7ddb7c6631 100644 --- a/contrib/argon2-gpu/include/argon2-opencl/kernel-runner.h +++ b/src/crypto/argon2gpu/opencl/kernel-runner.h @@ -18,19 +18,18 @@ #ifndef ARGON2_OPENCL_KERNELRUNNER_H #define ARGON2_OPENCL_KERNELRUNNER_H -#include "argon2-opencl/program-context.h" -#include "argon2-gpu/common.h" +#include "crypto/argon2gpu/common.h" +#include "crypto/argon2gpu/opencl/program-context.h" namespace argon2gpu { namespace opencl { - class KernelRunner { - private: - const ProgramContext *programContext; - const Argon2Params *params; +private: + const ProgramContext* programContext; + const Argon2Params* params; std::uint32_t batchSize; bool bySegment; @@ -45,7 +44,7 @@ class KernelRunner void precomputeRefs(); - public: +public: std::uint32_t getMinLanesPerBlock() const { return bySegment ? 1 : params->getLanes(); @@ -57,15 +56,18 @@ class KernelRunner std::uint32_t getBatchSize() const { return batchSize; } - KernelRunner(const ProgramContext *programContext, - const Argon2Params *params, const Device *device, - std::uint32_t batchSize, bool bySegment, bool precompute); + KernelRunner(const ProgramContext* programContext, + const Argon2Params* params, + const Device* device, + std::uint32_t batchSize, + bool bySegment, + bool precompute); - void *mapInputMemory(std::uint32_t jobId); - void unmapInputMemory(void *memory); + void* mapInputMemory(std::uint32_t jobId); + void unmapInputMemory(void* memory); - void *mapOutputMemory(std::uint32_t jobId); - void unmapOutputMemory(void *memory); + void* mapOutputMemory(std::uint32_t jobId); + void unmapOutputMemory(void* memory); void run(std::uint32_t lanesPerBlock, std::uint32_t jobsPerBlock); float finish(); diff --git a/contrib/argon2-gpu/src/argon2-opencl/kernel.cl b/src/crypto/argon2gpu/opencl/kernel.cl similarity index 100% rename from contrib/argon2-gpu/src/argon2-opencl/kernel.cl rename to src/crypto/argon2gpu/opencl/kernel.cl diff --git a/contrib/argon2-gpu/include/argon2-opencl/opencl.h b/src/crypto/argon2gpu/opencl/opencl.h similarity index 96% rename from contrib/argon2-gpu/include/argon2-opencl/opencl.h rename to src/crypto/argon2gpu/opencl/opencl.h index ee1bad2117..6efe1be906 100644 --- a/contrib/argon2-gpu/include/argon2-opencl/opencl.h +++ b/src/crypto/argon2gpu/opencl/opencl.h @@ -32,6 +32,6 @@ #define __CL_ENABLE_EXCEPTIONS /* Include local version of * because not all platforms ship with it: */ -#include "cl.hpp" +#include "crypto/argon2gpu/opencl/cl.hpp" #endif // OPENCL_H diff --git a/contrib/argon2-gpu/src/argon2-opencl/processing-unit.cpp b/src/crypto/argon2gpu/opencl/processing-unit.cpp similarity index 78% rename from contrib/argon2-gpu/src/argon2-opencl/processing-unit.cpp rename to src/crypto/argon2gpu/opencl/processing-unit.cpp index 0eba814cd1..f948190e3f 100644 --- a/contrib/argon2-gpu/src/argon2-opencl/processing-unit.cpp +++ b/src/crypto/argon2gpu/opencl/processing-unit.cpp @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -#include "argon2-opencl/processing-unit.h" +#include "crypto/argon2gpu/opencl/processing-unit.h" #include #ifndef NDEBUG @@ -26,46 +26,41 @@ namespace argon2gpu { namespace opencl { - static bool isPowerOfTwo(std::uint32_t x) { return (x & (x - 1)) == 0; } ProcessingUnit::ProcessingUnit( - const ProgramContext *programContext, const Argon2Params *params, - const Device *device, std::size_t batchSize, - bool bySegment, bool precomputeRefs) + const ProgramContext* programContext, + const Argon2Params* params, + const Device* device, + std::size_t batchSize, + bool bySegment, + bool precomputeRefs) : programContext(programContext), params(params), device(device), - runner(programContext, params, device, batchSize, bySegment, - precomputeRefs), + runner(programContext, params, device, batchSize, bySegment, precomputeRefs), bestLanesPerBlock(runner.getMinLanesPerBlock()), bestJobsPerBlock(runner.getMinJobsPerBlock()) { /* pre-fill first blocks with pseudo-random data: */ - for (std::size_t i = 0; i < batchSize; i++) - { + for (std::size_t i = 0; i < batchSize; i++) { setInputAndSalt(i, NULL, 0); } - if (runner.getMaxLanesPerBlock() > runner.getMinLanesPerBlock() && isPowerOfTwo(runner.getMaxLanesPerBlock())) - { + if (runner.getMaxLanesPerBlock() > runner.getMinLanesPerBlock() && isPowerOfTwo(runner.getMaxLanesPerBlock())) { #ifndef NDEBUG std::cerr << "[INFO] Tuning lanes per block..." << std::endl; #endif float bestTime = std::numeric_limits::infinity(); for (std::uint32_t lpb = 1; lpb <= runner.getMaxLanesPerBlock(); - lpb *= 2) - { + lpb *= 2) { float time; - try - { + try { runner.run(lpb, bestJobsPerBlock); time = runner.finish(); - } - catch (cl::Error &ex) - { + } catch (cl::Error& ex) { #ifndef NDEBUG std::cerr << "[WARN] OpenCL error on " << lpb << " lanes per block: " << ex.what() << std::endl; @@ -78,8 +73,7 @@ ProcessingUnit::ProcessingUnit( << time << " ms" << std::endl; #endif - if (time < bestTime) - { + if (time < bestTime) { bestTime = time; bestLanesPerBlock = lpb; } @@ -91,24 +85,19 @@ ProcessingUnit::ProcessingUnit( } /* Only tune jobs per block if we hit maximum lanes per block: */ - if (bestLanesPerBlock == runner.getMaxLanesPerBlock() && runner.getMaxJobsPerBlock() > runner.getMinJobsPerBlock() && isPowerOfTwo(runner.getMaxJobsPerBlock())) - { + if (bestLanesPerBlock == runner.getMaxLanesPerBlock() && runner.getMaxJobsPerBlock() > runner.getMinJobsPerBlock() && isPowerOfTwo(runner.getMaxJobsPerBlock())) { #ifndef NDEBUG std::cerr << "[INFO] Tuning jobs per block..." << std::endl; #endif float bestTime = std::numeric_limits::infinity(); for (std::uint32_t jpb = 1; jpb <= runner.getMaxJobsPerBlock(); - jpb *= 2) - { + jpb *= 2) { float time; - try - { + try { runner.run(bestLanesPerBlock, jpb); time = runner.finish(); - } - catch (cl::Error &ex) - { + } catch (cl::Error& ex) { #ifndef NDEBUG std::cerr << "[WARN] OpenCL error on " << jpb << " jobs per block: " << ex.what() << std::endl; @@ -121,8 +110,7 @@ ProcessingUnit::ProcessingUnit( << time << " ms" << std::endl; #endif - if (time < bestTime) - { + if (time < bestTime) { bestTime = time; bestJobsPerBlock = jpb; } @@ -134,19 +122,18 @@ ProcessingUnit::ProcessingUnit( } } -void ProcessingUnit::setInputAndSalt(std::size_t index, const void *pw, - std::size_t pwSize) +void ProcessingUnit::setInputAndSalt(std::size_t index, const void* pw, std::size_t pwSize) { - void *memory = runner.mapInputMemory(index); + void* memory = runner.mapInputMemory(index); params->fillFirstBlocks(memory, pw, pwSize, - programContext->getArgon2Type(), - programContext->getArgon2Version()); + programContext->getArgon2Type(), + programContext->getArgon2Version()); runner.unmapInputMemory(memory); } -void ProcessingUnit::getHash(std::size_t index, void *hash) +void ProcessingUnit::getHash(std::size_t index, void* hash) { - void *memory = runner.mapOutputMemory(index); + void* memory = runner.mapOutputMemory(index); params->finalize(hash, memory); runner.unmapOutputMemory(memory); } diff --git a/contrib/argon2-gpu/include/argon2-opencl/processing-unit.h b/src/crypto/argon2gpu/opencl/processing-unit.h similarity index 72% rename from contrib/argon2-gpu/include/argon2-opencl/processing-unit.h rename to src/crypto/argon2gpu/opencl/processing-unit.h index 565cefc377..c77f37a941 100644 --- a/contrib/argon2-gpu/include/argon2-opencl/processing-unit.h +++ b/src/crypto/argon2gpu/opencl/processing-unit.h @@ -20,34 +20,36 @@ #include -#include "argon2-opencl/kernel-runner.h" +#include "crypto/argon2gpu/opencl/kernel-runner.h" namespace argon2gpu { namespace opencl { - class ProcessingUnit { - private: - const ProgramContext *programContext; - const Argon2Params *params; - const Device *device; +private: + const ProgramContext* programContext; + const Argon2Params* params; + const Device* device; KernelRunner runner; std::uint32_t bestLanesPerBlock; std::uint32_t bestJobsPerBlock; - public: +public: std::size_t getBatchSize() const { return runner.getBatchSize(); } ProcessingUnit( - const ProgramContext *programContext, const Argon2Params *params, - const Device *device, std::size_t batchSize, - bool bySegment = true, bool precomputeRefs = false); - - void setInputAndSalt(std::size_t index, const void *input, std::size_t inputSize); - void getHash(std::size_t index, void *hash); + const ProgramContext* programContext, + const Argon2Params* params, + const Device* device, + std::size_t batchSize, + bool bySegment = true, + bool precomputeRefs = false); + + void setInputAndSalt(std::size_t index, const void* input, std::size_t inputSize); + void getHash(std::size_t index, void* hash); void beginProcessing(); void endProcessing(); diff --git a/contrib/argon2-gpu/src/argon2-opencl/program-context.cpp b/src/crypto/argon2gpu/opencl/program-context.cpp similarity index 78% rename from contrib/argon2-gpu/src/argon2-opencl/program-context.cpp rename to src/crypto/argon2gpu/opencl/program-context.cpp index 4ae414ebfc..f90e9596ea 100644 --- a/contrib/argon2-gpu/src/argon2-opencl/program-context.cpp +++ b/src/crypto/argon2gpu/opencl/program-context.cpp @@ -15,30 +15,29 @@ * along with this program. If not, see . */ -#include "argon2-opencl/program-context.h" -#include "argon2-opencl/kernel-loader.h" +#include "crypto/argon2gpu/opencl/program-context.h" +#include "crypto/argon2gpu/opencl/kernel-loader.h" namespace argon2gpu { namespace opencl { - ProgramContext::ProgramContext( - const GlobalContext *globalContext, - const std::vector &devices, - Type type, Version version) + const GlobalContext* globalContext, + const std::vector& devices, + Type type, + Version version) : globalContext(globalContext), devices(), type(type), version(version) { this->devices.reserve(devices.size()); - for (auto &device : devices) - { + for (auto& device : devices) { this->devices.push_back(device.getCLDevice()); } context = cl::Context(this->devices); program = KernelLoader::loadArgon2Program( // FIXME path: - context, "./src/argon2-opencl", type, version); + context, "./src/crypto/argon2gpu/opencl", type, version); } } // namespace opencl diff --git a/contrib/argon2-gpu/include/argon2-opencl/program-context.h b/src/crypto/argon2gpu/opencl/program-context.h similarity index 70% rename from contrib/argon2-gpu/include/argon2-opencl/program-context.h rename to src/crypto/argon2gpu/opencl/program-context.h index af31b8a6c8..674a7927bc 100644 --- a/contrib/argon2-gpu/include/argon2-opencl/program-context.h +++ b/src/crypto/argon2gpu/opencl/program-context.h @@ -18,18 +18,17 @@ #ifndef ARGON2_OPENCL_PROGRAMCONTEXT_H #define ARGON2_OPENCL_PROGRAMCONTEXT_H -#include "argon2-opencl/global-context.h" -#include "argon2-gpu/common.h" +#include "crypto/argon2gpu/opencl/global-context.h" +#include "crypto/argon2gpu/common.h" namespace argon2gpu { namespace opencl { - class ProgramContext { - private: - const GlobalContext *globalContext; +private: + const GlobalContext* globalContext; std::vector devices; cl::Context context; @@ -38,20 +37,21 @@ class ProgramContext Type type; Version version; - public: - const GlobalContext *getGlobalContext() const { return globalContext; } +public: + const GlobalContext* getGlobalContext() const { return globalContext; } - const std::vector &getDevices() const { return devices; } - const cl::Context &getContext() const { return context; } - const cl::Program &getProgram() const { return program; } + const std::vector& getDevices() const { return devices; } + const cl::Context& getContext() const { return context; } + const cl::Program& getProgram() const { return program; } Type getArgon2Type() const { return type; } Version getArgon2Version() const { return version; } ProgramContext( - const GlobalContext *globalContext, - const std::vector &devices, - Type type, Version version); + const GlobalContext* globalContext, + const std::vector& devices, + Type type, + Version version); }; } // namespace opencl diff --git a/src/miner-gpu.h b/src/miner-gpu.h index 204dfa1007..5bd0609b30 100644 --- a/src/miner-gpu.h +++ b/src/miner-gpu.h @@ -4,22 +4,25 @@ #define DYNAMIC_ARGON2_GPU #ifdef ENABLE_GPU -#define HAVE_CUDA #include -#include "argon2-gpu/common.h" -#ifndef HAVE_CUDA -#include "argon2-cuda/cuda-exception.h" -#include "argon2-cuda/processing-unit.h" +#include "crypto/argon2gpu/common.h" + +// TODO: configure script +#define HAVE_CUDA 1 + +#ifdef HAVE_CUDA +#include "crypto/argon2gpu/cuda/cuda-exception.h" +#include "crypto/argon2gpu/cuda/processing-unit.h" #else -#include "argon2-opencl/opencl.h" -#include "argon2-opencl/processing-unit.h" +#include "crypto/argon2gpu/opencl/opencl.h" +#include "crypto/argon2gpu/opencl/processing-unit.h" #endif using Argon2GPUParams = argon2gpu::Argon2Params; -#ifndef HAVE_CUDA +#ifdef HAVE_CUDA using Argon2GPU = argon2gpu::cuda::ProcessingUnit; using Argon2GPUDevice = argon2gpu::cuda::Device; using Argon2GPUContext = argon2gpu::cuda::GlobalContext; @@ -37,15 +40,21 @@ static std::size_t GetGPUDeviceCount() return global.getAllDevices().size(); } -static Argon2GPU GetGPUProcessingUnit(const std::size_t deviceIndex) -{ - Argon2GPUContext global; - auto& devices = global.getAllDevices(); - auto& device = devices[deviceIndex]; - Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); - Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); - Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); - return processingUnit; +static Argon2GPU GetProcessingUnit(std::size_t nDeviceIndex, bool fGPU) { + if (!fGPU) { + Argon2GPU processingUnit(nullptr, nullptr, nullptr, 1, false, false); + return processingUnit; + } + else { + // Argon2GPU processingUnit = GetGPUProcessingUnit(nDeviceIndex); + Argon2GPUContext global; + auto& devices = global.getAllDevices(); + auto& device = devices[nDeviceIndex]; + Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); + Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); + Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); + return processingUnit; + } } template diff --git a/src/miner.cpp b/src/miner.cpp index 0d096d03f9..e20fbdcf2d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -83,7 +83,7 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam } #ifdef ENABLE_WALLET -bool CheckWork(const CChainParams& chainparams, CBlock* pblock, CWallet& wallet, CReserveKey& reservekey, CConnman* connman) +bool CheckWork(const CChainParams& chainparams, const CBlock* pblock, CWallet& wallet, CReserveKey& reservekey, CConnman* connman) { uint256 hash = pblock->GetHash(); arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); @@ -503,25 +503,6 @@ static void WaitForNetworkInit(const CChainParams& chainparams, CConnman& connma } } -#ifdef ENABLE_GPU -static Argon2GPU GetProcessingUnit(std::size_t nDeviceIndex, bool fGPU) { - if (!fGPU) { - Argon2GPU processingUnit(nullptr, nullptr, nullptr, 1, false, false); - return processingUnit; - } - else { - // Argon2GPU processingUnit = GetGPUProcessingUnit(nDeviceIndex); - Argon2GPUContext global; - auto& devices = global.getAllDevices(); - auto& device = devices[nDeviceIndex]; - Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); - Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); - Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); - return processingUnit; - } -} -#endif // ENABLE_GPU - static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex, bool fGPU) { std::string dev = fGPU ? "GPU" : "CPU"; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 069c57b39a..013752b45b 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -112,7 +112,7 @@ namespace { /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ struct QueuedBlock { uint256 hash; - CBlockIndex* pindex; //!< Optional. + const CBlockIndex* pindex; //!< Optional. bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request. }; map::iterator> > mapBlocksInFlight; @@ -163,13 +163,13 @@ struct CNodeState { //! List of asynchronously-determined block rejections to notify this peer about. std::vector rejects; //! The best known block we know this peer has announced. - CBlockIndex *pindexBestKnownBlock; + const CBlockIndex *pindexBestKnownBlock; //! The hash of the last unknown block this peer has announced. uint256 hashLastUnknownBlock; //! The last full block we both have. - CBlockIndex *pindexLastCommonBlock; + const CBlockIndex *pindexLastCommonBlock; //! The best header we have sent our peer. - CBlockIndex *pindexBestHeaderSent; + const CBlockIndex *pindexBestHeaderSent; //! Length of current-streak of unconnecting headers announcements int nUnconnectingHeaders; //! Whether we've started headers synchronization with this peer. @@ -316,7 +316,7 @@ bool MarkBlockAsReceived(const uint256& hash) { } // Requires cs_main. -void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) { +void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, const CBlockIndex *pindex = NULL) { CNodeState *state = State(nodeid); assert(state != NULL); @@ -377,7 +377,7 @@ bool CanDirectFetch(const Consensus::Params &consensusParams) } // Requires cs_main -bool PeerHasHeader(CNodeState *state, CBlockIndex *pindex) +bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) { if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) return true; @@ -388,7 +388,7 @@ bool PeerHasHeader(CNodeState *state, CBlockIndex *pindex) /** Find the last common ancestor two blocks have. * Both pa and pb must be non-NULL. */ -CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { +const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) { if (pa->nHeight > pb->nHeight) { pa = pa->GetAncestor(pb->nHeight); } else if (pb->nHeight > pa->nHeight) { @@ -407,7 +407,7 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { /** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has * at most count entries. */ -void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) { +void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) { if (count == 0) return; @@ -435,8 +435,8 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorpindexLastCommonBlock == state->pindexBestKnownBlock) return; - std::vector vToFetch; - CBlockIndex *pindexWalk = state->pindexLastCommonBlock; + std::vector vToFetch; + const CBlockIndex *pindexWalk = state->pindexLastCommonBlock; // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to // download that next block if the window were 1 larger. @@ -459,7 +459,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorIsValid(BLOCK_VALID_TREE)) { // We consider the chain that this peer is on invalid. return; @@ -1482,7 +1482,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LOCK(cs_main); // Find the last block the caller has in the main chain - CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); + const CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); // Send the rest of the chain if (pindex) @@ -1530,7 +1530,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } CNodeState *nodestate = State(pfrom->GetId()); - CBlockIndex* pindex = NULL; + const CBlockIndex* pindex = NULL; if (locator.IsNull()) { // If locator is null, return the hashStop block @@ -1819,7 +1819,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, ReadCompactSize(vRecv); // ignore tx count; assume it is 0. } - CBlockIndex *pindexLast = NULL; + const CBlockIndex *pindexLast = NULL; { LOCK(cs_main); CNodeState *nodestate = State(pfrom->GetId()); @@ -1910,8 +1910,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // If this set of headers is valid and ends in a block with at least as // much work as our tip, download as much as possible. if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { - vector vToFetch; - CBlockIndex *pindexWalk = pindexLast; + vector vToFetch; + const CBlockIndex *pindexWalk = pindexLast; // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && @@ -1932,7 +1932,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } else { vector vGetData; // Download as much as possible, from earliest to latest. - BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vToFetch) { + BOOST_REVERSE_FOREACH(const CBlockIndex *pindex, vToFetch) { if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { // Can't download any more from this peer break; @@ -2552,7 +2552,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg LOCK(pto->cs_inventory); vector vHeaders; bool fRevertToInv = (!state.fPreferHeaders || pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE); - CBlockIndex *pBestIndex = NULL; // last header queued for delivery + const CBlockIndex *pBestIndex = NULL; // last header queued for delivery ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date if (!fRevertToInv) { @@ -2563,7 +2563,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg BOOST_FOREACH(const uint256 &hash, pto->vBlockHashesToAnnounce) { BlockMap::iterator mi = mapBlockIndex.find(hash); assert(mi != mapBlockIndex.end()); - CBlockIndex *pindex = mi->second; + const CBlockIndex *pindex = mi->second; if (chainActive[pindex->nHeight] != pindex) { // Bail out if we reorged away from this block fRevertToInv = true; @@ -2611,7 +2611,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back(); BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce); assert(mi != mapBlockIndex.end()); - CBlockIndex *pindex = mi->second; + const CBlockIndex *pindex = mi->second; // Warn if we're announcing a block that is not on the main chain. // This should be very rare and could be optimized out. @@ -2851,10 +2851,10 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg // vector vGetData; if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - vector vToDownload; + vector vToDownload; NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams); - BOOST_FOREACH(CBlockIndex *pindex, vToDownload) { + BOOST_FOREACH(const CBlockIndex *pindex, vToDownload) { vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex); LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 87cad5bf10..f894576e48 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -17,6 +17,8 @@ #include "util.h" #include "utilstrencodings.h" +#include "miner-gpu.h" + #include "test/test_dynamic.h" #include @@ -76,16 +78,14 @@ bool TestSequenceLocks(const CTransaction &tx, int flags) #ifdef ENABLE_GPU -#include "miner-gpu.h" - BOOST_AUTO_TEST_CASE(GetHashGPU_check) { - Argon2Context global; + Argon2GPUContext global; auto& devices = global.getAllDevices(); auto& device = devices[0]; - ProgramContext progCtx(&global, {device}, argon2::ARGON2_D, argon2::ARGON2_VERSION_10); - Argon2Params params((std::size_t)OUTPUT_BYTES, 2, 500, 8); - ProcessingUnit pu(&progCtx, ¶ms, &device, 1, false, false); + Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); + Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); + Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); // Random real block (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6) // With 4 txes @@ -93,8 +93,19 @@ BOOST_AUTO_TEST_CASE(GetHashGPU_check) CDataStream stream(ParseHex("0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; + uint256 cpuHash = block.GetHash(); + + const void* input = BEGIN(block.nVersion); + + uint256 gpuHash; + processingUnit.setInputAndSalt(0, (const void*)input, INPUT_BYTES); + processingUnit.beginProcessing(); + processingUnit.endProcessing(); + processingUnit.getHash(0, (uint8_t*)&gpuHash); - BOOST_CHECK(block.GetHash() == GetBlockHashGPU(&block, &pu)); + BOOST_CHECK(cpuHash == gpuHash); + BOOST_TEST_MESSAGE("CPU HASH: " << cpuHash.GetHex()); + BOOST_TEST_MESSAGE("GPU HASH: " << gpuHash.GetHex()); } #endif //ENABLE_GPU @@ -144,6 +155,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) txFirst.push_back(new CTransaction(pblock->vtx[0])); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; + // BOOST_TEST_MESSAGE("pblock->Hash: " << pblock->GetHash().GetHex()); + // BOOST_TEST_MESSAGE("pblock->nNonce: " << pblock->nNonce); BOOST_CHECK(ProcessNewBlock(chainparams, pblock, true, NULL, NULL)); pblock->hashPrevBlock = pblock->GetHash(); } diff --git a/src/validation.cpp b/src/validation.cpp index e946cbcdc2..e98bc52652 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2957,6 +2957,11 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus setDirtyBlockIndex.insert(pindex); setBlockIndexCandidates.erase(pindex); + if (pindex == pindexBestHeader) { + pindexBestInvalid = pindexBestHeader; + pindexBestHeader = pindexBestHeader->pprev; + } + while (chainActive.Contains(pindex)) { CBlockIndex *pindexWalk = chainActive.Tip(); pindexWalk->nStatus |= BLOCK_FAILED_CHILD; @@ -2968,6 +2973,10 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); return false; } + if (pindexWalk == pindexBestHeader) { + pindexBestInvalid = pindexBestHeader; + pindexBestHeader = pindexBestHeader->pprev; + } } LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); @@ -3481,14 +3490,18 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state } // Exposed wrapper for AcceptBlockHeader -bool ProcessNewBlockHeaders(const std::vector& headers, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) +bool ProcessNewBlockHeaders(const std::vector& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex) { { LOCK(cs_main); for (const CBlockHeader& header : headers) { - if (!AcceptBlockHeader(header, state, chainparams, ppindex)) { + CBlockIndex *pindex = NULL; // Use a temp pindex instead of ppindex to avoid a const_cast + if (!AcceptBlockHeader(header, state, chainparams, &pindex)) { return false; } + if (ppindex) { + *ppindex = pindex; + } } } NotifyHeaderTip(); diff --git a/src/validation.h b/src/validation.h index ac9a32fbcb..e4c30af746 100644 --- a/src/validation.h +++ b/src/validation.h @@ -243,7 +243,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const CBlock* pblock, bool * @param[in] chainparams The params for the chain we want to connect to * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers */ -bool ProcessNewBlockHeaders(const std::vector& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL); +bool ProcessNewBlockHeaders(const std::vector& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=NULL); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ From 0365ff54d739841315f0e82cec7f6264810a3d08 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Mon, 9 Jul 2018 04:48:44 -0500 Subject: [PATCH 0028/1653] [GPU] More fixes (#4) --- src/miner-gpu.h | 1 - src/miner.cpp | 214 +++++++++++++++++++++++++++++++++++++++++------- src/miner.h | 2 +- 3 files changed, 187 insertions(+), 30 deletions(-) diff --git a/src/miner-gpu.h b/src/miner-gpu.h index 5bd0609b30..0709d526fe 100644 --- a/src/miner-gpu.h +++ b/src/miner-gpu.h @@ -4,7 +4,6 @@ #define DYNAMIC_ARGON2_GPU #ifdef ENABLE_GPU - #include #include "crypto/argon2gpu/common.h" diff --git a/src/miner.cpp b/src/miner.cpp index e20fbdcf2d..4880a3148b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -502,27 +502,174 @@ static void WaitForNetworkInit(const CChainParams& chainparams, CConnman& connma } } } +#ifdef ENABLE_GPU +static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex) { + std::string dev = "GPU"; + LogPrintf("DynamicMinerGPU -- started #%u@%s\n", nDeviceIndex, dev); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("dynamic-gpu-miner"); -static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex, bool fGPU) { + double* dHashesPerSec = &dGPUHashesPerSec; + unsigned int nExtraNonce = 0; - std::string dev = fGPU ? "GPU" : "CPU"; - LogPrintf("DynamicMiner -- started #%u@%s\n", nDeviceIndex, dev); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - if (fGPU) { - RenameThread("dynamic-gpu-miner"); + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + // Argon2GPU processingUnit = GetGPUProcessingUnit(nDeviceIndex); + Argon2GPUContext global; + auto& devices = global.getAllDevices(); + auto& device = devices[nDeviceIndex]; + Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); + Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); + Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); + + try { + // Throw an error if no script was provided. This can happen + // due to some internal error but also if the keypool is empty. + // In the latter case, already the pointer is NULL. + if (!coinbaseScript || coinbaseScript->reserveScript.empty()) + throw std::runtime_error("No coinbase script available (mining requires a wallet)"); + + while (true) { + // Wait for blocks if required + WaitForNetworkInit(chainparams, connman); + + // + // Create new block + // + unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + CBlockIndex* pindexPrev = chainActive.Tip(); + std::unique_ptr pblocktemplate; + if(!pindexPrev) break; + + pblocktemplate = std::unique_ptr (CreateNewBlock(chainparams, coinbaseScript->reserveScript)); + + if (!pblocktemplate.get()) + { + LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", dev); + return; + } + CBlock *pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + LogPrintf("DynamicMiner%s -- Running miner with %u transactions in block (%u bytes)\n", dev, pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + + // + // Search + // + int64_t nStart = GetTime(); + arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + uint256 hash; + while (true) + { + unsigned int nHashesDone = 0; + + uint256 hash; + while (true) { + hash = GetBlockHashGPU(pblock, &processingUnit); + //assert(hash == pblock->GetHash()); + if (UintToArith256(hash) <= hashTarget) + { + // Found a solution + //assert(hash == pblock->GetHash()); + SetThreadPriority(THREAD_PRIORITY_NORMAL); + LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", dev, hash.GetHex(), hashTarget.GetHex()); + ProcessBlockFound(pblock, chainparams, &connman); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + coinbaseScript->KeepScript(); + + // In regression test mode, stop mining after a block is found. + if (chainparams.MineBlocksOnDemand()) + throw boost::thread_interrupted(); + + break; + } + pblock->nNonce += 1; + nHashesDone += 1; + if ((pblock->nNonce & 0xFF) == 0) + break; + } + + // Meter hashes/seconds + static int64_t nHashCounter = 0; + static int64_t nLogTime = 0; + + if (nHPSTimerStart == 0) + { + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + } + else + nHashCounter += nHashesDone; + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + static CCriticalSection cs; + { + LOCK(cs); + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + if (GetTime() - nLogTime > 30 * 60) + { + nLogTime = GetTime(); + LogPrintf("gpu hashmeter %6.0f khash/s\n", *dHashesPerSec / 1000.0); + } + } + } + } + + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + // Regtest mode doesn't require peers + if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && chainparams.MiningRequiresPeers()) + break; + if (pblock->nNonce >= 0xffff0000) + break; + if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (pindexPrev != chainActive.Tip()) + break; + + // Update nTime every few seconds + if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) + break; // Recreate the block if the clock has run backwards, + // so that we can use the correct time. + if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) + { + // Changing pblock->nTime can change work required on testnet: + hashTarget.SetCompact(pblock->nBits); + } + } + } } - else { - RenameThread("dynamic-cpu-miner"); + catch (const boost::thread_interrupted&) + { + LogPrintf("DynamicMinerGPU -- terminated\n"); + throw; + } + catch (const std::runtime_error &e) + { + LogPrintf("DynamicMinerGPU -- runtime error: %s\n", e.what()); + return; } +} +#endif // ENABLE_GPU - double* dHashesPerSec = fGPU ? &dGPUHashesPerSec : &dCPUHashesPerSec; +static void DynamicMinerCPU(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex) { + std::string dev = "CPU"; + LogPrintf("DynamicMinerCPU -- started #%u@%s\n", nDeviceIndex, dev); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("dynamic-cpu-miner"); + + double* dHashesPerSec = &dCPUHashesPerSec; unsigned int nExtraNonce = 0; boost::shared_ptr coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); -#ifdef ENABLE_GPU - Argon2GPU processingUnit = GetProcessingUnit(nDeviceIndex, fGPU); -#endif // ENABLE_GPU + try { // Throw an error if no script was provided. This can happen // due to some internal error but also if the keypool is empty. @@ -567,14 +714,7 @@ static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std uint256 hash; while (true) { -#ifdef ENABLE_GPU - if (fGPU) - hash = GetBlockHashGPU(pblock, &processingUnit); - else - hash = pblock->GetHash(); -#else hash = pblock->GetHash(); -#endif // ENABLE_GPU if (UintToArith256(hash) <= hashTarget) { // Found a solution @@ -623,7 +763,7 @@ static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std if (GetTime() - nLogTime > 30 * 60) { nLogTime = GetTime(); - LogPrintf("hashmeter %6.0f khash/s\n", *dHashesPerSec / 1000.0); + LogPrintf("cpu hashmeter %6.0f khash/s\n", *dHashesPerSec / 1000.0); } } } @@ -655,16 +795,31 @@ static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std } catch (const boost::thread_interrupted&) { - LogPrintf("DynamicMiner -- terminated\n"); + LogPrintf("DynamicMinerCPU -- terminated\n"); throw; } catch (const std::runtime_error &e) { - LogPrintf("DynamicMiner -- runtime error: %s\n", e.what()); + LogPrintf("DynamicMinerCPU -- runtime error: %s\n", e.what()); return; } } +// TODO: that part changed in bitcoin, we are using a mix with old one here for now +static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex, bool fGPU) +{ +#ifdef ENABLE_GPU + if (fGPU) { + DynamicMinerGPU(chainparams, connman, nDeviceIndex); + } + else { + DynamicMinerCPU(chainparams, connman, nDeviceIndex); + } +#else + DynamicMinerCPU(chainparams, connman, nDeviceIndex); +#endif // ENABLE_GPU +} + static boost::thread_group* GetCPUMinerThreads(bool fInit = true, bool fRestart = true) { static boost::thread_group* minerThreadsCPU = NULL; @@ -779,24 +934,27 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai boost::thread_group* cpuMinerThreads = GetCPUMinerThreads(); - if (nCPUThreads < 0) - nCPUThreads = GetNumCores(); + int nNumCores = GetNumCores(); + LogPrintf("DynamicMiner -- CPU Cores: %u\n", nNumCores); + + if (nCPUThreads < 0 || nCPUThreads > nNumCores) + nCPUThreads = nNumCores; // Start CPU threads while (cpuMinerThreads->size() < nCPUThreads) { - std::size_t nThread = cpuMinerThreads->size() -1; + std::size_t nThread = cpuMinerThreads->size(); LogPrintf("Starting CPU Miner thread #%u\n", nThread); cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), nThread, false)); } - if (nGPUThreads < 0) - nGPUThreads = 1; + if (nGPUThreads < 0 || nGPUThreads > (int)devices) + nGPUThreads = devices; // Start GPU threads boost::thread_group* gpuMinerThreads = GetGPUMinerThreads(); //for (std::size_t device = 0; device < devices; device++) { for (std::size_t i = 0; i < nGPUThreads || i < devices; i++) { - LogPrintf("Starting GPU Miner thread %u on device %u\n", i, i); + LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, i, devices); gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), i, true)); } //} diff --git a/src/miner.h b/src/miner.h index d212015cc7..e93606d618 100644 --- a/src/miner.h +++ b/src/miner.h @@ -26,7 +26,7 @@ namespace Consensus { struct Params; }; static const bool DEFAULT_GENERATE = false; static const int DEFAULT_GENERATE_THREADS_CPU = -1; // TODO(crackcom): Set to -1 after autotune tests -static const int DEFAULT_GENERATE_THREADS_GPU = 1; +static const int DEFAULT_GENERATE_THREADS_GPU = -1; static const bool DEFAULT_PRINTPRIORITY = false; From 77934d42ac2b2d170578590ba08f6da9974a5435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Mon, 9 Jul 2018 11:52:10 +0200 Subject: [PATCH 0029/1653] [GPU] Remove uncuded cuda --- src/crypto/argon2gpu/cuda/cuda-exception.h | 12 ------ src/crypto/argon2gpu/cuda/device.h | 22 ----------- src/crypto/argon2gpu/cuda/global-context.h | 6 --- src/crypto/argon2gpu/cuda/kernels.h | 4 -- src/crypto/argon2gpu/cuda/processing-unit.h | 41 --------------------- src/crypto/argon2gpu/cuda/program-context.h | 29 --------------- 6 files changed, 114 deletions(-) diff --git a/src/crypto/argon2gpu/cuda/cuda-exception.h b/src/crypto/argon2gpu/cuda/cuda-exception.h index d6e47b9916..50a3b6e2c9 100644 --- a/src/crypto/argon2gpu/cuda/cuda-exception.h +++ b/src/crypto/argon2gpu/cuda/cuda-exception.h @@ -19,9 +19,7 @@ #ifndef ARGON2_CUDA_CUDAEXCEPTION_H #define ARGON2_CUDA_CUDAEXCEPTION_H -#if HAVE_CUDA #include -#endif #include @@ -30,8 +28,6 @@ namespace argon2gpu namespace cuda { -#if HAVE_CUDA - class CudaException : public std::exception { private: @@ -54,14 +50,6 @@ class CudaException : public std::exception } }; -#else - -class CudaException : public std::exception -{ -}; - -#endif - } // namespace cuda } // namespace argon2gpu diff --git a/src/crypto/argon2gpu/cuda/device.h b/src/crypto/argon2gpu/cuda/device.h index 1f0edc19a2..9407848298 100644 --- a/src/crypto/argon2gpu/cuda/device.h +++ b/src/crypto/argon2gpu/cuda/device.h @@ -26,8 +26,6 @@ namespace argon2gpu namespace cuda { -#if HAVE_CUDA - class Device { private: @@ -56,26 +54,6 @@ class Device Device &operator=(const Device &) = default; }; -#else - -class Device -{ - public: - std::string getName() const { return {}; } - std::string getInfo() const { return {}; } - - int getDeviceIndex() const { return 0; } - - Device() {} - - Device(const Device &) = default; - Device(Device &&) = default; - - Device &operator=(const Device &) = default; -}; - -#endif /* HAVE_CUDA */ - } // namespace cuda } // namespace argon2gpu diff --git a/src/crypto/argon2gpu/cuda/global-context.h b/src/crypto/argon2gpu/cuda/global-context.h index 5ff699dace..ea897fc18f 100644 --- a/src/crypto/argon2gpu/cuda/global-context.h +++ b/src/crypto/argon2gpu/cuda/global-context.h @@ -37,13 +37,7 @@ class GlobalContext public: const std::vector &getAllDevices() const { return devices; } -#if HAVE_CUDA GlobalContext(); -#else - GlobalContext() : devices() - { - } -#endif /* HAVE_CUDA */ }; } // namespace cuda diff --git a/src/crypto/argon2gpu/cuda/kernels.h b/src/crypto/argon2gpu/cuda/kernels.h index 861039a478..67f1ac6b8a 100644 --- a/src/crypto/argon2gpu/cuda/kernels.h +++ b/src/crypto/argon2gpu/cuda/kernels.h @@ -19,8 +19,6 @@ #ifndef ARGON2_CUDA_KERNELS_H #define ARGON2_CUDA_KERNELS_H -#if HAVE_CUDA - #include #include @@ -82,6 +80,4 @@ class KernelRunner } // namespace cuda } // namespace argon2gpu -#endif /* HAVE_CUDA */ - #endif // ARGON2_CUDA_KERNELS_H diff --git a/src/crypto/argon2gpu/cuda/processing-unit.h b/src/crypto/argon2gpu/cuda/processing-unit.h index 6a093ae32c..ff9b598406 100644 --- a/src/crypto/argon2gpu/cuda/processing-unit.h +++ b/src/crypto/argon2gpu/cuda/processing-unit.h @@ -19,8 +19,6 @@ #ifndef ARGON2_CUDA_PROCESSINGUNIT_H #define ARGON2_CUDA_PROCESSINGUNIT_H -#if HAVE_CUDA - #include #include "crypto/argon2gpu/common.h" @@ -63,43 +61,4 @@ class ProcessingUnit } // namespace cuda } // namespace argon2gpu -#else - -#include - -#include "crypto/argon2gpu/common.h" -#include "crypto/argon2gpu/cuda/program-context.h" - -namespace argon2gpu -{ -namespace cuda -{ -class ProcessingUnit -{ -public: - std::size_t getBatchSize() const { return 0; } - - ProcessingUnit( - const ProgramContext* programContext, - const Argon2Params* params, - const Device* device, - std::size_t batchSize, - bool bySegment = true, - bool precomputeRefs = false) - { - } - - void setInputAndSalt(std::size_t index, const void* input, std::size_t inputSize) {} - - void getHash(std::size_t index, void* hash) {} - - void beginProcessing() {} - void endProcessing() {} -}; - -} // namespace cuda -} // namespace argon2gpu - -#endif /* HAVE_CUDA */ - #endif // ARGON2_CUDA_PROCESSINGUNIT_H diff --git a/src/crypto/argon2gpu/cuda/program-context.h b/src/crypto/argon2gpu/cuda/program-context.h index 66bb4cffbd..4e9decc41b 100644 --- a/src/crypto/argon2gpu/cuda/program-context.h +++ b/src/crypto/argon2gpu/cuda/program-context.h @@ -26,7 +26,6 @@ namespace argon2gpu { namespace cuda { -#if HAVE_CUDA class ProgramContext { @@ -49,34 +48,6 @@ class ProgramContext Version version); }; -#else - -class ProgramContext -{ -private: - const GlobalContext* globalContext; - - Type type; - Version version; - -public: - const GlobalContext* getGlobalContext() const { return globalContext; } - - Type getArgon2Type() const { return type; } - Version getArgon2Version() const { return version; } - - ProgramContext( - const GlobalContext* globalContext, - const std::vector& devices, - Type type, - Version version) - : globalContext(globalContext), type(type), version(version) - { - } -}; - -#endif /* HAVE_CUDA */ - } // namespace cuda } // namespace argon2gpu From 6b04831c0df71d3923cd150789ca88a19fa141e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Mon, 9 Jul 2018 13:11:26 +0200 Subject: [PATCH 0030/1653] [GPU] Autoconf fixes --- configure.ac | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index fecc7cc41c..63171b1733 100644 --- a/configure.ac +++ b/configure.ac @@ -217,10 +217,6 @@ AC_ARG_ENABLE([debug], AC_LANG_PUSH([C++]) AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""]) -if test x$enable_gpu_mining != xno; then - AC_SUBST(ENABLE_GPU, 1) -fi - if test "x$enable_debug" = xyes; then CPPFLAGS="$CPPFLAGS -DDEBUG" if test "x$GCC" = xyes; then @@ -938,27 +934,24 @@ else AC_MSG_RESULT(no) fi -AC_DEFINE_UNQUOTED([ENABLE_GPU],[1],[Define to 1 to enable gpu functions]) -AC_DEFINE_UNQUOTED([HAVE_CUDA],[1],[Define to 1 to enable CUDA]) - -dnl Checking for nvcc -AC_MSG_CHECKING([nvcc in $cuda_prefix/bin]) -if test -x "$cuda_prefix/bin/nvcc"; then - AC_MSG_RESULT([found]) - AC_SUBST(HAVE_CUDA, 1) - AC_DEFINE_UNQUOTED([NVCC_PATH], ["$cuda_prefix/bin/nvcc"], [path to nvcc binary]) - HAVE_CUDA="1" - CUDA_CFLAGS="-I$cuda_prefix/include" - CUDA_LDFLAGS="-L$cuda_prefix/lib64 -L/usr/lib/x86_64-linux-gnu" - CUDA_NVCC_FLAGS="$CUDA_NVCC_FLAGS;-std=c++11;-O3;--ptxas-options=-v;-arch sm_30;-lineinfo" -else - AC_MSG_RESULT([not found!]) - AC_MSG_WARN([nvcc was not found in $cuda_prefix/bin]) -fi - -dnl if cuda has been found check the header and the lib -if test "$HAVE_CUDA" == "1"; then - AC_CHECK_HEADER([cuda_runtime.h],, AC_MSG_ERROR(libcuda headers missing),) +if test x$enable_gpu != xno; then + AC_DEFINE_UNQUOTED([ENABLE_GPU],[1],[Define to 1 to enable gpu functions]) + + dnl Checking for nvcc + AC_MSG_CHECKING([nvcc in $cuda_prefix/bin]) + if test -x "$cuda_prefix/bin/nvcc"; then + AC_MSG_RESULT([found]) + AC_DEFINE_UNQUOTED([NVCC_PATH], ["$cuda_prefix/bin/nvcc"], [path to nvcc binary]) + AC_CHECK_HEADER([cuda_runtime.h],, AC_MSG_ERROR(libcuda headers missing),) + AC_DEFINE_UNQUOTED([HAVE_CUDA],[1],[Define to 1 to enable CUDA]) + use_cuda=yes + CUDA_CFLAGS="-I$cuda_prefix/include" + CUDA_LDFLAGS="-L$cuda_prefix/lib64 -L/usr/lib/x86_64-linux-gnu" + CUDA_NVCC_FLAGS="$CUDA_NVCC_FLAGS;-std=c++11;-O3;--ptxas-options=-v;-arch sm_30;-lineinfo" + else + AC_MSG_RESULT([not found!]) + AC_MSG_WARN([nvcc was not found in $cuda_prefix/bin]) + fi fi dnl enable upnp support @@ -1066,7 +1059,7 @@ AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reo AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) AM_CONDITIONAL([ENABLE_SSE42],[test x$enable_sse42 = xyes]) -AM_CONDITIONAL([HAVE_CUDA], [test "${HAVE_CUDA}" = "1"]) +AM_CONDITIONAL([HAVE_CUDA],[test x$use_cuda = xyes]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) @@ -1089,6 +1082,7 @@ AC_SUBST(PIC_FLAGS) AC_SUBST(PIE_FLAGS) AC_SUBST(SSE42_CXXFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) +AC_SUBST(HAVE_CUDA) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) AC_SUBST(BOOST_LIBS) From 1711ef56d1b91a59a32efed62dcf52f0ceefff7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Mon, 9 Jul 2018 13:19:31 +0200 Subject: [PATCH 0031/1653] [GPU] Autoconf CUDA --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index 63171b1733..8de03550f7 100644 --- a/configure.ac +++ b/configure.ac @@ -1083,6 +1083,9 @@ AC_SUBST(PIE_FLAGS) AC_SUBST(SSE42_CXXFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(HAVE_CUDA) +AC_SUBST(CUDA_CFLAGS) +AC_SUBST(CUDA_LDFLAGS) +AC_SUBST(CUDA_NVCC_FLAGS) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) AC_SUBST(BOOST_LIBS) From c5c824fe2c10f36275f2438169131a3f6b8d4961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Tue, 10 Jul 2018 11:08:56 +0200 Subject: [PATCH 0032/1653] [GPU] CUDA autoconf - adds HAVE_CUDA to dynamic-config.h - defines ENABLE_CUDA in autoconf scope - TODO(crackcomm): compile CUDA kernel --- build-aux/m4/ax_check_cuda.m4 | 153 ++++++++++++++++++++++++++++++ build-aux/m4/ax_normalize_path.m4 | 115 ++++++++++++++++++++++ configure.ac | 54 +++++------ src/Makefile.gpu.include | 4 +- src/miner-gpu.h | 12 +-- 5 files changed, 294 insertions(+), 44 deletions(-) create mode 100644 build-aux/m4/ax_check_cuda.m4 create mode 100644 build-aux/m4/ax_normalize_path.m4 diff --git a/build-aux/m4/ax_check_cuda.m4 b/build-aux/m4/ax_check_cuda.m4 new file mode 100644 index 0000000000..360d2a3b6f --- /dev/null +++ b/build-aux/m4/ax_check_cuda.m4 @@ -0,0 +1,153 @@ +##### +# +# SYNOPSIS +# +# AX_CHECK_CUDA +# +# DESCRIPTION +# +# Figures out if CUDA Driver API/nvcc is available, i.e. existence of: +# nvcc +# cuda.h +# libcuda.a +# +# If something isn't found, fails straight away. +# +# The following variables are substituted in the makefile: +# NVCC : the nvcc compiler command. +# NVCCFLAGS : nvcc specific flags +# CUDA_CFLAGS : CUDA includes +# CUDA_LDLIBS : CUDA libraries +# +# Defines HAVE_CUDA in config.h +# +# LICENCE +# Public domain +# +##### + +AC_DEFUN([AX_CHECK_CUDA], [ + +# Provide your CUDA path with this +AC_ARG_WITH([cuda], + [AS_HELP_STRING([--with-cuda=PATH],[prefix where CUDA is installed @<:@default=no@:>@])], + [], + [with_cuda=no]) + +NVCC=no +CUDA_CFLAGS= +CUDA_LDLIBS= + +if test "x$with_cuda" != "xno" +then + + # ----------------------------------------- + # Setup CUDA paths + # ----------------------------------------- + if test "x$with_cuda" != "xyes" + then + AX_NORMALIZE_PATH([with_cuda], ["/"]) + CUDAPATH="$with_cuda" + CUDA_CFLAGS+=" -I$with_cuda/include" + CUDA_LDLIBS+=" -L$with_cuda/lib64" + else + AC_CHECK_FILE(/usr/local/cuda/,[CUDAPATH="/usr/local/cuda"],[]) + AC_CHECK_FILE(/usr/local/cuda/include,[CUDA_CFLAGS+=" -I/usr/local/cuda/include"],[CUDA_CFLAGS=""]) + AC_CHECK_FILE(/usr/local/cuda/lib64,[CUDA_LDLIBS+=" -L/usr/local/cuda/lib64"],[]) + fi + CUDA_LDLIBS+=" -lcuda -lcudart -lcublas" + + + # ----------------------------------------- + # Checking for nvcc + # ----------------------------------------- + AC_PATH_PROG([NVCC],[nvcc],[no],[$PATH:$CUDAPATH/bin]) + if test "x$NVCC" = "xno" + then + AC_MSG_ERROR([Cannot find nvcc compiler. To enable CUDA, please add path to + nvcc in the PATH environment variable and/or specify the path + where CUDA is installed using: --with-cuda=PATH]) + fi + + + # ----------------------------------------- + # Setup nvcc flags + # ----------------------------------------- + AC_ARG_VAR(NVCCFLAGS,[Additional nvcc flags (example: NVCCFLAGS="-arch=compute_30 -code=sm_30")]) + if test x$DEBUG = xtrue + then + NVCCFLAGS+=" -g" + else + NVCCFLAGS+=" -O3" + fi + AC_ARG_ENABLE([emu], + AC_HELP_STRING([--enable-emu],[turn on device emulation for CUDA]), + [case "${enableval}" in + yes) EMULATION=true;; + no) EMULATION=false;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-emu]);; + esac], + [EMULATION=false]) + if test x$EMULATION = xtrue + then + NVCCFLAGS+=" -deviceemu" + fi + + + # ----------------------------------------- + # Check if nvcc works + # ----------------------------------------- + ac_compile_nvcc=no + AC_MSG_CHECKING([whether nvcc works]) + cat>conftest.cu< /dev/null + then + ac_compile_nvcc=yes + fi + rm -f conftest.cu conftest.o + AC_MSG_RESULT([$ac_compile_nvcc]) + + if test "x$ac_compile_nvcc" = "xno" + then + AC_MSG_ERROR([CUDA compiler has problems.]) + fi + + + # ----------------------------------------- + # Check for headers and libraries + # ----------------------------------------- + ax_save_CXXFLAGS="${CXXFLAGS}" + ax_save_LIBS="${LIBS}" + + CXXFLAGS="$CUDA_CFLAGS $CXXFLAGS" + LIBS="$CUDA_LDLIBS $LIBS" + + # And the header and the lib + AC_CHECK_HEADER([cuda.h], [], AC_MSG_FAILURE([Couldn't find cuda.h]), [#include ]) + AC_CHECK_HEADER([cuda_runtime_api.h], [], AC_MSG_FAILURE([Couldn't find cuda_runtime_api.h]), [#include ]) + AC_CHECK_HEADER([cublas.h], [], AC_MSG_FAILURE([Couldn't find cublas.h]), [#include ]) + AC_CHECK_LIB([cuda], [cuInit], [], AC_MSG_FAILURE([Couldn't find libcuda])) + AC_CHECK_LIB([cudart], [cudaMalloc], [], AC_MSG_FAILURE([Couldn't find libcudart])) + AC_CHECK_LIB([cublas], [cublasInit], [], AC_MSG_FAILURE([Couldn't find libcublas])) + + # Returning to the original flags + CXXFLAGS=${ax_save_CXXFLAGS} + LIBS=${ax_save_LIBS} + + AC_DEFINE(HAVE_CUDA,1,[Define if we have CUDA]) +fi + + +# Announcing the new variables +AC_SUBST([NVCC]) +AC_SUBST([NVCCFLAGS]) +AC_SUBST([CUDA_CFLAGS]) +AC_SUBST([CUDA_LDLIBS]) +]) diff --git a/build-aux/m4/ax_normalize_path.m4 b/build-aux/m4/ax_normalize_path.m4 new file mode 100644 index 0000000000..b789a9369e --- /dev/null +++ b/build-aux/m4/ax_normalize_path.m4 @@ -0,0 +1,115 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_normalize_path.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_NORMALIZE_PATH(VARNAME, [REFERENCE_STRING]) +# +# DESCRIPTION +# +# Perform some cleanups on the value of $VARNAME (interpreted as a path): +# +# - empty paths are changed to '.' +# - trailing slashes are removed +# - repeated slashes are squeezed except a leading doubled slash '//' +# (which might indicate a networked disk on some OS). +# +# REFERENCE_STRING is used to turn '/' into '\' and vice-versa: if +# REFERENCE_STRING contains some backslashes, all slashes and backslashes +# are turned into backslashes, otherwise they are all turned into slashes. +# +# This makes processing of DOS filenames quite easier, because you can +# turn a filename to the Unix notation, make your processing, and turn it +# back to original notation. +# +# filename='A:\FOO\\BAR\' +# old_filename="$filename" +# # Switch to the unix notation +# AX_NORMALIZE_PATH([filename], ["/"]) +# # now we have $filename = 'A:/FOO/BAR' and we can process it as if +# # it was a Unix path. For instance let's say that you want +# # to append '/subpath': +# filename="$filename/subpath" +# # finally switch back to the original notation +# AX_NORMALIZE_PATH([filename], ["$old_filename"]) +# # now $filename equals to 'A:\FOO\BAR\subpath' +# +# One good reason to make all path processing with the unix convention is +# that backslashes have a special meaning in many cases. For instance +# +# expr 'A:\FOO' : 'A:\Foo' +# +# will return 0 because the second argument is a regex in which +# backslashes have to be backslashed. In other words, to have the two +# strings to match you should write this instead: +# +# expr 'A:\Foo' : 'A:\\Foo' +# +# Such behavior makes DOS filenames extremely unpleasant to work with. So +# temporary turn your paths to the Unix notation, and revert them to the +# original notation after the processing. See the macro +# AX_COMPUTE_RELATIVE_PATHS for a concrete example of this. +# +# REFERENCE_STRING defaults to $VARIABLE, this means that slashes will be +# converted to backslashes if $VARIABLE already contains some backslashes +# (see $thirddir below). +# +# firstdir='/usr/local//share' +# seconddir='C:\Program Files\\' +# thirddir='C:\home/usr/' +# AX_NORMALIZE_PATH([firstdir]) +# AX_NORMALIZE_PATH([seconddir]) +# AX_NORMALIZE_PATH([thirddir]) +# # $firstdir = '/usr/local/share' +# # $seconddir = 'C:\Program Files' +# # $thirddir = 'C:\home\usr' +# +# LICENSE +# +# Copyright (c) 2008 Alexandre Duret-Lutz +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 8 + +AU_ALIAS([ADL_NORMALIZE_PATH], [AX_NORMALIZE_PATH]) +AC_DEFUN([AX_NORMALIZE_PATH], +[case ":[$]$1:" in +# change empty paths to '.' + ::) $1='.' ;; +# strip trailing slashes + :*[[\\/]]:) $1=`echo "[$]$1" | sed 's,[[\\/]]*[$],,'` ;; + :*:) ;; +esac +# squeeze repeated slashes +case ifelse($2,,"[$]$1",$2) in +# if the path contains any backslashes, turn slashes into backslashes + *\\*) $1=`echo "[$]$1" | sed 's,\(.\)[[\\/]][[\\/]]*,\1\\\\,g'` ;; +# if the path contains slashes, also turn backslashes into slashes + *) $1=`echo "[$]$1" | sed 's,\(.\)[[\\/]][[\\/]]*,\1/,g'` ;; +esac]) diff --git a/configure.ac b/configure.ac index 8de03550f7..4a0e1a4b8c 100644 --- a/configure.ac +++ b/configure.ac @@ -91,17 +91,19 @@ AC_ARG_ENABLE([wallet], [enable_wallet=$enableval], [enable_wallet=yes]) -# TODO: enable by default if CUDA is found -# Enable GPU mining +# Enable GPU miner AC_ARG_ENABLE([gpu], - AS_HELP_STRING([--enable-gpu],[enable GPU mining (disabled by default)]), - [enable_gpu=$enableval], - [enable_gpu=yes]) - -AC_ARG_WITH([cuda], - [AS_HELP_STRING([--with-cuda],[prefix of the CUDA installation, e.g. /usr/local/cuda])], - [cuda_prefix=$withval], - [cuda_prefix="/usr/local/cuda"]) + [AS_HELP_STRING([--disable-gpu], + [disable GPU miner (enabled by default)])], + [enable_gpu=$enableval], + [enable_gpu=yes]) + +# Enable CUDA +AC_ARG_ENABLE([cuda], + [AS_HELP_STRING([--disable-cuda], + [disable CUDA miner, use OpenCL instead (only GPU; enabled by default)])], + [enable_cuda=$enableval], + [enable_cuda=yes]) AC_ARG_WITH([miniupnpc], [AS_HELP_STRING([--with-miniupnpc], @@ -934,23 +936,15 @@ else AC_MSG_RESULT(no) fi -if test x$enable_gpu != xno; then - AC_DEFINE_UNQUOTED([ENABLE_GPU],[1],[Define to 1 to enable gpu functions]) - - dnl Checking for nvcc - AC_MSG_CHECKING([nvcc in $cuda_prefix/bin]) - if test -x "$cuda_prefix/bin/nvcc"; then - AC_MSG_RESULT([found]) - AC_DEFINE_UNQUOTED([NVCC_PATH], ["$cuda_prefix/bin/nvcc"], [path to nvcc binary]) - AC_CHECK_HEADER([cuda_runtime.h],, AC_MSG_ERROR(libcuda headers missing),) - AC_DEFINE_UNQUOTED([HAVE_CUDA],[1],[Define to 1 to enable CUDA]) - use_cuda=yes - CUDA_CFLAGS="-I$cuda_prefix/include" - CUDA_LDFLAGS="-L$cuda_prefix/lib64 -L/usr/lib/x86_64-linux-gnu" - CUDA_NVCC_FLAGS="$CUDA_NVCC_FLAGS;-std=c++11;-O3;--ptxas-options=-v;-arch sm_30;-lineinfo" - else - AC_MSG_RESULT([not found!]) - AC_MSG_WARN([nvcc was not found in $cuda_prefix/bin]) +if test x$enable_gpu = xyes; then + AC_DEFINE_UNQUOTED([ENABLE_GPU],[1],[Define to 1 to enable GPU miner]) + + if test "x$enable_cuda" = xyes; then + AX_CHECK_CUDA + if test "x$NVCC" = xno; then + enable_cuda=no + AC_MSG_FAILURE([NVIDIA CUDA nvcc compiler not found or CUDA support disabled. Check the $PATH variable to CUDA or specify --with-cuda=/path/to/cuda]) + fi fi fi @@ -1047,6 +1041,7 @@ AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_GPU],[test x$enable_gpu = xyes]) +AM_CONDITIONAL([ENABLE_CUDA], [test x"$enable_cuda" = xyes]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$dynamic_enable_qt = xyes]) @@ -1059,7 +1054,6 @@ AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reo AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) AM_CONDITIONAL([ENABLE_SSE42],[test x$enable_sse42 = xyes]) -AM_CONDITIONAL([HAVE_CUDA],[test x$use_cuda = xyes]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) @@ -1082,10 +1076,6 @@ AC_SUBST(PIC_FLAGS) AC_SUBST(PIE_FLAGS) AC_SUBST(SSE42_CXXFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) -AC_SUBST(HAVE_CUDA) -AC_SUBST(CUDA_CFLAGS) -AC_SUBST(CUDA_LDFLAGS) -AC_SUBST(CUDA_NVCC_FLAGS) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) AC_SUBST(BOOST_LIBS) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index 88da792e0e..cf1ca26da8 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -7,7 +7,7 @@ LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a DYNAMIC_INCLUDES += $(CUDA_CFLAGS) EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) -LIBDYNAMIC_GPU_LDADD = $(CUDA_LDFLAGS) $(LIBDYNAMIC_GPU) +LIBDYNAMIC_GPU_LDADD = $(CUDA_LDLIBS) $(LIBDYNAMIC_GPU) if TARGET_DARWIN LIBDYNAMIC_GPU_LDADD += "-framework OpenCL" @@ -23,7 +23,7 @@ crypto_argon2gpu_libdynamic_gpu_a_SOURCES = \ crypto/argon2gpu/common.cpp \ crypto/argon2gpu/blake2b.cpp -if HAVE_CUDA +if ENABLE_CUDA crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ crypto/argon2gpu/cuda/cuda-exception.h \ crypto/argon2gpu/cuda/device.h \ diff --git a/src/miner-gpu.h b/src/miner-gpu.h index 0709d526fe..47031ca9a0 100644 --- a/src/miner-gpu.h +++ b/src/miner-gpu.h @@ -8,10 +8,7 @@ #include "crypto/argon2gpu/common.h" -// TODO: configure script -#define HAVE_CUDA 1 - -#ifdef HAVE_CUDA +#if HAVE_CUDA #include "crypto/argon2gpu/cuda/cuda-exception.h" #include "crypto/argon2gpu/cuda/processing-unit.h" #else @@ -21,7 +18,7 @@ using Argon2GPUParams = argon2gpu::Argon2Params; -#ifdef HAVE_CUDA +#if HAVE_CUDA using Argon2GPU = argon2gpu::cuda::ProcessingUnit; using Argon2GPUDevice = argon2gpu::cuda::Device; using Argon2GPUContext = argon2gpu::cuda::GlobalContext; @@ -71,11 +68,6 @@ inline uint256 GetBlockHashGPU(const CBlockHeader* block, const Pu& pu) pu->getHash(0, (uint8_t*)&hashResult); return hashResult; } -#else -static std::size_t GetGPUDeviceCount() -{ - return 0; -} #endif // ENABLE_GPU #endif // DYNAMIC_ARGON2_GPU From 2dc18d7368563a45f269ef4f7a2b8b8fb900dd1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Tue, 10 Jul 2018 11:20:35 +0200 Subject: [PATCH 0033/1653] [GPU] Use OpenCL if CUDA is not found --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4a0e1a4b8c..7bf421796c 100644 --- a/configure.ac +++ b/configure.ac @@ -943,7 +943,7 @@ if test x$enable_gpu = xyes; then AX_CHECK_CUDA if test "x$NVCC" = xno; then enable_cuda=no - AC_MSG_FAILURE([NVIDIA CUDA nvcc compiler not found or CUDA support disabled. Check the $PATH variable to CUDA or specify --with-cuda=/path/to/cuda]) + AC_MSG_WARN([NVIDIA CUDA nvcc compiler not found, falling back on OpenCL. Specify --with-cuda=/path/to/cuda]) fi fi fi From 09dd38d7335c80959d86a394f636e5d565288659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Tue, 10 Jul 2018 12:06:47 +0200 Subject: [PATCH 0034/1653] [GPU] First attempt on NVCC build --- src/Makefile.gpu.include | 87 +++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index cf1ca26da8..1e261db4d1 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -3,18 +3,10 @@ # LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a +LIBDYNAMIC_GPU_LDADD = $(LIBDYNAMIC_GPU) -DYNAMIC_INCLUDES += $(CUDA_CFLAGS) EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) -LIBDYNAMIC_GPU_LDADD = $(CUDA_LDLIBS) $(LIBDYNAMIC_GPU) - -if TARGET_DARWIN - LIBDYNAMIC_GPU_LDADD += "-framework OpenCL" -else - LIBDYNAMIC_GPU_LDADD += -lOpenCL -endif - crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) crypto_argon2gpu_libdynamic_gpu_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_argon2gpu_libdynamic_gpu_a_SOURCES = \ @@ -24,34 +16,57 @@ crypto_argon2gpu_libdynamic_gpu_a_SOURCES = \ crypto/argon2gpu/blake2b.cpp if ENABLE_CUDA - crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ - crypto/argon2gpu/cuda/cuda-exception.h \ - crypto/argon2gpu/cuda/device.h \ - crypto/argon2gpu/cuda/global-context.h \ - crypto/argon2gpu/cuda/kernels.h \ - crypto/argon2gpu/cuda/processing-unit.h \ - crypto/argon2gpu/cuda/program-context.h \ - crypto/argon2gpu/cuda/device.cpp \ - crypto/argon2gpu/cuda/global-context.cpp \ - crypto/argon2gpu/cuda/kernels.cu \ - crypto/argon2gpu/cuda/processing-unit.cpp \ - crypto/argon2gpu/cuda/program-context.cpp +crypto_argon2gpu_libdynamic_gpu_a_LDADD = $(CUDA_LDLIBS) +crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS += $(CUDA_CFLAGS) +crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ + crypto/argon2gpu/cuda/cuda-exception.h \ + crypto/argon2gpu/cuda/device.h \ + crypto/argon2gpu/cuda/global-context.h \ + crypto/argon2gpu/cuda/kernels.h \ + crypto/argon2gpu/cuda/processing-unit.h \ + crypto/argon2gpu/cuda/program-context.h \ + crypto/argon2gpu/cuda/device.cpp \ + crypto/argon2gpu/cuda/global-context.cpp \ + crypto/argon2gpu/cuda/kernels.cu \ + crypto/argon2gpu/cuda/processing-unit.cpp \ + crypto/argon2gpu/cuda/program-context.cpp + +DYNAMIC_INCLUDES += $(CUDA_CFLAGS) +LIBDYNAMIC_GPU_LDADD += $(CUDA_LDLIBS) + +NVCCFLAGS += -std=c++11 --ptxas-options=-v -arch sm_30 -lineinfo + +.cu.o: + $(NVCC) $(CFLAGS) $(NVCCFLAGS) -o $@ -c $< + +crypto/argon2gpu/cuda/kernels.o: crypto/argon2gpu/cuda/kernels.cu + $(NVCC) $(CFLAGS) $(NVCCFLAGS) -o $@ -c $< + +else +if TARGET_DARWIN + LIBOPENCL = "-framework OpenCL" else - crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ - crypto/argon2gpu/opencl/cl.hpp \ - crypto/argon2gpu/opencl/device.h \ - crypto/argon2gpu/opencl/global-context.h \ - crypto/argon2gpu/opencl/kernel-loader.h \ - crypto/argon2gpu/opencl/kernel-runner.h \ - crypto/argon2gpu/opencl/opencl.h \ - crypto/argon2gpu/opencl/processing-unit.h \ - crypto/argon2gpu/opencl/program-context.h \ - crypto/argon2gpu/opencl/device.cpp \ - crypto/argon2gpu/opencl/global-context.cpp \ - crypto/argon2gpu/opencl/kernel-loader.cpp \ - crypto/argon2gpu/opencl/kernel-runner.cpp \ - crypto/argon2gpu/opencl/processing-unit.cpp \ - crypto/argon2gpu/opencl/program-context.cpp + LIBOPENCL = -lOpenCL +endif + +crypto_argon2gpu_libdynamic_gpu_a_LDADD = $(LIBOPENCL) +crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ + crypto/argon2gpu/opencl/cl.hpp \ + crypto/argon2gpu/opencl/device.h \ + crypto/argon2gpu/opencl/global-context.h \ + crypto/argon2gpu/opencl/kernel-loader.h \ + crypto/argon2gpu/opencl/kernel-runner.h \ + crypto/argon2gpu/opencl/opencl.h \ + crypto/argon2gpu/opencl/processing-unit.h \ + crypto/argon2gpu/opencl/program-context.h \ + crypto/argon2gpu/opencl/device.cpp \ + crypto/argon2gpu/opencl/global-context.cpp \ + crypto/argon2gpu/opencl/kernel-loader.cpp \ + crypto/argon2gpu/opencl/kernel-runner.cpp \ + crypto/argon2gpu/opencl/processing-unit.cpp \ + crypto/argon2gpu/opencl/program-context.cpp + +LIBDYNAMIC_GPU_LDADD += $(LIBOPENCL) endif dynamicd_LDADD += $(LIBDYNAMIC_GPU_LDADD) From 45e332c1d49c32a47ac66f97a74b7ae0de2028df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Tue, 10 Jul 2018 12:10:35 +0200 Subject: [PATCH 0035/1653] [GPU] Remove unused functions --- src/miner-gpu.h | 17 ----------------- src/miner.cpp | 10 ++++++---- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/miner-gpu.h b/src/miner-gpu.h index 47031ca9a0..e7b67c212a 100644 --- a/src/miner-gpu.h +++ b/src/miner-gpu.h @@ -36,23 +36,6 @@ static std::size_t GetGPUDeviceCount() return global.getAllDevices().size(); } -static Argon2GPU GetProcessingUnit(std::size_t nDeviceIndex, bool fGPU) { - if (!fGPU) { - Argon2GPU processingUnit(nullptr, nullptr, nullptr, 1, false, false); - return processingUnit; - } - else { - // Argon2GPU processingUnit = GetGPUProcessingUnit(nDeviceIndex); - Argon2GPUContext global; - auto& devices = global.getAllDevices(); - auto& device = devices[nDeviceIndex]; - Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); - Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); - Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); - return processingUnit; - } -} - template inline uint256 GetBlockHashGPU(const CBlockHeader* block, const Pu& pu) { diff --git a/src/miner.cpp b/src/miner.cpp index 4880a3148b..ba8e2bf313 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -515,7 +515,6 @@ static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, boost::shared_ptr coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); - // Argon2GPU processingUnit = GetGPUProcessingUnit(nDeviceIndex); Argon2GPUContext global; auto& devices = global.getAllDevices(); auto& device = devices[nDeviceIndex]; @@ -894,14 +893,17 @@ void AutoTuneDeviceThreads(const CChainParams& chainparams, CConnman& connman, s void GenerateAutoTuneDevice(const CChainParams& chainparams, CConnman& connman, bool fGPU) { - if (!fGPU) { - AutoTuneDeviceThreads(chainparams, connman); - } else { +#ifdef ENABLE_GPU + if (fGPU) { // Start GPU threads for (std::size_t device = 0; device < GetGPUDeviceCount(); device++) { AutoTuneDeviceThreads(chainparams, connman, device, true); } + return; } +#endif + + AutoTuneDeviceThreads(chainparams, connman); } void GenerateDynamicsAutoTune(const CChainParams& chainparams, CConnman& connman) From e2dd01c11693d696cbb9fd61d0012ad3a57aa998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Tue, 10 Jul 2018 12:11:51 +0200 Subject: [PATCH 0036/1653] [GPU] Autoconf use LIBADD instead of LDADD --- src/Makefile.gpu.include | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index 1e261db4d1..55b5ae6037 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -16,7 +16,7 @@ crypto_argon2gpu_libdynamic_gpu_a_SOURCES = \ crypto/argon2gpu/blake2b.cpp if ENABLE_CUDA -crypto_argon2gpu_libdynamic_gpu_a_LDADD = $(CUDA_LDLIBS) +crypto_argon2gpu_libdynamic_gpu_a_LIBADD = $(CUDA_LDLIBS) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS += $(CUDA_CFLAGS) crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ crypto/argon2gpu/cuda/cuda-exception.h \ @@ -49,7 +49,7 @@ else LIBOPENCL = -lOpenCL endif -crypto_argon2gpu_libdynamic_gpu_a_LDADD = $(LIBOPENCL) +crypto_argon2gpu_libdynamic_gpu_a_LIBADD = $(LIBOPENCL) crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ crypto/argon2gpu/opencl/cl.hpp \ crypto/argon2gpu/opencl/device.h \ From b1bbc9f5106cffbaf56000e80287de7e25810529 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 11 Jul 2018 17:35:17 -0500 Subject: [PATCH 0037/1653] [BDAP] Fix unserialize CDirectory from transaction --- src/bdap/directory.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index 578c53d6c5..723b0cf200 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -93,8 +93,11 @@ bool GetDirectoryData(const CScript& scriptPubKey, std::vector& v return false; if (!scriptPubKey.GetOp(pc, opcode, vchData)) return false; - if (!scriptPubKey.GetOp(pc, opcode, vchHash)) - return false; + + uint256 hash; + hash = Hash(vchData.begin(), vchData.end()); + vchHash = vchFromValue(hash.GetHex()); + return true; } From 72823e9c409fba060d9822a0f0267449ca1ecfbc Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 11 Jul 2018 18:27:04 -0500 Subject: [PATCH 0038/1653] [BDAP] Add checkpoint function for directory entries --- src/bdap/directory.cpp | 8 ++++++++ src/bdap/directory.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index 723b0cf200..978041f3a4 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -168,6 +168,14 @@ std::vector CDirectory::vchFullObjectPath() const { return vchReturnValue; } +void CDirectory::AddCheckpoint(const uint32_t& height, const CharString& vchHash) +{ + std::pair pairNewCheckpoint; + pairNewCheckpoint.first = height; + pairNewCheckpoint.second = vchHash; + CheckpointHashes.push_back(pairNewCheckpoint); +} + void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) { UniValue oName(UniValue::VOBJ); if (BuildBDAPJson(directory, oName)) { diff --git a/src/bdap/directory.h b/src/bdap/directory.h index 3aa1d9d812..6f3eec0c69 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -208,6 +208,7 @@ class CDirectory { CDynamicAddress GetWalletAddress() const; std::string GetFullObjectPath() const; std::vector vchFullObjectPath() const; + void AddCheckpoint(const uint32_t& height, const CharString& vchHash); }; class CDirectoryDB : public CDBWrapper { From 40645e4d9fa3f1ea6dd60bf7a904a7b71e64ead0 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 11 Jul 2018 19:59:11 -0500 Subject: [PATCH 0039/1653] [BDAP] Check and validate values in CDirectory before sending --- src/bdap/directory.cpp | 120 +++++++++++++++++++++++++++++++++++++- src/bdap/directory.h | 18 +++--- src/bdap/rpcdirectory.cpp | 20 +++---- 3 files changed, 135 insertions(+), 23 deletions(-) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index 978041f3a4..e7034af005 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -14,6 +14,11 @@ #include +#include +#include + +using namespace boost::xpressive; + CDirectoryDB *pDirectoryDB = NULL; bool IsDirectoryTransaction(CScript txOut) { @@ -176,6 +181,120 @@ void CDirectory::AddCheckpoint(const uint32_t& height, const CharString& vchHash CheckpointHashes.push_back(pairNewCheckpoint); } +bool CDirectory::ValidateValues(std::string& errorMessage) +{ + smatch sMatch; + std::string regExWithDot = "^((?!-)[a-z0-9-]{2," + std::to_string(MAX_OBJECT_NAME_LENGTH) + "}(? MAX_COMMON_NAME_LENGTH) + { + errorMessage = "Invalid BDAP common name. Can not have more than " + std::to_string(MAX_COMMON_NAME_LENGTH) + " characters."; + return false; + } + + // check object organization name component + std::string strOrganizationName = stringFromVch(OrganizationName); + if (strOrganizationName.length() > MAX_ORG_NAME_LENGTH) + { + errorMessage = "Invalid BDAP organization name. Can not have more than " + std::to_string(MAX_ORG_NAME_LENGTH) + " characters."; + return false; + } + + // check resource pointer component + std::string strResourcePointer = stringFromVch(ResourcePointer); + if (strResourcePointer.length() > MAX_RESOURCE_POINTER_LENGTH) + { + errorMessage = "Invalid BDAP resource pointer. Can not have more than " + std::to_string(MAX_RESOURCE_POINTER_LENGTH) + " characters."; + return false; + } + + // check certificate component + std::string strCertificate = stringFromVch(Certificate); + if (strCertificate.length() > MAX_CERTIFICATE_LENGTH) + { + errorMessage = "Invalid BDAP Certificate data. Can not have more than " + std::to_string(MAX_CERTIFICATE_LENGTH) + " characters."; + return false; + } + + // check private data component + std::string strPrivateData = stringFromVch(PrivateData); + if (strPrivateData.length() > MAX_PRIVATE_DATA_LENGTH) + { + errorMessage = "Invalid BDAP private data. Can not have more than " + std::to_string(MAX_PRIVATE_DATA_LENGTH) + " characters."; + return false; + } + + // make sure the number of checkpoints does not exceed limit + if (CheckpointHashes.size() > MAX_NUMBER_CHECKPOINTS) + { + errorMessage = "Invalid BDAP checkpoint count. Can not have more than " + std::to_string(MAX_NUMBER_CHECKPOINTS) + " checkpoints for one entry."; + return false; + } + // TODO: (bdap) check if EncryptPublicKey is valid + // TODO: (bdap) check WalletAddress and SignWalletAddress + return true; +} + void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) { UniValue oName(UniValue::VOBJ); if (BuildBDAPJson(directory, oName)) { @@ -202,7 +321,6 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) oName.push_back(Pair("signature_address", stringFromVch(directory.SignWalletAddress))); oName.push_back(Pair("public", (int)directory.fPublicObject)); oName.push_back(Pair("encryption_publickey", HexStr(directory.EncryptPublicKey))); - oName.push_back(Pair("encryption_privatekey", stringFromVch(directory.EncryptPrivateKey))); oName.push_back(Pair("sigatures_required", (int)directory.nSigaturesRequired)); oName.push_back(Pair("resource_pointer", stringFromVch(directory.ResourcePointer))); oName.push_back(Pair("txid", directory.txHash.GetHex())); diff --git a/src/bdap/directory.h b/src/bdap/directory.h index 6f3eec0c69..cf9d137f20 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -24,13 +24,14 @@ typedef std::vector vchCharString; typedef std::vector > vCheckPoints; // << height, block hash >> static const unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) -static const unsigned int MAX_DOMAIN_NAME_LENGTH = 128; -static const unsigned int MAX_OBJECT_NAME_LENGTH = 128; -static const unsigned int MAX_RESOURCE_POINTER_LENGTH = 128; +static const unsigned int MAX_OBJECT_NAME_LENGTH = 63; +static const unsigned int MAX_COMMON_NAME_LENGTH = 95; +static const unsigned int MAX_ORG_NAME_LENGTH = 95; +static const unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; static const unsigned int MAX_KEY_LENGTH = 156; -static const unsigned int MAX_PUBLIC_VALUE_LENGTH = 512; -static const unsigned int MAX_SECRET_VALUE_LENGTH = 512; // Pay per byte for hosting on chain -static const unsigned int MAX_NUMBER_CHECKPOINTS = 1000; // Pay per byte for hosting on chain +static const unsigned int MAX_CERTIFICATE_LENGTH = 512; +static const unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain +static const unsigned int MAX_NUMBER_CHECKPOINTS = 100; // Pay per byte for hosting on chain static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; static const std::string DEFAULT_PUBLIC_OU = "public"; static const std::string DEFAULT_ADMIN_OU = "admin"; @@ -87,7 +88,6 @@ class CDirectory { CharString WalletAddress; // used to send collateral funds for this directory record. int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. - CharString EncryptPrivateKey; // used to decrypt messages and data for this directory record CharString SignWalletAddress; // used to verify authorized update transaction unsigned int nSigaturesRequired; // number of signatures needed to approve a transaction. Default = 1 CharString ResourcePointer; // used to point to a domain shared resource like a stream (video, audio, file sharing), P2P storage (BitTorrent or IPFS network), or private cloud storage @@ -125,7 +125,6 @@ class CDirectory { WalletAddress.clear(); fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); - EncryptPrivateKey.clear(); SignWalletAddress.clear(); nSigaturesRequired = 1; ResourcePointer.clear(); @@ -154,7 +153,6 @@ class CDirectory { READWRITE(WalletAddress); READWRITE(VARINT(fPublicObject)); READWRITE(EncryptPublicKey); - READWRITE(EncryptPrivateKey); READWRITE(SignWalletAddress); READWRITE(VARINT(nSigaturesRequired)); READWRITE(ResourcePointer); @@ -187,7 +185,6 @@ class CDirectory { WalletAddress = b.WalletAddress; fPublicObject = b.fPublicObject; EncryptPublicKey = b.EncryptPublicKey; - EncryptPrivateKey = b.EncryptPrivateKey; SignWalletAddress = b.SignWalletAddress; nSigaturesRequired = b.nSigaturesRequired; ResourcePointer = b.ResourcePointer; @@ -209,6 +206,7 @@ class CDirectory { std::string GetFullObjectPath() const; std::vector vchFullObjectPath() const; void AddCheckpoint(const uint32_t& height, const CharString& vchHash); + bool ValidateValues(std::string& errorMessage); }; class CDirectoryDB : public CDBWrapper { diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 94c4cde874..24952158c3 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -11,10 +11,6 @@ #include -#include - -using namespace boost::xpressive; - extern void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdapOPScript, CWalletTx& wtxNew, CAmount nOPValue, CAmount nDataValue); UniValue addpublicname(const JSONRPCRequest& request) { @@ -28,11 +24,6 @@ UniValue addpublicname(const JSONRPCRequest& request) { // Format object and domain names to lower case. std::string strObjectID = request.params[0].get_str(); ToLowerCase(strObjectID); - // Check if the object name is valid. - sregex regexValidName = sregex::compile("^((?!-)[a-z0-9-]{2,64}(? Date: Wed, 11 Jul 2018 20:28:27 -0500 Subject: [PATCH 0040/1653] [BDAP] Add debug print after new public name RPC --- src/bdap/rpcdirectory.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 24952158c3..8c0cfd2b7f 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -4,6 +4,7 @@ #include "bdap/directory.h" +#include "core_io.h" // needed for ScriptToAsmStr #include "rpcprotocol.h" #include "rpcserver.h" #include "primitives/transaction.h" @@ -13,6 +14,8 @@ extern void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdapOPScript, CWalletTx& wtxNew, CAmount nOPValue, CAmount nDataValue); +static constexpr bool fPrintDebug = true; + UniValue addpublicname(const JSONRPCRequest& request) { if (request.params.size() != 2) { throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); @@ -120,6 +123,18 @@ UniValue addpublicname(const JSONRPCRequest& request) { UniValue oName(UniValue::VOBJ); if(!BuildBDAPJson(txDirectory, oName)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Failed to read from BDAP JSON object")); + + if (fPrintDebug) { + // make sure we can deserialize the transaction from the scriptData and get a valid CDirectory class + LogPrintf("Directory Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); + + const CTransaction testTx = (CTransaction)wtx; + CDirectory testDirectory(testTx); //loads the class from a transaction + + LogPrintf("CDirectory Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\nPrivateData = %s\n", + testDirectory.nVersion, testDirectory.GetFullObjectPath(), stringFromVch(testDirectory.CommonName), + stringFromVch(testDirectory.OrganizationalUnit), HexStr(testDirectory.EncryptPublicKey), stringFromVch(testDirectory.PrivateData)); + } return oName; } From c302f47d1c579d9a83514d078d6e8b490ea34a1b Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 12 Jul 2018 01:21:25 -0500 Subject: [PATCH 0041/1653] [BDAP] Use constexpr and inline string const to vch --- src/bdap/directory.h | 39 +++++++++++++++++++++++++-------------- src/bdap/rpcdirectory.cpp | 14 +++++--------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/bdap/directory.h b/src/bdap/directory.h index cf9d137f20..d7644b89e6 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -23,20 +23,31 @@ typedef std::vector CharString; typedef std::vector vchCharString; typedef std::vector > vCheckPoints; // << height, block hash >> -static const unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) -static const unsigned int MAX_OBJECT_NAME_LENGTH = 63; -static const unsigned int MAX_COMMON_NAME_LENGTH = 95; -static const unsigned int MAX_ORG_NAME_LENGTH = 95; -static const unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; -static const unsigned int MAX_KEY_LENGTH = 156; -static const unsigned int MAX_CERTIFICATE_LENGTH = 512; -static const unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain -static const unsigned int MAX_NUMBER_CHECKPOINTS = 100; // Pay per byte for hosting on chain -static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; -static const std::string DEFAULT_PUBLIC_OU = "public"; -static const std::string DEFAULT_ADMIN_OU = "admin"; -static const std::string DEFAULT_ORGANIZATION_NAME = "Duality Blockchain Solutions"; -static const std::string DEFAULT_OID_PREFIX = "0.0.0"; //TODO. Get a real OID prefix. +static constexpr unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) +static constexpr unsigned int MAX_OBJECT_NAME_LENGTH = 63; +static constexpr unsigned int MAX_COMMON_NAME_LENGTH = 95; +static constexpr unsigned int MAX_ORG_NAME_LENGTH = 95; +static constexpr unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; +static constexpr unsigned int MAX_KEY_LENGTH = 156; +static constexpr unsigned int MAX_CERTIFICATE_LENGTH = 512; +static constexpr unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain +static constexpr unsigned int MAX_NUMBER_CHECKPOINTS = 100; // Pay per byte for hosting on chain +static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; +static const std::string DEFAULT_PUBLIC_OU = "public"; +static const std::string DEFAULT_ADMIN_OU = "admin"; +static const std::string DEFAULT_ORGANIZATION_NAME = "Duality Blockchain Solutions"; +static const std::string DEFAULT_OID_PREFIX = "0.0.0"; + +inline const CharString ConvertConstantToCharString (const std::string strConvert) +{ + CharString vchConvert(strConvert.begin(), strConvert.end()); + return vchConvert; +}; +static const CharString vchDefaultDomainName = ConvertConstantToCharString(DEFAULT_PUBLIC_DOMAIN); +static const CharString vchDefaultPublicOU = ConvertConstantToCharString(DEFAULT_PUBLIC_OU); +static const CharString vchDefaultAdminOU = ConvertConstantToCharString(DEFAULT_ADMIN_OU); +static const CharString vchDefaultOrganizationName = ConvertConstantToCharString(DEFAULT_ORGANIZATION_NAME); +static const CharString vchDefaultOIDPrefix = ConvertConstantToCharString(DEFAULT_OID_PREFIX); /* Blockchain Directory Access Framework diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 8c0cfd2b7f..c4f7a9fcfd 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -32,20 +32,16 @@ UniValue addpublicname(const JSONRPCRequest& request) { ToLowerCase(vchObjectID); CharString vchCommonName = vchFromValue(request.params[1]); - CharString vchDomainComponent(DEFAULT_PUBLIC_DOMAIN.begin(), DEFAULT_PUBLIC_DOMAIN.end()); - CharString vchOrganizationalUnit(DEFAULT_PUBLIC_OU.begin(), DEFAULT_PUBLIC_OU.end()); - CharString vchOrganizationName (DEFAULT_ORGANIZATION_NAME.begin(), DEFAULT_ORGANIZATION_NAME.end()); - CharString vchOID (DEFAULT_OID_PREFIX.begin(), DEFAULT_OID_PREFIX.end()); // Check if name already exists - if (CheckIfNameExists(vchObjectID, vchOrganizationalUnit, vchDomainComponent)) + if (CheckIfNameExists(vchObjectID, vchDefaultPublicOU, vchDefaultDomainName)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3500 - " + _("This public name already exists")); CDirectory txDirectory; - txDirectory.OID = vchOID; - txDirectory.DomainComponent = vchDomainComponent; - txDirectory.OrganizationalUnit = vchOrganizationalUnit; + txDirectory.OID = vchDefaultOIDPrefix; + txDirectory.DomainComponent = vchDefaultDomainName; + txDirectory.OrganizationalUnit = vchDefaultPublicOU; txDirectory.CommonName = vchCommonName; - txDirectory.OrganizationName = vchOrganizationName; + txDirectory.OrganizationName = vchDefaultOrganizationName; txDirectory.ObjectID = vchObjectID; txDirectory.fPublicObject = 1; //make entry public txDirectory.transactionFee = 100; From c91e559d6f71933417cc6e642713e5b0f27986b4 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 15 Jul 2018 23:43:48 -0500 Subject: [PATCH 0042/1653] [BDAP] Move leveldb code to seperate code file --- src/Makefile.am | 2 ++ src/bdap/directory.cpp | 10 ---------- src/bdap/directory.h | 35 ----------------------------------- src/bdap/directorydb.cpp | 27 +++++++++++++++++++++++++++ src/bdap/directorydb.h | 38 ++++++++++++++++++++++++++++++++++++++ src/bdap/rpcdirectory.cpp | 2 +- src/init.cpp | 5 +++-- 7 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 src/bdap/directorydb.cpp create mode 100644 src/bdap/directorydb.h diff --git a/src/Makefile.am b/src/Makefile.am index 4e105a8e60..922cfbce2c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -98,6 +98,7 @@ DYNAMIC_CORE_H = \ core_io.h \ core_memusage.h \ bdap/directory.h \ + bdap/directorydb.h \ dbwrapper.h \ dynode.h \ dynode-payments.h \ @@ -221,6 +222,7 @@ libdynamic_server_a_SOURCES = \ chain.cpp \ checkpoints.cpp \ bdap/directory.cpp \ + bdap/directorydb.cpp \ dbwrapper.cpp \ dynode.cpp \ dynode-payments.cpp\ diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index e7034af005..e2a1a152a9 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -19,8 +19,6 @@ using namespace boost::xpressive; -CDirectoryDB *pDirectoryDB = NULL; - bool IsDirectoryTransaction(CScript txOut) { return (txOut.IsDirectoryScript(BDAP_START) || txOut.IsDirectoryScript(BDAP_NEW_TX) @@ -295,14 +293,6 @@ bool CDirectory::ValidateValues(std::string& errorMessage) return true; } -void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) { - UniValue oName(UniValue::VOBJ); - if (BuildBDAPJson(directory, oName)) { - GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "add.directory"); - //WriteDirectoryIndexHistory(directory, op); //TODO: implement local leveldb storage. - } -} - bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) { bool expired = false; diff --git a/src/bdap/directory.h b/src/bdap/directory.h index d7644b89e6..bf83f32266 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -7,7 +7,6 @@ #include "amount.h" #include "consensus/params.h" -#include "dbwrapper.h" #include "script/script.h" #include "serialize.h" #include "sync.h" @@ -220,38 +219,6 @@ class CDirectory { bool ValidateValues(std::string& errorMessage); }; -class CDirectoryDB : public CDBWrapper { -public: - CDirectoryDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "bdap", nCacheSize, fMemory, fWipe) { - } - - // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare - - bool AddDirectory(const CDirectory& directory, const int& op) { - bool writeState = Write(make_pair(std::string("domain_component"), directory.DomainComponent), directory) - && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.DomainComponent); - - AddDirectoryIndex(directory, op); - return writeState; - } - - void AddDirectoryIndex(const CDirectory& directory, const int& op); - - bool ReadDirectory(); - - bool UpdateDirectory(); - - bool ExpireDirectory(); - - bool DirectoryExists(); - - bool CleanupDirectoryDatabase(); - - - void WriteDirectoryIndex(const CDirectory& directory, const int& op); - void WriteDirectoryIndexHistory(const CDirectory& directory, const int& op); -}; - bool IsDirectoryDataOutput(const CTxOut& out); int GetDirectoryDataOutput(const CTransaction& tx); bool GetDirectoryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); @@ -266,6 +233,4 @@ void ToLowerCase(std::string& strValue); bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrganizationalUnit, const CharString& vchDomainComponent); CAmount GetBDAPFee(const CScript& scriptPubKey); -extern CDirectoryDB *pDirectoryDB; - #endif // DIRECTORY_H \ No newline at end of file diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp new file mode 100644 index 0000000000..af37095afc --- /dev/null +++ b/src/bdap/directorydb.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/directorydb.h" + +#include "validationinterface.h" + +#include + +CDirectoryDB *pDirectoryDB = NULL; + +bool CDirectoryDB::AddDirectory(const CDirectory& directory, const int& op) { + bool writeState = Write(make_pair(std::string("domain_component"), directory.DomainComponent), directory) + && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.DomainComponent); + + AddDirectoryIndex(directory, op); + return writeState; +} + +void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) { + UniValue oName(UniValue::VOBJ); + if (BuildBDAPJson(directory, oName)) { + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "add.directory"); + //WriteDirectoryIndexHistory(directory, op); //TODO: implement local leveldb storage. + } +} \ No newline at end of file diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h new file mode 100644 index 0000000000..38885f7390 --- /dev/null +++ b/src/bdap/directorydb.h @@ -0,0 +1,38 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_DIRECTORYDB_H +#define DYNAMIC_DIRECTORYDB_H + +#include "bdap/directory.h" +#include "dbwrapper.h" + +class CDirectoryDB : public CDBWrapper { +public: + CDirectoryDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "bdap", nCacheSize, fMemory, fWipe, obfuscate) { + } + + // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare + bool AddDirectory(const CDirectory& directory, const int& op); + + void AddDirectoryIndex(const CDirectory& directory, const int& op); + + bool ReadDirectory(); + + bool UpdateDirectory(); + + bool ExpireDirectory(); + + bool DirectoryExists(); + + bool CleanupDirectoryDatabase(); + + + void WriteDirectoryIndex(const CDirectory& directory, const int& op); + void WriteDirectoryIndexHistory(const CDirectory& directory, const int& op); +}; + +extern CDirectoryDB *pDirectoryDB; + +#endif // DYNAMIC_DIRECTORYDB_H \ No newline at end of file diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index c4f7a9fcfd..fba3e662d2 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "bdap/directory.h" - +#include "bdap/directorydb.h" #include "core_io.h" // needed for ScriptToAsmStr #include "rpcprotocol.h" #include "rpcserver.h" diff --git a/src/init.cpp b/src/init.cpp index 2b44e02e2f..5ba1be0a3f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -18,7 +18,7 @@ #include "chain.h" #include "chainparams.h" #include "checkpoints.h" -#include "bdap/directory.h" +#include "bdap/directorydb.h" #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeconfig.h" @@ -1489,7 +1489,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) pcoinsTip = new CCoinsViewCache(pcoinscatcher); // Init BDAP Services DB's - pDirectoryDB = new CDirectoryDB(nTotalCache * 35, false, fReindex); + bool obfuscate = false; + pDirectoryDB = new CDirectoryDB(nTotalCache * 35, false, fReindex, obfuscate); if (fReindex) { pblocktree->WriteReindexing(true); From 77bd1e029d22ecdbc5166990894f269870436529 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 16 Jul 2018 01:54:55 -0500 Subject: [PATCH 0043/1653] [BDAP] Add leveldb functions --- src/bdap/directory.cpp | 21 +---- src/bdap/directorydb.cpp | 174 +++++++++++++++++++++++++++++++++++++-- src/bdap/directorydb.h | 28 ++++--- 3 files changed, 185 insertions(+), 38 deletions(-) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index e2a1a152a9..860545d21d 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -323,7 +323,7 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) oName.push_back(Pair("time", nTime)); //oName.push_back(Pair("height", directory.nHeight)); expired_time = directory.nExpireTime; - if(expired_time <= chainActive.Tip()->GetMedianTimePast()) + if(expired_time <= (unsigned int)chainActive.Tip()->GetMedianTimePast()) { expired = true; } @@ -332,8 +332,8 @@ bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) oName.push_back(Pair("certificate", stringFromVch(directory.Certificate))); oName.push_back(Pair("private_data", stringFromVch(directory.PrivateData))); - //oName.push_back(Pair("transaction_fee", directory.transactionFee); - //oName.push_back(Pair("registration_fee", directory.registrationFeePerDay); + oName.push_back(Pair("transaction_fee", directory.transactionFee)); + oName.push_back(Pair("registration_fee", directory.registrationFeePerDay)); // loop CheckpointHashes return true; } @@ -402,17 +402,4 @@ CAmount GetBDAPFee(const CScript& scriptPubKey) nFee = CWallet::GetMinimumFee(nSize, nTxConfirmTarget, mempool); recp.nAmount = nFee; return recp.nAmount; -} - -/* -SignWalletAddresses.clear(); -transactionFee = 0; -registrationFeePerDay = 0; -CheckpointHashes.clear(); - -std::vector>> CIdentityParameters::InitialiseAdminOwners() -{ - - -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index af37095afc..661f99084e 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -4,24 +4,182 @@ #include "bdap/directorydb.h" +#include "base58.h" +#include "validation.h" #include "validationinterface.h" #include CDirectoryDB *pDirectoryDB = NULL; -bool CDirectoryDB::AddDirectory(const CDirectory& directory, const int& op) { - bool writeState = Write(make_pair(std::string("domain_component"), directory.DomainComponent), directory) - && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.DomainComponent); +bool BuildDirectoryIndexerHistoryJson(const CDirectory& directory, UniValue& oName) +{ + return BuildBDAPJson(directory, oName); +} + +std::string directoryFromOp(int op) +{ + switch (op) { + case OP_BDAP_NEW: + return "bdap_new"; + case OP_BDAP_DELETE: + return "bdap_delete"; + case OP_BDAP_ACTIVATE: + return "bdap_activate"; + case OP_BDAP_MODIFY: + return "bdap_update"; + case OP_BDAP_MODIFY_RDN: + return "bdap_move"; + case OP_BDAP_EXECUTE_CODE: + return "bdap_execute"; + case OP_BDAP_BIND: + return "bdap_bind"; + case OP_BDAP_REVOKE: + return "bdap_revoke"; + default: + return ""; + } +} + +bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory) +{ + if (!pDirectoryDB || !pDirectoryDB->ReadDirectory(vchObjectPath, directory)) { + return false; + } + + if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) { + directory.SetNull(); + return false; + } + return true; +} + +bool CDirectoryDB::AddDirectory(const CDirectory& directory, const int& op) +{ + bool writeState = false; + { + LOCK(cs_bdap_directory); + writeState = Write(make_pair(std::string("domain_component"), directory.GetFullObjectPath()), directory) + && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.GetFullObjectPath()); + } + if (writeState) + AddDirectoryIndex(directory, op); - AddDirectoryIndex(directory, op); return writeState; } -void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) { +void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) +{ UniValue oName(UniValue::VOBJ); if (BuildBDAPJson(directory, oName)) { - GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "add.directory"); - //WriteDirectoryIndexHistory(directory, op); //TODO: implement local leveldb storage. + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_new"); + WriteDirectoryIndexHistory(directory, op); } -} \ No newline at end of file +} + +bool CDirectoryDB::ReadDirectory(const std::vector& vchObjectPath, CDirectory& directory) +{ + LOCK(cs_bdap_directory); + return CDBWrapper::Read(make_pair(std::string("domain_component"), vchObjectPath), directory); +} + +bool CDirectoryDB::ReadDirectoryAddress(const std::vector& vchAddress, std::vector& vchObjectPath) +{ + LOCK(cs_bdap_directory); + return CDBWrapper::Read(make_pair(std::string("domain_wallet_address"), vchAddress), vchObjectPath); +} + +bool CDirectoryDB::EraseDirectory(const std::vector& vchObjectPath) +{ + LOCK(cs_bdap_directory); + return CDBWrapper::Erase(make_pair(std::string("domain_component"), vchObjectPath)); +} + +bool CDirectoryDB::EraseDirectoryAddress(const std::vector& vchAddress) +{ + LOCK(cs_bdap_directory); + return CDBWrapper::Erase(make_pair(std::string("domain_wallet_address"), vchAddress)); +} + +bool CDirectoryDB::DirectoryExists(const std::vector& vchObjectPath) +{ + LOCK(cs_bdap_directory); + return CDBWrapper::Exists(make_pair(std::string("domain_component"), vchObjectPath)); +} + +bool CDirectoryDB::DirectoryExistsAddress(const std::vector& vchAddress) +{ + LOCK(cs_bdap_directory); + return CDBWrapper::Exists(make_pair(std::string("domain_wallet_address"), vchAddress)); +} + +bool CDirectoryDB::RemoveExpired(int& entriesRemoved) +{ + boost::scoped_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + CDirectory directory; + std::pair > key; + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + try { + if (pcursor->GetKey(key) && key.first == "domain_component") { + pcursor->GetValue(directory); + if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) + { + entriesRemoved++; + EraseDirectory(key.second); + } + + } + else if (pcursor->GetKey(key) && key.first == "domain_wallet_address") { + std::vector value; + CDirectory directory; + pcursor->GetValue(value); + if (GetDirectory(value, directory) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) + { + entriesRemoved++; + EraseDirectoryAddress(directory.WalletAddress); + } + + } + pcursor->Next(); + } catch (std::exception &e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +void CDirectoryDB::WriteDirectoryIndexHistory(const CDirectory& directory, const int &op) +{ + if (IsArgSet("-zmqpubbdaphistory")) { + UniValue oName(UniValue::VOBJ); + BuildDirectoryIndexerHistoryJson(directory, oName); + oName.push_back(Pair("op", directoryFromOp(op))); + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_history"); + } +} + +void CDirectoryDB::WriteDirectoryIndex(const CDirectory& directory, const int &op) +{ + if (IsArgSet("-zmqpubbdaprecord")) { + UniValue oName(UniValue::VOBJ); + oName.push_back(Pair("_id", stringFromVch(directory.OID))); + CDynamicAddress address(EncodeBase58(directory.WalletAddress)); + oName.push_back(Pair("address", address.ToString())); + oName.push_back(Pair("expires_on", directory.nExpireTime)); + oName.push_back(Pair("encryption_publickey", HexStr(directory.EncryptPublicKey))); + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_record"); + } + WriteDirectoryIndexHistory(directory, op); +} + +bool CDirectoryDB::UpdateDirectory(const std::vector& vchObjectPath, CDirectory& directory) +{ + return true; //TODO (bdap): add update impl +} + +bool CDirectoryDB::UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory) +{ + return true; //TODO (bdap): add update impl +} diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h index 38885f7390..1853ee2908 100644 --- a/src/bdap/directorydb.h +++ b/src/bdap/directorydb.h @@ -8,6 +8,8 @@ #include "bdap/directory.h" #include "dbwrapper.h" +static CCriticalSection cs_bdap_directory; + class CDirectoryDB : public CDBWrapper { public: CDirectoryDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "bdap", nCacheSize, fMemory, fWipe, obfuscate) { @@ -15,24 +17,24 @@ class CDirectoryDB : public CDBWrapper { // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare bool AddDirectory(const CDirectory& directory, const int& op); - void AddDirectoryIndex(const CDirectory& directory, const int& op); - - bool ReadDirectory(); - - bool UpdateDirectory(); - - bool ExpireDirectory(); - - bool DirectoryExists(); - - bool CleanupDirectoryDatabase(); - - + bool ReadDirectory(const std::vector& vchObjectPath, CDirectory& directory); + bool ReadDirectoryAddress(const std::vector& vchAddress, std::vector& vchObjectPath); + bool EraseDirectory(const std::vector& vchObjectPath); + bool EraseDirectoryAddress(const std::vector& vchAddress); + bool DirectoryExists(const std::vector& vchObjectPath); + bool DirectoryExistsAddress(const std::vector& vchAddress); + bool RemoveExpired(int& entriesRemoved); void WriteDirectoryIndex(const CDirectory& directory, const int& op); void WriteDirectoryIndexHistory(const CDirectory& directory, const int& op); + bool UpdateDirectory(const std::vector& vchObjectPath, CDirectory& directory); + bool UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory); }; +bool BuildDirectoryIndexerHistoryJson(const CDirectory& directory, UniValue& oName); +std::string directoryFromOp(int op); +bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory); + extern CDirectoryDB *pDirectoryDB; #endif // DYNAMIC_DIRECTORYDB_H \ No newline at end of file From 4e03b8b0ae988ddabfe71005e495a29f59b46926 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 16 Jul 2018 02:47:25 -0500 Subject: [PATCH 0044/1653] [BDAP] Refactor, move constants to seperate code file. --- src/Makefile.am | 1 + src/bdap/bdap.h | 42 ++++++++++++++++++++++++++++++++++++++++++ src/bdap/directory.h | 37 ++++--------------------------------- 3 files changed, 47 insertions(+), 33 deletions(-) create mode 100644 src/bdap/bdap.h diff --git a/src/Makefile.am b/src/Makefile.am index 922cfbce2c..bb2278314a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,6 +97,7 @@ DYNAMIC_CORE_H = \ consensus/validation.h \ core_io.h \ core_memusage.h \ + bdap/bdap.h \ bdap/directory.h \ bdap/directorydb.h \ dbwrapper.h \ diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h new file mode 100644 index 0000000000..9e3ee17792 --- /dev/null +++ b/src/bdap/bdap.h @@ -0,0 +1,42 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_H +#define DYNAMIC_BDAP_H + +#include +#include + +typedef std::vector CharString; +typedef std::vector vchCharString; +typedef std::vector > vCheckPoints; // << height, block hash >> + +static constexpr unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) +static constexpr unsigned int MAX_OBJECT_NAME_LENGTH = 63; +static constexpr unsigned int MAX_COMMON_NAME_LENGTH = 95; +static constexpr unsigned int MAX_ORG_NAME_LENGTH = 95; +static constexpr unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; +static constexpr unsigned int MAX_KEY_LENGTH = 156; +static constexpr unsigned int MAX_CERTIFICATE_LENGTH = 512; +static constexpr unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain +static constexpr unsigned int MAX_NUMBER_CHECKPOINTS = 100; // Pay per byte for hosting on chain +static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; +static const std::string DEFAULT_PUBLIC_OU = "public"; +static const std::string DEFAULT_ADMIN_OU = "admin"; +static const std::string DEFAULT_ORGANIZATION_NAME = "Duality Blockchain Solutions"; +static const std::string DEFAULT_OID_PREFIX = "0.0.0"; //TODO (bdap): get real OID prefix + +inline const CharString ConvertConstantToCharString (const std::string strConvert) +{ + CharString vchConvert(strConvert.begin(), strConvert.end()); + return vchConvert; +}; + +static const CharString vchDefaultDomainName = ConvertConstantToCharString(DEFAULT_PUBLIC_DOMAIN); +static const CharString vchDefaultPublicOU = ConvertConstantToCharString(DEFAULT_PUBLIC_OU); +static const CharString vchDefaultAdminOU = ConvertConstantToCharString(DEFAULT_ADMIN_OU); +static const CharString vchDefaultOrganizationName = ConvertConstantToCharString(DEFAULT_ORGANIZATION_NAME); +static const CharString vchDefaultOIDPrefix = ConvertConstantToCharString(DEFAULT_OID_PREFIX); + +#endif // DYNAMIC_BDAP_H \ No newline at end of file diff --git a/src/bdap/directory.h b/src/bdap/directory.h index bf83f32266..5711dba72e 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -2,9 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef DIRECTORY_H -#define DIRECTORY_H +#ifndef DYNAMIC_DIRECTORY_H +#define DYNAMIC_DIRECTORY_H +#include "bdap.h" #include "amount.h" #include "consensus/params.h" #include "script/script.h" @@ -18,36 +19,6 @@ class CRecipient; class CTransaction; class CTxOut; -typedef std::vector CharString; -typedef std::vector vchCharString; -typedef std::vector > vCheckPoints; // << height, block hash >> - -static constexpr unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) -static constexpr unsigned int MAX_OBJECT_NAME_LENGTH = 63; -static constexpr unsigned int MAX_COMMON_NAME_LENGTH = 95; -static constexpr unsigned int MAX_ORG_NAME_LENGTH = 95; -static constexpr unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; -static constexpr unsigned int MAX_KEY_LENGTH = 156; -static constexpr unsigned int MAX_CERTIFICATE_LENGTH = 512; -static constexpr unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain -static constexpr unsigned int MAX_NUMBER_CHECKPOINTS = 100; // Pay per byte for hosting on chain -static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; -static const std::string DEFAULT_PUBLIC_OU = "public"; -static const std::string DEFAULT_ADMIN_OU = "admin"; -static const std::string DEFAULT_ORGANIZATION_NAME = "Duality Blockchain Solutions"; -static const std::string DEFAULT_OID_PREFIX = "0.0.0"; - -inline const CharString ConvertConstantToCharString (const std::string strConvert) -{ - CharString vchConvert(strConvert.begin(), strConvert.end()); - return vchConvert; -}; -static const CharString vchDefaultDomainName = ConvertConstantToCharString(DEFAULT_PUBLIC_DOMAIN); -static const CharString vchDefaultPublicOU = ConvertConstantToCharString(DEFAULT_PUBLIC_OU); -static const CharString vchDefaultAdminOU = ConvertConstantToCharString(DEFAULT_ADMIN_OU); -static const CharString vchDefaultOrganizationName = ConvertConstantToCharString(DEFAULT_ORGANIZATION_NAME); -static const CharString vchDefaultOIDPrefix = ConvertConstantToCharString(DEFAULT_OID_PREFIX); - /* Blockchain Directory Access Framework ***** Design Notes ***** @@ -233,4 +204,4 @@ void ToLowerCase(std::string& strValue); bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrganizationalUnit, const CharString& vchDomainComponent); CAmount GetBDAPFee(const CScript& scriptPubKey); -#endif // DIRECTORY_H \ No newline at end of file +#endif // DYNAMIC_DIRECTORY_H \ No newline at end of file From 0fe865dfb7ed93a6e39a7b3bc9918996b9bf5206 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 16 Jul 2018 13:31:19 -0500 Subject: [PATCH 0045/1653] [BDAP] Remove BuildDirectoryIndexerHistoryJson, use BuildBDAPJson instead --- src/bdap/directorydb.cpp | 17 ++++++----------- src/bdap/directorydb.h | 11 +++++------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index 661f99084e..514c510046 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -12,12 +12,7 @@ CDirectoryDB *pDirectoryDB = NULL; -bool BuildDirectoryIndexerHistoryJson(const CDirectory& directory, UniValue& oName) -{ - return BuildBDAPJson(directory, oName); -} - -std::string directoryFromOp(int op) +std::string directoryFromOp(const int op) { switch (op) { case OP_BDAP_NEW: @@ -54,7 +49,7 @@ bool GetDirectory(const std::vector& vchObjectPath, CDirectory& d return true; } -bool CDirectoryDB::AddDirectory(const CDirectory& directory, const int& op) +bool CDirectoryDB::AddDirectory(const CDirectory& directory, const int op) { bool writeState = false; { @@ -68,7 +63,7 @@ bool CDirectoryDB::AddDirectory(const CDirectory& directory, const int& op) return writeState; } -void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int& op) +void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int op) { UniValue oName(UniValue::VOBJ); if (BuildBDAPJson(directory, oName)) { @@ -150,17 +145,17 @@ bool CDirectoryDB::RemoveExpired(int& entriesRemoved) return true; } -void CDirectoryDB::WriteDirectoryIndexHistory(const CDirectory& directory, const int &op) +void CDirectoryDB::WriteDirectoryIndexHistory(const CDirectory& directory, const int op) { if (IsArgSet("-zmqpubbdaphistory")) { UniValue oName(UniValue::VOBJ); - BuildDirectoryIndexerHistoryJson(directory, oName); + BuildBDAPJson(directory, oName); oName.push_back(Pair("op", directoryFromOp(op))); GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_history"); } } -void CDirectoryDB::WriteDirectoryIndex(const CDirectory& directory, const int &op) +void CDirectoryDB::WriteDirectoryIndex(const CDirectory& directory, const int op) { if (IsArgSet("-zmqpubbdaprecord")) { UniValue oName(UniValue::VOBJ); diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h index 1853ee2908..f6d41669da 100644 --- a/src/bdap/directorydb.h +++ b/src/bdap/directorydb.h @@ -16,8 +16,8 @@ class CDirectoryDB : public CDBWrapper { } // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare - bool AddDirectory(const CDirectory& directory, const int& op); - void AddDirectoryIndex(const CDirectory& directory, const int& op); + bool AddDirectory(const CDirectory& directory, const int op); + void AddDirectoryIndex(const CDirectory& directory, const int op); bool ReadDirectory(const std::vector& vchObjectPath, CDirectory& directory); bool ReadDirectoryAddress(const std::vector& vchAddress, std::vector& vchObjectPath); bool EraseDirectory(const std::vector& vchObjectPath); @@ -25,14 +25,13 @@ class CDirectoryDB : public CDBWrapper { bool DirectoryExists(const std::vector& vchObjectPath); bool DirectoryExistsAddress(const std::vector& vchAddress); bool RemoveExpired(int& entriesRemoved); - void WriteDirectoryIndex(const CDirectory& directory, const int& op); - void WriteDirectoryIndexHistory(const CDirectory& directory, const int& op); + void WriteDirectoryIndex(const CDirectory& directory, const int op); + void WriteDirectoryIndexHistory(const CDirectory& directory, const int op); bool UpdateDirectory(const std::vector& vchObjectPath, CDirectory& directory); bool UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory); }; -bool BuildDirectoryIndexerHistoryJson(const CDirectory& directory, UniValue& oName); -std::string directoryFromOp(int op); +std::string directoryFromOp(const int op); bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory); extern CDirectoryDB *pDirectoryDB; From cc07fc48689eb69a3789fee6a167fa9b2d04078b Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 16 Jul 2018 14:40:05 -0500 Subject: [PATCH 0046/1653] [BDAP] Use RemoveBDAPScript in consensus functions --- src/script/interpreter.cpp | 14 ++- src/script/interpreter.h | 2 +- src/script/script.cpp | 199 +++++++++++++++++++++++-------------- src/script/script.h | 1 + src/script/sign.cpp | 14 ++- src/script/sign.h | 2 +- src/txmempool.cpp | 138 +++++++++++++++++++++++-- src/validation.cpp | 96 ++++++++++++++---- 8 files changed, 363 insertions(+), 103 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 1b2e768c02..1675851f02 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1239,8 +1239,20 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con return true; } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKeyIn, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(scriptPubKeyIn, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = scriptPubKeyIn; + } + set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { diff --git a/src/script/interpreter.h b/src/script/interpreter.h index fbf8e95fd6..3842e0b306 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -139,6 +139,6 @@ class MutableTransactionSignatureChecker : public TransactionSignatureChecker }; bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL); +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKeyIn, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL); #endif // DYNAMIC_SCRIPT_INTERPRETER_H diff --git a/src/script/script.cpp b/src/script/script.cpp index ff854c2f08..b194765d3e 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -171,6 +171,82 @@ const char* GetOpName(opcodetype opcode) } } +// TODO (bdap): move functions below to seperate code file +bool IsDirectoryOp(int op) +{ + return op == OP_BDAP + || op == OP_BDAP_NEW + || op == OP_BDAP_DELETE + || op == OP_BDAP_ACTIVATE + || op == OP_BDAP_MODIFY + || op == OP_BDAP_MODIFY_RDN + || op == OP_BDAP_EXECUTE_CODE + || op == OP_BDAP_BIND + || op == OP_BDAP_REVOKE; +} + +bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch, CScript::const_iterator& pc) +{ + opcodetype opcode; + vvch.clear(); + if (!script.GetOp(pc, opcode)) + return false; + if (opcode < OP_1 || opcode > OP_16) + return false; + op = CScript::DecodeOP_N(opcode); + if (op != OP_BDAP) + return false; + if (!script.GetOp(pc, opcode)) + return false; + if (opcode < OP_1 || opcode > OP_16) + return false; + op = CScript::DecodeOP_N(opcode); + if (!IsDirectoryOp(op)) + return false; + bool found = false; + for (;;) { + std::vector vch; + if (!script.GetOp(pc, opcode, vch)) + return false; + if (opcode == OP_DROP || opcode == OP_2DROP) + { + found = true; + break; + } + if (!(opcode >= 0 && opcode <= OP_PUSHDATA4)) + return false; + vvch.push_back(vch); + } + + // move the pc to after any DROP or NOP + while (opcode == OP_DROP || opcode == OP_2DROP) { + if (!script.GetOp(pc, opcode)) + break; + } + + pc--; + return found; +} + +bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch) +{ + CScript::const_iterator pc = script.begin(); + return DecodeBDAPScript(script, op, vvch, pc); +} + +bool RemoveBDAPScript(const CScript& scriptIn, CScript& scriptOut) +{ + int op; + std::vector > vvch; + CScript::const_iterator pc = scriptIn.begin(); + + if (!DecodeBDAPScript(scriptIn, op, vvch, pc)) + return false; + scriptOut = CScript(pc, scriptIn.end()); + return true; +} +// TODO (bdap): move the above functions to seperate code file + unsigned int CScript::GetSigOpCount(bool fAccurate) const { unsigned int n = 0; @@ -221,6 +297,18 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const bool CScript::IsPayToPublicKeyHash() const { + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(*this, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = *this; + } + // Extra-fast test for pay-to-pubkey-hash CScripts: return (this->size() == 25 && (*this)[0] == OP_DUP && @@ -232,6 +320,17 @@ bool CScript::IsPayToPublicKeyHash() const bool CScript::IsPayToScriptHash() const { + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(*this, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = *this; + } // Extra-fast test for pay-to-script-hash CScripts: return (this->size() == 23 && (*this)[0] == OP_HASH160 && @@ -239,6 +338,32 @@ bool CScript::IsPayToScriptHash() const (*this)[22] == OP_EQUAL); } +bool CScript::IsPayToPublicKey() const +{ + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(*this, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = *this; + } + // Test for pay-to-pubkey CScript with both + // compressed or uncompressed pubkey + if (scriptPubKey.size() == 35) { + return (scriptPubKey[1] == 0x02 || scriptPubKey[1] == 0x03) && + scriptPubKey[34] == OP_CHECKSIG; + } + if (scriptPubKey.size() == 67) { + return scriptPubKey[1] == 0x04 && + scriptPubKey[66] == OP_CHECKSIG; + } + return false; +} + bool CScript::IsPushOnly(const_iterator pc) const { while (pc < end()) @@ -259,78 +384,4 @@ bool CScript::IsPushOnly(const_iterator pc) const bool CScript::IsPushOnly() const { return this->IsPushOnly(begin()); -} - -bool IsDirectoryOp(int op) -{ - return op == OP_BDAP - || op == OP_BDAP_NEW - || op == OP_BDAP_DELETE - || op == OP_BDAP_ACTIVATE - || op == OP_BDAP_MODIFY - || op == OP_BDAP_MODIFY_RDN - || op == OP_BDAP_EXECUTE_CODE - || op == OP_BDAP_BIND - || op == OP_BDAP_REVOKE; -} - -bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch, CScript::const_iterator& pc) -{ - opcodetype opcode; - vvch.clear(); - if (!script.GetOp(pc, opcode)) - return false; - if (opcode < OP_1 || opcode > OP_16) - return false; - op = CScript::DecodeOP_N(opcode); - if (op != OP_BDAP) - return false; - if (!script.GetOp(pc, opcode)) - return false; - if (opcode < OP_1 || opcode > OP_16) - return false; - op = CScript::DecodeOP_N(opcode); - if (!IsDirectoryOp(op)) - return false; - bool found = false; - for (;;) { - std::vector vch; - if (!script.GetOp(pc, opcode, vch)) - return false; - if (opcode == OP_DROP || opcode == OP_2DROP) - { - found = true; - break; - } - if (!(opcode >= 0 && opcode <= OP_PUSHDATA4)) - return false; - vvch.push_back(vch); - } - - // move the pc to after any DROP or NOP - while (opcode == OP_DROP || opcode == OP_2DROP) { - if (!script.GetOp(pc, opcode)) - break; - } - - pc--; - return found; -} - -bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch) -{ - CScript::const_iterator pc = script.begin(); - return DecodeBDAPScript(script, op, vvch, pc); -} - -bool RemoveBDAPScript(const CScript& scriptIn, CScript& scriptOut) -{ - int op; - std::vector > vvch; - CScript::const_iterator pc = scriptIn.begin(); - - if (!DecodeBDAPScript(scriptIn, op, vvch, pc)) - return false; - scriptOut = CScript(pc, scriptIn.end()); - return true; } \ No newline at end of file diff --git a/src/script/script.h b/src/script/script.h index 0d8848397f..4f5d4d4c21 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -667,6 +667,7 @@ class CScript : public CScriptBase bool IsPayToPublicKeyHash() const; bool IsPayToScriptHash() const; + bool IsPayToPublicKey() const; /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly(const_iterator pc) const; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 80efd19eca..affa545a9b 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -126,8 +126,20 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP return false; } -bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig) +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKeyIn, CScript& scriptSig) { + // Remove BDAP portion of the script + CScript fromPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(fromPubKeyIn, scriptPubKeyOut)) + { + fromPubKey = scriptPubKeyOut; + } + else + { + fromPubKey = fromPubKeyIn; + } + txnouttype whichType; if (!SignStep(creator, fromPubKey, scriptSig, whichType)) return false; diff --git a/src/script/sign.h b/src/script/sign.h index b06fd566ae..fbab046d21 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -53,7 +53,7 @@ class DummySignatureCreator : public BaseSignatureCreator { }; /** Produce a script signature using a generic signature creator. */ -bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig); +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKeyIn, CScript& scriptSig); /** Produce a script signature for a transaction. */ bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 614755c32b..39a71e23fa 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -449,33 +449,117 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC const Coin& coin = view.AccessCoin(input.prevout); const CTxOut &prevout = coin.out; if (prevout.scriptPubKey.IsPayToScriptHash()) { - std::vector hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(prevout.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = prevout.scriptPubKey; + } + + std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, j, 1); CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); mapAddress.insert(std::make_pair(key, delta)); inserted.push_back(key); } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { - std::vector hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(prevout.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = prevout.scriptPubKey; + } + + std::vector hashBytes(scriptPubKey.begin()+3, scriptPubKey.begin()+23); CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, j, 1); CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); mapAddress.insert(std::make_pair(key, delta)); inserted.push_back(key); + } else if (prevout.scriptPubKey.IsPayToPublicKey()) { + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(prevout.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = prevout.scriptPubKey; + } + + uint160 hashBytes(Hash160(scriptPubKey.begin()+1, scriptPubKey.end()-1)); + CMempoolAddressDeltaKey key(1, hashBytes, txhash, j, 1); + CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); + mapAddress.insert(std::make_pair(key, delta)); + inserted.push_back(key); } } for (unsigned int k = 0; k < tx.vout.size(); k++) { const CTxOut &out = tx.vout[k]; if (out.scriptPubKey.IsPayToScriptHash()) { - std::vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(out.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = out.scriptPubKey; + } + + std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, k, 0); mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); inserted.push_back(key); } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { - std::vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(out.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = out.scriptPubKey; + } + + std::vector hashBytes(scriptPubKey.begin()+3, scriptPubKey.begin()+23); std::pair ret; CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, k, 0); mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); inserted.push_back(key); + } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(out.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = out.scriptPubKey; + } + + uint160 hashBytes(Hash160(scriptPubKey.begin()+1, scriptPubKey.end()-1)); + std::pair ret; + CMempoolAddressDeltaKey key(1, hashBytes, txhash, k, 0); + mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); + inserted.push_back(key); } } @@ -528,12 +612,52 @@ void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCac int addressType; if (prevout.scriptPubKey.IsPayToScriptHash()) { - addressHash = uint160(std::vector (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22)); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(prevout.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = prevout.scriptPubKey; + } + + addressHash = uint160(std::vector (scriptPubKey.begin()+2, scriptPubKey.begin()+22)); addressType = 2; } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { - addressHash = uint160(std::vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(prevout.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = prevout.scriptPubKey; + } + + addressHash = uint160(std::vector (scriptPubKey.begin()+3, scriptPubKey.begin()+23)); addressType = 1; - } else { + } else if (prevout.scriptPubKey.IsPayToPublicKey()) + { + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(prevout.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = prevout.scriptPubKey; + } + + addressHash = Hash160(scriptPubKey.begin()+1, scriptPubKey.end()-1); + addressType = 1; + } + else { addressHash.SetNull(); addressType = 0; } diff --git a/src/validation.cpp b/src/validation.cpp index 087f394715..27a8b7593d 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1695,7 +1695,19 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s const CTxOut &out = tx.vout[k]; if (out.scriptPubKey.IsPayToScriptHash()) { - std::vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(out.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = out.scriptPubKey; + } + + std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); // undo receiving activity addressIndex.push_back(std::make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue)); @@ -1704,7 +1716,19 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), hash, k), CAddressUnspentValue())); } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { - std::vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(out.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = out.scriptPubKey; + } + + std::vector hashBytes(scriptPubKey.begin()+3, scriptPubKey.begin()+23); // undo receiving activity addressIndex.push_back(std::make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue)); @@ -1758,24 +1782,42 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s const Coin &coin = view.AccessCoin(tx.vin[j].prevout); const CTxOut &prevout = coin.out; if (prevout.scriptPubKey.IsPayToScriptHash()) { - std::vector hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(prevout.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = prevout.scriptPubKey; + } + std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); // undo spending activity addressIndex.push_back(std::make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); - // restore unspent index - addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undoHeight))); - + addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, scriptPubKey, undoHeight))); } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { - std::vector hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(prevout.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = prevout.scriptPubKey; + } + std::vector hashBytes(scriptPubKey.begin()+3, scriptPubKey.begin()+23); // undo spending activity addressIndex.push_back(std::make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); - // restore unspent index - addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undoHeight))); - + addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, scriptPubKey, undoHeight))); } else { continue; } @@ -2116,23 +2158,41 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd const CTxOut &out = tx.vout[k]; if (out.scriptPubKey.IsPayToScriptHash()) { - std::vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(out.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = out.scriptPubKey; + } + std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); // record receiving activity addressIndex.push_back(std::make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue)); - // record unspent output - addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); - + addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(2, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, scriptPubKey, pindex->nHeight))); } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { - std::vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); + // Remove BDAP portion of the script + CScript scriptPubKey; + CScript scriptPubKeyOut; + if (RemoveBDAPScript(out.scriptPubKey, scriptPubKeyOut)) + { + scriptPubKey = scriptPubKeyOut; + } + else + { + scriptPubKey = out.scriptPubKey; + } + std::vector hashBytes(scriptPubKey.begin()+3, scriptPubKey.begin()+23); // record receiving activity addressIndex.push_back(std::make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue)); - // record unspent output - addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); - + addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, scriptPubKey, pindex->nHeight))); } else { continue; } From 7f66b8c5d6db2b36843466e0e55dea58fbd9c4e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Tue, 17 Jul 2018 19:16:02 +0200 Subject: [PATCH 0047/1653] [GPU] Fix CUDA autoconf build --- build-aux/m4/ax_check_cuda.m4 | 8 ++-- src/Makefile.am | 2 +- src/Makefile.gpu.include | 72 +++++++++++++++------------- src/crypto/argon2gpu/cuda/kernels.cu | 44 ++++++++--------- 4 files changed, 65 insertions(+), 61 deletions(-) diff --git a/build-aux/m4/ax_check_cuda.m4 b/build-aux/m4/ax_check_cuda.m4 index 360d2a3b6f..e626b36679 100644 --- a/build-aux/m4/ax_check_cuda.m4 +++ b/build-aux/m4/ax_check_cuda.m4 @@ -32,7 +32,7 @@ AC_DEFUN([AX_CHECK_CUDA], [ AC_ARG_WITH([cuda], [AS_HELP_STRING([--with-cuda=PATH],[prefix where CUDA is installed @<:@default=no@:>@])], [], - [with_cuda=no]) + [with_cuda=yes]) NVCC=no CUDA_CFLAGS= @@ -123,10 +123,10 @@ EOF # ----------------------------------------- # Check for headers and libraries # ----------------------------------------- - ax_save_CXXFLAGS="${CXXFLAGS}" + ax_save_CFLAGS="${CFLAGS}" ax_save_LIBS="${LIBS}" - CXXFLAGS="$CUDA_CFLAGS $CXXFLAGS" + CFLAGS="$CUDA_CFLAGS $CFLAGS" LIBS="$CUDA_LDLIBS $LIBS" # And the header and the lib @@ -138,7 +138,7 @@ EOF AC_CHECK_LIB([cublas], [cublasInit], [], AC_MSG_FAILURE([Couldn't find libcublas])) # Returning to the original flags - CXXFLAGS=${ax_save_CXXFLAGS} + CFLAGS=${ax_save_CFLAGS} LIBS=${ax_save_LIBS} AC_DEFINE(HAVE_CUDA,1,[Define if we have CUDA]) diff --git a/src/Makefile.am b/src/Makefile.am index 55e62d59d0..6f0f4e7a5a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ DIST_SUBDIRS = secp256k1 univalue -AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) -L/usr/lib/x86_64-linux-gnu -L/usr/local/cuda-9.2/lib64 +AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(HARDENED_CXXFLAGS) AM_CPPFLAGS = $(HARDENED_CPPFLAGS) EXTRA_LIBRARIES = diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index 55b5ae6037..3596675767 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -10,61 +10,65 @@ EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) crypto_argon2gpu_libdynamic_gpu_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_argon2gpu_libdynamic_gpu_a_SOURCES = \ - crypto/argon2gpu/blake2b.h \ - crypto/argon2gpu/common.h \ - crypto/argon2gpu/common.cpp \ - crypto/argon2gpu/blake2b.cpp + crypto/argon2gpu/blake2b.h \ + crypto/argon2gpu/common.h \ + crypto/argon2gpu/common.cpp \ + crypto/argon2gpu/blake2b.cpp if ENABLE_CUDA +NVCCFLAGS += --cudart shared --ptxas-options=-v -arch sm_30 -lineinfo -Xcompiler '--std=c++11 $(CFLAGS)' + +crypto_argon2gpu_libdynamic_gpu_a_AR = $(NVCC) $(NVCCFLAGS) -lib -o crypto_argon2gpu_libdynamic_gpu_a_LIBADD = $(CUDA_LDLIBS) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS += $(CUDA_CFLAGS) crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ - crypto/argon2gpu/cuda/cuda-exception.h \ - crypto/argon2gpu/cuda/device.h \ - crypto/argon2gpu/cuda/global-context.h \ - crypto/argon2gpu/cuda/kernels.h \ - crypto/argon2gpu/cuda/processing-unit.h \ - crypto/argon2gpu/cuda/program-context.h \ - crypto/argon2gpu/cuda/device.cpp \ - crypto/argon2gpu/cuda/global-context.cpp \ - crypto/argon2gpu/cuda/kernels.cu \ - crypto/argon2gpu/cuda/processing-unit.cpp \ - crypto/argon2gpu/cuda/program-context.cpp + crypto/argon2gpu/cuda/cuda-exception.h \ + crypto/argon2gpu/cuda/device.h \ + crypto/argon2gpu/cuda/global-context.h \ + crypto/argon2gpu/cuda/kernels.h \ + crypto/argon2gpu/cuda/processing-unit.h \ + crypto/argon2gpu/cuda/program-context.h \ + crypto/argon2gpu/cuda/device.cpp \ + crypto/argon2gpu/cuda/global-context.cpp \ + crypto/argon2gpu/cuda/kernels.cu \ + crypto/argon2gpu/cuda/processing-unit.cpp \ + crypto/argon2gpu/cuda/program-context.cpp DYNAMIC_INCLUDES += $(CUDA_CFLAGS) LIBDYNAMIC_GPU_LDADD += $(CUDA_LDLIBS) -NVCCFLAGS += -std=c++11 --ptxas-options=-v -arch sm_30 -lineinfo +nvcc_ARCH := -gencode=arch=compute_30,code=\"sm_30,compute_30\" +nvcc_FLAGS = $(nvcc_ARCH) -I. $(CUDA_CFLAGS) $(NVCCFLAGS) .cu.o: - $(NVCC) $(CFLAGS) $(NVCCFLAGS) -o $@ -c $< + $(NVCC) $(nvcc_FLAGS) -o $@ -c $< crypto/argon2gpu/cuda/kernels.o: crypto/argon2gpu/cuda/kernels.cu - $(NVCC) $(CFLAGS) $(NVCCFLAGS) -o $@ -c $< + $(NVCC) -dlink $(nvcc_FLAGS) -o $@ -c $< else if TARGET_DARWIN - LIBOPENCL = "-framework OpenCL" + LIBOPENCL = "-framework OpenCL" else - LIBOPENCL = -lOpenCL + LIBOPENCL = -lOpenCL endif crypto_argon2gpu_libdynamic_gpu_a_LIBADD = $(LIBOPENCL) crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ - crypto/argon2gpu/opencl/cl.hpp \ - crypto/argon2gpu/opencl/device.h \ - crypto/argon2gpu/opencl/global-context.h \ - crypto/argon2gpu/opencl/kernel-loader.h \ - crypto/argon2gpu/opencl/kernel-runner.h \ - crypto/argon2gpu/opencl/opencl.h \ - crypto/argon2gpu/opencl/processing-unit.h \ - crypto/argon2gpu/opencl/program-context.h \ - crypto/argon2gpu/opencl/device.cpp \ - crypto/argon2gpu/opencl/global-context.cpp \ - crypto/argon2gpu/opencl/kernel-loader.cpp \ - crypto/argon2gpu/opencl/kernel-runner.cpp \ - crypto/argon2gpu/opencl/processing-unit.cpp \ - crypto/argon2gpu/opencl/program-context.cpp + crypto/argon2gpu/opencl/cl.hpp \ + crypto/argon2gpu/opencl/device.h \ + crypto/argon2gpu/opencl/global-context.h \ + crypto/argon2gpu/opencl/kernel-loader.h \ + crypto/argon2gpu/opencl/kernel-runner.h \ + crypto/argon2gpu/opencl/opencl.h \ + crypto/argon2gpu/opencl/processing-unit.h \ + crypto/argon2gpu/opencl/program-context.h \ + crypto/argon2gpu/opencl/device.cpp \ + crypto/argon2gpu/opencl/global-context.cpp \ + crypto/argon2gpu/opencl/kernel-loader.cpp \ + crypto/argon2gpu/opencl/kernel-runner.cpp \ + crypto/argon2gpu/opencl/processing-unit.cpp \ + crypto/argon2gpu/opencl/program-context.cpp LIBDYNAMIC_GPU_LDADD += $(LIBOPENCL) endif diff --git a/src/crypto/argon2gpu/cuda/kernels.cu b/src/crypto/argon2gpu/cuda/kernels.cu index b1c1bf49c0..d20b82efa6 100644 --- a/src/crypto/argon2gpu/cuda/kernels.cu +++ b/src/crypto/argon2gpu/cuda/kernels.cu @@ -858,11 +858,11 @@ void KernelRunner::precomputeRefs() if (type == ARGON2_I) { argon2_precompute_kernel - << > >( + <<>>( refs, passes, lanes, segmentBlocks); } else { argon2_precompute_kernel - << > >( + <<>>( refs, passes, lanes, segmentBlocks); } } @@ -929,24 +929,24 @@ void KernelRunner::runKernelSegment(uint32_t lanesPerBlock, struct ref* refs = (struct ref*)this->refs; if (version == ARGON2_VERSION_10) { argon2_kernel_segment_precompute - << > >( + <<>>( memory_blocks, refs, passes, lanes, segmentBlocks, pass, slice); } else { argon2_kernel_segment_precompute - << > >( + <<>>( memory_blocks, refs, passes, lanes, segmentBlocks, pass, slice); } } else { if (version == ARGON2_VERSION_10) { argon2_kernel_segment - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } else { argon2_kernel_segment - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } @@ -956,24 +956,24 @@ void KernelRunner::runKernelSegment(uint32_t lanesPerBlock, struct ref* refs = (struct ref*)this->refs; if (version == ARGON2_VERSION_10) { argon2_kernel_segment_precompute - << > >( + <<>>( memory_blocks, refs, passes, lanes, segmentBlocks, pass, slice); } else { argon2_kernel_segment_precompute - << > >( + <<>>( memory_blocks, refs, passes, lanes, segmentBlocks, pass, slice); } } else { if (version == ARGON2_VERSION_10) { argon2_kernel_segment - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } else { argon2_kernel_segment - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } @@ -981,12 +981,12 @@ void KernelRunner::runKernelSegment(uint32_t lanesPerBlock, } else { if (version == ARGON2_VERSION_10) { argon2_kernel_segment - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } else { argon2_kernel_segment - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks, pass, slice); } @@ -1012,21 +1012,21 @@ void KernelRunner::runKernelOneshot(uint32_t lanesPerBlock, struct ref* refs = (struct ref*)this->refs; if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot_precompute - << > >( + <<>>( memory_blocks, refs, passes, lanes, segmentBlocks); } else { argon2_kernel_oneshot_precompute - << > >( + <<>>( memory_blocks, refs, passes, lanes, segmentBlocks); } } else { if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks); } else { argon2_kernel_oneshot - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks); } } @@ -1035,32 +1035,32 @@ void KernelRunner::runKernelOneshot(uint32_t lanesPerBlock, struct ref* refs = (struct ref*)this->refs; if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot_precompute - << > >( + <<>>( memory_blocks, refs, passes, lanes, segmentBlocks); } else { argon2_kernel_oneshot_precompute - << > >( + <<>>( memory_blocks, refs, passes, lanes, segmentBlocks); } } else { if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks); } else { argon2_kernel_oneshot - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks); } } } else { if (version == ARGON2_VERSION_10) { argon2_kernel_oneshot - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks); } else { argon2_kernel_oneshot - << > >( + <<>>( memory_blocks, passes, lanes, segmentBlocks); } } From 7c0cb37ce4bd25afdc132195fd255cd97d97ad94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Tue, 17 Jul 2018 20:30:18 +0200 Subject: [PATCH 0048/1653] [GPU] Miner threads per device --- src/miner.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index ba8e2bf313..cd861d4df9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -949,17 +949,17 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), nThread, false)); } - if (nGPUThreads < 0 || nGPUThreads > (int)devices) - nGPUThreads = devices; + if (nGPUThreads < 0) + nGPUThreads = 4; // Start GPU threads boost::thread_group* gpuMinerThreads = GetGPUMinerThreads(); - //for (std::size_t device = 0; device < devices; device++) { - for (std::size_t i = 0; i < nGPUThreads || i < devices; i++) { - LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, i, devices); - gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), i, true)); + for (std::size_t device = 0; device < devices; device++) { + for (std::size_t i = 0; i < nGPUThreads; i++) { + LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, device, devices); + gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), device, true)); } - //} + } } void ShutdownCPUMiners() From c9c73b55ad8e201101b557b6661aa3a52b97692f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Tue, 17 Jul 2018 20:30:37 +0200 Subject: [PATCH 0049/1653] [GPU] Fix setgenerate RPC method --- src/rpcclient.cpp | 1 + src/rpcmining.cpp | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 5b7018b69d..7627c52f32 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -29,6 +29,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "setmocktime", 0 }, { "setgenerate", 0 }, { "setgenerate", 1 }, + { "setgenerate", 2 }, { "generate", 0 }, { "generate", 1 }, { "generatetoaddress", 0 }, diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index e77e603baf..d6eb624e20 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -338,11 +338,17 @@ UniValue setgenerate(const JSONRPCRequest& request) if (nGenProcLimit == 0 && nGenProcLimitGPU == 0) fGenerate = false; - GetArg("-gen", "") = (fGenerate ? "1" : "0"); - GetArg("-genproclimit", "") = itostr(nGenProcLimit); - GetArg("-genproclimit-gpu", "") = itostr(nGenProcLimitGPU); + ForceSetArg("-gen", fGenerate ? "1" : "0"); + ForceSetArg("-genproclimit", nGenProcLimit); + ForceSetArg("-genproclimit-gpu", nGenProcLimitGPU); LogPrintf("setgenerate cpu = %u, gpu = %u \n", nGenProcLimit, nGenProcLimitGPU); - GenerateDynamics(nGenProcLimit, nGenProcLimitGPU, Params(), *g_connman); + + if (fGenerate) { + bool fAutotune = nGenProcLimit == -1 && nGenProcLimitGPU == -1; + GenerateDynamics(nGenProcLimit, nGenProcLimitGPU, Params(), *g_connman, fAutotune); + } else { + ShutdownMiners(); + } return NullUniValue; } From deb9f9f4154fc5f99521308bf85b59aa9416ab08 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 17 Jul 2018 19:51:39 -0500 Subject: [PATCH 0050/1653] [BDAP] Add leveldb check, cleanup and flush - move directoryFromOp function to directory.cpp/h --- src/bdap/directory.cpp | 27 ++++++++++- src/bdap/directory.h | 2 + src/bdap/directorydb.cpp | 96 +++++++++++++++++++++++++++++----------- src/bdap/directorydb.h | 5 ++- 4 files changed, 102 insertions(+), 28 deletions(-) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index 860545d21d..9b0c390ae0 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -19,7 +19,8 @@ using namespace boost::xpressive; -bool IsDirectoryTransaction(CScript txOut) { +bool IsDirectoryTransaction(const CScript& txOut) +{ return (txOut.IsDirectoryScript(BDAP_START) || txOut.IsDirectoryScript(BDAP_NEW_TX) || txOut.IsDirectoryScript(BDAP_DELETE_TX) @@ -32,6 +33,30 @@ bool IsDirectoryTransaction(CScript txOut) { ); } +std::string directoryFromOp(const int op) +{ + switch (op) { + case OP_BDAP_NEW: + return "bdap_new"; + case OP_BDAP_DELETE: + return "bdap_delete"; + case OP_BDAP_ACTIVATE: + return "bdap_activate"; + case OP_BDAP_MODIFY: + return "bdap_update"; + case OP_BDAP_MODIFY_RDN: + return "bdap_move"; + case OP_BDAP_EXECUTE_CODE: + return "bdap_execute"; + case OP_BDAP_BIND: + return "bdap_bind"; + case OP_BDAP_REVOKE: + return "bdap_revoke"; + default: + return ""; + } +} + bool IsDirectoryDataOutput(const CTxOut& out) { txnouttype whichType; if (!IsStandard(out.scriptPubKey, whichType)) diff --git a/src/bdap/directory.h b/src/bdap/directory.h index 5711dba72e..e6cbffd8eb 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -190,6 +190,8 @@ class CDirectory { bool ValidateValues(std::string& errorMessage); }; +bool IsDirectoryTransaction(const CScript& txOut); +std::string directoryFromOp(const int op); bool IsDirectoryDataOutput(const CTxOut& out); int GetDirectoryDataOutput(const CTransaction& tx); bool GetDirectoryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index 514c510046..20c39e92a2 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -12,30 +12,6 @@ CDirectoryDB *pDirectoryDB = NULL; -std::string directoryFromOp(const int op) -{ - switch (op) { - case OP_BDAP_NEW: - return "bdap_new"; - case OP_BDAP_DELETE: - return "bdap_delete"; - case OP_BDAP_ACTIVATE: - return "bdap_activate"; - case OP_BDAP_MODIFY: - return "bdap_update"; - case OP_BDAP_MODIFY_RDN: - return "bdap_move"; - case OP_BDAP_EXECUTE_CODE: - return "bdap_execute"; - case OP_BDAP_BIND: - return "bdap_bind"; - case OP_BDAP_REVOKE: - return "bdap_revoke"; - default: - return ""; - } -} - bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory) { if (!pDirectoryDB || !pDirectoryDB->ReadDirectory(vchObjectPath, directory)) { @@ -171,10 +147,78 @@ void CDirectoryDB::WriteDirectoryIndex(const CDirectory& directory, const int op bool CDirectoryDB::UpdateDirectory(const std::vector& vchObjectPath, CDirectory& directory) { - return true; //TODO (bdap): add update impl + return false; //TODO (bdap): add update impl } bool CDirectoryDB::UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory) { - return true; //TODO (bdap): add update impl + return false; //TODO (bdap): add update impl } + +// Removes expired records from databases. +bool CDirectoryDB::CleanupLevelDB(int& nRemoved) +{ + boost::scoped_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + CDirectory dirEntry; + std::pair > key; + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + try { + if (pcursor->GetKey(key) && key.first == "domain_component") + { + pcursor->GetValue(dirEntry); + if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= dirEntry.nExpireTime) + { + nRemoved++; + EraseDirectory(key.second); + } + } + else if (pcursor->GetKey(key) && key.first == "domain_wallet_address") + { + std::vector value; + CDirectory directory; + pcursor->GetValue(value); + if (GetDirectory(value, directory) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) + { + nRemoved++; + EraseDirectoryAddress(directory.vchFullObjectPath()); + } + } + pcursor->Next(); + } catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +bool CheckDirectoryDB() +{ + if (!pDirectoryDB) + return false; + + return true; +} + +bool FlushLevelDB() +{ + { + LOCK(cs_bdap_directory); + if (pDirectoryDB != NULL) + { + if (!pDirectoryDB->Flush()) { + LogPrintf("Failed to write to BDAP database!"); + return false; + } + } + } + return true; +} + +void CleanupLevelDB(int& nRemoved) +{ + if(pDirectoryDB != NULL) + pDirectoryDB->CleanupLevelDB(nRemoved); + FlushLevelDB(); +} \ No newline at end of file diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h index f6d41669da..21090d2df9 100644 --- a/src/bdap/directorydb.h +++ b/src/bdap/directorydb.h @@ -29,10 +29,13 @@ class CDirectoryDB : public CDBWrapper { void WriteDirectoryIndexHistory(const CDirectory& directory, const int op); bool UpdateDirectory(const std::vector& vchObjectPath, CDirectory& directory); bool UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory); + bool CleanupLevelDB(int& nRemoved); }; -std::string directoryFromOp(const int op); bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory); +bool CheckDirectoryDB(); +bool FlushLevelDB(); +void CleanupLevelDB(int& nRemoved); extern CDirectoryDB *pDirectoryDB; From 6461f2c8df79163e836ac91fa67d779f85716c47 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 17 Jul 2018 23:59:44 -0500 Subject: [PATCH 0051/1653] [BDAP] Start checking directory tx validity --- src/bdap/directory.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++ src/bdap/directory.h | 5 +++ src/init.cpp | 1 - src/validation.cpp | 60 +++++++++++++++++++++++++++++++++++ src/validation.h | 6 ++-- 5 files changed, 141 insertions(+), 3 deletions(-) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index 9b0c390ae0..d8e063095e 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -4,6 +4,8 @@ #include "bdap/directory.h" + +#include "coins.h" #include "fluid.h" #include "policy/policy.h" #include "rpcclient.h" @@ -427,4 +429,74 @@ CAmount GetBDAPFee(const CScript& scriptPubKey) nFee = CWallet::GetMinimumFee(nSize, nTxConfirmTarget, mempool); recp.nAmount = nFee; return recp.nAmount; +} + +bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector >& vvch) +{ + bool found = false; + + for (unsigned int i = 0; i < tx.vout.size(); i++) { + const CTxOut& out = tx.vout[i]; + std::vector > vvchRead; + if (DecodeBDAPScript(out.scriptPubKey, op, vvchRead)) { + found = true; + vvch = vvchRead; + break; + } + } + if (!found) + vvch.clear(); + + return found; +} + +bool FindDirectoryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch) +{ + int op; + for (unsigned int i = 0; i < tx.vin.size(); i++) { + const Coin& prevCoins = inputs.AccessCoin(tx.vin[i].prevout); + if (prevCoins.IsSpent()) { + continue; + } + // check unspent input for consensus before adding to a block + if (DecodeBDAPScript(prevCoins.out.scriptPubKey, op, vvch)) { + return true; + } + } + return false; +} + +bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, + const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck) +{ + if (tx.IsCoinBase() && !fJustCheck && !bSanityCheck) + { + LogPrintf("*Trying to add BDAP entry in coinbase transaction, skipping..."); + return true; + } + //TODO (bdap): add if back + //if (fDebug && !bSanityCheck) + LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, directoryFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + + // unserialize BDAP from txn, check if the entry is valid and does not conflict with a previous entry + CDirectory directory; + std::vector vchData; + std::vector vchHash; + int nDataOut; + bool bData = GetDirectoryData(tx, vchData, vchHash, nDataOut); + if(bData && !directory.UnserializeFromData(vchData, vchHash)) + { + errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3600 - " + _("UnserializeFromData data in tx failed!"); + return error(errorMessage.c_str()); + } + + if(!directory.ValidateValues(errorMessage)) + { + errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3601 - " + errorMessage; + return error(errorMessage.c_str()); + } + //TODO (bdap): continue checking transaction validity + + + return true; } \ No newline at end of file diff --git a/src/bdap/directory.h b/src/bdap/directory.h index e6cbffd8eb..4c41f9952b 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -14,6 +14,7 @@ #include +class CCoinsViewCache; class CDynamicAddress; class CRecipient; class CTransaction; @@ -205,5 +206,9 @@ void ToLowerCase(CharString& vchValue); void ToLowerCase(std::string& strValue); bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrganizationalUnit, const CharString& vchDomainComponent); CAmount GetBDAPFee(const CScript& scriptPubKey); +bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector >& vvch); +bool FindDirectoryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch); +bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, + const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); #endif // DYNAMIC_DIRECTORY_H \ No newline at end of file diff --git a/src/init.cpp b/src/init.cpp index 5ba1be0a3f..fb123226c9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1464,7 +1464,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); - bool fLoaded = false; int64_t nStart = GetTimeMillis(); while (!fLoaded && !fRequestShutdown) { bool fReset = fReindex; diff --git a/src/validation.cpp b/src/validation.cpp index 27a8b7593d..57ad816b94 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -9,6 +9,7 @@ #include "alert.h" #include "arith_uint256.h" +#include "bdap/directorydb.h" #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" @@ -27,6 +28,7 @@ #include "primitives/block.h" #include "primitives/transaction.h" #include "random.h" +#include "rpcserver.h" #include "script/script.h" #include "script/sigcache.h" #include "script/standard.h" @@ -89,6 +91,7 @@ int64_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; bool fAlerts = DEFAULT_ALERTS; bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; +bool fLoaded = false; CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; @@ -582,6 +585,51 @@ std::string FormatStateMessage(const CValidationState &state) state.GetRejectCode()); } +// Check if BDAP entry is valid +bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, const CBlock& block, bool fJustCheck, int nHeight, bool bSanity) +{ + // Do not check while wallet is loading + if (!fLoaded) + return true; + + std::string errorMessage; + if (!CheckDirectoryDB()) + { + errorMessage = "ValidateBDAPInputs: CheckDirectoryDB failed!"; + return state.DoS(100, false, REJECT_INVALID, errorMessage); + } + + std::string statusRpc = ""; + if (fJustCheck && (IsInitialBlockDownload() || RPCIsInWarmup(&statusRpc))) + return true; + + std::vector > vvchArgs; + std::vector > vvchBDAPArgs; + + int op = -1; + if (nHeight == 0) + { + nHeight = chainActive.Height() + 1; + } + + bool bValid = false; + if (block.vtx.empty() && tx.nVersion == BDAP_TX_VERSION) + { + if (DecodeDirectoryTx(tx, op, vvchBDAPArgs)) + { + bValid = CheckDirectoryTxInputs(inputs, tx, op, vvchBDAPArgs, fJustCheck, nHeight, errorMessage, bSanity); + if (!bValid) + { + errorMessage = "ValidateBDAPInputs: " + errorMessage; + return state.DoS(100, false, REJECT_INVALID, errorMessage); + } + if (!bValid || !errorMessage.empty()) + return state.DoS(100, false, REJECT_INVALID, errorMessage); + } + } + return true; +} + bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector& coins_to_uncache, bool fDryRun) @@ -1023,6 +1071,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C __func__, hash.ToString(), FormatStateMessage(state)); } + if (!ValidateBDAPInputs(tx, state, view, CBlock(), true, chainActive.Height())) + { + return false; + } + // Remove conflicting transactions from the mempool BOOST_FOREACH(const CTxMemPool::txiter it, allConflicting) { @@ -2303,6 +2356,13 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd if (!control.Wait()) return state.DoS(100, false); + + CCoinsViewCache viewCoinCache(pcoinsTip); + if (!ValidateBDAPInputs(block.vtx[0], state, viewCoinCache, block, fJustCheck, pindex->nHeight)) + { + return error("ConnectBlock(): ValidateBDAPInputs on block %s failed\n", block.GetHash().ToString()); + } + int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001); diff --git a/src/validation.h b/src/validation.h index 3bdff08052..be0166013c 100644 --- a/src/validation.h +++ b/src/validation.h @@ -197,7 +197,8 @@ extern std::map mapRejectedBlocks; /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex *pindexBestHeader; - +/** BDAP, only check when fully loaded **/ +extern bool fLoaded; /** Minimum disk space required - used in CheckDiskSpace() */ static const uint64_t nMinDiskSpace = 52428800; @@ -306,7 +307,8 @@ CBlockIndex * InsertBlockIndex(uint256 hash); void FlushStateToDisk(); /** Prune block files and flush state to disk. */ void PruneAndFlush(); - +/** Checks inputs for a BDAP transaction. */ +bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, const CBlock& block, bool fJustCheck, int nHeight, bool bSanity = false); /** (try to) add transaction to memory pool **/ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0, bool fDryRun=false); From db1114128d6e7119d9728922c5b4dac2ea797400 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:23:32 +0200 Subject: [PATCH 0052/1653] Drop delayed headers logic and fix duplicate initial headers sync --- src/chainparams.cpp | 3 -- src/chainparams.h | 2 -- src/net_processing.cpp | 82 ++++++++++++++++-------------------------- 3 files changed, 31 insertions(+), 56 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 06fb16bd34..233067c5b6 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -161,7 +161,6 @@ class CMainParams : public CChainParams { vAlertPubKey = ParseHex("04bf1391ff0c61a5d9a02cd2e997b707ced89bb48514e26d89f2464c98295ffef3f587263c94e6024d4e455802ad73e1e9694f3e482ff6e074736cb2327f9cd3e7"); nDefaultPort = DEFAULT_P2P_PORT; nMaxTipAge = 24 * 60 * 64; - nDelayGetHeadersTime = 24 * 60 * 60; nPruneAfterHeight = 20545; startNewChain = false; @@ -276,7 +275,6 @@ class CTestNetParams : public CChainParams { vAlertPubKey = ParseHex("04d7e3d70462588ccde4cf2e4e8f29925395ee3ae2ded5244056cc895aab4c158986c702b2ef9665bf8f34450e153a649bdff3b3c784ec707fb637e1ba5ae100f5"); nDefaultPort = DEFAULT_P2P_PORT + 100; nMaxTipAge = 24 * 60 * 64; - nDelayGetHeadersTime = 24 * 60 * 60; nPruneAfterHeight = 100; startNewChain = false; @@ -382,7 +380,6 @@ class CRegTestParams : public CChainParams { pchMessageStart[3] = 0x3f; vAlertPubKey = ParseHex("04e8118b469667861157f3b2b28056ae92581ce61ce2db80d04a701f5ec5391b751e6136bafdcca7b8d0b564a5afce213e8069bdd1d17131f61d116b73dbf7e2d6"); nMaxTipAge = 24 * 60 * 64; - nDelayGetHeadersTime = 0; // never delay nDefaultPort = DEFAULT_P2P_PORT + 200; nPruneAfterHeight = 100; startNewChain = false; diff --git a/src/chainparams.h b/src/chainparams.h index ce29db7146..5697cd6e38 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -68,7 +68,6 @@ class CChainParams /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } int64_t MaxTipAge() const { return nMaxTipAge; } - int64_t DelayGetHeadersTime() const { return nDelayGetHeadersTime; } uint64_t PruneAfterHeight() const { return nPruneAfterHeight; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } @@ -93,7 +92,6 @@ class CChainParams std::vector vAlertPubKey; int nDefaultPort; long nMaxTipAge; - int64_t nDelayGetHeadersTime; uint64_t nPruneAfterHeight; std::vector vSeeds; std::vector base58Prefixes[MAX_BASE58_TYPES]; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 013752b45b..5dadd12a5f 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1412,25 +1412,31 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (inv.type == MSG_BLOCK) { UpdateBlockAvailability(pfrom->GetId(), inv.hash); - if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { - if (chainparams.DelayGetHeadersTime() != 0 && pindexBestHeader->GetBlockTime() < GetAdjustedTime() - chainparams.DelayGetHeadersTime()) { - // We are pretty far from being completely synced at the moment. If we would initiate a new - // chain of GETHEADERS/HEADERS now, we may end up downnloading the full chain from multiple - // peers at the same time, slowing down the initial sync. At the same time, we don't know - // if the peer we got this INV from may have a chain we don't know about yet, so we HAVE TO - // send a GETHEADERS message at some point in time. This is delayed to later in SendMessages - // when the headers chain has catched up enough. - LogPrint("net", "delaying getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); - pfrom->PushBlockHashFromINV(inv.hash); - } else { - // We used to request the full block here, but since headers-announcements are now the - // primary method of announcement on the network, and since, in the case that a node - // fell back to inv we probably have a reorg which we should get the headers for first, - // we now only provide a getheaders response here. When we receive the headers, we will - // then ask for the blocks we need. - connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); - LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); - } + + if (fAlreadyHave || fImporting || fReindex || mapBlocksInFlight.count(inv.hash)) { + continue; + } + + CNodeState *state = State(pfrom->id); + if (!state) { + continue; + } + + // Download if this is a nice peer, or we have no nice peers and this one might do. + bool fFetch = state->fPreferredDownload || (nPreferredDownload == 0 && !pfrom->fOneShot); + // Only actively request headers from a single peer, unless we're close to end of initial download. + if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 64) { + // Make sure to mark this peer as the one we are currently syncing with etc. + state->fSyncStarted = true; + state->nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(chainparams.GetConsensus().nPowTargetSpacing); + nSyncStarted++; + // We used to request the full block here, but since headers-announcements are now the + // primary method of announcement on the network, and since, in the case that a node + // fell back to inv we probably have a reorg which we should get the headers for first, + // we now only provide a getheaders response here. When we receive the headers, we will + // then ask for the blocks we need. + connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); + LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); } } else @@ -1881,29 +1887,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } nodestate->nUnconnectingHeaders = 0; - if (pindexLast) - UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); + assert(pindexLast); + UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); - if (nCount == MAX_HEADERS_RESULTS && pindexLast) { + if (nCount == MAX_HEADERS_RESULTS) { // Headers message had its maximum size; the peer may have more headers. // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue // from there instead. LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()); - } else { - if (chainparams.DelayGetHeadersTime() != 0 && pindexBestHeader->GetBlockTime() < GetAdjustedTime() - chainparams.DelayGetHeadersTime()) { - // peer has sent us a HEADERS message below maximum size and we are still quite far from being fully - // synced, this means we probably got a bad peer for initial sync and need to continue with another one. - // By disconnecting we force to start a new iteration of initial headers sync in SendMessages - // TODO should we handle whitelisted peers here as we do in headers sync timeout handling? - pfrom->fDisconnect = true; - return error("detected bad peer for initial headers sync, disconnecting %d", pfrom->id); - } - - if (nCount == 0) { - // Nothing interesting. Stop asking this peers for more headers. - return true; - } } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); @@ -2398,8 +2390,7 @@ class CompareInvMempoolOrder bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsgProc) { - const CChainParams chainParams = Params(); - const Consensus::Params& consensusParams = chainParams.GetConsensus(); + const Consensus::Params& consensusParams = Params().GetConsensus(); { // Don't send anything until the version handshake is complete if (!pto->fSuccessfullyConnected || pto->fDisconnect) @@ -2500,7 +2491,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. if (!state.fSyncStarted && !pto->fClient && !pto->fDisconnect && !fImporting && !fReindex) { // Only actively request headers from a single peer, unless we're close to end of initial download. - if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 6 * 60 * 60) { // NOTE: was "close to today" and 24h in Bitcoin + if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 64) { state.fSyncStarted = true; state.nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(consensusParams.nPowTargetSpacing); nSyncStarted++; @@ -2519,17 +2510,6 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg } } - if (chainParams.DelayGetHeadersTime() != 0 && pindexBestHeader->GetBlockTime() >= GetAdjustedTime() - chainParams.DelayGetHeadersTime()) { - // Headers chain has catched up enough so we can send out GETHEADER messages which were initially meant to - // be sent directly after INV was received - LOCK(pto->cs_inventory); - BOOST_FOREACH(const uint256 &hash, pto->vBlockHashesFromINV) { - LogPrint("net", "process delayed getheaders (%d) to peer=%d\n", pindexBestHeader->nHeight, pto->id); - connman.PushMessage(pto, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), hash); - } - pto->vBlockHashesFromINV.clear(); - } - // Resend wallet transactions that haven't gotten in a block yet // Except during reindex, importing and IBD, when old wallet // transactions become unconfirmed and spams other nodes. @@ -2815,7 +2795,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg // Check for headers sync timeouts if (state.fSyncStarted && state.nHeadersSyncTimeout < std::numeric_limits::max()) { // Detect whether this is a stalling initial-headers-sync peer - if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 6*60*60) { // was 24*60*60 in bitcoin + if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 64) { if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) { // Disconnect a (non-whitelisted) peer if it is our only sync peer, // and we have others we could be using instead. From bf4707a4d34384bf2cb80efdbda189c98be10a8a Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:30:16 +0200 Subject: [PATCH 0053/1653] replace boost iterators with for --- src/instantsend.cpp | 4 ++-- src/qt/dynodelist.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/instantsend.cpp b/src/instantsend.cpp index d1fcac77a3..0406269b5d 100644 --- a/src/instantsend.cpp +++ b/src/instantsend.cpp @@ -147,7 +147,7 @@ bool CInstantSend::CreateTxLockCandidate(const CTxLockRequest& txLockRequest) CTxLockCandidate txLockCandidate(txLockRequest); // all inputs should already be checked by txLockRequest.IsValid() above, just use them now - BOOST_REVERSE_FOREACH(const CTxIn& txin, txLockRequest.vin) { + for(const auto& txin : txLockRequest.vin) { txLockCandidate.AddOutPointLock(txin.prevout); } mapTxLockCandidates.insert(std::make_pair(txHash, txLockCandidate)); @@ -161,7 +161,7 @@ bool CInstantSend::CreateTxLockCandidate(const CTxLockRequest& txLockRequest) LogPrintf("CInstantSend::CreateTxLockCandidate -- update empty, txid=%s\n", txHash.ToString()); // all inputs should already be checked by txLockRequest.IsValid() above, just use them now - BOOST_REVERSE_FOREACH(const CTxIn& txin, txLockRequest.vin) { + for(const auto& txin : txLockRequest.vin) { itLockCandidate->second.AddOutPointLock(txin.prevout); } } else { diff --git a/src/qt/dynodelist.cpp b/src/qt/dynodelist.cpp index 61f51816d1..2972475fdb 100644 --- a/src/qt/dynodelist.cpp +++ b/src/qt/dynodelist.cpp @@ -112,7 +112,7 @@ void DynodeList::StartAlias(std::string strAlias) std::string strStatusHtml; strStatusHtml += "
Alias: " + strAlias; - BOOST_FOREACH(CDynodeConfig::CDynodeEntry dne, dynodeConfig.getEntries()) { + for (const auto& dne : dynodeConfig.getEntries()) { if(dne.getAlias() == strAlias) { std::string strError; CDynodeBroadcast dnb; @@ -145,7 +145,7 @@ void DynodeList::StartAll(std::string strCommand) int nCountFailed = 0; std::string strFailedHtml; - BOOST_FOREACH(CDynodeConfig::CDynodeEntry dne, dynodeConfig.getEntries()) { + for (const auto& dne : dynodeConfig.getEntries()) { std::string strError; CDynodeBroadcast dnb; @@ -242,7 +242,7 @@ void DynodeList::updateMyNodeList(bool fForce) nTimeMyListUpdated = GetTime(); ui->tableWidgetDynodes->setSortingEnabled(false); - BOOST_FOREACH(CDynodeConfig::CDynodeEntry dne, dynodeConfig.getEntries()) { + for (const auto& dne : dynodeConfig.getEntries()) { int32_t nOutputIndex = 0; if(!ParseInt32(dne.getOutputIndex(), &nOutputIndex)) { continue; From 619a121ee75ff2857055abed80b05568a9b502be Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:33:13 +0200 Subject: [PATCH 0054/1653] RPC: Add description for InstantSend-related fields of mempool entry --- src/rpcblockchain.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 747b5d028d..771929487d 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -184,22 +184,24 @@ UniValue getdifficulty(const JSONRPCRequest& request) std::string EntryDescriptionString() { - return " \"size\" : n, (numeric) transaction size in bytes\n" - " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" - " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n" - " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" - " \"height\" : n, (numeric) block height when transaction entered pool\n" - " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n" - " \"currentpriority\" : n, (numeric) transaction priority now\n" - " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n" - " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n" - " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n" - " \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n" - " \"ancestorsize\" : n, (numeric) size of in-mempool ancestors (including this one)\n" - " \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n" - " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" - " \"transactionid\", (string) parent transaction id\n" - " ... ]\n"; + return " \"size\" : n, (numeric) transaction size in bytes\n" + " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" + " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n" + " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" + " \"height\" : n, (numeric) block height when transaction entered pool\n" + " \"startingpriority\" : n, (numeric) DEPRECATED. Priority when transaction entered pool\n" + " \"currentpriority\" : n, (numeric) DEPRECATED. Transaction priority now\n" + " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n" + " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n" + " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n" + " \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n" + " \"ancestorsize\" : n, (numeric) size of in-mempool ancestors (including this one)\n" + " \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n" + " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" + " \"transactionid\", (string) parent transaction id\n" + " ... ],\n" + " \"instantsend\" : true|false, (boolean) True if this transaction was sent as an InstantSend one\n" + " \"instantlock\" : true|false (boolean) True if this transaction was locked via InstantSend\n"; } void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) From bfe1582afda5710da21a5d6a27b99822c00eadd8 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:42:39 +0200 Subject: [PATCH 0055/1653] RPC: fix wallet lock check in --- src/rpcdynode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rpcdynode.cpp b/src/rpcdynode.cpp index 7578595d8a..65e24e924f 100644 --- a/src/rpcdynode.cpp +++ b/src/rpcdynode.cpp @@ -46,7 +46,8 @@ UniValue privatesend(const JSONRPCRequest& request) if(request.params[0].get_str() == "start") { { LOCK(pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); + if (pwalletMain->IsLocked(true)) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first."); } if(fDynodeMode) From 40d4b5abeb2c85096bedab244d71971b70c4ada3 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:44:17 +0200 Subject: [PATCH 0056/1653] minor reformatting --- src/wallet/wallet.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b044ee4825..7e4f4822de 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3565,6 +3565,12 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); + if (nBytes > MAX_STANDARD_TX_SIZE) { + // Do not create oversized transactions (bad-txns-oversize). + strFailReason = _("Transaction too large"); + return false; + } + // Remove scriptSigs if we used dummy signatures for fee calculation if (!sign) { BOOST_FOREACH (CTxIn& txin, txNew.vin) @@ -3574,13 +3580,6 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT // Embed the constructed transaction data in wtxNew. *static_cast(&wtxNew) = CTransaction(txNew); - // Limit size - if (nBytes >= MAX_STANDARD_TX_SIZE) - { - strFailReason = _("Transaction too large"); - return false; - } - dPriority = wtxNew.ComputePriority(dPriority, nBytes); // Allow to override the default confirmation target over the CoinControl instance int currentConfirmationTarget = nTxConfirmTarget; From e65f99f8bc920cdceb405f836404a1b7652adf59 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:45:01 +0200 Subject: [PATCH 0057/1653] Remove explicit wallet lock in DynodeList::StartAll() --- src/qt/dynodelist.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/dynodelist.cpp b/src/qt/dynodelist.cpp index 2972475fdb..17d5721a24 100644 --- a/src/qt/dynodelist.cpp +++ b/src/qt/dynodelist.cpp @@ -170,7 +170,6 @@ void DynodeList::StartAll(std::string strCommand) strFailedHtml += "\nFailed to start " + dne.getAlias() + ". Error: " + strError; } } - pwalletMain->Lock(); std::string returnObj; returnObj = strprintf("Successfully started %d Dynodes, failed to start %d, total %d", nCountSuccessful, nCountFailed, nCountFailed + nCountSuccessful); From 792f1511c981951b7ed0bd5f2a1f938c6d3b0e44 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:49:17 +0200 Subject: [PATCH 0058/1653] Do not create dnb until dynodeSync is finished --- src/dynode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dynode.cpp b/src/dynode.cpp index c065e0587f..af51cc01bc 100644 --- a/src/dynode.cpp +++ b/src/dynode.cpp @@ -338,8 +338,8 @@ bool CDynodeBroadcast::Create(std::string strService, std::string strKeyDynode, return false; }; - //need correct blocks to send ping - if (!fOffline && !dynodeSync.IsBlockchainSynced()) + // Wait for sync to finish because dnb simply won't be relayed otherwise + if (!fOffline && !dynodeSync.IsSynced()) return Log("Sync in progress. Must wait until sync is complete to start Dynode"); if (!CMessageSigner::GetKeysFromSecret(strKeyDynode, keyDynodeNew, pubKeyDynodeNew)) From 6299a17bd6bf570c17103d3b7325a11e41a0ba7a Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:51:34 +0200 Subject: [PATCH 0059/1653] Don't drop dnb's for outdated DN's --- src/dynode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dynode.cpp b/src/dynode.cpp index af51cc01bc..556983f6b4 100644 --- a/src/dynode.cpp +++ b/src/dynode.cpp @@ -426,8 +426,8 @@ bool CDynodeBroadcast::SimpleCheck(int& nDos) } if(nProtocolVersion < dnpayments.GetMinDynodePaymentsProto()) { - LogPrintf("CDynodeBroadcast::SimpleCheck -- ignoring outdated Dynode: Dynode=%s nProtocolVersion=%d\n", vin.prevout.ToStringShort(), nProtocolVersion); - return false; + LogPrintf("CDynodeBroadcast::SimpleCheck -- outdated Dynode: dynode=%s nProtocolVersion=%d\n", outpoint.ToStringShort(), nProtocolVersion); + nActiveState = DYNODE_UPDATE_REQUIRED; } CScript pubkeyScript; From 21276847adb9c9e110333ee12b615ce3d7c2f6a4 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:55:15 +0200 Subject: [PATCH 0060/1653] Fix previous commit and fix 2 Spork issues --- src/dynode.cpp | 2 +- src/spork.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/dynode.cpp b/src/dynode.cpp index 556983f6b4..d7851dcc51 100644 --- a/src/dynode.cpp +++ b/src/dynode.cpp @@ -426,7 +426,7 @@ bool CDynodeBroadcast::SimpleCheck(int& nDos) } if(nProtocolVersion < dnpayments.GetMinDynodePaymentsProto()) { - LogPrintf("CDynodeBroadcast::SimpleCheck -- outdated Dynode: dynode=%s nProtocolVersion=%d\n", outpoint.ToStringShort(), nProtocolVersion); + LogPrintf("CDynodeBroadcast::SimpleCheck -- outdated Dynode: Dynode=%s nProtocolVersion=%d\n", vin.prevout.ToStringShort(), nProtocolVersion); nActiveState = DYNODE_UPDATE_REQUIRED; } diff --git a/src/spork.cpp b/src/spork.cpp index 979d8ec363..25a721e307 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -220,6 +220,12 @@ bool CSporkManager::SetPrivKey(std::string strPrivKey) bool CSporkMessage::Sign(std::string strSignKey) { CKey key; + + if (!key.IsValid()) { + LogPrintf("CSporkMessage::Sign -- signing key is not valid\n"); + return false; + } + CPubKey pubkey; std::string strError = ""; std::string strMessage = boost::lexical_cast(nSporkID) + boost::lexical_cast(nValue) + boost::lexical_cast(nTimeSigned); @@ -250,7 +256,6 @@ bool CSporkMessage::CheckSignature() CPubKey pubkey(ParseHex(Params().SporkPubKey())); if(!CMessageSigner::VerifyMessage(pubkey, vchSig, strMessage, strError)) { - LogPrintf("CSporkMessage::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); return false; } From 7b0fc31572f18eeb50951ca7ec5a8de7ffe1c17c Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:56:44 +0200 Subject: [PATCH 0061/1653] PrepareDenominate fix --- src/privatesend-client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 042ea78c53..76fb450333 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -1091,8 +1091,8 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std:: ++it2; } } - if(nValueLeft == 0) break; nStep++; + if(nValueLeft == 0) break; } { From c0429524e87ba413ce9a55aec26232a84f7c1be8 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Sun, 22 Jul 2018 23:59:03 +0200 Subject: [PATCH 0062/1653] Sync DN list and DNW list from 3 peers max --- src/dynode-sync.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/dynode-sync.cpp b/src/dynode-sync.cpp index ef5ffbd15f..69d55a933a 100644 --- a/src/dynode-sync.cpp +++ b/src/dynode-sync.cpp @@ -274,6 +274,12 @@ void CDynodeSync::ProcessTick(CConnman& connman) return; } + // request from three peers max + if (nRequestedDynodeAttempt > 2) { + connman.ReleaseNodeVector(vNodesCopy); + return; + } + // only request once from each peer if(netfulfilledman.HasFulfilledRequest(pnode->addr, "dynode-list-sync")) continue; netfulfilledman.AddFulfilledRequest(pnode->addr, "dynode-list-sync"); @@ -317,6 +323,12 @@ void CDynodeSync::ProcessTick(CConnman& connman) return; } + // request from three peers max + if (nRequestedDynodeAttempt > 2) { + connman.ReleaseNodeVector(vNodesCopy); + return; + } + // only request once from each peer if(netfulfilledman.HasFulfilledRequest(pnode->addr, "dynode-payment-sync")) continue; netfulfilledman.AddFulfilledRequest(pnode->addr, "dynode-payment-sync"); From 9c1608e6d01354970bde5386a0e79830d421f096 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 23 Jul 2018 00:00:36 +0200 Subject: [PATCH 0063/1653] Use correct protocol when serializing messages in reply to --- src/net_processing.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 5dadd12a5f..a69613850e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1041,7 +1041,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (!push && inv.type == MSG_GOVERNANCE_OBJECT) { LogPrint("net", "ProcessGetData -- MSG_GOVERNANCE_OBJECT: inv = %s\n", inv.ToString()); - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ss(SER_NETWORK, pfrom->GetSendVersion()); bool topush = false; { if(governance.HaveObjectForHash(inv.hash)) { @@ -1059,7 +1059,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } if (!push && inv.type == MSG_GOVERNANCE_OBJECT_VOTE) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ss(SER_NETWORK, pfrom->GetSendVersion()); bool topush = false; { if(governance.HaveVoteForHash(inv.hash)) { From ce03a4823482e48c31e4731a9d7a211908afa825 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 23 Jul 2018 00:06:09 +0200 Subject: [PATCH 0064/1653] Bump Versioning --- README.md | 2 +- configure.ac | 2 +- contrib/gitian-descriptors/gitian-arm.yml | 2 +- contrib/gitian-descriptors/gitian-linux.yml | 2 +- contrib/gitian-descriptors/gitian-osx.yml | 2 +- contrib/gitian-descriptors/gitian-win.yml | 2 +- doc/release-notes.md | 4 ++-- dynamic-qt.pro | 2 +- qa/rpc-tests/test_framework/mininode.py | 2 +- src/clientversion.h | 2 +- src/dynodeman.cpp | 2 +- src/governance.cpp | 2 +- src/version.h | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 39e644a09c..ff7c60f657 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Graph on Pull Request History [![Throughput Graph](https://graphs.waffle.io/duality-solutions/Dynamic/throughput.svg)](https://waffle.io/duality-solutions/Dynamic/metrics/throughput) -# **Dynamic (DYN) v2.3.0.0** +# **Dynamic (DYN) v2.4.0.0** ![DYN logo](https://github.com/duality-solutions/Dynamic/blob/master/src/qt/res/icons/drk/about.png) diff --git a/configure.ac b/configure.ac index 8a6d0d3289..90fb196a1b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) -define(_CLIENT_VERSION_MINOR, 3) +define(_CLIENT_VERSION_MINOR, 4) define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-arm.yml b/contrib/gitian-descriptors/gitian-arm.yml index 65f42b9f44..08fb55c94b 100644 --- a/contrib/gitian-descriptors/gitian-arm.yml +++ b/contrib/gitian-descriptors/gitian-arm.yml @@ -1,5 +1,5 @@ --- -name: "dynamic-arm-2.3.0.0" +name: "dynamic-arm-2.4.0.0" enable_cache: true suites: - "trusty" diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 63782487bc..33f0344415 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "dynamic-linux-2.3.0.0" +name: "dynamic-linux-2.4.0.0" enable_cache: true suites: - "trusty" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 55c32f1b83..253538e465 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,5 +1,5 @@ --- -name: "dynamic-osx-2.3.0.0" +name: "dynamic-osx-2.4.0.0" enable_cache: true suites: - "trusty" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index f22d47d488..bf35a4ee14 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,5 +1,5 @@ --- -name: "dynamic-2.3.0.0" +name: "dynamic-2.4.0.0" enable_cache: true suites: - "trusty" diff --git a/doc/release-notes.md b/doc/release-notes.md index 1c76e9a2a6..55630b1a7b 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,3 +1,3 @@ -Dynamic 2.3.0.0 +Dynamic 2.4.0.0 ================== -- [v2.3.0.0](release-notes/dynamic/release-notes.md) \ No newline at end of file +- [v2.4.0.0](release-notes/dynamic/release-notes.md) \ No newline at end of file diff --git a/dynamic-qt.pro b/dynamic-qt.pro index 72a1d6cbb1..275f641adc 100644 --- a/dynamic-qt.pro +++ b/dynamic-qt.pro @@ -1,6 +1,6 @@ TEMPLATE = app TARGET = dynamic -VERSION = 2.3.0.0 +VERSION = 2.4.0.0 INCLUDEPATH += src \ src/crypto \ src/crypto/heavyhash \ diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index ee36c94969..4f4d70ae30 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -35,7 +35,7 @@ import dynamic_hash BIP0031_VERSION = 60000 -MY_VERSION = 70900 # past bip-31 for ping/pong +MY_VERSION = 71000 # past bip-31 for ping/pong MY_SUBVERSION = b"/python-mininode-tester:0.0.2/" MAX_INV_SZ = 50000 diff --git a/src/clientversion.h b/src/clientversion.h index bb8624d8ee..fda56a45bd 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ //! These need to be macros, as clientversion.cpp's and dynamic*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 2 -#define CLIENT_VERSION_MINOR 3 +#define CLIENT_VERSION_MINOR 4 #define CLIENT_VERSION_REVISION 0 #define CLIENT_VERSION_BUILD 0 diff --git a/src/dynodeman.cpp b/src/dynodeman.cpp index 1127d4bb31..9860a420fe 100644 --- a/src/dynodeman.cpp +++ b/src/dynodeman.cpp @@ -21,7 +21,7 @@ /** Dynode manager */ CDynodeMan dnodeman; -const std::string CDynodeMan::SERIALIZATION_VERSION_STRING = "CDynodeMan-Version-2"; +const std::string CDynodeMan::SERIALIZATION_VERSION_STRING = "CDynodeMan-Version-3"; struct CompareLastPaidBlock { diff --git a/src/governance.cpp b/src/governance.cpp index 1136633a12..c611900a54 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -20,7 +20,7 @@ CGovernanceManager governance; int nSubmittedFinalBudget; -const std::string CGovernanceManager::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-23"; +const std::string CGovernanceManager::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-24"; const int CGovernanceManager::MAX_TIME_FUTURE_DEVIATION = 60*60; const int CGovernanceManager::RELIABLE_PROPAGATION_TIME = 60; diff --git a/src/version.h b/src/version.h index 848c98de1e..bbc8911512 100644 --- a/src/version.h +++ b/src/version.h @@ -12,7 +12,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70900; +static const int PROTOCOL_VERSION = 71000; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; From 501b19f9926d58e40f97505fb20c6548a4b6c20b Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 23 Jul 2018 00:09:31 +0200 Subject: [PATCH 0065/1653] Update CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdf8aa9acc..0b14a2b47d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,20 @@ **Dynamic CHANGELOG** ------------------------- +**Dynamic v2.4.0.0** + +* Drop delayed headers logic and fix duplicate initial headers sync +* replace boost iterators with for +* RPC: Add description for InstantSend-related fields of mempool entry +* RPC: fix wallet lock check in +* minor reformatting +* Remove explicit wallet lock in DynodeList::StartAll() +* Do not create dnb until dynodeSync is finished +* Don't drop dnb's for outdated DN's +* Fix previous commit and fix 2 Spork issues +* PrepareDenominate fix +* Sync DN list and DNW list from 3 peers max + **Dynamic v2.3.0.0** * Skip existing Dynodes connections on mixing From 6043ae06326472dd6d96988ec0cde6d571f7e3eb Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 23 Jul 2018 09:39:33 +0200 Subject: [PATCH 0066/1653] Update dynamic_qt.m4 (Remove ability to build with Qt4) --- build-aux/m4/dynamic_qt.m4 | 380 +++++++++++++++++++------------------ 1 file changed, 197 insertions(+), 183 deletions(-) diff --git a/build-aux/m4/dynamic_qt.m4 b/build-aux/m4/dynamic_qt.m4 index 3f91ff2209..105cb9e956 100644 --- a/build-aux/m4/dynamic_qt.m4 +++ b/build-aux/m4/dynamic_qt.m4 @@ -1,23 +1,23 @@ -dnl Copyright (c) 2013-2016 The Dualiy Blockchain Solutions developers +dnl Copyright (c) 2013-2016 The Bitcoin Core developers dnl Distributed under the MIT software license, see the accompanying dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. dnl Helper for cases where a qt dependency is not met. dnl Output: If qt version is auto, set dynamic_enable_qt to false. Else, exit. AC_DEFUN([DYNAMIC_QT_FAIL],[ - if test "x$dynamic_qt_want_version" = "xauto" && test x$dynamic_qt_force != xyes; then - if test x$dynamic_enable_qt != xno; then + if test "x$dynamic_qt_want_version" = xauto && test "x$dynamic_qt_force" != xyes; then + if test "x$dynamic_enable_qt" != xno; then AC_MSG_WARN([$1; dynamic-qt frontend will not be built]) fi dynamic_enable_qt=no - dynamic_enable_qt_test=no + dynamic_enable_qt=no else AC_MSG_ERROR([$1]) fi ]) AC_DEFUN([DYNAMIC_QT_CHECK],[ - if test "x$dynamic_enable_qt" != "xno" && test x$dynamic_qt_want_version != xno; then + if test "x$dynamic_enable_qt" != xno && test "x$dynamic_qt_want_version" != xno; then true $1 else @@ -35,12 +35,12 @@ dnl Inputs: $4: If "yes", don't fail if $2 is not found. dnl Output: $1 is set to the path of $2 if found. $2 are searched in order. AC_DEFUN([DYNAMIC_QT_PATH_PROGS],[ DYNAMIC_QT_CHECK([ - if test "x$3" != "x"; then + if test "x$3" != x; then AC_PATH_PROGS($1,$2,,$3) else AC_PATH_PROGS($1,$2) fi - if test "x$$1" = "x" && test "x$4" != "xyes"; then + if test "x$$1" = x && test "x$4" != xyes; then DYNAMIC_QT_FAIL([$1 not found]) fi ]) @@ -53,11 +53,11 @@ dnl CAUTION: Do not use this inside of a conditional. AC_DEFUN([DYNAMIC_QT_INIT],[ dnl enable qt support AC_ARG_WITH([gui], - [AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@], - [build dynamic-qt GUI (default=auto, qt5 tried first)])], + [AS_HELP_STRING([--with-gui@<:@=no|qt5|auto@:>@], + [build dynamic-qt GUI (default=auto)])], [ dynamic_qt_want_version=$withval - if test x$dynamic_qt_want_version = xyes; then + if test "x$dynamic_qt_want_version" = xyes; then dynamic_qt_force=yes dynamic_qt_want_version=auto fi @@ -89,23 +89,22 @@ dnl Outputs: dynamic_enable_qt, dynamic_enable_qt_dbus, dynamic_enable_qt_test AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ use_pkgconfig=$1 - if test x$use_pkgconfig = x; then + if test "x$use_pkgconfig" = x; then use_pkgconfig=yes fi - if test x$use_pkgconfig = xyes; then - DYNAMIC_QT_CHECK([_DYNAMIC_QT_FIND_LIBS_WITH_PKGCONFIG([$2])]) + if test "x$use_pkgconfig" = xyes; then + DYNAMIC_QT_CHECK([_DYNAMIC_QT_FIND_LIBS_WITH_PKGCONFIG]) else DYNAMIC_QT_CHECK([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG]) fi dnl This is ugly and complicated. Yuck. Works as follows: - dnl We can't discern whether Qt4 builds are static or not. For Qt5, we can - dnl check a header to find out. When Qt is built statically, some plugins must - dnl be linked into the final binary as well. These plugins have changed between - dnl Qt4 and Qt5. With Qt5, languages moved into core and the WindowsIntegration - dnl plugin was added. Since we can't tell if Qt4 is static or not, it is - dnl assumed for windows builds. + dnl For Qt5, we can check a header to find out whether Qt is build + dnl statically. When Qt is built statically, some plugins must be linked into + dnl the final binary as well. + dnl With Qt5, languages moved into core and the WindowsIntegration plugin was + dnl added. dnl _DYNAMIC_QT_CHECK_STATIC_PLUGINS does a quick link-check and appends the dnl results to QT_LIBS. DYNAMIC_QT_CHECK([ @@ -113,69 +112,67 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ TEMP_CXXFLAGS=$CXXFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" CXXFLAGS="$PIC_FLAGS $CXXFLAGS" - if test x$dynamic_qt_got_major_vers = x5; then - _DYNAMIC_QT_IS_STATIC - if test x$dynamic_cv_static_qt = xyes; then - _DYNAMIC_QT_FIND_STATIC_PLUGINS - AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) - AC_CACHE_CHECK(for Qt < 5.4, dynamic_cv_need_acc_widget,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]],[[ + _DYNAMIC_QT_IS_STATIC + if test "x$dynamic_cv_static_qt" = xyes; then + _DYNAMIC_QT_FIND_STATIC_PLUGINS + AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) + AC_CACHE_CHECK(for Qt < 5.4, dynamic_cv_need_acc_widget,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], + [[ #if QT_VERSION >= 0x050400 - choke; + choke #endif - ]])], - [dynamic_cv_need_acc_widget=yes], - [dynamic_cv_need_acc_widget=no]) - ]) - if test "x$dynamic_cv_need_acc_widget" = "xyes"; then - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) - fi - if test x$TARGET_OS = xwindows; then - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) - AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) - elif test x$TARGET_OS = xlinux; then - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static]) - AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb]) - elif test x$TARGET_OS = xdarwin; then - AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)]) - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa]) - AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa]) - fi + ]])], + [dynamic_cv_need_acc_widget=yes], + [dynamic_cv_need_acc_widget=no]) + ]) + if test "x$dynamic_cv_need_acc_widget" = xyes; then + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) fi - else - if test x$TARGET_OS = xwindows; then - AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static]) - _DYNAMIC_QT_CHECK_STATIC_PLUGINS([ - Q_IMPORT_PLUGIN(qcncodecs) - Q_IMPORT_PLUGIN(qjpcodecs) - Q_IMPORT_PLUGIN(qtwcodecs) - Q_IMPORT_PLUGIN(qkrcodecs) - Q_IMPORT_PLUGIN(AccessibleFactory)], - [-lqcncodecs -lqjpcodecs -lqtwcodecs -lqkrcodecs -lqtaccessiblewidgets]) + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) + AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) + if test "x$TARGET_OS" = xwindows; then + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) + AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) + elif test "x$TARGET_OS" = xlinux; then + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)],[-lqxcb -lxcb-static]) + AC_DEFINE(QT_QPA_PLATFORM_XCB, 1, [Define this symbol if the qt platform is xcb]) + elif test "x$TARGET_OS" = xdarwin; then + AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)]) + _DYNAMIC_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa]) + AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa]) fi fi CPPFLAGS=$TEMP_CPPFLAGS CXXFLAGS=$TEMP_CXXFLAGS ]) - if test x$use_pkgconfig$qt_bin_path = xyes; then - if test x$dynamic_qt_got_major_vers = x5; then - qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`" - fi + if test "x$use_pkgconfig$qt_bin_path" = xyes; then + qt_bin_path="`$PKG_CONFIG --variable=host_bins Qt5Core 2>/dev/null`" fi - if test x$use_hardening != xno; then + if test "x$use_hardening" != xno; then DYNAMIC_QT_CHECK([ AC_MSG_CHECKING(whether -fPIE can be used with this Qt config) TEMP_CPPFLAGS=$CPPFLAGS TEMP_CXXFLAGS=$CXXFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" CXXFLAGS="$PIE_FLAGS $CXXFLAGS" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], [[ - #if defined(QT_REDUCE_RELOCATIONS) - choke; - #endif + #if defined(QT_REDUCE_RELOCATIONS) + choke + #endif ]])], [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIE_FLAGS ], [ AC_MSG_RESULT(no); QT_PIE_FLAGS=$PIC_FLAGS] @@ -188,11 +185,16 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ AC_MSG_CHECKING(whether -fPIC is needed with this Qt config) TEMP_CPPFLAGS=$CPPFLAGS CPPFLAGS="$QT_INCLUDES $CPPFLAGS" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], [[ - #if defined(QT_REDUCE_RELOCATIONS) - choke; - #endif + #if defined(QT_REDUCE_RELOCATIONS) + choke + #endif ]])], [ AC_MSG_RESULT(no)], [ AC_MSG_RESULT(yes); QT_PIE_FLAGS=$PIC_FLAGS] @@ -201,11 +203,11 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ ]) fi - DYNAMIC_QT_PATH_PROGS([MOC], [moc-qt${dynamic_qt_got_major_vers} moc${dynamic_qt_got_major_vers} moc], $qt_bin_path) - DYNAMIC_QT_PATH_PROGS([UIC], [uic-qt${dynamic_qt_got_major_vers} uic${dynamic_qt_got_major_vers} uic], $qt_bin_path) - DYNAMIC_QT_PATH_PROGS([RCC], [rcc-qt${dynamic_qt_got_major_vers} rcc${dynamic_qt_got_major_vers} rcc], $qt_bin_path) - DYNAMIC_QT_PATH_PROGS([LRELEASE], [lrelease-qt${dynamic_qt_got_major_vers} lrelease${dynamic_qt_got_major_vers} lrelease], $qt_bin_path) - DYNAMIC_QT_PATH_PROGS([LUPDATE], [lupdate-qt${dynamic_qt_got_major_vers} lupdate${dynamic_qt_got_major_vers} lupdate],$qt_bin_path, yes) + DYNAMIC_QT_PATH_PROGS([MOC], [moc-qt5 moc5 moc], $qt_bin_path) + DYNAMIC_QT_PATH_PROGS([UIC], [uic-qt5 uic5 uic], $qt_bin_path) + DYNAMIC_QT_PATH_PROGS([RCC], [rcc-qt5 rcc5 rcc], $qt_bin_path) + DYNAMIC_QT_PATH_PROGS([LRELEASE], [lrelease-qt5 lrelease5 lrelease], $qt_bin_path) + DYNAMIC_QT_PATH_PROGS([LUPDATE], [lupdate-qt5 lupdate5 lupdate],$qt_bin_path, yes) MOC_DEFS='-DHAVE_CONFIG_H -I$(srcdir)' case $host in @@ -228,23 +230,23 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ DYNAMIC_QT_CHECK([ dynamic_enable_qt=yes dynamic_enable_qt_test=yes - if test x$have_qt_test = xno; then + if test "x$have_qt_test" = xno; then dynamic_enable_qt_test=no fi dynamic_enable_qt_dbus=no - if test x$use_dbus != xno && test x$have_qt_dbus = xyes; then + if test "x$use_dbus" != xno && test "x$have_qt_dbus" = xyes; then dynamic_enable_qt_dbus=yes fi - if test x$use_dbus = xyes && test x$have_qt_dbus = xno; then - AC_MSG_ERROR("libQtDBus not found. Install libQtDBus or remove --with-qtdbus.") + if test "x$use_dbus" = xyes && test "x$have_qt_dbus" = xno; then + AC_MSG_ERROR([libQtDBus not found. Install libQtDBus or remove --with-qtdbus.]) fi - if test x$LUPDATE = x; then - AC_MSG_WARN("lupdate is required to update qt translations") + if test "x$LUPDATE" = x; then + AC_MSG_WARN([lupdate is required to update qt translations]) fi ],[ dynamic_enable_qt=no ]) - AC_MSG_RESULT([$dynamic_enable_qt (Qt${dynamic_qt_got_major_vers})]) + AC_MSG_RESULT([$dynamic_enable_qt (Qt5)]) AC_SUBST(QT_PIE_FLAGS) AC_SUBST(QT_INCLUDES) @@ -254,7 +256,7 @@ AC_DEFUN([DYNAMIC_QT_CONFIGURE],[ AC_SUBST(QT_DBUS_LIBS) AC_SUBST(QT_TEST_INCLUDES) AC_SUBST(QT_TEST_LIBS) - AC_SUBST(QT_SELECT, qt${dynamic_qt_got_major_vers}) + AC_SUBST(QT_SELECT, qt5) AC_SUBST(MOC_DEFS) ]) @@ -267,39 +269,64 @@ dnl Requires: INCLUDES must be populated as necessary. dnl Output: dynamic_cv_qt5=yes|no AC_DEFUN([_DYNAMIC_QT_CHECK_QT5],[ AC_CACHE_CHECK(for Qt 5, dynamic_cv_qt5,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], [[ - #if QT_VERSION < 0x050000 - choke me - #else - return 0; + #if QT_VERSION < 0x050000 || QT_VERSION_MAJOR < 5 + choke #endif ]])], [dynamic_cv_qt5=yes], [dynamic_cv_qt5=no]) ])]) +dnl Internal. Check if the included version of Qt is greater than Qt58. +dnl Requires: INCLUDES must be populated as necessary. +dnl Output: dynamic_cv_qt5=yes|no +AC_DEFUN([_DYNAMIC_QT_CHECK_QT58],[ + AC_CACHE_CHECK(for > Qt 5.7, dynamic_cv_qt58,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], + [[ + #if QT_VERSION_MINOR < 8 + choke + #endif + ]])], + [dynamic_cv_qt58=yes], + [dynamic_cv_qt58=no]) +])]) + + dnl Internal. Check if the linked version of Qt was built as static libs. -dnl Requires: Qt5. This check cannot determine if Qt4 is static. +dnl Requires: Qt5. dnl Requires: INCLUDES and LIBS must be populated as necessary. dnl Output: dynamic_cv_static_qt=yes|no dnl Output: Defines QT_STATICPLUGIN if plugins are static. AC_DEFUN([_DYNAMIC_QT_IS_STATIC],[ AC_CACHE_CHECK(for static Qt, dynamic_cv_static_qt,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]], - [[ - #if defined(QT_STATIC) - return 0; - #else - choke me - #endif - ]])], - [dynamic_cv_static_qt=yes], - [dynamic_cv_static_qt=no]) - ]) - if test xdynamic_cv_static_qt = xyes; then + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION OR QT_VERSION_STR + # include + #endif + ]], + [[ + #if !defined(QT_STATIC) + choke + #endif + ]])], + [dynamic_cv_static_qt=yes], + [dynamic_cv_static_qt=no]) + ]) + if test "x$dynamic_cv_static_qt" = xyes; then AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol for static Qt plugins]) fi ]) @@ -324,56 +351,71 @@ AC_DEFUN([_DYNAMIC_QT_CHECK_STATIC_PLUGINS],[ ]) dnl Internal. Find paths necessary for linking qt static plugins -dnl Inputs: dynamic_qt_got_major_vers. 4 or 5. dnl Inputs: qt_plugin_path. optional. dnl Outputs: QT_LIBS is appended AC_DEFUN([_DYNAMIC_QT_FIND_STATIC_PLUGINS],[ - if test x$dynamic_qt_got_major_vers = x5; then - if test x$qt_plugin_path != x; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" - if test -d "$qt_plugin_path/accessible"; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" - fi + if test "x$qt_plugin_path" != x; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" + if test -d "$qt_plugin_path/accessible"; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" fi - if test x$use_pkgconfig = xyes; then + if test "x$use_pkgconfig" = xyes; then : dnl m4_ifdef([PKG_CHECK_MODULES],[ - PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) - if test x$TARGET_OS = xlinux; then + if test x$dynamic_cv_qt58 = xno; then + PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"]) + else + PKG_CHECK_MODULES([QTFONTDATABASE], [Qt5FontDatabaseSupport], [QT_LIBS="-lQt5FontDatabaseSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTEVENTDISPATCHER], [Qt5EventDispatcherSupport], [QT_LIBS="-lQt5EventDispatcherSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTTHEME], [Qt5ThemeSupport], [QT_LIBS="-lQt5ThemeSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTDEVICEDISCOVERY], [Qt5DeviceDiscoverySupport], [QT_LIBS="-lQt5DeviceDiscoverySupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTACCESSIBILITY], [Qt5AccessibilitySupport], [QT_LIBS="-lQt5AccessibilitySupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTFB], [Qt5FbSupport], [QT_LIBS="-lQt5FbSupport $QT_LIBS"]) + fi + if test "x$TARGET_OS" = xlinux; then PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"]) if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"]) fi - elif test x$TARGET_OS = xdarwin; then - PKG_CHECK_MODULES([QTPRINT], [Qt5PrintSupport], [QT_LIBS="$QTPRINT_LIBS $QT_LIBS"]) - else - if ${PKG_CONFIG} --exists "Qt5Core >= 5.6" 2>/dev/null; then - QT_LIBS="-lQt5PlatformSupport $QT_LIBS" - fi + elif test "x$TARGET_OS" = xdarwin; then + PKG_CHECK_MODULES([QTCLIPBOARD], [Qt5ClipboardSupport], [QT_LIBS="-lQt5ClipboardSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTGRAPHICS], [Qt5GraphicsSupport], [QT_LIBS="-lQt5GraphicsSupport $QT_LIBS"]) + PKG_CHECK_MODULES([QTCGL], [Qt5CglSupport], [QT_LIBS="-lQt5CglSupport $QT_LIBS"]) fi ]) else - if test x$TARGET_OS = xwindows; then - AC_CACHE_CHECK(for Qt >= 5.6, dynamic_cv_need_platformsupport,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]],[[ - #if QT_VERSION < 0x050600 - choke; - #endif + if test "x$TARGET_OS" = xwindows; then + AC_CACHE_CHECK(for Qt >= 5.6, dynamic_cv_need_platformsupport,[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #ifndef QT_VERSION + # include + #endif + ]], + [[ + #if QT_VERSION < 0x050600 || QT_VERSION_MINOR < 6 + choke + #endif ]])], [dynamic_cv_need_platformsupport=yes], [dynamic_cv_need_platformsupport=no]) ]) - if test x$dynamic_cv_need_platformsupport = xyes; then - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PlatformSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXPlatformSupport not found))) + if test "x$dynamic_cv_need_platformsupport" = xyes; then + if test x$dynamic_cv_qt58 = xno; then + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}PlatformSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXPlatformSupport not found))) + else + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}FontDatabaseSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXFontDatabaseSupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}EventDispatcherSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXEventDispatcherSupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}ThemeSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXThemeSupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}FbSupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXFbSupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}DeviceDiscoverySupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXDeviceDiscoverySupport not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}AccessibilitySupport],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXAccessibilitySupport not found))) + QT_LIBS="$QT_LIBS -lversion -ldwmapi -luxtheme" + fi fi fi fi - else - if test x$qt_plugin_path != x; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" - QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs" - fi - fi + fi ]) dnl Internal. Find Qt libraries using pkg-config. @@ -382,46 +424,22 @@ dnl first. dnl Inputs: $1: If dynamic_qt_want_version is "auto", check for this version dnl first. dnl Outputs: All necessary QT_* variables are set. -dnl Outputs: dynamic_qt_got_major_vers is set to "4" or "5". dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITH_PKGCONFIG],[ m4_ifdef([PKG_CHECK_MODULES],[ - auto_priority_version=$1 - if test x$auto_priority_version = x; then - auto_priority_version=qt5 - fi - if test x$dynamic_qt_want_version = xqt5 || ( test x$dynamic_qt_want_version = xauto && test x$auto_priority_version = xqt5 ); then - QT_LIB_PREFIX=Qt5 - dynamic_qt_got_major_vers=5 - else - QT_LIB_PREFIX=Qt - dynamic_qt_got_major_vers=4 - fi + QT_LIB_PREFIX=Qt5 qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets" - qt4_modules="QtCore QtGui QtNetwork" DYNAMIC_QT_CHECK([ - if test x$dynamic_qt_want_version = xqt5 || ( test x$dynamic_qt_want_version = xauto && test x$auto_priority_version = xqt5 ); then - PKG_CHECK_MODULES([QT], [$qt5_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes],[have_qt=no]) - elif test x$dynamic_qt_want_version = xqt4 || ( test x$dynamic_qt_want_version = xauto && test x$auto_priority_version = xqt4 ); then - PKG_CHECK_MODULES([QT], [$qt4_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes], [have_qt=no]) - fi + PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" have_qt=yes],[have_qt=no]) - dnl qt version is set to 'auto' and the preferred version wasn't found. Now try the other. - if test x$have_qt = xno && test x$dynamic_qt_want_version = xauto; then - if test x$auto_priority_version = xqt5; then - PKG_CHECK_MODULES([QT], [$qt4_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes; QT_LIB_PREFIX=Qt; dynamic_qt_got_major_vers=4], [have_qt=no]) - else - PKG_CHECK_MODULES([QT], [$qt5_modules], [QT_INCLUDES="$QT_CFLAGS"; have_qt=yes; QT_LIB_PREFIX=Qt5; dynamic_qt_got_major_vers=5], [have_qt=no]) - fi - fi - if test x$have_qt != xyes; then + if test "x$have_qt" != xyes; then have_qt=no DYNAMIC_QT_FAIL([Qt dependencies not found]) fi ]) DYNAMIC_QT_CHECK([ PKG_CHECK_MODULES([QT_TEST], [${QT_LIB_PREFIX}Test], [QT_TEST_INCLUDES="$QT_TEST_CFLAGS"; have_qt_test=yes], [have_qt_test=no]) - if test x$use_dbus != xno; then + if test "x$use_dbus" != xno; then PKG_CHECK_MODULES([QT_DBUS], [${QT_LIB_PREFIX}DBus], [QT_DBUS_INCLUDES="$QT_DBUS_CFLAGS"; have_qt_dbus=yes], [have_qt_dbus=no]) fi ]) @@ -434,7 +452,6 @@ dnl from the discovered headers. dnl Inputs: dynamic_qt_want_version (from --with-gui=). The version to use. dnl If "auto", the version will be discovered by _DYNAMIC_QT_CHECK_QT5. dnl Outputs: All necessary QT_* variables are set. -dnl Outputs: dynamic_qt_got_major_vers is set to "4" or "5". dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ TEMP_CPPFLAGS="$CPPFLAGS" @@ -442,7 +459,7 @@ AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ CXXFLAGS="$PIC_FLAGS $CXXFLAGS" TEMP_LIBS="$LIBS" DYNAMIC_QT_CHECK([ - if test x$qt_include_path != x; then + if test "x$qt_include_path" != x; then QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus" CPPFLAGS="$QT_INCLUDES $CPPFLAGS" fi @@ -453,54 +470,52 @@ AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ DYNAMIC_QT_CHECK([AC_CHECK_HEADER([QLocalSocket],, DYNAMIC_QT_FAIL(QtNetwork headers missing))]) DYNAMIC_QT_CHECK([ - if test x$dynamic_qt_want_version = xauto; then + if test "x$dynamic_qt_want_version" = xauto; then _DYNAMIC_QT_CHECK_QT5 + _DYNAMIC_QT_CHECK_QT58 fi - if test x$dynamic_cv_qt5 = xyes || test x$dynamic_qt_want_version = xqt5; then - QT_LIB_PREFIX=Qt5 - dynamic_qt_got_major_vers=5 - else - QT_LIB_PREFIX=Qt - dynamic_qt_got_major_vers=4 - fi + QT_LIB_PREFIX=Qt5 ]) DYNAMIC_QT_CHECK([ LIBS= - if test x$qt_lib_path != x; then + if test "x$qt_lib_path" != x; then LIBS="$LIBS -L$qt_lib_path" fi - if test x$TARGET_OS = xwindows; then + if test "x$TARGET_OS" = xwindows; then AC_CHECK_LIB([imm32], [main],, DYNAMIC_QT_FAIL(libimm32 not found)) fi ]) DYNAMIC_QT_CHECK(AC_CHECK_LIB([z] ,[main],,AC_MSG_WARN([zlib not found. Assuming qt has it built-in]))) - DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([jpeg_create_decompress] ,[qtjpeg jpeg],,AC_MSG_WARN([libjpeg not found. Assuming qt has it built-in]))) - DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in]))) - DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([hb_ot_tags_from_script] ,[qtharfbuzzng harfbuzz],,AC_MSG_WARN([libharfbuzz not found. Assuming qt has it built-in or support is disabled]))) - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Core] ,[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXCore not found))) - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXGui not found))) - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXNetwork not found))) - if test x$dynamic_qt_got_major_vers = x5; then - DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,DYNAMIC_QT_FAIL(lib$QT_LIB_PREFIXWidgets not found))) + if test x$dynamic_cv_qt58 = xno; then + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in]))) + else + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtlibpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([pcre2_match_16], [qtpcre2 libqtpcre2],,AC_MSG_WARN([libqtpcre2 not found. Assuming qt has it built-in]))) fi + DYNAMIC_QT_CHECK(AC_SEARCH_LIBS([hb_ot_tags_from_script] ,[qtharfbuzzng qtharfbuzz harfbuzz],,AC_MSG_WARN([libharfbuzz not found. Assuming qt has it built-in or support is disabled]))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Core] ,[main],,DYNAMIC_QT_FAIL(lib${QT_LIB_PREFIX}Core not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,DYNAMIC_QT_FAIL(lib${QT_LIB_PREFIX}Gui not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,DYNAMIC_QT_FAIL(lib${QT_LIB_PREFIX}Network not found))) + DYNAMIC_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,DYNAMIC_QT_FAIL(lib${QT_LIB_PREFIX}Widgets not found))) QT_LIBS="$LIBS" LIBS="$TEMP_LIBS" DYNAMIC_QT_CHECK([ LIBS= - if test x$qt_lib_path != x; then + if test "x$qt_lib_path" != x; then LIBS="-L$qt_lib_path" fi AC_CHECK_LIB([${QT_LIB_PREFIX}Test], [main],, have_qt_test=no) AC_CHECK_HEADER([QTest],, have_qt_test=no) QT_TEST_LIBS="$LIBS" - if test x$use_dbus != xno; then + if test "x$use_dbus" != xno; then LIBS= - if test x$qt_lib_path != x; then + if test "x$qt_lib_path" != x; then LIBS="-L$qt_lib_path" fi AC_CHECK_LIB([${QT_LIB_PREFIX}DBus], [main],, have_qt_dbus=no) @@ -512,4 +527,3 @@ AC_DEFUN([_DYNAMIC_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ CXXFLAGS="$TEMP_CXXFLAGS" LIBS="$TEMP_LIBS" ]) - From cbb6c7ef0aeac4b7026de26b58629420a7815e45 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 23 Jul 2018 09:54:32 +0200 Subject: [PATCH 0067/1653] Update CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b14a2b47d..5e214042c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ * Fix previous commit and fix 2 Spork issues * PrepareDenominate fix * Sync DN list and DNW list from 3 peers max +* Use correct protocol when serializing messages in reply to +* Bump Versioning +* Update dynamic_qt.m4 (Remove ability to build with Qt4) **Dynamic v2.3.0.0** From 2eff4f89782370cb109ec683eb20f46dcd2a5924 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 23 Jul 2018 14:02:40 +0200 Subject: [PATCH 0068/1653] Remove unused serialization method --- src/hdchain.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hdchain.h b/src/hdchain.h index bba7227892..adc5762586 100644 --- a/src/hdchain.h +++ b/src/hdchain.h @@ -141,7 +141,6 @@ class CHDPubKey inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); - nVersion = this->nVersion; READWRITE(extPubKey); READWRITE(hdchainID); READWRITE(nAccountIndex); From 71e5e25ece8610479549e3979ddd49730b772f2d Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Mon, 23 Jul 2018 14:06:55 +0200 Subject: [PATCH 0069/1653] include stdint --- src/timedata.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/timedata.h b/src/timedata.h index d524bb036a..f7cdf333db 100644 --- a/src/timedata.h +++ b/src/timedata.h @@ -8,6 +8,8 @@ #ifndef DYNAMIC_TIMEDATA_H #define DYNAMIC_TIMEDATA_H +#include + #include #include #include From 15b2d00963ced929f1e57168de2732cbcc886ed3 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 00:56:35 +0200 Subject: [PATCH 0070/1653] [depends] upgrade boost to 1.67.0 --- depends/packages/boost.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 423a3ce01b..c6d2145fb0 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_65_1_rc2 -$(package)_download_path=https://dl.bintray.com/boostorg/release/1.65.1/source/ +$(package)_version=1_67_0 +$(package)_download_path=https://dl.bintray.com/boostorg/release/1.67.0/source/ $(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=9807a5d16566c57fd74fb522764e0b134a8bbe6b6e8967b83afefd30dcd3be81 +$(package)_sha256_hash=2684c972994ee57fc5632e03bf044746f6eb45d4920c343937a465fd67a5adba define $(package)_set_vars $(package)_config_opts_release=variant=release From 2560dbe28c7c4d1845ff14f8014dbf7680f5a465 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 00:57:49 +0200 Subject: [PATCH 0071/1653] [depends] upgrade dbus to 1.13.4 --- depends/packages/dbus.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/dbus.mk b/depends/packages/dbus.mk index ecac8a2cbd..7fa626f2f9 100644 --- a/depends/packages/dbus.mk +++ b/depends/packages/dbus.mk @@ -1,8 +1,8 @@ package=dbus -$(package)_version=1.12.2 +$(package)_version=1.13.4 $(package)_download_path=http://dbus.freedesktop.org/releases/dbus $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=272bb5091770b047c8188b926d5e6038fa4fe6745488b2add96b23e2d9a83d88 +$(package)_sha256_hash=8a8f0b986ac6214da9707da521bea9f49f09610083c71fdc8eddf8b4c54f384b $(package)_dependencies=expat define $(package)_set_vars From e826758ff9e271e5fe2da1ca5f31bebe43d1560b Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 00:58:35 +0200 Subject: [PATCH 0072/1653] [depends] update expad download path --- depends/packages/expat.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk index c041fd6c4d..acbc60eea3 100644 --- a/depends/packages/expat.mk +++ b/depends/packages/expat.mk @@ -1,6 +1,6 @@ package=expat $(package)_version=2.2.5 -$(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version) +$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_2_5/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=d9dc32efba7e74f788fcc4f212a43216fc37cf5f23f4c2339664d473353aedf6 From 866240f0765f8effc5a4ac828639e56ae0e526fc Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 00:59:20 +0200 Subject: [PATCH 0073/1653] [depends] upgrade freetype to 2.9.1 --- depends/packages/freetype.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk index e53ac25e96..7051266d2e 100644 --- a/depends/packages/freetype.mk +++ b/depends/packages/freetype.mk @@ -1,8 +1,8 @@ package=freetype -$(package)_version=2.8.1 +$(package)_version=2.9.1 $(package)_download_path=http://download.savannah.gnu.org/releases/$(package) $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=e5435f02e02d2b87bb8e4efdcaa14b1f78c9cf3ab1ed80f94b6382fb6acc7d78 +$(package)_sha256_hash=aa2f835ef8f50072630ddc48b9eb65f1f456014ffa3b5adddcb6bf390a3c5828 define $(package)_set_vars $(package)_config_opts=--without-zlib --without-png --disable-static From bb7fc77e0e8de71a007310b74f168942671560aa Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:00:11 +0200 Subject: [PATCH 0074/1653] [depends] update libevent download path --- depends/packages/libevent.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index f6d17a7924..5f622f8e6e 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -1,7 +1,7 @@ package=libevent -$(package)_version=2.1.8 +$(package)_version=2.1.8-stable $(package)_download_path=https://github.com/libevent/libevent/archive/ -$(package)_file_name=release-$($(package)_version)-stable.tar.gz +$(package)_file_name=release-$($(package)_version).tar.gz $(package)_sha256_hash=316ddb401745ac5d222d7c529ef1eada12f58f6376a66c1118eee803cb70f83d define $(package)_preprocess_cmds @@ -9,7 +9,7 @@ define $(package)_preprocess_cmds endef define $(package)_set_vars - $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress + $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples $(package)_config_opts_release=--disable-debug-mode $(package)_config_opts_linux=--with-pic endef From 324adab05e94b4dc057665447687cb346fbeeefc Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:00:56 +0200 Subject: [PATCH 0075/1653] [depends] upgrade libxcb to 1.13 --- depends/packages/libxcb.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk index e0f205b990..18982b68f9 100644 --- a/depends/packages/libxcb.mk +++ b/depends/packages/libxcb.mk @@ -1,8 +1,8 @@ package=libxcb -$(package)_version=1.12 +$(package)_version=1.13 $(package)_download_path=http://xcb.freedesktop.org/dist $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=4adfb1b7c67e99bc9c2ccb110b2f175686576d2f792c8a71b9c8b19014057b5b +$(package)_sha256_hash=188c8752193c50ff2dbe89db4554c63df2e26a2e47b0fa415a70918b5b851daa $(package)_dependencies=xcb_proto libXau xproto define $(package)_set_vars From b58e8d0000a88afe463ec5272f825d52cc91beeb Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:02:13 +0200 Subject: [PATCH 0076/1653] [depends] upgrade miniupnpc to 2.1 --- depends/packages/miniupnpc.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index fc4461f3e2..8257c63f39 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,12 +1,12 @@ package=miniupnpc -$(package)_version=2.0.20171102 +$(package)_version=2.1 $(package)_download_path=http://miniupnp.free.fr/files $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=148517020581260c8a2fa532224870bc53e59004777affcaf27ef636a72825d4 +$(package)_sha256_hash=e19fb5e01ea5a707e2a8cb96f537fbd9f3a913d53d804a3265e3aeab3d2064c6 define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" -$(package)_build_opts_darwin=OS=Darwin LIBTOOL="$($(package)_libtool)" +$(package)_build_opts_darwin=LIBTOOL="$($(package)_libtool)" $(package)_build_opts_mingw32=-f Makefile.mingw $(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)" endef From 9147c0f94fb19c68cf97d538670541f195a446ef Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:03:14 +0200 Subject: [PATCH 0077/1653] [depends] upgrade native_biplist to 1.0.3 --- depends/packages/native_biplist.mk | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk index 3c6e8900f6..5f247e9bf3 100644 --- a/depends/packages/native_biplist.mk +++ b/depends/packages/native_biplist.mk @@ -1,14 +1,9 @@ package=native_biplist -$(package)_version=0.9 -$(package)_download_path=https://pypi.python.org/packages/source/b/biplist +$(package)_version=1.0.3 +$(package)_download_path=https://bitbucket.org/wooster/biplist/downloads $(package)_file_name=biplist-$($(package)_version).tar.gz -$(package)_sha256_hash=b57cadfd26e4754efdf89e9e37de87885f9b5c847b2615688ca04adfaf6ca604 +$(package)_sha256_hash=4c0549764c5fe50b28042ec21aa2e14fe1a2224e239a1dae77d9e7f3932aa4c6 $(package)_install_libdir=$(build_prefix)/lib/python/dist-packages -$(package)_patches=sorted_list.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/sorted_list.patch -endef define $(package)_build_cmds python setup.py build From 316f2ebbcfa740723a7853a132af52cabe8611ff Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:04:20 +0200 Subject: [PATCH 0078/1653] [depends] upgrade native_ccache to 3.4.2 --- depends/packages/native_ccache.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk index 966804ce8b..3be669dc47 100644 --- a/depends/packages/native_ccache.mk +++ b/depends/packages/native_ccache.mk @@ -1,8 +1,8 @@ package=native_ccache -$(package)_version=3.3.4 +$(package)_version=3.4.2 $(package)_download_path=https://samba.org/ftp/ccache $(package)_file_name=ccache-$($(package)_version).tar.bz2 -$(package)_sha256_hash=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567 +$(package)_sha256_hash=3aa5587793d4c790bd22999bfc678250c029307b3afb9d16f6f4a49c67b78fb3 define $(package)_set_vars $(package)_config_opts= From caa61a9e1e7a0e962c8d9252bc9587ead4fba134 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:05:38 +0200 Subject: [PATCH 0079/1653] [depends] update native_ds_store download path --- depends/packages/native_ds_store.mk | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk index c25b836972..116fa25d38 100644 --- a/depends/packages/native_ds_store.mk +++ b/depends/packages/native_ds_store.mk @@ -1,8 +1,7 @@ package=native_ds_store $(package)_version=1.1.2 -$(package)_download_path=https://github.com/al45tair/ds_store/archive -$(package)_download_file=v$($(package)_version).tar.gz -$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_download_path=https://github.com/al45tair/ds_store/archive/ +$(package)_file_name=v$($(package)_version).tar.gz $(package)_sha256_hash=3b3ecb7bf0a5157f5b6010bc3af7c141fb0ad3527084e63336220d22744bc20c $(package)_install_libdir=$(build_prefix)/lib/python/dist-packages $(package)_dependencies=native_biplist From e637bccb008cb48d519adca7f6ee605e1aa5a417 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:07:07 +0200 Subject: [PATCH 0080/1653] [depends] upgrade native_mac_alias to 2.0.7 --- depends/packages/native_mac_alias.mk | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk index 665c13cff3..306c835656 100644 --- a/depends/packages/native_mac_alias.mk +++ b/depends/packages/native_mac_alias.mk @@ -1,15 +1,9 @@ package=native_mac_alias -$(package)_version=2.0.1 -$(package)_download_path=https://bitbucket.org/al45tair/mac_alias/get -$(package)_download_file=v$($(package)_version).tar.bz2 -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=7285739414d8d6bc36b0b1a00c8ec8d6757e92971e8142cda51e4c3a5d76b413 +$(package)_version=2.0.7 +$(package)_download_path=https://github.com/al45tair/mac_alias/archive/ +$(package)_file_name=v$($(package)_version).tar.gz +$(package)_sha256_hash=6f606d3b6bccd2112aeabf1a063f5b5ece87005a5d7e97c8faca23b916e88838 $(package)_install_libdir=$(build_prefix)/lib/python/dist-packages -$(package)_patches=python3.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/python3.patch -endef define $(package)_build_cmds python setup.py build From 964b8b877797e8d40edde470df691fa58efd7614 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:08:49 +0200 Subject: [PATCH 0081/1653] [depends] upgrade native_protobuf to 3.6.0 --- depends/packages/native_protobuf.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/native_protobuf.mk b/depends/packages/native_protobuf.mk index c8f7da5745..1beecdfd66 100644 --- a/depends/packages/native_protobuf.mk +++ b/depends/packages/native_protobuf.mk @@ -1,8 +1,8 @@ package=native_protobuf -$(package)_version=3.5.0 +$(package)_version=3.6.0 $(package)_download_path=https://github.com/google/protobuf/releases/download/v$($(package)_version) $(package)_file_name=protobuf-all-$($(package)_version).tar.gz -$(package)_sha256_hash=5c3e0b369e767993969fdebcb3f44cbddd7fdd86644a926780daab46341d10a7 +$(package)_sha256_hash=1532154addf85080330fdd037949d4653dfce16550df5c70ea0cd212d8aff3af define $(package)_set_vars $(package)_config_opts=--disable-shared From 8ef258c3b2f4f69f18525a2eb90fcd8d7e5e7e63 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:11:14 +0200 Subject: [PATCH 0082/1653] [depends] update openssl to 1.0.1k - Add RISC-V support --- depends/packages/openssl.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 5ee9f17a63..db47113b2f 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -47,10 +47,13 @@ $(package)_config_opts_linux=-fPIC -Wa,--noexecstack $(package)_config_opts_x86_64_linux=linux-x86_64 $(package)_config_opts_i686_linux=linux-generic32 $(package)_config_opts_arm_linux=linux-generic32 +$(package)_config_opts_armv7l_linux=linux-generic32 $(package)_config_opts_aarch64_linux=linux-generic64 $(package)_config_opts_mipsel_linux=linux-generic32 $(package)_config_opts_mips_linux=linux-generic32 $(package)_config_opts_powerpc_linux=linux-generic32 +$(package)_config_opts_riscv32_linux=linux-generic32 +$(package)_config_opts_riscv64_linux=linux-generic64 $(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc $(package)_config_opts_x86_64_mingw32=mingw64 $(package)_config_opts_i686_mingw32=mingw From f49cf6b82e405f4133885c517da4b8a69b01d025 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:12:55 +0200 Subject: [PATCH 0083/1653] [depends] upgrade qt to 5.9.6 --- depends/packages/qt.mk | 55 ++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index f0f930616f..22cf4f515b 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,21 +1,20 @@ PACKAGE=qt -$(package)_version=5.7.1 -$(package)_download_path=http://download.qt.io/official_releases/qt/5.7/$($(package)_version)/submodules -$(package)_suffix=opensource-src-$($(package)_version).tar.gz +$(package)_version=5.9.6 +$(package)_download_path=https://download.qt.io/official_releases/qt/5.9/$($(package)_version)/submodules +$(package)_suffix=opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410 +$(package)_sha256_hash=eed620cb268b199bd83b3fc6a471c51d51e1dc2dbb5374fc97a0cc75facbe36f $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib -$(package)_patches=mac-qmake.conf mingw-uuidof.patch pidlist_absolute.patch fix-xcb-include-order.patch fix_qt_pkgconfig.patch +$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=3a15aebd523c6d89fb97b2d3df866c94149653a26d27a00aac9b6d3020bc5a1d - +$(package)_qttranslations_sha256_hash=9822084f8e2d2939ba39f4af4c0c2320e45d5996762a9423f833055607604ed8 $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=22d67de915cb8cd93e16fdd38fa006224ad9170bd217c2be1e53045a8dd02f0f +$(package)_qttools_sha256_hash=50e75417ec0c74bb8b1989d1d8e981ee83690dce7dfc0c2169f7c00f397e5117 $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) @@ -28,25 +27,18 @@ $(package)_config_opts += -c++std c++11 $(package)_config_opts += -confirm-license $(package)_config_opts += -dbus-runtime $(package)_config_opts += -hostprefix $(build_prefix) -$(package)_config_opts += -no-alsa -$(package)_config_opts += -no-audio-backend $(package)_config_opts += -no-cups $(package)_config_opts += -no-egl $(package)_config_opts += -no-eglfs -$(package)_config_opts += -no-feature-style-windowsmobile -$(package)_config_opts += -no-feature-style-windowsce $(package)_config_opts += -no-freetype $(package)_config_opts += -no-gif $(package)_config_opts += -no-glib -$(package)_config_opts += -no-gstreamer $(package)_config_opts += -no-icu $(package)_config_opts += -no-iconv $(package)_config_opts += -no-kms $(package)_config_opts += -no-linuxfb $(package)_config_opts += -no-libudev -$(package)_config_opts += -no-mitshm $(package)_config_opts += -no-mtdev -$(package)_config_opts += -no-pulseaudio $(package)_config_opts += -no-openvg $(package)_config_opts += -no-reduce-relocations $(package)_config_opts += -no-qml-debug @@ -61,7 +53,6 @@ $(package)_config_opts += -no-sql-sqlite $(package)_config_opts += -no-sql-sqlite2 $(package)_config_opts += -no-use-gold-linker $(package)_config_opts += -no-xinput2 -$(package)_config_opts += -no-xrender $(package)_config_opts += -nomake examples $(package)_config_opts += -nomake tests $(package)_config_opts += -opensource @@ -74,12 +65,13 @@ $(package)_config_opts += -qt-libpng $(package)_config_opts += -qt-libjpeg $(package)_config_opts += -qt-pcre $(package)_config_opts += -system-zlib -$(package)_config_opts += -reduce-exports $(package)_config_opts += -static $(package)_config_opts += -silent $(package)_config_opts += -v $(package)_config_opts += -no-feature-printer $(package)_config_opts += -no-feature-printdialog +$(package)_config_opts += -no-feature-concurrent +$(package)_config_opts += -no-feature-xml ifneq ($(build_os),darwin) $(package)_config_opts_darwin = -xplatform macx-clang-linux @@ -94,11 +86,12 @@ endif $(package)_config_opts_linux = -qt-xkbcommon $(package)_config_opts_linux += -qt-xcb $(package)_config_opts_linux += -system-freetype -$(package)_config_opts_linux += -no-sm +$(package)_config_opts_linux += -no-feature-sessionmanager $(package)_config_opts_linux += -fontconfig $(package)_config_opts_linux += -no-opengl -$(package)_config_opts_arm_linux = -platform linux-g++ -xplatform $(host) +$(package)_config_opts_arm_linux += -platform linux-g++ -xplatform bitcoin-linux-g++ $(package)_config_opts_i686_linux = -xplatform linux-g++-32 +$(package)_config_opts_x86_64_linux = -xplatform linux-g++-64 $(package)_config_opts_mingw32 = -no-opengl -xplatform win32-g++ -device-option CROSS_COMPILE="$(host)-" $(package)_build_env = QT_RCC_TEST=1 endef @@ -123,11 +116,10 @@ define $(package)_extract_cmds tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools endef - define $(package)_preprocess_cmds sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \ - sed -i.old "s/src_plugins.depends = src_sql src_xml src_network/src_plugins.depends = src_xml src_network/" qtbase/src/src.pro && \ + sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \ sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \ sed -i.old 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' qtbase/configure && \ sed -i.old 's/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0)/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft)/' qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm && \ @@ -136,17 +128,19 @@ define $(package)_preprocess_cmds cp -f qtbase/mkspecs/macx-clang/Info.plist.app qtbase/mkspecs/macx-clang-linux/ &&\ cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ - patch -p1 < $($(package)_patch_dir)/mingw-uuidof.patch && \ - patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \ - patch -p1 < $($(package)_patch_dir)/fix-xcb-include-order.patch && \ - patch -p1 < $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ + cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/bitcoin-linux-g++ && \ + sed -i s/arm-linux-gnueabi-/$(host)-/g qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch &&\ + patch -p1 -i $($(package)_patch_dir)/fix_configure_mac.patch &&\ + patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch &&\ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ + echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ sed -i.old "s|QMAKE_CFLAGS = |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ sed -i.old "s|QMAKE_LFLAGS = |!host_build: QMAKE_LFLAGS = $($(package)_ldflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ sed -i.old "s|QMAKE_CXXFLAGS = |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf - endef define $(package)_config_cmds @@ -158,19 +152,22 @@ define $(package)_config_cmds echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \ $(MAKE) sub-src-clean && \ cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \ - cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. &&\ - cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile + cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. && \ + cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile && \ + cd ../lupdate/ && ../../../../qtbase/bin/qmake lupdate.pro -o Makefile && cd ../../../.. endef define $(package)_build_cmds $(MAKE) -C src $(addprefix sub-,$($(package)_qt_libs)) && \ $(MAKE) -C ../qttools/src/linguist/lrelease && \ + $(MAKE) -C ../qttools/src/linguist/lupdate && \ $(MAKE) -C ../qttranslations endef define $(package)_stage_cmds - $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. &&\ + $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. && \ $(MAKE) -C qttools/src/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install_target && \ + $(MAKE) -C qttools/src/linguist/lupdate INSTALL_ROOT=$($(package)_staging_dir) install_target && \ $(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets && \ if `test -f qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a`; then \ cp qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a $($(package)_staging_prefix_dir)/lib; \ From 76279ca20c8520ea1c5d71f1afc5e110d659e27e Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 01:15:39 +0200 Subject: [PATCH 0084/1653] [depends] upgrade qrencode --- depends/packages/qrencode.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk index 377febe28a..9166872946 100644 --- a/depends/packages/qrencode.mk +++ b/depends/packages/qrencode.mk @@ -1,8 +1,8 @@ package=qrencode -$(package)_version=4.0.0 +$(package)_version=4.0.2 $(package)_download_path=https://fukuchi.org/works/qrencode/ $(package)_file_name=qrencode-$(qrencode_version).tar.bz2 -$(package)_sha256_hash=c90035e16921117d4086a7fdee65aab85be32beb4a376f6b664b8a425d327d0b +$(package)_sha256_hash=c9cb278d3b28dcc36b8d09e8cad51c0eca754eb004cb0247d4703cb4472b58b4 define $(package)_set_vars $(package)_config_opts=--disable-shared -without-tools --disable-sdltest From 95ea31926af205313b13785f936b92f22598e28d Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 09:41:48 +0200 Subject: [PATCH 0085/1653] [depends] upgrade xcb_proto to 1.13 --- depends/packages/xcb_proto.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk index 55c6e08462..1eb19a04f7 100644 --- a/depends/packages/xcb_proto.mk +++ b/depends/packages/xcb_proto.mk @@ -1,8 +1,8 @@ package=xcb_proto -$(package)_version=1.12 +$(package)_version=1.13 $(package)_download_path=http://xcb.freedesktop.org/dist $(package)_file_name=xcb-proto-$($(package)_version).tar.bz2 -$(package)_sha256_hash=5922aba4c664ab7899a29d92ea91a87aa4c1fc7eb5ee550325c3216c480a4906 +$(package)_sha256_hash=7b98721e669be80284e9bbfeab02d2d0d54cd11172b72271e47a2fe875e2bde1 define $(package)_set_vars $(package)_config_opts=--disable-shared From b15e2b37d29d65991c4b777f16b93ee0554adc1b Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 09:43:08 +0200 Subject: [PATCH 0086/1653] [depends] upgrade xtrans to 1.3.5 --- depends/packages/xtrans.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/xtrans.mk b/depends/packages/xtrans.mk index 99eefa6d5e..4d949a00e7 100644 --- a/depends/packages/xtrans.mk +++ b/depends/packages/xtrans.mk @@ -1,8 +1,8 @@ package=xtrans -$(package)_version=1.3.4 +$(package)_version=1.3.5 $(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=054d4ee3efd52508c753e9f7bc655ef185a29bd2850dd9e2fc2ccc33544f583a +$(package)_sha256_hash=adbd3b36932ce4c062cd10f57d78a156ba98d618bdb6f50664da327502bc8301 $(package)_dependencies= define $(package)_set_vars From b8506eee86be67fc0e56003b97a671cf4eed3b91 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 09:44:51 +0200 Subject: [PATCH 0087/1653] [depends] upgrade zeromq to 4.2.5 --- depends/packages/zeromq.mk | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 01146c26f6..c9068e83a5 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,20 +1,20 @@ package=zeromq -$(package)_version=4.1.5 -$(package)_download_path=https://github.com/zeromq/zeromq4-1/releases/download/v$($(package)_version)/ +$(package)_version=4.2.5 +$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=04aac57f081ffa3a2ee5ed04887be9e205df3a7ddade0027460b8042432bdbcf -$(package)_patches=9114d3957725acd34aa8b8d011585812f3369411.patch 9e6745c12e0b100cd38acecc16ce7db02905e27c.patch +$(package)_sha256_hash=cc9090ba35713d59bb2f7d7965f877036c49c5558ea0c290b0dcc6f2a17e489f +$(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch define $(package)_set_vars - $(package)_config_opts=--without-documentation --disable-shared --without-libsodium --disable-curve + $(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf --disable-Werror $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 endef define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/9114d3957725acd34aa8b8d011585812f3369411.patch && \ - patch -p1 < $($(package)_patch_dir)/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch && \ - ./autogen.sh + patch -p1 < $($(package)_patch_dir)/0001-fix-build-with-older-mingw64.patch && \ + patch -p1 < $($(package)_patch_dir)/0002-disable-pthread_set_name_np.patch && \ + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config endef define $(package)_config_cmds @@ -22,7 +22,7 @@ define $(package)_config_cmds endef define $(package)_build_cmds - $(MAKE) libzmq.la + $(MAKE) src/libzmq.la endef define $(package)_stage_cmds @@ -30,5 +30,6 @@ define $(package)_stage_cmds endef define $(package)_postprocess_cmds + sed -i.old "s/ -lstdc++//" lib/pkgconfig/libzmq.pc && \ rm -rf bin share endef From 219cc46aed7d9a392511e5de05e7bc9700dfbb63 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 09:48:46 +0200 Subject: [PATCH 0088/1653] [depends] add fix_configure_mac.patch file --- depends/patches/qt/fix_configure_mac.patch | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 depends/patches/qt/fix_configure_mac.patch diff --git a/depends/patches/qt/fix_configure_mac.patch b/depends/patches/qt/fix_configure_mac.patch new file mode 100644 index 0000000000..0d7dd647de --- /dev/null +++ b/depends/patches/qt/fix_configure_mac.patch @@ -0,0 +1,50 @@ +--- old/qtbase/mkspecs/features/mac/sdk.prf 2018-02-08 10:24:48.000000000 -0800 ++++ new/qtbase/mkspecs/features/mac/sdk.prf 2018-03-23 10:38:56.000000000 -0700 +@@ -8,21 +8,21 @@ + defineReplace(xcodeSDKInfo) { + info = $$1 + equals(info, "Path"): \ +- info = --show-sdk-path ++ infoarg = --show-sdk-path + equals(info, "PlatformPath"): \ +- info = --show-sdk-platform-path ++ infoarg = --show-sdk-platform-path + equals(info, "SDKVersion"): \ +- info = --show-sdk-version ++ infoarg = --show-sdk-version + sdk = $$2 + isEmpty(sdk): \ + sdk = $$QMAKE_MAC_SDK + + isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}) { +- QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$info 2>/dev/null") ++ QMAKE_MAC_SDK.$${sdk}.$${info} = $$system("/usr/bin/xcrun --sdk $$sdk $$infoarg 2>/dev/null") + # --show-sdk-platform-path won't work for Command Line Tools; this is fine + # only used by the XCTest backend to testlib +- isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(info, "--show-sdk-platform-path")): \ +- error("Could not resolve SDK $$info for \'$$sdk\'") ++ isEmpty(QMAKE_MAC_SDK.$${sdk}.$${info}):if(!isEmpty(QMAKE_XCODEBUILD_PATH)|!equals(infoarg, "--show-sdk-platform-path")): \ ++ error("Could not resolve SDK $$info for \'$$sdk\' using $$infoarg") + cache(QMAKE_MAC_SDK.$${sdk}.$${info}, set stash, QMAKE_MAC_SDK.$${sdk}.$${info}) + } + +--- old/qtbase/configure 2018-02-08 10:24:48.000000000 -0800 ++++ new/qtbase/configure 2018-03-23 05:42:29.000000000 -0700 +@@ -232,8 +232,13 @@ + + sdk=$(getSingleQMakeVariable "QMAKE_MAC_SDK" "$1") + if [ -z "$sdk" ]; then echo "QMAKE_MAC_SDK must be set when building on Mac" >&2; exit 1; fi +- sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null) +- if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi ++ sysroot=$(getSingleQMakeVariable "QMAKE_MAC_SDK_PATH" "$1") ++ ++ echo "sysroot pre-configured as $sysroot"; ++ if [ -z "$sysroot" ]; then ++ sysroot=$(/usr/bin/xcrun --sdk $sdk --show-sdk-path 2>/dev/null) ++ if [ -z "$sysroot" ]; then echo "Failed to resolve SDK path for '$sdk'" >&2; exit 1; fi ++ fi + + case "$sdk" in + macosx*) + + From 46c31fddf0611c2781be78b30e8f6daa1333ea83 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 09:49:54 +0200 Subject: [PATCH 0089/1653] [depends] add fix_no_printer.patch file --- depends/patches/qt/fix_no_printer.patch | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 depends/patches/qt/fix_no_printer.patch diff --git a/depends/patches/qt/fix_no_printer.patch b/depends/patches/qt/fix_no_printer.patch new file mode 100644 index 0000000000..f868ca2577 --- /dev/null +++ b/depends/patches/qt/fix_no_printer.patch @@ -0,0 +1,19 @@ +--- x/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h ++++ y/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h +@@ -52,6 +52,7 @@ + // + + #include ++#include + + #ifndef QT_NO_PRINTER + +--- x/qtbase/src/plugins/plugins.pro ++++ y/qtbase/src/plugins/plugins.pro +@@ -8,6 +8,3 @@ qtHaveModule(gui) { + qtConfig(imageformatplugin): SUBDIRS *= imageformats + !android:qtConfig(library): SUBDIRS *= generic + } +- +-!winrt:qtHaveModule(printsupport): \ +- SUBDIRS += printsupport From 4fb9b153129562723e62bf86e7dedca12cd83335 Mon Sep 17 00:00:00 2001 From: Sven <24934984+coin-info-net@users.noreply.github.com> Date: Tue, 24 Jul 2018 09:51:11 +0200 Subject: [PATCH 0090/1653] [depends] update mac-qmake.conf patch file --- depends/patches/qt/mac-qmake.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/depends/patches/qt/mac-qmake.conf b/depends/patches/qt/mac-qmake.conf index ca70d30b15..337d0eb9ca 100644 --- a/depends/patches/qt/mac-qmake.conf +++ b/depends/patches/qt/mac-qmake.conf @@ -14,6 +14,7 @@ QMAKE_MAC_SDK.macosx.Path = $${MAC_SDK_PATH} QMAKE_MAC_SDK.macosx.platform_name = macosx QMAKE_MAC_SDK.macosx.SDKVersion = $${MAC_SDK_VERSION} QMAKE_MAC_SDK.macosx.PlatformPath = /phony +QMAKE_APPLE_DEVICE_ARCHS=x86_64 !host_build: QMAKE_CFLAGS += -target $${MAC_TARGET} !host_build: QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS !host_build: QMAKE_CXXFLAGS += $$QMAKE_CFLAGS From 866005302a07229dab7bbc16ef7b5a18ad433203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Wed, 25 Jul 2018 17:41:50 +0200 Subject: [PATCH 0091/1653] [GPU] Split CUDA and OpenCL libraries --- src/Makefile.gpu.include | 51 +++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index 3596675767..70693ebe69 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -4,7 +4,6 @@ LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a LIBDYNAMIC_GPU_LDADD = $(LIBDYNAMIC_GPU) - EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) @@ -16,12 +15,22 @@ crypto_argon2gpu_libdynamic_gpu_a_SOURCES = \ crypto/argon2gpu/blake2b.cpp if ENABLE_CUDA -NVCCFLAGS += --cudart shared --ptxas-options=-v -arch sm_30 -lineinfo -Xcompiler '--std=c++11 $(CFLAGS)' +LIBDYNAMIC_GPU_CUDA = crypto/argon2gpu/cuda/libdynamic_gpu_cuda.a +EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_CUDA) + +LIBDYNAMIC_GPU_LDADD += $(LIBDYNAMIC_GPU_CUDA) +LIBDYNAMIC_GPU_LDADD += $(CUDA_LDLIBS) +DYNAMIC_INCLUDES += $(CUDA_CFLAGS) -crypto_argon2gpu_libdynamic_gpu_a_AR = $(NVCC) $(NVCCFLAGS) -lib -o -crypto_argon2gpu_libdynamic_gpu_a_LIBADD = $(CUDA_LDLIBS) -crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS += $(CUDA_CFLAGS) -crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ +NVCCFLAGS += -arch=sm_30 -w -lineinfo -Xcompiler='--std=c++11 $(CFLAGS)' + +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_AR = $(NVCC) $(NVCCFLAGS) -lib -o +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_LIBADD = $(CUDA_LDLIBS) +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_CPPFLAGS = $(DYNAMIC_INCLUDES) +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_LIBADD += \ + crypto/argon2gpu/cuda/kernels.cu.o +crypto_argon2gpu_cuda_libdynamic_gpu_cuda_a_SOURCES = \ crypto/argon2gpu/cuda/cuda-exception.h \ crypto/argon2gpu/cuda/device.h \ crypto/argon2gpu/cuda/global-context.h \ @@ -34,27 +43,32 @@ crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ crypto/argon2gpu/cuda/processing-unit.cpp \ crypto/argon2gpu/cuda/program-context.cpp -DYNAMIC_INCLUDES += $(CUDA_CFLAGS) -LIBDYNAMIC_GPU_LDADD += $(CUDA_LDLIBS) - -nvcc_ARCH := -gencode=arch=compute_30,code=\"sm_30,compute_30\" -nvcc_FLAGS = $(nvcc_ARCH) -I. $(CUDA_CFLAGS) $(NVCCFLAGS) +nvcc_FLAGS = -I. $(CUDA_CFLAGS) $(NVCCFLAGS) .cu.o: - $(NVCC) $(nvcc_FLAGS) -o $@ -c $< + $(NVCC) $(nvcc_FLAGS) -dc -o $@ -c $< + +crypto/argon2gpu/cuda/kernels.cu.o: crypto/argon2gpu/cuda/kernels.cu + $(NVCC) $(nvcc_FLAGS) -dc -o $@ -c $< -crypto/argon2gpu/cuda/kernels.o: crypto/argon2gpu/cuda/kernels.cu - $(NVCC) -dlink $(nvcc_FLAGS) -o $@ -c $< +crypto/argon2gpu/cuda/kernels.o: crypto/argon2gpu/cuda/kernels.cu.o + $(NVCC) $(nvcc_FLAGS) -dlink -o $@ $< else +LIBDYNAMIC_GPU_OPENCL = crypto/argon2gpu/opencl/libdynamic_gpu_opencl.a +EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_OPENCL) + +LIBOPENCL = -lOpenCL if TARGET_DARWIN LIBOPENCL = "-framework OpenCL" -else - LIBOPENCL = -lOpenCL endif -crypto_argon2gpu_libdynamic_gpu_a_LIBADD = $(LIBOPENCL) -crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ +LIBDYNAMIC_GPU_LDADD += $(LIBDYNAMIC_GPU_OPENCL) +LIBDYNAMIC_GPU_LDADD += $(LIBOPENCL) + +crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) +crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_SOURCES = \ crypto/argon2gpu/opencl/cl.hpp \ crypto/argon2gpu/opencl/device.h \ crypto/argon2gpu/opencl/global-context.h \ @@ -70,7 +84,6 @@ crypto_argon2gpu_libdynamic_gpu_a_SOURCES += \ crypto/argon2gpu/opencl/processing-unit.cpp \ crypto/argon2gpu/opencl/program-context.cpp -LIBDYNAMIC_GPU_LDADD += $(LIBOPENCL) endif dynamicd_LDADD += $(LIBDYNAMIC_GPU_LDADD) From c2365e707f638ff7fdfd443a8155456f2a3f47a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Wed, 25 Jul 2018 21:31:53 +0200 Subject: [PATCH 0092/1653] [GPU] Remove autoconf indent --- src/Makefile.gpu.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index 70693ebe69..dd165d128b 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -60,7 +60,7 @@ EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_OPENCL) LIBOPENCL = -lOpenCL if TARGET_DARWIN - LIBOPENCL = "-framework OpenCL" +LIBOPENCL = "-framework OpenCL" endif LIBDYNAMIC_GPU_LDADD += $(LIBDYNAMIC_GPU_OPENCL) From 7c727b8a10f5a56cb14e08806284e0a2ee422d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Wed, 25 Jul 2018 22:36:23 +0200 Subject: [PATCH 0093/1653] [GPU] Apple OpenCL linker flags --- src/Makefile.am | 2 +- src/Makefile.gpu.include | 12 ++++++++---- src/Makefile.qt.include | 1 + src/Makefile.qttest.include | 1 + src/Makefile.test.include | 1 + 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 6f0f4e7a5a..4792610432 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -411,7 +411,7 @@ nodist_libdynamic_util_a_SOURCES = $(srcdir)/obj/build.h dynamicd_SOURCES = dynamicd.cpp dynamicd_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) dynamicd_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -dynamicd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -Wl,-rpath=/usr/local/cuda-9.2/lib64 +dynamicd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS dynamicd_SOURCES += dynamicd-res.rc diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index dd165d128b..cd6bd4fe39 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -4,6 +4,7 @@ LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a LIBDYNAMIC_GPU_LDADD = $(LIBDYNAMIC_GPU) +LIBDYNAMIC_GPU_LDFLAGS = EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) @@ -58,13 +59,15 @@ else LIBDYNAMIC_GPU_OPENCL = crypto/argon2gpu/opencl/libdynamic_gpu_opencl.a EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_OPENCL) -LIBOPENCL = -lOpenCL +LIBDYNAMIC_GPU_LDADD += $(LIBDYNAMIC_GPU_OPENCL) + if TARGET_DARWIN LIBOPENCL = "-framework OpenCL" -endif - -LIBDYNAMIC_GPU_LDADD += $(LIBDYNAMIC_GPU_OPENCL) +LIBDYNAMIC_GPU_LDFLAGS += $(LIBOPENCL) +else +LIBOPENCL = -lOpenCL LIBDYNAMIC_GPU_LDADD += $(LIBOPENCL) +endif crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) @@ -87,3 +90,4 @@ crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_SOURCES = \ endif dynamicd_LDADD += $(LIBDYNAMIC_GPU_LDADD) +dynamicd_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 31b174f675..3b6f3403c3 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -371,6 +371,7 @@ qt_dynamic_qt_LDADD += $(LIBDYNAMIC_WALLET) endif if ENABLE_GPU qt_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD) +qt_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) endif if ENABLE_ZMQ qt_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index a6a4cab4b6..57badeb368 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -45,6 +45,7 @@ qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif if ENABLE_GPU qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD) +qt_test_test_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) endif qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index d591076592..c190870b1c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -123,6 +123,7 @@ test_test_dynamic_LDADD += $(ZMQ_LIBS) endif if ENABLE_GPU test_test_dynamic_LDADD += $(LIBDYNAMIC_GPU_LDADD) +test_test_dynamic_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) endif nodist_test_test_dynamic_SOURCES = $(GENERATED_TEST_FILES) From 55f37668c7af62d42c40b1c46022c4b61392da12 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Thu, 26 Jul 2018 00:16:38 +0200 Subject: [PATCH 0094/1653] Makefile shuffle --- src/Makefile.gpu.include | 4 ++-- src/Makefile.qt.include | 4 ++-- src/Makefile.qttest.include | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index cd6bd4fe39..521ed314b8 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -4,7 +4,6 @@ LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a LIBDYNAMIC_GPU_LDADD = $(LIBDYNAMIC_GPU) -LIBDYNAMIC_GPU_LDFLAGS = EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) @@ -62,8 +61,9 @@ EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_OPENCL) LIBDYNAMIC_GPU_LDADD += $(LIBDYNAMIC_GPU_OPENCL) if TARGET_DARWIN +LIBDYNAMIC_GPU_LDFLAGS = $(LIBOPENCL) +LIBDYNAMIC_GPU_LDFLAGS += -stdlib=libc++ LIBOPENCL = "-framework OpenCL" -LIBDYNAMIC_GPU_LDFLAGS += $(LIBOPENCL) else LIBOPENCL = -lOpenCL LIBDYNAMIC_GPU_LDADD += $(LIBOPENCL) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 3b6f3403c3..f1bb8a8563 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -237,7 +237,7 @@ RES_ICONS = \ qt/res/icons/drk/unit_satoshis.png \ qt/res/icons/drk/unit_udyn.png \ qt/res/icons/drk/fontbigger.png \ - qt/res/icons/drk/fontsmaller.png \ + qt/res/icons/drk/fontsmaller.png \ qt/res/icons/drk/verify.png \ qt/res/icons/drk/warning.png @@ -369,6 +369,7 @@ qt_dynamic_qt_LDADD = qt/libdynamicqt.a $(LIBDYNAMIC_SERVER) if ENABLE_WALLET qt_dynamic_qt_LDADD += $(LIBDYNAMIC_WALLET) endif +qt_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if ENABLE_GPU qt_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD) qt_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) @@ -379,7 +380,6 @@ endif qt_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) -qt_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_dynamic_qt_LIBTOOLFLAGS = --tag CXX #locale/foo.ts -> locale/foo.qm diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 57badeb368..f6612eeb08 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -43,6 +43,7 @@ endif if ENABLE_ZMQ qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif +qt_test_test_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if ENABLE_GPU qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD) qt_test_test_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) @@ -51,7 +52,6 @@ qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYN $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) -qt_test_test_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_test_test_dynamic_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) CLEAN_DYNAMIC_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno From bebfed80861ea1d2c319f73c785a74ba8f8506f6 Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Thu, 26 Jul 2018 00:33:24 +0200 Subject: [PATCH 0095/1653] Update Makefile.gpu.include --- src/Makefile.gpu.include | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index 521ed314b8..a8583be2c4 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -4,6 +4,7 @@ LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a LIBDYNAMIC_GPU_LDADD = $(LIBDYNAMIC_GPU) +LIBDYNAMIC_GPU_LDFLAGS = EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) From fb7c0fae2bada1f1b29fffcb09da9ccda5c6324d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 26 Jul 2018 18:17:36 +0200 Subject: [PATCH 0096/1653] [GPU] Fix autoconf warnings --- src/Makefile.gpu.include | 20 ++++++++++---------- src/Makefile.qt.include | 4 ++-- src/Makefile.qttest.include | 4 ++-- src/Makefile.test.include | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index a8583be2c4..a4a66dbe68 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -3,8 +3,8 @@ # LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a -LIBDYNAMIC_GPU_LDADD = $(LIBDYNAMIC_GPU) -LIBDYNAMIC_GPU_LDFLAGS = +LIBDYNAMIC_GPU_LDADD_EXTRA = $(LIBDYNAMIC_GPU) +LIBDYNAMIC_GPU_LDFLAGS_EXTRA = EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) @@ -19,8 +19,8 @@ if ENABLE_CUDA LIBDYNAMIC_GPU_CUDA = crypto/argon2gpu/cuda/libdynamic_gpu_cuda.a EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_CUDA) -LIBDYNAMIC_GPU_LDADD += $(LIBDYNAMIC_GPU_CUDA) -LIBDYNAMIC_GPU_LDADD += $(CUDA_LDLIBS) +LIBDYNAMIC_GPU_LDADD_EXTRA += $(LIBDYNAMIC_GPU_CUDA) +LIBDYNAMIC_GPU_LDADD_EXTRA += $(CUDA_LDLIBS) DYNAMIC_INCLUDES += $(CUDA_CFLAGS) NVCCFLAGS += -arch=sm_30 -w -lineinfo -Xcompiler='--std=c++11 $(CFLAGS)' @@ -59,15 +59,15 @@ else LIBDYNAMIC_GPU_OPENCL = crypto/argon2gpu/opencl/libdynamic_gpu_opencl.a EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_OPENCL) -LIBDYNAMIC_GPU_LDADD += $(LIBDYNAMIC_GPU_OPENCL) +LIBDYNAMIC_GPU_LDADD_EXTRA += $(LIBDYNAMIC_GPU_OPENCL) if TARGET_DARWIN -LIBDYNAMIC_GPU_LDFLAGS = $(LIBOPENCL) -LIBDYNAMIC_GPU_LDFLAGS += -stdlib=libc++ LIBOPENCL = "-framework OpenCL" +LIBDYNAMIC_GPU_LDFLAGS_EXTRA = $(LIBOPENCL) +LIBDYNAMIC_GPU_LDFLAGS_EXTRA += -stdlib=libc++ else LIBOPENCL = -lOpenCL -LIBDYNAMIC_GPU_LDADD += $(LIBOPENCL) +LIBDYNAMIC_GPU_LDADD_EXTRA += $(LIBOPENCL) endif crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) @@ -90,5 +90,5 @@ crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_SOURCES = \ endif -dynamicd_LDADD += $(LIBDYNAMIC_GPU_LDADD) -dynamicd_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) +dynamicd_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) +dynamicd_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS_EXTRA) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index f1bb8a8563..c727410257 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -371,8 +371,8 @@ qt_dynamic_qt_LDADD += $(LIBDYNAMIC_WALLET) endif qt_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if ENABLE_GPU -qt_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD) -qt_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) +qt_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) +qt_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS_EXTRA) endif if ENABLE_ZMQ qt_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index f6612eeb08..45e5fa94fe 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -45,8 +45,8 @@ qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif qt_test_test_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if ENABLE_GPU -qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD) -qt_test_test_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) +qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) +qt_test_test_dynamic_qt_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS_EXTRA) endif qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c190870b1c..6a3e5239fc 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -122,8 +122,8 @@ if ENABLE_ZMQ test_test_dynamic_LDADD += $(ZMQ_LIBS) endif if ENABLE_GPU -test_test_dynamic_LDADD += $(LIBDYNAMIC_GPU_LDADD) -test_test_dynamic_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS) +test_test_dynamic_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) +test_test_dynamic_LDFLAGS += $(LIBDYNAMIC_GPU_LDFLAGS_EXTRA) endif nodist_test_test_dynamic_SOURCES = $(GENERATED_TEST_FILES) From 76ad485daad77b64be4ffc8dff6081bccea3c236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 26 Jul 2018 19:36:35 +0200 Subject: [PATCH 0097/1653] [GPU] Fix autoconf warning --- src/Makefile.gpu.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index a4a66dbe68..cd781cfd14 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -63,7 +63,7 @@ LIBDYNAMIC_GPU_LDADD_EXTRA += $(LIBDYNAMIC_GPU_OPENCL) if TARGET_DARWIN LIBOPENCL = "-framework OpenCL" -LIBDYNAMIC_GPU_LDFLAGS_EXTRA = $(LIBOPENCL) +LIBDYNAMIC_GPU_LDFLAGS_EXTRA += $(LIBOPENCL) LIBDYNAMIC_GPU_LDFLAGS_EXTRA += -stdlib=libc++ else LIBOPENCL = -lOpenCL From feb4a08b699179a8e354cc1c0cfe90380d983695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 26 Jul 2018 20:10:30 +0200 Subject: [PATCH 0098/1653] [GPU] Disable CUDA in Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ba1bee70d9..8c6645d68f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: - sudo add-apt-repository -y ppa:bitcoin/bitcoin - sudo apt-get update -y && sudo apt-get install -y libdb4.8-dev libdb4.8++-dev script: - - ./autogen.sh && ./configure --with-gui=qt5 --enable-gpu && make + - ./autogen.sh && ./configure --with-gui=qt5 --enable-gpu --disable-cuda && make deploy: provider: releases From 01471d4fdb9d9dffc39e11b10b793eab132378b8 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Fri, 27 Jul 2018 11:36:33 -0500 Subject: [PATCH 0099/1653] [BDAP] Add directory type function --- src/bdap/directory.cpp | 45 +++++++++++++++++++++++++++++++++++++++ src/bdap/directory.h | 2 ++ src/bdap/rpcdirectory.cpp | 1 + 3 files changed, 48 insertions(+) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index d8e063095e..960897d6e9 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -499,4 +499,49 @@ bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& t return true; +} + +int GetDirectoryOpType(const CScript& script) +{ + std::string ret; + CScript::const_iterator it = script.begin(); + opcodetype op1 = OP_INVALIDOPCODE; + opcodetype op2 = OP_INVALIDOPCODE; + while (it != script.end()) { + std::vector vch; + if (op1 == OP_INVALIDOPCODE) + { + if (script.GetOp2(it, op1, &vch)) + { + if (op1 - OP_1NEGATE - 1 == OP_BDAP) + { + continue; + } + else + { + return 0; + } + } + } + else + { + if (script.GetOp2(it, op2, &vch)) + { + if (op2 - OP_1NEGATE - 1 > OP_BDAP && op2 - OP_1NEGATE - 1 <= OP_BDAP_REVOKE) + { + return (int)op2 - OP_1NEGATE - 1; + } + else + { + return -1; + } + } + } + } + return (int)op2; +} + +std::string GetDirectoryOpTypeString(const CScript& script) +{ + return directoryFromOp(GetDirectoryOpType(script)); } \ No newline at end of file diff --git a/src/bdap/directory.h b/src/bdap/directory.h index 4c41f9952b..c721f75737 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -210,5 +210,7 @@ bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector >& vvch); bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); +int GetDirectoryOpType(const CScript& script); +std::string GetDirectoryOpTypeString(const CScript& script); #endif // DYNAMIC_DIRECTORY_H \ No newline at end of file diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index fba3e662d2..557c58da8e 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -98,6 +98,7 @@ UniValue addpublicname(const JSONRPCRequest& request) { CScript scriptDestination; scriptDestination = GetScriptForDestination(payWallet.Get()); scriptPubKey += scriptDestination; + LogPrintf("BDAP GetDirectoryType = %s \n", GetDirectoryOpTypeString(scriptPubKey)); CScript scriptData; scriptData << OP_RETURN << data; From aea3f8c3e3d825293d69e8ea364016070cae22a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Mon, 30 Jul 2018 23:42:56 +0200 Subject: [PATCH 0100/1653] [GPU] Mac build fix attempt --- src/Makefile.gpu.include | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index cd781cfd14..628c3e9bee 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -5,7 +5,7 @@ LIBDYNAMIC_GPU = crypto/argon2gpu/libdynamic_gpu.a LIBDYNAMIC_GPU_LDADD_EXTRA = $(LIBDYNAMIC_GPU) LIBDYNAMIC_GPU_LDFLAGS_EXTRA = -EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) +EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU) crypto_argon2gpu_libdynamic_gpu_a_CPPFLAGS = $(DYNAMIC_INCLUDES) crypto_argon2gpu_libdynamic_gpu_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) @@ -62,12 +62,9 @@ EXTRA_LIBRARIES += $(LIBDYNAMIC_GPU_OPENCL) LIBDYNAMIC_GPU_LDADD_EXTRA += $(LIBDYNAMIC_GPU_OPENCL) if TARGET_DARWIN -LIBOPENCL = "-framework OpenCL" -LIBDYNAMIC_GPU_LDFLAGS_EXTRA += $(LIBOPENCL) -LIBDYNAMIC_GPU_LDFLAGS_EXTRA += -stdlib=libc++ +LIBDYNAMIC_GPU_LDFLAGS_EXTRA += -stdlib=libc++ -framework OpenCL -L/System/Library/Frameworks/OpenCL.framework/Libraries -Wl,-x -m64 else -LIBOPENCL = -lOpenCL -LIBDYNAMIC_GPU_LDADD_EXTRA += $(LIBOPENCL) +LIBDYNAMIC_GPU_LDADD_EXTRA += -lOpenCL endif crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) From 630ef015ef09c4bc5ac7919d76eaf6a743347bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 2 Aug 2018 00:10:56 +0200 Subject: [PATCH 0101/1653] [GPU] Remove unsigned and signed int comparison --- src/miner.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index cd861d4df9..f90532401e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -855,8 +855,9 @@ static boost::thread_group* GetMinerThreads(bool fGPU = false, bool fInit = true return GetCPUMinerThreads(fInit, fRestart); } -void AutoTuneDeviceThreads(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex = -1, bool fGPU = false) +void AutoTuneDeviceThreads(const CChainParams& chainparams, CConnman& connman, boost::optional nGPUDeviceIndex = boost::none) { + bool fGPU = static_cast(nGPUDeviceIndex); // Threads boost::thread* lastThread = NULL; boost::thread_group* minerThreads = GetMinerThreads(fGPU); @@ -874,7 +875,7 @@ void AutoTuneDeviceThreads(const CChainParams& chainparams, CConnman& connman, s while (true) { LogPrintf("Starting %s Miner thread #%u %6.0f khash/s\n", dev, minerThreads->size(), *dHashesPerSec / 1000.0); std::size_t nThread = minerThreads->size(); - std::size_t device = nDeviceIndex == -1 ? nThread : nDeviceIndex; + std::size_t device = nGPUDeviceIndex.value_or(nThread); lastThread = minerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), boost::cref(device), boost::cref(fGPU))); MilliSleep(10000); @@ -897,7 +898,7 @@ void GenerateAutoTuneDevice(const CChainParams& chainparams, CConnman& connman, if (fGPU) { // Start GPU threads for (std::size_t device = 0; device < GetGPUDeviceCount(); device++) { - AutoTuneDeviceThreads(chainparams, connman, device, true); + AutoTuneDeviceThreads(chainparams, connman, device); } return; } @@ -943,7 +944,8 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai nCPUThreads = nNumCores; // Start CPU threads - while (cpuMinerThreads->size() < nCPUThreads) { + std::size_t nCPUTarget = static_cast(nCPUThreads); + while (cpuMinerThreads->size() < nCPUTarget) { std::size_t nThread = cpuMinerThreads->size(); LogPrintf("Starting CPU Miner thread #%u\n", nThread); cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), nThread, false)); @@ -953,9 +955,10 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai nGPUThreads = 4; // Start GPU threads + std::size_t nGPUTarget = static_cast(nGPUThreads); boost::thread_group* gpuMinerThreads = GetGPUMinerThreads(); for (std::size_t device = 0; device < devices; device++) { - for (std::size_t i = 0; i < nGPUThreads; i++) { + for (std::size_t i = 0; i < nGPUTarget; i++) { LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, device, devices); gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), device, true)); } From 60d928447eeebc9bbe416e6f21cae14d301887b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 2 Aug 2018 00:13:34 +0200 Subject: [PATCH 0102/1653] [GPU] OpenCL kernel static build rule --- .gitignore | 1 + src/Makefile.gpu.include | 19 +++++++++++++++++++ .../argon2gpu/opencl/global-context.cpp | 3 --- src/crypto/argon2gpu/opencl/kernel-loader.cpp | 16 +++------------- src/crypto/argon2gpu/opencl/kernel-loader.h | 1 - .../argon2gpu/opencl/program-context.cpp | 5 +---- 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 647a348b09..8f76305570 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,7 @@ libconftest.dylib* *.json.h *.raw.h +*.cl.h #libtool object files *.lo diff --git a/src/Makefile.gpu.include b/src/Makefile.gpu.include index 628c3e9bee..4b278aa7e3 100644 --- a/src/Makefile.gpu.include +++ b/src/Makefile.gpu.include @@ -67,9 +67,14 @@ else LIBDYNAMIC_GPU_LDADD_EXTRA += -lOpenCL endif +OPENCL_KERNEL_FILES = crypto/argon2gpu/opencl/kernel.cl + +GENERATED_KERNEL_FILES = $(OPENCL_KERNEL_FILES:.cl=.cl.h) + crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_SOURCES = \ + $(OPENCL_KERNEL_FILES) \ crypto/argon2gpu/opencl/cl.hpp \ crypto/argon2gpu/opencl/device.h \ crypto/argon2gpu/opencl/global-context.h \ @@ -85,6 +90,20 @@ crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_SOURCES = \ crypto/argon2gpu/opencl/processing-unit.cpp \ crypto/argon2gpu/opencl/program-context.cpp +nodist_crypto_argon2gpu_opencl_libdynamic_gpu_opencl_a_SOURCES = $(GENERATED_KERNEL_FILES) + +BUILT_SOURCES = $(GENERATED_KERNEL_FILES) +CLEANFILES += $(GENERATED_KERNEL_FILES) + +%.cl.h: %.cl + @$(MKDIR_P) $(@D) + @echo "namespace argon2gpu { namespace opencl { namespace code {" > $@ + @echo "static unsigned const char $(*F)[] = {" >> $@ + @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ + @echo "};" >> $@ + @echo "}}}" >> $@ + @echo "Generated $@" + endif dynamicd_LDADD += $(LIBDYNAMIC_GPU_LDADD_EXTRA) diff --git a/src/crypto/argon2gpu/opencl/global-context.cpp b/src/crypto/argon2gpu/opencl/global-context.cpp index 8742cc1743..56902a676c 100644 --- a/src/crypto/argon2gpu/opencl/global-context.cpp +++ b/src/crypto/argon2gpu/opencl/global-context.cpp @@ -26,11 +26,8 @@ namespace opencl GlobalContext::GlobalContext() : devices() { - std::clog << "globalcontextinit <" << std::endl; std::vector platforms; - std::clog << "cl::Platform::get <" << std::endl; cl::Platform::get(&platforms); - std::clog << "cl::Platform::get >" << std::endl; std::vector clDevices; for (cl::Platform platform : platforms) { diff --git a/src/crypto/argon2gpu/opencl/kernel-loader.cpp b/src/crypto/argon2gpu/opencl/kernel-loader.cpp index 7abfec63fe..1fea898a73 100644 --- a/src/crypto/argon2gpu/opencl/kernel-loader.cpp +++ b/src/crypto/argon2gpu/opencl/kernel-loader.cpp @@ -16,6 +16,7 @@ */ #include "crypto/argon2gpu/opencl/kernel-loader.h" +#include "crypto/argon2gpu/opencl/kernel.cl.h" #include #include @@ -27,29 +28,18 @@ namespace opencl { cl::Program KernelLoader::loadArgon2Program( const cl::Context& context, - const std::string& sourceDirectory, Type type, Version version, bool debug) { - std::string sourcePath = sourceDirectory + "/kernel.cl"; - std::string sourceText; std::stringstream buildOpts; - { - std::ifstream sourceFile{sourcePath}; - sourceText = { - std::istreambuf_iterator(sourceFile), - std::istreambuf_iterator()}; - } - if (debug) { - buildOpts << "-g -s \"" << sourcePath << "\"" - << " "; + buildOpts << "-g "; } buildOpts << "-DARGON2_TYPE=" << type << " "; buildOpts << "-DARGON2_VERSION=" << version << " "; - cl::Program prog(context, sourceText); + cl::Program prog(context, reinterpret_cast(code::kernel)); try { std::string opts = buildOpts.str(); prog.build(opts.c_str()); diff --git a/src/crypto/argon2gpu/opencl/kernel-loader.h b/src/crypto/argon2gpu/opencl/kernel-loader.h index e2614460f4..30546ef84d 100644 --- a/src/crypto/argon2gpu/opencl/kernel-loader.h +++ b/src/crypto/argon2gpu/opencl/kernel-loader.h @@ -31,7 +31,6 @@ namespace KernelLoader { cl::Program loadArgon2Program( const cl::Context& context, - const std::string& sourceDirectory, Type type, Version version, bool debug = false); diff --git a/src/crypto/argon2gpu/opencl/program-context.cpp b/src/crypto/argon2gpu/opencl/program-context.cpp index f90e9596ea..fc5f59ad9e 100644 --- a/src/crypto/argon2gpu/opencl/program-context.cpp +++ b/src/crypto/argon2gpu/opencl/program-context.cpp @@ -34,10 +34,7 @@ ProgramContext::ProgramContext( this->devices.push_back(device.getCLDevice()); } context = cl::Context(this->devices); - - program = KernelLoader::loadArgon2Program( - // FIXME path: - context, "./src/crypto/argon2gpu/opencl", type, version); + program = KernelLoader::loadArgon2Program(context, type, version); } } // namespace opencl From 31dc206e808751dcaf539292d05ad66728d726f1 Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Thu, 2 Aug 2018 13:35:08 +0200 Subject: [PATCH 0103/1653] Amend device type. --- src/crypto/argon2gpu/opencl/global-context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/argon2gpu/opencl/global-context.cpp b/src/crypto/argon2gpu/opencl/global-context.cpp index 56902a676c..5b25263c45 100644 --- a/src/crypto/argon2gpu/opencl/global-context.cpp +++ b/src/crypto/argon2gpu/opencl/global-context.cpp @@ -32,7 +32,7 @@ GlobalContext::GlobalContext() std::vector clDevices; for (cl::Platform platform : platforms) { try { - platform.getDevices(CL_DEVICE_TYPE_ALL, &clDevices); + platform.getDevices(CL_DEVICE_TYPE_GPU, &clDevices); devices.insert(devices.end(), clDevices.begin(), clDevices.end()); } catch (const cl::Error& err) { std::cerr << "WARNING: Unable to get devices for platform '" From 8e19f55d7d383a2b951834a49da54e31b3e2f8fc Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 2 Aug 2018 22:22:20 -0500 Subject: [PATCH 0104/1653] [BDAP] Implement add new entry validation checking --- src/bdap/directory.cpp | 59 ++++-------- src/bdap/directory.h | 4 +- src/bdap/directorydb.cpp | 191 +++++++++++++++++++++++++++++++++++++- src/bdap/directorydb.h | 10 ++ src/bdap/rpcdirectory.cpp | 11 +-- 5 files changed, 222 insertions(+), 53 deletions(-) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index 960897d6e9..ded96fdf4b 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -414,12 +414,6 @@ void ToLowerCase(std::string& strValue) { } } -bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrganizationalUnit, const CharString& vchDomainComponent) { - - - return false; -} - CAmount GetBDAPFee(const CScript& scriptPubKey) { CAmount nFee = 0; @@ -437,7 +431,7 @@ bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector > vvchRead; + vchCharString vvchRead; if (DecodeBDAPScript(out.scriptPubKey, op, vvchRead)) { found = true; vvch = vvchRead; @@ -452,13 +446,13 @@ bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector >& vvch) { - int op; for (unsigned int i = 0; i < tx.vin.size(); i++) { const Coin& prevCoins = inputs.AccessCoin(tx.vin[i].prevout); if (prevCoins.IsSpent()) { continue; } // check unspent input for consensus before adding to a block + int op; if (DecodeBDAPScript(prevCoins.out.scriptPubKey, op, vvch)) { return true; } @@ -466,41 +460,6 @@ bool FindDirectoryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, st return false; } -bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, - const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck) -{ - if (tx.IsCoinBase() && !fJustCheck && !bSanityCheck) - { - LogPrintf("*Trying to add BDAP entry in coinbase transaction, skipping..."); - return true; - } - //TODO (bdap): add if back - //if (fDebug && !bSanityCheck) - LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, directoryFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); - - // unserialize BDAP from txn, check if the entry is valid and does not conflict with a previous entry - CDirectory directory; - std::vector vchData; - std::vector vchHash; - int nDataOut; - bool bData = GetDirectoryData(tx, vchData, vchHash, nDataOut); - if(bData && !directory.UnserializeFromData(vchData, vchHash)) - { - errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3600 - " + _("UnserializeFromData data in tx failed!"); - return error(errorMessage.c_str()); - } - - if(!directory.ValidateValues(errorMessage)) - { - errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3601 - " + errorMessage; - return error(errorMessage.c_str()); - } - //TODO (bdap): continue checking transaction validity - - - return true; -} - int GetDirectoryOpType(const CScript& script) { std::string ret; @@ -544,4 +503,18 @@ int GetDirectoryOpType(const CScript& script) std::string GetDirectoryOpTypeString(const CScript& script) { return directoryFromOp(GetDirectoryOpType(script)); +} + +bool GetDirectoryOpScript(const CTransaction& tx, CScript& scriptDirectoryOp, vchCharString& vvchOpParameters, int& op) +{ + for (unsigned int i = 0; i < tx.vout.size(); i++) + { + const CTxOut& out = tx.vout[i]; + if (DecodeBDAPScript(out.scriptPubKey, op, vvchOpParameters)) + { + scriptDirectoryOp = out.scriptPubKey; + return true; + } + } + return false; } \ No newline at end of file diff --git a/src/bdap/directory.h b/src/bdap/directory.h index c721f75737..56977dbf2b 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -204,13 +204,11 @@ std::vector vchFromValue(const UniValue& value); void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); void ToLowerCase(CharString& vchValue); void ToLowerCase(std::string& strValue); -bool CheckIfNameExists(const CharString& vchObjectID, const CharString& vchOrganizationalUnit, const CharString& vchDomainComponent); CAmount GetBDAPFee(const CScript& scriptPubKey); bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector >& vvch); bool FindDirectoryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch); -bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, - const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); int GetDirectoryOpType(const CScript& script); std::string GetDirectoryOpTypeString(const CScript& script); +bool GetDirectoryOpScript(const CTransaction& tx, CScript& scriptDirectoryOp, vchCharString& vvchOpParameters, int& op); #endif // DYNAMIC_DIRECTORY_H \ No newline at end of file diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index 20c39e92a2..a100a8062e 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -18,11 +18,14 @@ bool GetDirectory(const std::vector& vchObjectPath, CDirectory& d return false; } + //TODO: (bdap) calculate directory.nExpireTime + /* if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) { directory.SetNull(); return false; } - return true; + */ + return !directory.IsNull(); } bool CDirectoryDB::AddDirectory(const CDirectory& directory, const int op) @@ -221,4 +224,190 @@ void CleanupLevelDB(int& nRemoved) if(pDirectoryDB != NULL) pDirectoryDB->CleanupLevelDB(nRemoved); FlushLevelDB(); +} + + +static bool CommonDataCheck(const CDirectory& directory, const vchCharString& vvchOpParameters, std::string& errorMessage) +{ + if (directory.IsNull() == true) + { + errorMessage = "CommonDataCheck failed! Directory is null."; + return false; + } + + if (vvchOpParameters.size() == 0) + { + errorMessage = "CommonDataCheck failed! Invalid parameters."; + return false; + } + + if (directory.GetFullObjectPath() != stringFromVch(vvchOpParameters[0])) + { + errorMessage = "CommonDataCheck failed! Script operation parameter does not match directory entry object."; + return false; + } + + if (directory.DomainComponent != vchDefaultDomainName) + { + errorMessage = "CommonDataCheck failed! Must use default domain."; + return false; + } + + if (directory.OrganizationalUnit != vchDefaultPublicOU && directory.OrganizationalUnit != vchDefaultAdminOU) + { + errorMessage = "CommonDataCheck failed! Must use default public organizational unit."; + return false; + } + + if (directory.OrganizationalUnit == vchDefaultAdminOU) + { + errorMessage = "CommonDataCheck failed! Can not use default admin domain."; + return false; + } + + if (!pDirectoryDB) + { + errorMessage = "CommonDataCheck failed! Can not open LevelDB BDAP database."; + return false; + } + return true; +} + +bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +{ + if (!CommonDataCheck(directory, vvchOpParameters, errorMessage)) + return false; + + CDirectory getDirectory; + if (GetDirectory(directory.vchFullObjectPath(), getDirectory)) + { + errorMessage = "CheckNewDirectoryTxInputs failed! " + getDirectory.GetFullObjectPath() + " already exists."; + return false; + } + + if (!pDirectoryDB->AddDirectory(directory, op)) + { + errorMessage = "CheckNewDirectoryTxInputs failed! Error adding new directory entry request to LevelDB."; + return false; + } + + return FlushLevelDB(); +} + +bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +{ + //check name in operation matches directory data in leveldb + //check if exists already + //if exists, check for owner's signature + return false; +} + +bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +{ + //check name in operation matches directory data in leveldb as a new request + //check if new request exists and is not expired + return false; +} + +bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +{ + //check name in operation matches directory data in leveldb + //check if exists already + //if exists, check for owner's signature + return false; +} + +bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +{ + //check name in operation matches directory data in leveldb + //check if exists already + //if exists, check for owner's signature + return false; +} + +bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +{ + //check name in operation matches directory data in leveldb + //check if exists already + //if exists, check for owner's signature + return false; +} + +bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +{ + //check names in operation matches directory data in leveldb + //check if request or accept response + //check if names exists already + //if exists, check for owner's signature + return false; +} + +bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +{ + //check name in operation matches directory data in leveldb + //check if names exists already + //if exists, check for fluid signature + return false; +} + +bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, + const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck) +{ + if (tx.IsCoinBase() && !fJustCheck && !bSanityCheck) + { + LogPrintf("*Trying to add BDAP entry in coinbase transaction, skipping..."); + return true; + } + + if (fDebug && !bSanityCheck) + LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, directoryFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + + CScript scriptOp; + vchCharString vvchOpParameters; + if (!GetDirectoryOpScript(tx, scriptOp, vvchOpParameters, op)) + { + errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3600 - " + _("Transaction does not contain BDAP operation script!"); + return error(errorMessage.c_str()); + } + const std::string strOperationType = GetDirectoryOpTypeString(scriptOp); + if (fDebug) + LogPrintf("CheckDirectoryTxInputs, strOperationType= %s \n", strOperationType); + + // unserialize BDAP from txn, check if the entry is valid and does not conflict with a previous entry + CDirectory directory; + std::vector vchData; + std::vector vchHash; + int nDataOut; + + bool bData = GetDirectoryData(tx, vchData, vchHash, nDataOut); + if(bData && !directory.UnserializeFromData(vchData, vchHash)) + { + errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3601 - " + _("UnserializeFromData data in tx failed!"); + return error(errorMessage.c_str()); + } + + if(!directory.ValidateValues(errorMessage)) + { + errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3602 - " + errorMessage; + return error(errorMessage.c_str()); + } + + if (strOperationType == "bdap_new") + return CheckNewDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + else if (strOperationType == "bdap_delete") + return CheckDeleteDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + else if (strOperationType == "bdap_activate") + return CheckActivateDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + else if (strOperationType == "bdap_update") + return CheckUpdateDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + else if (strOperationType == "bdap_move") + return CheckMoveDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + else if (strOperationType == "bdap_execute") + return CheckExecuteDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + else if (strOperationType == "bdap_bind") + return CheckBindDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + else if (strOperationType == "bdap_revoke") + return CheckRevokeDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + + return false; } \ No newline at end of file diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h index 21090d2df9..295668bf41 100644 --- a/src/bdap/directorydb.h +++ b/src/bdap/directorydb.h @@ -36,6 +36,16 @@ bool GetDirectory(const std::vector& vchObjectPath, CDirectory& d bool CheckDirectoryDB(); bool FlushLevelDB(); void CleanupLevelDB(int& nRemoved); +bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); +bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); +bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); +bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); +bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); +bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); +bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); +bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); +bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, + const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); extern CDirectoryDB *pDirectoryDB; diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 557c58da8e..0227879039 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -32,9 +32,7 @@ UniValue addpublicname(const JSONRPCRequest& request) { ToLowerCase(vchObjectID); CharString vchCommonName = vchFromValue(request.params[1]); - // Check if name already exists - if (CheckIfNameExists(vchObjectID, vchDefaultPublicOU, vchDefaultDomainName)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3500 - " + _("This public name already exists")); + CDirectory txDirectory; txDirectory.OID = vchDefaultOIDPrefix; @@ -46,6 +44,10 @@ UniValue addpublicname(const JSONRPCRequest& request) { txDirectory.fPublicObject = 1; //make entry public txDirectory.transactionFee = 100; + // Check if name already exists + if (GetDirectory(txDirectory.vchFullObjectPath(), txDirectory)) + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3500 - " + txDirectory.GetFullObjectPath() + _(" entry already exists. Can not add duplicate.")); + // TODO: Add ability to pass in the wallet address and public key CKey privWalletKey; privWalletKey.MakeNewKey(true); @@ -84,9 +86,6 @@ UniValue addpublicname(const JSONRPCRequest& request) { txDirectory.SignWalletAddress = vchSignWalletAddress; - if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3505 - " + _("Failed to read from BDAP database")); - CharString data; txDirectory.Serialize(data); From f4a5994dc8ef6e5530ec87bb685f195e1856a2af Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 2 Aug 2018 23:47:16 -0500 Subject: [PATCH 0105/1653] [BDAP] Fix validation when syncing blocks from peers --- src/bdap/directorydb.cpp | 62 ++++++++++++++++++++++++---------------- src/bdap/directorydb.h | 28 +++++++++++------- src/validation.cpp | 15 +++++----- 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index a100a8062e..a1576b2ac1 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -265,26 +265,31 @@ static bool CommonDataCheck(const CDirectory& directory, const vchCharString& vv return false; } - if (!pDirectoryDB) - { - errorMessage = "CommonDataCheck failed! Can not open LevelDB BDAP database."; - return false; - } return true; } -bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck) { if (!CommonDataCheck(directory, vvchOpParameters, errorMessage)) return false; + if (fJustCheck) + return true; + CDirectory getDirectory; if (GetDirectory(directory.vchFullObjectPath(), getDirectory)) { errorMessage = "CheckNewDirectoryTxInputs failed! " + getDirectory.GetFullObjectPath() + " already exists."; return false; } - + + if (!pDirectoryDB) + { + errorMessage = "CheckNewDirectoryTxInputs failed! Can not open LevelDB BDAP entry database."; + return false; + } + if (!pDirectoryDB->AddDirectory(directory, op)) { errorMessage = "CheckNewDirectoryTxInputs failed! Error adding new directory entry request to LevelDB."; @@ -294,7 +299,8 @@ bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directo return FlushLevelDB(); } -bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck) { //check name in operation matches directory data in leveldb //check if exists already @@ -302,14 +308,16 @@ bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& dire return false; } -bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck) { //check name in operation matches directory data in leveldb as a new request //check if new request exists and is not expired return false; } -bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck) { //check name in operation matches directory data in leveldb //check if exists already @@ -317,7 +325,8 @@ bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& dire return false; } -bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck) { //check name in operation matches directory data in leveldb //check if exists already @@ -325,7 +334,8 @@ bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& direct return false; } -bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck) { //check name in operation matches directory data in leveldb //check if exists already @@ -333,7 +343,8 @@ bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& dir return false; } -bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck) { //check names in operation matches directory data in leveldb //check if request or accept response @@ -342,7 +353,8 @@ bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& direct return false; } -bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage) +bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck) { //check name in operation matches directory data in leveldb //check if names exists already @@ -350,8 +362,8 @@ bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& dire return false; } -bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, - const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck) +bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, + int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck) { if (tx.IsCoinBase() && !fJustCheck && !bSanityCheck) { @@ -359,7 +371,7 @@ bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& t return true; } - if (fDebug && !bSanityCheck) + //if (fDebug && !bSanityCheck) LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, directoryFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); CScript scriptOp; @@ -393,21 +405,21 @@ bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& t } if (strOperationType == "bdap_new") - return CheckNewDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + return CheckNewDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_delete") - return CheckDeleteDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + return CheckDeleteDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_activate") - return CheckActivateDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + return CheckActivateDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_update") - return CheckUpdateDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + return CheckUpdateDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_move") - return CheckMoveDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + return CheckMoveDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_execute") - return CheckExecuteDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + return CheckExecuteDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_bind") - return CheckBindDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + return CheckBindDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_revoke") - return CheckRevokeDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage); + return CheckRevokeDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); return false; } \ No newline at end of file diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h index 295668bf41..f54f4149f1 100644 --- a/src/bdap/directorydb.h +++ b/src/bdap/directorydb.h @@ -36,16 +36,24 @@ bool GetDirectory(const std::vector& vchObjectPath, CDirectory& d bool CheckDirectoryDB(); bool FlushLevelDB(); void CleanupLevelDB(int& nRemoved); -bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); -bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); -bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); -bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); -bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); -bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); -bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); -bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage); -bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, - const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); +bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, + int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); extern CDirectoryDB *pDirectoryDB; diff --git a/src/validation.cpp b/src/validation.cpp index 57ad816b94..d2926bc9d2 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -603,7 +603,6 @@ bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const C if (fJustCheck && (IsInitialBlockDownload() || RPCIsInWarmup(&statusRpc))) return true; - std::vector > vvchArgs; std::vector > vvchBDAPArgs; int op = -1; @@ -613,7 +612,7 @@ bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const C } bool bValid = false; - if (block.vtx.empty() && tx.nVersion == BDAP_TX_VERSION) + if (tx.nVersion == BDAP_TX_VERSION) { if (DecodeDirectoryTx(tx, op, vvchBDAPArgs)) { @@ -2252,6 +2251,12 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd } } + + CCoinsViewCache viewCoinCache(pcoinsTip); + if (!ValidateBDAPInputs(tx, state, viewCoinCache, block, fJustCheck, pindex->nHeight)) + { + return error("ConnectBlock(): ValidateBDAPInputs on block %s failed\n", block.GetHash().ToString()); + } CTxUndo undoDummy; if (i > 0) { @@ -2357,12 +2362,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd if (!control.Wait()) return state.DoS(100, false); - CCoinsViewCache viewCoinCache(pcoinsTip); - if (!ValidateBDAPInputs(block.vtx[0], state, viewCoinCache, block, fJustCheck, pindex->nHeight)) - { - return error("ConnectBlock(): ValidateBDAPInputs on block %s failed\n", block.GetHash().ToString()); - } - int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001); From f2ed104371e0463f142638e4871f3915fd4e0130 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 5 Aug 2018 17:28:21 -0500 Subject: [PATCH 0106/1653] [BDAP] Implement directory entry list RPC command --- src/bdap/directory.cpp | 85 +++++++++++++++++++++++---------------- src/bdap/directory.h | 4 +- src/bdap/directorydb.cpp | 32 +++++++++++++++ src/bdap/directorydb.h | 1 + src/bdap/rpcdirectory.cpp | 43 ++++++++++++-------- 5 files changed, 113 insertions(+), 52 deletions(-) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index ded96fdf4b..7e7d5eb56e 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -192,12 +192,22 @@ std::string CDirectory::GetFullObjectPath() const { return stringFromVch(ObjectID) + "@" + stringFromVch(OrganizationalUnit) + "." + stringFromVch(DomainComponent); } +std::string CDirectory::GetObjectLocation() const { + return stringFromVch(OrganizationalUnit) + "." + stringFromVch(DomainComponent); +} + std::vector CDirectory::vchFullObjectPath() const { std::string strFullObjectPath = GetFullObjectPath(); std::vector vchReturnValue(strFullObjectPath.begin(), strFullObjectPath.end()); return vchReturnValue; } +std::vector CDirectory::vchObjectLocation() const { + std::string strObjectLocation = GetObjectLocation(); + std::vector vchReturnValue(strObjectLocation.begin(), strObjectLocation.end()); + return vchReturnValue; +} + void CDirectory::AddCheckpoint(const uint32_t& height, const CharString& vchHash) { std::pair pairNewCheckpoint; @@ -320,48 +330,53 @@ bool CDirectory::ValidateValues(std::string& errorMessage) return true; } -bool BuildBDAPJson(const CDirectory& directory, UniValue& oName) +bool BuildBDAPJson(const CDirectory& directory, UniValue& oName, bool fAbridged) { bool expired = false; int64_t expired_time = 0; int64_t nTime = 0; - oName.push_back(Pair("_id", stringFromVch(directory.OID))); - oName.push_back(Pair("version", directory.nVersion)); - oName.push_back(Pair("domain_component", stringFromVch(directory.DomainComponent))); - oName.push_back(Pair("common_name", stringFromVch(directory.CommonName))); - oName.push_back(Pair("organizational_unit", stringFromVch(directory.OrganizationalUnit))); - oName.push_back(Pair("organization_name", stringFromVch(directory.DomainComponent))); - oName.push_back(Pair("object_id", stringFromVch(directory.ObjectID))); - oName.push_back(Pair("object_full_path", stringFromVch(directory.vchFullObjectPath()))); - oName.push_back(Pair("object_type", directory.ObjectType)); - oName.push_back(Pair("wallet_address", stringFromVch(directory.WalletAddress))); - oName.push_back(Pair("signature_address", stringFromVch(directory.SignWalletAddress))); - oName.push_back(Pair("public", (int)directory.fPublicObject)); - oName.push_back(Pair("encryption_publickey", HexStr(directory.EncryptPublicKey))); - oName.push_back(Pair("sigatures_required", (int)directory.nSigaturesRequired)); - oName.push_back(Pair("resource_pointer", stringFromVch(directory.ResourcePointer))); - oName.push_back(Pair("txid", directory.txHash.GetHex())); - if ((unsigned int)chainActive.Height() >= directory.nHeight-1) { - CBlockIndex *pindex = chainActive[directory.nHeight-1]; - if (pindex) { - nTime = pindex->GetMedianTimePast(); + if (!fAbridged) { + oName.push_back(Pair("_id", stringFromVch(directory.OID))); + oName.push_back(Pair("version", directory.nVersion)); + oName.push_back(Pair("domain_component", stringFromVch(directory.DomainComponent))); + oName.push_back(Pair("common_name", stringFromVch(directory.CommonName))); + oName.push_back(Pair("organizational_unit", stringFromVch(directory.OrganizationalUnit))); + oName.push_back(Pair("organization_name", stringFromVch(directory.DomainComponent))); + oName.push_back(Pair("object_id", stringFromVch(directory.ObjectID))); + oName.push_back(Pair("object_full_path", stringFromVch(directory.vchFullObjectPath()))); + oName.push_back(Pair("object_type", directory.ObjectType)); + oName.push_back(Pair("wallet_address", stringFromVch(directory.WalletAddress))); + oName.push_back(Pair("signature_address", stringFromVch(directory.SignWalletAddress))); + oName.push_back(Pair("public", (int)directory.fPublicObject)); + oName.push_back(Pair("encryption_publickey", HexStr(directory.EncryptPublicKey))); + oName.push_back(Pair("sigatures_required", (int)directory.nSigaturesRequired)); + oName.push_back(Pair("resource_pointer", stringFromVch(directory.ResourcePointer))); + oName.push_back(Pair("txid", directory.txHash.GetHex())); + if ((unsigned int)chainActive.Height() >= directory.nHeight-1) { + CBlockIndex *pindex = chainActive[directory.nHeight-1]; + if (pindex) { + nTime = pindex->GetMedianTimePast(); + } + } + oName.push_back(Pair("time", nTime)); + //oName.push_back(Pair("height", directory.nHeight)); + expired_time = directory.nExpireTime; + if(expired_time <= (unsigned int)chainActive.Tip()->GetMedianTimePast()) + { + expired = true; } + oName.push_back(Pair("expires_on", expired_time)); + oName.push_back(Pair("expired", expired)); + oName.push_back(Pair("certificate", stringFromVch(directory.Certificate))); + oName.push_back(Pair("private_data", stringFromVch(directory.PrivateData))); + oName.push_back(Pair("transaction_fee", directory.transactionFee)); + oName.push_back(Pair("registration_fee", directory.registrationFeePerDay)); } - oName.push_back(Pair("time", nTime)); - //oName.push_back(Pair("height", directory.nHeight)); - expired_time = directory.nExpireTime; - if(expired_time <= (unsigned int)chainActive.Tip()->GetMedianTimePast()) - { - expired = true; + else { + oName.push_back(Pair("common_name", stringFromVch(directory.CommonName))); + oName.push_back(Pair("object_full_path", stringFromVch(directory.vchFullObjectPath()))); + oName.push_back(Pair("wallet_address", stringFromVch(directory.WalletAddress))); } - oName.push_back(Pair("expires_on", expired_time)); - oName.push_back(Pair("expired", expired)); - - oName.push_back(Pair("certificate", stringFromVch(directory.Certificate))); - oName.push_back(Pair("private_data", stringFromVch(directory.PrivateData))); - oName.push_back(Pair("transaction_fee", directory.transactionFee)); - oName.push_back(Pair("registration_fee", directory.registrationFeePerDay)); - // loop CheckpointHashes return true; } diff --git a/src/bdap/directory.h b/src/bdap/directory.h index 56977dbf2b..a8dcfc5769 100644 --- a/src/bdap/directory.h +++ b/src/bdap/directory.h @@ -186,7 +186,9 @@ class CDirectory { CDynamicAddress GetWalletAddress() const; std::string GetFullObjectPath() const; + std::string GetObjectLocation() const; std::vector vchFullObjectPath() const; + std::vector vchObjectLocation() const; // OU . Domain Name void AddCheckpoint(const uint32_t& height, const CharString& vchHash); bool ValidateValues(std::string& errorMessage); }; @@ -197,7 +199,7 @@ bool IsDirectoryDataOutput(const CTxOut& out); int GetDirectoryDataOutput(const CTransaction& tx); bool GetDirectoryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); bool GetDirectoryData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash); -bool BuildBDAPJson(const CDirectory& directory, UniValue& oName); +bool BuildBDAPJson(const CDirectory& directory, UniValue& oName, bool fAbridged = false); std::string stringFromVch(const CharString& vch); std::vector vchFromValue(const UniValue& value); diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index a1576b2ac1..1dff686896 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -196,6 +196,38 @@ bool CDirectoryDB::CleanupLevelDB(int& nRemoved) return true; } +// Lists active entries by domain name with paging support +bool CDirectoryDB::ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDirectoryList) +{ + // TODO: (bdap) implement paging + // if vchObjectLocation is empty, list entries from all domains + int index = 0; + std::pair key; + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CDirectory directory; + try { + if (pcursor->GetKey(key) && key.first == "domain_component") { + pcursor->GetValue(directory); + if (vchObjectLocation.empty() || directory.vchObjectLocation() == vchObjectLocation) + { + UniValue oDirectoryEntry(UniValue::VOBJ); + BuildBDAPJson(directory, oDirectoryEntry, true); + oDirectoryList.push_back(oDirectoryEntry); + index++; + } + } + pcursor->Next(); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + bool CheckDirectoryDB() { if (!pDirectoryDB) diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h index f54f4149f1..c457d371c1 100644 --- a/src/bdap/directorydb.h +++ b/src/bdap/directorydb.h @@ -30,6 +30,7 @@ class CDirectoryDB : public CDBWrapper { bool UpdateDirectory(const std::vector& vchObjectPath, CDirectory& directory); bool UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory); bool CleanupLevelDB(int& nRemoved); + bool ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDirectoryList); }; bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory); diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 0227879039..47d68eb946 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -16,8 +16,10 @@ extern void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdap static constexpr bool fPrintDebug = true; -UniValue addpublicname(const JSONRPCRequest& request) { - if (request.params.size() != 2) { +UniValue addpublicname(const JSONRPCRequest& request) +{ + if (request.params.size() != 2) + { throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); } @@ -135,21 +137,30 @@ UniValue addpublicname(const JSONRPCRequest& request) { return oName; } -UniValue directorylist(const JSONRPCRequest& request) { - if (request.params.size() != 1) { - throw std::runtime_error("directorylist \nAdd directory to blockchain.\n"); +UniValue getdirectories(const JSONRPCRequest& request) +{ + if (request.params.size() > 2) + { + throw std::runtime_error("directorylist \nLists all BDAP entries.\n"); } + + unsigned int nRecordsPerPage = 100; + unsigned int nPage = 1; + if (request.params.size() > 0) + nRecordsPerPage = request.params[0].get_int(); - std::vector vchDirectoryName = vchFromValue(request.params[0]); - CDirectory txDirectory; - if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) - throw std::runtime_error("Failed to read from BDAP database"); - - UniValue oName(UniValue::VOBJ); - if(!BuildBDAPJson(txDirectory, oName)) - throw std::runtime_error("Failed to read from BDAP JSON object"); - - return oName; + if (request.params.size() == 2) + nPage = request.params[1].get_int(); + + // only return entries from the default public domain OU + std::string strObjectLocation = DEFAULT_PUBLIC_OU + "." + DEFAULT_PUBLIC_DOMAIN; + CharString vchObjectLocation(strObjectLocation.begin(), strObjectLocation.end()); + + UniValue oDirectoryList(UniValue::VARR); + if (CheckDirectoryDB()) + pDirectoryDB->ListDirectories(vchObjectLocation, nRecordsPerPage, nPage, oDirectoryList); + + return oDirectoryList; } UniValue directoryupdate(const JSONRPCRequest& request) { @@ -174,7 +185,7 @@ static const CRPCCommand commands[] = #ifdef ENABLE_WALLET /* BDAP */ { "bdap", "addpublicname", &addpublicname, true }, - { "bdap", "directorylist", &directorylist, true }, + { "bdap", "getdirectories", &getdirectories, true }, { "bdap", "directoryupdate", &directoryupdate, true }, #endif //ENABLE_WALLET }; From 161e1bc8d70cf523445c4698440a3db4d110943c Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 6 Aug 2018 14:16:58 -0500 Subject: [PATCH 0107/1653] [BDAP] Add getdirectoryinfo RPC command --- src/bdap/directorydb.cpp | 14 ++++++++++++++ src/bdap/directorydb.h | 1 + src/bdap/rpcdirectory.cpp | 23 +++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index 1dff686896..429f75e598 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -228,6 +228,20 @@ bool CDirectoryDB::ListDirectories(const std::vector& vchObjectLo return true; } +bool CDirectoryDB::GetDirectoryInfo(const std::vector& vchFullObjectPath, UniValue& oDirectoryInfo) +{ + CDirectory directory; + if (!ReadDirectory(vchFullObjectPath, directory)) { + return false; + } + + if (!BuildBDAPJson(directory, oDirectoryInfo, false)) { + return false; + } + + return true; +} + bool CheckDirectoryDB() { if (!pDirectoryDB) diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h index c457d371c1..8fdfd62598 100644 --- a/src/bdap/directorydb.h +++ b/src/bdap/directorydb.h @@ -31,6 +31,7 @@ class CDirectoryDB : public CDBWrapper { bool UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory); bool CleanupLevelDB(int& nRemoved); bool ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDirectoryList); + bool GetDirectoryInfo(const std::vector& vchFullObjectPath, UniValue& oDirectoryInfo); }; bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory); diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 47d68eb946..7a1522483b 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -163,6 +163,28 @@ UniValue getdirectories(const JSONRPCRequest& request) return oDirectoryList; } +UniValue getdirectoryinfo(const JSONRPCRequest& request) +{ + if (request.params.size() != 1) + { + throw std::runtime_error("getdirectoryinfo \nList BDAP entry.\n"); + } + + CharString vchObjectID = vchFromValue(request.params[0]); + ToLowerCase(vchObjectID); + + CDirectory directory; + directory.DomainComponent = vchDefaultDomainName; + directory.OrganizationalUnit = vchDefaultPublicOU; + directory.ObjectID = vchObjectID; + + UniValue oDirectoryInfo(UniValue::VOBJ); + if (CheckDirectoryDB()) + pDirectoryDB->GetDirectoryInfo(directory.vchFullObjectPath(), oDirectoryInfo); + + return oDirectoryInfo; +} + UniValue directoryupdate(const JSONRPCRequest& request) { if (request.params.size() != 1) { throw std::runtime_error("directoryupdate \nAdd directory to blockchain.\n"); @@ -186,6 +208,7 @@ static const CRPCCommand commands[] = /* BDAP */ { "bdap", "addpublicname", &addpublicname, true }, { "bdap", "getdirectories", &getdirectories, true }, + { "bdap", "getdirectoryinfo", &getdirectoryinfo, true }, { "bdap", "directoryupdate", &directoryupdate, true }, #endif //ENABLE_WALLET }; From d3b008b3e3d79d54b2595dda0b7ca7b82218bc8c Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 7 Aug 2018 10:28:29 -0500 Subject: [PATCH 0108/1653] [BDAP] Add leveldb update method to db wrapper class --- src/dbwrapper.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 67d40d9915..4df5eccd8b 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -247,6 +247,32 @@ class CDBWrapper return true; } + template + bool Update(const K& key, const V& value) const + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); + ssKey << key; + leveldb::Slice slKey(ssKey.data(), ssKey.size()); + std::string strValue; + try { + CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); + ssValue.Xor(obfuscate_key); + ssValue << value; + leveldb::Slice slValue(ssValue.data(), ssValue.size()); + leveldb::Status status = pdb->Put(writeoptions, slKey, slValue); + if (!status.ok()) { + if (status.IsNotFound()) + return false; + LogPrintf("LevelDB update failure: %s\n", status.ToString()); + dbwrapper_private::HandleError(status); + } + } catch (const std::exception&) { + return false; + } + return true; + } + template bool Write(const K& key, const V& value, bool fSync = false) { From 42db20a8533cf92bcdaf18ccfd5951e340c62eec Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 7 Aug 2018 10:40:03 -0500 Subject: [PATCH 0109/1653] [BDAP] Fix validate input function; leveldb check not DOS --- src/validation.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index d2926bc9d2..940b2bf473 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -592,13 +592,9 @@ bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const C if (!fLoaded) return true; - std::string errorMessage; if (!CheckDirectoryDB()) - { - errorMessage = "ValidateBDAPInputs: CheckDirectoryDB failed!"; - return state.DoS(100, false, REJECT_INVALID, errorMessage); - } - + return true; + std::string statusRpc = ""; if (fJustCheck && (IsInitialBlockDownload() || RPCIsInWarmup(&statusRpc))) return true; @@ -616,14 +612,15 @@ bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const C { if (DecodeDirectoryTx(tx, op, vvchBDAPArgs)) { + std::string errorMessage; bValid = CheckDirectoryTxInputs(inputs, tx, op, vvchBDAPArgs, fJustCheck, nHeight, errorMessage, bSanity); if (!bValid) { errorMessage = "ValidateBDAPInputs: " + errorMessage; return state.DoS(100, false, REJECT_INVALID, errorMessage); } - if (!bValid || !errorMessage.empty()) - return state.DoS(100, false, REJECT_INVALID, errorMessage); + if (!errorMessage.empty()) + return state.DoS(100, false, REJECT_INVALID, errorMessage); } } return true; From d14b2f2c6556de5e60b00bd3ecdafe8cb7fbf297 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 7 Aug 2018 10:41:09 -0500 Subject: [PATCH 0110/1653] [BDAP] Update getdirectoryinfo help parameter --- src/bdap/rpcdirectory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 7a1522483b..e4d91e4b66 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -167,7 +167,7 @@ UniValue getdirectoryinfo(const JSONRPCRequest& request) { if (request.params.size() != 1) { - throw std::runtime_error("getdirectoryinfo \nList BDAP entry.\n"); + throw std::runtime_error("getdirectoryinfo \nList BDAP entry.\n"); } CharString vchObjectID = vchFromValue(request.params[0]); From f930c42e29cb31c3f72955084317e8308843f1c4 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 7 Aug 2018 11:30:58 -0500 Subject: [PATCH 0111/1653] [BDAP] Implement update & delete entry tx validation checking --- src/bdap/directory.cpp | 5 ++ src/bdap/directory.h | 1 + src/bdap/directorydb.cpp | 109 ++++++++++++++++++++++++++++++++------- src/bdap/directorydb.h | 3 +- 4 files changed, 98 insertions(+), 20 deletions(-) diff --git a/src/bdap/directory.cpp b/src/bdap/directory.cpp index 7e7d5eb56e..41872533e1 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/directory.cpp @@ -105,6 +105,11 @@ std::vector vchFromValue(const UniValue& value) { return std::vector(strbeg, strbeg + strName.size()); } +std::vector vchFromString(const std::string& str) +{ + return std::vector(str.begin(), str.end()); +} + int GetDirectoryDataOutput(const CTransaction& tx) { for(unsigned int i = 0; i vchFromValue(const UniValue& value); +std::vector vchFromString(const std::string& str); void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); void ToLowerCase(CharString& vchValue); void ToLowerCase(std::string& strValue); diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index 429f75e598..5a3b10ffdb 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -46,7 +46,8 @@ void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int op) { UniValue oName(UniValue::VOBJ); if (BuildBDAPJson(directory, oName)) { - GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_new"); + CharString vchOperationType = vchFromString(directoryFromOp(op)); + GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), reinterpret_cast(vchOperationType.data())); WriteDirectoryIndexHistory(directory, op); } } @@ -148,14 +149,20 @@ void CDirectoryDB::WriteDirectoryIndex(const CDirectory& directory, const int op WriteDirectoryIndexHistory(directory, op); } -bool CDirectoryDB::UpdateDirectory(const std::vector& vchObjectPath, CDirectory& directory) +bool CDirectoryDB::UpdateDirectory(const std::vector& vchObjectPath, const CDirectory& directory) { - return false; //TODO (bdap): add update impl -} + LOCK(cs_bdap_directory); -bool CDirectoryDB::UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory) -{ - return false; //TODO (bdap): add update impl + if (!EraseDirectoryAddress(directory.WalletAddress)) + return false; + + bool writeState = false; + writeState = Update(make_pair(std::string("domain_component"), directory.GetFullObjectPath()), directory) + && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.GetFullObjectPath()); + if (writeState) + AddDirectoryIndex(directory, OP_BDAP_MODIFY); + + return writeState; } // Removes expired records from databases. @@ -318,7 +325,7 @@ bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directo const int op, std::string& errorMessage, bool fJustCheck) { if (!CommonDataCheck(directory, vvchOpParameters, errorMessage)) - return false; + return error(errorMessage.c_str()); if (fJustCheck) return true; @@ -326,20 +333,20 @@ bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directo CDirectory getDirectory; if (GetDirectory(directory.vchFullObjectPath(), getDirectory)) { - errorMessage = "CheckNewDirectoryTxInputs failed! " + getDirectory.GetFullObjectPath() + " already exists."; - return false; + errorMessage = "CheckNewDirectoryTxInputs: - The entry " + getDirectory.GetFullObjectPath() + " already exists. Add new entry failed!"; + return error(errorMessage.c_str()); } if (!pDirectoryDB) { errorMessage = "CheckNewDirectoryTxInputs failed! Can not open LevelDB BDAP entry database."; - return false; + return error(errorMessage.c_str()); } if (!pDirectoryDB->AddDirectory(directory, op)) { errorMessage = "CheckNewDirectoryTxInputs failed! Error adding new directory entry request to LevelDB."; - return false; + return error(errorMessage.c_str()); } return FlushLevelDB(); @@ -348,10 +355,43 @@ bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directo bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { - //check name in operation matches directory data in leveldb - //check if exists already //if exists, check for owner's signature - return false; + if (!CommonDataCheck(directory, vvchOpParameters, errorMessage)) + return error(errorMessage.c_str()); + + if (fJustCheck) + return true; + + CDirectory prevDirectory; + if (!GetDirectory(directory.vchFullObjectPath(), prevDirectory)) + { + errorMessage = "CheckDeleteDirectoryTxInputs: - Can not find " + prevDirectory.GetFullObjectPath() + " entry; this delete operation failed!"; + return error(errorMessage.c_str()); + } + + CTxDestination bdapDest; + if (!ExtractDestination(scriptOp, bdapDest)) + { + errorMessage = "CheckDeleteDirectoryTxInputs: - " + _("Cannot extract destination of BDAP input; this delete operation failed!"); + return error(errorMessage.c_str()); + } + else + { + CDynamicAddress prevSignAddress(bdapDest); + { + if (EncodeBase58(directory.SignWalletAddress) != prevSignAddress.ToString()) + errorMessage = "CheckDeleteDirectoryTxInputs: - " + _("You are not the owner of this BDAP entry; this delete operation failed!"); + return error(errorMessage.c_str()); + } + } + + if (!pDirectoryDB->EraseDirectory(directory.vchFullObjectPath())) + { + errorMessage = "CheckDeleteDirectoryTxInputs: - Error deleting directory entry in LevelDB; this delete operation failed!"; + return error(errorMessage.c_str()); + } + + return FlushLevelDB(); } bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, @@ -365,10 +405,43 @@ bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& di bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { - //check name in operation matches directory data in leveldb - //check if exists already //if exists, check for owner's signature - return false; + if (!CommonDataCheck(directory, vvchOpParameters, errorMessage)) + return error(errorMessage.c_str()); + + if (fJustCheck) + return true; + + CDirectory prevDirectory; + if (!GetDirectory(directory.vchFullObjectPath(), prevDirectory)) + { + errorMessage = "CheckUpdateDirectoryTxInputs: - Can not find " + prevDirectory.GetFullObjectPath() + " entry; this update operation failed!"; + return error(errorMessage.c_str()); + } + + CTxDestination bdapDest; + if (!ExtractDestination(scriptOp, bdapDest)) + { + errorMessage = "CheckUpdateDirectoryTxInputs: - " + _("Cannot extract destination of BDAP input; this update operation failed!"); + return error(errorMessage.c_str()); + } + else + { + CDynamicAddress prevSignAddress(bdapDest); + { + if (EncodeBase58(directory.SignWalletAddress) != prevSignAddress.ToString()) + errorMessage = "CheckUpdateDirectoryTxInputs: - " + _("You are not the owner of this BDAP entry; this update operation failed!"); + return error(errorMessage.c_str()); + } + } + + if (!pDirectoryDB->UpdateDirectory(directory.vchFullObjectPath(), directory)) + { + errorMessage = "CheckUpdateDirectoryTxInputs: - Error updating directory entry in LevelDB; this update operation failed!"; + return error(errorMessage.c_str()); + } + + return FlushLevelDB(); } bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h index 8fdfd62598..21d6398598 100644 --- a/src/bdap/directorydb.h +++ b/src/bdap/directorydb.h @@ -27,8 +27,7 @@ class CDirectoryDB : public CDBWrapper { bool RemoveExpired(int& entriesRemoved); void WriteDirectoryIndex(const CDirectory& directory, const int op); void WriteDirectoryIndexHistory(const CDirectory& directory, const int op); - bool UpdateDirectory(const std::vector& vchObjectPath, CDirectory& directory); - bool UpdateDirectoryAddress(const std::vector& vchAddress, CDirectory& directory); + bool UpdateDirectory(const std::vector& vchObjectPath, const CDirectory& directory); bool CleanupLevelDB(int& nRemoved); bool ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDirectoryList); bool GetDirectoryInfo(const std::vector& vchFullObjectPath, UniValue& oDirectoryInfo); From 3a5910d1cb1fa383dfc9ec02796c689408db4fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 02:08:55 +0200 Subject: [PATCH 0112/1653] [GPU] Device get total memory method --- src/crypto/argon2gpu/cuda/device.cpp | 7 +++++++ src/crypto/argon2gpu/cuda/device.h | 1 + src/crypto/argon2gpu/opencl/device.cpp | 5 +++++ src/crypto/argon2gpu/opencl/device.h | 1 + 4 files changed, 14 insertions(+) diff --git a/src/crypto/argon2gpu/cuda/device.cpp b/src/crypto/argon2gpu/cuda/device.cpp index b2764317a8..d98b51b1ef 100644 --- a/src/crypto/argon2gpu/cuda/device.cpp +++ b/src/crypto/argon2gpu/cuda/device.cpp @@ -39,5 +39,12 @@ std::string Device::getInfo() const return "CUDA Device '" + std::string(prop.name) + "'"; } +std::size_t Device::getTotalMemory() const +{ + cudaDeviceProp prop; + CudaException::check(cudaGetDeviceProperties(&prop, deviceIndex)); + return prop.totalGlobalMem; +} + } // namespace cuda } // namespace argon2gpu diff --git a/src/crypto/argon2gpu/cuda/device.h b/src/crypto/argon2gpu/cuda/device.h index 9407848298..eea2c7464a 100644 --- a/src/crypto/argon2gpu/cuda/device.h +++ b/src/crypto/argon2gpu/cuda/device.h @@ -34,6 +34,7 @@ class Device public: std::string getName() const; std::string getInfo() const; + std::size_t getTotalMemory() const; int getDeviceIndex() const { return deviceIndex; } diff --git a/src/crypto/argon2gpu/opencl/device.cpp b/src/crypto/argon2gpu/opencl/device.cpp index aa05d7ffbf..e598c615c6 100644 --- a/src/crypto/argon2gpu/opencl/device.cpp +++ b/src/crypto/argon2gpu/opencl/device.cpp @@ -30,6 +30,11 @@ std::string Device::getName() const return "OpenCL Device '" + device.getInfo() + "' (" + device.getInfo() + ")"; } +std::size_t Device::getTotalMemory() const +{ + return device.getInfo(); +} + template static std::ostream& printBitfield(std::ostream& out, T value, const std::vector >& lookup) { diff --git a/src/crypto/argon2gpu/opencl/device.h b/src/crypto/argon2gpu/opencl/device.h index 928757497e..ca1c11f512 100644 --- a/src/crypto/argon2gpu/opencl/device.h +++ b/src/crypto/argon2gpu/opencl/device.h @@ -33,6 +33,7 @@ class Device public: std::string getName() const; std::string getInfo() const; + std::size_t getTotalMemory() const; const cl::Device& getCLDevice() const { return device; } From 394bd00f9920e1a5116583cfffc394fb67858c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 02:10:55 +0200 Subject: [PATCH 0113/1653] [GPU] Remove obvious type hint --- src/miner-gpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner-gpu.h b/src/miner-gpu.h index e7b67c212a..c437177994 100644 --- a/src/miner-gpu.h +++ b/src/miner-gpu.h @@ -45,7 +45,7 @@ inline uint256 GetBlockHashGPU(const CBlockHeader* block, const Pu& pu) const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); uint256 hashResult; - pu->setInputAndSalt(0, (const void*)input, INPUT_BYTES); + pu->setInputAndSalt(0, input, INPUT_BYTES); pu->beginProcessing(); pu->endProcessing(); pu->getHash(0, (uint8_t*)&hashResult); From 410e356b67370c548d05c9660a981600ff6051c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 02:13:23 +0200 Subject: [PATCH 0114/1653] [GPU] Process hashes in batches --- src/miner.cpp | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index f90532401e..a6ef70bc30 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -521,6 +521,7 @@ static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); + std::size_t batchSizeTarget = device.getTotalMemory() / 512e3; try { // Throw an error if no script was provided. This can happen @@ -564,12 +565,36 @@ static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, { unsigned int nHashesDone = 0; - uint256 hash; - while (true) { - hash = GetBlockHashGPU(pblock, &processingUnit); - //assert(hash == pblock->GetHash()); - if (UintToArith256(hash) <= hashTarget) - { + // current batch size + std::size_t batchSize = batchSizeTarget; + + // set batch input + static unsigned char pblank[1]; + for (std::size_t i = 0; i < batchSizeTarget; i++) { + const auto pBegin = BEGIN(pblock->nVersion); + const auto pEnd = END(pblock->nNonce); + const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); + // input is copied onto memory buffer + pu->setInputAndSalt(i, input, INPUT_BYTES); + // increment block nonce + pblock->nNonce += 1; + // increment hashes done + nHashesDone += 1; + // TODO(crackcomm): is this only to count hashes? + if ((pblock->nNonce & 0xFF) == 0) { + batchSize = i + 1; + break; + } + } + + // start GPU processing + pu->beginProcessing(); + // wait for results + pu->endProcessing(); + // check batch results + for (std::size_t i = 0; i < batchSize; i++) { + pu->getHash(i, (uint8_t*)&hash); + if (UintToArith256(hash) <= hashTarget) { // Found a solution //assert(hash == pblock->GetHash()); SetThreadPriority(THREAD_PRIORITY_NORMAL); @@ -584,10 +609,6 @@ static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, break; } - pblock->nNonce += 1; - nHashesDone += 1; - if ((pblock->nNonce & 0xFF) == 0) - break; } // Meter hashes/seconds @@ -601,6 +622,7 @@ static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, } else nHashCounter += nHashesDone; + if (GetTimeMillis() - nHPSTimerStart > 4000) { static CCriticalSection cs; From c0a9d54c8a7c724236ea344606a38763d0f18a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 03:45:21 +0200 Subject: [PATCH 0115/1653] Refactor miners code --- src/init.cpp | 3 +- src/miner.cpp | 766 +++++++++++++++++++--------------------------- src/miner.h | 15 +- src/rpcmining.cpp | 3 +- 4 files changed, 328 insertions(+), 459 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index e17978b3a3..ef092d9a00 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -510,7 +510,6 @@ std::string HelpMessage(HelpMessageMode mode) if (showDebug) { strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0"); - strUsage += HelpMessageOpt("-autotune", _("Autotune threads per device (default: false)")); strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), DEFAULT_GENERATE)); strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS_CPU)); #if ENABLE_GPU @@ -1833,7 +1832,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Generate coins in the background if (GetBoolArg("-gen", DEFAULT_GENERATE)) { - GenerateDynamics(GetArg("-genproclimit", DEFAULT_GENERATE_THREADS_CPU), GetArg("-genproclimit-gpu", DEFAULT_GENERATE_THREADS_GPU), chainparams, connman, GetBoolArg("-autotune", false)); + GenerateDynamics(GetArg("-genproclimit", DEFAULT_GENERATE_THREADS_CPU), GetArg("-genproclimit-gpu", DEFAULT_GENERATE_THREADS_GPU), chainparams, connman); } // ********************************************************* Step 13: finished diff --git a/src/miner.cpp b/src/miner.cpp index a6ef70bc30..4bca4f2a49 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -12,25 +12,25 @@ #include "chainparams.h" #include "coins.h" #include "consensus/consensus.h" +#include "consensus/merkle.h" +#include "consensus/validation.h" #include "dynode-payments.h" #include "dynode-sync.h" +#include "fluid.h" #include "governance-classes.h" #include "hash.h" -#include "validation.h" -#include "consensus/merkle.h" #include "net.h" #include "policy/policy.h" #include "pow.h" +#include "primitives/transaction.h" #include "script/standard.h" #include "timedata.h" -#include "primitives/transaction.h" #include "txmempool.h" #include "util.h" #include "utilmoneystr.h" -#include "consensus/validation.h" +#include "validation.h" #include "validationinterface.h" #include "wallet/wallet.h" -#include "fluid.h" #include #include @@ -63,14 +63,14 @@ class ScoreCompare bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b) { - return CompareTxMemPoolEntryByScore()(*b,*a); // Convert to less than + return CompareTxMemPoolEntryByScore()(*b, *a); // Convert to less than } }; int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { int64_t nOldTime = pblock->nTime; - int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime()); if (nOldTime < nNewTime) pblock->nTime = nNewTime; @@ -119,10 +119,8 @@ bool CheckWork(const CChainParams& chainparams, const CBlock* pblock, CWallet& w std::unique_ptr CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn) { // Create new block - std::unique_ptr pblocktemplate(new CBlockTemplate()); - if(!pblocktemplate.get()) - return nullptr; - CBlock *pblock = &pblocktemplate->block; // pointer for convenience + auto pblocktemplate = std::make_unique(); + CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Create coinbase tx with fluid issuance // TODO: Can this be made any more elegant? @@ -134,7 +132,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity: - nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); + nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE - 1000), nBlockMaxSize)); // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay @@ -175,7 +173,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, // Add our coinbase tx as first transaction pblock->vtx.push_back(txNew); - pblocktemplate->vTxFees.push_back(-1); // updated at end + pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); // -regtest only: allow overriding block.nVersion with @@ -183,17 +181,14 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, if (chainparams.MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); - int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) - ? nMedianTimePast - : pblock->GetBlockTime(); + int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) ? nMedianTimePast : pblock->GetBlockTime(); bool fPriorityBlock = nBlockPrioritySize > 0; if (fPriorityBlock) { vecPriority.reserve(mempool.mapTx.size()); for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); - mi != mempool.mapTx.end(); ++mi) - { + mi != mempool.mapTx.end(); ++mi) { double dPriority = mi->GetPriority(nHeight); CAmount dummy; mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy); @@ -205,8 +200,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, CTxMemPool::indexed_transaction_set::index::type::iterator mi = mempool.mapTx.get().begin(); CTxMemPool::txiter iter; - while (mi != mempool.mapTx.get().end() || !clearedTxs.empty()) - { + while (mi != mempool.mapTx.get().end() || !clearedTxs.empty()) { bool priorityTx = false; if (fPriorityBlock && !vecPriority.empty()) { // add a tx from priority queue to fill the blockprioritysize priorityTx = true; @@ -214,12 +208,10 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, actualPriority = vecPriority.front().first; std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer); vecPriority.pop_back(); - } - else if (clearedTxs.empty()) { // add tx with next highest score + } else if (clearedTxs.empty()) { // add tx with next highest score iter = mempool.mapTx.project<0>(mi); mi++; - } - else { // try to add a previously postponed child tx + } else { // try to add a previously postponed child tx iter = clearedTxs.top(); clearedTxs.pop(); } @@ -230,8 +222,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, const CTransaction& tx = iter->GetTx(); bool fOrphan = false; - BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter)) - { + BOOST_FOREACH (CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter)) { if (!inBlock.count(parent)) { fOrphan = true; break; @@ -239,7 +230,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, } if (fOrphan) { if (priorityTx) - waitPriMap.insert(std::make_pair(iter,actualPriority)); + waitPriMap.insert(std::make_pair(iter, actualPriority)); else waitSet.insert(iter); continue; @@ -247,16 +238,16 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, unsigned int nTxSize = iter->GetTxSize(); if (fPriorityBlock && - (nBlockSize + nTxSize >= nBlockPrioritySize || !AllowFree(actualPriority))) { + (nBlockSize + nTxSize >= nBlockPrioritySize || !AllowFree(actualPriority))) { fPriorityBlock = false; waitPriMap.clear(); } if (!priorityTx && - (iter->GetModifiedFee() < ::minRelayTxFee.GetFee(nTxSize) && nBlockSize >= nBlockMinSize)) { + (iter->GetModifiedFee() < ::minRelayTxFee.GetFee(nTxSize) && nBlockSize >= nBlockMinSize)) { break; } if (nBlockSize + nTxSize >= nBlockMaxSize) { - if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) { + if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) { break; } // Once we're within 1000 bytes of a full block, only look at 50 more txs @@ -288,29 +279,26 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, nBlockSigOps += nTxSigOps; nFees += nTxFees; - if (fPrintPriority) - { + if (fPrintPriority) { double dPriority = iter->GetPriority(nHeight); CAmount dummy; mempool.ApplyDeltas(tx.GetHash(), dPriority, dummy); LogPrintf("priority %.1f fee %s txid %s\n", - dPriority, CFeeRate(iter->GetModifiedFee(), nTxSize).ToString(), tx.GetHash().ToString()); + dPriority, CFeeRate(iter->GetModifiedFee(), nTxSize).ToString(), tx.GetHash().ToString()); } inBlock.insert(iter); // Add transactions that depend on this one to the priority queue - BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter)) - { + BOOST_FOREACH (CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter)) { if (fPriorityBlock) { waitPriIter wpiter = waitPriMap.find(child); if (wpiter != waitPriMap.end()) { - vecPriority.push_back(TxCoinAgePriority(wpiter->second,child)); + vecPriority.push_back(TxCoinAgePriority(wpiter->second, child)); std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer); waitPriMap.erase(wpiter); } - } - else { + } else { if (waitSet.count(child)) { clearedTxs.push(child); waitSet.erase(child); @@ -321,7 +309,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, CDynamicAddress address; CFluidEntry prevFluidIndex = pindexPrev->fluidParams; - CAmount fluidIssuance = 0, blockReward = getBlockSubsidyWithOverride(nHeight, prevFluidIndex.blockReward); + CAmount fluidIssuance = 0, blockReward = getBlockSubsidyWithOverride(nHeight, prevFluidIndex.blockReward); bool areWeMinting = fluid.GetMintingInstructions(pindexPrev, address, fluidIssuance); // Compute regular coinbase transaction. @@ -332,12 +320,12 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, } else { txNew.vout[0].nValue = blockReward; } - + txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; CScript script; - - if (areWeMinting) { + + if (areWeMinting) { // Pick out the amount of issuance txNew.vout[0].nValue -= fluidIssuance; @@ -362,21 +350,21 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); - + CAmount blockAmount = blockReward + fluidIssuance; - LogPrintf("CreateNewBlock(): Computed Miner Block Reward is %ld DYN\n", FormatMoney(blockAmount)); + LogPrintf("CreateNewBlock(): Computed Miner Block Reward is %ld DYN\n", FormatMoney(blockAmount)); // Update block coinbase pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; // Fill in header - pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); - CValidationState state; + CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { LogPrintf("CreateNewBlock(): Generated Transaction:\n%s\n", txNew.ToString()); throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); @@ -390,13 +378,12 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned { // Update nExtraNonce static uint256 hashPrevBlock; - if (hashPrevBlock != pblock->hashPrevBlock) - { + if (hashPrevBlock != pblock->hashPrevBlock) { nExtraNonce = 0; hashPrevBlock = pblock->hashPrevBlock; } ++nExtraNonce; - unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 + unsigned int nHeight = pindexPrev->nHeight + 1; // Height first in coinbase required for block.version=2 CMutableTransaction txCoinbase(pblock->vtx[0]); txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; assert(txCoinbase.vin[0].scriptSig.size() <= 100); @@ -440,7 +427,7 @@ int64_t GetGPUHashRate() // //bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) //{ - // Write the first 76 bytes of the block header to a double-SHA256 state. +// Write the first 76 bytes of the block header to a double-SHA256 state. // CHash256 hasher; // CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); // ss << *pblock; @@ -450,16 +437,16 @@ int64_t GetGPUHashRate() // while (true) { // nNonce++; - // Write the last 4 bytes of the block header (the nonce) to a copy of - // the double-SHA256 state, and compute the result. +// Write the last 4 bytes of the block header (the nonce) to a copy of +// the double-SHA256 state, and compute the result. // CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash); - // Return the nonce if the hash has at least some zero bits, - // caller will check if it has enough to reach the target +// Return the nonce if the hash has at least some zero bits, +// caller will check if it has enough to reach the target // if (((uint16_t*)phash)[15] == 0) // return true; - // If nothing found after trying for a while, return -1 +// If nothing found after trying for a while, return -1 // if ((nNonce & 0xfff) == 0) // return false; // }/ @@ -502,448 +489,331 @@ static void WaitForNetworkInit(const CChainParams& chainparams, CConnman& connma } } } -#ifdef ENABLE_GPU -static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex) { - std::string dev = "GPU"; - LogPrintf("DynamicMinerGPU -- started #%u@%s\n", nDeviceIndex, dev); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread("dynamic-gpu-miner"); - double* dHashesPerSec = &dGPUHashesPerSec; +namespace miner +{ +class BaseMiner +{ +private: + const CChainParams& chainparams; + CConnman& connman; + + virtual static boost::thread_group* thread_group() = 0; + +public: + BaseMiner(const CChainParams& chainparams, CConnman& connman) + : chainparams(chainparams), + connman(connman) {} + + static boost::thread_group* + ThreadGroup(bool fInit = true, bool fRestart = true) + { + boost::thread_group* minerThreads = this->thread_group(); + if (fRestart && minerThreads != NULL) { + minerThreads->interrupt_all(); + delete minerThreads; + minerThreads = NULL; + } + if (fInit && minerThreads == NULL) { + minerThreads = new boost::thread_group(); + } + return minerThreads; + } + + static void Shutdown() + { + this->ThreadGroup(false); + } + +private: + std::string deviceName; + double* dHashesPerSec; unsigned int nExtraNonce = 0; + std::shared_ptr coinbaseScript; - boost::shared_ptr coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); + int64_t nStart; + arith_uint256 hashTarget; - Argon2GPUContext global; - auto& devices = global.getAllDevices(); - auto& device = devices[nDeviceIndex]; - Argon2GPUProgramContext context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10); - Argon2GPUParams params((std::size_t)OUTPUT_BYTES, 2, 500, 8); - Argon2GPU processingUnit(&context, ¶ms, &device, 1, false, false); - std::size_t batchSizeTarget = device.getTotalMemory() / 512e3; - - try { + void Init() + { + LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, nDeviceIndex); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("dynamic-cpu-miner"); + GetMainSignals().ScriptForMining(coinbaseScript); + } + + void ValidateCoinbase() + { // Throw an error if no script was provided. This can happen // due to some internal error but also if the keypool is empty. // In the latter case, already the pointer is NULL. if (!coinbaseScript || coinbaseScript->reserveScript.empty()) throw std::runtime_error("No coinbase script available (mining requires a wallet)"); + } - while (true) { - // Wait for blocks if required - WaitForNetworkInit(chainparams, connman); - - // - // Create new block - // - unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); - std::unique_ptr pblocktemplate; - if(!pindexPrev) break; - - pblocktemplate = std::unique_ptr (CreateNewBlock(chainparams, coinbaseScript->reserveScript)); - - if (!pblocktemplate.get()) - { - LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", dev); - return; - } - CBlock *pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - LogPrintf("DynamicMiner%s -- Running miner with %u transactions in block (%u bytes)\n", dev, pblock->vtx.size(), - ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - - // - // Search - // - int64_t nStart = GetTime(); - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - uint256 hash; - while (true) - { - unsigned int nHashesDone = 0; - - // current batch size - std::size_t batchSize = batchSizeTarget; - - // set batch input - static unsigned char pblank[1]; - for (std::size_t i = 0; i < batchSizeTarget; i++) { - const auto pBegin = BEGIN(pblock->nVersion); - const auto pEnd = END(pblock->nNonce); - const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); - // input is copied onto memory buffer - pu->setInputAndSalt(i, input, INPUT_BYTES); - // increment block nonce - pblock->nNonce += 1; - // increment hashes done - nHashesDone += 1; - // TODO(crackcomm): is this only to count hashes? - if ((pblock->nNonce & 0xFF) == 0) { - batchSize = i + 1; - break; - } - } - - // start GPU processing - pu->beginProcessing(); - // wait for results - pu->endProcessing(); - // check batch results - for (std::size_t i = 0; i < batchSize; i++) { - pu->getHash(i, (uint8_t*)&hash); - if (UintToArith256(hash) <= hashTarget) { - // Found a solution - //assert(hash == pblock->GetHash()); - SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", dev, hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, chainparams, &connman); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - coinbaseScript->KeepScript(); - - // In regression test mode, stop mining after a block is found. - if (chainparams.MineBlocksOnDemand()) - throw boost::thread_interrupted(); - - break; - } - } - - // Meter hashes/seconds - static int64_t nHashCounter = 0; - static int64_t nLogTime = 0; - - if (nHPSTimerStart == 0) - { - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - } - else - nHashCounter += nHashesDone; - - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - static CCriticalSection cs; - { - LOCK(cs); - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - if (GetTime() - nLogTime > 30 * 60) - { - nLogTime = GetTime(); - LogPrintf("gpu hashmeter %6.0f khash/s\n", *dHashesPerSec / 1000.0); - } - } - } - } - - // Check for stop or if block needs to be rebuilt - boost::this_thread::interruption_point(); - // Regtest mode doesn't require peers - if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && chainparams.MiningRequiresPeers()) - break; - if (pblock->nNonce >= 0xffff0000) - break; - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; - if (pindexPrev != chainActive.Tip()) - break; + void ProcessFoundSolution(CBlock* pblock, const uint256& hash) + { + // Found a solution + SetThreadPriority(THREAD_PRIORITY_NORMAL); + LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", deviceName, hash.GetHex(), hashTarget.GetHex()); + ProcessBlockFound(pblock, chainparams, &connman); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + coinbaseScript->KeepScript(); + // In regression test mode, stop mining after a block is found. + if (chainparams.MineBlocksOnDemand()) + throw boost::thread_interrupted(); + } - // Update nTime every few seconds - if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) - break; // Recreate the block if the clock has run backwards, - // so that we can use the correct time. - if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) - { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); - } - } + std::unique_ptr CreateNewBlock() + { + // Wait for blocks if required + WaitForNetworkInit(chainparams, connman); + // Create new block + unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + CBlockIndex* pindexPrev = chainActive.Tip(); + if (!pindexPrev) { + return std::nullptr; } + return CreateNewBlock(chainparams, coinbaseScript->reserveScript); } - catch (const boost::thread_interrupted&) + + void SomeChecks() { - LogPrintf("DynamicMinerGPU -- terminated\n"); - throw; + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + // Regtest mode doesn't require peers + if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && chainparams.MiningRequiresPeers()) + break; + if (pblock->nNonce >= 0xffff0000) + break; + if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (pindexPrev != chainActive.Tip()) + break; + + // Update nTime every few seconds + if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) + break; // Recreate the block if the clock has run backwards, + // so that we can use the correct time. + if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) { + // Changing pblock->nTime can change work required on testnet: + hashTarget.SetCompact(pblock->nBits); + } } - catch (const std::runtime_error &e) + + void CountHashes() { - LogPrintf("DynamicMinerGPU -- runtime error: %s\n", e.what()); - return; - } -} -#endif // ENABLE_GPU + // Meter hashes/seconds + static int64_t nHashCounter = 0; + static int64_t nLogTime = 0; -static void DynamicMinerCPU(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex) { - std::string dev = "CPU"; - LogPrintf("DynamicMinerCPU -- started #%u@%s\n", nDeviceIndex, dev); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread("dynamic-cpu-miner"); + if (nHPSTimerStart == 0) { + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + } else { + nHashCounter += nHashesDone; + } - double* dHashesPerSec = &dCPUHashesPerSec; - unsigned int nExtraNonce = 0; + static CCriticalSection cs; + if (GetTimeMillis() - nHPSTimerStart > 4000) { + LOCK(cs); + *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + if (GetTime() - nLogTime > 30 * 60) { + nLogTime = GetTime(); + LogPrintf("%s hashmeter %6.0f khash/s\n", deviceName, *dHashesPerSec / 1000.0); + } + } + } - boost::shared_ptr coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); + virtual unsigned int LoopTick(CBlock* pblock) = 0; - try { - // Throw an error if no script was provided. This can happen - // due to some internal error but also if the keypool is empty. - // In the latter case, already the pointer is NULL. - if (!coinbaseScript || coinbaseScript->reserveScript.empty()) - throw std::runtime_error("No coinbase script available (mining requires a wallet)"); +public: + void StartLoop() + { + this->Init(); - while (true) { - // Wait for blocks if required - WaitForNetworkInit(chainparams, connman); - - // - // Create new block - // - unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); - std::unique_ptr pblocktemplate; - if(!pindexPrev) break; - - pblocktemplate = std::unique_ptr (CreateNewBlock(chainparams, coinbaseScript->reserveScript)); - - if (!pblocktemplate.get()) - { - LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", dev); - return; - } - CBlock *pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - LogPrintf("DynamicMiner%s -- Running miner with %u transactions in block (%u bytes)\n", dev, pblock->vtx.size(), - ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - - // - // Search - // - int64_t nStart = GetTime(); - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - uint256 hash; - while (true) - { - unsigned int nHashesDone = 0; - - uint256 hash; - while (true) { - hash = pblock->GetHash(); - if (UintToArith256(hash) <= hashTarget) - { - // Found a solution - //pblock->nNonce = nNonce; - //assert(hash == pblock->GetHash()); - - SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", dev, hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, chainparams, &connman); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - coinbaseScript->KeepScript(); - - // In regression test mode, stop mining after a block is found. - if (chainparams.MineBlocksOnDemand()) - throw boost::thread_interrupted(); - - break; - } - pblock->nNonce += 1; - nHashesDone += 1; - if ((pblock->nNonce & 0xFF) == 0) - break; - } - - // Meter hashes/seconds - static int64_t nHashCounter = 0; - static int64_t nLogTime = 0; - - if (nHPSTimerStart == 0) - { - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - } - else - nHashCounter += nHashesDone; - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - static CCriticalSection cs; - { - LOCK(cs); - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - if (GetTime() - nLogTime > 30 * 60) - { - nLogTime = GetTime(); - LogPrintf("cpu hashmeter %6.0f khash/s\n", *dHashesPerSec / 1000.0); - } - } - } + try { + this->ValidateCoinbase(); + + while (true) { + std::unique_ptr pblocktemplate = this->CreateNewBlock(); + if (pblocktemplate) { + LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", deviceName); + return; } + CBlock* pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - // Check for stop or if block needs to be rebuilt - boost::this_thread::interruption_point(); - // Regtest mode doesn't require peers - if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && chainparams.MiningRequiresPeers()) - break; - if (pblock->nNonce >= 0xffff0000) - break; - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; - if (pindexPrev != chainActive.Tip()) - break; + LogPrintf("DynamicMiner%s -- Running miner with %u transactions in block (%u bytes)\n", deviceName, pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + + nStart = GetTime(); + hashTarget = arith_uint256().SetCompact(pblock->nBits); - // Update nTime every few seconds - if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) - break; // Recreate the block if the clock has run backwards, - // so that we can use the correct time. - if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) - { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); + // search + while (true) { + auto hashesDone = this->LoopTick(pblock); + this->CountHashes(hashesDone); + this->SomeChecks(); } } + } catch (const boost::thread_interrupted&) { + LogPrintf("DynamicMiner%s -- terminated\n", deviceName); + throw; + } catch (const std::runtime_error& e) { + LogPrintf("DynamicMiner%s -- runtime error: %s\n", deviceName, e.what()); + return; } } - catch (const boost::thread_interrupted&) + +} + +class CPUMiner : public BaseMiner +{ +private: + virtual static boost::thread_group* thread_group() { - LogPrintf("DynamicMinerCPU -- terminated\n"); - throw; + static boost::thread_group* minerThreadsCPU = NULL; + return minerThreadsCPU; } - catch (const std::runtime_error &e) + +public: + BaseMiner(const CChainParams& chainparams, CConnman& connman) + : BaseMiner(chainparams, connman), + deviceName("CPU"), + dHashesPerSec(&dCPUHashesPerSec) { - LogPrintf("DynamicMinerCPU -- runtime error: %s\n", e.what()); - return; } -} -// TODO: that part changed in bitcoin, we are using a mix with old one here for now -static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex, bool fGPU) -{ -#ifdef ENABLE_GPU - if (fGPU) { - DynamicMinerGPU(chainparams, connman, nDeviceIndex); - } - else { - DynamicMinerCPU(chainparams, connman, nDeviceIndex); +private: + unsigned int + LoopTick(CBlock* pblock) + { + unsigned int nHashesDone = 0; + while (true) { + uint256 hash = pblock->GetHash(); + if (UintToArith256(hash) <= hashTarget) { + ProcessFoundSolution(pblock, hash); + break; + } + pblock->nNonce += 1; + nHashesDone += 1; + if ((pblock->nNonce & 0xFF) == 0) + break; + } + return nHashesDone; } -#else - DynamicMinerCPU(chainparams, connman, nDeviceIndex); -#endif // ENABLE_GPU } -static boost::thread_group* GetCPUMinerThreads(bool fInit = true, bool fRestart = true) +// #ifdef ENABLE_GPU +class GPUMiner : public BaseMiner { - static boost::thread_group* minerThreadsCPU = NULL; - if (fRestart && minerThreadsCPU != NULL) { - minerThreadsCPU->interrupt_all(); - delete minerThreadsCPU; - minerThreadsCPU = NULL; - } - if (fInit && minerThreadsCPU == NULL) { - minerThreadsCPU = new boost::thread_group(); +private: + Argon2GPUParams params; + Argon2GPUDevice device; + Argon2GPUContext global; + Argon2GPUProgramContext context; + Argon2GPU processingUnit; + + std::size_t batchSizeTarget; + + virtual static boost::thread_group* thread_group() + { + static boost::thread_group* minerThreadsGPU = NULL; + return minerThreadsGPU; } - return minerThreadsCPU; -} -static boost::thread_group* GetGPUMinerThreads(bool fInit = true, bool fRestart = true) -{ - static boost::thread_group* minerThreadsGPU = NULL; - if (fRestart && minerThreadsGPU != NULL) { - minerThreadsGPU->interrupt_all(); - delete minerThreadsGPU; - minerThreadsGPU = NULL; +public: + GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) + : BaseMiner(chainparams, connman), + deviceName("GPU"), + dHashesPerSec(&dGPUHashesPerSec), + device(global.getAllDevices()[deviceIndex]), + params((std::size_t)OUTPUT_BYTES, 2, 500, 8), + context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), + processingUnit(&context, ¶ms, &device, 1, false, false), + batchSizeTarget(device.getTotalMemory() / 512e3) + { } - if (fInit && minerThreadsGPU == NULL) { - minerThreadsGPU = new boost::thread_group(); + +private: + unsigned int + LoopTick(CBlock* pblock) + { + unsigned int nHashesDone = 0; + + // current batch size + std::size_t batchSize = batchSizeTarget; + + // set batch input + static unsigned char pblank[1]; + for (std::size_t i = 0; i < batchSizeTarget; i++) { + const auto pBegin = BEGIN(pblock->nVersion); + const auto pEnd = END(pblock->nNonce); + const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); + // input is copied onto memory buffer + pu->setInputAndSalt(i, input, INPUT_BYTES); + // increment block nonce + pblock->nNonce += 1; + // increment hashes done + nHashesDone += 1; + // TODO(crackcomm): is this only to count hashes? + if ((pblock->nNonce & 0xFF) == 0) { + batchSize = i + 1; + break; + } + } + // start GPU processing + pu->beginProcessing(); + // wait for results + pu->endProcessing(); + // check batch results + uint256 hash; + for (std::size_t i = 0; i < batchSize; i++) { + pu->getHash(i, (uint8_t*)&hash); + if (UintToArith256(hash) <= hashTarget) { + ProcessFoundSolution(pblock, hash); + break; + } + } + return nHashesDone; } - return minerThreadsGPU; } +// #endif // ENABLE_GPU + +} // namespace miner -static boost::thread_group* GetMinerThreads(bool fGPU = false, bool fInit = true, bool fRestart = true) +// #ifdef ENABLE_GPU +static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex) { - if (fGPU) { - return GetGPUMinerThreads(fInit, fRestart); - } - return GetCPUMinerThreads(fInit, fRestart); + miner::GPUMiner miner(chainparams, connman, nDeviceIndex); + miner->StartLoop(); } +// #endif // ENABLE_GPU -void AutoTuneDeviceThreads(const CChainParams& chainparams, CConnman& connman, boost::optional nGPUDeviceIndex = boost::none) +static void DynamicMinerCPU(const CChainParams& chainparams, CConnman& connman) { - bool fGPU = static_cast(nGPUDeviceIndex); - // Threads - boost::thread* lastThread = NULL; - boost::thread_group* minerThreads = GetMinerThreads(fGPU); - - // Metrics - double nLastHashesPerSec = 0.0; - double* dHashesPerSec = fGPU ? &dGPUHashesPerSec : &dCPUHashesPerSec; - - // Device name - std::string dev = fGPU ? "GPU" : "CPU"; - - LogPrintf("Autotune hashmeter: %6.0f\n", *dHashesPerSec / 1000.0); - - // Start Dynamin miner threads on device - while (true) { - LogPrintf("Starting %s Miner thread #%u %6.0f khash/s\n", dev, minerThreads->size(), *dHashesPerSec / 1000.0); - std::size_t nThread = minerThreads->size(); - std::size_t device = nGPUDeviceIndex.value_or(nThread); - lastThread = minerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), boost::cref(device), boost::cref(fGPU))); - MilliSleep(10000); - - if (*dHashesPerSec > nLastHashesPerSec) { - nLastHashesPerSec = *dHashesPerSec; - continue; - } - - LogPrintf("Removing %s Miner thread #%u %6.0f khash/s\n", dev, minerThreads->size(), *dHashesPerSec / 1000.0); - minerThreads->remove_thread(lastThread); - break; - } - - LogPrintf("Autotune %s finished with hashrate %6.0f\n khash/s", dev, *dHashesPerSec / 1000.0); + miner::CPUMiner miner(chainparams, connman); + miner->StartLoop(); } -void GenerateAutoTuneDevice(const CChainParams& chainparams, CConnman& connman, bool fGPU) +static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, boost::optional nGPUDeviceIndex = boost::none) { #ifdef ENABLE_GPU - if (fGPU) { - // Start GPU threads - for (std::size_t device = 0; device < GetGPUDeviceCount(); device++) { - AutoTuneDeviceThreads(chainparams, connman, device); - } - return; + if (nGPUDeviceIndex) { + DynamicMinerGPU(chainparams, connman, nGPUDeviceIndex.value()); + } else { + DynamicMinerCPU(chainparams, connman); } -#endif - - AutoTuneDeviceThreads(chainparams, connman); -} - -void GenerateDynamicsAutoTune(const CChainParams& chainparams, CConnman& connman) -{ - // Wait for blocks if required - WaitForNetworkInit(chainparams, connman); - MilliSleep(30000); - - GenerateAutoTuneDevice(chainparams, connman, false); - GenerateAutoTuneDevice(chainparams, connman, true); +#else + DynamicMinerCPU(chainparams, connman); +#endif // ENABLE_GPU } -void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman, bool fAutotune) +void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman) { - if (fAutotune) { - return GenerateDynamicsAutoTune(chainparams, connman); - } std::size_t devices = 0; #ifdef ENABLE_GPU devices = GetGPUDeviceCount(); @@ -957,7 +827,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai return; } - boost::thread_group* cpuMinerThreads = GetCPUMinerThreads(); + boost::thread_group* cpuMinerThreads = miner::CPUMiner::ThreadGroup(); int nNumCores = GetNumCores(); LogPrintf("DynamicMiner -- CPU Cores: %u\n", nNumCores); @@ -970,7 +840,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai while (cpuMinerThreads->size() < nCPUTarget) { std::size_t nThread = cpuMinerThreads->size(); LogPrintf("Starting CPU Miner thread #%u\n", nThread); - cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), nThread, false)); + cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman))); } if (nGPUThreads < 0) @@ -978,23 +848,23 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai // Start GPU threads std::size_t nGPUTarget = static_cast(nGPUThreads); - boost::thread_group* gpuMinerThreads = GetGPUMinerThreads(); + boost::thread_group* gpuMinerThreads = miner::GPUMiner::ThreadGroup(); for (std::size_t device = 0; device < devices; device++) { for (std::size_t i = 0; i < nGPUTarget; i++) { LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, device, devices); - gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), device, true)); + gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), device)); } } } void ShutdownCPUMiners() { - GetCPUMinerThreads(false); + miner::CPUMiner::Shutdown(); } void ShutdownGPUMiners() { - GetGPUMinerThreads(false); + miner::GPUMiner::Shutdown(); } void ShutdownMiners() diff --git a/src/miner.h b/src/miner.h index e93606d618..f2b3689619 100644 --- a/src/miner.h +++ b/src/miner.h @@ -10,9 +10,9 @@ #include "primitives/block.h" -#include -#include #include +#include +#include class CBlockIndex; class CChainParams; @@ -21,17 +21,18 @@ class CReserveKey; class CScript; class CWallet; -namespace Consensus { struct Params; }; +namespace Consensus +{ +struct Params; +}; static const bool DEFAULT_GENERATE = false; static const int DEFAULT_GENERATE_THREADS_CPU = -1; -// TODO(crackcom): Set to -1 after autotune tests static const int DEFAULT_GENERATE_THREADS_GPU = -1; static const bool DEFAULT_PRINTPRIORITY = false; -struct CBlockTemplate -{ +struct CBlockTemplate { CBlock block; std::vector vTxFees; std::vector vTxSigOps; @@ -42,7 +43,7 @@ struct CBlockTemplate bool CheckWork(const CChainParams& chainparams, CBlock* pblock, CWallet& wallet, CReserveKey& reservekey, CConnman* connman); #endif //ENABLE_WALLET /** Run the miner threads */ -void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman, bool fAutotune = false); +void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman); /** Shuts down all miner threads */ void ShutdownMiners(); /** Shuts down all CPU miner threads */ diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index d6eb624e20..1854d19c45 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -344,8 +344,7 @@ UniValue setgenerate(const JSONRPCRequest& request) LogPrintf("setgenerate cpu = %u, gpu = %u \n", nGenProcLimit, nGenProcLimitGPU); if (fGenerate) { - bool fAutotune = nGenProcLimit == -1 && nGenProcLimitGPU == -1; - GenerateDynamics(nGenProcLimit, nGenProcLimitGPU, Params(), *g_connman, fAutotune); + GenerateDynamics(nGenProcLimit, nGenProcLimitGPU, Params(), *g_connman); } else { ShutdownMiners(); } From a8c95188b17355e487287fb3acc0c6d1be9fa6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 03:54:08 +0200 Subject: [PATCH 0116/1653] use shared_ptr to manage thread_group ptr --- src/miner.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 4bca4f2a49..197ac57cbf 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -498,7 +498,7 @@ class BaseMiner const CChainParams& chainparams; CConnman& connman; - virtual static boost::thread_group* thread_group() = 0; + virtual static std::shared_ptr* thread_group() = 0; public: BaseMiner(const CChainParams& chainparams, CConnman& connman) @@ -508,16 +508,15 @@ class BaseMiner static boost::thread_group* ThreadGroup(bool fInit = true, bool fRestart = true) { - boost::thread_group* minerThreads = this->thread_group(); - if (fRestart && minerThreads != NULL) { + auto minerThreads = this->thread_group(); + if (fRestart && minerThreads) { minerThreads->interrupt_all(); - delete minerThreads; - minerThreads = NULL; + minerThreads.reset(std::nullptr); } - if (fInit && minerThreads == NULL) { - minerThreads = new boost::thread_group(); + if (fInit && !minerThreads) { + minerThreads.reset(new boost::thread_group()); } - return minerThreads; + return minerThreads.get(); } static void Shutdown() @@ -673,10 +672,10 @@ class BaseMiner class CPUMiner : public BaseMiner { private: - virtual static boost::thread_group* thread_group() + virtual static std::shared_ptr* thread_group() { - static boost::thread_group* minerThreadsCPU = NULL; - return minerThreadsCPU; + static std::shared_ptr minerThreadsCPU = NULL; + return &minerThreadsCPU; } public: @@ -719,10 +718,10 @@ class GPUMiner : public BaseMiner std::size_t batchSizeTarget; - virtual static boost::thread_group* thread_group() + virtual static std::shared_ptr* thread_group() { - static boost::thread_group* minerThreadsGPU = NULL; - return minerThreadsGPU; + static std::shared_ptr minerThreadsGPU = NULL; + return &minerThreadsGPU; } public: From 7afd8e7a811c80305dcd3b7ea393f97af33dc787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 03:57:25 +0200 Subject: [PATCH 0117/1653] rename check function and fix breaks --- src/miner.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 197ac57cbf..e9f094327c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -576,28 +576,29 @@ class BaseMiner return CreateNewBlock(chainparams, coinbaseScript->reserveScript); } - void SomeChecks() + bool LoopChecks() { // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); // Regtest mode doesn't require peers if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && chainparams.MiningRequiresPeers()) - break; + return false; if (pblock->nNonce >= 0xffff0000) - break; + return false; if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; + return false; if (pindexPrev != chainActive.Tip()) - break; + return false; // Update nTime every few seconds if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) - break; // Recreate the block if the clock has run backwards, - // so that we can use the correct time. + return false; // Recreate the block if the clock has run backwards, + // so that we can use the correct time. if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) { // Changing pblock->nTime can change work required on testnet: hashTarget.SetCompact(pblock->nBits); } + return true; } void CountHashes() @@ -655,7 +656,8 @@ class BaseMiner while (true) { auto hashesDone = this->LoopTick(pblock); this->CountHashes(hashesDone); - this->SomeChecks(); + if (!this->LoopChecks()) + break; } } } catch (const boost::thread_interrupted&) { From c5a6f89cf5016749aac3ba80175fc07fd1555974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:01:16 +0200 Subject: [PATCH 0118/1653] fix optional dereference --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index e9f094327c..0a4aac0a72 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -804,7 +804,7 @@ static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, boo { #ifdef ENABLE_GPU if (nGPUDeviceIndex) { - DynamicMinerGPU(chainparams, connman, nGPUDeviceIndex.value()); + DynamicMinerGPU(chainparams, connman, *nGPUDeviceIndex); } else { DynamicMinerCPU(chainparams, connman); } From 07d1a166e946351e31924d11658c7ca2d639a844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:02:08 +0200 Subject: [PATCH 0119/1653] remove static from thread_group --- src/miner.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 0a4aac0a72..65a9b1a73d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -498,14 +498,14 @@ class BaseMiner const CChainParams& chainparams; CConnman& connman; - virtual static std::shared_ptr* thread_group() = 0; + virtual std::shared_ptr* thread_group() = 0; public: BaseMiner(const CChainParams& chainparams, CConnman& connman) : chainparams(chainparams), connman(connman) {} - static boost::thread_group* + boost::thread_group* ThreadGroup(bool fInit = true, bool fRestart = true) { auto minerThreads = this->thread_group(); @@ -674,7 +674,7 @@ class BaseMiner class CPUMiner : public BaseMiner { private: - virtual static std::shared_ptr* thread_group() + virtual std::shared_ptr* thread_group() { static std::shared_ptr minerThreadsCPU = NULL; return &minerThreadsCPU; @@ -720,7 +720,7 @@ class GPUMiner : public BaseMiner std::size_t batchSizeTarget; - virtual static std::shared_ptr* thread_group() + virtual std::shared_ptr* thread_group() { static std::shared_ptr minerThreadsGPU = NULL; return &minerThreadsGPU; From 8f802619c3cb4806839b6ed2a64698b93402d58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:02:58 +0200 Subject: [PATCH 0120/1653] rename processing unit --- src/miner.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 65a9b1a73d..24e124216a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -755,7 +755,7 @@ class GPUMiner : public BaseMiner const auto pEnd = END(pblock->nNonce); const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); // input is copied onto memory buffer - pu->setInputAndSalt(i, input, INPUT_BYTES); + processingUnit->setInputAndSalt(i, input, INPUT_BYTES); // increment block nonce pblock->nNonce += 1; // increment hashes done @@ -767,13 +767,13 @@ class GPUMiner : public BaseMiner } } // start GPU processing - pu->beginProcessing(); + processingUnit->beginProcessing(); // wait for results - pu->endProcessing(); + processingUnit->endProcessing(); // check batch results uint256 hash; for (std::size_t i = 0; i < batchSize; i++) { - pu->getHash(i, (uint8_t*)&hash); + processingUnit->getHash(i, (uint8_t*)&hash); if (UintToArith256(hash) <= hashTarget) { ProcessFoundSolution(pblock, hash); break; From 4d14b9119f3afa3578ed48ed762e894805e7ba17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:04:04 +0200 Subject: [PATCH 0121/1653] bring back enable_gpu ifdef --- src/miner.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 24e124216a..60f11182e1 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -668,8 +668,7 @@ class BaseMiner return; } } - -} +}; class CPUMiner : public BaseMiner { @@ -706,9 +705,9 @@ class CPUMiner : public BaseMiner } return nHashesDone; } -} +}; -// #ifdef ENABLE_GPU +#ifdef ENABLE_GPU class GPUMiner : public BaseMiner { private: @@ -781,8 +780,8 @@ class GPUMiner : public BaseMiner } return nHashesDone; } -} -// #endif // ENABLE_GPU +}; +#endif // ENABLE_GPU } // namespace miner From c67417da1b2d71811d9b4a7c1a88f95e803df481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:05:20 +0200 Subject: [PATCH 0122/1653] mark function as override --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 60f11182e1..354a2e93ce 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -673,7 +673,7 @@ class BaseMiner class CPUMiner : public BaseMiner { private: - virtual std::shared_ptr* thread_group() + virtual std::shared_ptr* thread_group() override { static std::shared_ptr minerThreadsCPU = NULL; return &minerThreadsCPU; @@ -719,7 +719,7 @@ class GPUMiner : public BaseMiner std::size_t batchSizeTarget; - virtual std::shared_ptr* thread_group() + virtual std::shared_ptr* thread_group() override { static std::shared_ptr minerThreadsGPU = NULL; return &minerThreadsGPU; From 400290f81d08ca049a18be948e103e50c92e4e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:06:15 +0200 Subject: [PATCH 0123/1653] fix count hashes function params --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 354a2e93ce..488a5bbef3 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -601,7 +601,7 @@ class BaseMiner return true; } - void CountHashes() + void CountHashes(unsigned int nHashesDone) { // Meter hashes/seconds static int64_t nHashCounter = 0; From e24709e5aec90c095d3832efd342bf9e2f78db16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:11:15 +0200 Subject: [PATCH 0124/1653] fix ptr ptr semantics --- src/miner.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 488a5bbef3..63205e9cb9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -509,14 +509,14 @@ class BaseMiner ThreadGroup(bool fInit = true, bool fRestart = true) { auto minerThreads = this->thread_group(); - if (fRestart && minerThreads) { - minerThreads->interrupt_all(); - minerThreads.reset(std::nullptr); + if (fRestart && *minerThreads) { + (*minerThreads)->interrupt_all(); + minerThreads->reset(std::nullptr); } - if (fInit && !minerThreads) { - minerThreads.reset(new boost::thread_group()); + if (fInit && !*minerThreads) { + minerThreads->reset(new boost::thread_group()); } - return minerThreads.get(); + return minerThreads->get(); } static void Shutdown() From da351112f96b1b1f9028960e2b80674afd2f189a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:43:43 +0200 Subject: [PATCH 0125/1653] move threads to namespace --- src/miner.cpp | 95 +++++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 63205e9cb9..f268cefa98 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -492,38 +492,56 @@ static void WaitForNetworkInit(const CChainParams& chainparams, CConnman& connma namespace miner { +namespace threads +{ +// CPU threads +struct CPU { +}; +// GPU threads +struct GPU { +}; + +// we are using template to instantiate two +// distinct threads groups for CPU and GPU +template +static boost::thread_group* +ThreadGroup(bool fInit = true, bool fRestart = true) +{ + static boost::thread_group* minerThreads = std::nullptr; + if (fRestart && *minerThreads) { + minerThreads->interrupt_all(); + delete minerThreads; + minerThreads = std::nullptr; + } + if (fInit && !*minerThreads) { + minerThreads = new boost::thread_group(); + } + return minerThreads; +} + +// shutdown all miner threads +template +static void Shutdown() +{ + ThreadGroup(false); +} +} // namespace threads + +using threads::Shutdown; +using threads::ThreadGroup; + +template class BaseMiner { private: const CChainParams& chainparams; CConnman& connman; - virtual std::shared_ptr* thread_group() = 0; - public: BaseMiner(const CChainParams& chainparams, CConnman& connman) : chainparams(chainparams), connman(connman) {} - boost::thread_group* - ThreadGroup(bool fInit = true, bool fRestart = true) - { - auto minerThreads = this->thread_group(); - if (fRestart && *minerThreads) { - (*minerThreads)->interrupt_all(); - minerThreads->reset(std::nullptr); - } - if (fInit && !*minerThreads) { - minerThreads->reset(new boost::thread_group()); - } - return minerThreads->get(); - } - - static void Shutdown() - { - this->ThreadGroup(false); - } - private: std::string deviceName; double* dHashesPerSec; @@ -533,6 +551,8 @@ class BaseMiner int64_t nStart; arith_uint256 hashTarget; + virtual unsigned int LoopTick(CBlock* pblock) = 0; + void Init() { LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, nDeviceIndex); @@ -627,10 +647,8 @@ class BaseMiner } } - virtual unsigned int LoopTick(CBlock* pblock) = 0; - public: - void StartLoop() + static void StartLoop() { this->Init(); @@ -672,13 +690,6 @@ class BaseMiner class CPUMiner : public BaseMiner { -private: - virtual std::shared_ptr* thread_group() override - { - static std::shared_ptr minerThreadsCPU = NULL; - return &minerThreadsCPU; - } - public: BaseMiner(const CChainParams& chainparams, CConnman& connman) : BaseMiner(chainparams, connman), @@ -688,8 +699,8 @@ class CPUMiner : public BaseMiner } private: - unsigned int - LoopTick(CBlock* pblock) + virtual unsigned int + LoopTick(CBlock* pblock) override { unsigned int nHashesDone = 0; while (true) { @@ -719,12 +730,6 @@ class GPUMiner : public BaseMiner std::size_t batchSizeTarget; - virtual std::shared_ptr* thread_group() override - { - static std::shared_ptr minerThreadsGPU = NULL; - return &minerThreadsGPU; - } - public: GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) : BaseMiner(chainparams, connman), @@ -739,8 +744,8 @@ class GPUMiner : public BaseMiner } private: - unsigned int - LoopTick(CBlock* pblock) + virtual unsigned int + LoopTick(CBlock* pblock) override { unsigned int nHashesDone = 0; @@ -827,7 +832,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai return; } - boost::thread_group* cpuMinerThreads = miner::CPUMiner::ThreadGroup(); + boost::thread_group* cpuMinerThreads = miner::ThreadGroup(); int nNumCores = GetNumCores(); LogPrintf("DynamicMiner -- CPU Cores: %u\n", nNumCores); @@ -848,7 +853,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai // Start GPU threads std::size_t nGPUTarget = static_cast(nGPUThreads); - boost::thread_group* gpuMinerThreads = miner::GPUMiner::ThreadGroup(); + boost::thread_group* gpuMinerThreads = miner::ThreadGroup(); for (std::size_t device = 0; device < devices; device++) { for (std::size_t i = 0; i < nGPUTarget; i++) { LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, device, devices); @@ -859,12 +864,12 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai void ShutdownCPUMiners() { - miner::CPUMiner::Shutdown(); + miner::Shutdown(); } void ShutdownGPUMiners() { - miner::GPUMiner::Shutdown(); + miner::Shutdown(); } void ShutdownMiners() From 3c2e49f5e3328bcef34a89371c2c17d232a41aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:46:02 +0200 Subject: [PATCH 0126/1653] rename namespace to miners --- src/miner.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index f268cefa98..a0431cfc74 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -490,7 +490,7 @@ static void WaitForNetworkInit(const CChainParams& chainparams, CConnman& connma } } -namespace miner +namespace miners { namespace threads { @@ -788,19 +788,19 @@ class GPUMiner : public BaseMiner }; #endif // ENABLE_GPU -} // namespace miner +} // namespace miners // #ifdef ENABLE_GPU static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex) { - miner::GPUMiner miner(chainparams, connman, nDeviceIndex); + miners::GPUMiner miner(chainparams, connman, nDeviceIndex); miner->StartLoop(); } // #endif // ENABLE_GPU static void DynamicMinerCPU(const CChainParams& chainparams, CConnman& connman) { - miner::CPUMiner miner(chainparams, connman); + miners::CPUMiner miner(chainparams, connman); miner->StartLoop(); } @@ -832,7 +832,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai return; } - boost::thread_group* cpuMinerThreads = miner::ThreadGroup(); + boost::thread_group* cpuMinerThreads = miners::ThreadGroup(); int nNumCores = GetNumCores(); LogPrintf("DynamicMiner -- CPU Cores: %u\n", nNumCores); @@ -853,7 +853,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai // Start GPU threads std::size_t nGPUTarget = static_cast(nGPUThreads); - boost::thread_group* gpuMinerThreads = miner::ThreadGroup(); + boost::thread_group* gpuMinerThreads = miners::ThreadGroup(); for (std::size_t device = 0; device < devices; device++) { for (std::size_t i = 0; i < nGPUTarget; i++) { LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, device, devices); @@ -864,12 +864,12 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai void ShutdownCPUMiners() { - miner::Shutdown(); + miners::Shutdown(); } void ShutdownGPUMiners() { - miner::Shutdown(); + miners::Shutdown(); } void ShutdownMiners() From cfaa26756e8809797306eb0b11c01722d450fb99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:47:11 +0200 Subject: [PATCH 0127/1653] fix miner start loop call --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index a0431cfc74..bcccb35ac7 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -794,14 +794,14 @@ class GPUMiner : public BaseMiner static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex) { miners::GPUMiner miner(chainparams, connman, nDeviceIndex); - miner->StartLoop(); + miner.StartLoop(); } // #endif // ENABLE_GPU static void DynamicMinerCPU(const CChainParams& chainparams, CConnman& connman) { miners::CPUMiner miner(chainparams, connman); - miner->StartLoop(); + miner.StartLoop(); } static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, boost::optional nGPUDeviceIndex = boost::none) From 55f9547d8883f234a7ae6da31ef2a9d5eec64d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:47:55 +0200 Subject: [PATCH 0128/1653] enable_gpu ifdef --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index bcccb35ac7..2ff86c86cf 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -790,13 +790,13 @@ class GPUMiner : public BaseMiner } // namespace miners -// #ifdef ENABLE_GPU +#ifdef ENABLE_GPU static void DynamicMinerGPU(const CChainParams& chainparams, CConnman& connman, std::size_t nDeviceIndex) { miners::GPUMiner miner(chainparams, connman, nDeviceIndex); miner.StartLoop(); } -// #endif // ENABLE_GPU +#endif // ENABLE_GPU static void DynamicMinerCPU(const CChainParams& chainparams, CConnman& connman) { From e9cde6990eecbf562aaedaab643bf1eb85134788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:52:16 +0200 Subject: [PATCH 0129/1653] move transactionsUdatedLast to base class --- src/miner.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 2ff86c86cf..9b5bb7a734 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -544,11 +544,14 @@ class BaseMiner private: std::string deviceName; + + int64_t nStart; double* dHashesPerSec; unsigned int nExtraNonce = 0; + unsigned int nTransactionsUpdatedLast; + std::shared_ptr coinbaseScript; - int64_t nStart; arith_uint256 hashTarget; virtual unsigned int LoopTick(CBlock* pblock) = 0; @@ -588,7 +591,7 @@ class BaseMiner // Wait for blocks if required WaitForNetworkInit(chainparams, connman); // Create new block - unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); if (!pindexPrev) { return std::nullptr; From 4e36befa8e7376d3ef49c11513e34497549616a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 04:59:47 +0200 Subject: [PATCH 0130/1653] use boost::shared_ptr as expected --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 9b5bb7a734..4c0c6c1dd3 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -550,7 +550,7 @@ class BaseMiner unsigned int nExtraNonce = 0; unsigned int nTransactionsUpdatedLast; - std::shared_ptr coinbaseScript; + boost::shared_ptr coinbaseScript; arith_uint256 hashTarget; From 4fc4e999590e19257171b40799527a9212a6fe47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:00:48 +0200 Subject: [PATCH 0131/1653] nullptr comparisons --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 4c0c6c1dd3..8a2b6dac7f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -508,12 +508,12 @@ static boost::thread_group* ThreadGroup(bool fInit = true, bool fRestart = true) { static boost::thread_group* minerThreads = std::nullptr; - if (fRestart && *minerThreads) { + if (fRestart && minerThreads != std::nullptr) { minerThreads->interrupt_all(); delete minerThreads; minerThreads = std::nullptr; } - if (fInit && !*minerThreads) { + if (fInit && minerThreads == std::nullptr) { minerThreads = new boost::thread_group(); } return minerThreads; From d3e4d8b611da3685754eadf2a7987c396bc29bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:02:42 +0200 Subject: [PATCH 0132/1653] remove unused assignment --- src/miner.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 8a2b6dac7f..9f0e4d9faf 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -846,8 +846,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai // Start CPU threads std::size_t nCPUTarget = static_cast(nCPUThreads); while (cpuMinerThreads->size() < nCPUTarget) { - std::size_t nThread = cpuMinerThreads->size(); - LogPrintf("Starting CPU Miner thread #%u\n", nThread); + LogPrintf("Starting CPU Miner thread #%u\n", cpuMinerThreads->size()); cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman))); } From d9e30b1513dd244f57e5543b52d33fc40b1faa6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:07:03 +0200 Subject: [PATCH 0133/1653] cleanup thread constructor --- src/miner.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 9f0e4d9faf..249c512ef5 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -822,21 +822,11 @@ static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, boo void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman) { - std::size_t devices = 0; -#ifdef ENABLE_GPU - devices = GetGPUDeviceCount(); - LogPrintf("DynamicMiner -- GPU Devices: %u\n", devices); -#else - LogPrintf("DynamicMiner -- GPU no support\n"); -#endif - - if (nCPUThreads == 0 && (devices == 0 || nGPUThreads == 0)) { - LogPrintf("DynamicMiner -- disabled -- CPU Threads set to zero\n"); + if (nCPUThreads == 0 && nGPUThreads == 0) { + LogPrintf("DynamicMiner -- disabled -- CPU and GPU Threads set to zero\n"); return; } - boost::thread_group* cpuMinerThreads = miners::ThreadGroup(); - int nNumCores = GetNumCores(); LogPrintf("DynamicMiner -- CPU Cores: %u\n", nNumCores); @@ -845,11 +835,16 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai // Start CPU threads std::size_t nCPUTarget = static_cast(nCPUThreads); + boost::thread_group* cpuMinerThreads = miners::ThreadGroup(); while (cpuMinerThreads->size() < nCPUTarget) { LogPrintf("Starting CPU Miner thread #%u\n", cpuMinerThreads->size()); cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman))); } +#ifdef ENABLE_GPU + std::size_t devices = GetGPUDeviceCount(); + LogPrintf("DynamicMiner -- GPU Devices: %u\n", devices); + if (nGPUThreads < 0) nGPUThreads = 4; @@ -862,6 +857,9 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), device)); } } +#else + LogPrintf("DynamicMiner -- GPU no support\n"); +#endif } void ShutdownCPUMiners() From 1711cf704e80892d5ec4b43c45afa93474f759fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:11:07 +0200 Subject: [PATCH 0134/1653] c++11 compatibility --- src/miner.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 249c512ef5..e95b498b6e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -119,7 +119,7 @@ bool CheckWork(const CChainParams& chainparams, const CBlock* pblock, CWallet& w std::unique_ptr CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn) { // Create new block - auto pblocktemplate = std::make_unique(); + std::unique_ptr pblocktemplate(new CBlockTemplate()); CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Create coinbase tx with fluid issuance @@ -507,13 +507,13 @@ template static boost::thread_group* ThreadGroup(bool fInit = true, bool fRestart = true) { - static boost::thread_group* minerThreads = std::nullptr; - if (fRestart && minerThreads != std::nullptr) { + static boost::thread_group* minerThreads = nullptr; + if (fRestart && minerThreads != nullptr) { minerThreads->interrupt_all(); delete minerThreads; - minerThreads = std::nullptr; + minerThreads = nullptr; } - if (fInit && minerThreads == std::nullptr) { + if (fInit && minerThreads == nullptr) { minerThreads = new boost::thread_group(); } return minerThreads; @@ -594,7 +594,7 @@ class BaseMiner nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); if (!pindexPrev) { - return std::nullptr; + return nullptr; } return CreateNewBlock(chainparams, coinbaseScript->reserveScript); } From bd1ed2c8db0dfdedcb79131abbdc19b8ce1fff45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:11:55 +0200 Subject: [PATCH 0135/1653] remove static from StartLoop --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index e95b498b6e..a5d865ad46 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -651,7 +651,7 @@ class BaseMiner } public: - static void StartLoop() + void StartLoop() { this->Init(); From 08f5572a00983f9663b0e025594a0f6bd41339bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:13:31 +0200 Subject: [PATCH 0136/1653] remove unused template from BaseMiner --- src/miner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index a5d865ad46..62a7e59ba4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -530,7 +530,6 @@ static void Shutdown() using threads::Shutdown; using threads::ThreadGroup; -template class BaseMiner { private: From 3e036bb42fb1aebe35f94960d83abc4460bba86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:14:44 +0200 Subject: [PATCH 0137/1653] provide pblock to LoopChecks --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 62a7e59ba4..ac70b9b73e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -598,7 +598,7 @@ class BaseMiner return CreateNewBlock(chainparams, coinbaseScript->reserveScript); } - bool LoopChecks() + bool LoopChecks(CBlock* pblock) { // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); @@ -676,7 +676,7 @@ class BaseMiner while (true) { auto hashesDone = this->LoopTick(pblock); this->CountHashes(hashesDone); - if (!this->LoopChecks()) + if (!this->LoopChecks(pblock)) break; } } From 17307fb68d74c3a46b1b916ed0af1a0572cd9e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:32:49 +0200 Subject: [PATCH 0138/1653] add device index to base class --- src/miner.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index ac70b9b73e..d686d89653 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -543,6 +543,7 @@ class BaseMiner private: std::string deviceName; + boost::optional deviceIndex; int64_t nStart; double* dHashesPerSec; @@ -557,7 +558,7 @@ class BaseMiner void Init() { - LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, nDeviceIndex); + LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, deviceIndex.value_or(0)); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("dynamic-cpu-miner"); GetMainSignals().ScriptForMining(coinbaseScript); @@ -735,6 +736,7 @@ class GPUMiner : public BaseMiner public: GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) : BaseMiner(chainparams, connman), + deviceIndex(deviceIndex), deviceName("GPU"), dHashesPerSec(&dGPUHashesPerSec), device(global.getAllDevices()[deviceIndex]), From 980b1f6afcbda3a214a1e0b8481862bc1f9666fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:33:27 +0200 Subject: [PATCH 0139/1653] remove name collison --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index d686d89653..895892c25f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -586,7 +586,7 @@ class BaseMiner throw boost::thread_interrupted(); } - std::unique_ptr CreateNewBlock() + std::unique_ptr CreateNewMinerBlock() { // Wait for blocks if required WaitForNetworkInit(chainparams, connman); @@ -659,7 +659,7 @@ class BaseMiner this->ValidateCoinbase(); while (true) { - std::unique_ptr pblocktemplate = this->CreateNewBlock(); + std::unique_ptr pblocktemplate = this->CreateNewMinerBlock(); if (pblocktemplate) { LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", deviceName); return; From a2058026a84a67c404b0dfd03e8cc61f6327e9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:37:54 +0200 Subject: [PATCH 0140/1653] track chain tip --- src/miner.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 895892c25f..a390bb5025 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -550,6 +550,7 @@ class BaseMiner unsigned int nExtraNonce = 0; unsigned int nTransactionsUpdatedLast; + CBlockIndex* pindexPrev; boost::shared_ptr coinbaseScript; arith_uint256 hashTarget; @@ -592,7 +593,7 @@ class BaseMiner WaitForNetworkInit(chainparams, connman); // Create new block nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); + pindexPrev = chainActive.Tip(); if (!pindexPrev) { return nullptr; } From dfa9dea8355652fe726006555f84106407b87f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 05:39:48 +0200 Subject: [PATCH 0141/1653] fix CPUMiner constructor --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index a390bb5025..8f8cc13aa4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -695,7 +695,7 @@ class BaseMiner class CPUMiner : public BaseMiner { public: - BaseMiner(const CChainParams& chainparams, CConnman& connman) + CPUMiner(const CChainParams& chainparams, CConnman& connman) : BaseMiner(chainparams, connman), deviceName("CPU"), dHashesPerSec(&dCPUHashesPerSec) From f1d63cbbab60bc50a3e201c4c16459ac214f2740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 06:01:54 +0200 Subject: [PATCH 0142/1653] move protected variables --- src/miner.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 8f8cc13aa4..68cfe73850 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -542,11 +542,7 @@ class BaseMiner connman(connman) {} private: - std::string deviceName; - boost::optional deviceIndex; - int64_t nStart; - double* dHashesPerSec; unsigned int nExtraNonce = 0; unsigned int nTransactionsUpdatedLast; @@ -557,6 +553,13 @@ class BaseMiner virtual unsigned int LoopTick(CBlock* pblock) = 0; +protected: + std::string deviceName; + boost::optional deviceIndex; + + double* dHashesPerSec; + +private: void Init() { LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, deviceIndex.value_or(0)); From fa4112dbc47ea6042b2f90ec53d49e6a285d2ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 06:02:23 +0200 Subject: [PATCH 0143/1653] fix non-pointer operand --- src/miner.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 68cfe73850..721bdff4a5 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -767,7 +767,7 @@ class GPUMiner : public BaseMiner const auto pEnd = END(pblock->nNonce); const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); // input is copied onto memory buffer - processingUnit->setInputAndSalt(i, input, INPUT_BYTES); + processingUnit.setInputAndSalt(i, input, INPUT_BYTES); // increment block nonce pblock->nNonce += 1; // increment hashes done @@ -779,13 +779,13 @@ class GPUMiner : public BaseMiner } } // start GPU processing - processingUnit->beginProcessing(); + processingUnit.beginProcessing(); // wait for results - processingUnit->endProcessing(); + processingUnit.endProcessing(); // check batch results uint256 hash; for (std::size_t i = 0; i < batchSize; i++) { - processingUnit->getHash(i, (uint8_t*)&hash); + processingUnit.getHash(i, (uint8_t*)&hash); if (UintToArith256(hash) <= hashTarget) { ProcessFoundSolution(pblock, hash); break; From db838615029df04d5698c983debebf7f4745e72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 06:03:14 +0200 Subject: [PATCH 0144/1653] move hashTarget to protected variables --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 721bdff4a5..8f04db6cce 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -549,8 +549,6 @@ class BaseMiner CBlockIndex* pindexPrev; boost::shared_ptr coinbaseScript; - arith_uint256 hashTarget; - virtual unsigned int LoopTick(CBlock* pblock) = 0; protected: @@ -559,6 +557,8 @@ class BaseMiner double* dHashesPerSec; + arith_uint256 hashTarget; + private: void Init() { From 0d65a4e53ae656b09201128eb786c015d695543d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 06:17:30 +0200 Subject: [PATCH 0145/1653] move constructor code to base --- src/miner.cpp | 52 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 8f04db6cce..f3aa610ec6 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -537,9 +537,12 @@ class BaseMiner CConnman& connman; public: - BaseMiner(const CChainParams& chainparams, CConnman& connman) + BaseMiner(const CChainParams& chainparams, CConnman& connman, double* hashesPerSec, std::string deviceName, boost::optional deviceIndex = boost::none) : chainparams(chainparams), - connman(connman) {} + connman(connman), + deviceName(deviceName), + deviceIndex(deviceIndex), + dHashesPerSec(hashesPerSec) {} private: int64_t nStart; @@ -549,8 +552,6 @@ class BaseMiner CBlockIndex* pindexPrev; boost::shared_ptr coinbaseScript; - virtual unsigned int LoopTick(CBlock* pblock) = 0; - protected: std::string deviceName; boost::optional deviceIndex; @@ -559,6 +560,21 @@ class BaseMiner arith_uint256 hashTarget; + void ProcessFoundSolution(CBlock* pblock, const uint256& hash) + { + // Found a solution + SetThreadPriority(THREAD_PRIORITY_NORMAL); + LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", deviceName, hash.GetHex(), hashTarget.GetHex()); + ProcessBlockFound(pblock, chainparams, &connman); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + coinbaseScript->KeepScript(); + // In regression test mode, stop mining after a block is found. + if (chainparams.MineBlocksOnDemand()) + throw boost::thread_interrupted(); + } + + virtual unsigned int LoopTick(CBlock* pblock) = 0; + private: void Init() { @@ -577,19 +593,6 @@ class BaseMiner throw std::runtime_error("No coinbase script available (mining requires a wallet)"); } - void ProcessFoundSolution(CBlock* pblock, const uint256& hash) - { - // Found a solution - SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", deviceName, hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, chainparams, &connman); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - coinbaseScript->KeepScript(); - // In regression test mode, stop mining after a block is found. - if (chainparams.MineBlocksOnDemand()) - throw boost::thread_interrupted(); - } - std::unique_ptr CreateNewMinerBlock() { // Wait for blocks if required @@ -699,13 +702,9 @@ class CPUMiner : public BaseMiner { public: CPUMiner(const CChainParams& chainparams, CConnman& connman) - : BaseMiner(chainparams, connman), - deviceName("CPU"), - dHashesPerSec(&dCPUHashesPerSec) - { - } + : BaseMiner(chainparams, connman, &dCPUHashesPerSec, "CPU") {} -private: +protected: virtual unsigned int LoopTick(CBlock* pblock) override { @@ -739,10 +738,7 @@ class GPUMiner : public BaseMiner public: GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) - : BaseMiner(chainparams, connman), - deviceIndex(deviceIndex), - deviceName("GPU"), - dHashesPerSec(&dGPUHashesPerSec), + : BaseMiner(chainparams, connman, &dGPUHashesPerSec, "GPU", deviceIndex), device(global.getAllDevices()[deviceIndex]), params((std::size_t)OUTPUT_BYTES, 2, 500, 8), context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), @@ -751,7 +747,7 @@ class GPUMiner : public BaseMiner { } -private: +protected: virtual unsigned int LoopTick(CBlock* pblock) override { From dd0cd62e47ad2465a555c4af6b2e917e1fabd4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 06:18:31 +0200 Subject: [PATCH 0146/1653] reorder constructor initialization --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index f3aa610ec6..660540dcfe 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -739,8 +739,8 @@ class GPUMiner : public BaseMiner public: GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) : BaseMiner(chainparams, connman, &dGPUHashesPerSec, "GPU", deviceIndex), - device(global.getAllDevices()[deviceIndex]), params((std::size_t)OUTPUT_BYTES, 2, 500, 8), + device(global.getAllDevices()[deviceIndex]), context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), processingUnit(&context, ¶ms, &device, 1, false, false), batchSizeTarget(device.getTotalMemory() / 512e3) From 095b41960810ba32648b6e78a75479ca35c59b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 06:33:53 +0200 Subject: [PATCH 0147/1653] fix boost::optional no value_or method error --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 660540dcfe..369b0be440 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -578,7 +578,7 @@ class BaseMiner private: void Init() { - LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, deviceIndex.value_or(0)); + LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, deviceIndex ? *deviceIndex : 0); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("dynamic-cpu-miner"); GetMainSignals().ScriptForMining(coinbaseScript); From 0fd066e376f3c40dba63ad9d50c89710a964de43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 06:45:25 +0200 Subject: [PATCH 0148/1653] explicit boost::none for boost::bind --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 369b0be440..423eb9fcb1 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -839,7 +839,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai boost::thread_group* cpuMinerThreads = miners::ThreadGroup(); while (cpuMinerThreads->size() < nCPUTarget) { LogPrintf("Starting CPU Miner thread #%u\n", cpuMinerThreads->size()); - cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman))); + cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), boost::none)); } #ifdef ENABLE_GPU From 920e62c219128a5544f5b48d8a3dde5104968020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 06:53:07 +0200 Subject: [PATCH 0149/1653] remove redundant DynamicMiner function --- src/miner.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 423eb9fcb1..800d7c8e09 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -808,19 +808,6 @@ static void DynamicMinerCPU(const CChainParams& chainparams, CConnman& connman) miner.StartLoop(); } -static void DynamicMiner(const CChainParams& chainparams, CConnman& connman, boost::optional nGPUDeviceIndex = boost::none) -{ -#ifdef ENABLE_GPU - if (nGPUDeviceIndex) { - DynamicMinerGPU(chainparams, connman, *nGPUDeviceIndex); - } else { - DynamicMinerCPU(chainparams, connman); - } -#else - DynamicMinerCPU(chainparams, connman); -#endif // ENABLE_GPU -} - void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman) { if (nCPUThreads == 0 && nGPUThreads == 0) { @@ -839,7 +826,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai boost::thread_group* cpuMinerThreads = miners::ThreadGroup(); while (cpuMinerThreads->size() < nCPUTarget) { LogPrintf("Starting CPU Miner thread #%u\n", cpuMinerThreads->size()); - cpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), boost::none)); + cpuMinerThreads->create_thread(boost::bind(&DynamicMinerCPU, boost::cref(chainparams), boost::ref(connman))); } #ifdef ENABLE_GPU @@ -855,7 +842,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai for (std::size_t device = 0; device < devices; device++) { for (std::size_t i = 0; i < nGPUTarget; i++) { LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, device, devices); - gpuMinerThreads->create_thread(boost::bind(&DynamicMiner, boost::cref(chainparams), boost::ref(connman), device)); + gpuMinerThreads->create_thread(boost::bind(&DynamicMinerGPU, boost::cref(chainparams), boost::ref(connman), device)); } } #else From 21b4b52773bce7451f5d0023bf109542f9038edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 07:02:42 +0200 Subject: [PATCH 0150/1653] follow pattern and add this-> --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 800d7c8e09..3097b1e51b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -712,7 +712,7 @@ class CPUMiner : public BaseMiner while (true) { uint256 hash = pblock->GetHash(); if (UintToArith256(hash) <= hashTarget) { - ProcessFoundSolution(pblock, hash); + this->ProcessFoundSolution(pblock, hash); break; } pblock->nNonce += 1; @@ -783,7 +783,7 @@ class GPUMiner : public BaseMiner for (std::size_t i = 0; i < batchSize; i++) { processingUnit.getHash(i, (uint8_t*)&hash); if (UintToArith256(hash) <= hashTarget) { - ProcessFoundSolution(pblock, hash); + this->ProcessFoundSolution(pblock, hash); break; } } From 1c5311040ff5ed20e71afaf13a34c446884c4d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 07:05:48 +0200 Subject: [PATCH 0151/1653] remove redundant comments and whitespace --- src/miner.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 3097b1e51b..73e71725a2 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -619,7 +619,6 @@ class BaseMiner return false; if (pindexPrev != chainActive.Tip()) return false; - // Update nTime every few seconds if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) return false; // Recreate the block if the clock has run backwards, @@ -633,7 +632,6 @@ class BaseMiner void CountHashes(unsigned int nHashesDone) { - // Meter hashes/seconds static int64_t nHashCounter = 0; static int64_t nLogTime = 0; @@ -752,10 +750,8 @@ class GPUMiner : public BaseMiner LoopTick(CBlock* pblock) override { unsigned int nHashesDone = 0; - // current batch size std::size_t batchSize = batchSizeTarget; - // set batch input static unsigned char pblank[1]; for (std::size_t i = 0; i < batchSizeTarget; i++) { From 1e99ad193c73a9adaea07e1786620a585201e0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 07:11:53 +0200 Subject: [PATCH 0152/1653] fix thread names --- src/miner.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 73e71725a2..f86a265c8c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -578,9 +578,10 @@ class BaseMiner private: void Init() { - LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, deviceIndex ? *deviceIndex : 0); + std::size_t device = deviceIndex ? *deviceIndex : 0; + LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, device); SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread("dynamic-cpu-miner"); + RenameThread(tfm::format("dynamic-%s-miner-%u", deviceName, device)); GetMainSignals().ScriptForMining(coinbaseScript); } From 88e718269dbe889d2b72e42866a3528a33ff8ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 07:16:10 +0200 Subject: [PATCH 0153/1653] remove redundant comments and whitespace --- src/miner.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index f86a265c8c..2dcb804e7e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -679,7 +679,6 @@ class BaseMiner nStart = GetTime(); hashTarget = arith_uint256().SetCompact(pblock->nBits); - // search while (true) { auto hashesDone = this->LoopTick(pblock); this->CountHashes(hashesDone); @@ -742,9 +741,7 @@ class GPUMiner : public BaseMiner device(global.getAllDevices()[deviceIndex]), context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), processingUnit(&context, ¶ms, &device, 1, false, false), - batchSizeTarget(device.getTotalMemory() / 512e3) - { - } + batchSizeTarget(device.getTotalMemory() / 512e3) {} protected: virtual unsigned int From 121d989b6a6311cbab32cc95a3a107786a52568f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 07:20:00 +0200 Subject: [PATCH 0154/1653] fix unique_ptr null check --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 2dcb804e7e..feefb06bd2 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -666,7 +666,7 @@ class BaseMiner while (true) { std::unique_ptr pblocktemplate = this->CreateNewMinerBlock(); - if (pblocktemplate) { + if (!pblocktemplate) { LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", deviceName); return; } From b9c588121a00dec7f47814246da272c5e12da41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Thu, 9 Aug 2018 07:33:38 +0200 Subject: [PATCH 0155/1653] fix const char* instead of std::string --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index feefb06bd2..ed87e05530 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -581,7 +581,7 @@ class BaseMiner std::size_t device = deviceIndex ? *deviceIndex : 0; LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, device); SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread(tfm::format("dynamic-%s-miner-%u", deviceName, device)); + RenameThread(tfm::format("dynamic-%s-miner-%u", deviceName, device).data()); GetMainSignals().ScriptForMining(coinbaseScript); } From 5e06a55a8099e0d765f3493a234876f123d0d03f Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 9 Aug 2018 02:34:50 -0500 Subject: [PATCH 0156/1653] [BDAP] Fix saving tx hash in leveldb bdap database --- src/bdap/directorydb.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bdap/directorydb.cpp b/src/bdap/directorydb.cpp index 5a3b10ffdb..4f6e471d47 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/directorydb.cpp @@ -523,6 +523,8 @@ bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& t return error(errorMessage.c_str()); } + directory.txHash = tx.GetHash(); + if (strOperationType == "bdap_new") return CheckNewDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_delete") From b59232f6483873444a53c5df0270c3131dad643d Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 9 Aug 2018 03:22:34 -0500 Subject: [PATCH 0157/1653] [BDAP] Replace updatedirectory RPC command --- src/bdap/rpcdirectory.cpp | 85 +++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 13 deletions(-) diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index e4d91e4b66..8658587069 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -60,8 +60,8 @@ UniValue addpublicname(const JSONRPCRequest& request) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Error adding receiving address key wo wallet for BDAP")); pwalletMain->SetAddressBook(keyWalletID, strObjectID, "receive"); - CDynamicAddress payWallet = CDynamicAddress(keyWalletID); - std::string strWalletAddress = payWallet.ToString(); + + std::string strWalletAddress = CDynamicAddress(keyWalletID).ToString(); CharString vchWalletAddress(strWalletAddress.begin(), strWalletAddress.end()); txDirectory.WalletAddress = vchWalletAddress; @@ -80,7 +80,8 @@ UniValue addpublicname(const JSONRPCRequest& request) privSignKey.MakeNewKey(true); CPubKey pubSignKey = privSignKey.GetPubKey(); CKeyID keySignID = pubSignKey.GetID(); - std::string strSignWalletAddress = CDynamicAddress(keySignID).ToString(); + CDynamicAddress signWallet = CDynamicAddress(keySignID); + std::string strSignWalletAddress = signWallet.ToString(); CharString vchSignWalletAddress(strSignWalletAddress.begin(), strSignWalletAddress.end()); if (pwalletMain && !pwalletMain->AddKeyPubKey(privSignKey, pubSignKey)) @@ -97,7 +98,7 @@ UniValue addpublicname(const JSONRPCRequest& request) scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_NEW) << vchFullObjectPath << OP_2DROP << OP_DROP; CScript scriptDestination; - scriptDestination = GetScriptForDestination(payWallet.Get()); + scriptDestination = GetScriptForDestination(signWallet.Get()); scriptPubKey += scriptDestination; LogPrintf("BDAP GetDirectoryType = %s \n", GetDirectoryOpTypeString(scriptPubKey)); @@ -185,20 +186,78 @@ UniValue getdirectoryinfo(const JSONRPCRequest& request) return oDirectoryInfo; } -UniValue directoryupdate(const JSONRPCRequest& request) { - if (request.params.size() != 1) { - throw std::runtime_error("directoryupdate \nAdd directory to blockchain.\n"); +UniValue updatedirectory(const JSONRPCRequest& request) { + if (request.params.size() != 2) + { + throw std::runtime_error("updatedirectory \nUpdate an existing public name blockchain directory entry.\n"); } - std::vector vchDirectoryName = vchFromValue(request.params[0]); + EnsureWalletIsUnlocked(); + + // Format object and domain names to lower case. + CharString vchObjectID = vchFromValue(request.params[0]); + ToLowerCase(vchObjectID); + CDirectory txDirectory; - if (!pDirectoryDB || !pDirectoryDB->AddDirectory(txDirectory, OP_BDAP_NEW)) - throw std::runtime_error("Failed to read from BDAP database"); + txDirectory.DomainComponent = vchDefaultDomainName; + txDirectory.OrganizationalUnit = vchDefaultPublicOU; + txDirectory.ObjectID = vchObjectID; + + // Check if name already exists + if (!GetDirectory(txDirectory.vchFullObjectPath(), txDirectory)) + throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txDirectory.GetFullObjectPath() + _(" does not exists. Can not update.")); + + // TODO: Check if Signature Wallet address is owned. If not, return an error before submitting to the mem pool. + CharString vchCommonName = vchFromValue(request.params[1]); + txDirectory.CommonName = vchCommonName; + + CharString data; + txDirectory.Serialize(data); + // Create BDAP OP_RETURN Signature Scripts + CScript scriptPubKey; + std::vector vchFullObjectPath = txDirectory.vchFullObjectPath(); + scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_MODIFY) << vchFullObjectPath << OP_2DROP << OP_DROP; + + CDynamicAddress signWallet(stringFromVch(txDirectory.SignWalletAddress)); + CScript scriptDestination; + scriptDestination = GetScriptForDestination(signWallet.Get()); + scriptPubKey += scriptDestination; + LogPrintf("BDAP GetDirectoryType = %s \n", GetDirectoryOpTypeString(scriptPubKey)); + + CScript scriptData; + scriptData << OP_RETURN << data; + + // Send the transaction + float fYears = 1.0; //TODO use a variable for registration years. + CWalletTx wtx; + CAmount nOperationFee = GetBDAPFee(scriptPubKey) * powf(3.1, fYears); + CAmount nDataFee = GetBDAPFee(scriptData) * powf(3.1, fYears); + + // check BDAP values + std::string strMessage; + if (!txDirectory.ValidateValues(strMessage)) + throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - " + strMessage); + + SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); + txDirectory.txHash = wtx.GetHash(); + UniValue oName(UniValue::VOBJ); if(!BuildBDAPJson(txDirectory, oName)) - throw std::runtime_error("Failed to read from BDAP JSON object"); - + throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3702 - " + _("Failed to read from BDAP JSON object")); + + if (fPrintDebug) { + // make sure we can deserialize the transaction from the scriptData and get a valid CDirectory class + LogPrintf("Directory Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); + + const CTransaction testTx = (CTransaction)wtx; + CDirectory testDirectory(testTx); //loads the class from a transaction + + LogPrintf("CDirectory Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\nPrivateData = %s\n", + testDirectory.nVersion, testDirectory.GetFullObjectPath(), stringFromVch(testDirectory.CommonName), + stringFromVch(testDirectory.OrganizationalUnit), HexStr(testDirectory.EncryptPublicKey), stringFromVch(testDirectory.PrivateData)); + } + return oName; } @@ -209,7 +268,7 @@ static const CRPCCommand commands[] = { "bdap", "addpublicname", &addpublicname, true }, { "bdap", "getdirectories", &getdirectories, true }, { "bdap", "getdirectoryinfo", &getdirectoryinfo, true }, - { "bdap", "directoryupdate", &directoryupdate, true }, + { "bdap", "updatedirectory", &updatedirectory, true }, #endif //ENABLE_WALLET }; From 890329924551d3863460c374e3e24e79d11a0540 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 9 Aug 2018 03:53:40 -0500 Subject: [PATCH 0158/1653] [BDAP] Fix getdirectoryinfo return when entry not found --- src/bdap/rpcdirectory.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 8658587069..9e22331c72 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -180,8 +180,14 @@ UniValue getdirectoryinfo(const JSONRPCRequest& request) directory.ObjectID = vchObjectID; UniValue oDirectoryInfo(UniValue::VOBJ); - if (CheckDirectoryDB()) - pDirectoryDB->GetDirectoryInfo(directory.vchFullObjectPath(), oDirectoryInfo); + if (CheckDirectoryDB()) { + if (!pDirectoryDB->GetDirectoryInfo(directory.vchFullObjectPath(), oDirectoryInfo)) { + throw std::runtime_error("BDAP_SELECT_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3600 - " + directory.GetFullObjectPath() + _(" can not be found. Get info failed!")); + } + } + else { + throw std::runtime_error("BDAP_SELECT_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3601 - " + _("Can not access BDAP LevelDB database. Get info failed!")); + } return oDirectoryInfo; } From 86b76c4e00652f2fe4c9d763b29f02087aa23dc3 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 9 Aug 2018 04:44:52 -0500 Subject: [PATCH 0159/1653] [BDAP] Fix expire time in RPC commands - Entry registration expiration defaults to 4 years after the current block --- src/bdap/bdap.h | 1 + src/bdap/rpcdirectory.cpp | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h index 9e3ee17792..177c82ffb9 100644 --- a/src/bdap/bdap.h +++ b/src/bdap/bdap.h @@ -21,6 +21,7 @@ static constexpr unsigned int MAX_KEY_LENGTH = 156; static constexpr unsigned int MAX_CERTIFICATE_LENGTH = 512; static constexpr unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain static constexpr unsigned int MAX_NUMBER_CHECKPOINTS = 100; // Pay per byte for hosting on chain +static constexpr unsigned int SECONDS_PER_DAY = 86400; // Number of seconds per day. static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; static const std::string DEFAULT_PUBLIC_OU = "public"; static const std::string DEFAULT_ADMIN_OU = "admin"; diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdirectory.cpp index 9e22331c72..2995b18e0e 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdirectory.cpp @@ -9,6 +9,7 @@ #include "rpcserver.h" #include "primitives/transaction.h" #include "wallet/wallet.h" +#include "validation.h" #include @@ -18,9 +19,9 @@ static constexpr bool fPrintDebug = true; UniValue addpublicname(const JSONRPCRequest& request) { - if (request.params.size() != 2) + if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); + throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); } EnsureWalletIsUnlocked(); @@ -89,6 +90,13 @@ UniValue addpublicname(const JSONRPCRequest& request) txDirectory.SignWalletAddress = vchSignWalletAddress; + uint64_t nDays = 1461; //default to 4 years. + if (request.params.size() >= 3) { + nDays = request.params[2].get_int(); + } + uint64_t nSeconds = nDays * SECONDS_PER_DAY; + txDirectory.nExpireTime = chainActive.Tip()->GetMedianTimePast() + nSeconds; + CharString data; txDirectory.Serialize(data); @@ -106,8 +114,8 @@ UniValue addpublicname(const JSONRPCRequest& request) scriptData << OP_RETURN << data; // Send the transaction - float fYears = 1.0; //TODO use a variable for registration years. CWalletTx wtx; + float fYears = ((float)nDays/365.25); CAmount nOperationFee = GetBDAPFee(scriptPubKey) * powf(3.1, fYears); CAmount nDataFee = GetBDAPFee(scriptData) * powf(3.1, fYears); @@ -193,9 +201,9 @@ UniValue getdirectoryinfo(const JSONRPCRequest& request) } UniValue updatedirectory(const JSONRPCRequest& request) { - if (request.params.size() != 2) + if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("updatedirectory \nUpdate an existing public name blockchain directory entry.\n"); + throw std::runtime_error("updatedirectory \nUpdate an existing public name blockchain directory entry.\n"); } EnsureWalletIsUnlocked(); @@ -217,6 +225,13 @@ UniValue updatedirectory(const JSONRPCRequest& request) { CharString vchCommonName = vchFromValue(request.params[1]); txDirectory.CommonName = vchCommonName; + uint64_t nDays = 1461; //default to 4 years. + if (request.params.size() >= 3) { + nDays = request.params[2].get_int(); + } + uint64_t nSeconds = nDays * SECONDS_PER_DAY; + txDirectory.nExpireTime = chainActive.Tip()->GetMedianTimePast() + nSeconds; + CharString data; txDirectory.Serialize(data); @@ -235,8 +250,8 @@ UniValue updatedirectory(const JSONRPCRequest& request) { scriptData << OP_RETURN << data; // Send the transaction - float fYears = 1.0; //TODO use a variable for registration years. CWalletTx wtx; + float fYears = ((float)nDays/365.25); CAmount nOperationFee = GetBDAPFee(scriptPubKey) * powf(3.1, fYears); CAmount nDataFee = GetBDAPFee(scriptData) * powf(3.1, fYears); From 2f6ae75e9724e2feef7c42e1e354d7f969042209 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 10 Aug 2018 14:21:53 -0500 Subject: [PATCH 0160/1653] [BDAP] Refactor directory to domainentry --- src/Makefile.am | 10 +- src/bdap/directorydb.h | 61 ---- src/bdap/{directory.cpp => domainentry.cpp} | 135 +++++---- src/bdap/{directory.h => domainentry.h} | 54 ++-- .../{directorydb.cpp => domainentrydb.cpp} | 284 +++++++++--------- src/bdap/domainentrydb.h | 61 ++++ .../{rpcdirectory.cpp => rpcdomainentry.cpp} | 120 ++++---- src/init.cpp | 6 +- src/qt/transactionrecord.cpp | 13 +- src/rpcregister.h | 4 +- src/script/script.cpp | 16 +- src/script/script.h | 2 +- src/validation.cpp | 8 +- 13 files changed, 386 insertions(+), 388 deletions(-) delete mode 100644 src/bdap/directorydb.h rename src/bdap/{directory.cpp => domainentry.cpp} (76%) rename src/bdap/{directory.h => domainentry.h} (80%) rename src/bdap/{directorydb.cpp => domainentrydb.cpp} (50%) create mode 100644 src/bdap/domainentrydb.h rename src/bdap/{rpcdirectory.cpp => rpcdomainentry.cpp} (69%) diff --git a/src/Makefile.am b/src/Makefile.am index bb2278314a..3dbd93cd2e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -98,8 +98,8 @@ DYNAMIC_CORE_H = \ core_io.h \ core_memusage.h \ bdap/bdap.h \ - bdap/directory.h \ - bdap/directorydb.h \ + bdap/domainentry.h \ + bdap/domainentrydb.h \ dbwrapper.h \ dynode.h \ dynode-payments.h \ @@ -222,8 +222,8 @@ libdynamic_server_a_SOURCES = \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ - bdap/directory.cpp \ - bdap/directorydb.cpp \ + bdap/domainentry.cpp \ + bdap/domainentrydb.cpp \ dbwrapper.cpp \ dynode.cpp \ dynode-payments.cpp\ @@ -258,7 +258,7 @@ libdynamic_server_a_SOURCES = \ psnotificationinterface.cpp \ rest.cpp \ rpcblockchain.cpp \ - bdap/rpcdirectory.cpp \ + bdap/rpcdomainentry.cpp \ rpcdynode.cpp \ rpcgovernance.cpp \ rpcmining.cpp \ diff --git a/src/bdap/directorydb.h b/src/bdap/directorydb.h deleted file mode 100644 index 21d6398598..0000000000 --- a/src/bdap/directorydb.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2018 Duality Blockchain Solutions Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef DYNAMIC_DIRECTORYDB_H -#define DYNAMIC_DIRECTORYDB_H - -#include "bdap/directory.h" -#include "dbwrapper.h" - -static CCriticalSection cs_bdap_directory; - -class CDirectoryDB : public CDBWrapper { -public: - CDirectoryDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "bdap", nCacheSize, fMemory, fWipe, obfuscate) { - } - - // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare - bool AddDirectory(const CDirectory& directory, const int op); - void AddDirectoryIndex(const CDirectory& directory, const int op); - bool ReadDirectory(const std::vector& vchObjectPath, CDirectory& directory); - bool ReadDirectoryAddress(const std::vector& vchAddress, std::vector& vchObjectPath); - bool EraseDirectory(const std::vector& vchObjectPath); - bool EraseDirectoryAddress(const std::vector& vchAddress); - bool DirectoryExists(const std::vector& vchObjectPath); - bool DirectoryExistsAddress(const std::vector& vchAddress); - bool RemoveExpired(int& entriesRemoved); - void WriteDirectoryIndex(const CDirectory& directory, const int op); - void WriteDirectoryIndexHistory(const CDirectory& directory, const int op); - bool UpdateDirectory(const std::vector& vchObjectPath, const CDirectory& directory); - bool CleanupLevelDB(int& nRemoved); - bool ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDirectoryList); - bool GetDirectoryInfo(const std::vector& vchFullObjectPath, UniValue& oDirectoryInfo); -}; - -bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory); -bool CheckDirectoryDB(); -bool FlushLevelDB(); -void CleanupLevelDB(int& nRemoved); -bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, - int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); - -extern CDirectoryDB *pDirectoryDB; - -#endif // DYNAMIC_DIRECTORYDB_H \ No newline at end of file diff --git a/src/bdap/directory.cpp b/src/bdap/domainentry.cpp similarity index 76% rename from src/bdap/directory.cpp rename to src/bdap/domainentry.cpp index 41872533e1..1bb65ff1c6 100644 --- a/src/bdap/directory.cpp +++ b/src/bdap/domainentry.cpp @@ -2,8 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "bdap/directory.h" - +#include "bdap/domainentry.h" #include "coins.h" #include "fluid.h" @@ -21,21 +20,21 @@ using namespace boost::xpressive; -bool IsDirectoryTransaction(const CScript& txOut) +bool IsDomainEntryTransaction(const CScript& txOut) { - return (txOut.IsDirectoryScript(BDAP_START) - || txOut.IsDirectoryScript(BDAP_NEW_TX) - || txOut.IsDirectoryScript(BDAP_DELETE_TX) - || txOut.IsDirectoryScript(BDAP_ACTIVATE_TX) - || txOut.IsDirectoryScript(BDAP_MODIFY_TX) - || txOut.IsDirectoryScript(BDAP_MODIFY_RDN_TX) - || txOut.IsDirectoryScript(BDAP_EXECUTE_CODE_TX) - || txOut.IsDirectoryScript(BDAP_BIND_TX) - || txOut.IsDirectoryScript(BDAP_REVOKE_TX) + return (txOut.IsBDAPScript(BDAP_START) + || txOut.IsBDAPScript(BDAP_NEW_TX) + || txOut.IsBDAPScript(BDAP_DELETE_TX) + || txOut.IsBDAPScript(BDAP_ACTIVATE_TX) + || txOut.IsBDAPScript(BDAP_MODIFY_TX) + || txOut.IsBDAPScript(BDAP_MODIFY_RDN_TX) + || txOut.IsBDAPScript(BDAP_EXECUTE_CODE_TX) + || txOut.IsBDAPScript(BDAP_BIND_TX) + || txOut.IsBDAPScript(BDAP_REVOKE_TX) ); } -std::string directoryFromOp(const int op) +std::string DomainEntryFromOp(const int op) { switch (op) { case OP_BDAP_NEW: @@ -55,11 +54,11 @@ std::string directoryFromOp(const int op) case OP_BDAP_REVOKE: return "bdap_revoke"; default: - return ""; + return ""; } } -bool IsDirectoryDataOutput(const CTxOut& out) { +bool IsDomainEntryDataOutput(const CTxOut& out) { txnouttype whichType; if (!IsStandard(out.scriptPubKey, whichType)) return false; @@ -68,7 +67,7 @@ bool IsDirectoryDataOutput(const CTxOut& out) { return false; } -bool GetDirectoryTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams) +bool GetDomainEntryTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams) { if(nHeight < 0 || nHeight > chainActive.Height()) return false; @@ -110,15 +109,15 @@ std::vector vchFromString(const std::string& str) return std::vector(str.begin(), str.end()); } -int GetDirectoryDataOutput(const CTransaction& tx) { +int GetDomainEntryDataOutput(const CTransaction& tx) { for(unsigned int i = 0; i& vchData, std::vector& vchHash) +bool GetDomainEntryData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash) { CScript::const_iterator pc = scriptPubKey.begin(); opcodetype opcode; @@ -136,21 +135,21 @@ bool GetDirectoryData(const CScript& scriptPubKey, std::vector& v return true; } -bool GetDirectoryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut) +bool GetDomainEntryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut) { - nOut = GetDirectoryDataOutput(tx); + nOut = GetDomainEntryDataOutput(tx); if(nOut == -1) return false; const CScript &scriptPubKey = tx.vout[nOut].scriptPubKey; - return GetDirectoryData(scriptPubKey, vchData, vchHash); + return GetDomainEntryData(scriptPubKey, vchData, vchHash); } -bool CDirectory::UnserializeFromTx(const CTransaction& tx) { +bool CDomainEntry::UnserializeFromTx(const CTransaction& tx) { std::vector vchData; std::vector vchHash; int nOut; - if(!GetDirectoryData(tx, vchData, vchHash, nOut)) + if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) { SetNull(); return false; @@ -162,13 +161,13 @@ bool CDirectory::UnserializeFromTx(const CTransaction& tx) { return true; } -void CDirectory::Serialize(std::vector& vchData) { +void CDomainEntry::Serialize(std::vector& vchData) { CDataStream dsBDAP(SER_NETWORK, PROTOCOL_VERSION); dsBDAP << *this; vchData = std::vector(dsBDAP.begin(), dsBDAP.end()); } -bool CDirectory::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) { +bool CDomainEntry::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) { try { CDataStream dsBDAP(vchData, SER_NETWORK, PROTOCOL_VERSION); dsBDAP >> *this; @@ -189,31 +188,31 @@ bool CDirectory::UnserializeFromData(const std::vector& vchData, return true; } -CDynamicAddress CDirectory::GetWalletAddress() const { +CDynamicAddress CDomainEntry::GetWalletAddress() const { return CDynamicAddress(stringFromVch(WalletAddress)); } -std::string CDirectory::GetFullObjectPath() const { +std::string CDomainEntry::GetFullObjectPath() const { return stringFromVch(ObjectID) + "@" + stringFromVch(OrganizationalUnit) + "." + stringFromVch(DomainComponent); } -std::string CDirectory::GetObjectLocation() const { +std::string CDomainEntry::GetObjectLocation() const { return stringFromVch(OrganizationalUnit) + "." + stringFromVch(DomainComponent); } -std::vector CDirectory::vchFullObjectPath() const { +std::vector CDomainEntry::vchFullObjectPath() const { std::string strFullObjectPath = GetFullObjectPath(); std::vector vchReturnValue(strFullObjectPath.begin(), strFullObjectPath.end()); return vchReturnValue; } -std::vector CDirectory::vchObjectLocation() const { +std::vector CDomainEntry::vchObjectLocation() const { std::string strObjectLocation = GetObjectLocation(); std::vector vchReturnValue(strObjectLocation.begin(), strObjectLocation.end()); return vchReturnValue; } -void CDirectory::AddCheckpoint(const uint32_t& height, const CharString& vchHash) +void CDomainEntry::AddCheckpoint(const uint32_t& height, const CharString& vchHash) { std::pair pairNewCheckpoint; pairNewCheckpoint.first = height; @@ -221,7 +220,7 @@ void CDirectory::AddCheckpoint(const uint32_t& height, const CharString& vchHash CheckpointHashes.push_back(pairNewCheckpoint); } -bool CDirectory::ValidateValues(std::string& errorMessage) +bool CDomainEntry::ValidateValues(std::string& errorMessage) { smatch sMatch; std::string regExWithDot = "^((?!-)[a-z0-9-]{2," + std::to_string(MAX_OBJECT_NAME_LENGTH) + "}(?= directory.nHeight-1) { - CBlockIndex *pindex = chainActive[directory.nHeight-1]; + oName.push_back(Pair("_id", stringFromVch(entry.OID))); + oName.push_back(Pair("version", entry.nVersion)); + oName.push_back(Pair("domain_component", stringFromVch(entry.DomainComponent))); + oName.push_back(Pair("common_name", stringFromVch(entry.CommonName))); + oName.push_back(Pair("organizational_unit", stringFromVch(entry.OrganizationalUnit))); + oName.push_back(Pair("organization_name", stringFromVch(entry.DomainComponent))); + oName.push_back(Pair("object_id", stringFromVch(entry.ObjectID))); + oName.push_back(Pair("object_full_path", stringFromVch(entry.vchFullObjectPath()))); + oName.push_back(Pair("object_type", entry.ObjectType)); + oName.push_back(Pair("wallet_address", stringFromVch(entry.WalletAddress))); + oName.push_back(Pair("signature_address", stringFromVch(entry.SignWalletAddress))); + oName.push_back(Pair("public", (int)entry.fPublicObject)); + oName.push_back(Pair("encryption_publickey", HexStr(entry.EncryptPublicKey))); + oName.push_back(Pair("sigatures_required", (int)entry.nSigaturesRequired)); + oName.push_back(Pair("resource_pointer", stringFromVch(entry.ResourcePointer))); + oName.push_back(Pair("txid", entry.txHash.GetHex())); + if ((unsigned int)chainActive.Height() >= entry.nHeight-1) { + CBlockIndex *pindex = chainActive[entry.nHeight-1]; if (pindex) { nTime = pindex->GetMedianTimePast(); } } oName.push_back(Pair("time", nTime)); - //oName.push_back(Pair("height", directory.nHeight)); - expired_time = directory.nExpireTime; + //oName.push_back(Pair("height", entry.nHeight)); + expired_time = entry.nExpireTime; if(expired_time <= (unsigned int)chainActive.Tip()->GetMedianTimePast()) { expired = true; } oName.push_back(Pair("expires_on", expired_time)); oName.push_back(Pair("expired", expired)); - oName.push_back(Pair("certificate", stringFromVch(directory.Certificate))); - oName.push_back(Pair("private_data", stringFromVch(directory.PrivateData))); - oName.push_back(Pair("transaction_fee", directory.transactionFee)); - oName.push_back(Pair("registration_fee", directory.registrationFeePerDay)); + oName.push_back(Pair("certificate", stringFromVch(entry.Certificate))); + oName.push_back(Pair("private_data", stringFromVch(entry.PrivateData))); + oName.push_back(Pair("transaction_fee", entry.transactionFee)); + oName.push_back(Pair("registration_fee", entry.registrationFeePerDay)); } else { - oName.push_back(Pair("common_name", stringFromVch(directory.CommonName))); - oName.push_back(Pair("object_full_path", stringFromVch(directory.vchFullObjectPath()))); - oName.push_back(Pair("wallet_address", stringFromVch(directory.WalletAddress))); + oName.push_back(Pair("common_name", stringFromVch(entry.CommonName))); + oName.push_back(Pair("object_full_path", stringFromVch(entry.vchFullObjectPath()))); + oName.push_back(Pair("wallet_address", stringFromVch(entry.WalletAddress))); } return true; } @@ -445,7 +444,7 @@ CAmount GetBDAPFee(const CScript& scriptPubKey) return recp.nAmount; } -bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector >& vvch) +bool DecodeDomainEntryTx(const CTransaction& tx, int& op, std::vector >& vvch) { bool found = false; @@ -464,7 +463,7 @@ bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector >& vvch) +bool FindDomainEntryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch) { for (unsigned int i = 0; i < tx.vin.size(); i++) { const Coin& prevCoins = inputs.AccessCoin(tx.vin[i].prevout); @@ -480,7 +479,7 @@ bool FindDirectoryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, st return false; } -int GetDirectoryOpType(const CScript& script) +int GetDomainEntryOpType(const CScript& script) { std::string ret; CScript::const_iterator it = script.begin(); @@ -520,19 +519,19 @@ int GetDirectoryOpType(const CScript& script) return (int)op2; } -std::string GetDirectoryOpTypeString(const CScript& script) +std::string GetDomainEntryOpTypeString(const CScript& script) { - return directoryFromOp(GetDirectoryOpType(script)); + return DomainEntryFromOp(GetDomainEntryOpType(script)); } -bool GetDirectoryOpScript(const CTransaction& tx, CScript& scriptDirectoryOp, vchCharString& vvchOpParameters, int& op) +bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp, vchCharString& vvchOpParameters, int& op) { for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut& out = tx.vout[i]; if (DecodeBDAPScript(out.scriptPubKey, op, vvchOpParameters)) { - scriptDirectoryOp = out.scriptPubKey; + scriptDomainEntryOp = out.scriptPubKey; return true; } } diff --git a/src/bdap/directory.h b/src/bdap/domainentry.h similarity index 80% rename from src/bdap/directory.h rename to src/bdap/domainentry.h index 5fd672fc19..d09d5e30f1 100644 --- a/src/bdap/directory.h +++ b/src/bdap/domainentry.h @@ -2,8 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef DYNAMIC_DIRECTORY_H -#define DYNAMIC_DIRECTORY_H +#ifndef DYNAMIC_BDAP_DOMAINENTRY_H +#define DYNAMIC_BDAP_DOMAINENTRY_H #include "bdap.h" #include "amount.h" @@ -37,13 +37,13 @@ class CTxOut; - Implement file sharing using IPFS */ -class CDirectoryDefaultParameters { +class CDomainEntryDefaultParameters { public: void InitialiseAdminOwners(); //DEFAULT_ADMIN_DOMAIN void InitialisePublicDomain(); //DEFAULT_PUBLIC_DOMAIN }; -enum DirectoryObjectType { +enum DomainEntryObjectType { USER_ACCOUNT = 0, DEVICE_ACCOUNT = 1, GROUP = 2, @@ -55,9 +55,9 @@ enum DirectoryObjectType { }; // See LDAP Distinguished Name -class CDirectory { +class CDomainEntry { public: - static const int CURRENT_VERSION=3; + static const int CURRENT_VERSION=1; int nVersion; CharString OID; // Canonical Object ID //CN=John Smith,OU=Public,DC=BDAP,DC=IO, O=Duality Blockchain Solutions, UID=johnsmith21 @@ -66,7 +66,7 @@ class CDirectory { CharString OrganizationalUnit; // OU. Like OU=sales. blank for top level domain directories CharString OrganizationName; // O. Like Duality Blockchain Solutions CharString ObjectID; // UID. Like johnsmith21. blank for top level domain directories - DirectoryObjectType ObjectType; // see enum above + DomainEntryObjectType ObjectType; // see enum above CharString WalletAddress; // used to send collateral funds for this directory record. int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. @@ -85,25 +85,25 @@ class CDirectory { CAmount registrationFeePerDay; vCheckPoints CheckpointHashes; // used to store main chain hash checkpoints for added security - CDirectory() { + CDomainEntry() { SetNull(); } - CDirectory(const CTransaction &tx) { + CDomainEntry(const CTransaction &tx) { SetNull(); UnserializeFromTx(tx); } inline void SetNull() { - nVersion = CDirectory::CURRENT_VERSION; + nVersion = CDomainEntry::CURRENT_VERSION; OID.clear(); DomainComponent.clear(); CommonName.clear(); OrganizationalUnit.clear(); OrganizationName.clear(); ObjectID.clear(); - ObjectType = DirectoryObjectType::DOMAIN_ACCOUNT; + ObjectType = DomainEntryObjectType::DOMAIN_ACCOUNT; WalletAddress.clear(); fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); @@ -148,15 +148,15 @@ class CDirectory { READWRITE(CheckpointHashes); } - inline friend bool operator==(const CDirectory &a, const CDirectory &b) { + inline friend bool operator==(const CDomainEntry &a, const CDomainEntry &b) { return (a.OID == b.OID && a.DomainComponent == b.DomainComponent && a.OrganizationalUnit == b.OrganizationalUnit && a.ObjectID == b.ObjectID); } - inline friend bool operator!=(const CDirectory &a, const CDirectory &b) { + inline friend bool operator!=(const CDomainEntry &a, const CDomainEntry &b) { return !(a == b); } - inline CDirectory operator=(const CDirectory &b) { + inline CDomainEntry operator=(const CDomainEntry &b) { OID = b.OID; DomainComponent = b.DomainComponent; CommonName = b.CommonName; @@ -193,13 +193,13 @@ class CDirectory { bool ValidateValues(std::string& errorMessage); }; -bool IsDirectoryTransaction(const CScript& txOut); -std::string directoryFromOp(const int op); -bool IsDirectoryDataOutput(const CTxOut& out); -int GetDirectoryDataOutput(const CTransaction& tx); -bool GetDirectoryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); -bool GetDirectoryData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash); -bool BuildBDAPJson(const CDirectory& directory, UniValue& oName, bool fAbridged = false); +bool IsDomainEntryTransaction(const CScript& txOut); +std::string DomainEntryFromOp(const int op); +bool IsDomainEntryDataOutput(const CTxOut& out); +int GetDomainEntryDataOutput(const CTransaction& tx); +bool GetDomainEntryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); +bool GetDomainEntryData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash); +bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged = false); std::string stringFromVch(const CharString& vch); std::vector vchFromValue(const UniValue& value); @@ -208,10 +208,10 @@ void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); void ToLowerCase(CharString& vchValue); void ToLowerCase(std::string& strValue); CAmount GetBDAPFee(const CScript& scriptPubKey); -bool DecodeDirectoryTx(const CTransaction& tx, int& op, std::vector >& vvch); -bool FindDirectoryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch); -int GetDirectoryOpType(const CScript& script); -std::string GetDirectoryOpTypeString(const CScript& script); -bool GetDirectoryOpScript(const CTransaction& tx, CScript& scriptDirectoryOp, vchCharString& vvchOpParameters, int& op); +bool DecodeDomainEntryTx(const CTransaction& tx, int& op, std::vector >& vvch); +bool FindDomainEntryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch); +int GetDomainEntryOpType(const CScript& script); +std::string GetDomainEntryOpTypeString(const CScript& script); +bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp, vchCharString& vvchOpParameters, int& op); -#endif // DYNAMIC_DIRECTORY_H \ No newline at end of file +#endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file diff --git a/src/bdap/directorydb.cpp b/src/bdap/domainentrydb.cpp similarity index 50% rename from src/bdap/directorydb.cpp rename to src/bdap/domainentrydb.cpp index 4f6e471d47..e4662946dd 100644 --- a/src/bdap/directorydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "bdap/directorydb.h" +#include "bdap/domainentrydb.h" #include "base58.h" #include "validation.h" @@ -10,110 +10,110 @@ #include -CDirectoryDB *pDirectoryDB = NULL; +CDomainEntryDB *pDomainEntryDB = NULL; -bool GetDirectory(const std::vector& vchObjectPath, CDirectory& directory) +bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry) { - if (!pDirectoryDB || !pDirectoryDB->ReadDirectory(vchObjectPath, directory)) { + if (!pDomainEntryDB || !pDomainEntryDB->ReadDomainEntry(vchObjectPath, entry)) { return false; } - //TODO: (bdap) calculate directory.nExpireTime + //TODO: (bdap) calculate entry.nExpireTime /* - if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) { - directory.SetNull(); + if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) { + entry.SetNull(); return false; } */ - return !directory.IsNull(); + return !entry.IsNull(); } -bool CDirectoryDB::AddDirectory(const CDirectory& directory, const int op) +bool CDomainEntryDB::AddDomainEntry(const CDomainEntry& entry, const int op) { bool writeState = false; { - LOCK(cs_bdap_directory); - writeState = Write(make_pair(std::string("domain_component"), directory.GetFullObjectPath()), directory) - && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.GetFullObjectPath()); + LOCK(cs_bdap_entry); + writeState = Write(make_pair(std::string("domain_component"), entry.GetFullObjectPath()), entry) + && Write(make_pair(std::string("domain_wallet_address"), entry.WalletAddress), entry.GetFullObjectPath()); } if (writeState) - AddDirectoryIndex(directory, op); + AddDomainEntryIndex(entry, op); return writeState; } -void CDirectoryDB::AddDirectoryIndex(const CDirectory& directory, const int op) +void CDomainEntryDB::AddDomainEntryIndex(const CDomainEntry& entry, const int op) { UniValue oName(UniValue::VOBJ); - if (BuildBDAPJson(directory, oName)) { - CharString vchOperationType = vchFromString(directoryFromOp(op)); + if (BuildBDAPJson(entry, oName)) { + CharString vchOperationType = vchFromString(DomainEntryFromOp(op)); GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), reinterpret_cast(vchOperationType.data())); - WriteDirectoryIndexHistory(directory, op); + WriteDomainEntryIndexHistory(entry, op); } } -bool CDirectoryDB::ReadDirectory(const std::vector& vchObjectPath, CDirectory& directory) +bool CDomainEntryDB::ReadDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry) { - LOCK(cs_bdap_directory); - return CDBWrapper::Read(make_pair(std::string("domain_component"), vchObjectPath), directory); + LOCK(cs_bdap_entry); + return CDBWrapper::Read(make_pair(std::string("domain_component"), vchObjectPath), entry); } -bool CDirectoryDB::ReadDirectoryAddress(const std::vector& vchAddress, std::vector& vchObjectPath) +bool CDomainEntryDB::ReadDomainEntryAddress(const std::vector& vchAddress, std::vector& vchObjectPath) { - LOCK(cs_bdap_directory); + LOCK(cs_bdap_entry); return CDBWrapper::Read(make_pair(std::string("domain_wallet_address"), vchAddress), vchObjectPath); } -bool CDirectoryDB::EraseDirectory(const std::vector& vchObjectPath) +bool CDomainEntryDB::EraseDomainEntry(const std::vector& vchObjectPath) { - LOCK(cs_bdap_directory); + LOCK(cs_bdap_entry); return CDBWrapper::Erase(make_pair(std::string("domain_component"), vchObjectPath)); } -bool CDirectoryDB::EraseDirectoryAddress(const std::vector& vchAddress) +bool CDomainEntryDB::EraseDomainEntryAddress(const std::vector& vchAddress) { - LOCK(cs_bdap_directory); + LOCK(cs_bdap_entry); return CDBWrapper::Erase(make_pair(std::string("domain_wallet_address"), vchAddress)); } -bool CDirectoryDB::DirectoryExists(const std::vector& vchObjectPath) +bool CDomainEntryDB::DomainEntryExists(const std::vector& vchObjectPath) { - LOCK(cs_bdap_directory); + LOCK(cs_bdap_entry); return CDBWrapper::Exists(make_pair(std::string("domain_component"), vchObjectPath)); } -bool CDirectoryDB::DirectoryExistsAddress(const std::vector& vchAddress) +bool CDomainEntryDB::DomainEntryExistsAddress(const std::vector& vchAddress) { - LOCK(cs_bdap_directory); + LOCK(cs_bdap_entry); return CDBWrapper::Exists(make_pair(std::string("domain_wallet_address"), vchAddress)); } -bool CDirectoryDB::RemoveExpired(int& entriesRemoved) +bool CDomainEntryDB::RemoveExpired(int& entriesRemoved) { boost::scoped_ptr pcursor(NewIterator()); pcursor->SeekToFirst(); - CDirectory directory; + CDomainEntry entry; std::pair > key; while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { if (pcursor->GetKey(key) && key.first == "domain_component") { - pcursor->GetValue(directory); - if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) + pcursor->GetValue(entry); + if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) { entriesRemoved++; - EraseDirectory(key.second); + EraseDomainEntry(key.second); } } else if (pcursor->GetKey(key) && key.first == "domain_wallet_address") { std::vector value; - CDirectory directory; + CDomainEntry entry; pcursor->GetValue(value); - if (GetDirectory(value, directory) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) + if (GetDomainEntry(value, entry) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) { entriesRemoved++; - EraseDirectoryAddress(directory.WalletAddress); + EraseDomainEntryAddress(entry.WalletAddress); } } @@ -125,52 +125,52 @@ bool CDirectoryDB::RemoveExpired(int& entriesRemoved) return true; } -void CDirectoryDB::WriteDirectoryIndexHistory(const CDirectory& directory, const int op) +void CDomainEntryDB::WriteDomainEntryIndexHistory(const CDomainEntry& entry, const int op) { if (IsArgSet("-zmqpubbdaphistory")) { UniValue oName(UniValue::VOBJ); - BuildBDAPJson(directory, oName); - oName.push_back(Pair("op", directoryFromOp(op))); + BuildBDAPJson(entry, oName); + oName.push_back(Pair("op", DomainEntryFromOp(op))); GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_history"); } } -void CDirectoryDB::WriteDirectoryIndex(const CDirectory& directory, const int op) +void CDomainEntryDB::WriteDomainEntryIndex(const CDomainEntry& entry, const int op) { if (IsArgSet("-zmqpubbdaprecord")) { UniValue oName(UniValue::VOBJ); - oName.push_back(Pair("_id", stringFromVch(directory.OID))); - CDynamicAddress address(EncodeBase58(directory.WalletAddress)); + oName.push_back(Pair("_id", stringFromVch(entry.OID))); + CDynamicAddress address(EncodeBase58(entry.WalletAddress)); oName.push_back(Pair("address", address.ToString())); - oName.push_back(Pair("expires_on", directory.nExpireTime)); - oName.push_back(Pair("encryption_publickey", HexStr(directory.EncryptPublicKey))); + oName.push_back(Pair("expires_on", entry.nExpireTime)); + oName.push_back(Pair("encryption_publickey", HexStr(entry.EncryptPublicKey))); GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_record"); } - WriteDirectoryIndexHistory(directory, op); + WriteDomainEntryIndexHistory(entry, op); } -bool CDirectoryDB::UpdateDirectory(const std::vector& vchObjectPath, const CDirectory& directory) +bool CDomainEntryDB::UpdateDomainEntry(const std::vector& vchObjectPath, const CDomainEntry& entry) { - LOCK(cs_bdap_directory); + LOCK(cs_bdap_entry); - if (!EraseDirectoryAddress(directory.WalletAddress)) + if (!EraseDomainEntryAddress(entry.WalletAddress)) return false; bool writeState = false; - writeState = Update(make_pair(std::string("domain_component"), directory.GetFullObjectPath()), directory) - && Write(make_pair(std::string("domain_wallet_address"), directory.WalletAddress), directory.GetFullObjectPath()); + writeState = Update(make_pair(std::string("domain_component"), entry.GetFullObjectPath()), entry) + && Write(make_pair(std::string("domain_wallet_address"), entry.WalletAddress), entry.GetFullObjectPath()); if (writeState) - AddDirectoryIndex(directory, OP_BDAP_MODIFY); + AddDomainEntryIndex(entry, OP_BDAP_MODIFY); return writeState; } // Removes expired records from databases. -bool CDirectoryDB::CleanupLevelDB(int& nRemoved) +bool CDomainEntryDB::CleanupLevelDB(int& nRemoved) { boost::scoped_ptr pcursor(NewIterator()); pcursor->SeekToFirst(); - CDirectory dirEntry; + CDomainEntry dirEntry; std::pair > key; while (pcursor->Valid()) { boost::this_thread::interruption_point(); @@ -181,18 +181,18 @@ bool CDirectoryDB::CleanupLevelDB(int& nRemoved) if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= dirEntry.nExpireTime) { nRemoved++; - EraseDirectory(key.second); + EraseDomainEntry(key.second); } } else if (pcursor->GetKey(key) && key.first == "domain_wallet_address") { std::vector value; - CDirectory directory; + CDomainEntry entry; pcursor->GetValue(value); - if (GetDirectory(value, directory) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= directory.nExpireTime) + if (GetDomainEntry(value, entry) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) { nRemoved++; - EraseDirectoryAddress(directory.vchFullObjectPath()); + EraseDomainEntryAddress(entry.vchFullObjectPath()); } } pcursor->Next(); @@ -204,7 +204,7 @@ bool CDirectoryDB::CleanupLevelDB(int& nRemoved) } // Lists active entries by domain name with paging support -bool CDirectoryDB::ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDirectoryList) +bool CDomainEntryDB::ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDomainEntryList) { // TODO: (bdap) implement paging // if vchObjectLocation is empty, list entries from all domains @@ -214,15 +214,15 @@ bool CDirectoryDB::ListDirectories(const std::vector& vchObjectLo pcursor->SeekToFirst(); while (pcursor->Valid()) { boost::this_thread::interruption_point(); - CDirectory directory; + CDomainEntry entry; try { if (pcursor->GetKey(key) && key.first == "domain_component") { - pcursor->GetValue(directory); - if (vchObjectLocation.empty() || directory.vchObjectLocation() == vchObjectLocation) + pcursor->GetValue(entry); + if (vchObjectLocation.empty() || entry.vchObjectLocation() == vchObjectLocation) { - UniValue oDirectoryEntry(UniValue::VOBJ); - BuildBDAPJson(directory, oDirectoryEntry, true); - oDirectoryList.push_back(oDirectoryEntry); + UniValue oDomainEntryEntry(UniValue::VOBJ); + BuildBDAPJson(entry, oDomainEntryEntry, true); + oDomainEntryList.push_back(oDomainEntryEntry); index++; } } @@ -235,23 +235,23 @@ bool CDirectoryDB::ListDirectories(const std::vector& vchObjectLo return true; } -bool CDirectoryDB::GetDirectoryInfo(const std::vector& vchFullObjectPath, UniValue& oDirectoryInfo) +bool CDomainEntryDB::GetDomainEntryInfo(const std::vector& vchFullObjectPath, UniValue& oDomainEntryInfo) { - CDirectory directory; - if (!ReadDirectory(vchFullObjectPath, directory)) { + CDomainEntry entry; + if (!ReadDomainEntry(vchFullObjectPath, entry)) { return false; } - if (!BuildBDAPJson(directory, oDirectoryInfo, false)) { + if (!BuildBDAPJson(entry, oDomainEntryInfo, false)) { return false; } return true; } -bool CheckDirectoryDB() +bool CheckDomainEntryDB() { - if (!pDirectoryDB) + if (!pDomainEntryDB) return false; return true; @@ -260,10 +260,10 @@ bool CheckDirectoryDB() bool FlushLevelDB() { { - LOCK(cs_bdap_directory); - if (pDirectoryDB != NULL) + LOCK(cs_bdap_entry); + if (pDomainEntryDB != NULL) { - if (!pDirectoryDB->Flush()) { + if (!pDomainEntryDB->Flush()) { LogPrintf("Failed to write to BDAP database!"); return false; } @@ -274,17 +274,17 @@ bool FlushLevelDB() void CleanupLevelDB(int& nRemoved) { - if(pDirectoryDB != NULL) - pDirectoryDB->CleanupLevelDB(nRemoved); + if(pDomainEntryDB != NULL) + pDomainEntryDB->CleanupLevelDB(nRemoved); FlushLevelDB(); } -static bool CommonDataCheck(const CDirectory& directory, const vchCharString& vvchOpParameters, std::string& errorMessage) +static bool CommonDataCheck(const CDomainEntry& entry, const vchCharString& vvchOpParameters, std::string& errorMessage) { - if (directory.IsNull() == true) + if (entry.IsNull() == true) { - errorMessage = "CommonDataCheck failed! Directory is null."; + errorMessage = "CommonDataCheck failed! DomainEntry is null."; return false; } @@ -294,25 +294,25 @@ static bool CommonDataCheck(const CDirectory& directory, const vchCharString& vv return false; } - if (directory.GetFullObjectPath() != stringFromVch(vvchOpParameters[0])) + if (entry.GetFullObjectPath() != stringFromVch(vvchOpParameters[0])) { - errorMessage = "CommonDataCheck failed! Script operation parameter does not match directory entry object."; + errorMessage = "CommonDataCheck failed! Script operation parameter does not match entry entry object."; return false; } - if (directory.DomainComponent != vchDefaultDomainName) + if (entry.DomainComponent != vchDefaultDomainName) { errorMessage = "CommonDataCheck failed! Must use default domain."; return false; } - if (directory.OrganizationalUnit != vchDefaultPublicOU && directory.OrganizationalUnit != vchDefaultAdminOU) + if (entry.OrganizationalUnit != vchDefaultPublicOU && entry.OrganizationalUnit != vchDefaultAdminOU) { errorMessage = "CommonDataCheck failed! Must use default public organizational unit."; return false; } - if (directory.OrganizationalUnit == vchDefaultAdminOU) + if (entry.OrganizationalUnit == vchDefaultAdminOU) { errorMessage = "CommonDataCheck failed! Can not use default admin domain."; return false; @@ -321,167 +321,167 @@ static bool CommonDataCheck(const CDirectory& directory, const vchCharString& vv return true; } -bool CheckNewDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { - if (!CommonDataCheck(directory, vvchOpParameters, errorMessage)) + if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) return error(errorMessage.c_str()); if (fJustCheck) return true; - CDirectory getDirectory; - if (GetDirectory(directory.vchFullObjectPath(), getDirectory)) + CDomainEntry getDomainEntry; + if (GetDomainEntry(entry.vchFullObjectPath(), getDomainEntry)) { - errorMessage = "CheckNewDirectoryTxInputs: - The entry " + getDirectory.GetFullObjectPath() + " already exists. Add new entry failed!"; + errorMessage = "CheckNewDomainEntryTxInputs: - The entry " + getDomainEntry.GetFullObjectPath() + " already exists. Add new entry failed!"; return error(errorMessage.c_str()); } - if (!pDirectoryDB) + if (!pDomainEntryDB) { - errorMessage = "CheckNewDirectoryTxInputs failed! Can not open LevelDB BDAP entry database."; + errorMessage = "CheckNewDomainEntryTxInputs failed! Can not open LevelDB BDAP entry database."; return error(errorMessage.c_str()); } - if (!pDirectoryDB->AddDirectory(directory, op)) + if (!pDomainEntryDB->AddDomainEntry(entry, op)) { - errorMessage = "CheckNewDirectoryTxInputs failed! Error adding new directory entry request to LevelDB."; + errorMessage = "CheckNewDomainEntryTxInputs failed! Error adding new entry entry request to LevelDB."; return error(errorMessage.c_str()); } return FlushLevelDB(); } -bool CheckDeleteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { //if exists, check for owner's signature - if (!CommonDataCheck(directory, vvchOpParameters, errorMessage)) + if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) return error(errorMessage.c_str()); if (fJustCheck) return true; - CDirectory prevDirectory; - if (!GetDirectory(directory.vchFullObjectPath(), prevDirectory)) + CDomainEntry prevDomainEntry; + if (!GetDomainEntry(entry.vchFullObjectPath(), prevDomainEntry)) { - errorMessage = "CheckDeleteDirectoryTxInputs: - Can not find " + prevDirectory.GetFullObjectPath() + " entry; this delete operation failed!"; + errorMessage = "CheckDeleteDomainEntryTxInputs: - Can not find " + prevDomainEntry.GetFullObjectPath() + " entry; this delete operation failed!"; return error(errorMessage.c_str()); } CTxDestination bdapDest; if (!ExtractDestination(scriptOp, bdapDest)) { - errorMessage = "CheckDeleteDirectoryTxInputs: - " + _("Cannot extract destination of BDAP input; this delete operation failed!"); + errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("Cannot extract destination of BDAP input; this delete operation failed!"); return error(errorMessage.c_str()); } else { CDynamicAddress prevSignAddress(bdapDest); { - if (EncodeBase58(directory.SignWalletAddress) != prevSignAddress.ToString()) - errorMessage = "CheckDeleteDirectoryTxInputs: - " + _("You are not the owner of this BDAP entry; this delete operation failed!"); + if (EncodeBase58(entry.SignWalletAddress) != prevSignAddress.ToString()) + errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("You are not the owner of this BDAP entry; this delete operation failed!"); return error(errorMessage.c_str()); } } - if (!pDirectoryDB->EraseDirectory(directory.vchFullObjectPath())) + if (!pDomainEntryDB->EraseDomainEntry(entry.vchFullObjectPath())) { - errorMessage = "CheckDeleteDirectoryTxInputs: - Error deleting directory entry in LevelDB; this delete operation failed!"; + errorMessage = "CheckDeleteDomainEntryTxInputs: - Error deleting entry entry in LevelDB; this delete operation failed!"; return error(errorMessage.c_str()); } return FlushLevelDB(); } -bool CheckActivateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckActivateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { - //check name in operation matches directory data in leveldb as a new request + //check name in operation matches entry data in leveldb as a new request //check if new request exists and is not expired return false; } -bool CheckUpdateDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { //if exists, check for owner's signature - if (!CommonDataCheck(directory, vvchOpParameters, errorMessage)) + if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) return error(errorMessage.c_str()); if (fJustCheck) return true; - CDirectory prevDirectory; - if (!GetDirectory(directory.vchFullObjectPath(), prevDirectory)) + CDomainEntry prevDomainEntry; + if (!GetDomainEntry(entry.vchFullObjectPath(), prevDomainEntry)) { - errorMessage = "CheckUpdateDirectoryTxInputs: - Can not find " + prevDirectory.GetFullObjectPath() + " entry; this update operation failed!"; + errorMessage = "CheckUpdateDomainEntryTxInputs: - Can not find " + prevDomainEntry.GetFullObjectPath() + " entry; this update operation failed!"; return error(errorMessage.c_str()); } CTxDestination bdapDest; if (!ExtractDestination(scriptOp, bdapDest)) { - errorMessage = "CheckUpdateDirectoryTxInputs: - " + _("Cannot extract destination of BDAP input; this update operation failed!"); + errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Cannot extract destination of BDAP input; this update operation failed!"); return error(errorMessage.c_str()); } else { CDynamicAddress prevSignAddress(bdapDest); { - if (EncodeBase58(directory.SignWalletAddress) != prevSignAddress.ToString()) - errorMessage = "CheckUpdateDirectoryTxInputs: - " + _("You are not the owner of this BDAP entry; this update operation failed!"); + if (EncodeBase58(entry.SignWalletAddress) != prevSignAddress.ToString()) + errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("You are not the owner of this BDAP entry; this update operation failed!"); return error(errorMessage.c_str()); } } - if (!pDirectoryDB->UpdateDirectory(directory.vchFullObjectPath(), directory)) + if (!pDomainEntryDB->UpdateDomainEntry(entry.vchFullObjectPath(), entry)) { - errorMessage = "CheckUpdateDirectoryTxInputs: - Error updating directory entry in LevelDB; this update operation failed!"; + errorMessage = "CheckUpdateDomainEntryTxInputs: - Error updating entry entry in LevelDB; this update operation failed!"; return error(errorMessage.c_str()); } return FlushLevelDB(); } -bool CheckMoveDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckMoveDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { - //check name in operation matches directory data in leveldb + //check name in operation matches entry data in leveldb //check if exists already //if exists, check for owner's signature return false; } -bool CheckExecuteDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckExecuteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { - //check name in operation matches directory data in leveldb + //check name in operation matches entry data in leveldb //check if exists already //if exists, check for owner's signature return false; } -bool CheckBindDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { - //check names in operation matches directory data in leveldb + //check names in operation matches entry data in leveldb //check if request or accept response //check if names exists already //if exists, check for owner's signature return false; } -bool CheckRevokeDirectoryTxInputs(const CTransaction& tx, const CDirectory& directory, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckRevokeDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const int op, std::string& errorMessage, bool fJustCheck) { - //check name in operation matches directory data in leveldb + //check name in operation matches entry data in leveldb //check if names exists already //if exists, check for fluid signature return false; } -bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, +bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck) { if (tx.IsCoinBase() && !fJustCheck && !bSanityCheck) @@ -491,56 +491,56 @@ bool CheckDirectoryTxInputs(const CCoinsViewCache& inputs, const CTransaction& t } //if (fDebug && !bSanityCheck) - LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, directoryFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, DomainEntryFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); CScript scriptOp; vchCharString vvchOpParameters; - if (!GetDirectoryOpScript(tx, scriptOp, vvchOpParameters, op)) + if (!GetDomainEntryOpScript(tx, scriptOp, vvchOpParameters, op)) { errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3600 - " + _("Transaction does not contain BDAP operation script!"); return error(errorMessage.c_str()); } - const std::string strOperationType = GetDirectoryOpTypeString(scriptOp); + const std::string strOperationType = GetDomainEntryOpTypeString(scriptOp); if (fDebug) - LogPrintf("CheckDirectoryTxInputs, strOperationType= %s \n", strOperationType); + LogPrintf("CheckDomainEntryTxInputs, strOperationType= %s \n", strOperationType); // unserialize BDAP from txn, check if the entry is valid and does not conflict with a previous entry - CDirectory directory; + CDomainEntry entry; std::vector vchData; std::vector vchHash; int nDataOut; - bool bData = GetDirectoryData(tx, vchData, vchHash, nDataOut); - if(bData && !directory.UnserializeFromData(vchData, vchHash)) + bool bData = GetDomainEntryData(tx, vchData, vchHash, nDataOut); + if(bData && !entry.UnserializeFromData(vchData, vchHash)) { errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3601 - " + _("UnserializeFromData data in tx failed!"); return error(errorMessage.c_str()); } - if(!directory.ValidateValues(errorMessage)) + if(!entry.ValidateValues(errorMessage)) { errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3602 - " + errorMessage; return error(errorMessage.c_str()); } - directory.txHash = tx.GetHash(); + entry.txHash = tx.GetHash(); if (strOperationType == "bdap_new") - return CheckNewDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckNewDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_delete") - return CheckDeleteDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckDeleteDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_activate") - return CheckActivateDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckActivateDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_update") - return CheckUpdateDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckUpdateDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_move") - return CheckMoveDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckMoveDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_execute") - return CheckExecuteDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckExecuteDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_bind") - return CheckBindDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckBindDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); else if (strOperationType == "bdap_revoke") - return CheckRevokeDirectoryTxInputs(tx, directory, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckRevokeDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); return false; } \ No newline at end of file diff --git a/src/bdap/domainentrydb.h b/src/bdap/domainentrydb.h new file mode 100644 index 0000000000..ef82f1671b --- /dev/null +++ b/src/bdap/domainentrydb.h @@ -0,0 +1,61 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_DOMAINENTRYDB_H +#define DYNAMIC_BDAP_DOMAINENTRYDB_H + +#include "bdap/domainentry.h" +#include "dbwrapper.h" + +static CCriticalSection cs_bdap_entry; + +class CDomainEntryDB : public CDBWrapper { +public: + CDomainEntryDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "bdap", nCacheSize, fMemory, fWipe, obfuscate) { + } + + // Add, Read, Modify, ModifyRDN, Delete, List, Search, Bind, and Compare + bool AddDomainEntry(const CDomainEntry& entry, const int op); + void AddDomainEntryIndex(const CDomainEntry& entry, const int op); + bool ReadDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry); + bool ReadDomainEntryAddress(const std::vector& vchAddress, std::vector& vchObjectPath); + bool EraseDomainEntry(const std::vector& vchObjectPath); + bool EraseDomainEntryAddress(const std::vector& vchAddress); + bool DomainEntryExists(const std::vector& vchObjectPath); + bool DomainEntryExistsAddress(const std::vector& vchAddress); + bool RemoveExpired(int& entriesRemoved); + void WriteDomainEntryIndex(const CDomainEntry& entry, const int op); + void WriteDomainEntryIndexHistory(const CDomainEntry& entry, const int op); + bool UpdateDomainEntry(const std::vector& vchObjectPath, const CDomainEntry& entry); + bool CleanupLevelDB(int& nRemoved); + bool ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDomainEntryList); + bool GetDomainEntryInfo(const std::vector& vchFullObjectPath, UniValue& oDomainEntryInfo); +}; + +bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry); +bool CheckDomainEntryDB(); +bool FlushLevelDB(); +void CleanupLevelDB(int& nRemoved); +bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckActivateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckMoveDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckExecuteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckRevokeDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, + const int op, std::string& errorMessage, bool fJustCheck); +bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, + int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); + +extern CDomainEntryDB *pDomainEntryDB; + +#endif // DYNAMIC_BDAP_DOMAINENTRYDB_H \ No newline at end of file diff --git a/src/bdap/rpcdirectory.cpp b/src/bdap/rpcdomainentry.cpp similarity index 69% rename from src/bdap/rpcdirectory.cpp rename to src/bdap/rpcdomainentry.cpp index 2995b18e0e..20d2db2724 100644 --- a/src/bdap/rpcdirectory.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -2,8 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "bdap/directory.h" -#include "bdap/directorydb.h" +#include "bdap/domainentry.h" +#include "bdap/domainentrydb.h" #include "core_io.h" // needed for ScriptToAsmStr #include "rpcprotocol.h" #include "rpcserver.h" @@ -37,19 +37,19 @@ UniValue addpublicname(const JSONRPCRequest& request) - CDirectory txDirectory; - txDirectory.OID = vchDefaultOIDPrefix; - txDirectory.DomainComponent = vchDefaultDomainName; - txDirectory.OrganizationalUnit = vchDefaultPublicOU; - txDirectory.CommonName = vchCommonName; - txDirectory.OrganizationName = vchDefaultOrganizationName; - txDirectory.ObjectID = vchObjectID; - txDirectory.fPublicObject = 1; //make entry public - txDirectory.transactionFee = 100; + CDomainEntry txDomainEntry; + txDomainEntry.OID = vchDefaultOIDPrefix; + txDomainEntry.DomainComponent = vchDefaultDomainName; + txDomainEntry.OrganizationalUnit = vchDefaultPublicOU; + txDomainEntry.CommonName = vchCommonName; + txDomainEntry.OrganizationName = vchDefaultOrganizationName; + txDomainEntry.ObjectID = vchObjectID; + txDomainEntry.fPublicObject = 1; //make entry public + txDomainEntry.transactionFee = 100; // Check if name already exists - if (GetDirectory(txDirectory.vchFullObjectPath(), txDirectory)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3500 - " + txDirectory.GetFullObjectPath() + _(" entry already exists. Can not add duplicate.")); + if (GetDomainEntry(txDomainEntry.vchFullObjectPath(), txDomainEntry)) + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3500 - " + txDomainEntry.GetFullObjectPath() + _(" entry already exists. Can not add duplicate.")); // TODO: Add ability to pass in the wallet address and public key CKey privWalletKey; @@ -64,7 +64,7 @@ UniValue addpublicname(const JSONRPCRequest& request) std::string strWalletAddress = CDynamicAddress(keyWalletID).ToString(); CharString vchWalletAddress(strWalletAddress.begin(), strWalletAddress.end()); - txDirectory.WalletAddress = vchWalletAddress; + txDomainEntry.WalletAddress = vchWalletAddress; CKey privEncryptKey; privEncryptKey.MakeNewKey(true); @@ -75,7 +75,7 @@ UniValue addpublicname(const JSONRPCRequest& request) if (pwalletMain && !pwalletMain->AddKeyPubKey(privEncryptKey, pubEncryptKey)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3503 - " + _("Error adding encrypt key to wallet for BDAP")); - txDirectory.EncryptPublicKey = vchEncryptPubKey; + txDomainEntry.EncryptPublicKey = vchEncryptPubKey; CKey privSignKey; privSignKey.MakeNewKey(true); @@ -88,27 +88,27 @@ UniValue addpublicname(const JSONRPCRequest& request) if (pwalletMain && !pwalletMain->AddKeyPubKey(privSignKey, pubSignKey)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3504 - " + _("Error adding signature key to wallet for BDAP")); - txDirectory.SignWalletAddress = vchSignWalletAddress; + txDomainEntry.SignWalletAddress = vchSignWalletAddress; uint64_t nDays = 1461; //default to 4 years. if (request.params.size() >= 3) { nDays = request.params[2].get_int(); } uint64_t nSeconds = nDays * SECONDS_PER_DAY; - txDirectory.nExpireTime = chainActive.Tip()->GetMedianTimePast() + nSeconds; + txDomainEntry.nExpireTime = chainActive.Tip()->GetMedianTimePast() + nSeconds; CharString data; - txDirectory.Serialize(data); + txDomainEntry.Serialize(data); // Create BDAP OP_RETURN Signature Scripts CScript scriptPubKey; - std::vector vchFullObjectPath = txDirectory.vchFullObjectPath(); + std::vector vchFullObjectPath = txDomainEntry.vchFullObjectPath(); scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_NEW) << vchFullObjectPath << OP_2DROP << OP_DROP; CScript scriptDestination; scriptDestination = GetScriptForDestination(signWallet.Get()); scriptPubKey += scriptDestination; - LogPrintf("BDAP GetDirectoryType = %s \n", GetDirectoryOpTypeString(scriptPubKey)); + LogPrintf("BDAP GetDomainEntryType = %s \n", GetDomainEntryOpTypeString(scriptPubKey)); CScript scriptData; scriptData << OP_RETURN << data; @@ -121,26 +121,26 @@ UniValue addpublicname(const JSONRPCRequest& request) // check BDAP values std::string strMessage; - if (!txDirectory.ValidateValues(strMessage)) + if (!txDomainEntry.ValidateValues(strMessage)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3501 - " + strMessage); SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); - txDirectory.txHash = wtx.GetHash(); + txDomainEntry.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); - if(!BuildBDAPJson(txDirectory, oName)) + if(!BuildBDAPJson(txDomainEntry, oName)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Failed to read from BDAP JSON object")); if (fPrintDebug) { - // make sure we can deserialize the transaction from the scriptData and get a valid CDirectory class - LogPrintf("Directory Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); + // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class + LogPrintf("DomainEntry Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); const CTransaction testTx = (CTransaction)wtx; - CDirectory testDirectory(testTx); //loads the class from a transaction + CDomainEntry testDomainEntry(testTx); //loads the class from a transaction - LogPrintf("CDirectory Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\nPrivateData = %s\n", - testDirectory.nVersion, testDirectory.GetFullObjectPath(), stringFromVch(testDirectory.CommonName), - stringFromVch(testDirectory.OrganizationalUnit), HexStr(testDirectory.EncryptPublicKey), stringFromVch(testDirectory.PrivateData)); + LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\nPrivateData = %s\n", + testDomainEntry.nVersion, testDomainEntry.GetFullObjectPath(), stringFromVch(testDomainEntry.CommonName), + stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey), stringFromVch(testDomainEntry.PrivateData)); } return oName; @@ -165,11 +165,11 @@ UniValue getdirectories(const JSONRPCRequest& request) std::string strObjectLocation = DEFAULT_PUBLIC_OU + "." + DEFAULT_PUBLIC_DOMAIN; CharString vchObjectLocation(strObjectLocation.begin(), strObjectLocation.end()); - UniValue oDirectoryList(UniValue::VARR); - if (CheckDirectoryDB()) - pDirectoryDB->ListDirectories(vchObjectLocation, nRecordsPerPage, nPage, oDirectoryList); + UniValue oDomainEntryList(UniValue::VARR); + if (CheckDomainEntryDB()) + pDomainEntryDB->ListDirectories(vchObjectLocation, nRecordsPerPage, nPage, oDomainEntryList); - return oDirectoryList; + return oDomainEntryList; } UniValue getdirectoryinfo(const JSONRPCRequest& request) @@ -182,14 +182,14 @@ UniValue getdirectoryinfo(const JSONRPCRequest& request) CharString vchObjectID = vchFromValue(request.params[0]); ToLowerCase(vchObjectID); - CDirectory directory; + CDomainEntry directory; directory.DomainComponent = vchDefaultDomainName; directory.OrganizationalUnit = vchDefaultPublicOU; directory.ObjectID = vchObjectID; - UniValue oDirectoryInfo(UniValue::VOBJ); - if (CheckDirectoryDB()) { - if (!pDirectoryDB->GetDirectoryInfo(directory.vchFullObjectPath(), oDirectoryInfo)) { + UniValue oDomainEntryInfo(UniValue::VOBJ); + if (CheckDomainEntryDB()) { + if (!pDomainEntryDB->GetDomainEntryInfo(directory.vchFullObjectPath(), oDomainEntryInfo)) { throw std::runtime_error("BDAP_SELECT_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3600 - " + directory.GetFullObjectPath() + _(" can not be found. Get info failed!")); } } @@ -197,7 +197,7 @@ UniValue getdirectoryinfo(const JSONRPCRequest& request) throw std::runtime_error("BDAP_SELECT_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3601 - " + _("Can not access BDAP LevelDB database. Get info failed!")); } - return oDirectoryInfo; + return oDomainEntryInfo; } UniValue updatedirectory(const JSONRPCRequest& request) { @@ -212,39 +212,39 @@ UniValue updatedirectory(const JSONRPCRequest& request) { CharString vchObjectID = vchFromValue(request.params[0]); ToLowerCase(vchObjectID); - CDirectory txDirectory; - txDirectory.DomainComponent = vchDefaultDomainName; - txDirectory.OrganizationalUnit = vchDefaultPublicOU; - txDirectory.ObjectID = vchObjectID; + CDomainEntry txDomainEntry; + txDomainEntry.DomainComponent = vchDefaultDomainName; + txDomainEntry.OrganizationalUnit = vchDefaultPublicOU; + txDomainEntry.ObjectID = vchObjectID; // Check if name already exists - if (!GetDirectory(txDirectory.vchFullObjectPath(), txDirectory)) - throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txDirectory.GetFullObjectPath() + _(" does not exists. Can not update.")); + if (!GetDomainEntry(txDomainEntry.vchFullObjectPath(), txDomainEntry)) + throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txDomainEntry.GetFullObjectPath() + _(" does not exists. Can not update.")); // TODO: Check if Signature Wallet address is owned. If not, return an error before submitting to the mem pool. CharString vchCommonName = vchFromValue(request.params[1]); - txDirectory.CommonName = vchCommonName; + txDomainEntry.CommonName = vchCommonName; uint64_t nDays = 1461; //default to 4 years. if (request.params.size() >= 3) { nDays = request.params[2].get_int(); } uint64_t nSeconds = nDays * SECONDS_PER_DAY; - txDirectory.nExpireTime = chainActive.Tip()->GetMedianTimePast() + nSeconds; + txDomainEntry.nExpireTime = chainActive.Tip()->GetMedianTimePast() + nSeconds; CharString data; - txDirectory.Serialize(data); + txDomainEntry.Serialize(data); // Create BDAP OP_RETURN Signature Scripts CScript scriptPubKey; - std::vector vchFullObjectPath = txDirectory.vchFullObjectPath(); + std::vector vchFullObjectPath = txDomainEntry.vchFullObjectPath(); scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_MODIFY) << vchFullObjectPath << OP_2DROP << OP_DROP; - CDynamicAddress signWallet(stringFromVch(txDirectory.SignWalletAddress)); + CDynamicAddress signWallet(stringFromVch(txDomainEntry.SignWalletAddress)); CScript scriptDestination; scriptDestination = GetScriptForDestination(signWallet.Get()); scriptPubKey += scriptDestination; - LogPrintf("BDAP GetDirectoryType = %s \n", GetDirectoryOpTypeString(scriptPubKey)); + LogPrintf("BDAP GetDomainEntryType = %s \n", GetDomainEntryOpTypeString(scriptPubKey)); CScript scriptData; scriptData << OP_RETURN << data; @@ -257,26 +257,26 @@ UniValue updatedirectory(const JSONRPCRequest& request) { // check BDAP values std::string strMessage; - if (!txDirectory.ValidateValues(strMessage)) + if (!txDomainEntry.ValidateValues(strMessage)) throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - " + strMessage); SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); - txDirectory.txHash = wtx.GetHash(); + txDomainEntry.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); - if(!BuildBDAPJson(txDirectory, oName)) + if(!BuildBDAPJson(txDomainEntry, oName)) throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3702 - " + _("Failed to read from BDAP JSON object")); if (fPrintDebug) { - // make sure we can deserialize the transaction from the scriptData and get a valid CDirectory class - LogPrintf("Directory Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); + // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class + LogPrintf("DomainEntry Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); const CTransaction testTx = (CTransaction)wtx; - CDirectory testDirectory(testTx); //loads the class from a transaction + CDomainEntry testDomainEntry(testTx); //loads the class from a transaction - LogPrintf("CDirectory Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\nPrivateData = %s\n", - testDirectory.nVersion, testDirectory.GetFullObjectPath(), stringFromVch(testDirectory.CommonName), - stringFromVch(testDirectory.OrganizationalUnit), HexStr(testDirectory.EncryptPublicKey), stringFromVch(testDirectory.PrivateData)); + LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\nPrivateData = %s\n", + testDomainEntry.nVersion, testDomainEntry.GetFullObjectPath(), stringFromVch(testDomainEntry.CommonName), + stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey), stringFromVch(testDomainEntry.PrivateData)); } return oName; @@ -293,7 +293,7 @@ static const CRPCCommand commands[] = #endif //ENABLE_WALLET }; -void RegisterDirectoryRPCCommands(CRPCTable &tableRPC) +void RegisterDomainEntryRPCCommands(CRPCTable &tableRPC) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); diff --git a/src/init.cpp b/src/init.cpp index fb123226c9..6336dccbeb 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -18,7 +18,7 @@ #include "chain.h" #include "chainparams.h" #include "checkpoints.h" -#include "bdap/directorydb.h" +#include "bdap/domainentrydb.h" #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeconfig.h" @@ -1480,7 +1480,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) delete pcoinscatcher; delete pblocktree; // BDAP Services DB's - delete pDirectoryDB; + delete pDomainEntryDB; pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); @@ -1489,7 +1489,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Init BDAP Services DB's bool obfuscate = false; - pDirectoryDB = new CDirectoryDB(nTotalCache * 35, false, fReindex, obfuscate); + pDomainEntryDB = new CDomainEntryDB(nTotalCache * 35, false, fReindex, obfuscate); if (fReindex) { pblocktree->WriteReindexing(true); diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 89c6f96c2f..fc3e17a926 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -9,7 +9,7 @@ #include "base58.h" #include "consensus/consensus.h" -#include "bdap/directory.h" +#include "bdap/domainentry.h" #include "instantsend.h" #include "validation.h" #include "privatesend.h" @@ -80,7 +80,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // Generated sub.type = TransactionRecord::Generated; } - if (IsDirectoryDataOutput(txout)) + if (IsDomainEntryDataOutput(txout)) { // BDAP type sub.type = TransactionRecord::BDAP; @@ -155,7 +155,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * { const CTxOut& txout = wtx.vout[nOut]; sub.idx = parts.size(); - if (IsDirectoryDataOutput(txout)) + if (IsDomainEntryDataOutput(txout)) { // BDAP type sub.type = TransactionRecord::BDAP; @@ -213,7 +213,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * sub.type = TransactionRecord::PrivateSend; } - if(IsDirectoryDataOutput(txout)) + if(IsDomainEntryDataOutput(txout)) { sub.type = TransactionRecord::BDAP; } @@ -317,7 +317,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) { status.status = TransactionStatus::Unconfirmed; if (wtx.isAbandoned()) - status.status = TransactionStatus::Abandoned; + status.status = TransactionStatus::Abandoned; } else if (status.depth < RecommendedNumConfirmations) { @@ -345,5 +345,4 @@ QString TransactionRecord::getTxID() const int TransactionRecord::getOutputIndex() const { return idx; -} - +} \ No newline at end of file diff --git a/src/rpcregister.h b/src/rpcregister.h index 4adae52aff..e91835181a 100644 --- a/src/rpcregister.h +++ b/src/rpcregister.h @@ -27,7 +27,7 @@ void RegisterGovernanceRPCCommands(CRPCTable &tableRPC); /** Register fluid RPC commands */ void RegisterFluidRPCCommands(CRPCTable &tableRPC); /** Register BDAP RPC commands */ -void RegisterDirectoryRPCCommands(CRPCTable &tableRPC); +void RegisterDomainEntryRPCCommands(CRPCTable &tableRPC); static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) { RegisterBlockchainRPCCommands(tableRPC); @@ -38,7 +38,7 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) RegisterDynodeRPCCommands(tableRPC); RegisterGovernanceRPCCommands(tableRPC); RegisterFluidRPCCommands(tableRPC); - RegisterDirectoryRPCCommands(tableRPC); + RegisterDomainEntryRPCCommands(tableRPC); } #endif // DYNAMIC_RPCREGISTER_H \ No newline at end of file diff --git a/src/script/script.cpp b/src/script/script.cpp index b194765d3e..740906e5a8 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -139,7 +139,7 @@ const char* GetOpName(opcodetype opcode) case OP_NOP9 : return "OP_NOP9"; case OP_NOP10 : return "OP_NOP10"; - // fluid + // fluid case OP_MINT : return "OP_MINT"; case OP_REWARD_DYNODE : return "OP_REWARD_DYNODE"; case OP_REWARD_MINING : return "OP_REWARD_MINING"; @@ -172,7 +172,7 @@ const char* GetOpName(opcodetype opcode) } // TODO (bdap): move functions below to seperate code file -bool IsDirectoryOp(int op) +bool IsBDAPOp(int op) { return op == OP_BDAP || op == OP_BDAP_NEW @@ -201,7 +201,7 @@ bool DecodeBDAPScript(const CScript& script, int& op, std::vector OP_16) return false; op = CScript::DecodeOP_N(opcode); - if (!IsDirectoryOp(op)) + if (!IsBDAPOp(op)) return false; bool found = false; for (;;) { @@ -311,11 +311,11 @@ bool CScript::IsPayToPublicKeyHash() const // Extra-fast test for pay-to-pubkey-hash CScripts: return (this->size() == 25 && - (*this)[0] == OP_DUP && - (*this)[1] == OP_HASH160 && - (*this)[2] == 0x14 && - (*this)[23] == OP_EQUALVERIFY && - (*this)[24] == OP_CHECKSIG); + (*this)[0] == OP_DUP && + (*this)[1] == OP_HASH160 && + (*this)[2] == 0x14 && + (*this)[23] == OP_EQUALVERIFY && + (*this)[24] == OP_CHECKSIG); } bool CScript::IsPayToScriptHash() const diff --git a/src/script/script.h b/src/script/script.h index 4f5d4d4c21..e40aabaf60 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -701,7 +701,7 @@ class CScript : public CScriptBase return false; } - bool IsDirectoryScript(ProtocolCodes code) const + bool IsBDAPScript(ProtocolCodes code) const { switch(code) { case BDAP_START: diff --git a/src/validation.cpp b/src/validation.cpp index 940b2bf473..f306a63949 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -9,7 +9,7 @@ #include "alert.h" #include "arith_uint256.h" -#include "bdap/directorydb.h" +#include "bdap/domainentrydb.h" #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" @@ -592,7 +592,7 @@ bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const C if (!fLoaded) return true; - if (!CheckDirectoryDB()) + if (!CheckDomainEntryDB()) return true; std::string statusRpc = ""; @@ -610,10 +610,10 @@ bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const C bool bValid = false; if (tx.nVersion == BDAP_TX_VERSION) { - if (DecodeDirectoryTx(tx, op, vvchBDAPArgs)) + if (DecodeDomainEntryTx(tx, op, vvchBDAPArgs)) { std::string errorMessage; - bValid = CheckDirectoryTxInputs(inputs, tx, op, vvchBDAPArgs, fJustCheck, nHeight, errorMessage, bSanity); + bValid = CheckDomainEntryTxInputs(inputs, tx, op, vvchBDAPArgs, fJustCheck, nHeight, errorMessage, bSanity); if (!bValid) { errorMessage = "ValidateBDAPInputs: " + errorMessage; From 9290f4eabcaf6565013b7e0d37e8e4b66860406a Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 10 Aug 2018 15:40:17 -0500 Subject: [PATCH 0161/1653] [BDAP] Add domain entry link class for binding operations --- src/Makefile.am | 2 + src/bdap/entrylink.cpp | 57 +++++++++++++++++++++++++ src/bdap/entrylink.h | 97 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 src/bdap/entrylink.cpp create mode 100644 src/bdap/entrylink.h diff --git a/src/Makefile.am b/src/Makefile.am index 3dbd93cd2e..561f5dfe91 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -100,6 +100,7 @@ DYNAMIC_CORE_H = \ bdap/bdap.h \ bdap/domainentry.h \ bdap/domainentrydb.h \ + bdap/entrylink.h \ dbwrapper.h \ dynode.h \ dynode-payments.h \ @@ -224,6 +225,7 @@ libdynamic_server_a_SOURCES = \ checkpoints.cpp \ bdap/domainentry.cpp \ bdap/domainentrydb.cpp \ + bdap/entrylink.cpp \ dbwrapper.cpp \ dynode.cpp \ dynode-payments.cpp\ diff --git a/src/bdap/entrylink.cpp b/src/bdap/entrylink.cpp new file mode 100644 index 0000000000..f6064f1da2 --- /dev/null +++ b/src/bdap/entrylink.cpp @@ -0,0 +1,57 @@ + +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/entrylink.h" + +#include "bdap/domainentry.h" +#include "hash.h" +#include "script/script.h" +#include "streams.h" + +void CEntryLink::Serialize(std::vector& vchData) +{ + CDataStream dsEntryLink(SER_NETWORK, PROTOCOL_VERSION); + dsEntryLink << *this; + vchData = std::vector(dsEntryLink.begin(), dsEntryLink.end()); +} + +bool CEntryLink::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsEntryLink(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsEntryLink >> *this; + + std::vector vchEntryLinkData; + Serialize(vchEntryLinkData); + const uint256 &calculatedHash = Hash(vchEntryLinkData.begin(), vchEntryLinkData.end()); + const std::vector &vchRandEntryLink = vchFromValue(calculatedHash.GetHex()); + if(vchRandEntryLink != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CEntryLink::UnserializeFromTx(const CTransaction& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} \ No newline at end of file diff --git a/src/bdap/entrylink.h b/src/bdap/entrylink.h new file mode 100644 index 0000000000..5de8c9d4a1 --- /dev/null +++ b/src/bdap/entrylink.h @@ -0,0 +1,97 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_ENTRYLINK_H +#define DYNAMIC_BDAP_ENTRYLINK_H + +#include "bdap.h" +#include "serialize.h" +#include "uint256.h" + +/* +Entry linking is a DAP binding operation. This class is used to +manage domain entry link requests. When linking entries, we want +to use stealth addresses so the linkage requests are not public. +*/ + +class CTransaction; + +class CEntryLink { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString SenderFullPath; // points to the link requestor's full domain entry path + CharString SenderPublicKey; // an unique public key for this link request + CharString RecipientFullPath; // points to the link recipient's full domain entry path + CharString RecipientPublicKey; // an unique public key for this link request + unsigned int nHeight; + uint64_t nExpireTime; + uint256 txHash; + + CEntryLink() { + SetNull(); + } + + CEntryLink(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CEntryLink::CURRENT_VERSION; + SenderFullPath.clear(); + SenderPublicKey.clear(); + RecipientFullPath.clear(); + RecipientPublicKey.clear(); + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(SenderFullPath); + READWRITE(SenderPublicKey); + READWRITE(RecipientFullPath); + READWRITE(RecipientPublicKey); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CEntryLink &a, const CEntryLink &b) { + return (a.SenderFullPath == b.SenderFullPath && a.RecipientFullPath == b.RecipientFullPath && a.nHeight == b.nHeight); + } + + inline friend bool operator!=(const CEntryLink &a, const CEntryLink &b) { + return !(a == b); + } + + inline CEntryLink operator=(const CEntryLink &b) { + SenderFullPath = b.SenderFullPath; + SenderFullPath = b.SenderFullPath; + SenderPublicKey = b.SenderPublicKey; + RecipientFullPath = b.RecipientFullPath; + RecipientPublicKey = b.RecipientPublicKey; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (SenderFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); + bool UnserializeFromTx(const CTransaction &tx); + + bool IsMyRequest(const CTransaction& tx); + CharString SenderFileName(unsigned int nTime); + CharString RecipientFileName(unsigned int nTime); +}; + +#endif // DYNAMIC_BDAP_ENTRYLINK_H \ No newline at end of file From 0e8545d4e57abb4cd51e77be8f0b3944afadd558 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 10 Aug 2018 16:35:50 -0500 Subject: [PATCH 0162/1653] [BDAP] Refactor domain entry certificate and move to its own class --- src/Makefile.am | 2 + src/bdap/bdap.h | 3 + src/bdap/domainentry.cpp | 9 --- src/bdap/domainentry.h | 5 +- src/bdap/entrycertificate.cpp | 101 ++++++++++++++++++++++++++++++++ src/bdap/entrycertificate.h | 107 ++++++++++++++++++++++++++++++++++ 6 files changed, 214 insertions(+), 13 deletions(-) create mode 100644 src/bdap/entrycertificate.cpp create mode 100644 src/bdap/entrycertificate.h diff --git a/src/Makefile.am b/src/Makefile.am index 561f5dfe91..c4d7ce143b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -100,6 +100,7 @@ DYNAMIC_CORE_H = \ bdap/bdap.h \ bdap/domainentry.h \ bdap/domainentrydb.h \ + bdap/entrycertificate.h \ bdap/entrylink.h \ dbwrapper.h \ dynode.h \ @@ -225,6 +226,7 @@ libdynamic_server_a_SOURCES = \ checkpoints.cpp \ bdap/domainentry.cpp \ bdap/domainentrydb.cpp \ + bdap/entrycertificate.cpp \ bdap/entrylink.cpp \ dbwrapper.cpp \ dynode.cpp \ diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h index 177c82ffb9..fa145afbda 100644 --- a/src/bdap/bdap.h +++ b/src/bdap/bdap.h @@ -14,11 +14,14 @@ typedef std::vector > vCheckPoints; // << height static constexpr unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) static constexpr unsigned int MAX_OBJECT_NAME_LENGTH = 63; +static constexpr unsigned int MAX_OBJECT_FULL_PATH_LENGTH = (MAX_OBJECT_NAME_LENGTH * 3) + 2; // domain + ou + object name + 2 dot chars static constexpr unsigned int MAX_COMMON_NAME_LENGTH = 95; static constexpr unsigned int MAX_ORG_NAME_LENGTH = 95; static constexpr unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; static constexpr unsigned int MAX_KEY_LENGTH = 156; static constexpr unsigned int MAX_CERTIFICATE_LENGTH = 512; +static constexpr unsigned int MAX_CERTIFICATE_NAME = 63; +static constexpr unsigned int MAX_SIGNATURE_LENGTH = 65; // https://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always-65-13232-bytes-long static constexpr unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain static constexpr unsigned int MAX_NUMBER_CHECKPOINTS = 100; // Pay per byte for hosting on chain static constexpr unsigned int SECONDS_PER_DAY = 86400; // Number of seconds per day. diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 1bb65ff1c6..4147cb101d 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -307,14 +307,6 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) return false; } - // check certificate component - std::string strCertificate = stringFromVch(Certificate); - if (strCertificate.length() > MAX_CERTIFICATE_LENGTH) - { - errorMessage = "Invalid BDAP Certificate data. Can not have more than " + std::to_string(MAX_CERTIFICATE_LENGTH) + " characters."; - return false; - } - // check private data component std::string strPrivateData = stringFromVch(PrivateData); if (strPrivateData.length() > MAX_PRIVATE_DATA_LENGTH) @@ -371,7 +363,6 @@ bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) } oName.push_back(Pair("expires_on", expired_time)); oName.push_back(Pair("expired", expired)); - oName.push_back(Pair("certificate", stringFromVch(entry.Certificate))); oName.push_back(Pair("private_data", stringFromVch(entry.PrivateData))); oName.push_back(Pair("transaction_fee", entry.transactionFee)); oName.push_back(Pair("registration_fee", entry.registrationFeePerDay)); diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index d09d5e30f1..dfd8c2f5d0 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -79,7 +79,6 @@ class CDomainEntry { unsigned int nHeight; uint64_t nExpireTime; - CharString Certificate; CharString PrivateData; CAmount transactionFee; CAmount registrationFeePerDay; @@ -113,7 +112,6 @@ class CDomainEntry { txHash.SetNull(); nHeight = 0; nExpireTime = 0; - Certificate.clear(); PrivateData.clear(); transactionFee = 0; registrationFeePerDay = 0; @@ -141,7 +139,6 @@ class CDomainEntry { READWRITE(VARINT(nHeight)); READWRITE(txHash); READWRITE(VARINT(nExpireTime)); - READWRITE(Certificate); READWRITE(PrivateData); READWRITE(transactionFee); READWRITE(registrationFeePerDay); @@ -173,9 +170,9 @@ class CDomainEntry { txHash = b.txHash; nHeight = b.nHeight; nExpireTime = b.nExpireTime; - Certificate = b.Certificate; PrivateData = b.PrivateData; CheckpointHashes = b.CheckpointHashes; + txHash = b.txHash; return *this; } diff --git a/src/bdap/entrycertificate.cpp b/src/bdap/entrycertificate.cpp new file mode 100644 index 0000000000..bf511b6897 --- /dev/null +++ b/src/bdap/entrycertificate.cpp @@ -0,0 +1,101 @@ + +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/entrycertificate.h" + +#include "hash.h" +#include "script/script.h" +#include "streams.h" + +void CEntryCertificate::Serialize(std::vector& vchData) +{ + CDataStream dsEntryCertificate(SER_NETWORK, PROTOCOL_VERSION); + dsEntryCertificate << *this; + vchData = std::vector(dsEntryCertificate.begin(), dsEntryCertificate.end()); +} + +bool CEntryCertificate::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsEntryCertificate(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsEntryCertificate >> *this; + + std::vector vchEntryLinkData; + Serialize(vchEntryLinkData); + const uint256 &calculatedHash = Hash(vchEntryLinkData.begin(), vchEntryLinkData.end()); + const std::vector &vchRandEntryLink = vchFromValue(calculatedHash.GetHex()); + if(vchRandEntryLink != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CEntryCertificate::UnserializeFromTx(const CTransaction& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +bool CEntryCertificate::ValidateValues(std::string& errorMessage) +{ + // check certificate owner path + std::string strOwnerFullPath = stringFromVch(OwnerFullPath); + if (strOwnerFullPath.length() > MAX_OBJECT_FULL_PATH_LENGTH) // object + { + errorMessage = "Invalid BDAP owner full path name. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + + // check certificate name length + std::string strName = stringFromVch(Name); + if (strName.length() > MAX_CERTIFICATE_NAME) + { + errorMessage = "Invalid BDAP Certificate name. Can not have more than " + std::to_string(MAX_CERTIFICATE_NAME) + " characters."; + return false; + } + + // check certificate data length + std::string strCertificate = stringFromVch(CertificateData); + if (strCertificate.length() > MAX_CERTIFICATE_LENGTH) + { + errorMessage = "Invalid BDAP Certificate data. Can not have more than " + std::to_string(MAX_CERTIFICATE_LENGTH) + " characters."; + return false; + } + + // check authority full path + std::string strAuthorityFullPath = stringFromVch(AuthorityFullPath); + if (strAuthorityFullPath.length() > MAX_OBJECT_FULL_PATH_LENGTH) + { + errorMessage = "Invalid BDAP certificate authority full path. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + + // check authority full path + std::string strAuthoritySignature = stringFromVch(AuthoritySignature); + if (strAuthoritySignature.length() > MAX_SIGNATURE_LENGTH) + { + errorMessage = "Invalid BDAP certificate authority signature. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/bdap/entrycertificate.h b/src/bdap/entrycertificate.h new file mode 100644 index 0000000000..6a2b258a35 --- /dev/null +++ b/src/bdap/entrycertificate.h @@ -0,0 +1,107 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_ENTRYCERTIFICATE_H +#define DYNAMIC_BDAP_ENTRYCERTIFICATE_H + +#include "bdap.h" +#include "bdap/domainentry.h" +#include "serialize.h" +#include "uint256.h" + +class CTransaction; + +class CEntryCertificate { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString OwnerFullPath; // name of the owner's full domain entry path + CharString Name; // Certificate name + CharString CertificateData; + CharString AuthorityFullPath; + CharString AuthoritySignature; + unsigned int nHeight; + uint64_t nExpireTime; + uint256 txHash; + CDomainEntry* OwnerDomainEntry; + CDomainEntry* AuthorityDomainEntry; + + CEntryCertificate() { + SetNull(); + } + + CEntryCertificate(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CEntryCertificate::CURRENT_VERSION; + OwnerFullPath.clear(); + Name.clear(); + CertificateData.clear(); + AuthorityFullPath.clear(); + AuthoritySignature.clear(); + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + OwnerDomainEntry = nullptr; + AuthorityDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(OwnerFullPath); + READWRITE(Name); + READWRITE(CertificateData); + READWRITE(AuthorityFullPath); + READWRITE(AuthoritySignature); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CEntryCertificate &a, const CEntryCertificate &b) { + return (a.OwnerFullPath == b.OwnerFullPath && a.Name == b.Name && a.CertificateData == b.CertificateData && a.nExpireTime == b.nExpireTime); + } + + inline friend bool operator!=(const CEntryCertificate &a, const CEntryCertificate &b) { + return !(a == b); + } + + inline CEntryCertificate operator=(const CEntryCertificate &b) { + OwnerFullPath = b.OwnerFullPath; + Name = b.Name; + CertificateData = b.CertificateData; + AuthorityFullPath = b.AuthorityFullPath; + AuthoritySignature = b.AuthoritySignature; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (OwnerFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); + bool UnserializeFromTx(const CTransaction &tx); + + bool SelfSignedCertificate() const { + if (OwnerDomainEntry == nullptr || AuthorityDomainEntry == nullptr) + return false; + + if (OwnerDomainEntry == AuthorityDomainEntry) + return true; + + return false; + } + + bool ValidateValues(std::string& errorMessage); +}; + +#endif // DYNAMIC_BDAP_ENTRYCERTIFICATE_H \ No newline at end of file From 4f298a872d80bd2484c60d1cc4d23adf370f0532 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 10 Aug 2018 17:28:51 -0500 Subject: [PATCH 0163/1653] [BDAP] Refactor domain entry checkpoints and move to its own class --- src/Makefile.am | 2 + src/bdap/bdap.h | 6 ++- src/bdap/domainentry.cpp | 14 ------ src/bdap/domainentry.h | 5 -- src/bdap/entrycheckpoints.cpp | 94 +++++++++++++++++++++++++++++++++++ src/bdap/entrycheckpoints.h | 84 +++++++++++++++++++++++++++++++ 6 files changed, 184 insertions(+), 21 deletions(-) create mode 100644 src/bdap/entrycheckpoints.cpp create mode 100644 src/bdap/entrycheckpoints.h diff --git a/src/Makefile.am b/src/Makefile.am index c4d7ce143b..a4e50aa7de 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -101,6 +101,7 @@ DYNAMIC_CORE_H = \ bdap/domainentry.h \ bdap/domainentrydb.h \ bdap/entrycertificate.h \ + bdap/entrycheckpoints.h \ bdap/entrylink.h \ dbwrapper.h \ dynode.h \ @@ -227,6 +228,7 @@ libdynamic_server_a_SOURCES = \ bdap/domainentry.cpp \ bdap/domainentrydb.cpp \ bdap/entrycertificate.cpp \ + bdap/entrycheckpoints.cpp \ bdap/entrylink.cpp \ dbwrapper.cpp \ dynode.cpp \ diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h index fa145afbda..afff1d6745 100644 --- a/src/bdap/bdap.h +++ b/src/bdap/bdap.h @@ -10,7 +10,8 @@ typedef std::vector CharString; typedef std::vector vchCharString; -typedef std::vector > vCheckPoints; // << height, block hash >> +typedef std::pair CheckPoint; +typedef std::vector vCheckPoints; // << height, block hash >> static constexpr unsigned int ACTIVATE_BDAP_HEIGHT = 10; // TODO: Change for mainnet or spork activate (???) static constexpr unsigned int MAX_OBJECT_NAME_LENGTH = 63; @@ -23,7 +24,8 @@ static constexpr unsigned int MAX_CERTIFICATE_LENGTH = 512; static constexpr unsigned int MAX_CERTIFICATE_NAME = 63; static constexpr unsigned int MAX_SIGNATURE_LENGTH = 65; // https://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always-65-13232-bytes-long static constexpr unsigned int MAX_PRIVATE_DATA_LENGTH = 512; // Pay per byte for hosting on chain -static constexpr unsigned int MAX_NUMBER_CHECKPOINTS = 100; // Pay per byte for hosting on chain +static constexpr unsigned int MAX_NUMBER_CHECKPOINTS = 25; // Pay per byte for hosting on chain +static constexpr unsigned int MAX_CHECKPOINT_HASH_LENGTH = 64; static constexpr unsigned int SECONDS_PER_DAY = 86400; // Number of seconds per day. static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; static const std::string DEFAULT_PUBLIC_OU = "public"; diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 4147cb101d..e83a087fc3 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -212,14 +212,6 @@ std::vector CDomainEntry::vchObjectLocation() const { return vchReturnValue; } -void CDomainEntry::AddCheckpoint(const uint32_t& height, const CharString& vchHash) -{ - std::pair pairNewCheckpoint; - pairNewCheckpoint.first = height; - pairNewCheckpoint.second = vchHash; - CheckpointHashes.push_back(pairNewCheckpoint); -} - bool CDomainEntry::ValidateValues(std::string& errorMessage) { smatch sMatch; @@ -315,12 +307,6 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) return false; } - // make sure the number of checkpoints does not exceed limit - if (CheckpointHashes.size() > MAX_NUMBER_CHECKPOINTS) - { - errorMessage = "Invalid BDAP checkpoint count. Can not have more than " + std::to_string(MAX_NUMBER_CHECKPOINTS) + " checkpoints for one entry."; - return false; - } // TODO: (bdap) check if EncryptPublicKey is valid // TODO: (bdap) check WalletAddress and SignWalletAddress return true; diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index dfd8c2f5d0..655e1f23a4 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -82,7 +82,6 @@ class CDomainEntry { CharString PrivateData; CAmount transactionFee; CAmount registrationFeePerDay; - vCheckPoints CheckpointHashes; // used to store main chain hash checkpoints for added security CDomainEntry() { SetNull(); @@ -115,7 +114,6 @@ class CDomainEntry { PrivateData.clear(); transactionFee = 0; registrationFeePerDay = 0; - CheckpointHashes.clear(); } ADD_SERIALIZE_METHODS; @@ -142,7 +140,6 @@ class CDomainEntry { READWRITE(PrivateData); READWRITE(transactionFee); READWRITE(registrationFeePerDay); - READWRITE(CheckpointHashes); } inline friend bool operator==(const CDomainEntry &a, const CDomainEntry &b) { @@ -171,7 +168,6 @@ class CDomainEntry { nHeight = b.nHeight; nExpireTime = b.nExpireTime; PrivateData = b.PrivateData; - CheckpointHashes = b.CheckpointHashes; txHash = b.txHash; return *this; } @@ -186,7 +182,6 @@ class CDomainEntry { std::string GetObjectLocation() const; std::vector vchFullObjectPath() const; std::vector vchObjectLocation() const; // OU . Domain Name - void AddCheckpoint(const uint32_t& height, const CharString& vchHash); bool ValidateValues(std::string& errorMessage); }; diff --git a/src/bdap/entrycheckpoints.cpp b/src/bdap/entrycheckpoints.cpp new file mode 100644 index 0000000000..8a92fed8ed --- /dev/null +++ b/src/bdap/entrycheckpoints.cpp @@ -0,0 +1,94 @@ + +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/entrycheckpoints.h" + +#include "hash.h" +#include "script/script.h" +#include "streams.h" + +void CEntryCheckpoints::Serialize(std::vector& vchData) +{ + CDataStream dsEntryCheckpoints(SER_NETWORK, PROTOCOL_VERSION); + dsEntryCheckpoints << *this; + vchData = std::vector(dsEntryCheckpoints.begin(), dsEntryCheckpoints.end()); +} + +bool CEntryCheckpoints::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsEntryCheckpoints(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsEntryCheckpoints >> *this; + + std::vector vchEntryLinkData; + Serialize(vchEntryLinkData); + const uint256 &calculatedHash = Hash(vchEntryLinkData.begin(), vchEntryLinkData.end()); + const std::vector &vchRandEntryLink = vchFromValue(calculatedHash.GetHex()); + if(vchRandEntryLink != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CEntryCheckpoints::UnserializeFromTx(const CTransaction& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +bool CEntryCheckpoints::ValidateValues(std::string& errorMessage) +{ + // check certificate owner path + std::string strOwnerFullPath = stringFromVch(OwnerFullPath); + if (strOwnerFullPath.length() > MAX_OBJECT_FULL_PATH_LENGTH) // object + { + errorMessage = "Invalid BDAP owner full path name. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + + // check max checkpoints per transaction + if (CheckPointHashes.size() > MAX_NUMBER_CHECKPOINTS) + { + errorMessage = "Invalid number of BDAP checkpoints. Can not have more than " + std::to_string(MAX_NUMBER_CHECKPOINTS) + " checkpoints per transaction."; + return false; + } + + // check length of checkpoint hashes + for (unsigned int i = 0; i < CheckPointHashes.size(); i++) { + std::string strCheckpointHash = stringFromVch(CheckPointHashes[i].second); + if (strCheckpointHash.length() > MAX_CHECKPOINT_HASH_LENGTH) // object + { + errorMessage = "Invalid BDAP checkpoint hash length. Can not have more than " + std::to_string(MAX_CHECKPOINT_HASH_LENGTH) + " characters."; + return false; + } + } + + return true; +} + +void CEntryCheckpoints::AddCheckpoint(const uint32_t& height, const CharString& vchHash) +{ + CheckPoint pairNewCheckpoint; + pairNewCheckpoint.first = height; + pairNewCheckpoint.second = vchHash; + CheckPointHashes.push_back(pairNewCheckpoint); +} \ No newline at end of file diff --git a/src/bdap/entrycheckpoints.h b/src/bdap/entrycheckpoints.h new file mode 100644 index 0000000000..0eeeb5361e --- /dev/null +++ b/src/bdap/entrycheckpoints.h @@ -0,0 +1,84 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_ENTRYCHECKPOINT_H +#define DYNAMIC_BDAP_ENTRYCHECKPOINT_H + +#include "bdap.h" +#include "bdap/domainentry.h" +#include "serialize.h" +#include "uint256.h" + +class CTransaction; + +class CEntryCheckpoints { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString OwnerFullPath; // name of the owner's full domain entry path + vCheckPoints CheckPointHashes; // vector of checkpoints containing the entry's channel or sub-chain block height and hash + unsigned int nHeight; + //uint64_t nExpireTime; // not sure if needed. checkpoint will expire when owner channel expires + uint256 txHash; + CDomainEntry* OwnerDomainEntry; + + CEntryCheckpoints() { + SetNull(); + } + + CEntryCheckpoints(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CEntryCheckpoints::CURRENT_VERSION; + OwnerFullPath.clear(); + CheckPointHashes.clear(); + nHeight = 0; + txHash.SetNull(); + OwnerDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(OwnerFullPath); + READWRITE(CheckPointHashes); + READWRITE(VARINT(nHeight)); + READWRITE(txHash); + } + + inline friend bool operator==(const CEntryCheckpoints& a, const CEntryCheckpoints& b) { + return (a.OwnerFullPath == b.OwnerFullPath && a.CheckPointHashes == b.CheckPointHashes && a.nHeight == b.nHeight); + } + + inline friend bool operator!=(const CEntryCheckpoints& a, const CEntryCheckpoints& b) { + return !(a == b); + } + + inline CEntryCheckpoints operator=(const CEntryCheckpoints& b) { + OwnerFullPath = b.OwnerFullPath; + + for (unsigned int i = 0; i < b.CheckPointHashes.size(); i++) + CheckPointHashes.push_back(b.CheckPointHashes[i]); + + nHeight = b.nHeight; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (OwnerFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransaction& tx); + + bool ValidateValues(std::string& errorMessage); + void AddCheckpoint(const uint32_t& height, const CharString& vchHash); +}; + +#endif // DYNAMIC_BDAP_ENTRYCHECKPOINT_H \ No newline at end of file From b270de3930cfc6a81e396bbb1aaf77022b698442 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 10 Aug 2018 18:21:29 -0500 Subject: [PATCH 0164/1653] [BDAP] Refactor domain entry channel data and move to its own class --- src/Makefile.am | 2 + src/bdap/bdap.h | 1 + src/bdap/domainentry.cpp | 21 ------- src/bdap/domainentry.h | 19 ------ src/bdap/entrychannel.cpp | 85 ++++++++++++++++++++++++++ src/bdap/entrychannel.h | 118 ++++++++++++++++++++++++++++++++++++ src/bdap/rpcdomainentry.cpp | 11 ++-- 7 files changed, 210 insertions(+), 47 deletions(-) create mode 100644 src/bdap/entrychannel.cpp create mode 100644 src/bdap/entrychannel.h diff --git a/src/Makefile.am b/src/Makefile.am index a4e50aa7de..be82e8711f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -101,6 +101,7 @@ DYNAMIC_CORE_H = \ bdap/domainentry.h \ bdap/domainentrydb.h \ bdap/entrycertificate.h \ + bdap/entrychannel.h \ bdap/entrycheckpoints.h \ bdap/entrylink.h \ dbwrapper.h \ @@ -228,6 +229,7 @@ libdynamic_server_a_SOURCES = \ bdap/domainentry.cpp \ bdap/domainentrydb.cpp \ bdap/entrycertificate.cpp \ + bdap/entrychannel.cpp \ bdap/entrycheckpoints.cpp \ bdap/entrylink.cpp \ dbwrapper.cpp \ diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h index afff1d6745..091698e1d8 100644 --- a/src/bdap/bdap.h +++ b/src/bdap/bdap.h @@ -20,6 +20,7 @@ static constexpr unsigned int MAX_COMMON_NAME_LENGTH = 95; static constexpr unsigned int MAX_ORG_NAME_LENGTH = 95; static constexpr unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; static constexpr unsigned int MAX_KEY_LENGTH = 156; +static constexpr unsigned int MAX_DESCRIPTION_LENGTH = 256; static constexpr unsigned int MAX_CERTIFICATE_LENGTH = 512; static constexpr unsigned int MAX_CERTIFICATE_NAME = 63; static constexpr unsigned int MAX_SIGNATURE_LENGTH = 65; // https://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always-65-13232-bytes-long diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index e83a087fc3..1d6ab0a74e 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -291,22 +291,6 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) return false; } - // check resource pointer component - std::string strResourcePointer = stringFromVch(ResourcePointer); - if (strResourcePointer.length() > MAX_RESOURCE_POINTER_LENGTH) - { - errorMessage = "Invalid BDAP resource pointer. Can not have more than " + std::to_string(MAX_RESOURCE_POINTER_LENGTH) + " characters."; - return false; - } - - // check private data component - std::string strPrivateData = stringFromVch(PrivateData); - if (strPrivateData.length() > MAX_PRIVATE_DATA_LENGTH) - { - errorMessage = "Invalid BDAP private data. Can not have more than " + std::to_string(MAX_PRIVATE_DATA_LENGTH) + " characters."; - return false; - } - // TODO: (bdap) check if EncryptPublicKey is valid // TODO: (bdap) check WalletAddress and SignWalletAddress return true; @@ -331,8 +315,6 @@ bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) oName.push_back(Pair("signature_address", stringFromVch(entry.SignWalletAddress))); oName.push_back(Pair("public", (int)entry.fPublicObject)); oName.push_back(Pair("encryption_publickey", HexStr(entry.EncryptPublicKey))); - oName.push_back(Pair("sigatures_required", (int)entry.nSigaturesRequired)); - oName.push_back(Pair("resource_pointer", stringFromVch(entry.ResourcePointer))); oName.push_back(Pair("txid", entry.txHash.GetHex())); if ((unsigned int)chainActive.Height() >= entry.nHeight-1) { CBlockIndex *pindex = chainActive[entry.nHeight-1]; @@ -349,9 +331,6 @@ bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) } oName.push_back(Pair("expires_on", expired_time)); oName.push_back(Pair("expired", expired)); - oName.push_back(Pair("private_data", stringFromVch(entry.PrivateData))); - oName.push_back(Pair("transaction_fee", entry.transactionFee)); - oName.push_back(Pair("registration_fee", entry.registrationFeePerDay)); } else { oName.push_back(Pair("common_name", stringFromVch(entry.CommonName))); diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index 655e1f23a4..b47343eb6a 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -71,18 +71,12 @@ class CDomainEntry { int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. CharString SignWalletAddress; // used to verify authorized update transaction - unsigned int nSigaturesRequired; // number of signatures needed to approve a transaction. Default = 1 - CharString ResourcePointer; // used to point to a domain shared resource like a stream (video, audio, file sharing), P2P storage (BitTorrent or IPFS network), or private cloud storage uint256 txHash; unsigned int nHeight; uint64_t nExpireTime; - CharString PrivateData; - CAmount transactionFee; - CAmount registrationFeePerDay; - CDomainEntry() { SetNull(); } @@ -106,14 +100,9 @@ class CDomainEntry { fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); SignWalletAddress.clear(); - nSigaturesRequired = 1; - ResourcePointer.clear(); txHash.SetNull(); nHeight = 0; nExpireTime = 0; - PrivateData.clear(); - transactionFee = 0; - registrationFeePerDay = 0; } ADD_SERIALIZE_METHODS; @@ -132,14 +121,9 @@ class CDomainEntry { READWRITE(VARINT(fPublicObject)); READWRITE(EncryptPublicKey); READWRITE(SignWalletAddress); - READWRITE(VARINT(nSigaturesRequired)); - READWRITE(ResourcePointer); READWRITE(VARINT(nHeight)); READWRITE(txHash); READWRITE(VARINT(nExpireTime)); - READWRITE(PrivateData); - READWRITE(transactionFee); - READWRITE(registrationFeePerDay); } inline friend bool operator==(const CDomainEntry &a, const CDomainEntry &b) { @@ -162,12 +146,9 @@ class CDomainEntry { fPublicObject = b.fPublicObject; EncryptPublicKey = b.EncryptPublicKey; SignWalletAddress = b.SignWalletAddress; - nSigaturesRequired = b.nSigaturesRequired; - ResourcePointer = b.ResourcePointer; txHash = b.txHash; nHeight = b.nHeight; nExpireTime = b.nExpireTime; - PrivateData = b.PrivateData; txHash = b.txHash; return *this; } diff --git a/src/bdap/entrychannel.cpp b/src/bdap/entrychannel.cpp new file mode 100644 index 0000000000..c71ea2d009 --- /dev/null +++ b/src/bdap/entrychannel.cpp @@ -0,0 +1,85 @@ + +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/entrychannel.h" + +#include "hash.h" +#include "script/script.h" +#include "streams.h" + +void CEntryChannel::Serialize(std::vector& vchData) +{ + CDataStream dsEntryChannel(SER_NETWORK, PROTOCOL_VERSION); + dsEntryChannel << *this; + vchData = std::vector(dsEntryChannel.begin(), dsEntryChannel.end()); +} + +bool CEntryChannel::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsEntryChannel(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsEntryChannel >> *this; + + std::vector vchEntryLinkData; + Serialize(vchEntryLinkData); + const uint256 &calculatedHash = Hash(vchEntryLinkData.begin(), vchEntryLinkData.end()); + const std::vector &vchRandEntryLink = vchFromValue(calculatedHash.GetHex()); + if(vchRandEntryLink != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CEntryChannel::UnserializeFromTx(const CTransaction& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +bool CEntryChannel::ValidateValues(std::string& errorMessage) +{ + // check channel owner path + std::string strOwnerFullPath = stringFromVch(OwnerFullPath); + if (strOwnerFullPath.length() > MAX_OBJECT_FULL_PATH_LENGTH) // object + { + errorMessage = "Invalid BDAP owner full path name. Can not have more than " + std::to_string(MAX_OBJECT_FULL_PATH_LENGTH) + " characters."; + return false; + } + + // check channel description + std::string strDescription = stringFromVch(Description); + if (strDescription.length() > MAX_DESCRIPTION_LENGTH) + { + errorMessage = "Invalid channel description. Can not have more than " + std::to_string(MAX_DESCRIPTION_LENGTH) + " characters."; + return false; + } + + // check channel resource pointer + std::string strResourcePointer = stringFromVch(ResourcePointer); + if (strResourcePointer.length() > MAX_RESOURCE_POINTER_LENGTH) // object + { + errorMessage = "Invalid BDAP resource pointer. Can not have more than " + std::to_string(MAX_RESOURCE_POINTER_LENGTH) + " characters."; + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/bdap/entrychannel.h b/src/bdap/entrychannel.h new file mode 100644 index 0000000000..96d9a03255 --- /dev/null +++ b/src/bdap/entrychannel.h @@ -0,0 +1,118 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_ENTRYCHANNEL_H +#define DYNAMIC_BDAP_ENTRYCHANNEL_H + +#include "amount.h" +#include "bdap.h" +#include "bdap/domainentry.h" +#include "serialize.h" +#include "uint256.h" + +class CTransaction; + +enum ResourcePointerType { + OTHER = 0, + IPFS = 1, + LIBTORRENT = 2, + CLOUDSTORAGE = 3 +}; + +class CEntryChannel { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString OwnerFullPath; // name of the owner's full domain entry path + CharString Description; + CharString ResourcePointer; // used to point to a domain shared resource like a stream (video, audio, file sharing), P2P storage (LibTorrent or IPFS network), or private cloud storage + ResourcePointerType ResourceType; + CAmount InitialTransactionFee; + CAmount InitialRegistrationFeePerDay; + CAmount InitialSupply; + CAmount InitialBlockReward; + unsigned int nTargetSpacing; + unsigned int nHeight; + uint64_t nExpireTime; + + uint256 txHash; + + CDomainEntry* OwnerDomainEntry; + + CEntryChannel() { + SetNull(); + } + + CEntryChannel(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CEntryChannel::CURRENT_VERSION; + OwnerFullPath.clear(); + Description.clear(); + ResourcePointer.clear(); + ResourceType = ResourcePointerType::OTHER; + InitialTransactionFee = 0; + InitialRegistrationFeePerDay = 0; + InitialSupply = 0; + nTargetSpacing = 0; + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + OwnerDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(OwnerFullPath); + READWRITE(Description); + READWRITE(ResourcePointer); + //READWRITE(ResourceType); //TODO: (bdap) serialize this enum. + READWRITE(InitialTransactionFee); + READWRITE(InitialRegistrationFeePerDay); + READWRITE(InitialSupply); + READWRITE(VARINT(nTargetSpacing)); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CEntryChannel& a, const CEntryChannel& b) { + return (a.OwnerFullPath == b.OwnerFullPath && a.ResourcePointer == b.ResourcePointer && a.Description == b.Description && a.nHeight == b.nHeight); + } + + inline friend bool operator!=(const CEntryChannel& a, const CEntryChannel& b) { + return !(a == b); + } + + inline CEntryChannel operator=(const CEntryChannel& b) { + OwnerFullPath = b.OwnerFullPath; + Description = b.Description; + ResourcePointer = b.ResourcePointer; + ResourceType = b.ResourceType; + InitialTransactionFee = b.InitialTransactionFee; + InitialRegistrationFeePerDay = b.InitialRegistrationFeePerDay; + InitialSupply = b.InitialSupply; + nTargetSpacing = b.nTargetSpacing; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (OwnerFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransaction& tx); + + bool ValidateValues(std::string& errorMessage); +}; + +#endif // DYNAMIC_BDAP_ENTRYCHANNEL_H \ No newline at end of file diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 20d2db2724..6330d94740 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -35,8 +35,6 @@ UniValue addpublicname(const JSONRPCRequest& request) ToLowerCase(vchObjectID); CharString vchCommonName = vchFromValue(request.params[1]); - - CDomainEntry txDomainEntry; txDomainEntry.OID = vchDefaultOIDPrefix; txDomainEntry.DomainComponent = vchDefaultDomainName; @@ -45,7 +43,6 @@ UniValue addpublicname(const JSONRPCRequest& request) txDomainEntry.OrganizationName = vchDefaultOrganizationName; txDomainEntry.ObjectID = vchObjectID; txDomainEntry.fPublicObject = 1; //make entry public - txDomainEntry.transactionFee = 100; // Check if name already exists if (GetDomainEntry(txDomainEntry.vchFullObjectPath(), txDomainEntry)) @@ -138,9 +135,9 @@ UniValue addpublicname(const JSONRPCRequest& request) const CTransaction testTx = (CTransaction)wtx; CDomainEntry testDomainEntry(testTx); //loads the class from a transaction - LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\nPrivateData = %s\n", + LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", testDomainEntry.nVersion, testDomainEntry.GetFullObjectPath(), stringFromVch(testDomainEntry.CommonName), - stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey), stringFromVch(testDomainEntry.PrivateData)); + stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey)); } return oName; @@ -274,9 +271,9 @@ UniValue updatedirectory(const JSONRPCRequest& request) { const CTransaction testTx = (CTransaction)wtx; CDomainEntry testDomainEntry(testTx); //loads the class from a transaction - LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\nPrivateData = %s\n", + LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", testDomainEntry.nVersion, testDomainEntry.GetFullObjectPath(), stringFromVch(testDomainEntry.CommonName), - stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey), stringFromVch(testDomainEntry.PrivateData)); + stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey)); } return oName; From a00c95a211b3e678ca1c2f74b3bae6b220fe83fe Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sat, 11 Aug 2018 04:02:35 -0500 Subject: [PATCH 0165/1653] [BDAP] Check if tx exists in memory pool for new domain entries --- src/bdap/domainentry.cpp | 33 +++++++++++++++++++-------------- src/bdap/domainentry.h | 3 ++- src/script/script.h | 3 ++- src/validation.cpp | 10 +++++++++- src/wallet/wallet.cpp | 11 ++++++++++- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 1d6ab0a74e..4f6d0436d9 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -9,6 +9,7 @@ #include "policy/policy.h" #include "rpcclient.h" #include "rpcserver.h" +#include "txmempool.h" #include "validation.h" #include "validationinterface.h" #include "wallet/wallet.h" @@ -20,20 +21,6 @@ using namespace boost::xpressive; -bool IsDomainEntryTransaction(const CScript& txOut) -{ - return (txOut.IsBDAPScript(BDAP_START) - || txOut.IsBDAPScript(BDAP_NEW_TX) - || txOut.IsBDAPScript(BDAP_DELETE_TX) - || txOut.IsBDAPScript(BDAP_ACTIVATE_TX) - || txOut.IsBDAPScript(BDAP_MODIFY_TX) - || txOut.IsBDAPScript(BDAP_MODIFY_RDN_TX) - || txOut.IsBDAPScript(BDAP_EXECUTE_CODE_TX) - || txOut.IsBDAPScript(BDAP_BIND_TX) - || txOut.IsBDAPScript(BDAP_REVOKE_TX) - ); -} - std::string DomainEntryFromOp(const int op) { switch (op) { @@ -296,6 +283,24 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) return true; } +/** Checks if BDAP transaction exists in the memory pool */ +bool CDomainEntry::CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& errorMessage) +{ + for (const CTxMemPoolEntry& e : pool.mapTx) { + const CTransaction& tx = e.GetTx(); + for (const CTxOut& txOut : tx.vout) { + if (IsDomainEntryDataOutput(txOut)) { + CDomainEntry domainEntry(tx); + if (this->GetFullObjectPath() == domainEntry.GetFullObjectPath()) { + errorMessage = "CheckIfExistsInMemPool: A BDAP domain entry transaction for " + GetFullObjectPath() + " is already in the memory pool!"; + return true; + } + } + } + } + return false; +} + bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) { bool expired = false; diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index b47343eb6a..46f174d060 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -19,6 +19,7 @@ class CDynamicAddress; class CRecipient; class CTransaction; class CTxOut; +class CTxMemPool; /* Blockchain Directory Access Framework @@ -164,9 +165,9 @@ class CDomainEntry { std::vector vchFullObjectPath() const; std::vector vchObjectLocation() const; // OU . Domain Name bool ValidateValues(std::string& errorMessage); + bool CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& errorMessage); }; -bool IsDomainEntryTransaction(const CScript& txOut); std::string DomainEntryFromOp(const int op); bool IsDomainEntryDataOutput(const CTxOut& out); int GetDomainEntryDataOutput(const CTransaction& tx); diff --git a/src/script/script.h b/src/script/script.h index e40aabaf60..af839c8953 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -700,7 +700,8 @@ class CScript : public CScriptBase } return false; } - + + //TODO: (bdap) test if this is working bool IsBDAPScript(ProtocolCodes code) const { switch(code) { diff --git a/src/validation.cpp b/src/validation.cpp index f306a63949..1017df803c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -661,6 +661,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } } + if (tx.nVersion == BDAP_TX_VERSION) { + std::string strErrorMessage; + CDomainEntry domainEntry(tx); + if (domainEntry.CheckIfExistsInMemPool(pool, strErrorMessage)) { + return state.Invalid(false, REJECT_ALREADY_KNOWN, "bdap-txn-already-in-mempool " + strErrorMessage); + } + } + // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) return state.DoS(100, false, REJECT_INVALID, "coinbase"); @@ -1071,7 +1079,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C { return false; } - + // Remove conflicting transactions from the mempool BOOST_FOREACH(const CTxMemPool::txiter it, allConflicting) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 90b74622db..852c97f0e0 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -9,6 +9,7 @@ #include "base58.h" #include "primitives/block.h" +#include "bdap/domainentry.h" #include "checkpoints.h" #include "chain.h" #include "wallet/coincontrol.h" @@ -3290,7 +3291,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT // Use special version number when creating a BDAP transaction if (fIsBDAP) txNew.nVersion = BDAP_TX_VERSION; - + // Discourage fee sniping. // // For a large miner the value of the transactions in the best block and @@ -3578,6 +3579,14 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT // Embed the constructed transaction data in wtxNew. *static_cast(&wtxNew) = CTransaction(txNew); + if (fIsBDAP) { + // Check the memory pool for a pending tranaction for the same domain entry + CDomainEntry domainEntry(txNew); + if (domainEntry.CheckIfExistsInMemPool(mempool, strFailReason)) { + return false; + } + } + // Limit size if (nBytes >= MAX_STANDARD_TX_SIZE) { From 4805ab9c01a64b9ec5618d5211179a2b241f7a61 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sat, 11 Aug 2018 12:11:32 -0500 Subject: [PATCH 0166/1653] [BDAP] Update RPC command names --- src/bdap/rpcdomainentry.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 6330d94740..93c1a996aa 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -17,11 +17,11 @@ extern void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdap static constexpr bool fPrintDebug = true; -UniValue addpublicname(const JSONRPCRequest& request) +UniValue adddomainentry(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("addpublicname \nAdd public name entry to blockchain directory.\n"); + throw std::runtime_error("adddomainentry \nAdd public name entry to blockchain directory.\n"); } EnsureWalletIsUnlocked(); @@ -143,11 +143,11 @@ UniValue addpublicname(const JSONRPCRequest& request) return oName; } -UniValue getdirectories(const JSONRPCRequest& request) +UniValue getdomainentries(const JSONRPCRequest& request) { if (request.params.size() > 2) { - throw std::runtime_error("directorylist \nLists all BDAP entries.\n"); + throw std::runtime_error("getdomainentries \nLists all BDAP entries.\n"); } unsigned int nRecordsPerPage = 100; @@ -169,11 +169,11 @@ UniValue getdirectories(const JSONRPCRequest& request) return oDomainEntryList; } -UniValue getdirectoryinfo(const JSONRPCRequest& request) +UniValue getdomainentryinfo(const JSONRPCRequest& request) { if (request.params.size() != 1) { - throw std::runtime_error("getdirectoryinfo \nList BDAP entry.\n"); + throw std::runtime_error("getdomainentryinfo \nList BDAP entry.\n"); } CharString vchObjectID = vchFromValue(request.params[0]); @@ -197,10 +197,10 @@ UniValue getdirectoryinfo(const JSONRPCRequest& request) return oDomainEntryInfo; } -UniValue updatedirectory(const JSONRPCRequest& request) { +UniValue updatedomainentry(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("updatedirectory \nUpdate an existing public name blockchain directory entry.\n"); + throw std::runtime_error("updatedomainentry \nUpdate an existing public name blockchain directory entry.\n"); } EnsureWalletIsUnlocked(); @@ -283,10 +283,10 @@ static const CRPCCommand commands[] = { // category name actor (function) okSafeMode #ifdef ENABLE_WALLET /* BDAP */ - { "bdap", "addpublicname", &addpublicname, true }, - { "bdap", "getdirectories", &getdirectories, true }, - { "bdap", "getdirectoryinfo", &getdirectoryinfo, true }, - { "bdap", "updatedirectory", &updatedirectory, true }, + { "bdap", "adddomainentry", &adddomainentry, true }, + { "bdap", "getdomainentries", &getdomainentries, true }, + { "bdap", "getdomainentryinfo", &getdomainentryinfo, true }, + { "bdap", "updatedomainentry", &updatedomainentry, true }, #endif //ENABLE_WALLET }; From 42f66c29832f671e145bbd9371399f89bac98c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Sun, 12 Aug 2018 08:13:06 +0200 Subject: [PATCH 0167/1653] move implementations out of definitions --- src/miner.cpp | 396 ++++++++++++++++++++++++++------------------------ 1 file changed, 206 insertions(+), 190 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index ed87e05530..fa02c9b437 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -178,7 +178,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios - if (chainparams.MineBlocksOnDemand()) + if (chainparams.TryMineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) ? nMedianTimePast : pblock->GetBlockTime(); @@ -537,14 +537,12 @@ class BaseMiner CConnman& connman; public: - BaseMiner(const CChainParams& chainparams, CConnman& connman, double* hashesPerSec, std::string deviceName, boost::optional deviceIndex = boost::none) - : chainparams(chainparams), - connman(connman), - deviceName(deviceName), - deviceIndex(deviceIndex), - dHashesPerSec(hashesPerSec) {} + BaseMiner(const CChainParams& chainparams, CConnman& connman, double* hashesPerSec, std::string deviceName, boost::optional deviceIndex = boost::none); private: + std::string deviceName; + boost::optional deviceIndex; + int64_t nStart; unsigned int nExtraNonce = 0; unsigned int nTransactionsUpdatedLast; @@ -552,179 +550,200 @@ class BaseMiner CBlockIndex* pindexPrev; boost::shared_ptr coinbaseScript; -protected: - std::string deviceName; - boost::optional deviceIndex; - double* dHashesPerSec; +private: + bool IsBlockSynced(CBlock* pblock); + void IncrementHashesDone(unsigned int nHashesDone); + + std::unique_ptr CreateNewMinerBlock(); + +protected: + // target of the hash arith_uint256 hashTarget; - void ProcessFoundSolution(CBlock* pblock, const uint256& hash) - { - // Found a solution - SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", deviceName, hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, chainparams, &connman); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - coinbaseScript->KeepScript(); - // In regression test mode, stop mining after a block is found. - if (chainparams.MineBlocksOnDemand()) - throw boost::thread_interrupted(); - } + // it should be used by miner to process found solution + void ProcessFoundSolution(CBlock* pblock, const uint256& hash); - virtual unsigned int LoopTick(CBlock* pblock) = 0; + // this is single method required to implement miner + // returned number is amount of hashes processed + virtual unsigned int TryMineBlock(CBlock* pblock) = 0; -private: - void Init() - { - std::size_t device = deviceIndex ? *deviceIndex : 0; - LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, device); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread(tfm::format("dynamic-%s-miner-%u", deviceName, device).data()); - GetMainSignals().ScriptForMining(coinbaseScript); +public: + // starts miner loop + void StartLoop(); +}; + +BaseMiner::BaseMiner(const CChainParams& chainparams, CConnman& connman, double* hashesPerSec, std::string deviceName, boost::optional deviceIndex) + : chainparams(chainparams), + connman(connman), + deviceName(deviceName), + deviceIndex(deviceIndex), + dHashesPerSec(hashesPerSec) {} + +void BaseMiner::ProcessFoundSolution(CBlock* pblock, const uint256& hash) +{ + // Found a solution + SetThreadPriority(THREAD_PRIORITY_NORMAL); + LogPrintf("DynamicMiner%s:\n proof-of-work found \n hash: %s \ntarget: %s\n", deviceName, hash.GetHex(), hashTarget.GetHex()); + ProcessBlockFound(pblock, chainparams, &connman); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + coinbaseScript->KeepScript(); + // In regression test mode, stop mining after a block is found. + if (chainparams.TryMineBlocksOnDemand()) + throw boost::thread_interrupted(); +} + +bool BaseMiner::IsBlockSynced(CBlock* pblock) +{ + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + // Regtest mode doesn't require peers + if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && chainparams.MiningRequiresPeers()) + return false; + if (pblock->nNonce >= 0xffff0000) + return false; + if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) + return false; + if (pindexPrev != chainActive.Tip()) + return false; + // Update nTime every few seconds + if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) + return false; // Recreate the block if the clock has run backwards, + // so that we can use the correct time. + if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) { + // Changing pblock->nTime can change work required on testnet: + hashTarget.SetCompact(pblock->nBits); } + return true; +} - void ValidateCoinbase() - { - // Throw an error if no script was provided. This can happen - // due to some internal error but also if the keypool is empty. - // In the latter case, already the pointer is NULL. - if (!coinbaseScript || coinbaseScript->reserveScript.empty()) - throw std::runtime_error("No coinbase script available (mining requires a wallet)"); +void BaseMiner::IncrementHashesDone(unsigned int nHashesDone) +{ + static int64_t nHashCounter = 0; + static int64_t nLogTime = 0; + + if (nHPSTimerStart == 0) { + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + } else { + nHashCounter += nHashesDone; } - std::unique_ptr CreateNewMinerBlock() - { - // Wait for blocks if required - WaitForNetworkInit(chainparams, connman); - // Create new block - nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - pindexPrev = chainActive.Tip(); - if (!pindexPrev) { - return nullptr; + static CCriticalSection cs; + if (GetTimeMillis() - nHPSTimerStart > 4000) { + LOCK(cs); + *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + if (GetTime() - nLogTime > 30 * 60) { + nLogTime = GetTime(); + LogPrintf("%s hashmeter %6.0f khash/s\n", deviceName, *dHashesPerSec / 1000.0); } - return CreateNewBlock(chainparams, coinbaseScript->reserveScript); } +} - bool LoopChecks(CBlock* pblock) - { - // Check for stop or if block needs to be rebuilt - boost::this_thread::interruption_point(); - // Regtest mode doesn't require peers - if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && chainparams.MiningRequiresPeers()) - return false; - if (pblock->nNonce >= 0xffff0000) - return false; - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) - return false; - if (pindexPrev != chainActive.Tip()) - return false; - // Update nTime every few seconds - if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) - return false; // Recreate the block if the clock has run backwards, - // so that we can use the correct time. - if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); - } - return true; +std::unique_ptr BaseMiner::CreateNewMinerBlock() +{ + // Wait for blocks if required + WaitForNetworkInit(chainparams, connman); + // Create new block + nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + pindexPrev = chainActive.Tip(); + if (!pindexPrev) { + return nullptr; } + return CreateNewBlock(chainparams, coinbaseScript->reserveScript); +} - void CountHashes(unsigned int nHashesDone) - { - static int64_t nHashCounter = 0; - static int64_t nLogTime = 0; +void BaseMiner::StartLoop() +{ + std::size_t device = deviceIndex ? *deviceIndex : 0; + LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, device); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread(tfm::format("dynamic-%s-miner-%u", deviceName, device).data()); + GetMainSignals().ScriptForMining(coinbaseScript); - if (nHPSTimerStart == 0) { - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - } else { - nHashCounter += nHashesDone; - } + try { + // Throw an error if no script was provided. This can happen + // due to some internal error but also if the keypool is empty. + // In the latter case, already the pointer is NULL. + if (!coinbaseScript || coinbaseScript->reserveScript.empty()) + throw std::runtime_error("No coinbase script available (mining requires a wallet)"); - static CCriticalSection cs; - if (GetTimeMillis() - nHPSTimerStart > 4000) { - LOCK(cs); - *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - if (GetTime() - nLogTime > 30 * 60) { - nLogTime = GetTime(); - LogPrintf("%s hashmeter %6.0f khash/s\n", deviceName, *dHashesPerSec / 1000.0); + while (true) { + std::unique_ptr pblocktemplate = this->CreateNewMinerBlock(); + if (!pblocktemplate) { + LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", deviceName); + return; } - } - } - -public: - void StartLoop() - { - this->Init(); + CBlock* pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - try { - this->ValidateCoinbase(); + LogPrintf("DynamicMiner%s -- Running miner with %u transactions in block (%u bytes)\n", deviceName, pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + // set loop start for counter + nStart = GetTime(); + hashTarget = arith_uint256().SetCompact(pblock->nBits); + // start mining the block while (true) { - std::unique_ptr pblocktemplate = this->CreateNewMinerBlock(); - if (!pblocktemplate) { - LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", deviceName); - return; - } - CBlock* pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - LogPrintf("DynamicMiner%s -- Running miner with %u transactions in block (%u bytes)\n", deviceName, pblock->vtx.size(), - ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - - nStart = GetTime(); - hashTarget = arith_uint256().SetCompact(pblock->nBits); - - while (true) { - auto hashesDone = this->LoopTick(pblock); - this->CountHashes(hashesDone); - if (!this->LoopChecks(pblock)) - break; - } + // try mining the block + auto hashesDone = this->TryMineBlock(pblock); + // increment hash statistics + this->IncrementHashesDone(hashesDone); + // check if miner is in sync with blockchain + if (!this->IsBlockSynced(pblock)) + break; } - } catch (const boost::thread_interrupted&) { - LogPrintf("DynamicMiner%s -- terminated\n", deviceName); - throw; - } catch (const std::runtime_error& e) { - LogPrintf("DynamicMiner%s -- runtime error: %s\n", deviceName, e.what()); - return; } + } catch (const boost::thread_interrupted&) { + LogPrintf("DynamicMiner%s -- terminated\n", deviceName); + throw; + } catch (const std::runtime_error& e) { + LogPrintf("DynamicMiner%s -- runtime error: %s\n", deviceName, e.what()); + return; } -}; +} class CPUMiner : public BaseMiner { public: - CPUMiner(const CChainParams& chainparams, CConnman& connman) - : BaseMiner(chainparams, connman, &dCPUHashesPerSec, "CPU") {} + CPUMiner(const CChainParams& chainparams, CConnman& connman); protected: - virtual unsigned int - LoopTick(CBlock* pblock) override - { - unsigned int nHashesDone = 0; - while (true) { - uint256 hash = pblock->GetHash(); - if (UintToArith256(hash) <= hashTarget) { - this->ProcessFoundSolution(pblock, hash); - break; - } - pblock->nNonce += 1; - nHashesDone += 1; - if ((pblock->nNonce & 0xFF) == 0) - break; + virtual unsigned int TryMineBlock(CBlock* pblock) override; +}; + +CPUMiner::CPUMiner(const CChainParams& chainparams, CConnman& connman) + : BaseMiner(chainparams, connman, &dCPUHashesPerSec, "CPU") {} + +unsigned int CPUMiner::TryMineBlock(CBlock* pblock) +{ + unsigned int nHashesDone = 0; + while (true) { + uint256 hash = pblock->GetHash(); + if (UintToArith256(hash) <= hashTarget) { + this->ProcessFoundSolution(pblock, hash); + break; } - return nHashesDone; + pblock->nNonce += 1; + nHashesDone += 1; + if ((pblock->nNonce & 0xFF) == 0) + break; } -}; + return nHashesDone; +} #ifdef ENABLE_GPU class GPUMiner : public BaseMiner { +public: + GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex); + +protected: + virtual unsigned int TryMineBlock(CBlock* pblock) override; + private: Argon2GPUParams params; Argon2GPUDevice device; @@ -733,57 +752,54 @@ class GPUMiner : public BaseMiner Argon2GPU processingUnit; std::size_t batchSizeTarget; +}; -public: - GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) - : BaseMiner(chainparams, connman, &dGPUHashesPerSec, "GPU", deviceIndex), - params((std::size_t)OUTPUT_BYTES, 2, 500, 8), - device(global.getAllDevices()[deviceIndex]), - context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), - processingUnit(&context, ¶ms, &device, 1, false, false), - batchSizeTarget(device.getTotalMemory() / 512e3) {} +GPUMiner::GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) + : BaseMiner(chainparams, connman, &dGPUHashesPerSec, "GPU", deviceIndex), + params((std::size_t)OUTPUT_BYTES, 2, 500, 8), + device(global.getAllDevices()[deviceIndex]), + context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), + processingUnit(&context, ¶ms, &device, 1, false, false), + batchSizeTarget(device.getTotalMemory() / 512e3) {} -protected: - virtual unsigned int - LoopTick(CBlock* pblock) override - { - unsigned int nHashesDone = 0; - // current batch size - std::size_t batchSize = batchSizeTarget; - // set batch input - static unsigned char pblank[1]; - for (std::size_t i = 0; i < batchSizeTarget; i++) { - const auto pBegin = BEGIN(pblock->nVersion); - const auto pEnd = END(pblock->nNonce); - const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); - // input is copied onto memory buffer - processingUnit.setInputAndSalt(i, input, INPUT_BYTES); - // increment block nonce - pblock->nNonce += 1; - // increment hashes done - nHashesDone += 1; - // TODO(crackcomm): is this only to count hashes? - if ((pblock->nNonce & 0xFF) == 0) { - batchSize = i + 1; - break; - } +unsigned int GPUMiner::TryMineBlock(CBlock* pblock) +{ + unsigned int nHashesDone = 0; + // current batch size + std::size_t batchSize = batchSizeTarget; + // set batch input + static unsigned char pblank[1]; + for (std::size_t i = 0; i < batchSizeTarget; i++) { + const auto pBegin = BEGIN(pblock->nVersion); + const auto pEnd = END(pblock->nNonce); + const void* input = (pBegin == pEnd ? pblank : static_cast(&pBegin[0])); + // input is copied onto memory buffer + processingUnit.setInputAndSalt(i, input, INPUT_BYTES); + // increment block nonce + pblock->nNonce += 1; + // increment hashes done + nHashesDone += 1; + // TODO(crackcomm): is this only to count hashes? + if ((pblock->nNonce & 0xFF) == 0) { + batchSize = i + 1; + break; } - // start GPU processing - processingUnit.beginProcessing(); - // wait for results - processingUnit.endProcessing(); - // check batch results - uint256 hash; - for (std::size_t i = 0; i < batchSize; i++) { - processingUnit.getHash(i, (uint8_t*)&hash); - if (UintToArith256(hash) <= hashTarget) { - this->ProcessFoundSolution(pblock, hash); - break; - } + } + // start GPU processing + processingUnit.beginProcessing(); + // wait for results + processingUnit.endProcessing(); + // check batch results + uint256 hash; + for (std::size_t i = 0; i < batchSize; i++) { + processingUnit.getHash(i, (uint8_t*)&hash); + if (UintToArith256(hash) <= hashTarget) { + this->ProcessFoundSolution(pblock, hash); + break; } - return nHashesDone; } -}; + return nHashesDone; +} #endif // ENABLE_GPU } // namespace miners From 1ca3a03cd3f6c3b601228b48ac5afcdb2c716f6c Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 12 Aug 2018 15:01:51 -0500 Subject: [PATCH 0168/1653] [BDAP] Check domain entry wallet address and encrypt pub key --- src/bdap/bdap.h | 1 + src/bdap/domainentry.cpp | 35 +++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h index 091698e1d8..10996e45db 100644 --- a/src/bdap/bdap.h +++ b/src/bdap/bdap.h @@ -18,6 +18,7 @@ static constexpr unsigned int MAX_OBJECT_NAME_LENGTH = 63; static constexpr unsigned int MAX_OBJECT_FULL_PATH_LENGTH = (MAX_OBJECT_NAME_LENGTH * 3) + 2; // domain + ou + object name + 2 dot chars static constexpr unsigned int MAX_COMMON_NAME_LENGTH = 95; static constexpr unsigned int MAX_ORG_NAME_LENGTH = 95; +static constexpr unsigned int MAX_WALLET_ADDRESS_LENGTH = 102; // Stealth addresses are 102 chars in length. Regular addresses are 34 chars. static constexpr unsigned int MAX_RESOURCE_POINTER_LENGTH = 127; static constexpr unsigned int MAX_KEY_LENGTH = 156; static constexpr unsigned int MAX_DESCRIPTION_LENGTH = 256; diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 4f6d0436d9..cc6bb428e1 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -263,23 +263,46 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) } // check object common name component - std::string strCommonName = stringFromVch(CommonName); - if (strCommonName.length() > MAX_COMMON_NAME_LENGTH) + if (CommonName.size() > MAX_COMMON_NAME_LENGTH) { errorMessage = "Invalid BDAP common name. Can not have more than " + std::to_string(MAX_COMMON_NAME_LENGTH) + " characters."; return false; } // check object organization name component - std::string strOrganizationName = stringFromVch(OrganizationName); - if (strOrganizationName.length() > MAX_ORG_NAME_LENGTH) + if (OrganizationName.size() > MAX_ORG_NAME_LENGTH) { errorMessage = "Invalid BDAP organization name. Can not have more than " + std::to_string(MAX_ORG_NAME_LENGTH) + " characters."; return false; } - // TODO: (bdap) check if EncryptPublicKey is valid - // TODO: (bdap) check WalletAddress and SignWalletAddress + if (WalletAddress.size() > MAX_WALLET_ADDRESS_LENGTH) + { + errorMessage = "Invalid BDAP wallet address. Can not have more than " + std::to_string(MAX_WALLET_ADDRESS_LENGTH) + " characters."; + return false; + } + else { + std::string strWalletAddress = stringFromVch(WalletAddress); + CDynamicAddress entryAddress(strWalletAddress); + if (!entryAddress.IsValid()) { + errorMessage = "Invalid BDAP wallet address. Wallet address failed IsValid check."; + return false; + } + } + + if (EncryptPublicKey.size() > MAX_KEY_LENGTH) + { + errorMessage = "Invalid BDAP encryption public key. Can not have more than " + std::to_string(MAX_KEY_LENGTH) + " characters."; + return false; + } + else { + CPubKey entryEncryptPublicKey(EncryptPublicKey); + if (!entryEncryptPublicKey.IsFullyValid()) { + errorMessage = "Invalid BDAP encryption public key. Encryption public key failed IsFullyValid check."; + return false; + } + } + return true; } From 396d3b10225b016d7b9984776db5795911429528 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 12 Aug 2018 15:12:42 -0500 Subject: [PATCH 0169/1653] [BDAP] Remove SignWalletAddress in domain entry. Only use WalletAddress --- src/bdap/domainentry.cpp | 1 - src/bdap/domainentry.h | 4 ---- src/bdap/domainentrydb.cpp | 8 ++++---- src/bdap/rpcdomainentry.cpp | 32 ++++++++++---------------------- 4 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index cc6bb428e1..4a26e54362 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -340,7 +340,6 @@ bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) oName.push_back(Pair("object_full_path", stringFromVch(entry.vchFullObjectPath()))); oName.push_back(Pair("object_type", entry.ObjectType)); oName.push_back(Pair("wallet_address", stringFromVch(entry.WalletAddress))); - oName.push_back(Pair("signature_address", stringFromVch(entry.SignWalletAddress))); oName.push_back(Pair("public", (int)entry.fPublicObject)); oName.push_back(Pair("encryption_publickey", HexStr(entry.EncryptPublicKey))); oName.push_back(Pair("txid", entry.txHash.GetHex())); diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index 46f174d060..d646a2c808 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -71,7 +71,6 @@ class CDomainEntry { CharString WalletAddress; // used to send collateral funds for this directory record. int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. - CharString SignWalletAddress; // used to verify authorized update transaction uint256 txHash; @@ -100,7 +99,6 @@ class CDomainEntry { WalletAddress.clear(); fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); - SignWalletAddress.clear(); txHash.SetNull(); nHeight = 0; nExpireTime = 0; @@ -121,7 +119,6 @@ class CDomainEntry { READWRITE(WalletAddress); READWRITE(VARINT(fPublicObject)); READWRITE(EncryptPublicKey); - READWRITE(SignWalletAddress); READWRITE(VARINT(nHeight)); READWRITE(txHash); READWRITE(VARINT(nExpireTime)); @@ -146,7 +143,6 @@ class CDomainEntry { WalletAddress = b.WalletAddress; fPublicObject = b.fPublicObject; EncryptPublicKey = b.EncryptPublicKey; - SignWalletAddress = b.SignWalletAddress; txHash = b.txHash; nHeight = b.nHeight; nExpireTime = b.nExpireTime; diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index e4662946dd..4af410cc9d 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -377,9 +377,9 @@ bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } else { - CDynamicAddress prevSignAddress(bdapDest); + CDynamicAddress prevAddress(bdapDest); { - if (EncodeBase58(entry.SignWalletAddress) != prevSignAddress.ToString()) + if (EncodeBase58(entry.WalletAddress) != prevAddress.ToString()) errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("You are not the owner of this BDAP entry; this delete operation failed!"); return error(errorMessage.c_str()); } @@ -427,9 +427,9 @@ bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } else { - CDynamicAddress prevSignAddress(bdapDest); + CDynamicAddress prevAddress(bdapDest); { - if (EncodeBase58(entry.SignWalletAddress) != prevSignAddress.ToString()) + if (EncodeBase58(entry.WalletAddress) != prevAddress.ToString()) errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("You are not the owner of this BDAP entry; this update operation failed!"); return error(errorMessage.c_str()); } diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 93c1a996aa..be595e1f8b 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -53,14 +53,14 @@ UniValue adddomainentry(const JSONRPCRequest& request) privWalletKey.MakeNewKey(true); CPubKey pubWalletKey = privWalletKey.GetPubKey(); CKeyID keyWalletID = pubWalletKey.GetID(); - + CDynamicAddress walletAddress = CDynamicAddress(keyWalletID); + if (pwalletMain && !pwalletMain->AddKeyPubKey(privWalletKey, pubWalletKey)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Error adding receiving address key wo wallet for BDAP")); pwalletMain->SetAddressBook(keyWalletID, strObjectID, "receive"); - std::string strWalletAddress = CDynamicAddress(keyWalletID).ToString(); - CharString vchWalletAddress(strWalletAddress.begin(), strWalletAddress.end()); + CharString vchWalletAddress = vchFromString(walletAddress.ToString()); txDomainEntry.WalletAddress = vchWalletAddress; CKey privEncryptKey; @@ -74,19 +74,6 @@ UniValue adddomainentry(const JSONRPCRequest& request) txDomainEntry.EncryptPublicKey = vchEncryptPubKey; - CKey privSignKey; - privSignKey.MakeNewKey(true); - CPubKey pubSignKey = privSignKey.GetPubKey(); - CKeyID keySignID = pubSignKey.GetID(); - CDynamicAddress signWallet = CDynamicAddress(keySignID); - std::string strSignWalletAddress = signWallet.ToString(); - CharString vchSignWalletAddress(strSignWalletAddress.begin(), strSignWalletAddress.end()); - - if (pwalletMain && !pwalletMain->AddKeyPubKey(privSignKey, pubSignKey)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3504 - " + _("Error adding signature key to wallet for BDAP")); - - txDomainEntry.SignWalletAddress = vchSignWalletAddress; - uint64_t nDays = 1461; //default to 4 years. if (request.params.size() >= 3) { nDays = request.params[2].get_int(); @@ -97,16 +84,17 @@ UniValue adddomainentry(const JSONRPCRequest& request) CharString data; txDomainEntry.Serialize(data); - // Create BDAP OP_RETURN Signature Scripts + // Create BDAP operation script CScript scriptPubKey; std::vector vchFullObjectPath = txDomainEntry.vchFullObjectPath(); scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_NEW) << vchFullObjectPath << OP_2DROP << OP_DROP; CScript scriptDestination; - scriptDestination = GetScriptForDestination(signWallet.Get()); + scriptDestination = GetScriptForDestination(walletAddress.Get()); scriptPubKey += scriptDestination; LogPrintf("BDAP GetDomainEntryType = %s \n", GetDomainEntryOpTypeString(scriptPubKey)); + // Create BDAP OP_RETURN script CScript scriptData; scriptData << OP_RETURN << data; @@ -232,17 +220,17 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { CharString data; txDomainEntry.Serialize(data); - // Create BDAP OP_RETURN Signature Scripts + // Create BDAP operation script CScript scriptPubKey; std::vector vchFullObjectPath = txDomainEntry.vchFullObjectPath(); scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_MODIFY) << vchFullObjectPath << OP_2DROP << OP_DROP; - CDynamicAddress signWallet(stringFromVch(txDomainEntry.SignWalletAddress)); + CDynamicAddress walletAddress(stringFromVch(txDomainEntry.WalletAddress)); CScript scriptDestination; - scriptDestination = GetScriptForDestination(signWallet.Get()); + scriptDestination = GetScriptForDestination(walletAddress.Get()); scriptPubKey += scriptDestination; - LogPrintf("BDAP GetDomainEntryType = %s \n", GetDomainEntryOpTypeString(scriptPubKey)); + // Create BDAP OP_RETURN script CScript scriptData; scriptData << OP_RETURN << data; From 49bd525139424d72556b125c6f668860f03cfeda Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 12 Aug 2018 19:43:22 -0500 Subject: [PATCH 0170/1653] [BDAP] Check ownership in updatedomainentry RPC command --- src/bdap/rpcdomainentry.cpp | 38 ++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index be595e1f8b..175489b862 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -197,35 +197,39 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { CharString vchObjectID = vchFromValue(request.params[0]); ToLowerCase(vchObjectID); - CDomainEntry txDomainEntry; - txDomainEntry.DomainComponent = vchDefaultDomainName; - txDomainEntry.OrganizationalUnit = vchDefaultPublicOU; - txDomainEntry.ObjectID = vchObjectID; + CDomainEntry txPreviousEntry; + txPreviousEntry.DomainComponent = vchDefaultDomainName; + txPreviousEntry.OrganizationalUnit = vchDefaultPublicOU; + txPreviousEntry.ObjectID = vchObjectID; // Check if name already exists - if (!GetDomainEntry(txDomainEntry.vchFullObjectPath(), txDomainEntry)) - throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txDomainEntry.GetFullObjectPath() + _(" does not exists. Can not update.")); + if (!GetDomainEntry(txPreviousEntry.vchFullObjectPath(), txPreviousEntry)) + throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txPreviousEntry.GetFullObjectPath() + _(" does not exists. Can not update.")); + + COutPoint outpoint = COutPoint(txPreviousEntry.txHash, 1); + if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) + throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txPreviousEntry.GetFullObjectPath() + _(" entry. Can not update.")); - // TODO: Check if Signature Wallet address is owned. If not, return an error before submitting to the mem pool. + CDomainEntry txUpdatedEntry = txPreviousEntry; CharString vchCommonName = vchFromValue(request.params[1]); - txDomainEntry.CommonName = vchCommonName; + txUpdatedEntry.CommonName = vchCommonName; uint64_t nDays = 1461; //default to 4 years. if (request.params.size() >= 3) { nDays = request.params[2].get_int(); } uint64_t nSeconds = nDays * SECONDS_PER_DAY; - txDomainEntry.nExpireTime = chainActive.Tip()->GetMedianTimePast() + nSeconds; + txUpdatedEntry.nExpireTime = chainActive.Tip()->GetMedianTimePast() + nSeconds; CharString data; - txDomainEntry.Serialize(data); + txUpdatedEntry.Serialize(data); // Create BDAP operation script CScript scriptPubKey; - std::vector vchFullObjectPath = txDomainEntry.vchFullObjectPath(); + std::vector vchFullObjectPath = txUpdatedEntry.vchFullObjectPath(); scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_MODIFY) << vchFullObjectPath << OP_2DROP << OP_DROP; - CDynamicAddress walletAddress(stringFromVch(txDomainEntry.WalletAddress)); + CDynamicAddress walletAddress(stringFromVch(txUpdatedEntry.WalletAddress)); CScript scriptDestination; scriptDestination = GetScriptForDestination(walletAddress.Get()); scriptPubKey += scriptDestination; @@ -242,15 +246,15 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { // check BDAP values std::string strMessage; - if (!txDomainEntry.ValidateValues(strMessage)) - throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - " + strMessage); + if (!txUpdatedEntry.ValidateValues(strMessage)) + throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3702 - " + strMessage); SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); - txDomainEntry.txHash = wtx.GetHash(); + txUpdatedEntry.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); - if(!BuildBDAPJson(txDomainEntry, oName)) - throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3702 - " + _("Failed to read from BDAP JSON object")); + if(!BuildBDAPJson(txUpdatedEntry, oName)) + throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3703 - " + _("Failed to read from BDAP JSON object")); if (fPrintDebug) { // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class From c187baef45f8afcfadc8cf9939982fe4ec1490a4 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 13 Aug 2018 13:06:44 -0500 Subject: [PATCH 0171/1653] [BDAP] Fix domain entry so it populates block height --- src/bdap/domainentrydb.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index 4af410cc9d..7ca70a5c34 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -524,6 +524,7 @@ bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& } entry.txHash = tx.GetHash(); + entry.nHeight = nHeight; if (strOperationType == "bdap_new") return CheckNewDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); From 1d4e920040aea1d92ad0a7615f2892f3f747adea Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 14 Aug 2018 18:52:46 -0500 Subject: [PATCH 0172/1653] [BDAP] Add code to check domain entry's previous UTXO --- src/bdap/domainentry.cpp | 40 +++++++++++++++++++++++++++++++++++++ src/bdap/domainentry.h | 6 +++++- src/bdap/domainentrydb.cpp | 7 ++++--- src/bdap/rpcdomainentry.cpp | 3 ++- src/validation.cpp | 25 +++++++++++++++++++++++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 4a26e54362..847b408beb 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -4,6 +4,7 @@ #include "bdap/domainentry.h" +#include "chainparams.h" #include "coins.h" #include "fluid.h" #include "policy/policy.h" @@ -324,6 +325,18 @@ bool CDomainEntry::CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& e return false; } +/** Checks if the domain entry transaction uses the entry's UTXO */ +bool CDomainEntry::TxUsesPreviousUTXO(const CTransaction& tx) +{ + int nIn = GetDomainEntryOperationOutIndex(tx); + COutPoint entryOutpoint = COutPoint(txHash, nIn); + for (const CTxIn& txIn : tx.vin) { + if (txIn.prevout == entryOutpoint) + return true; + } + return false; +} + bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) { bool expired = false; @@ -519,4 +532,31 @@ bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp } } return false; +} + +bool IsDomainEntryOperationOutput(const CTxOut& out) +{ + if (GetDomainEntryOpType(out.scriptPubKey) > 0) + return true; + return false; +} + +int GetDomainEntryOperationOutIndex(const CTransaction& tx) +{ + for(unsigned int i = 0; i vchObjectLocation() const; // OU . Domain Name bool ValidateValues(std::string& errorMessage); bool CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& errorMessage); + bool TxUsesPreviousUTXO(const CTransaction& tx); }; std::string DomainEntryFromOp(const int op); @@ -183,5 +184,8 @@ bool FindDomainEntryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, int GetDomainEntryOpType(const CScript& script); std::string GetDomainEntryOpTypeString(const CScript& script); bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp, vchCharString& vvchOpParameters, int& op); - +bool IsDomainEntryOperationOutput(const CTxOut& out); +int GetDomainEntryOperationOutIndex(const CTransaction& tx); +int GetDomainEntryOperationOutIndex(int nHeight, const uint256& txHash); +bool GetDomainEntryTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams); #endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index 7ca70a5c34..da72520adc 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -427,10 +427,11 @@ bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } else { - CDynamicAddress prevAddress(bdapDest); + // TODO: (bdap) also allow entries with signatures from the same wallet address as the previous UTXO. + if (!prevDomainEntry.TxUsesPreviousUTXO(tx)) { - if (EncodeBase58(entry.WalletAddress) != prevAddress.ToString()) - errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("You are not the owner of this BDAP entry; this update operation failed!"); + //check if PreviousUTXO wallet address is used. + errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Update must use the previous UTXO; this update operation failed!"); return error(errorMessage.c_str()); } } diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 175489b862..1e2bbb5fb7 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -206,7 +206,8 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { if (!GetDomainEntry(txPreviousEntry.vchFullObjectPath(), txPreviousEntry)) throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txPreviousEntry.GetFullObjectPath() + _(" does not exists. Can not update.")); - COutPoint outpoint = COutPoint(txPreviousEntry.txHash, 1); + int nIn = GetDomainEntryOperationOutIndex(txPreviousEntry.nHeight, txPreviousEntry.txHash); + COutPoint outpoint = COutPoint(txPreviousEntry.txHash, nIn); if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txPreviousEntry.GetFullObjectPath() + _(" entry. Can not update.")); diff --git a/src/validation.cpp b/src/validation.cpp index 1017df803c..c077021552 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -667,6 +667,31 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C if (domainEntry.CheckIfExistsInMemPool(pool, strErrorMessage)) { return state.Invalid(false, REJECT_ALREADY_KNOWN, "bdap-txn-already-in-mempool " + strErrorMessage); } + int op; + CScript scriptOp; + vchCharString vvchOpParameters; + if (!GetDomainEntryOpScript(tx, scriptOp, vvchOpParameters, op)) + { + return state.Invalid(false, REJECT_INVALID, "bdap-txn-get-op-failed" + strErrorMessage); + } + const std::string strOperationType = GetDomainEntryOpTypeString(scriptOp); + if (strOperationType == "bdap_update" || strOperationType == "bdap_delete") { + CDomainEntry entry; + std::vector vchData; + std::vector vchHash; + int nDataOut; + + bool bData = GetDomainEntryData(tx, vchData, vchHash, nDataOut); + if(bData && !entry.UnserializeFromData(vchData, vchHash)) + { + return state.Invalid(false, REJECT_INVALID, "bdap-txn-get-data-failed" + strErrorMessage); + } + // TODO: (bdap) also allow entries with signatures from the same wallet address as the previous UTXO. + if (!entry.TxUsesPreviousUTXO(tx)) + { + return state.Invalid(false, REJECT_INVALID, "bdap-txn-incorrect-utxo-and-wallet" + strErrorMessage); + } + } } // Coinbase is only valid in a block, not as a loose transaction From 7ca56bcfb719fa50c068b44c28011454a3d7e67f Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 16 Aug 2018 19:25:08 -0500 Subject: [PATCH 0173/1653] Remove duplicate mem pool check in wallet available coins --- src/wallet/wallet.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b044ee4825..67d7ff33d4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2498,11 +2498,6 @@ void CWallet::AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed, if (nDepth == 0 && !pcoin->InMempool()) continue; - // We should not consider coins which aren't at least in our mempool - // It's possible for these to be conflicted via ancestors which we may never be able to detect - if (nDepth == 0 && !pcoin->InMempool()) - continue; - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { bool found = false; if(nCoinType == ONLY_DENOMINATED) { From d500db62e3a73863fe5ed92ac7955ccee54d784e Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 14 Aug 2018 19:21:16 -0500 Subject: [PATCH 0174/1653] [BDAP] Add link address to domain entry class --- src/bdap/domainentry.cpp | 15 +++++++++++++++ src/bdap/domainentry.h | 6 +++++- src/bdap/rpcdomainentry.cpp | 22 ++++++++++++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 847b408beb..945868b57e 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -291,6 +291,20 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) } } + if (LinkAddress.size() > MAX_WALLET_ADDRESS_LENGTH) + { + errorMessage = "Invalid BDAP link address. Can not have more than " + std::to_string(MAX_WALLET_ADDRESS_LENGTH) + " characters."; + return false; + } + else { + std::string strLinkAddress = stringFromVch(LinkAddress); + CDynamicAddress entryLinkAddress(strLinkAddress); + if (!entryLinkAddress.IsValid()) { + errorMessage = "Invalid BDAP link address. Link wallet address failed IsValid check."; + return false; + } + } + if (EncryptPublicKey.size() > MAX_KEY_LENGTH) { errorMessage = "Invalid BDAP encryption public key. Can not have more than " + std::to_string(MAX_KEY_LENGTH) + " characters."; @@ -355,6 +369,7 @@ bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) oName.push_back(Pair("wallet_address", stringFromVch(entry.WalletAddress))); oName.push_back(Pair("public", (int)entry.fPublicObject)); oName.push_back(Pair("encryption_publickey", HexStr(entry.EncryptPublicKey))); + oName.push_back(Pair("link_address", stringFromVch(entry.LinkAddress))); oName.push_back(Pair("txid", entry.txHash.GetHex())); if ((unsigned int)chainActive.Height() >= entry.nHeight-1) { CBlockIndex *pindex = chainActive[entry.nHeight-1]; diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index 2ed10ef5ca..905e1ecc82 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -71,7 +71,8 @@ class CDomainEntry { CharString WalletAddress; // used to send collateral funds for this directory record. int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. - + CharString LinkAddress; // used to send link requests. should use a stealth address. + uint256 txHash; unsigned int nHeight; @@ -99,6 +100,7 @@ class CDomainEntry { WalletAddress.clear(); fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); + LinkAddress.clear(); txHash.SetNull(); nHeight = 0; nExpireTime = 0; @@ -119,6 +121,7 @@ class CDomainEntry { READWRITE(WalletAddress); READWRITE(VARINT(fPublicObject)); READWRITE(EncryptPublicKey); + READWRITE(LinkAddress); READWRITE(VARINT(nHeight)); READWRITE(txHash); READWRITE(VARINT(nExpireTime)); @@ -143,6 +146,7 @@ class CDomainEntry { WalletAddress = b.WalletAddress; fPublicObject = b.fPublicObject; EncryptPublicKey = b.EncryptPublicKey; + LinkAddress = b.LinkAddress; txHash = b.txHash; nHeight = b.nHeight; nExpireTime = b.nExpireTime; diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 1e2bbb5fb7..25d8dd76a0 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -48,7 +48,7 @@ UniValue adddomainentry(const JSONRPCRequest& request) if (GetDomainEntry(txDomainEntry.vchFullObjectPath(), txDomainEntry)) throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3500 - " + txDomainEntry.GetFullObjectPath() + _(" entry already exists. Can not add duplicate.")); - // TODO: Add ability to pass in the wallet address and public key + // TODO: Add ability to pass in the wallet address CKey privWalletKey; privWalletKey.MakeNewKey(true); CPubKey pubWalletKey = privWalletKey.GetPubKey(); @@ -63,6 +63,7 @@ UniValue adddomainentry(const JSONRPCRequest& request) CharString vchWalletAddress = vchFromString(walletAddress.ToString()); txDomainEntry.WalletAddress = vchWalletAddress; + // TODO: Add ability to pass in the encryption public key CKey privEncryptKey; privEncryptKey.MakeNewKey(true); CPubKey pubEncryptKey = privEncryptKey.GetPubKey(); @@ -74,6 +75,20 @@ UniValue adddomainentry(const JSONRPCRequest& request) txDomainEntry.EncryptPublicKey = vchEncryptPubKey; + // TODO: Add ability to pass in the link address + CKey privLinkKey; + privLinkKey.MakeNewKey(true); + CPubKey pubLinkKey = privLinkKey.GetPubKey(); + CKeyID keyLinkID = pubLinkKey.GetID(); + CDynamicAddress linkAddress = CDynamicAddress(keyLinkID); + if (pwalletMain && !pwalletMain->AddKeyPubKey(privLinkKey, pubLinkKey)) + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3504 - " + _("Error adding receiving address key wo wallet for BDAP")); + + pwalletMain->SetAddressBook(keyLinkID, strObjectID, "link"); + + CharString vchLinkAddress = vchFromString(linkAddress.ToString()); + txDomainEntry.LinkAddress = vchLinkAddress; + uint64_t nDays = 1461; //default to 4 years. if (request.params.size() >= 3) { nDays = request.params[2].get_int(); @@ -92,7 +107,6 @@ UniValue adddomainentry(const JSONRPCRequest& request) CScript scriptDestination; scriptDestination = GetScriptForDestination(walletAddress.Get()); scriptPubKey += scriptDestination; - LogPrintf("BDAP GetDomainEntryType = %s \n", GetDomainEntryOpTypeString(scriptPubKey)); // Create BDAP OP_RETURN script CScript scriptData; @@ -107,14 +121,14 @@ UniValue adddomainentry(const JSONRPCRequest& request) // check BDAP values std::string strMessage; if (!txDomainEntry.ValidateValues(strMessage)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3501 - " + strMessage); + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3505 - " + strMessage); SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); txDomainEntry.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); if(!BuildBDAPJson(txDomainEntry, oName)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Failed to read from BDAP JSON object")); + throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3506 - " + _("Failed to read from BDAP JSON object")); if (fPrintDebug) { // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class From 3433277a1d353e2e6cbd3ea88b731beb4c721078 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 16 Aug 2018 21:17:13 -0500 Subject: [PATCH 0175/1653] [BDAP] Check previous wallet address for update and delete txs --- src/bdap/domainentry.cpp | 52 +++++++++++++++++++++++++ src/bdap/domainentry.h | 4 ++ src/bdap/domainentrydb.cpp | 28 ++++++++++++-- src/bdap/domainentrydb.h | 1 + src/validation.cpp | 23 +++++++++-- src/wallet/rpcwallet.cpp | 10 ++--- src/wallet/wallet.cpp | 79 +++++++++++++++++++++++++++++++++++++- src/wallet/wallet.h | 5 ++- 8 files changed, 187 insertions(+), 15 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 945868b57e..58ec2613ba 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -549,6 +549,27 @@ bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp return false; } +bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp) +{ + int op; + vchCharString vvchOpParameters; + return GetDomainEntryOpScript(tx, scriptDomainEntryOp, vvchOpParameters, op); +} + +bool GetDomainEntryDataScript(const CTransaction& tx, CScript& scriptDomainEntryData) +{ + for (unsigned int i = 0; i < tx.vout.size(); i++) + { + const CTxOut& out = tx.vout[i]; + if (out.scriptPubKey.IsUnspendable()) + { + scriptDomainEntryData = out.scriptPubKey; + return true; + } + } + return false; +} + bool IsDomainEntryOperationOutput(const CTxOut& out) { if (GetDomainEntryOpType(out.scriptPubKey) > 0) @@ -574,4 +595,35 @@ int GetDomainEntryOperationOutIndex(int nHeight, const uint256& txHash) return -1; } return GetDomainEntryOperationOutIndex(tx); +} + +bool GetDomainEntryFromRecipient(const std::vector& vecSend, CDomainEntry& entry, std::string& strOpType) +{ + for (const CRecipient& rec : vecSend) { + CScript bdapScript = rec.scriptPubKey; + if (bdapScript.IsUnspendable()) { + std::vector vchData; + std::vector vchHash; + if (!GetDomainEntryData(bdapScript, vchData, vchHash)) + { + return false; + } + entry.UnserializeFromData(vchData, vchHash); + } + else { + strOpType = GetDomainEntryOpTypeString(bdapScript); + } + } + if (!entry.IsNull() && strOpType.size() > 0) { + return true; + } + return false; +} + +CDynamicAddress GetScriptAddress(const CScript& pubScript) +{ + CTxDestination txDestination; + ExtractDestination(pubScript, txDestination); + CDynamicAddress entryAddress(txDestination); + return entryAddress; } \ No newline at end of file diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index 905e1ecc82..2dba24bfc0 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -188,8 +188,12 @@ bool FindDomainEntryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, int GetDomainEntryOpType(const CScript& script); std::string GetDomainEntryOpTypeString(const CScript& script); bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp, vchCharString& vvchOpParameters, int& op); +bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp); +bool GetDomainEntryDataScript(const CTransaction& tx, CScript& scriptDomainEntryData); bool IsDomainEntryOperationOutput(const CTxOut& out); int GetDomainEntryOperationOutIndex(const CTransaction& tx); int GetDomainEntryOperationOutIndex(int nHeight, const uint256& txHash); bool GetDomainEntryTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams); +bool GetDomainEntryFromRecipient(const std::vector& vecSend, CDomainEntry& entry, std::string& strOpType); +CDynamicAddress GetScriptAddress(const CScript& pubScript); #endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index da72520adc..45c937193f 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -249,6 +249,15 @@ bool CDomainEntryDB::GetDomainEntryInfo(const std::vector& vchFul return true; } +bool CDomainEntryDB::GetDomainEntryInfo(const std::vector& vchFullObjectPath, CDomainEntry& entry) +{ + if (!ReadDomainEntry(vchFullObjectPath, entry)) { + return false; + } + + return true; +} + bool CheckDomainEntryDB() { if (!pDomainEntryDB) @@ -427,11 +436,22 @@ bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } else { - // TODO: (bdap) also allow entries with signatures from the same wallet address as the previous UTXO. - if (!prevDomainEntry.TxUsesPreviousUTXO(tx)) + CTransaction prevTx; + uint256 hashBlock; + if (!GetTransaction(prevDomainEntry.txHash, prevTx, Params().GetConsensus(), hashBlock, true)) { + errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Cannot extract previous transaction from BDAP output; this update operation failed!"); + return error(errorMessage.c_str()); + } + // Get current wallet address used for BDAP tx + CDynamicAddress txAddress = GetScriptAddress(scriptOp); + // Get previous wallet address used for BDAP tx + CScript prevScriptPubKey; + GetDomainEntryOpScript(prevTx, prevScriptPubKey); + CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); + if (txAddress.ToString() != prevAddress.ToString()) { - //check if PreviousUTXO wallet address is used. - errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Update must use the previous UTXO; this update operation failed!"); + //check if previous wallet address is used for update and delete txs + errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Update must use the previous wallet address; this update operation failed!"); return error(errorMessage.c_str()); } } diff --git a/src/bdap/domainentrydb.h b/src/bdap/domainentrydb.h index ef82f1671b..b211ec033b 100644 --- a/src/bdap/domainentrydb.h +++ b/src/bdap/domainentrydb.h @@ -31,6 +31,7 @@ class CDomainEntryDB : public CDBWrapper { bool CleanupLevelDB(int& nRemoved); bool ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDomainEntryList); bool GetDomainEntryInfo(const std::vector& vchFullObjectPath, UniValue& oDomainEntryInfo); + bool GetDomainEntryInfo(const std::vector& vchFullObjectPath, CDomainEntry& entry); }; bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry); diff --git a/src/validation.cpp b/src/validation.cpp index c077021552..6f9f8435b0 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -677,6 +677,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C const std::string strOperationType = GetDomainEntryOpTypeString(scriptOp); if (strOperationType == "bdap_update" || strOperationType == "bdap_delete") { CDomainEntry entry; + CDomainEntry prevEntry; std::vector vchData; std::vector vchHash; int nDataOut; @@ -686,10 +687,26 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C { return state.Invalid(false, REJECT_INVALID, "bdap-txn-get-data-failed" + strErrorMessage); } - // TODO: (bdap) also allow entries with signatures from the same wallet address as the previous UTXO. - if (!entry.TxUsesPreviousUTXO(tx)) + + if (!pDomainEntryDB->GetDomainEntryInfo(entry.vchFullObjectPath(), prevEntry)) { + return state.Invalid(false, REJECT_INVALID, "bdap-txn-get-previous-failed" + strErrorMessage); + } + CTransaction prevTx; + uint256 hashBlock; + if (!GetTransaction(prevEntry.txHash, prevTx, Params().GetConsensus(), hashBlock, true)) { + return state.Invalid(false, REJECT_INVALID, "bdap-txn-get-previous-tx-failed" + strErrorMessage); + } + // Get current wallet address used for BDAP tx + CScript scriptPubKey; + GetDomainEntryOpScript(tx, scriptPubKey); + CDynamicAddress txAddress = GetScriptAddress(scriptPubKey); + // Get previous wallet address used for BDAP tx + CScript prevScriptPubKey; + GetDomainEntryOpScript(prevTx, prevScriptPubKey); + CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); + if (txAddress.ToString() != prevAddress.ToString()) { - return state.Invalid(false, REJECT_INVALID, "bdap-txn-incorrect-utxo-and-wallet" + strErrorMessage); + return state.Invalid(false, REJECT_INVALID, "bdap-txn-incorrect-wallet-address-used" + strErrorMessage); } } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 34707d06a9..a794d8d3ab 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -411,10 +411,10 @@ void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdapOPScrip // Check amount if (nOPValue <= 0 || nDataValue <= 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "SendBDAPTransaction invalid amount"); if (nOPValue + nDataValue > curBalance) - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "SendBDAPTransaction insufficient funds"); // Create and send the transaction CReserveKey reservekey(pwalletMain); @@ -426,14 +426,14 @@ void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdapOPScrip LogPrintf("Sending BDAP Data Script: %s\n", ScriptToAsmStr(bdapDataScript)); LogPrintf("Sending BDAP OP Script: %s\n", ScriptToAsmStr(bdapOPScript)); - CRecipient recDataScript = {bdapDataScript, nDataValue, false}; + CRecipient recDataScript = {bdapDataScript, DEFAULT_MIN_RELAY_TX_FEE, false}; vecSend.push_back(recDataScript); - CRecipient recOPScript = {bdapOPScript, nOPValue, false}; + CRecipient recOPScript = {bdapOPScript, DEFAULT_MIN_RELAY_TX_FEE, false}; vecSend.push_back(recOPScript); if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosInOut, strError, NULL, true, ALL_COINS, false, true)) { - if (nOPValue + nDataValue + nFeeRequired > pwalletMain->GetBalance()) + if (DEFAULT_MIN_RELAY_TX_FEE + DEFAULT_MIN_RELAY_TX_FEE + nFeeRequired > pwalletMain->GetBalance()) strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 852c97f0e0..9571242364 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -9,7 +9,7 @@ #include "base58.h" #include "primitives/block.h" -#include "bdap/domainentry.h" +#include "bdap/domainentrydb.h" #include "checkpoints.h" #include "chain.h" #include "wallet/coincontrol.h" @@ -2469,6 +2469,48 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const return nTotal; } +void CWallet::GetBDAPCoins(std::vector& vCoins, const CScript& prevScriptPubKey) const +{ + CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); + //LogPrintf("GetBDAPCoins prevAddress = %s\n", prevAddress.ToString()); + vCoins.clear(); + { + LOCK2(cs_main, cs_wallet); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const uint256& wtxid = it->first; + const CWalletTx* pcoin = &(*it).second; + + if (!CheckFinalTx(*pcoin)) + continue; + + if (!pcoin->IsTrusted()) + continue; + + if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) + continue; + + int nDepth = pcoin->GetDepthInMainChain(false); + + // We should not consider coins which aren't at least in our mempool + // It's possible for these to be conflicted via ancestors which we may never be able to detect + if (nDepth == 0 && !pcoin->InMempool()) + continue; + + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { + isminetype mine = IsMine(pcoin->vout[i]); + if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && (!IsLockedCoin((*it).first, i)) && (pcoin->vout[i].nValue > 0)) { + CDynamicAddress address = GetScriptAddress(pcoin->vout[i].scriptPubKey); + //LogPrintf("GetBDAPCoins address = %s\n", address.ToString()); + if (prevAddress == address) { + vCoins.push_back(COutput(pcoin, i, nDepth, true, (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO)); + } + } + } + } + } +} + void CWallet::AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, AvailableCoinsType nCoinType, bool fUseInstantSend) const { vCoins.clear(); @@ -3329,7 +3371,40 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT LOCK2(cs_main, cs_wallet); { std::vector vAvailableCoins; - AvailableCoins(vAvailableCoins, true, coinControl, false, nCoinType, fUseInstantSend); + if (fIsBDAP) { + CDomainEntry entry; + CDomainEntry prevEntry; + std::string strOpType; + if (!GetDomainEntryFromRecipient(vecSend, entry, strOpType)) { + strFailReason = _("GetDomainEntryFromRecipient failed to find BDAP scripts in the recipient array."); + return false; + } + if (strOpType == "bdap_new") { + AvailableCoins(vAvailableCoins, true, coinControl, false, nCoinType, fUseInstantSend); + } + else if (strOpType == "bdap_update" || strOpType == "bdap_delete") { + //LogPrintf("CreateTransaction for BDAP entry %s , operation type = %s\n", entry.GetFullObjectPath(), strOpType); + if (CheckDomainEntryDB()) { + + if (!pDomainEntryDB->GetDomainEntryInfo(entry.vchFullObjectPath(), prevEntry)) { + strFailReason = _("GetDomainEntryInfo failed to find previous domanin entry."); + return false; + } + } + CTransaction prevTx; + uint256 hashBlock; + if (!GetTransaction(prevEntry.txHash, prevTx, Params().GetConsensus(), hashBlock, true)) { + strFailReason = _("GetDomainEntryInfo failed to find previous domanin entry transaction."); + return false; + } + CScript prevScriptPubKey; + GetDomainEntryOpScript(prevTx, prevScriptPubKey); + GetBDAPCoins(vAvailableCoins, prevScriptPubKey); + } + } + else { + AvailableCoins(vAvailableCoins, true, coinControl, false, nCoinType, fUseInstantSend); + } nFeeRet = 0; if(nFeePay > 0) nFeeRet = nFeePay; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 128d50c124..5e38db64ab 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -685,7 +685,10 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface * populate vCoins with vector of available COutputs. */ void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend = false) const; - + /** + * populate vCoins with vector of available COutputs for a BDAP transaction. + */ + void GetBDAPCoins(std::vector& vCoins, const CScript& prevScriptPubKey) const; /** * Shuffle and select coins until nTargetValue is reached while avoiding * small change; This method is stochastic for some inputs and upon From 9d3d9525ebfca464d9083b137d176f261cee3b86 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 17 Aug 2018 02:14:29 -0500 Subject: [PATCH 0176/1653] [BDAP] Add delete domain entry RPC command - cleanup leveldb code. use tx hash instead of wallet address - remove unused input funtion parameters in domain entry db class --- src/bdap/domainentrydb.cpp | 125 +++++++++++++++++++++--------------- src/bdap/domainentrydb.h | 24 +++---- src/bdap/rpcdomainentry.cpp | 76 ++++++++++++++++++++++ 3 files changed, 161 insertions(+), 64 deletions(-) diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index 45c937193f..adc93f677f 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -18,13 +18,10 @@ bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntr return false; } - //TODO: (bdap) calculate entry.nExpireTime - /* if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) { entry.SetNull(); return false; } - */ return !entry.IsNull(); } @@ -33,8 +30,8 @@ bool CDomainEntryDB::AddDomainEntry(const CDomainEntry& entry, const int op) bool writeState = false; { LOCK(cs_bdap_entry); - writeState = Write(make_pair(std::string("domain_component"), entry.GetFullObjectPath()), entry) - && Write(make_pair(std::string("domain_wallet_address"), entry.WalletAddress), entry.GetFullObjectPath()); + writeState = Write(make_pair(std::string("dc"), entry.GetFullObjectPath()), entry) + && Write(make_pair(std::string("txid"), entry.txHash), entry.GetFullObjectPath()); } if (writeState) AddDomainEntryIndex(entry, op); @@ -55,37 +52,37 @@ void CDomainEntryDB::AddDomainEntryIndex(const CDomainEntry& entry, const int op bool CDomainEntryDB::ReadDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry) { LOCK(cs_bdap_entry); - return CDBWrapper::Read(make_pair(std::string("domain_component"), vchObjectPath), entry); + return CDBWrapper::Read(make_pair(std::string("dc"), vchObjectPath), entry); } -bool CDomainEntryDB::ReadDomainEntryAddress(const std::vector& vchAddress, std::vector& vchObjectPath) +bool CDomainEntryDB::ReadDomainEntryTxId(const uint256& txHash, std::vector& vchObjectPath) { LOCK(cs_bdap_entry); - return CDBWrapper::Read(make_pair(std::string("domain_wallet_address"), vchAddress), vchObjectPath); + return CDBWrapper::Read(make_pair(std::string("txid"), txHash), vchObjectPath); } bool CDomainEntryDB::EraseDomainEntry(const std::vector& vchObjectPath) { LOCK(cs_bdap_entry); - return CDBWrapper::Erase(make_pair(std::string("domain_component"), vchObjectPath)); + return CDBWrapper::Erase(make_pair(std::string("dc"), vchObjectPath)); } -bool CDomainEntryDB::EraseDomainEntryAddress(const std::vector& vchAddress) +bool CDomainEntryDB::EraseDomainEntryTxId(const uint256& txHash) { LOCK(cs_bdap_entry); - return CDBWrapper::Erase(make_pair(std::string("domain_wallet_address"), vchAddress)); + return CDBWrapper::Erase(make_pair(std::string("txid"), txHash)); } bool CDomainEntryDB::DomainEntryExists(const std::vector& vchObjectPath) { LOCK(cs_bdap_entry); - return CDBWrapper::Exists(make_pair(std::string("domain_component"), vchObjectPath)); + return CDBWrapper::Exists(make_pair(std::string("dc"), vchObjectPath)); } -bool CDomainEntryDB::DomainEntryExistsAddress(const std::vector& vchAddress) +bool CDomainEntryDB::DomainEntryExistsTxId(const uint256& txHash) { LOCK(cs_bdap_entry); - return CDBWrapper::Exists(make_pair(std::string("domain_wallet_address"), vchAddress)); + return CDBWrapper::Exists(make_pair(std::string("txid"), txHash)); } bool CDomainEntryDB::RemoveExpired(int& entriesRemoved) @@ -97,7 +94,7 @@ bool CDomainEntryDB::RemoveExpired(int& entriesRemoved) while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { - if (pcursor->GetKey(key) && key.first == "domain_component") { + if (pcursor->GetKey(key) && key.first == "dc") { pcursor->GetValue(entry); if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) { @@ -106,14 +103,14 @@ bool CDomainEntryDB::RemoveExpired(int& entriesRemoved) } } - else if (pcursor->GetKey(key) && key.first == "domain_wallet_address") { + else if (pcursor->GetKey(key) && key.first == "txid") { std::vector value; CDomainEntry entry; pcursor->GetValue(value); if (GetDomainEntry(value, entry) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) { entriesRemoved++; - EraseDomainEntryAddress(entry.WalletAddress); + EraseDomainEntryTxId(entry.txHash); } } @@ -153,12 +150,12 @@ bool CDomainEntryDB::UpdateDomainEntry(const std::vector& vchObje { LOCK(cs_bdap_entry); - if (!EraseDomainEntryAddress(entry.WalletAddress)) + if (!EraseDomainEntryTxId(entry.txHash)) return false; bool writeState = false; - writeState = Update(make_pair(std::string("domain_component"), entry.GetFullObjectPath()), entry) - && Write(make_pair(std::string("domain_wallet_address"), entry.WalletAddress), entry.GetFullObjectPath()); + writeState = Update(make_pair(std::string("dc"), entry.GetFullObjectPath()), entry) + && Write(make_pair(std::string("txid"), entry.txHash), entry.GetFullObjectPath()); if (writeState) AddDomainEntryIndex(entry, OP_BDAP_MODIFY); @@ -175,7 +172,7 @@ bool CDomainEntryDB::CleanupLevelDB(int& nRemoved) while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { - if (pcursor->GetKey(key) && key.first == "domain_component") + if (pcursor->GetKey(key) && key.first == "dc") { pcursor->GetValue(dirEntry); if ((unsigned int)chainActive.Tip()->GetMedianTimePast() >= dirEntry.nExpireTime) @@ -184,7 +181,7 @@ bool CDomainEntryDB::CleanupLevelDB(int& nRemoved) EraseDomainEntry(key.second); } } - else if (pcursor->GetKey(key) && key.first == "domain_wallet_address") + else if (pcursor->GetKey(key) && key.first == "txid") { std::vector value; CDomainEntry entry; @@ -192,7 +189,7 @@ bool CDomainEntryDB::CleanupLevelDB(int& nRemoved) if (GetDomainEntry(value, entry) && (unsigned int)chainActive.Tip()->GetMedianTimePast() >= entry.nExpireTime) { nRemoved++; - EraseDomainEntryAddress(entry.vchFullObjectPath()); + EraseDomainEntryTxId(entry.txHash); } } pcursor->Next(); @@ -216,7 +213,7 @@ bool CDomainEntryDB::ListDirectories(const std::vector& vchObject boost::this_thread::interruption_point(); CDomainEntry entry; try { - if (pcursor->GetKey(key) && key.first == "domain_component") { + if (pcursor->GetKey(key) && key.first == "dc") { pcursor->GetValue(entry); if (vchObjectLocation.empty() || entry.vchObjectLocation() == vchObjectLocation) { @@ -257,7 +254,29 @@ bool CDomainEntryDB::GetDomainEntryInfo(const std::vector& vchFul return true; } +/* +bool CDomainEntryDB::GetDomainEntryInfoTxId(const uint256& txHash, CDomainEntry& entry) +{ + std::vector vchFullObjectPath; + if (!ReadDomainEntryTxId(txHash, vchFullObjectPath)) { + return false; + } + if (!ReadDomainEntry(vchFullObjectPath, entry)) { + return false; + } + + return true; +} +bool CDomainEntryDB::GetDomainEntryInfoTxId(const uint256& txHash, std::vector& vchFullObjectPath) +{ + if (!ReadDomainEntryTxId(txHash, vchFullObjectPath)) { + return false; + } + + return true; +} +*/ bool CheckDomainEntryDB() { if (!pDomainEntryDB) @@ -331,7 +350,7 @@ static bool CommonDataCheck(const CDomainEntry& entry, const vchCharString& vvch } bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck) + std::string& errorMessage, bool fJustCheck) { if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) return error(errorMessage.c_str()); @@ -351,7 +370,7 @@ bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& ent errorMessage = "CheckNewDomainEntryTxInputs failed! Can not open LevelDB BDAP entry database."; return error(errorMessage.c_str()); } - + int op = OP_BDAP_NEW; if (!pDomainEntryDB->AddDomainEntry(entry, op)) { errorMessage = "CheckNewDomainEntryTxInputs failed! Error adding new entry entry request to LevelDB."; @@ -362,7 +381,7 @@ bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& ent } bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck) + std::string& errorMessage, bool fJustCheck) { //if exists, check for owner's signature if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) @@ -386,10 +405,22 @@ bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } else { - CDynamicAddress prevAddress(bdapDest); + CTransaction prevTx; + uint256 hashBlock; + if (!GetTransaction(prevDomainEntry.txHash, prevTx, Params().GetConsensus(), hashBlock, true)) { + errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("Cannot extract previous transaction from BDAP output; this delete operation failed!"); + return error(errorMessage.c_str()); + } + // Get current wallet address used for BDAP tx + CDynamicAddress txAddress = GetScriptAddress(scriptOp); + // Get previous wallet address used for BDAP tx + CScript prevScriptPubKey; + GetDomainEntryOpScript(prevTx, prevScriptPubKey); + CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); + if (txAddress.ToString() != prevAddress.ToString()) { - if (EncodeBase58(entry.WalletAddress) != prevAddress.ToString()) - errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("You are not the owner of this BDAP entry; this delete operation failed!"); + //check if previous wallet address is used for update and delete txs + errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("Delete must use the previous wallet address; this delete operation failed!"); return error(errorMessage.c_str()); } } @@ -403,16 +434,8 @@ bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& return FlushLevelDB(); } -bool CheckActivateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck) -{ - //check name in operation matches entry data in leveldb as a new request - //check if new request exists and is not expired - return false; -} - bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck) + std::string& errorMessage, bool fJustCheck) { //if exists, check for owner's signature if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) @@ -466,7 +489,7 @@ bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } bool CheckMoveDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck) + std::string& errorMessage, bool fJustCheck) { //check name in operation matches entry data in leveldb //check if exists already @@ -475,7 +498,7 @@ bool CheckMoveDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& en } bool CheckExecuteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck) + std::string& errorMessage, bool fJustCheck) { //check name in operation matches entry data in leveldb //check if exists already @@ -484,7 +507,7 @@ bool CheckExecuteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck) + std::string& errorMessage, bool fJustCheck) { //check names in operation matches entry data in leveldb //check if request or accept response @@ -494,7 +517,7 @@ bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& en } bool CheckRevokeDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck) + std::string& errorMessage, bool fJustCheck) { //check name in operation matches entry data in leveldb //check if names exists already @@ -548,21 +571,19 @@ bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& entry.nHeight = nHeight; if (strOperationType == "bdap_new") - return CheckNewDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckNewDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_delete") - return CheckDeleteDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); - else if (strOperationType == "bdap_activate") - return CheckActivateDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckDeleteDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_update") - return CheckUpdateDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckUpdateDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_move") - return CheckMoveDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckMoveDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_execute") - return CheckExecuteDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckExecuteDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_bind") - return CheckBindDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckBindDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_revoke") - return CheckRevokeDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, op, errorMessage, fJustCheck); + return CheckRevokeDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); return false; } \ No newline at end of file diff --git a/src/bdap/domainentrydb.h b/src/bdap/domainentrydb.h index b211ec033b..c083a6c0e1 100644 --- a/src/bdap/domainentrydb.h +++ b/src/bdap/domainentrydb.h @@ -19,11 +19,11 @@ class CDomainEntryDB : public CDBWrapper { bool AddDomainEntry(const CDomainEntry& entry, const int op); void AddDomainEntryIndex(const CDomainEntry& entry, const int op); bool ReadDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry); - bool ReadDomainEntryAddress(const std::vector& vchAddress, std::vector& vchObjectPath); + bool ReadDomainEntryTxId(const uint256& txHash, std::vector& vchObjectPath); bool EraseDomainEntry(const std::vector& vchObjectPath); - bool EraseDomainEntryAddress(const std::vector& vchAddress); + bool EraseDomainEntryTxId(const uint256& txHash); bool DomainEntryExists(const std::vector& vchObjectPath); - bool DomainEntryExistsAddress(const std::vector& vchAddress); + bool DomainEntryExistsTxId(const uint256& txHash); bool RemoveExpired(int& entriesRemoved); void WriteDomainEntryIndex(const CDomainEntry& entry, const int op); void WriteDomainEntryIndexHistory(const CDomainEntry& entry, const int op); @@ -32,6 +32,8 @@ class CDomainEntryDB : public CDBWrapper { bool ListDirectories(const std::vector& vchObjectLocation, const unsigned int nResultsPerPage, const unsigned int nPage, UniValue& oDomainEntryList); bool GetDomainEntryInfo(const std::vector& vchFullObjectPath, UniValue& oDomainEntryInfo); bool GetDomainEntryInfo(const std::vector& vchFullObjectPath, CDomainEntry& entry); + //bool GetDomainEntryInfoTxId(const uint256& txHash, CDomainEntry& entry); + //bool GetDomainEntryInfoTxId(const uint256& txHash, std::vector& vchFullObjectPath); }; bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry); @@ -39,21 +41,19 @@ bool CheckDomainEntryDB(); bool FlushLevelDB(); void CleanupLevelDB(int& nRemoved); bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); + std::string& errorMessage, bool fJustCheck); bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); -bool CheckActivateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); + std::string& errorMessage, bool fJustCheck); bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); + std::string& errorMessage, bool fJustCheck); bool CheckMoveDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); + std::string& errorMessage, bool fJustCheck); bool CheckExecuteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); + std::string& errorMessage, bool fJustCheck); bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); + std::string& errorMessage, bool fJustCheck); bool CheckRevokeDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, - const int op, std::string& errorMessage, bool fJustCheck); + std::string& errorMessage, bool fJustCheck); bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 25d8dd76a0..9602043232 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -286,6 +286,81 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { return oName; } +UniValue deletedomainentry(const JSONRPCRequest& request) { + if (request.params.size() != 1) + { + throw std::runtime_error("deletedomainentry \nDelete an existing public name blockchain directory entry.\n"); + } + + EnsureWalletIsUnlocked(); + + // Format object and domain names to lower case. + CharString vchObjectID = vchFromValue(request.params[0]); + ToLowerCase(vchObjectID); + + CDomainEntry txSearchEntry; + txSearchEntry.DomainComponent = vchDefaultDomainName; + txSearchEntry.OrganizationalUnit = vchDefaultPublicOU; + txSearchEntry.ObjectID = vchObjectID; + CDomainEntry txDeletedEntry = txSearchEntry; + + // Check if name already exists + if (!GetDomainEntry(txSearchEntry.vchFullObjectPath(), txSearchEntry)) + throw std::runtime_error("BDAP_DELETE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txSearchEntry.GetFullObjectPath() + _(" does not exists. Can not delete.")); + + int nIn = GetDomainEntryOperationOutIndex(txSearchEntry.nHeight, txSearchEntry.txHash); + COutPoint outpoint = COutPoint(txSearchEntry.txHash, nIn); + if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) + throw std::runtime_error("BDAP_DELETE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txSearchEntry.GetFullObjectPath() + _(" entry. Can not delete.")); + + txDeletedEntry.WalletAddress = txSearchEntry.WalletAddress; + txDeletedEntry.CommonName = txSearchEntry.CommonName; + + CharString data; + txDeletedEntry.Serialize(data); + + // Create BDAP operation script + CScript scriptPubKey; + std::vector vchFullObjectPath = txDeletedEntry.vchFullObjectPath(); + scriptPubKey << CScript::EncodeOP_N(OP_BDAP) << CScript::EncodeOP_N(OP_BDAP_DELETE) << vchFullObjectPath << OP_2DROP << OP_DROP; + + CDynamicAddress walletAddress(stringFromVch(txDeletedEntry.WalletAddress)); + CScript scriptDestination; + scriptDestination = GetScriptForDestination(walletAddress.Get()); + scriptPubKey += scriptDestination; + + // Create BDAP OP_RETURN script + CScript scriptData; + scriptData << OP_RETURN << data; + + // Send the transaction + CWalletTx wtx; + float fYears = ((float)1/365.25); + CAmount nOperationFee = GetBDAPFee(scriptPubKey) * powf(3.1, fYears); + CAmount nDataFee = GetBDAPFee(scriptData) * powf(3.1, fYears); + + SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); + txDeletedEntry.txHash = wtx.GetHash(); + + UniValue oName(UniValue::VOBJ); + if(!BuildBDAPJson(txDeletedEntry, oName)) + throw std::runtime_error("BDAP_DELETE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3703 - " + _("Failed to read from BDAP JSON object")); + + if (fPrintDebug) { + // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class + LogPrintf("DomainEntry Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); + + const CTransaction testTx = (CTransaction)wtx; + CDomainEntry testDomainEntry(testTx); //loads the class from a transaction + + LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", + testDomainEntry.nVersion, testDomainEntry.GetFullObjectPath(), stringFromVch(testDomainEntry.CommonName), + stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey)); + } + + return oName; +} + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode #ifdef ENABLE_WALLET @@ -294,6 +369,7 @@ static const CRPCCommand commands[] = { "bdap", "getdomainentries", &getdomainentries, true }, { "bdap", "getdomainentryinfo", &getdomainentryinfo, true }, { "bdap", "updatedomainentry", &updatedomainentry, true }, + { "bdap", "deletedomainentry", &deletedomainentry, true }, #endif //ENABLE_WALLET }; From ca170ecb1cb9d4986dd2cef3733a073b7f77da82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Fri, 17 Aug 2018 19:52:14 +0200 Subject: [PATCH 0177/1653] fix autoreplace --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index fa02c9b437..639008e0c3 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -178,7 +178,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios - if (chainparams.TryMineBlocksOnDemand()) + if (chainparams.MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) ? nMedianTimePast : pblock->GetBlockTime(); @@ -590,7 +590,7 @@ void BaseMiner::ProcessFoundSolution(CBlock* pblock, const uint256& hash) SetThreadPriority(THREAD_PRIORITY_LOWEST); coinbaseScript->KeepScript(); // In regression test mode, stop mining after a block is found. - if (chainparams.TryMineBlocksOnDemand()) + if (chainparams.MineBlocksOnDemand()) throw boost::thread_interrupted(); } From b504589882e714c28d09954ff296f2be096882f8 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 17 Aug 2018 13:04:03 -0500 Subject: [PATCH 0178/1653] [BDAP] Allow blank link address and encrypt pub key for delete operations --- src/bdap/domainentry.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 58ec2613ba..68c7fed458 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -297,11 +297,13 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) return false; } else { - std::string strLinkAddress = stringFromVch(LinkAddress); - CDynamicAddress entryLinkAddress(strLinkAddress); - if (!entryLinkAddress.IsValid()) { - errorMessage = "Invalid BDAP link address. Link wallet address failed IsValid check."; - return false; + if (LinkAddress.size() > 0) { + std::string strLinkAddress = stringFromVch(LinkAddress); + CDynamicAddress entryLinkAddress(strLinkAddress); + if (!entryLinkAddress.IsValid()) { + errorMessage = "Invalid BDAP link address. Link wallet address failed IsValid check."; + return false; + } } } @@ -311,10 +313,12 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) return false; } else { - CPubKey entryEncryptPublicKey(EncryptPublicKey); - if (!entryEncryptPublicKey.IsFullyValid()) { - errorMessage = "Invalid BDAP encryption public key. Encryption public key failed IsFullyValid check."; - return false; + if (EncryptPublicKey.size() > 0) { + CPubKey entryEncryptPublicKey(EncryptPublicKey); + if (!entryEncryptPublicKey.IsFullyValid()) { + errorMessage = "Invalid BDAP encryption public key. Encryption public key failed IsFullyValid check."; + return false; + } } } From 2e13c64373cbc7cb12892bf100504b35c498d0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Sat, 18 Aug 2018 08:45:07 +0200 Subject: [PATCH 0179/1653] fix processingUnit batch size and minor code tweaks --- src/miner.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 639008e0c3..c578e6ca79 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -545,12 +545,15 @@ class BaseMiner int64_t nStart; unsigned int nExtraNonce = 0; - unsigned int nTransactionsUpdatedLast; + double* dHashesPerSec; + + // set by CreateNewMinerBlock CBlockIndex* pindexPrev; - boost::shared_ptr coinbaseScript; + unsigned int nTransactionsUpdatedLast; - double* dHashesPerSec; + // set in StartLoop + boost::shared_ptr coinbaseScript; private: bool IsBlockSynced(CBlock* pblock); @@ -560,7 +563,7 @@ class BaseMiner protected: // target of the hash - arith_uint256 hashTarget; + arith_uint256 hashTarget = 0; // it should be used by miner to process found solution void ProcessFoundSolution(CBlock* pblock, const uint256& hash); @@ -759,8 +762,8 @@ GPUMiner::GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size params((std::size_t)OUTPUT_BYTES, 2, 500, 8), device(global.getAllDevices()[deviceIndex]), context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), - processingUnit(&context, ¶ms, &device, 1, false, false), - batchSizeTarget(device.getTotalMemory() / 512e3) {} + batchSizeTarget(device.getTotalMemory() / 512e3), + processingUnit(&context, ¶ms, &device, batchSizeTarget, false, false) {} unsigned int GPUMiner::TryMineBlock(CBlock* pblock) { From 357afdc67e2316348ad4728f2c94ecaa32f2e1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kurowski?= Date: Sat, 18 Aug 2018 23:32:13 +0200 Subject: [PATCH 0180/1653] fix global and order members as they appear in initializer --- src/miner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index c578e6ca79..637a7ae5ce 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -748,17 +748,17 @@ class GPUMiner : public BaseMiner virtual unsigned int TryMineBlock(CBlock* pblock) override; private: + Argon2GPUContext global; Argon2GPUParams params; Argon2GPUDevice device; - Argon2GPUContext global; Argon2GPUProgramContext context; - Argon2GPU processingUnit; - std::size_t batchSizeTarget; + Argon2GPU processingUnit; }; GPUMiner::GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) : BaseMiner(chainparams, connman, &dGPUHashesPerSec, "GPU", deviceIndex), + global(), params((std::size_t)OUTPUT_BYTES, 2, 500, 8), device(global.getAllDevices()[deviceIndex]), context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), From 68efda8c57be7330ebb8b1ebfbe9bb4532c0b5d6 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 19 Aug 2018 01:28:41 -0500 Subject: [PATCH 0181/1653] Move makekeypair to BDAP and change testnet spork pub key --- src/bdap/rpcdomainentry.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/chainparams.cpp | 6 ++++-- src/wallet/rpcwallet.cpp | 36 ------------------------------------ 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 9602043232..46883a7f36 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -361,6 +361,41 @@ UniValue deletedomainentry(const JSONRPCRequest& request) { return oName; } +UniValue makekeypair(const JSONRPCRequest& request) +{ + if (request.params.size() > 1) + throw std::runtime_error( + "makekeypair [prefix]\n" + "Make a public/private key pair.\n" + "[prefix] is optional preferred prefix for the public key.\n"); + + std::string strPrefix = ""; + if (request.params.size() > 0) + strPrefix = request.params[0].get_str(); + + CKey key; + int nCount = 0; + do + { + key.MakeNewKey(false); + nCount++; + } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size())); + + if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size())) + return NullUniValue; + + CPrivKey vchPrivKey = key.GetPrivKey(); + CKeyID keyID = key.GetPubKey().GetID(); + CKey vchSecret = CKey(); + vchSecret.SetPrivKey(vchPrivKey, false); + UniValue result(UniValue::VOBJ); + result.push_back(Pair("PrivateKey", HexStr(vchPrivKey.begin(), vchPrivKey.end()))); + result.push_back(Pair("PublicKey", HexStr(key.GetPubKey()))); + result.push_back(Pair("WalletAddress", CDynamicAddress(keyID).ToString())); + result.push_back(Pair("WalletPrivateKey", CDynamicSecret(vchSecret).ToString())); + return result; +} + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode #ifdef ENABLE_WALLET @@ -371,6 +406,7 @@ static const CRPCCommand commands[] = { "bdap", "updatedomainentry", &updatedomainentry, true }, { "bdap", "deletedomainentry", &deletedomainentry, true }, #endif //ENABLE_WALLET + { "bdap", "makekeypair", &makekeypair, true }, }; void RegisterDomainEntryRPCCommands(CRPCTable &tableRPC) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 06fb16bd34..4706a3bd9b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -273,7 +273,8 @@ class CTestNetParams : public CChainParams { pchMessageStart[1] = 0x32; pchMessageStart[2] = 0x15; pchMessageStart[3] = 0x40; - vAlertPubKey = ParseHex("04d7e3d70462588ccde4cf2e4e8f29925395ee3ae2ded5244056cc895aab4c158986c702b2ef9665bf8f34450e153a649bdff3b3c784ec707fb637e1ba5ae100f5"); + // To import alter key: importprivkey 6Jjb9DG1cr71VWiwxg97zVEyZUBhFzzGhqE7GY9DrbYYM6gVgxS + vAlertPubKey = ParseHex("043d9e8440ea8fe66b0c2639f0a0931c9d7c41132ec9ee04cdf5d9e88ada2c2df52d93a0c1983958d3aea56df9fb3d1a61ca4eb6f72c27456fc313be80cdc70032"); nDefaultPort = DEFAULT_P2P_PORT + 100; nMaxTipAge = 24 * 60 * 64; nDelayGetHeadersTime = 24 * 60 * 60; @@ -319,7 +320,8 @@ class CTestNetParams : public CChainParams { nPoolMaxTransactions = 3; nFulfilledRequestExpireTime = 5 * 60; // fulfilled requests expire in 5 minutes - strSporkPubKey = "04d7e3d70462588ccde4cf2e4e8f29925395ee3ae2ded5244056cc895aab4c158986c702b2ef9665bf8f34450e153a649bdff3b3c784ec707fb637e1ba5ae100f5"; + // To import spork key: importprivkey 6Jjb9DG1cr71VWiwxg97zVEyZUBhFzzGhqE7GY9DrbYYM6gVgxS + strSporkPubKey = "043d9e8440ea8fe66b0c2639f0a0931c9d7c41132ec9ee04cdf5d9e88ada2c2df52d93a0c1983958d3aea56df9fb3d1a61ca4eb6f72c27456fc313be80cdc70032"; checkpointData = (CCheckpointData) { boost::assign::map_list_of diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a794d8d3ab..907c6e9386 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2739,42 +2739,6 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) return result; } - -UniValue makekeypair(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw std::runtime_error( - "makekeypair [prefix]\n" - "Make a public/private key pair.\n" - "[prefix] is optional preferred prefix for the public key.\n"); - - std::string strPrefix = ""; - if (params.size() > 0) - strPrefix = params[0].get_str(); - - CKey key; - int nCount = 0; - do - { - key.MakeNewKey(false); - nCount++; - } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size())); - - if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size())) - return NullUniValue; - - CPrivKey vchPrivKey = key.GetPrivKey(); - CKeyID keyID = key.GetPubKey().GetID(); - CKey vchSecret = CKey(); - vchSecret.SetPrivKey(vchPrivKey, false); - UniValue result(UniValue::VOBJ); - result.push_back(Pair("PrivateKey", HexStr(vchPrivKey.begin(), vchPrivKey.end()))); - result.push_back(Pair("PublicKey", HexStr(key.GetPubKey()))); - result.push_back(Pair("WalletAddress", CDynamicAddress(keyID).ToString())); - result.push_back(Pair("WalletPrivateKey", CDynamicSecret(vchSecret).ToString())); - return result; -} - UniValue convertrawprivkey(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) From 64f9dcccbda7c9a5da0480247d0b001e742a2f66 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 20 Aug 2018 00:36:39 +0200 Subject: [PATCH 0182/1653] Split CPU/GPU UI thread allocation --- src/miner.cpp | 2 +- src/qt/guiutil.cpp | 10 +++++++++- src/qt/guiutil.h | 3 ++- src/qt/miningpage.cpp | 19 ++++++++++--------- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 637a7ae5ce..1310e9f39a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -762,7 +762,7 @@ GPUMiner::GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size params((std::size_t)OUTPUT_BYTES, 2, 500, 8), device(global.getAllDevices()[deviceIndex]), context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), - batchSizeTarget(device.getTotalMemory() / 512e3), + batchSizeTarget(device.getTotalMemory() / 128e3), processingUnit(&context, ¶ms, &device, batchSizeTarget, false, false) {} unsigned int GPUMiner::TryMineBlock(CBlock* pblock) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 0ddd360f6e..4d8da85223 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1088,7 +1088,7 @@ void ClickableProgressBar::mouseReleaseEvent(QMouseEvent *event) Q_EMIT clicked(event->pos()); } -int MaxThreads() { +int CPUMaxThreads() { int nThreads = boost::thread::hardware_concurrency(); int nUseThreads = GetArg("-genproclimit", -1); @@ -1098,6 +1098,14 @@ int MaxThreads() { return nUseThreads; } +int GPUMaxThreads() { + int nUseThreads = 1; + if (nUseThreads < 1) { + nUseThreads = 1; + } + return nUseThreads; +} + QString FormatHashRate(qint64 n) { if (n == 0) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 238e66f37c..f7929e03c1 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -264,7 +264,8 @@ namespace GUIUtil #endif // utility functions for mining UI - int MaxThreads(); + int CPUMaxThreads(); + int GPUMaxThreads(); QString FormatHashRate(qint64 n); int64_t GetNetworkHashPS(int lookup, int height); QString FormatTimeInterval(arith_uint256 time); diff --git a/src/qt/miningpage.cpp b/src/qt/miningpage.cpp index d0fd40d6a2..6a7dd4a8a5 100644 --- a/src/qt/miningpage.cpp +++ b/src/qt/miningpage.cpp @@ -20,7 +20,8 @@ MiningPage::MiningPage(const PlatformStyle *platformStyle, QWidget *parent) : { ui->setupUi(this); - int nMaxUseThreads = GUIUtil::MaxThreads(); + int nCPUMaxUseThreads = GUIUtil::CPUMaxThreads(); + int nGPUMaxUseThreads = GUIUtil::GPUMaxThreads(); std::string PrivAddress = GetArg("-miningprivkey", ""); if (!PrivAddress.empty()) @@ -36,15 +37,15 @@ MiningPage::MiningPage(const PlatformStyle *platformStyle, QWidget *parent) : } } - ui->sliderCPUCores->setMinimum(0); - ui->sliderCPUCores->setMaximum(nMaxUseThreads); - ui->sliderCPUCores->setValue(nMaxUseThreads); - ui->labelNCPUCores->setText(QString("%1").arg(nMaxUseThreads)); + ui->sliderCPUCores->setMinimum(1); + ui->sliderCPUCores->setMaximum(nCPUMaxUseThreads); + ui->sliderCPUCores->setValue(nCPUMaxUseThreads); + ui->labelNCPUCores->setText(QString("%1").arg(nCPUMaxUseThreads)); - ui->sliderGPUCores->setMinimum(0); - ui->sliderGPUCores->setMaximum(nMaxUseThreads); - ui->sliderGPUCores->setValue(nMaxUseThreads); - ui->labelNGPUCores->setText(QString("%1").arg(nMaxUseThreads)); + ui->sliderGPUCores->setMinimum(1); + ui->sliderGPUCores->setMaximum(nGPUMaxUseThreads); + ui->sliderGPUCores->setValue(nGPUMaxUseThreads); + ui->labelNGPUCores->setText(QString("%1").arg(nGPUMaxUseThreads)); ui->sliderCPUGraphSampleTime->setMaximum(0); ui->sliderCPUGraphSampleTime->setMaximum(6); From 4a90d8fb8f5cba2c4706efc697f16f3e76431ec7 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 20 Aug 2018 01:02:58 +0200 Subject: [PATCH 0183/1653] Hide slider until sync completes/change batch size --- src/miner.cpp | 2 +- src/qt/miningpage.cpp | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 1310e9f39a..94ed4c6615 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -762,7 +762,7 @@ GPUMiner::GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size params((std::size_t)OUTPUT_BYTES, 2, 500, 8), device(global.getAllDevices()[deviceIndex]), context(&global, {device}, argon2gpu::ARGON2_D, argon2gpu::ARGON2_VERSION_10), - batchSizeTarget(device.getTotalMemory() / 128e3), + batchSizeTarget(device.getTotalMemory() / 8192e3), processingUnit(&context, ¶ms, &device, batchSizeTarget, false, false) {} unsigned int GPUMiner::TryMineBlock(CBlock* pblock) diff --git a/src/qt/miningpage.cpp b/src/qt/miningpage.cpp index 6a7dd4a8a5..d86de5f54f 100644 --- a/src/qt/miningpage.cpp +++ b/src/qt/miningpage.cpp @@ -37,15 +37,31 @@ MiningPage::MiningPage(const PlatformStyle *platformStyle, QWidget *parent) : } } + if (!dynodeSync.IsSynced() || !dynodeSync.IsBlockchainSynced()) { + ui->sliderCPUCores->setVisible(false); + ui->labelNCPUCores->setText(QString("Slider will show once Dynamic has finished syncing").arg(nCPUMaxUseThreads)); + } + else { + ui->sliderCPUCores->setVisible(true); + ui->labelNCPUCores->setText(QString("%1").arg(nCPUMaxUseThreads)); + } + ui->sliderCPUCores->setMinimum(1); ui->sliderCPUCores->setMaximum(nCPUMaxUseThreads); ui->sliderCPUCores->setValue(nCPUMaxUseThreads); - ui->labelNCPUCores->setText(QString("%1").arg(nCPUMaxUseThreads)); + + if (!dynodeSync.IsSynced() || !dynodeSync.IsBlockchainSynced()) { + ui->sliderGPUCores->setVisible(false); + ui->labelNGPUCores->setText(QString("Slider will show once Dynamic has finished syncing").arg(nGPUMaxUseThreads)); + } + else { + ui->sliderGPUCores->setVisible(true); + ui->labelNGPUCores->setText(QString("%1").arg(nGPUMaxUseThreads)); + } ui->sliderGPUCores->setMinimum(1); ui->sliderGPUCores->setMaximum(nGPUMaxUseThreads); ui->sliderGPUCores->setValue(nGPUMaxUseThreads); - ui->labelNGPUCores->setText(QString("%1").arg(nGPUMaxUseThreads)); ui->sliderCPUGraphSampleTime->setMaximum(0); ui->sliderCPUGraphSampleTime->setMaximum(6); From c917b91f1a8081fc049b265fbf1a001b23a56e03 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Tue, 21 Aug 2018 15:48:49 -0500 Subject: [PATCH 0184/1653] Fixes to miner UI controls --- src/qt/hashrategraphwidget.cpp | 8 +-- src/qt/hashrategraphwidget.h | 7 +-- src/qt/miningpage.cpp | 110 ++++++++++++++++++++++++--------- src/qt/miningpage.h | 5 +- 4 files changed, 90 insertions(+), 40 deletions(-) diff --git a/src/qt/hashrategraphwidget.cpp b/src/qt/hashrategraphwidget.cpp index e0a214f3fe..8cca1fee14 100644 --- a/src/qt/hashrategraphwidget.cpp +++ b/src/qt/hashrategraphwidget.cpp @@ -23,7 +23,7 @@ HashRateGraphWidget::HashRateGraphWidget(QWidget *parent) : QWidget(parent), - graphType(GraphType::MINER_HASHRATE), + graphType(GraphType::MINER_CPU_HASHRATE), iDesiredSamples(DEFAULT_DESIRED_SAMPLES), iMaxHashRate(0), vSampleHashRate(), @@ -80,7 +80,7 @@ void HashRateGraphWidget::drawHashRate(QPainter& painter) path.lineTo(x, y); } path.lineTo(x, YMARGIN + h); - if (graphType == MINER_HASHRATE) { + if (graphType == MINER_CPU_HASHRATE || graphType == MINER_GPU_HASHRATE) { painter.fillPath(path, QColor(0, 255, 0, 128)); //green painter.setPen(Qt::red); } @@ -116,10 +116,10 @@ void HashRateGraphWidget::truncateSampleQueue() void HashRateGraphWidget::updateHashRateGraph() { int64_t iCurrentHashRate = 0; - if (graphType == MINER_HASHRATE) { + if (graphType == GraphType::MINER_CPU_HASHRATE || graphType == GraphType::MINER_GPU_HASHRATE) { iCurrentHashRate = getHashRate(); } - else if (graphType == NETWORK_HASHRATE) { + else if (graphType == GraphType::NETWORK_HASHRATE) { iCurrentHashRate = GUIUtil::GetNetworkHashPS(120, -1); } diff --git a/src/qt/hashrategraphwidget.h b/src/qt/hashrategraphwidget.h index 3af7847d0f..8208db7044 100644 --- a/src/qt/hashrategraphwidget.h +++ b/src/qt/hashrategraphwidget.h @@ -23,10 +23,9 @@ class HashRateGraphWidget : public QWidget enum GraphType { - MINER_HASHRATE = 0, - NETWORK_HASHRATE, - MINER_CPU_HASHRATE, - MINER_GPU_HASHRATE + MINER_CPU_HASHRATE = 0, + MINER_GPU_HASHRATE, + NETWORK_HASHRATE }; enum SampleTime diff --git a/src/qt/miningpage.cpp b/src/qt/miningpage.cpp index d86de5f54f..3f2928a78a 100644 --- a/src/qt/miningpage.cpp +++ b/src/qt/miningpage.cpp @@ -22,7 +22,7 @@ MiningPage::MiningPage(const PlatformStyle *platformStyle, QWidget *parent) : int nCPUMaxUseThreads = GUIUtil::CPUMaxThreads(); int nGPUMaxUseThreads = GUIUtil::GPUMaxThreads(); - + std::string PrivAddress = GetArg("-miningprivkey", ""); if (!PrivAddress.empty()) { @@ -39,7 +39,7 @@ MiningPage::MiningPage(const PlatformStyle *platformStyle, QWidget *parent) : if (!dynodeSync.IsSynced() || !dynodeSync.IsBlockchainSynced()) { ui->sliderCPUCores->setVisible(false); - ui->labelNCPUCores->setText(QString("Slider will show once Dynamic has finished syncing").arg(nCPUMaxUseThreads)); + ui->labelNCPUCores->setText(QString("Slider will show once Dynamic has finished syncing")); } else { ui->sliderCPUCores->setVisible(true); @@ -52,7 +52,7 @@ MiningPage::MiningPage(const PlatformStyle *platformStyle, QWidget *parent) : if (!dynodeSync.IsSynced() || !dynodeSync.IsBlockchainSynced()) { ui->sliderGPUCores->setVisible(false); - ui->labelNGPUCores->setText(QString("Slider will show once Dynamic has finished syncing").arg(nGPUMaxUseThreads)); + ui->labelNGPUCores->setText(QString("Slider will show once Dynamic has finished syncing")); } else { ui->sliderGPUCores->setVisible(true); @@ -97,6 +97,8 @@ MiningPage::MiningPage(const PlatformStyle *platformStyle, QWidget *parent) : showHashMeterControls(false, false); showHashMeterControls(false, true); + fCPUMinerOn = false; + fGPUMinerOn = false; updateUI(); startTimer(3511); } @@ -113,6 +115,18 @@ void MiningPage::setModel(WalletModel *model) void MiningPage::updateUI() { + if (dynodeSync.IsSynced() && dynodeSync.IsBlockchainSynced()) { + if (ui->sliderGPUCores->isHidden()) { + int nThreads = ui->sliderGPUCores->value(); + ui->sliderGPUCores->setVisible(true); + ui->labelNGPUCores->setText(QString("%1").arg(nThreads)); + } + if (ui->sliderCPUCores->isHidden()) { + int nThreads = ui->sliderCPUCores->value(); + ui->sliderCPUCores->setVisible(true); + ui->labelNCPUCores->setText(QString("%1").arg(nThreads)); + } + } qint64 networkHashrate = GUIUtil::GetNetworkHashPS(120, -1); qint64 hashrate = GetHashRate(); @@ -145,21 +159,40 @@ void MiningPage::updatePushSwitch(bool fGPU) pushSwitch->setToolTip(tr("Blockchain/Dynodes are not synced, please wait until fully synced before mining!")); pushSwitch->setText(tr("Disabled")); pushSwitch->setEnabled(false); - } else if (dynodeSync.IsSynced() && dynodeSync.IsBlockchainSynced() && GetHashRate() == 0) { + return; + } + + if (fGPU && fGPUMinerOn) { + pushSwitch->setToolTip(tr("Click 'Stop mining' to stop mining!")); + pushSwitch->setText(tr("Stop mining")); + } + else if (fGPU && !fGPUMinerOn) { pushSwitch->setToolTip(tr("Click 'Start mining' to begin mining!")); pushSwitch->setText(tr("Start mining")); - pushSwitch->setEnabled(true); - } else { - pushSwitch->setToolTip(tr("Click 'Stop mining' to finish mining!")); + } + else if (!fGPU && fCPUMinerOn) { + pushSwitch->setToolTip(tr("Click 'Stop mining' to stop mining!")); pushSwitch->setText(tr("Stop mining")); - pushSwitch->setEnabled(true); } + else if (!fGPU && !fCPUMinerOn) { + pushSwitch->setToolTip(tr("Click 'Start mining' to begin mining!")); + pushSwitch->setText(tr("Start mining")); + } + pushSwitch->setEnabled(true); } -void MiningPage::StartMiner() +void MiningPage::StartMiner(bool fGPU) { - int nCPUThreads = (int)ui->sliderCPUCores->value(); - int nGPUThreads = (int)ui->sliderGPUCores->value(); + int nGPUThreads = 0; + int nCPUThreads = 0; + if (fGPU) { + fGPUMinerOn = true; + nGPUThreads = (int)ui->sliderGPUCores->value(); + } + else { + fCPUMinerOn = true; + nCPUThreads = (int)ui->sliderCPUCores->value(); + } GenerateDynamics(nCPUThreads, nGPUThreads, Params(), *g_connman); updateUI(); } @@ -167,8 +200,10 @@ void MiningPage::StartMiner() void MiningPage::StopMiner(bool fGPU) { if (fGPU) { + fGPUMinerOn = false; ShutdownGPUMiners(); } else { + fCPUMinerOn = false; ShutdownCPUMiners(); } updateUI(); @@ -177,20 +212,20 @@ void MiningPage::StopMiner(bool fGPU) void MiningPage::changeNumberOfCPUThreads(int i) { ui->labelNCPUCores->setText(QString("%1").arg(i)); - if (i == 0) { - StopMiner(false); - } else if (i > 0 && GetCPUHashRate() <= 0) { - StartMiner(); + if (fCPUMinerOn) { + if (i > 0) { + StartMiner(false); + } } } void MiningPage::changeNumberOfGPUThreads(int i) { ui->labelNGPUCores->setText(QString("%1").arg(i)); - if (i == 0) { - StopMiner(true); - } else if (i > 0 && GetGPUHashRate() <= 0) { - StartMiner(); + if (fGPUMinerOn) { + if (i > 0) { + StartMiner(true); + } } } @@ -208,19 +243,34 @@ void MiningPage::switchMining(bool fGPU) { QPushButton* pushSwitch = fGPU ? ui->pushSwitchGPUMining : ui->pushSwitchCPUMining; QSlider* coreSlider = fGPU ? ui->sliderGPUCores : ui->sliderCPUCores; + QLabel* labelCores = fGPU ? ui->labelNGPUCores : ui->labelNCPUCores; int nThreads = (int)(fGPU ? ui->sliderGPUCores->value() : ui->sliderCPUCores->value()); - int64_t hashRate = fGPU ? GetGPUHashRate() : GetCPUHashRate(); - if (hashRate > 0) { + if (fGPU && !fGPUMinerOn) { + if (nThreads == 0) + coreSlider->setValue(1); + coreSlider->setVisible(true); + labelCores->setText(QString("%1").arg(nThreads)); + pushSwitch->setText(tr("Starting")); + StartMiner(fGPU); + } + else if (fGPU && fGPUMinerOn) { pushSwitch->setText(tr("Stopping")); + coreSlider->setVisible(false); StopMiner(fGPU); - } else if (nThreads == 0 && hashRate == 0) { - coreSlider->setValue(1); - pushSwitch->setText(tr("Starting")); - StartMiner(); - } else { + } + else if (!fGPU && !fCPUMinerOn) { + if (nThreads == 0) + coreSlider->setValue(1); + coreSlider->setVisible(true); + labelCores->setText(QString("%1").arg(nThreads)); pushSwitch->setText(tr("Starting")); - StartMiner(); + StartMiner(fGPU); + } + else if (!fGPU && fCPUMinerOn) { + pushSwitch->setText(tr("Stopping")); + coreSlider->setVisible(false); + StopMiner(fGPU); } } @@ -241,12 +291,12 @@ void MiningPage::showGPUHashRate(int i) void MiningPage::showHashRate(int i, bool fGPU) { - HashRateGraphWidget* widget = fGPU ? ui->minerGPUHashRateWidget : ui->minerCPUHashRateWidget; + HashRateGraphWidget* minerHashRateWidget = fGPU ? ui->minerGPUHashRateWidget : ui->minerCPUHashRateWidget; if (i == 0) { - widget->StopHashMeter(); + minerHashRateWidget->StopHashMeter(); showHashMeterControls(false, fGPU); } else { - widget->StartHashMeter(); + minerHashRateWidget->StartHashMeter(); showHashMeterControls(true, fGPU); } } diff --git a/src/qt/miningpage.h b/src/qt/miningpage.h index 46d422fd44..273d916734 100644 --- a/src/qt/miningpage.h +++ b/src/qt/miningpage.h @@ -34,10 +34,11 @@ class MiningPage : public QWidget WalletModel *model; std::unique_ptr unlockContext; bool hasMiningprivkey; - + bool fGPUMinerOn; + bool fCPUMinerOn; void timerEvent(QTimerEvent *event); void updateUI(); - void StartMiner(); + void StartMiner(bool fGPU); void StopMiner(bool fGPU); void showHashMeterControls(bool show, bool fGPU); void updatePushSwitch(bool fGPU); From f586c79e7a06a431232f6e70ab0d24d2df141e21 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Wed, 22 Aug 2018 03:31:21 -0500 Subject: [PATCH 0185/1653] Fix Qt mining page layout so it expands --- src/qt/forms/miningpage.ui | 1252 +++++++++++++++++------------------- 1 file changed, 602 insertions(+), 650 deletions(-) diff --git a/src/qt/forms/miningpage.ui b/src/qt/forms/miningpage.ui index 0e6c5a51aa..295ceefc32 100644 --- a/src/qt/forms/miningpage.ui +++ b/src/qt/forms/miningpage.ui @@ -6,8 +6,8 @@ 0 0 - 655 - 377 + 682 + 474 @@ -19,68 +19,69 @@ color: rgb(255, 255, 255); - - - #bgWidget { background: rgba(0,0,0,220); } - - - 0 - - - - true - - - - 0 - 0 - - - - background-color: rgb(0, 0, 0); -color: rgb(255, 255, 255); - - - CPU - - - - - 0 - 0 - 631 - 102 - + + + + + #bgWidget { background: rgba(0,0,0,220); } - - - - - - - - - background-color: rgb(0, 0, 0); + + 0 + + + + true + + + + 0 + 0 + + + + + 0 + 0 + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + CPU + + + + + + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - 4 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 250 - 0 - - - - QSlider::groove:horizontal { + + + 4 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 250 + 0 + + + + QSlider::groove:horizontal { border: 1px solid #bbb; background: white; height: 10px; @@ -136,122 +137,114 @@ background: #eee; border: 1px solid #aaa; border-radius: 4px; } - - - Qt::Horizontal - - - - - - - - - background-color: rgb(0, 0, 0); + + + Qt::Horizontal + + + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Average spacing between your blocks: - - - - - - - background-color: rgb(0, 0, 0); + + + Average spacing between your blocks: + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Your hashrate (built-in miner): - - - - - - - background-color: rgb(0, 0, 0); + + + Your hashrate (built-in miner): + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Network hashrate: - - - - - - - background-color: rgb(0, 0, 0); + + + Network hashrate: + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Number of threads to use: - - - - - - - background-color: rgb(0, 0, 0); + + + Number of threads to use: + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - 0 - - - - - - - background-color: rgb(0, 0, 0); + + + 0 + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - ? - - - - - - - background-color: rgb(0, 0, 0); + + + ? + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 100 - 631 - 64 - - - - - - - QPushButton { /* Global Button Style */ + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + QPushButton { /* Global Button Style */ background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); border:0; border-radius:3px; @@ -277,110 +270,94 @@ QPushButton:pressed { background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); border:1px solid #520072; } - - - Start mining - - - - - - - Qt::Vertical - - - - 20 - 100 - - - - - - - - background-color: rgb(0, 0, 0); + + + Start mining + + + + + + + Qt::Vertical + + + + 20 + 100 + + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Show Hash Meter Graph - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 174 - 631 - 154 - - - - - - - - 0 - 0 - - - - background-color: rgb(0, 0, 0); + + + Show Hash Meter Graph + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - - - - - Qt::Vertical - - - - 10 - 200 - - - - - - - - - - 0 - 338 - 631 - 34 - - - - - - - - 250 - 0 - - - - QSlider::groove:horizontal { + + + + + + + Qt::Vertical + + + + 10 + 200 + + + + + + + + + + + + + 250 + 0 + + + + QSlider::groove:horizontal { border: 1px solid #bbb; background: white; height: 10px; @@ -436,102 +413,98 @@ color: rgb(255, 255, 255); border: 1px solid #aaa; border-radius: 4px; } - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 10 - 20 - - - - - - - - - - - 75 - true - - - - 5 m - - - - - - - Clear - - - - - - layoutWidget - layoutWidget - layoutWidget - layoutWidget - - - - background-color: rgb(0, 0, 0); + + + Qt::Horizontal + + + + + + + + + Qt::Vertical + + + + 10 + 20 + + + + + + + + + + + 75 + true + + + + 5 m + + + + + + + Clear + + + + + + + + + + + 0 + 0 + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - GPU - - - - - 0 - 0 - 631 - 102 - - - - - - - - - - - background-color: rgb(0, 0, 0); + + + GPU + + + + + + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - 4 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 250 - 0 - - - - QSlider::groove:horizontal { + + + 4 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 250 + 0 + + + + QSlider::groove:horizontal { border: 1px solid #bbb; background: white; height: 10px; @@ -587,167 +560,227 @@ background: #eee; border: 1px solid #aaa; border-radius: 4px; } - - - Qt::Horizontal - - - - - - - - - background-color: rgb(0, 0, 0); + + + Qt::Horizontal + + + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Average spacing between your blocks: - - - - - - - background-color: rgb(0, 0, 0); + + + Average spacing between your blocks: + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Your hashrate (built-in miner): - - - - - - - background-color: rgb(0, 0, 0); + + + Your hashrate (built-in miner): + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Network hashrate: - - - - - - - background-color: rgb(0, 0, 0); + + + Network hashrate: + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - Number of threads to use: - - - - - - - background-color: rgb(0, 0, 0); + + + Number of threads to use: + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - 0 - - - - - - - background-color: rgb(0, 0, 0); + + + 0 + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - ? - - - - - - - background-color: rgb(0, 0, 0); + + + ? + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - 174 - 631 - 154 - - - - - - - - 0 - 0 - - - - background-color: rgb(0, 0, 0); + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + QPushButton { /* Global Button Style */ +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); +border:0; +border-radius:3px; +color:#ffffff; +font-size:12px; +font-weight:bold; +padding-left:25px; +padding-right:25px; +padding-top:5px; +padding-bottom:5px; +} + +QPushButton:hover { +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #BA77D4, stop: .1 #9F2DCC, stop: .95 #9F2DCC, stop: 1 #7400A1); +} + +QPushButton:focus { +border:none; +outline:none; +} + +QPushButton:pressed { +background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); +border:1px solid #520072; +} + + + Start mining + + + + + + + Qt::Vertical + + + + 20 + 100 + + + + + + + + background-color: rgb(0, 0, 0); color: rgb(255, 255, 255); - - - - - - - Qt::Vertical - - - - 10 - 200 - - - - - - - - - - 0 - 338 - 631 - 34 - - - - - - - - 250 - 0 - - - - QSlider::groove:horizontal { + + + Show Hash Meter Graph + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + background-color: rgb(0, 0, 0); +color: rgb(255, 255, 255); + + + + + + + Qt::Vertical + + + + 10 + 200 + + + + + + + + + + + + + 250 + 0 + + + + QSlider::groove:horizontal { border: 1px solid #bbb; background: white; height: 10px; @@ -803,137 +836,56 @@ color: rgb(255, 255, 255); border: 1px solid #aaa; border-radius: 4px; } - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 10 - 20 - - - - - - - - - - - 75 - true - - - - 5 m - - - - - - - Clear - - - - - - - - - 0 - 100 - 631 - 64 - - - - - - - QPushButton { /* Global Button Style */ -background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); -border:0; -border-radius:3px; -color:#ffffff; -font-size:12px; -font-weight:bold; -padding-left:25px; -padding-right:25px; -padding-top:5px; -padding-bottom:5px; -} - -QPushButton:hover { -background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #BA77D4, stop: .1 #9F2DCC, stop: .95 #9F2DCC, stop: 1 #7400A1); -} - -QPushButton:focus { -border:none; -outline:none; -} - -QPushButton:pressed { -background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #8F5BA3, stop: .1 #771F99, stop: .95 #771F99, stop: 1 #520072); -border:1px solid #520072; -} - - - Start mining - - - - - - - Qt::Vertical - - - - 20 - 100 - - - - - - - - background-color: rgb(0, 0, 0); -color: rgb(255, 255, 255); - - - Show Hash Meter Graph - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + Qt::Horizontal + + + + + + + + + Qt::Vertical + + + + 10 + 20 + + + + + + + + + + + 75 + true + + + + 5 m + + + + + + + Clear + + + + + + + - - + + From ff17898c1d69a8984bedc6a8d69afa0d79c9bcf6 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 23 Aug 2018 15:29:22 -0500 Subject: [PATCH 0186/1653] [BDAP] Add identity and identity verification classes --- src/Makefile.am | 2 + src/bdap/identity.cpp | 100 +++++++++++++++++++++++++++++ src/bdap/identity.h | 146 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 src/bdap/identity.cpp create mode 100644 src/bdap/identity.h diff --git a/src/Makefile.am b/src/Makefile.am index be82e8711f..c66b0e3b74 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,6 +104,7 @@ DYNAMIC_CORE_H = \ bdap/entrychannel.h \ bdap/entrycheckpoints.h \ bdap/entrylink.h \ + bdap/identity.h \ dbwrapper.h \ dynode.h \ dynode-payments.h \ @@ -232,6 +233,7 @@ libdynamic_server_a_SOURCES = \ bdap/entrychannel.cpp \ bdap/entrycheckpoints.cpp \ bdap/entrylink.cpp \ + bdap/identity.cpp \ dbwrapper.cpp \ dynode.cpp \ dynode-payments.cpp\ diff --git a/src/bdap/identity.cpp b/src/bdap/identity.cpp new file mode 100644 index 0000000000..480f249ea4 --- /dev/null +++ b/src/bdap/identity.cpp @@ -0,0 +1,100 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/identity.h" + +#include "hash.h" +#include "streams.h" + +void CIdentity::Serialize(std::vector& vchData) +{ + CDataStream dsIdentity(SER_NETWORK, PROTOCOL_VERSION); + dsIdentity << *this; + vchData = std::vector(dsIdentity.begin(), dsIdentity.end()); +} + +bool CIdentity::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsIdentity(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsIdentity >> *this; + + std::vector vchIdentityData; + Serialize(vchIdentityData); + const uint256 &calculatedHash = Hash(vchIdentityData.begin(), vchIdentityData.end()); + const std::vector &vchRandIdentity = vchFromValue(calculatedHash.GetHex()); + if(vchRandIdentity != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CIdentity::UnserializeFromTx(const CTransaction& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +void CIdentityVerification::Serialize(std::vector& vchData) +{ + CDataStream dsIdentityVerification(SER_NETWORK, PROTOCOL_VERSION); + dsIdentityVerification << *this; + vchData = std::vector(dsIdentityVerification.begin(), dsIdentityVerification.end()); +} + +bool CIdentityVerification::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsIdentityVerification(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsIdentityVerification >> *this; + + std::vector vchIdentityVerification; + Serialize(vchIdentityVerification); + const uint256 &calculatedHash = Hash(vchIdentityVerification.begin(), vchIdentityVerification.end()); + const std::vector &vchRandIdentityVerification = vchFromValue(calculatedHash.GetHex()); + if(vchRandIdentityVerification != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CIdentityVerification::UnserializeFromTx(const CTransaction& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} \ No newline at end of file diff --git a/src/bdap/identity.h b/src/bdap/identity.h new file mode 100644 index 0000000000..4e932ff018 --- /dev/null +++ b/src/bdap/identity.h @@ -0,0 +1,146 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_IDENTITY_H +#define DYNAMIC_BDAP_IDENTITY_H + +#include "bdap.h" +#include "domainentry.h" +#include "serialize.h" +#include "uint256.h" + +class CIdentity { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString OwnerFullPath; // name of the owner's full domain entry path + CharString VerificationData; + unsigned int nHeight; + + uint256 txHash; + + CDomainEntry* OwnerDomainEntry; + + CIdentity() { + SetNull(); + } + + CIdentity(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CIdentity::CURRENT_VERSION; + OwnerFullPath.clear(); + VerificationData.clear(); + nHeight = 0; + txHash.SetNull(); + OwnerDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(OwnerFullPath); + READWRITE(VerificationData); + READWRITE(VARINT(nHeight)); + READWRITE(txHash); + } + + inline friend bool operator==(const CIdentity& a, const CIdentity& b) { + return (a.OwnerFullPath == b.OwnerFullPath && a.VerificationData == b.VerificationData); + } + + inline friend bool operator!=(const CIdentity& a, const CIdentity& b) { + return !(a == b); + } + + inline CIdentity operator=(const CIdentity& b) { + OwnerFullPath = b.OwnerFullPath; + VerificationData = b.VerificationData; + nHeight = b.nHeight; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (OwnerFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransaction& tx); +}; + +class CIdentityVerification { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString VerifierFullPath; // name of the verifier's full domain entry path + CIdentity Identity; + CharString Signature; + unsigned int nHeight; + + uint256 txHash; + + CDomainEntry* VerifierDomainEntry; + + CIdentityVerification() { + SetNull(); + } + + CIdentityVerification(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CIdentityVerification::CURRENT_VERSION; + VerifierFullPath.clear(); + Identity.SetNull(); + Signature.clear(); + nHeight = 0; + txHash.SetNull(); + VerifierDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(VerifierFullPath); + READWRITE(Identity); + READWRITE(Signature); + READWRITE(VARINT(nHeight)); + READWRITE(txHash); + } + + inline friend bool operator==(const CIdentityVerification& a, const CIdentityVerification& b) { + return (a.VerifierFullPath == b.VerifierFullPath && a.Identity == b.Identity && a.Signature == b.Signature); + } + + inline friend bool operator!=(const CIdentityVerification& a, const CIdentityVerification& b) { + return !(a == b); + } + + inline CIdentityVerification operator=(const CIdentityVerification& b) { + VerifierFullPath = b.VerifierFullPath; + Identity = b.Identity; + Signature = b.Signature; + nHeight = b.nHeight; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (VerifierFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransaction& tx); + +}; + +#endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file From c857aea1d6d02e4b589ea3cbded7d90d270d6ed5 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 23 Aug 2018 16:41:03 -0500 Subject: [PATCH 0187/1653] [BDAP] Add missing operation codes --- src/bdap/domainentry.cpp | 20 +++++++--- src/script/script.cpp | 36 +++++++++++------- src/script/script.h | 79 ++++++++++++++++++++++++++-------------- 3 files changed, 89 insertions(+), 46 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 68c7fed458..2cb034d5ef 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -29,8 +29,8 @@ std::string DomainEntryFromOp(const int op) return "bdap_new"; case OP_BDAP_DELETE: return "bdap_delete"; - case OP_BDAP_ACTIVATE: - return "bdap_activate"; + case OP_BDAP_REVOKE: + return "bdap_revoke"; case OP_BDAP_MODIFY: return "bdap_update"; case OP_BDAP_MODIFY_RDN: @@ -38,9 +38,19 @@ std::string DomainEntryFromOp(const int op) case OP_BDAP_EXECUTE_CODE: return "bdap_execute"; case OP_BDAP_BIND: - return "bdap_bind"; - case OP_BDAP_REVOKE: - return "bdap_revoke"; + return "bdap_link"; + case OP_BDAP_AUDIT: + return "bdap_audit"; + case OP_BDAP_CERTIFICATE: + return "bdap_certificate"; + case OP_BDAP_IDENTITY: + return "bdap_identity"; + case OP_BDAP_ID_VERIFICATION: + return "bdap_identity_verification"; + case OP_BDAP_CHANNEL: + return "bdap_new_channel"; + case OP_BDAP_CHANNEL_CHECKPOINT: + return "bdap_channel_checkpoint"; default: return ""; } diff --git a/src/script/script.cpp b/src/script/script.cpp index 740906e5a8..f1f3244c7d 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -149,17 +149,22 @@ const char* GetOpName(opcodetype opcode) case OP_RELEASE_ADDRESS : return "OP_RELEASE_ADDRESS"; // BDAP, directory access, user identity and certificate system - case OP_BDAP : return "OP_BDAP"; - case OP_BDAP_NEW : return "OP_BDAP_NEW"; - case OP_BDAP_DELETE : return "OP_BDAP_DELETE"; - case OP_BDAP_ACTIVATE : return "OP_BDAP_ACTIVATE"; - case OP_BDAP_MODIFY : return "OP_BDAP_MODIFY"; - case OP_BDAP_MODIFY_RDN : return "OP_BDAP_MODIFY_RDN"; - case OP_BDAP_EXECUTE_CODE : return "OP_BDAP_EXECUTE_CODE"; - case OP_BDAP_BIND : return "OP_BDAP_BIND"; - case OP_BDAP_REVOKE : return "OP_BDAP_REVOKE"; - - case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; + case OP_BDAP : return "OP_BDAP"; + case OP_BDAP_NEW : return "OP_BDAP_NEW"; + case OP_BDAP_DELETE : return "OP_BDAP_DELETE"; + case OP_BDAP_REVOKE : return "OP_BDAP_REVOKE"; + case OP_BDAP_MODIFY : return "OP_BDAP_MODIFY"; + case OP_BDAP_MODIFY_RDN : return "OP_BDAP_MODIFY_RDN"; + case OP_BDAP_EXECUTE_CODE : return "OP_BDAP_EXECUTE_CODE"; + case OP_BDAP_BIND : return "OP_BDAP_BIND"; + case OP_BDAP_AUDIT : return "OP_BDAP_AUDIT"; + case OP_BDAP_CERTIFICATE : return "OP_BDAP_CERTIFICATE"; + case OP_BDAP_IDENTITY : return "OP_BDAP_IDENTITY"; + case OP_BDAP_ID_VERIFICATION : return "OP_BDAP_ID_VERIFICATION"; + case OP_BDAP_CHANNEL : return "OP_BDAP_CHANNEL"; + case OP_BDAP_CHANNEL_CHECKPOINT : return "OP_BDAP_CHANNEL_CHECKPOINT"; + + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; // Note: // The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum @@ -177,12 +182,17 @@ bool IsBDAPOp(int op) return op == OP_BDAP || op == OP_BDAP_NEW || op == OP_BDAP_DELETE - || op == OP_BDAP_ACTIVATE + || op == OP_BDAP_REVOKE || op == OP_BDAP_MODIFY || op == OP_BDAP_MODIFY_RDN || op == OP_BDAP_EXECUTE_CODE || op == OP_BDAP_BIND - || op == OP_BDAP_REVOKE; + || op == OP_BDAP_AUDIT + || op == OP_BDAP_CERTIFICATE + || op == OP_BDAP_IDENTITY + || op == OP_BDAP_ID_VERIFICATION + || op == OP_BDAP_CHANNEL + || op == OP_BDAP_CHANNEL_CHECKPOINT; } bool DecodeBDAPScript(const CScript& script, int& op, std::vector >& vvch, CScript::const_iterator& pc) diff --git a/src/script/script.h b/src/script/script.h index af839c8953..92055e1966 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -23,21 +23,24 @@ // Identification codes for Fluid and BDAP Transactions enum ProtocolCodes { - MINT_TX = 1, - DYNODE_MODFIY_TX = 2, - MINING_MODIFY_TX = 3, - BDAP_START = 4, - BDAP_NEW_TX = 5, - BDAP_DELETE_TX = 6, - BDAP_ACTIVATE_TX = 7, - BDAP_MODIFY_TX = 8, - BDAP_MODIFY_RDN_TX = 9, - BDAP_EXECUTE_CODE_TX = 10, - BDAP_BIND_TX = 11, - BDAP_AUDIT_TX = 12, - BDAP_VERIFICATION_TX = 13, - BDAP_REVOKE_TX = 14, - NO_TX = 0 + MINT_TX = 1, + DYNODE_MODFIY_TX = 2, + MINING_MODIFY_TX = 3, + BDAP_START = 4, + BDAP_NEW_TX = 5, + BDAP_DELETE_TX = 6, + BDAP_REVOKE_TX = 7, + BDAP_MODIFY_TX = 8, + BDAP_MODIFY_RDN_TX = 9, + BDAP_EXECUTE_CODE_TX = 10, + BDAP_BIND_TX = 11, + BDAP_AUDIT_TX = 12, + BDAP_CERTIFICATE_TX = 13, + BDAP_IDENTITY_TX = 14, + BDAP_ID_VERIFICATION_TX = 15, + BDAP_CHANNEL_TX = 16, + BDAP_CHANNEL_CHECKPOINT = 17, + NO_TX = 0 }; // Maximum number of bytes pushable to the stack @@ -214,16 +217,21 @@ enum opcodetype OP_FREEZE_ADDRESS = 0xc7, OP_RELEASE_ADDRESS = 0xc8, - // directory access, user identity and certificate system + // BDAP directory access, user identity and certificate system OP_BDAP = 0x01, - OP_BDAP_NEW = 0x02, - OP_BDAP_DELETE = 0x03, - OP_BDAP_ACTIVATE = 0x04, - OP_BDAP_MODIFY = 0x05, - OP_BDAP_MODIFY_RDN = 0x06, - OP_BDAP_EXECUTE_CODE = 0x07, - OP_BDAP_BIND = 0x08, - OP_BDAP_REVOKE = 0x09, + OP_BDAP_NEW = 0x02, // = BDAP create new entry + OP_BDAP_DELETE = 0x03, // = BDAP user delete entry + OP_BDAP_REVOKE = 0x04, // = BDAP delete using fluid protocol + OP_BDAP_MODIFY = 0x05, // = BDAP update entry + OP_BDAP_MODIFY_RDN = 0x06, // = move BDAP entry + OP_BDAP_EXECUTE_CODE = 0x07, // = BDAP smart contract + OP_BDAP_BIND = 0x08, // = BDAP entry link request + OP_BDAP_AUDIT = 0x09, // = BDAP entry audit entry + OP_BDAP_CERTIFICATE = 0x0a, // = BDAP entry certificate + OP_BDAP_IDENTITY = 0x0b, // = BDAP entry identity + OP_BDAP_ID_VERIFICATION = 0x0c, // = BDAP identity verification + OP_BDAP_CHANNEL = 0x0d, // = BDAP sub chain + OP_BDAP_CHANNEL_CHECKPOINT = 0x0e, // = BDAP sub chain checkpoint // dynamic extended reserved OP_DYNAMIC_EXTENDED = 0x10, @@ -714,8 +722,8 @@ class CScript : public CScriptBase case BDAP_DELETE_TX: return (size() > 0 && *begin() == OP_BDAP_DELETE); break; - case BDAP_ACTIVATE_TX: - return (size() > 0 && *begin() == OP_BDAP_ACTIVATE); + case BDAP_REVOKE_TX: + return (size() > 0 && *begin() == OP_BDAP_REVOKE); break; case BDAP_MODIFY_TX: return (size() > 0 && *begin() == OP_BDAP_MODIFY); @@ -729,8 +737,23 @@ class CScript : public CScriptBase case BDAP_BIND_TX: return (size() > 0 && *begin() == OP_BDAP_BIND); break; - case BDAP_REVOKE_TX: - return (size() > 0 && *begin() == OP_BDAP_REVOKE); + case BDAP_AUDIT_TX: + return (size() > 0 && *begin() == OP_BDAP_AUDIT); + break; + case BDAP_CERTIFICATE_TX: + return (size() > 0 && *begin() == OP_BDAP_CERTIFICATE); + break; + case BDAP_IDENTITY_TX: + return (size() > 0 && *begin() == OP_BDAP_IDENTITY); + break; + case BDAP_ID_VERIFICATION_TX: + return (size() > 0 && *begin() == OP_BDAP_ID_VERIFICATION); + break; + case BDAP_CHANNEL_TX: + return (size() > 0 && *begin() == OP_BDAP_CHANNEL); + break; + case BDAP_CHANNEL_CHECKPOINT: + return (size() > 0 && *begin() == OP_BDAP_CHANNEL_CHECKPOINT); break; default: throw std::runtime_error("BDAP code is invalid!"); From bf1b4b114f9263c70da6210f698ace993a968d6b Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 23 Aug 2018 17:26:21 -0500 Subject: [PATCH 0188/1653] [BDAP] Adjust identity verification class --- src/bdap/identity.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bdap/identity.h b/src/bdap/identity.h index 4e932ff018..eb0cd1d69f 100644 --- a/src/bdap/identity.h +++ b/src/bdap/identity.h @@ -80,8 +80,9 @@ class CIdentityVerification { int nVersion; CharString VerifierFullPath; // name of the verifier's full domain entry path CIdentity Identity; - CharString Signature; + CharString VerificationData; unsigned int nHeight; + uint64_t nExpireTime; uint256 txHash; @@ -101,8 +102,9 @@ class CIdentityVerification { nVersion = CIdentityVerification::CURRENT_VERSION; VerifierFullPath.clear(); Identity.SetNull(); - Signature.clear(); + VerificationData.clear(); nHeight = 0; + nExpireTime = 0; txHash.SetNull(); VerifierDomainEntry = nullptr; } @@ -114,13 +116,14 @@ class CIdentityVerification { READWRITE(this->nVersion); READWRITE(VerifierFullPath); READWRITE(Identity); - READWRITE(Signature); + READWRITE(VerificationData); READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); READWRITE(txHash); } inline friend bool operator==(const CIdentityVerification& a, const CIdentityVerification& b) { - return (a.VerifierFullPath == b.VerifierFullPath && a.Identity == b.Identity && a.Signature == b.Signature); + return (a.VerifierFullPath == b.VerifierFullPath && a.Identity == b.Identity && a.VerificationData == b.VerificationData && a.nExpireTime == b.nExpireTime); } inline friend bool operator!=(const CIdentityVerification& a, const CIdentityVerification& b) { @@ -130,8 +133,9 @@ class CIdentityVerification { inline CIdentityVerification operator=(const CIdentityVerification& b) { VerifierFullPath = b.VerifierFullPath; Identity = b.Identity; - Signature = b.Signature; + VerificationData = b.VerificationData; nHeight = b.nHeight; + nExpireTime = b.nExpireTime; txHash = b.txHash; return *this; } From 55b042e8892a0db30945407ca8b1822c6b245304 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 23 Aug 2018 18:34:48 -0500 Subject: [PATCH 0189/1653] [BDAP] Fix domain entry object type enum --- src/bdap/bdap.h | 19 ++++++++++++++++++ src/bdap/domainentry.cpp | 42 ++++++++++++++++++++++++++++++++++++++-- src/bdap/domainentry.h | 29 +++++++++++++-------------- 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h index 10996e45db..1078f9d764 100644 --- a/src/bdap/bdap.h +++ b/src/bdap/bdap.h @@ -8,6 +8,25 @@ #include #include +namespace BDAP { + enum ObjectType { + DEFAULT_TYPE = 0, + USER_ACCOUNT = 1, + GROUP = 2, + DEVICE_ACCOUNT = 3, + DOMAIN_ACCOUNT = 4, + ORGANIZATIONAL_UNIT = 5, + CERTIFICATE = 6, + AUDIT = 7, + CHANNEL = 8, + CHECKPOINT = 9, + BINDING_LINK = 10, + IDENTITY = 11, + IDENTITY_VERIFICATION = 12, + SMART_CONTRACT = 13 + }; +} + typedef std::vector CharString; typedef std::vector vchCharString; typedef std::pair CheckPoint; diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 2cb034d5ef..af3f708fa0 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -22,6 +22,44 @@ using namespace boost::xpressive; +namespace BDAP { + std::string GetObjectTypeString(unsigned int nObjectType) + { + switch ((BDAP::ObjectType)nObjectType) { + case BDAP::DEFAULT_TYPE: + return "Default"; + case BDAP::USER_ACCOUNT: + return "User Entry"; + case BDAP::GROUP: + return "Group Entry"; + case BDAP::DEVICE_ACCOUNT: + return "Device Entry"; + case BDAP::DOMAIN_ACCOUNT: + return "Domain Entry"; + case BDAP::ORGANIZATIONAL_UNIT: + return "OU Entry"; + case BDAP::CERTIFICATE: + return "Certificate Entry"; + case BDAP::AUDIT: + return "Audit Entry"; + case BDAP::CHANNEL: + return "Channel Entry"; + case BDAP::CHECKPOINT: + return "Channel Checkpoint Entry"; + case BDAP::BINDING_LINK: + return "Binding Link Entry"; + case BDAP::IDENTITY: + return "Identity Entry"; + case BDAP::IDENTITY_VERIFICATION: + return "Identity Verification Entry"; + case BDAP::SMART_CONTRACT: + return "Smart Contract Entry"; + default: + return "Unknown"; + } + } +} + std::string DomainEntryFromOp(const int op) { switch (op) { @@ -378,8 +416,8 @@ bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) oName.push_back(Pair("organizational_unit", stringFromVch(entry.OrganizationalUnit))); oName.push_back(Pair("organization_name", stringFromVch(entry.DomainComponent))); oName.push_back(Pair("object_id", stringFromVch(entry.ObjectID))); - oName.push_back(Pair("object_full_path", stringFromVch(entry.vchFullObjectPath()))); - oName.push_back(Pair("object_type", entry.ObjectType)); + oName.push_back(Pair("object_full_path", entry.GetFullObjectPath())); + oName.push_back(Pair("object_type", entry.ObjectTypeString())); oName.push_back(Pair("wallet_address", stringFromVch(entry.WalletAddress))); oName.push_back(Pair("public", (int)entry.fPublicObject)); oName.push_back(Pair("encryption_publickey", HexStr(entry.EncryptPublicKey))); diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index 2dba24bfc0..ddf4f63047 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -38,23 +38,18 @@ class CTxMemPool; - Implement file sharing using IPFS */ +using namespace BDAP; + +namespace BDAP { + std::string GetObjectTypeString(unsigned int nObjectType); +} + class CDomainEntryDefaultParameters { public: void InitialiseAdminOwners(); //DEFAULT_ADMIN_DOMAIN void InitialisePublicDomain(); //DEFAULT_PUBLIC_DOMAIN }; -enum DomainEntryObjectType { - USER_ACCOUNT = 0, - DEVICE_ACCOUNT = 1, - GROUP = 2, - DOMAIN_ACCOUNT = 3, - ORGANIZATIONAL_UNIT = 4, - CERTIFICATE = 5, - CODE = 6, - BINDING = 7 -}; - // See LDAP Distinguished Name class CDomainEntry { public: @@ -67,7 +62,7 @@ class CDomainEntry { CharString OrganizationalUnit; // OU. Like OU=sales. blank for top level domain directories CharString OrganizationName; // O. Like Duality Blockchain Solutions CharString ObjectID; // UID. Like johnsmith21. blank for top level domain directories - DomainEntryObjectType ObjectType; // see enum above + unsigned int nObjectType; // see enum above CharString WalletAddress; // used to send collateral funds for this directory record. int8_t fPublicObject; // public and private visibility is relative to other objects in its domain directory CharString EncryptPublicKey; // used to encrypt data to send to this directory record. @@ -96,7 +91,7 @@ class CDomainEntry { OrganizationalUnit.clear(); OrganizationName.clear(); ObjectID.clear(); - ObjectType = DomainEntryObjectType::DOMAIN_ACCOUNT; + nObjectType = 0; WalletAddress.clear(); fPublicObject = 0; // by default set to private visibility. EncryptPublicKey.clear(); @@ -117,7 +112,7 @@ class CDomainEntry { READWRITE(OrganizationalUnit); READWRITE(OrganizationName); READWRITE(ObjectID); - //READWRITE(static_cast(ObjectType)); + READWRITE(VARINT(nObjectType)); READWRITE(WalletAddress); READWRITE(VARINT(fPublicObject)); READWRITE(EncryptPublicKey); @@ -128,7 +123,7 @@ class CDomainEntry { } inline friend bool operator==(const CDomainEntry &a, const CDomainEntry &b) { - return (a.OID == b.OID && a.DomainComponent == b.DomainComponent && a.OrganizationalUnit == b.OrganizationalUnit && a.ObjectID == b.ObjectID); + return (a.OID == b.OID && a.DomainComponent == b.DomainComponent && a.OrganizationalUnit == b.OrganizationalUnit && a.nObjectType == b.nObjectType); } inline friend bool operator!=(const CDomainEntry &a, const CDomainEntry &b) { @@ -142,7 +137,7 @@ class CDomainEntry { OrganizationalUnit = b.OrganizationalUnit; OrganizationName = b.OrganizationName; ObjectID = b.ObjectID; - ObjectType = b.ObjectType; + nObjectType = b.nObjectType; WalletAddress = b.WalletAddress; fPublicObject = b.fPublicObject; EncryptPublicKey = b.EncryptPublicKey; @@ -167,6 +162,8 @@ class CDomainEntry { bool ValidateValues(std::string& errorMessage); bool CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& errorMessage); bool TxUsesPreviousUTXO(const CTransaction& tx); + BDAP::ObjectType ObjectType() const { return (BDAP::ObjectType)nObjectType; } + std::string ObjectTypeString() const { return BDAP::GetObjectTypeString(nObjectType); }; }; std::string DomainEntryFromOp(const int op); From 9b67ebe790a2978e08513b6487e915a754c3165b Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 23 Aug 2018 18:35:19 -0500 Subject: [PATCH 0190/1653] [BDAP] Add entry audit data class --- src/Makefile.am | 2 + src/bdap/auditdata.cpp | 70 ++++++++++++++++++++++++++++ src/bdap/auditdata.h | 98 ++++++++++++++++++++++++++++++++++++++++ src/bdap/bdap.h | 16 +++---- src/bdap/domainentry.cpp | 29 ++++++------ 5 files changed, 193 insertions(+), 22 deletions(-) create mode 100644 src/bdap/auditdata.cpp create mode 100644 src/bdap/auditdata.h diff --git a/src/Makefile.am b/src/Makefile.am index c66b0e3b74..8c83c5ad8b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,6 +97,7 @@ DYNAMIC_CORE_H = \ consensus/validation.h \ core_io.h \ core_memusage.h \ + bdap/auditdata.h \ bdap/bdap.h \ bdap/domainentry.h \ bdap/domainentrydb.h \ @@ -227,6 +228,7 @@ libdynamic_server_a_SOURCES = \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ + bdap/auditdata.cpp \ bdap/domainentry.cpp \ bdap/domainentrydb.cpp \ bdap/entrycertificate.cpp \ diff --git a/src/bdap/auditdata.cpp b/src/bdap/auditdata.cpp new file mode 100644 index 0000000000..5b7cc1b055 --- /dev/null +++ b/src/bdap/auditdata.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bdap/auditdata.h" + +#include "hash.h" +#include "streams.h" + + +namespace BDAP { + std::string GetAuditTypeString(unsigned int nAuditType) + { + switch ((BDAP::AuditType)nAuditType) { + + case BDAP::AuditType::UNKNOWN: + return "Unknown"; + case BDAP::AuditType::HASH_POINTER_AUDIT: + return "User Entry"; + default: + return "Unknown"; + } + } +} + +void CAuditData::Serialize(std::vector& vchData) +{ + CDataStream dsAuditData(SER_NETWORK, PROTOCOL_VERSION); + dsAuditData << *this; + vchData = std::vector(dsAuditData.begin(), dsAuditData.end()); +} + +bool CAuditData::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsAuditData(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsAuditData >> *this; + + std::vector vchAuditData; + Serialize(vchAuditData); + const uint256 &calculatedHash = Hash(vchAuditData.begin(), vchAuditData.end()); + const std::vector &vchRandAuditData = vchFromValue(calculatedHash.GetHex()); + if(vchRandAuditData != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CAuditData::UnserializeFromTx(const CTransaction& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} \ No newline at end of file diff --git a/src/bdap/auditdata.h b/src/bdap/auditdata.h new file mode 100644 index 0000000000..dd34974fdd --- /dev/null +++ b/src/bdap/auditdata.h @@ -0,0 +1,98 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_BDAP_IDENTITY_H +#define DYNAMIC_BDAP_IDENTITY_H + +#include "bdap.h" +#include "domainentry.h" +#include "serialize.h" +#include "uint256.h" + +using namespace BDAP; + +namespace BDAP { + enum AuditType { + UNKNOWN = 0, + HASH_POINTER_AUDIT = 1 + }; + std::string GetAuditTypeString(unsigned int nAuditType); +} + +class CAuditData { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString OwnerFullPath; // name of the owner's full domain entry path + CharString AuditData; // usually just a hash that points to the document being audited + unsigned int nAuditType; + unsigned int nHeight; + uint64_t nExpireTime; + + uint256 txHash; + + CDomainEntry* OwnerDomainEntry; + + CAuditData() { + SetNull(); + } + + CAuditData(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CAuditData::CURRENT_VERSION; + OwnerFullPath.clear(); + AuditData.clear(); + nAuditType = 0; + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + OwnerDomainEntry = nullptr; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(OwnerFullPath); + READWRITE(AuditData); + READWRITE(VARINT(nAuditType)); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CAuditData& a, const CAuditData& b) { + return (a.OwnerFullPath == b.OwnerFullPath && a.AuditData == b.AuditData && a.nExpireTime == b.nExpireTime); + } + + inline friend bool operator!=(const CAuditData& a, const CAuditData& b) { + return !(a == b); + } + + inline CAuditData operator=(const CAuditData& b) { + OwnerFullPath = b.OwnerFullPath; + AuditData = b.AuditData; + nAuditType = b.nAuditType; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (OwnerFullPath.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); + bool UnserializeFromTx(const CTransaction& tx); + + BDAP::AuditType AuditType() { return (BDAP::AuditType)nAuditType; } + std::string AuditTypeString() { return BDAP::GetAuditTypeString(nAuditType); } +}; + +#endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h index 1078f9d764..eee519932f 100644 --- a/src/bdap/bdap.h +++ b/src/bdap/bdap.h @@ -16,14 +16,14 @@ namespace BDAP { DEVICE_ACCOUNT = 3, DOMAIN_ACCOUNT = 4, ORGANIZATIONAL_UNIT = 5, - CERTIFICATE = 6, - AUDIT = 7, - CHANNEL = 8, - CHECKPOINT = 9, - BINDING_LINK = 10, - IDENTITY = 11, - IDENTITY_VERIFICATION = 12, - SMART_CONTRACT = 13 + CERTIFICATE = 6, + AUDIT = 7, + CHANNEL = 8, + CHECKPOINT = 9, + BINDING_LINK = 10, + IDENTITY = 11, + IDENTITY_VERIFICATION = 12, + SMART_CONTRACT = 13 }; } diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index af3f708fa0..9e950dfa87 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -26,33 +26,34 @@ namespace BDAP { std::string GetObjectTypeString(unsigned int nObjectType) { switch ((BDAP::ObjectType)nObjectType) { - case BDAP::DEFAULT_TYPE: + + case BDAP::ObjectType::DEFAULT_TYPE: return "Default"; - case BDAP::USER_ACCOUNT: + case BDAP::ObjectType::USER_ACCOUNT: return "User Entry"; - case BDAP::GROUP: + case BDAP::ObjectType::GROUP: return "Group Entry"; - case BDAP::DEVICE_ACCOUNT: + case BDAP::ObjectType::DEVICE_ACCOUNT: return "Device Entry"; - case BDAP::DOMAIN_ACCOUNT: + case BDAP::ObjectType::DOMAIN_ACCOUNT: return "Domain Entry"; - case BDAP::ORGANIZATIONAL_UNIT: + case BDAP::ObjectType::ORGANIZATIONAL_UNIT: return "OU Entry"; - case BDAP::CERTIFICATE: + case BDAP::ObjectType::CERTIFICATE: return "Certificate Entry"; - case BDAP::AUDIT: + case BDAP::ObjectType::AUDIT: return "Audit Entry"; - case BDAP::CHANNEL: + case BDAP::ObjectType::CHANNEL: return "Channel Entry"; - case BDAP::CHECKPOINT: + case BDAP::ObjectType::CHECKPOINT: return "Channel Checkpoint Entry"; - case BDAP::BINDING_LINK: + case BDAP::ObjectType::BINDING_LINK: return "Binding Link Entry"; - case BDAP::IDENTITY: + case BDAP::ObjectType::IDENTITY: return "Identity Entry"; - case BDAP::IDENTITY_VERIFICATION: + case BDAP::ObjectType::IDENTITY_VERIFICATION: return "Identity Verification Entry"; - case BDAP::SMART_CONTRACT: + case BDAP::ObjectType::SMART_CONTRACT: return "Smart Contract Entry"; default: return "Unknown"; From 40f682613918851e2e1f05c1734d88ca0b39cc16 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 24 Aug 2018 01:42:28 -0500 Subject: [PATCH 0191/1653] [BDAP] Add new public group entry RPC command --- src/bdap/bdap.h | 4 ++ src/bdap/domainentry.cpp | 5 ++ src/bdap/domainentry.h | 1 + src/bdap/domainentrydb.cpp | 4 +- src/bdap/rpcdomainentry.cpp | 103 +++++++++++++++++++++++++++--------- 5 files changed, 91 insertions(+), 26 deletions(-) diff --git a/src/bdap/bdap.h b/src/bdap/bdap.h index eee519932f..0a82c65125 100644 --- a/src/bdap/bdap.h +++ b/src/bdap/bdap.h @@ -50,6 +50,8 @@ static constexpr unsigned int MAX_CHECKPOINT_HASH_LENGTH = 64; static constexpr unsigned int SECONDS_PER_DAY = 86400; // Number of seconds per day. static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io"; static const std::string DEFAULT_PUBLIC_OU = "public"; +static const std::string DEFAULT_PUBLIC_USER_OU = "users"; +static const std::string DEFAULT_PUBLIC_GROUP_OU = "groups"; static const std::string DEFAULT_ADMIN_OU = "admin"; static const std::string DEFAULT_ORGANIZATION_NAME = "Duality Blockchain Solutions"; static const std::string DEFAULT_OID_PREFIX = "0.0.0"; //TODO (bdap): get real OID prefix @@ -62,6 +64,8 @@ inline const CharString ConvertConstantToCharString (const std::string strConver static const CharString vchDefaultDomainName = ConvertConstantToCharString(DEFAULT_PUBLIC_DOMAIN); static const CharString vchDefaultPublicOU = ConvertConstantToCharString(DEFAULT_PUBLIC_OU); +static const CharString vchDefaultUserOU = ConvertConstantToCharString(DEFAULT_PUBLIC_USER_OU); +static const CharString vchDefaultGroupOU = ConvertConstantToCharString(DEFAULT_PUBLIC_GROUP_OU); static const CharString vchDefaultAdminOU = ConvertConstantToCharString(DEFAULT_ADMIN_OU); static const CharString vchDefaultOrganizationName = ConvertConstantToCharString(DEFAULT_ORGANIZATION_NAME); static const CharString vchDefaultOIDPrefix = ConvertConstantToCharString(DEFAULT_OID_PREFIX); diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 9e950dfa87..881d640fe8 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -59,6 +59,11 @@ namespace BDAP { return "Unknown"; } } + + unsigned int GetObjectTypeInt(BDAP::ObjectType ObjectType) + { + return (unsigned int)ObjectType; + } } std::string DomainEntryFromOp(const int op) diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index ddf4f63047..b037d2699a 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -42,6 +42,7 @@ using namespace BDAP; namespace BDAP { std::string GetObjectTypeString(unsigned int nObjectType); + unsigned int GetObjectTypeInt(BDAP::ObjectType ObjectType); } class CDomainEntryDefaultParameters { diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index adc93f677f..362651ed2b 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -334,9 +334,9 @@ static bool CommonDataCheck(const CDomainEntry& entry, const vchCharString& vvch return false; } - if (entry.OrganizationalUnit != vchDefaultPublicOU && entry.OrganizationalUnit != vchDefaultAdminOU) + if (entry.OrganizationalUnit != vchDefaultPublicOU && entry.OrganizationalUnit != vchDefaultUserOU && entry.OrganizationalUnit != vchDefaultGroupOU) { - errorMessage = "CommonDataCheck failed! Must use default public organizational unit."; + errorMessage = "CommonDataCheck failed! Must use default organizational units."; return false; } diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 46883a7f36..35a2c5ddc6 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -17,13 +17,8 @@ extern void SendBDAPTransaction(const CScript bdapDataScript, const CScript bdap static constexpr bool fPrintDebug = true; -UniValue adddomainentry(const JSONRPCRequest& request) +static UniValue AddDomainEntry(const JSONRPCRequest& request, BDAP::ObjectType bdapType) { - if (request.params.size() < 2 || request.params.size() > 3) - { - throw std::runtime_error("adddomainentry \nAdd public name entry to blockchain directory.\n"); - } - EnsureWalletIsUnlocked(); // Adds a new name to channel zero. OID = 0.0.block-height.tx-ordinal.0.0.0.0 @@ -38,15 +33,22 @@ UniValue adddomainentry(const JSONRPCRequest& request) CDomainEntry txDomainEntry; txDomainEntry.OID = vchDefaultOIDPrefix; txDomainEntry.DomainComponent = vchDefaultDomainName; - txDomainEntry.OrganizationalUnit = vchDefaultPublicOU; + if (bdapType == BDAP::ObjectType::USER_ACCOUNT) { + txDomainEntry.OrganizationalUnit = vchDefaultUserOU; + } + else if (bdapType == BDAP::ObjectType::GROUP) { + txDomainEntry.OrganizationalUnit = vchDefaultGroupOU; + } + txDomainEntry.CommonName = vchCommonName; txDomainEntry.OrganizationName = vchDefaultOrganizationName; txDomainEntry.ObjectID = vchObjectID; - txDomainEntry.fPublicObject = 1; //make entry public + txDomainEntry.fPublicObject = 1; // make entry public + txDomainEntry.nObjectType = GetObjectTypeInt(bdapType); // Check if name already exists if (GetDomainEntry(txDomainEntry.vchFullObjectPath(), txDomainEntry)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3500 - " + txDomainEntry.GetFullObjectPath() + _(" entry already exists. Can not add duplicate.")); + throw std::runtime_error("BDAP_ADD_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3500 - " + txDomainEntry.GetFullObjectPath() + _(" entry already exists. Can not add duplicate.")); // TODO: Add ability to pass in the wallet address CKey privWalletKey; @@ -56,7 +58,7 @@ UniValue adddomainentry(const JSONRPCRequest& request) CDynamicAddress walletAddress = CDynamicAddress(keyWalletID); if (pwalletMain && !pwalletMain->AddKeyPubKey(privWalletKey, pubWalletKey)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3502 - " + _("Error adding receiving address key wo wallet for BDAP")); + throw std::runtime_error("BDAP_ADD_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3502 - " + _("Error adding receiving address key wo wallet for BDAP")); pwalletMain->SetAddressBook(keyWalletID, strObjectID, "receive"); @@ -71,7 +73,7 @@ UniValue adddomainentry(const JSONRPCRequest& request) CharString vchEncryptPriKey(strPrivateEncryptKey.begin(), strPrivateEncryptKey.end()); CharString vchEncryptPubKey(pubEncryptKey.begin(), pubEncryptKey.end()); if (pwalletMain && !pwalletMain->AddKeyPubKey(privEncryptKey, pubEncryptKey)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3503 - " + _("Error adding encrypt key to wallet for BDAP")); + throw std::runtime_error("BDAP_ADD_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3503 - " + _("Error adding encrypt key to wallet for BDAP")); txDomainEntry.EncryptPublicKey = vchEncryptPubKey; @@ -82,7 +84,7 @@ UniValue adddomainentry(const JSONRPCRequest& request) CKeyID keyLinkID = pubLinkKey.GetID(); CDynamicAddress linkAddress = CDynamicAddress(keyLinkID); if (pwalletMain && !pwalletMain->AddKeyPubKey(privLinkKey, pubLinkKey)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3504 - " + _("Error adding receiving address key wo wallet for BDAP")); + throw std::runtime_error("BDAP_ADD_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3504 - " + _("Error adding receiving address key wo wallet for BDAP")); pwalletMain->SetAddressBook(keyLinkID, strObjectID, "link"); @@ -121,14 +123,14 @@ UniValue adddomainentry(const JSONRPCRequest& request) // check BDAP values std::string strMessage; if (!txDomainEntry.ValidateValues(strMessage)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3505 - " + strMessage); + throw std::runtime_error("BDAP_ADD_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3505 - " + strMessage); SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); txDomainEntry.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); if(!BuildBDAPJson(txDomainEntry, oName)) - throw std::runtime_error("BDAP_ADD_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3506 - " + _("Failed to read from BDAP JSON object")); + throw std::runtime_error("BDAP_ADD_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3506 - " + _("Failed to read from BDAP JSON object")); if (fPrintDebug) { // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class @@ -145,6 +147,16 @@ UniValue adddomainentry(const JSONRPCRequest& request) return oName; } +UniValue adddomainentry(const JSONRPCRequest& request) +{ + if (request.params.size() < 2 || request.params.size() > 3) + { + throw std::runtime_error("adddomainentry \nAdd public name entry to blockchain directory.\n"); + } + BDAP::ObjectType bdapType = BDAP::ObjectType::USER_ACCOUNT; + return AddDomainEntry(request, bdapType); +} + UniValue getdomainentries(const JSONRPCRequest& request) { if (request.params.size() > 2) @@ -161,7 +173,7 @@ UniValue getdomainentries(const JSONRPCRequest& request) nPage = request.params[1].get_int(); // only return entries from the default public domain OU - std::string strObjectLocation = DEFAULT_PUBLIC_OU + "." + DEFAULT_PUBLIC_DOMAIN; + std::string strObjectLocation = DEFAULT_PUBLIC_USER_OU + "." + DEFAULT_PUBLIC_DOMAIN; CharString vchObjectLocation(strObjectLocation.begin(), strObjectLocation.end()); UniValue oDomainEntryList(UniValue::VARR); @@ -171,11 +183,11 @@ UniValue getdomainentries(const JSONRPCRequest& request) return oDomainEntryList; } -UniValue getdomainentryinfo(const JSONRPCRequest& request) +UniValue getdomainuserinfo(const JSONRPCRequest& request) { if (request.params.size() != 1) { - throw std::runtime_error("getdomainentryinfo \nList BDAP entry.\n"); + throw std::runtime_error("getdomainuserinfo \nList BDAP entry.\n"); } CharString vchObjectID = vchFromValue(request.params[0]); @@ -183,17 +195,45 @@ UniValue getdomainentryinfo(const JSONRPCRequest& request) CDomainEntry directory; directory.DomainComponent = vchDefaultDomainName; - directory.OrganizationalUnit = vchDefaultPublicOU; + directory.OrganizationalUnit = vchDefaultUserOU; directory.ObjectID = vchObjectID; UniValue oDomainEntryInfo(UniValue::VOBJ); if (CheckDomainEntryDB()) { if (!pDomainEntryDB->GetDomainEntryInfo(directory.vchFullObjectPath(), oDomainEntryInfo)) { - throw std::runtime_error("BDAP_SELECT_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3600 - " + directory.GetFullObjectPath() + _(" can not be found. Get info failed!")); + throw std::runtime_error("BDAP_SELECT_PUBLIC_USER_RPC_ERROR: ERRCODE: 3600 - " + directory.GetFullObjectPath() + _(" can not be found. Get info failed!")); } } else { - throw std::runtime_error("BDAP_SELECT_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3601 - " + _("Can not access BDAP LevelDB database. Get info failed!")); + throw std::runtime_error("BDAP_SELECT_PUBLIC_USER_RPC_ERROR: ERRCODE: 3601 - " + _("Can not access BDAP LevelDB database. Get info failed!")); + } + + return oDomainEntryInfo; +} + +UniValue getdomaingroupinfo(const JSONRPCRequest& request) +{ + if (request.params.size() != 1) + { + throw std::runtime_error("getdomaingroupinfo \nList BDAP entry.\n"); + } + + CharString vchObjectID = vchFromValue(request.params[0]); + ToLowerCase(vchObjectID); + + CDomainEntry directory; + directory.DomainComponent = vchDefaultDomainName; + directory.OrganizationalUnit = vchDefaultGroupOU; + directory.ObjectID = vchObjectID; + + UniValue oDomainEntryInfo(UniValue::VOBJ); + if (CheckDomainEntryDB()) { + if (!pDomainEntryDB->GetDomainEntryInfo(directory.vchFullObjectPath(), oDomainEntryInfo)) { + throw std::runtime_error("BDAP_SELECT_PUBLIC_USER_RPC_ERROR: ERRCODE: 3600 - " + directory.GetFullObjectPath() + _(" can not be found. Get info failed!")); + } + } + else { + throw std::runtime_error("BDAP_SELECT_PUBLIC_USER_RPC_ERROR: ERRCODE: 3601 - " + _("Can not access BDAP LevelDB database. Get info failed!")); } return oDomainEntryInfo; @@ -213,7 +253,7 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { CDomainEntry txPreviousEntry; txPreviousEntry.DomainComponent = vchDefaultDomainName; - txPreviousEntry.OrganizationalUnit = vchDefaultPublicOU; + txPreviousEntry.OrganizationalUnit = vchDefaultUserOU; txPreviousEntry.ObjectID = vchObjectID; // Check if name already exists @@ -228,6 +268,7 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { CDomainEntry txUpdatedEntry = txPreviousEntry; CharString vchCommonName = vchFromValue(request.params[1]); txUpdatedEntry.CommonName = vchCommonName; + txUpdatedEntry.nObjectType = GetObjectTypeInt(BDAP::ObjectType::USER_ACCOUNT); uint64_t nDays = 1461; //default to 4 years. if (request.params.size() >= 3) { @@ -300,10 +341,10 @@ UniValue deletedomainentry(const JSONRPCRequest& request) { CDomainEntry txSearchEntry; txSearchEntry.DomainComponent = vchDefaultDomainName; - txSearchEntry.OrganizationalUnit = vchDefaultPublicOU; + txSearchEntry.OrganizationalUnit = vchDefaultUserOU; txSearchEntry.ObjectID = vchObjectID; CDomainEntry txDeletedEntry = txSearchEntry; - + // Check if name already exists if (!GetDomainEntry(txSearchEntry.vchFullObjectPath(), txSearchEntry)) throw std::runtime_error("BDAP_DELETE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txSearchEntry.GetFullObjectPath() + _(" does not exists. Can not delete.")); @@ -315,6 +356,7 @@ UniValue deletedomainentry(const JSONRPCRequest& request) { txDeletedEntry.WalletAddress = txSearchEntry.WalletAddress; txDeletedEntry.CommonName = txSearchEntry.CommonName; + txDeletedEntry.nObjectType = GetObjectTypeInt(BDAP::ObjectType::USER_ACCOUNT); CharString data; txDeletedEntry.Serialize(data); @@ -396,15 +438,28 @@ UniValue makekeypair(const JSONRPCRequest& request) return result; } +UniValue adddomaingroup(const JSONRPCRequest& request) +{ + if (request.params.size() < 2 || request.params.size() > 3) + { + throw std::runtime_error("adddomaingroup \nAdd public group entry to blockchain directory.\n"); + } + + BDAP::ObjectType bdapType = BDAP::ObjectType::GROUP; + return AddDomainEntry(request, bdapType); +} + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode #ifdef ENABLE_WALLET /* BDAP */ { "bdap", "adddomainentry", &adddomainentry, true }, { "bdap", "getdomainentries", &getdomainentries, true }, - { "bdap", "getdomainentryinfo", &getdomainentryinfo, true }, + { "bdap", "getdomainuserinfo", &getdomainuserinfo, true }, { "bdap", "updatedomainentry", &updatedomainentry, true }, { "bdap", "deletedomainentry", &deletedomainentry, true }, + { "bdap", "adddomaingroup", &adddomaingroup, true }, + { "bdap", "getdomaingroupinfo", &getdomaingroupinfo, true }, #endif //ENABLE_WALLET { "bdap", "makekeypair", &makekeypair, true }, }; From acd425437697973df60a89fa4c9abee5e8faac75 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 24 Aug 2018 02:16:15 -0500 Subject: [PATCH 0192/1653] [BDAP] Add list domain group entries RPC command --- src/bdap/rpcdomainentry.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 35a2c5ddc6..8a3468434c 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -157,11 +157,11 @@ UniValue adddomainentry(const JSONRPCRequest& request) return AddDomainEntry(request, bdapType); } -UniValue getdomainentries(const JSONRPCRequest& request) +UniValue getdomainusers(const JSONRPCRequest& request) { if (request.params.size() > 2) { - throw std::runtime_error("getdomainentries \nLists all BDAP entries.\n"); + throw std::runtime_error("getdomainusers \nLists all BDAP public users.\n"); } unsigned int nRecordsPerPage = 100; @@ -183,6 +183,32 @@ UniValue getdomainentries(const JSONRPCRequest& request) return oDomainEntryList; } +UniValue getdomaingroups(const JSONRPCRequest& request) +{ + if (request.params.size() > 2) + { + throw std::runtime_error("getdomainugroups \nLists all BDAP public groups.\n"); + } + + unsigned int nRecordsPerPage = 100; + unsigned int nPage = 1; + if (request.params.size() > 0) + nRecordsPerPage = request.params[0].get_int(); + + if (request.params.size() == 2) + nPage = request.params[1].get_int(); + + // only return entries from the default public domain OU + std::string strObjectLocation = DEFAULT_PUBLIC_GROUP_OU + "." + DEFAULT_PUBLIC_DOMAIN; + CharString vchObjectLocation(strObjectLocation.begin(), strObjectLocation.end()); + + UniValue oDomainEntryList(UniValue::VARR); + if (CheckDomainEntryDB()) + pDomainEntryDB->ListDirectories(vchObjectLocation, nRecordsPerPage, nPage, oDomainEntryList); + + return oDomainEntryList; +} + UniValue getdomainuserinfo(const JSONRPCRequest& request) { if (request.params.size() != 1) @@ -454,7 +480,8 @@ static const CRPCCommand commands[] = #ifdef ENABLE_WALLET /* BDAP */ { "bdap", "adddomainentry", &adddomainentry, true }, - { "bdap", "getdomainentries", &getdomainentries, true }, + { "bdap", "getdomainusers", &getdomainusers, true }, + { "bdap", "getdomaingroups", &getdomaingroups, true }, { "bdap", "getdomainuserinfo", &getdomainuserinfo, true }, { "bdap", "updatedomainentry", &updatedomainentry, true }, { "bdap", "deletedomainentry", &deletedomainentry, true }, From 43b7a98912a202ec152e9df776f1dd0e1ab71232 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 24 Aug 2018 02:31:09 -0500 Subject: [PATCH 0193/1653] [BDAP] Add update and delete public group RPC commands --- src/bdap/rpcdomainentry.cpp | 81 ++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 8a3468434c..5cbaf9beac 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -265,12 +265,8 @@ UniValue getdomaingroupinfo(const JSONRPCRequest& request) return oDomainEntryInfo; } -UniValue updatedomainentry(const JSONRPCRequest& request) { - if (request.params.size() < 2 || request.params.size() > 3) - { - throw std::runtime_error("updatedomainentry \nUpdate an existing public name blockchain directory entry.\n"); - } - +static UniValue UpdateDomainEntry(const JSONRPCRequest& request, BDAP::ObjectType bdapType) +{ EnsureWalletIsUnlocked(); // Format object and domain names to lower case. @@ -279,7 +275,12 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { CDomainEntry txPreviousEntry; txPreviousEntry.DomainComponent = vchDefaultDomainName; - txPreviousEntry.OrganizationalUnit = vchDefaultUserOU; + if (bdapType == BDAP::ObjectType::USER_ACCOUNT) { + txPreviousEntry.OrganizationalUnit = vchDefaultUserOU; + } + else if (bdapType == BDAP::ObjectType::GROUP) { + txPreviousEntry.OrganizationalUnit = vchDefaultGroupOU; + } txPreviousEntry.ObjectID = vchObjectID; // Check if name already exists @@ -294,7 +295,7 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { CDomainEntry txUpdatedEntry = txPreviousEntry; CharString vchCommonName = vchFromValue(request.params[1]); txUpdatedEntry.CommonName = vchCommonName; - txUpdatedEntry.nObjectType = GetObjectTypeInt(BDAP::ObjectType::USER_ACCOUNT); + txUpdatedEntry.nObjectType = GetObjectTypeInt(bdapType); uint64_t nDays = 1461; //default to 4 years. if (request.params.size() >= 3) { @@ -353,12 +354,29 @@ UniValue updatedomainentry(const JSONRPCRequest& request) { return oName; } -UniValue deletedomainentry(const JSONRPCRequest& request) { - if (request.params.size() != 1) +UniValue updatedomainuser(const JSONRPCRequest& request) { + if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("deletedomainentry \nDelete an existing public name blockchain directory entry.\n"); + throw std::runtime_error("updatedomainuser \nUpdate an existing public name blockchain directory entry.\n"); } + BDAP::ObjectType bdapType = BDAP::ObjectType::USER_ACCOUNT; + return UpdateDomainEntry(request, bdapType); +} + +UniValue updatedomaingroup(const JSONRPCRequest& request) { + if (request.params.size() < 2 || request.params.size() > 3) + { + throw std::runtime_error("updatedomaingroup \nUpdate an existing public name blockchain directory entry.\n"); + } + + BDAP::ObjectType bdapType = BDAP::ObjectType::GROUP; + return UpdateDomainEntry(request, bdapType); +} + +static UniValue DeleteDomainEntry(const JSONRPCRequest& request, BDAP::ObjectType bdapType) +{ + EnsureWalletIsUnlocked(); // Format object and domain names to lower case. @@ -367,22 +385,27 @@ UniValue deletedomainentry(const JSONRPCRequest& request) { CDomainEntry txSearchEntry; txSearchEntry.DomainComponent = vchDefaultDomainName; - txSearchEntry.OrganizationalUnit = vchDefaultUserOU; + if (bdapType == BDAP::ObjectType::USER_ACCOUNT) { + txSearchEntry.OrganizationalUnit = vchDefaultUserOU; + } + else if (bdapType == BDAP::ObjectType::GROUP) { + txSearchEntry.OrganizationalUnit = vchDefaultGroupOU; + } txSearchEntry.ObjectID = vchObjectID; CDomainEntry txDeletedEntry = txSearchEntry; // Check if name already exists if (!GetDomainEntry(txSearchEntry.vchFullObjectPath(), txSearchEntry)) - throw std::runtime_error("BDAP_DELETE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txSearchEntry.GetFullObjectPath() + _(" does not exists. Can not delete.")); + throw std::runtime_error("BDAP_DELETE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3700 - " + txSearchEntry.GetFullObjectPath() + _(" does not exists. Can not delete.")); int nIn = GetDomainEntryOperationOutIndex(txSearchEntry.nHeight, txSearchEntry.txHash); COutPoint outpoint = COutPoint(txSearchEntry.txHash, nIn); if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) - throw std::runtime_error("BDAP_DELETE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txSearchEntry.GetFullObjectPath() + _(" entry. Can not delete.")); + throw std::runtime_error("BDAP_DELETE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txSearchEntry.GetFullObjectPath() + _(" entry. Can not delete.")); txDeletedEntry.WalletAddress = txSearchEntry.WalletAddress; txDeletedEntry.CommonName = txSearchEntry.CommonName; - txDeletedEntry.nObjectType = GetObjectTypeInt(BDAP::ObjectType::USER_ACCOUNT); + txDeletedEntry.nObjectType = GetObjectTypeInt(bdapType); CharString data; txDeletedEntry.Serialize(data); @@ -412,7 +435,7 @@ UniValue deletedomainentry(const JSONRPCRequest& request) { UniValue oName(UniValue::VOBJ); if(!BuildBDAPJson(txDeletedEntry, oName)) - throw std::runtime_error("BDAP_DELETE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3703 - " + _("Failed to read from BDAP JSON object")); + throw std::runtime_error("BDAP_DELETE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3703 - " + _("Failed to read from BDAP JSON object")); if (fPrintDebug) { // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class @@ -429,6 +452,26 @@ UniValue deletedomainentry(const JSONRPCRequest& request) { return oName; } +UniValue deletedomainuser(const JSONRPCRequest& request) { + if (request.params.size() != 1) + { + throw std::runtime_error("deletedomainuser \nDelete an existing public name blockchain directory entry.\n"); + } + + BDAP::ObjectType bdapType = BDAP::ObjectType::USER_ACCOUNT; + return DeleteDomainEntry(request, bdapType); +} + +UniValue deletedomaingroup(const JSONRPCRequest& request) { + if (request.params.size() != 1) + { + throw std::runtime_error("deletedomaingroup \nDelete an existing public name blockchain directory entry.\n"); + } + + BDAP::ObjectType bdapType = BDAP::ObjectType::GROUP; + return DeleteDomainEntry(request, bdapType); +} + UniValue makekeypair(const JSONRPCRequest& request) { if (request.params.size() > 1) @@ -483,8 +526,10 @@ static const CRPCCommand commands[] = { "bdap", "getdomainusers", &getdomainusers, true }, { "bdap", "getdomaingroups", &getdomaingroups, true }, { "bdap", "getdomainuserinfo", &getdomainuserinfo, true }, - { "bdap", "updatedomainentry", &updatedomainentry, true }, - { "bdap", "deletedomainentry", &deletedomainentry, true }, + { "bdap", "updatedomainuser", &updatedomainuser, true }, + { "bdap", "updatedomaingroup", &updatedomaingroup, true }, + { "bdap", "deletedomainuser", &deletedomainuser, true }, + { "bdap", "deletedomaingroup", &deletedomaingroup, true }, { "bdap", "adddomaingroup", &adddomaingroup, true }, { "bdap", "getdomaingroupinfo", &getdomaingroupinfo, true }, #endif //ENABLE_WALLET From d2b3c1dc18ec28a2b46224e01a0a3f865d6bb408 Mon Sep 17 00:00:00 2001 From: Jacob Bryan Date: Fri, 24 Aug 2018 11:08:10 -0500 Subject: [PATCH 0194/1653] Corrected the documentation for Fluid RPC Calls --- src/rpcfluid.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rpcfluid.cpp b/src/rpcfluid.cpp index 196092c8f7..7ee822a96a 100644 --- a/src/rpcfluid.cpp +++ b/src/rpcfluid.cpp @@ -79,8 +79,8 @@ UniValue getrawpubkey(const UniValue& params, bool fHelp) "\nArguments:\n" "1. \"address\" (string, required) The Dynamic Address from which the pubkey is to recovered.\n" "\nExamples:\n" - + HelpExampleCli("burndynamic", "123.456") - + HelpExampleRpc("burndynamic", "123.456") + + HelpExampleCli("getrawpubkey", "D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf") + + HelpExampleRpc("getrawpubkey", "D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf") ); CDynamicAddress address(params[0].get_str()); @@ -112,8 +112,8 @@ UniValue burndynamic(const UniValue& params, bool fHelp) "\nArguments:\n" "1. \"account\" (numeric or string, required) The amount of coins to be minted.\n" "\nExamples:\n" - + HelpExampleCli("burndynamic", "123.456") - + HelpExampleRpc("burndynamic", "123.456") + + HelpExampleCli("burndynamic", "\"123.456\" \"D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf\"") + + HelpExampleRpc("burndynamic", "\"123.456\" \"D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf\"") ); EnsureWalletIsUnlocked(); @@ -230,8 +230,8 @@ UniValue verifyquorum(const UniValue& params, bool fHelp) "\nArguments:\n" "1. \"tokenkey\" (string, required) The token which has to be initially signed\n" "\nExamples:\n" - + HelpExampleCli("consenttoken", "\"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") - + HelpExampleRpc("consenttoken", "\"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") + + HelpExampleCli("verifyquorum", "\"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") + + HelpExampleRpc("verifyquorum", "\"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") ); if (!fluid.CheckNonScriptQuorum(params[0].get_str(), message, false)) From a0b1dd8cfef8a7ebbd4f0d3766c4a8471fa6ee92 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 24 Aug 2018 13:06:34 -0500 Subject: [PATCH 0195/1653] [BDAP] Refactor general functions and fix get op type --- src/bdap/auditdata.cpp | 2 +- src/bdap/domainentry.cpp | 67 +++++++++++++++++------------------ src/bdap/domainentry.h | 32 ++++++++--------- src/bdap/domainentrydb.cpp | 16 ++++----- src/bdap/entrycertificate.cpp | 2 +- src/bdap/entrychannel.cpp | 2 +- src/bdap/entrycheckpoints.cpp | 2 +- src/bdap/entrylink.cpp | 2 +- src/bdap/identity.cpp | 4 +-- src/bdap/rpcdomainentry.cpp | 4 +-- src/qt/transactionrecord.cpp | 6 ++-- src/validation.cpp | 12 +++---- src/wallet/wallet.cpp | 2 +- 13 files changed, 76 insertions(+), 77 deletions(-) diff --git a/src/bdap/auditdata.cpp b/src/bdap/auditdata.cpp index 5b7cc1b055..571d083312 100644 --- a/src/bdap/auditdata.cpp +++ b/src/bdap/auditdata.cpp @@ -57,7 +57,7 @@ bool CAuditData::UnserializeFromTx(const CTransaction& tx) std::vector vchData; std::vector vchHash; int nOut; - if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { SetNull(); return false; diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 881d640fe8..598dd272cf 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -66,7 +66,7 @@ namespace BDAP { } } -std::string DomainEntryFromOp(const int op) +std::string BDAPFromOp(const int op) { switch (op) { case OP_BDAP_NEW: @@ -100,7 +100,7 @@ std::string DomainEntryFromOp(const int op) } } -bool IsDomainEntryDataOutput(const CTxOut& out) { +bool IsBDAPDataOutput(const CTxOut& out) { txnouttype whichType; if (!IsStandard(out.scriptPubKey, whichType)) return false; @@ -109,7 +109,7 @@ bool IsDomainEntryDataOutput(const CTxOut& out) { return false; } -bool GetDomainEntryTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams) +bool GetBDAPTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams) { if(nHeight < 0 || nHeight > chainActive.Height()) return false; @@ -151,15 +151,15 @@ std::vector vchFromString(const std::string& str) return std::vector(str.begin(), str.end()); } -int GetDomainEntryDataOutput(const CTransaction& tx) { +int GetBDAPDataOutput(const CTransaction& tx) { for(unsigned int i = 0; i& vchData, std::vector& vchHash) +bool GetBDAPData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash) { CScript::const_iterator pc = scriptPubKey.begin(); opcodetype opcode; @@ -177,21 +177,21 @@ bool GetDomainEntryData(const CScript& scriptPubKey, std::vector& return true; } -bool GetDomainEntryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut) +bool GetBDAPData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut) { - nOut = GetDomainEntryDataOutput(tx); + nOut = GetBDAPDataOutput(tx); if(nOut == -1) return false; const CScript &scriptPubKey = tx.vout[nOut].scriptPubKey; - return GetDomainEntryData(scriptPubKey, vchData, vchHash); + return GetBDAPData(scriptPubKey, vchData, vchHash); } bool CDomainEntry::UnserializeFromTx(const CTransaction& tx) { std::vector vchData; std::vector vchHash; int nOut; - if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { SetNull(); return false; @@ -385,7 +385,7 @@ bool CDomainEntry::CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& e for (const CTxMemPoolEntry& e : pool.mapTx) { const CTransaction& tx = e.GetTx(); for (const CTxOut& txOut : tx.vout) { - if (IsDomainEntryDataOutput(txOut)) { + if (IsBDAPDataOutput(txOut)) { CDomainEntry domainEntry(tx); if (this->GetFullObjectPath() == domainEntry.GetFullObjectPath()) { errorMessage = "CheckIfExistsInMemPool: A BDAP domain entry transaction for " + GetFullObjectPath() + " is already in the memory pool!"; @@ -400,7 +400,7 @@ bool CDomainEntry::CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& e /** Checks if the domain entry transaction uses the entry's UTXO */ bool CDomainEntry::TxUsesPreviousUTXO(const CTransaction& tx) { - int nIn = GetDomainEntryOperationOutIndex(tx); + int nIn = GetBDAPOperationOutIndex(tx); COutPoint entryOutpoint = COutPoint(txHash, nIn); for (const CTxIn& txIn : tx.vin) { if (txIn.prevout == entryOutpoint) @@ -513,7 +513,7 @@ CAmount GetBDAPFee(const CScript& scriptPubKey) return recp.nAmount; } -bool DecodeDomainEntryTx(const CTransaction& tx, int& op, std::vector >& vvch) +bool DecodeBDAPTx(const CTransaction& tx, int& op, std::vector >& vvch) { bool found = false; @@ -532,7 +532,7 @@ bool DecodeDomainEntryTx(const CTransaction& tx, int& op, std::vector >& vvch) +bool FindBDAPInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch) { for (unsigned int i = 0; i < tx.vin.size(); i++) { const Coin& prevCoins = inputs.AccessCoin(tx.vin[i].prevout); @@ -548,9 +548,8 @@ bool FindDomainEntryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, return false; } -int GetDomainEntryOpType(const CScript& script) +int GetBDAPOpType(const CScript& script) { - std::string ret; CScript::const_iterator it = script.begin(); opcodetype op1 = OP_INVALIDOPCODE; opcodetype op2 = OP_INVALIDOPCODE; @@ -574,7 +573,7 @@ int GetDomainEntryOpType(const CScript& script) { if (script.GetOp2(it, op2, &vch)) { - if (op2 - OP_1NEGATE - 1 > OP_BDAP && op2 - OP_1NEGATE - 1 <= OP_BDAP_REVOKE) + if (op2 - OP_1NEGATE - 1 > OP_BDAP && op2 - OP_1NEGATE - 1 <= OP_BDAP_CHANNEL_CHECKPOINT) { return (int)op2 - OP_1NEGATE - 1; } @@ -588,71 +587,71 @@ int GetDomainEntryOpType(const CScript& script) return (int)op2; } -std::string GetDomainEntryOpTypeString(const CScript& script) +std::string GetBDAPOpTypeString(const CScript& script) { - return DomainEntryFromOp(GetDomainEntryOpType(script)); + return BDAPFromOp(GetBDAPOpType(script)); } -bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp, vchCharString& vvchOpParameters, int& op) +bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp, vchCharString& vvchOpParameters, int& op) { for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut& out = tx.vout[i]; if (DecodeBDAPScript(out.scriptPubKey, op, vvchOpParameters)) { - scriptDomainEntryOp = out.scriptPubKey; + scriptBDAPOp = out.scriptPubKey; return true; } } return false; } -bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp) +bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp) { int op; vchCharString vvchOpParameters; - return GetDomainEntryOpScript(tx, scriptDomainEntryOp, vvchOpParameters, op); + return GetBDAPOpScript(tx, scriptBDAPOp, vvchOpParameters, op); } -bool GetDomainEntryDataScript(const CTransaction& tx, CScript& scriptDomainEntryData) +bool GetBDAPDataScript(const CTransaction& tx, CScript& scriptBDAPData) { for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut& out = tx.vout[i]; if (out.scriptPubKey.IsUnspendable()) { - scriptDomainEntryData = out.scriptPubKey; + scriptBDAPData = out.scriptPubKey; return true; } } return false; } -bool IsDomainEntryOperationOutput(const CTxOut& out) +bool IsBDAPOperationOutput(const CTxOut& out) { - if (GetDomainEntryOpType(out.scriptPubKey) > 0) + if (GetBDAPOpType(out.scriptPubKey) > 0) return true; return false; } -int GetDomainEntryOperationOutIndex(const CTransaction& tx) +int GetBDAPOperationOutIndex(const CTransaction& tx) { for(unsigned int i = 0; i& vecSend, CDomainEntry& entry, std::string& strOpType) @@ -662,14 +661,14 @@ bool GetDomainEntryFromRecipient(const std::vector& vecSend, CDomain if (bdapScript.IsUnspendable()) { std::vector vchData; std::vector vchHash; - if (!GetDomainEntryData(bdapScript, vchData, vchHash)) + if (!GetBDAPData(bdapScript, vchData, vchHash)) { return false; } entry.UnserializeFromData(vchData, vchHash); } else { - strOpType = GetDomainEntryOpTypeString(bdapScript); + strOpType = GetBDAPOpTypeString(bdapScript); } } if (!entry.IsNull() && strOpType.size() > 0) { diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index b037d2699a..2d601b379a 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -167,11 +167,11 @@ class CDomainEntry { std::string ObjectTypeString() const { return BDAP::GetObjectTypeString(nObjectType); }; }; -std::string DomainEntryFromOp(const int op); -bool IsDomainEntryDataOutput(const CTxOut& out); -int GetDomainEntryDataOutput(const CTransaction& tx); -bool GetDomainEntryData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); -bool GetDomainEntryData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash); +std::string BDAPFromOp(const int op); +bool IsBDAPDataOutput(const CTxOut& out); +int GetBDAPDataOutput(const CTransaction& tx); +bool GetBDAPData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); +bool GetBDAPData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash); bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged = false); std::string stringFromVch(const CharString& vch); @@ -181,17 +181,17 @@ void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); void ToLowerCase(CharString& vchValue); void ToLowerCase(std::string& strValue); CAmount GetBDAPFee(const CScript& scriptPubKey); -bool DecodeDomainEntryTx(const CTransaction& tx, int& op, std::vector >& vvch); -bool FindDomainEntryInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch); -int GetDomainEntryOpType(const CScript& script); -std::string GetDomainEntryOpTypeString(const CScript& script); -bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp, vchCharString& vvchOpParameters, int& op); -bool GetDomainEntryOpScript(const CTransaction& tx, CScript& scriptDomainEntryOp); -bool GetDomainEntryDataScript(const CTransaction& tx, CScript& scriptDomainEntryData); -bool IsDomainEntryOperationOutput(const CTxOut& out); -int GetDomainEntryOperationOutIndex(const CTransaction& tx); -int GetDomainEntryOperationOutIndex(int nHeight, const uint256& txHash); -bool GetDomainEntryTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams); +bool DecodeBDAPTx(const CTransaction& tx, int& op, std::vector >& vvch); +bool FindBDAPInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch); +int GetBDAPOpType(const CScript& script); +std::string GetBDAPOpTypeString(const CScript& script); +bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp, vchCharString& vvchOpParameters, int& op); +bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp); +bool GetBDAPDataScript(const CTransaction& tx, CScript& scriptBDAPData); +bool IsBDAPOperationOutput(const CTxOut& out); +int GetBDAPOperationOutIndex(const CTransaction& tx); +int GetBDAPOperationOutIndex(int nHeight, const uint256& txHash); +bool GetBDAPTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams); bool GetDomainEntryFromRecipient(const std::vector& vecSend, CDomainEntry& entry, std::string& strOpType); CDynamicAddress GetScriptAddress(const CScript& pubScript); #endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index 362651ed2b..1a693af315 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -43,7 +43,7 @@ void CDomainEntryDB::AddDomainEntryIndex(const CDomainEntry& entry, const int op { UniValue oName(UniValue::VOBJ); if (BuildBDAPJson(entry, oName)) { - CharString vchOperationType = vchFromString(DomainEntryFromOp(op)); + CharString vchOperationType = vchFromString(BDAPFromOp(op)); GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), reinterpret_cast(vchOperationType.data())); WriteDomainEntryIndexHistory(entry, op); } @@ -127,7 +127,7 @@ void CDomainEntryDB::WriteDomainEntryIndexHistory(const CDomainEntry& entry, con if (IsArgSet("-zmqpubbdaphistory")) { UniValue oName(UniValue::VOBJ); BuildBDAPJson(entry, oName); - oName.push_back(Pair("op", DomainEntryFromOp(op))); + oName.push_back(Pair("op", BDAPFromOp(op))); GetMainSignals().NotifyBDAPUpdate(oName.write().c_str(), "bdap_history"); } } @@ -415,7 +415,7 @@ bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& CDynamicAddress txAddress = GetScriptAddress(scriptOp); // Get previous wallet address used for BDAP tx CScript prevScriptPubKey; - GetDomainEntryOpScript(prevTx, prevScriptPubKey); + GetBDAPOpScript(prevTx, prevScriptPubKey); CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); if (txAddress.ToString() != prevAddress.ToString()) { @@ -469,7 +469,7 @@ bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& CDynamicAddress txAddress = GetScriptAddress(scriptOp); // Get previous wallet address used for BDAP tx CScript prevScriptPubKey; - GetDomainEntryOpScript(prevTx, prevScriptPubKey); + GetBDAPOpScript(prevTx, prevScriptPubKey); CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); if (txAddress.ToString() != prevAddress.ToString()) { @@ -535,16 +535,16 @@ bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& } //if (fDebug && !bSanityCheck) - LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, DomainEntryFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); CScript scriptOp; vchCharString vvchOpParameters; - if (!GetDomainEntryOpScript(tx, scriptOp, vvchOpParameters, op)) + if (!GetBDAPOpScript(tx, scriptOp, vvchOpParameters, op)) { errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3600 - " + _("Transaction does not contain BDAP operation script!"); return error(errorMessage.c_str()); } - const std::string strOperationType = GetDomainEntryOpTypeString(scriptOp); + const std::string strOperationType = GetBDAPOpTypeString(scriptOp); if (fDebug) LogPrintf("CheckDomainEntryTxInputs, strOperationType= %s \n", strOperationType); @@ -554,7 +554,7 @@ bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& std::vector vchHash; int nDataOut; - bool bData = GetDomainEntryData(tx, vchData, vchHash, nDataOut); + bool bData = GetBDAPData(tx, vchData, vchHash, nDataOut); if(bData && !entry.UnserializeFromData(vchData, vchHash)) { errorMessage = "BDAP_CONSENSUS_ERROR: ERRCODE: 3601 - " + _("UnserializeFromData data in tx failed!"); diff --git a/src/bdap/entrycertificate.cpp b/src/bdap/entrycertificate.cpp index bf511b6897..34721a3f65 100644 --- a/src/bdap/entrycertificate.cpp +++ b/src/bdap/entrycertificate.cpp @@ -43,7 +43,7 @@ bool CEntryCertificate::UnserializeFromTx(const CTransaction& tx) std::vector vchData; std::vector vchHash; int nOut; - if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { SetNull(); return false; diff --git a/src/bdap/entrychannel.cpp b/src/bdap/entrychannel.cpp index c71ea2d009..092f6f474a 100644 --- a/src/bdap/entrychannel.cpp +++ b/src/bdap/entrychannel.cpp @@ -43,7 +43,7 @@ bool CEntryChannel::UnserializeFromTx(const CTransaction& tx) std::vector vchData; std::vector vchHash; int nOut; - if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { SetNull(); return false; diff --git a/src/bdap/entrycheckpoints.cpp b/src/bdap/entrycheckpoints.cpp index 8a92fed8ed..206d26db6f 100644 --- a/src/bdap/entrycheckpoints.cpp +++ b/src/bdap/entrycheckpoints.cpp @@ -43,7 +43,7 @@ bool CEntryCheckpoints::UnserializeFromTx(const CTransaction& tx) std::vector vchData; std::vector vchHash; int nOut; - if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { SetNull(); return false; diff --git a/src/bdap/entrylink.cpp b/src/bdap/entrylink.cpp index f6064f1da2..256e6c9ada 100644 --- a/src/bdap/entrylink.cpp +++ b/src/bdap/entrylink.cpp @@ -44,7 +44,7 @@ bool CEntryLink::UnserializeFromTx(const CTransaction& tx) std::vector vchData; std::vector vchHash; int nOut; - if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { SetNull(); return false; diff --git a/src/bdap/identity.cpp b/src/bdap/identity.cpp index 480f249ea4..fd4e5b8975 100644 --- a/src/bdap/identity.cpp +++ b/src/bdap/identity.cpp @@ -41,7 +41,7 @@ bool CIdentity::UnserializeFromTx(const CTransaction& tx) std::vector vchData; std::vector vchHash; int nOut; - if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { SetNull(); return false; @@ -87,7 +87,7 @@ bool CIdentityVerification::UnserializeFromTx(const CTransaction& tx) std::vector vchData; std::vector vchHash; int nOut; - if(!GetDomainEntryData(tx, vchData, vchHash, nOut)) + if(!GetBDAPData(tx, vchData, vchHash, nOut)) { SetNull(); return false; diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 5cbaf9beac..b7a97b8366 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -287,7 +287,7 @@ static UniValue UpdateDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp if (!GetDomainEntry(txPreviousEntry.vchFullObjectPath(), txPreviousEntry)) throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txPreviousEntry.GetFullObjectPath() + _(" does not exists. Can not update.")); - int nIn = GetDomainEntryOperationOutIndex(txPreviousEntry.nHeight, txPreviousEntry.txHash); + int nIn = GetBDAPOperationOutIndex(txPreviousEntry.nHeight, txPreviousEntry.txHash); COutPoint outpoint = COutPoint(txPreviousEntry.txHash, nIn); if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txPreviousEntry.GetFullObjectPath() + _(" entry. Can not update.")); @@ -398,7 +398,7 @@ static UniValue DeleteDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp if (!GetDomainEntry(txSearchEntry.vchFullObjectPath(), txSearchEntry)) throw std::runtime_error("BDAP_DELETE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3700 - " + txSearchEntry.GetFullObjectPath() + _(" does not exists. Can not delete.")); - int nIn = GetDomainEntryOperationOutIndex(txSearchEntry.nHeight, txSearchEntry.txHash); + int nIn = GetBDAPOperationOutIndex(txSearchEntry.nHeight, txSearchEntry.txHash); COutPoint outpoint = COutPoint(txSearchEntry.txHash, nIn); if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) throw std::runtime_error("BDAP_DELETE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txSearchEntry.GetFullObjectPath() + _(" entry. Can not delete.")); diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index fc3e17a926..c3c7de0225 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -80,7 +80,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // Generated sub.type = TransactionRecord::Generated; } - if (IsDomainEntryDataOutput(txout)) + if (IsBDAPDataOutput(txout)) { // BDAP type sub.type = TransactionRecord::BDAP; @@ -155,7 +155,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * { const CTxOut& txout = wtx.vout[nOut]; sub.idx = parts.size(); - if (IsDomainEntryDataOutput(txout)) + if (IsBDAPDataOutput(txout)) { // BDAP type sub.type = TransactionRecord::BDAP; @@ -213,7 +213,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * sub.type = TransactionRecord::PrivateSend; } - if(IsDomainEntryDataOutput(txout)) + if(IsBDAPDataOutput(txout)) { sub.type = TransactionRecord::BDAP; } diff --git a/src/validation.cpp b/src/validation.cpp index 6f9f8435b0..30ece322fb 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -610,7 +610,7 @@ bool ValidateBDAPInputs(const CTransaction& tx, CValidationState& state, const C bool bValid = false; if (tx.nVersion == BDAP_TX_VERSION) { - if (DecodeDomainEntryTx(tx, op, vvchBDAPArgs)) + if (DecodeBDAPTx(tx, op, vvchBDAPArgs)) { std::string errorMessage; bValid = CheckDomainEntryTxInputs(inputs, tx, op, vvchBDAPArgs, fJustCheck, nHeight, errorMessage, bSanity); @@ -670,11 +670,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C int op; CScript scriptOp; vchCharString vvchOpParameters; - if (!GetDomainEntryOpScript(tx, scriptOp, vvchOpParameters, op)) + if (!GetBDAPOpScript(tx, scriptOp, vvchOpParameters, op)) { return state.Invalid(false, REJECT_INVALID, "bdap-txn-get-op-failed" + strErrorMessage); } - const std::string strOperationType = GetDomainEntryOpTypeString(scriptOp); + const std::string strOperationType = GetBDAPOpTypeString(scriptOp); if (strOperationType == "bdap_update" || strOperationType == "bdap_delete") { CDomainEntry entry; CDomainEntry prevEntry; @@ -682,7 +682,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C std::vector vchHash; int nDataOut; - bool bData = GetDomainEntryData(tx, vchData, vchHash, nDataOut); + bool bData = GetBDAPData(tx, vchData, vchHash, nDataOut); if(bData && !entry.UnserializeFromData(vchData, vchHash)) { return state.Invalid(false, REJECT_INVALID, "bdap-txn-get-data-failed" + strErrorMessage); @@ -698,11 +698,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } // Get current wallet address used for BDAP tx CScript scriptPubKey; - GetDomainEntryOpScript(tx, scriptPubKey); + GetBDAPOpScript(tx, scriptPubKey); CDynamicAddress txAddress = GetScriptAddress(scriptPubKey); // Get previous wallet address used for BDAP tx CScript prevScriptPubKey; - GetDomainEntryOpScript(prevTx, prevScriptPubKey); + GetBDAPOpScript(prevTx, prevScriptPubKey); CDynamicAddress prevAddress = GetScriptAddress(prevScriptPubKey); if (txAddress.ToString() != prevAddress.ToString()) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9571242364..149754ce96 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3398,7 +3398,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT return false; } CScript prevScriptPubKey; - GetDomainEntryOpScript(prevTx, prevScriptPubKey); + GetBDAPOpScript(prevTx, prevScriptPubKey); GetBDAPCoins(vAvailableCoins, prevScriptPubKey); } } From 54451c7b92456b9d276b436680d78f962a5a6cc8 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 24 Aug 2018 18:08:25 -0500 Subject: [PATCH 0196/1653] [BDAP] Improve transaction display in Qt UI --- src/bdap/domainentry.cpp | 33 ++++++++++++++++-- src/bdap/domainentry.h | 5 +++ src/qt/transactionrecord.cpp | 58 ++++++++++++++++++++++---------- src/qt/transactionrecord.h | 9 ++++- src/qt/transactiontablemodel.cpp | 48 ++++++++++++++++++++++---- src/qt/transactionview.cpp | 9 ++++- 6 files changed, 135 insertions(+), 27 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 598dd272cf..03b0f126e9 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -64,6 +64,11 @@ namespace BDAP { { return (unsigned int)ObjectType; } + + BDAP::ObjectType GetObjectTypeEnum(unsigned int nObjectType) + { + return (BDAP::ObjectType)nObjectType; + } } std::string BDAPFromOp(const int op) @@ -101,7 +106,7 @@ std::string BDAPFromOp(const int op) } bool IsBDAPDataOutput(const CTxOut& out) { - txnouttype whichType; + txnouttype whichType; if (!IsStandard(out.scriptPubKey, whichType)) return false; if (whichType == TX_NULL_DATA) @@ -187,6 +192,11 @@ bool GetBDAPData(const CTransaction& tx, std::vector& vchData, st return GetBDAPData(scriptPubKey, vchData, vchHash); } +bool GetBDAPData(const CTxOut& out, std::vector& vchData, std::vector& vchHash) +{ + return GetBDAPData(out.scriptPubKey, vchData, vchHash); +} + bool CDomainEntry::UnserializeFromTx(const CTransaction& tx) { std::vector vchData; std::vector vchHash; @@ -587,6 +597,11 @@ int GetBDAPOpType(const CScript& script) return (int)op2; } +int GetBDAPOpType(const CTxOut& out) +{ + return GetBDAPOpType(out.scriptPubKey); +} + std::string GetBDAPOpTypeString(const CScript& script) { return BDAPFromOp(GetBDAPOpType(script)); @@ -627,13 +642,27 @@ bool GetBDAPDataScript(const CTransaction& tx, CScript& scriptBDAPData) return false; } -bool IsBDAPOperationOutput(const CTxOut& out) +bool IsBDAPOperationOutput(const CTxOut& out) { if (GetBDAPOpType(out.scriptPubKey) > 0) return true; return false; } +int GetBDAPOpCodeFromOutput(const CTxOut& out) +{ + if (!IsBDAPOperationOutput(out)) { + return 0; + } + + return GetBDAPOpType(out.scriptPubKey); +} + +std::string GetBDAPOpStringFromOutput(const CTxOut& out) +{ + return GetBDAPOpTypeString(out.scriptPubKey); +} + int GetBDAPOperationOutIndex(const CTransaction& tx) { for(unsigned int i = 0; i& vchData, std::vector& vchHash, int& nOut); bool GetBDAPData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash); +bool GetBDAPData(const CTxOut& out, std::vector& vchData, std::vector& vchHash); bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged = false); std::string stringFromVch(const CharString& vch); @@ -184,6 +186,7 @@ CAmount GetBDAPFee(const CScript& scriptPubKey); bool DecodeBDAPTx(const CTransaction& tx, int& op, std::vector >& vvch); bool FindBDAPInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch); int GetBDAPOpType(const CScript& script); +int GetBDAPOpType(const CTxOut& out); std::string GetBDAPOpTypeString(const CScript& script); bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp, vchCharString& vvchOpParameters, int& op); bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp); @@ -194,4 +197,6 @@ int GetBDAPOperationOutIndex(int nHeight, const uint256& txHash); bool GetBDAPTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams); bool GetDomainEntryFromRecipient(const std::vector& vecSend, CDomainEntry& entry, std::string& strOpType); CDynamicAddress GetScriptAddress(const CScript& pubScript); +int GetBDAPOpCodeFromOutput(const CTxOut& out); +std::string GetBDAPOpStringFromOutput(const CTxOut& out); #endif // DYNAMIC_BDAP_DOMAINENTRY_H \ No newline at end of file diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index c3c7de0225..910d21ceb0 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -9,6 +9,7 @@ #include "base58.h" #include "consensus/consensus.h" +#include "bdap/bdap.h" #include "bdap/domainentry.h" #include "instantsend.h" #include "validation.h" @@ -80,11 +81,6 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // Generated sub.type = TransactionRecord::Generated; } - if (IsBDAPDataOutput(txout)) - { - // BDAP type - sub.type = TransactionRecord::BDAP; - } parts.append(sub); } @@ -155,11 +151,6 @@ QList TransactionRecord::decomposeTransaction(const CWallet * { const CTxOut& txout = wtx.vout[nOut]; sub.idx = parts.size(); - if (IsBDAPDataOutput(txout)) - { - // BDAP type - sub.type = TransactionRecord::BDAP; - } if(CPrivateSend::IsCollateralAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendMakeCollaterals; if(CPrivateSend::IsDenominatedAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendCreateDenominations; if(nDebit - wtx.GetValueOut() == CPrivateSend::GetCollateralAmount()) sub.type = TransactionRecord::PrivateSendCollateralPayment; @@ -179,14 +170,21 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // Debit // CAmount nTxFee = nDebit - wtx.GetValueOut(); - + CDomainEntry entry; + std::string strOpType; for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); sub.involvesWatchAddress = involvesWatchAddress; - + + if (GetBDAPOpType(txout) > 0) + { + // BDAP type + strOpType = BDAPFromOp(GetBDAPOpCodeFromOutput(txout)); + continue; + } if(wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change @@ -208,14 +206,40 @@ QList TransactionRecord::decomposeTransaction(const CWallet * sub.address = mapValue["to"]; } - if(mapValue["PS"] == "1") - { - sub.type = TransactionRecord::PrivateSend; + if (IsBDAPDataOutput(txout)) { + std::vector vchData; + std::vector vchHash; + GetBDAPData(txout, vchData, vchHash); + entry.UnserializeFromData(vchData, vchHash); + if (strOpType == "bdap_new" && entry.ObjectTypeString() == "User Entry"){ + sub.type = TransactionRecord::NewDomainUser; + } + else if (strOpType == "bdap_update" && entry.ObjectTypeString() == "User Entry") { + sub.type = TransactionRecord::UpdateDomainUser; + } + else if (strOpType == "bdap_delete" && entry.ObjectTypeString() == "User Entry") { + sub.type = TransactionRecord::DeleteDomainUser; + } + else if (strOpType == "bdap_revoke" && entry.ObjectTypeString() == "User Entry") { + sub.type = TransactionRecord::RevokeDomainUser; + } + else if (strOpType == "bdap_new" && entry.ObjectTypeString() == "Group Entry"){ + sub.type = TransactionRecord::NewDomainGroup; + } + else if (strOpType == "bdap_update" && entry.ObjectTypeString() == "Group Entry") { + sub.type = TransactionRecord::UpdateDomainGroup; + } + else if (strOpType == "bdap_delete" && entry.ObjectTypeString() == "Group Entry") { + sub.type = TransactionRecord::DeleteDomainGroup; + } + else if (strOpType == "bdap_revoke" && entry.ObjectTypeString() == "Group Entry") { + sub.type = TransactionRecord::RevokeDomainGroup; + } } - if(IsBDAPDataOutput(txout)) + if(mapValue["PS"] == "1") { - sub.type = TransactionRecord::BDAP; + sub.type = TransactionRecord::PrivateSend; } CAmount nValue = txout.nValue; diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index d7b0bca716..7ed0d84823 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -84,7 +84,14 @@ class TransactionRecord RecvWithAddress, RecvFromOther, SendToSelf, - BDAP, + NewDomainUser, + UpdateDomainUser, + DeleteDomainUser, + RevokeDomainUser, + NewDomainGroup, + UpdateDomainGroup, + DeleteDomainGroup, + RevokeDomainGroup, RecvWithPrivateSend, PrivateSendDenominate, PrivateSendCollateralPayment, diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 273f6bf6e0..a9a9cff559 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -384,8 +384,16 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const return tr("Payment to yourself"); case TransactionRecord::Generated: return tr("Mined"); - case TransactionRecord::BDAP: - return tr("BDAP"); + case TransactionRecord::NewDomainUser: + case TransactionRecord::UpdateDomainUser: + case TransactionRecord::DeleteDomainUser: + case TransactionRecord::RevokeDomainUser: + return tr("BDAP User Entry"); + case TransactionRecord::NewDomainGroup: + case TransactionRecord::UpdateDomainGroup: + case TransactionRecord::DeleteDomainGroup: + case TransactionRecord::RevokeDomainGroup: + return tr("BDAP Group Entry"); case TransactionRecord::PrivateSendDenominate: return tr("PrivateSend Denominate"); case TransactionRecord::PrivateSendCollateralPayment: @@ -416,7 +424,14 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx case TransactionRecord::SendToAddress: case TransactionRecord::SendToOther: return QIcon(":/icons/" + theme + "/tx_output"); - case TransactionRecord::BDAP: + case TransactionRecord::NewDomainUser: + case TransactionRecord::UpdateDomainUser: + case TransactionRecord::DeleteDomainUser: + case TransactionRecord::RevokeDomainUser: + case TransactionRecord::NewDomainGroup: + case TransactionRecord::UpdateDomainGroup: + case TransactionRecord::DeleteDomainGroup: + case TransactionRecord::RevokeDomainGroup: return QIcon(":/icons/" + theme + "/tx_bdap"); default: return QIcon(":/icons/" + theme + "/tx_inout"); @@ -443,8 +458,22 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b return lookupAddress(wtx->address, tooltip) + watchAddress; case TransactionRecord::SendToOther: return QString::fromStdString(wtx->address) + watchAddress; - case TransactionRecord::BDAP: - return tr("Directory Entry"); //TODO: Add BDAP Name and Operation Type here + case TransactionRecord::NewDomainUser: + return tr("New Directory User"); + case TransactionRecord::UpdateDomainUser: + return tr("Update Directory User"); + case TransactionRecord::DeleteDomainUser: + return tr("Delete Directory User"); + case TransactionRecord::RevokeDomainUser: + return tr("Revoke Directory User"); + case TransactionRecord::NewDomainGroup: + return tr("New Directory Group"); + case TransactionRecord::UpdateDomainGroup: + return tr("Update Directory Group"); + case TransactionRecord::DeleteDomainGroup: + return tr("Delete Directory Group"); + case TransactionRecord::RevokeDomainGroup: + return tr("Revoke Directory Group"); case TransactionRecord::SendToSelf: default: return tr("(n/a)") + watchAddress; @@ -461,7 +490,14 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const case TransactionRecord::Generated: case TransactionRecord::PrivateSend: case TransactionRecord::RecvWithPrivateSend: - case TransactionRecord::BDAP: + case TransactionRecord::NewDomainUser: + case TransactionRecord::UpdateDomainUser: + case TransactionRecord::DeleteDomainUser: + case TransactionRecord::RevokeDomainUser: + case TransactionRecord::NewDomainGroup: + case TransactionRecord::UpdateDomainGroup: + case TransactionRecord::DeleteDomainGroup: + case TransactionRecord::RevokeDomainGroup: { QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address)); if(label.isEmpty()) diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index f8bfb83a34..86a8c7b689 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -103,7 +103,14 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa typeWidget->addItem(tr("PrivateSend Collateral Payment"), TransactionFilterProxy::TYPE(TransactionRecord::PrivateSendCollateralPayment)); typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf)); typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); - typeWidget->addItem(tr("BDAP"), TransactionFilterProxy::TYPE(TransactionRecord::BDAP)); + typeWidget->addItem(tr("BDAP"), TransactionFilterProxy::TYPE(TransactionRecord::NewDomainUser) | + TransactionFilterProxy::TYPE(TransactionRecord::UpdateDomainUser) | + TransactionFilterProxy::TYPE(TransactionRecord::DeleteDomainUser) | + TransactionFilterProxy::TYPE(TransactionRecord::RevokeDomainUser) | + TransactionFilterProxy::TYPE(TransactionRecord::NewDomainGroup) | + TransactionFilterProxy::TYPE(TransactionRecord::UpdateDomainGroup) | + TransactionFilterProxy::TYPE(TransactionRecord::DeleteDomainGroup) | + TransactionFilterProxy::TYPE(TransactionRecord::RevokeDomainGroup)); typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other)); typeWidget->setCurrentIndex(settings.value("transactionType").toInt()); From 4f2a500f32cb2d2073c6839c99dfb5883890c5d0 Mon Sep 17 00:00:00 2001 From: Sven Kercher <24934984+SvenKercher@users.noreply.github.com> Date: Tue, 28 Aug 2018 02:05:03 +0200 Subject: [PATCH 0197/1653] Remove double forcecompactdb arg --- src/dbwrapper.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 1f06b9a223..0a6470e9f7 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -125,12 +125,6 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b LogPrintf("Finished database compaction of %s\n", path.string()); } - if (GetBoolArg("-forcecompactdb", false)) { - LogPrintf("Starting database compaction of %s\n", path.string()); - pdb->CompactRange(nullptr, nullptr); - LogPrintf("Finished database compaction of %s\n", path.string()); - } - // The base-case obfuscation key, which is a noop. obfuscate_key = std::vector(OBFUSCATE_KEY_NUM_BYTES, '\000'); From 96fdc3c1b7133719e43c9345c7d5133db32180c2 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 29 Aug 2018 01:32:44 -0500 Subject: [PATCH 0198/1653] [BDAP] Add bdap directory to make clean --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index 8c83c5ad8b..afd75cb6e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -525,6 +525,7 @@ endif CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a CLEANFILES += *.gcda *.gcno +CLEANFILES += bdap/*.gcda bdap/*.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno From bbf690c3ddcdfdac23c903206afce7bc10a9dbc0 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 29 Aug 2018 11:38:17 -0500 Subject: [PATCH 0199/1653] [Fluid] Refactor fluid code and remove index database --- src/Makefile.am | 9 +- src/chain.cpp | 6 - src/chain.h | 73 ------------- src/dbwrapper.cpp | 1 + src/dbwrapper.h | 1 + src/dynode-payments.cpp | 9 +- src/dynode.cpp | 6 +- src/{ => fluid}/fluid.cpp | 93 +++++++++++++--- src/{ => fluid}/fluid.h | 11 +- src/fluid/fluiddynode.cpp | 153 ++++++++++++++++++++++++++ src/fluid/fluiddynode.h | 108 ++++++++++++++++++ src/{ => fluid}/rpcfluid.cpp | 48 +++++++- src/init.cpp | 10 +- src/miner.cpp | 26 +++-- src/qt/transactionrecord.cpp | 1 + src/txdb.cpp | 1 - src/validation.cpp | 206 ++++++++++++++++++----------------- src/wallet/wallet.cpp | 2 +- 18 files changed, 537 insertions(+), 227 deletions(-) rename src/{ => fluid}/fluid.cpp (92%) rename src/{ => fluid}/fluid.h (92%) create mode 100644 src/fluid/fluiddynode.cpp create mode 100644 src/fluid/fluiddynode.h rename src/{ => fluid}/rpcfluid.cpp (93%) diff --git a/src/Makefile.am b/src/Makefile.am index 8c83c5ad8b..d4be330e35 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -113,7 +113,8 @@ DYNAMIC_CORE_H = \ dynodeman.h \ dynodeconfig.h \ flat-database.h \ - fluid.h \ + fluid/fluid.h \ + fluid/fluiddynode.h \ governance.h \ governance-classes.h \ governance-exceptions.h \ @@ -242,7 +243,9 @@ libdynamic_server_a_SOURCES = \ dynode-sync.cpp \ dynodeconfig.cpp \ dynodeman.cpp \ - fluid.cpp \ + fluid/fluid.cpp \ + fluid/fluiddynode.cpp \ + fluid/rpcfluid.cpp \ governance.cpp \ governance-classes.cpp \ governance-object.cpp \ @@ -278,7 +281,6 @@ libdynamic_server_a_SOURCES = \ rpcnet.cpp \ rpcrawtransaction.cpp \ rpcserver.cpp \ - rpcfluid.cpp \ script/sigcache.cpp \ sendalert.cpp \ spork.cpp \ @@ -528,6 +530,7 @@ CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno +CLEANFILES += fluid/*.gcda fluid/*.gcno CLEANFILES += policy/*.gcda policy/*.gcno CLEANFILES += primitives/*.gcda primitives/*.gcno CLEANFILES += script/*.gcda script/*.gcno diff --git a/src/chain.cpp b/src/chain.cpp index 0fe0787c7c..70a8f2c471 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -6,7 +6,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "chain.h" -#include "fluid.h" /** * CChain implementation @@ -120,11 +119,6 @@ void CBlockIndex::BuildSkip() pskip = pprev->GetAncestor(GetSkipHeight(nHeight)); } -std::vector InitialiseAddresses() { - CFluidParameters params; - return params.InitialiseAddresses(); -} - arith_uint256 GetBlockProof(const CBlockIndex& block) { arith_uint256 bnTarget; diff --git a/src/chain.h b/src/chain.h index fdc3e9182c..067776be52 100644 --- a/src/chain.h +++ b/src/chain.h @@ -16,8 +16,6 @@ #include -std::vector InitialiseAddresses(); - class CBlockFileInfo { public: @@ -150,71 +148,6 @@ enum BlockStatus: uint32_t { BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, }; -/** Fluid Protocol Entry Corresponding to Each Block */ -class CFluidEntry -{ -public: - CAmount blockReward; - CAmount dynodeReward; - unsigned int dynodeRecipientCount; - std::vector fluidHistory; - std::vector fluidSovereigns; - std::vector fluidFrozenAccounts; - - CFluidEntry() { - SetNull(); - } - - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(VARINT(blockReward)); - READWRITE(VARINT(dynodeReward)); - READWRITE(VARINT(dynodeRecipientCount)); - READWRITE(fluidHistory); - READWRITE(fluidSovereigns); - READWRITE(fluidFrozenAccounts); - } - - inline friend bool operator==(const CFluidEntry &a, const CFluidEntry &b) { - return ( - a.fluidHistory == b.fluidHistory - && a.fluidSovereigns == b.fluidSovereigns - && a.blockReward == b.blockReward - && a.dynodeReward == b.dynodeReward - && a.dynodeRecipientCount == b.dynodeRecipientCount - && a.fluidFrozenAccounts == b.fluidFrozenAccounts - ); - } - - inline CFluidEntry operator=(const CFluidEntry &b) { - fluidHistory = b.fluidHistory; - fluidSovereigns = b.fluidSovereigns; - blockReward = b.blockReward; - dynodeReward = b.dynodeReward; - dynodeRecipientCount = b.dynodeRecipientCount; - fluidFrozenAccounts = b.fluidFrozenAccounts; - return *this; - } - - inline friend bool operator!=(const CFluidEntry &a, const CFluidEntry &b) { - return !(a == b); - } - - inline void SetNull() { - fluidHistory.clear(); - fluidSovereigns = InitialiseAddresses(); - fluidFrozenAccounts.clear(); - blockReward = 0; - dynodeReward = 0; - dynodeRecipientCount = 1; - } - - inline bool IsNull() const { - return (fluidHistory.empty() && fluidSovereigns == InitialiseAddresses() && fluidFrozenAccounts.empty() && blockReward == 0 && dynodeReward == 0 && dynodeRecipientCount == 1); - } -}; - /** The block chain is a tree shaped structure starting with the * genesis block at the root, with each block potentially having multiple * candidates to be the next block. A blockindex may have multiple pprev pointing @@ -269,9 +202,6 @@ class CBlockIndex //! (memory only) Sequential id assigned to distinguish order in which blocks are received. int32_t nSequenceId; - //! Fluid Entry - CFluidEntry fluidParams; - void SetNull() { phashBlock = NULL; @@ -286,7 +216,6 @@ class CBlockIndex nChainTx = 0; nStatus = 0; nSequenceId = 0; - fluidParams.SetNull(); nVersion = 0; hashMerkleRoot = uint256(); @@ -447,8 +376,6 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(VARINT(nDataPos)); if (nStatus & BLOCK_HAVE_UNDO) READWRITE(VARINT(nUndoPos)); - - READWRITE(fluidParams); // block hash READWRITE(hash); diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 1f06b9a223..6ae5615bc1 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -202,6 +202,7 @@ bool CDBWrapper::IsEmpty() CDBIterator::~CDBIterator() { delete piter; } bool CDBIterator::Valid() { return piter->Valid(); } void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } +void CDBIterator::SeekToLast() { piter->SeekToLast(); } void CDBIterator::Next() { piter->Next(); } namespace dbwrapper_private { diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 4df5eccd8b..3c8ff07761 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -133,6 +133,7 @@ class CDBIterator bool Valid(); void SeekToFirst(); + void SeekToLast(); template void Seek(const K& key) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); diff --git a/src/dynode-payments.cpp b/src/dynode-payments.cpp index 0f64ba674a..63d114728e 100644 --- a/src/dynode-payments.cpp +++ b/src/dynode-payments.cpp @@ -10,7 +10,7 @@ #include "dynode-sync.h" #include "dynodeman.h" #include "policy/fees.h" -#include "fluid.h" +#include "fluid/fluid.h" #include "governance-classes.h" #include "messagesigner.h" #include "netfulfilledman.h" @@ -315,8 +315,8 @@ void CDynodePayments::FillBlockPayee(CMutableTransaction& txNew, int nBlockHeigh // make sure it's not filled yet txoutDynodeRet = CTxOut(); - - CAmount dynodePayment = getDynodeSubsidyWithOverride(pindexPrev->fluidParams.dynodeReward); + //TODO fluid + CAmount dynodePayment = GetDynodePayment(true);//getDynodeSubsidyWithOverride(pindexPrev->fluidParams.dynodeReward); txoutDynodeRet = CTxOut(dynodePayment, payee); txNew.vout.push_back(txoutDynodeRet); @@ -585,7 +585,8 @@ bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew) std::string strPayeesPossible = ""; /* Dirtiest trick in the book */ - CAmount nDynodePayment = getDynodeSubsidyWithOverride(chainActive.Tip()->fluidParams.dynodeReward); + //TODO fluid + CAmount nDynodePayment = GetDynodePayment(true); //getDynodeSubsidyWithOverride(chainActive.Tip()->fluidParams.dynodeReward); //require at least DNPAYMENTS_SIGNATURES_REQUIRED signatures diff --git a/src/dynode.cpp b/src/dynode.cpp index c065e0587f..311ac370e7 100644 --- a/src/dynode.cpp +++ b/src/dynode.cpp @@ -11,7 +11,7 @@ #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeman.h" -#include "fluid.h" +#include "fluid/fluid.h" #include "init.h" #include "messagesigner.h" #include "netbase.h" @@ -301,8 +301,8 @@ void CDynode::UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack CBlock block; if(!ReadBlockFromDisk(block, BlockReading, Params().GetConsensus())) // shouldn't really happen continue; - - CAmount nDynodePayment = getDynodeSubsidyWithOverride(BlockReading->fluidParams.dynodeReward); + //TODO fluid. + CAmount nDynodePayment = GetDynodePayment(true); //getDynodeSubsidyWithOverride(BlockReading->fluidParams.dynodeReward); BOOST_FOREACH(CTxOut txout, block.vtx[0].vout) if(dnpayee == txout.scriptPubKey && nDynodePayment == txout.nValue) { diff --git a/src/fluid.cpp b/src/fluid/fluid.cpp similarity index 92% rename from src/fluid.cpp rename to src/fluid/fluid.cpp index ded9f4e265..1ba7bb3d79 100644 --- a/src/fluid.cpp +++ b/src/fluid/fluid.cpp @@ -23,13 +23,41 @@ CFluid fluid; extern CWallet* pwalletMain; #endif //ENABLE_WALLET -bool IsTransactionFluid(CScript txOut) { +bool IsTransactionFluid(const CScript& txOut) { return (txOut.IsProtocolInstruction(MINT_TX) || txOut.IsProtocolInstruction(DYNODE_MODFIY_TX) || txOut.IsProtocolInstruction(MINING_MODIFY_TX) ); } +bool IsTransactionFluid(const CTransaction& tx, CScript& fluidScript) +{ + for (const CTxOut& txout : tx.vout) { + CScript txOut = txout.scriptPubKey; + if (IsTransactionFluid(txOut)) { + fluidScript = txOut; + return true; + } + } + return false; +} + +int GetFluidOpCode(const CScript& fluidScript) +{ + if (fluidScript.IsProtocolInstruction(MINT_TX)) { + return OP_MINT; + } + else if (fluidScript.IsProtocolInstruction(DYNODE_MODFIY_TX)) + { + return OP_REWARD_DYNODE; + } + else if (fluidScript.IsProtocolInstruction(MINING_MODIFY_TX)) + { + return OP_REWARD_MINING; + } + return 0; +} + /** Initialise sovereign identities that are able to run fluid commands */ std::vector> CFluidParameters::InitialiseSovereignIdentities() { std::vector> x; @@ -57,6 +85,11 @@ std::vector> CFluidParameters::Initialis return x; } +std::vector InitialiseAddresses() { + CFluidParameters params; + return params.InitialiseAddresses(); +} + /** Checks if any given address is a current master key (invoked by RPC) */ bool CFluid::IsGivenKeyMaster(CDynamicAddress inputKey) { if (!inputKey.IsValid()) { @@ -67,8 +100,11 @@ bool CFluid::IsGivenKeyMaster(CDynamicAddress inputKey) { GetLastBlockIndex(chainActive.Tip()); CBlockIndex* pindex = chainActive.Tip(); - if (pindex != NULL) - fluidSovereigns = pindex->fluidParams.fluidSovereigns; + if (pindex != NULL) { + //TODO fluid + fluidSovereigns = InitialiseAddresses(); //pindex->fluidParams.fluidSovereigns; + } + else fluidSovereigns = InitialiseAddresses(); @@ -176,8 +212,10 @@ bool CFluid::CheckIfQuorumExists(const std::string consentToken, std::string &me GetLastBlockIndex(chainActive.Tip()); CBlockIndex* pindex = chainActive.Tip(); - if (pindex != NULL) - fluidSovereigns = pindex->fluidParams.fluidSovereigns; + if (pindex != NULL) { + //TODO fluid + fluidSovereigns = InitialiseAddresses(); //pindex->fluidParams.fluidSovereigns; + } else fluidSovereigns = InitialiseAddresses(); @@ -477,19 +515,24 @@ void CFluid::AddFluidTransactionsToRecord(const CBlockIndex* pblockindex, std::v /* Check if transaction exists in record */ bool CFluid::CheckTransactionInRecord(CScript fluidInstruction, CBlockIndex* pindex) { - std::string verificationString; - CFluidEntry fluidIndex; - if (chainActive.Height() <= fluid.FLUID_ACTIVATE_HEIGHT) - return false; - else if (pindex == nullptr) { - GetLastBlockIndex(chainActive.Tip()); - fluidIndex = chainActive.Tip()->fluidParams; - } else - fluidIndex = pindex->fluidParams; - - std::vector transactionRecord = fluidIndex.fluidHistory; - if (IsTransactionFluid(fluidInstruction)) { + std::string verificationString; + //TODO fluid + /* + CFluidEntry fluidIndex; + if (chainActive.Height() <= fluid.FLUID_ACTIVATE_HEIGHT) { + return false; + } + else if (pindex == nullptr) { + GetLastBlockIndex(chainActive.Tip()); + //TODO fluid + //fluidIndex = chainActive.Tip()->fluidParams; + } else { + //TODO fluid + //fluidIndex = pindex->fluidParams; + } + */ + std::vector transactionRecord;//fluidIndex.fluidHistory; verificationString = ScriptToAsmStr(fluidInstruction); std::string verificationWithoutOpCode = GetRidOfScriptStatement(verificationString); std::string message; @@ -646,4 +689,20 @@ bool CFluid::CheckTransactionToBlock(const CTransaction& transaction, const uint } return true; +} + +std::vector CharVectorFromString(const std::string& str) +{ + return std::vector(str.begin(), str.end()); +} + +std::string StringFromCharVector(const std::vector& vch) +{ + std::string strReturn; + std::vector::const_iterator vi = vch.begin(); + while (vi != vch.end()) { + strReturn += (char) (*vi); + vi++; + } + return strReturn; } \ No newline at end of file diff --git a/src/fluid.h b/src/fluid/fluid.h similarity index 92% rename from src/fluid.h rename to src/fluid/fluid.h index ca7419a570..37a744c682 100644 --- a/src/fluid.h +++ b/src/fluid/fluid.h @@ -9,7 +9,6 @@ #include "script/script.h" #include "consensus/validation.h" #include "utilstrencodings.h" -#include "dbwrapper.h" #include "operations.h" #include @@ -22,6 +21,7 @@ class CBlock; class CTxMemPool; struct CBlockTemplate; +class CTransaction; /** Configuration Framework */ class CFluidParameters { @@ -38,6 +38,8 @@ class CFluidParameters { std::vector InitialiseAddresses(); }; +std::vector InitialiseAddresses(); + /** Fluid Asset Management Framework */ class CFluid : public CFluidParameters, public COperations { public: @@ -83,7 +85,12 @@ CAmount getBlockSubsidyWithOverride(const int& nHeight, CAmount lastOverrideComm CAmount getDynodeSubsidyWithOverride(CAmount lastOverrideCommand, bool fDynode = true); void BuildFluidInformationIndex(CBlockIndex* pindex, CAmount &nExpectedBlockValue, bool fDynodePaid); -bool IsTransactionFluid(CScript txOut); +bool IsTransactionFluid(const CScript& txOut); +bool IsTransactionFluid(const CTransaction& tx, CScript& fluidScript); +int GetFluidOpCode(const CScript& fluidScript); + +std::vector CharVectorFromString(const std::string& str); +std::string StringFromCharVector(const std::vector& vch); extern CFluid fluid; diff --git a/src/fluid/fluiddynode.cpp b/src/fluid/fluiddynode.cpp new file mode 100644 index 0000000000..0915584a53 --- /dev/null +++ b/src/fluid/fluiddynode.cpp @@ -0,0 +1,153 @@ +// Copyright (c) 2017 Duality Blockchain Solutions Developers + + +#include "fluiddynode.h" + +#include "core_io.h" +#include "fluid.h" +#include "operations.h" +#include "script/script.h" + +CFluidDynodeDB *pFluidDynodeDB = NULL; + +bool GetFluidDynodeData(const CScript& scriptPubKey, CFluidDynode& entry) +{ + std::string fluidOperationString = ScriptToAsmStr(scriptPubKey); + std::string strOperationCode = GetRidOfScriptStatement(fluidOperationString, 0); + std::string verificationWithoutOpCode = GetRidOfScriptStatement(fluidOperationString); + std::vector splitString; + HexFunctions hexConvert; + hexConvert.ConvertToString(verificationWithoutOpCode); + SeparateString(verificationWithoutOpCode, splitString, false); + std::string messageTokenKey = splitString.at(0); + std::vector vecSplitScript; + SeparateFluidOpString(verificationWithoutOpCode, vecSplitScript); + + if (vecSplitScript.size() == 5 && strOperationCode == "OP_REWARD_DYNODE") { + std::vector vchFluidOperation = CharVectorFromString(fluidOperationString); + entry.FluidScript.insert(entry.FluidScript.end(), vchFluidOperation.begin(), vchFluidOperation.end()); + std::string strAmount = vecSplitScript[0]; + CAmount fluidAmount; + if (ParseFixedPoint(strAmount, 8, &fluidAmount)) { + entry.DynodeReward = fluidAmount; + } + std::string strTimeStamp = vecSplitScript[1]; + int64_t tokenTimeStamp; + if (ParseInt64(strTimeStamp, &tokenTimeStamp)) { + entry.nTimeStamp = tokenTimeStamp; + } + entry.SovereignAddresses.clear(); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[2], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[3], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[4], messageTokenKey).ToString())); + + LogPrintf("GetFluidDynodeData: strAmount = %s, strTimeStamp = %d, Addresses1 = %s, Addresses2 = %s, Addresses3 = %s \n", + strAmount, entry.nTimeStamp, StringFromCharVector(entry.SovereignAddresses[0]), + StringFromCharVector(entry.SovereignAddresses[1]), StringFromCharVector(entry.SovereignAddresses[2])); + + return true; + } + return false; +} + +bool GetFluidDynodeData(const CTransaction& tx, CFluidDynode& entry, int& nOut) +{ + int n = 0; + for (const CTxOut& txout : tx.vout) { + CScript txOut = txout.scriptPubKey; + if (IsTransactionFluid(txOut)) { + nOut = n; + return GetFluidDynodeData(txOut, entry); + } + n++; + } + return false; +} + +bool CFluidDynode::UnserializeFromTx(const CTransaction& tx) { + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetFluidDynodeData(tx, *this, nOut)) + { + SetNull(); + return false; + } + return true; +} + +bool CFluidDynode::UnserializeFromScript(const CScript& fluidScript) { + std::vector vchData; + std::vector vchHash; + if(!GetFluidDynodeData(fluidScript, *this)) + { + SetNull(); + return false; + } + return true; +} + +void CFluidDynode::Serialize(std::vector& vchData) { + CDataStream dsFluidOp(SER_NETWORK, PROTOCOL_VERSION); + dsFluidOp << *this; + vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); +} + +CFluidDynodeDB::CFluidDynodeDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-dynode", nCacheSize, fMemory, fWipe, obfuscate) +{ +} + +bool CFluidDynodeDB::AddFluidDynodeEntry(const CFluidDynode& entry, const int op) +{ + bool writeState = false; + { + LOCK(cs_fluid_dynode); + writeState = Write(make_pair(std::string("script"), entry.FluidScript), entry) + && Write(make_pair(std::string("txid"), entry.txHash), entry.FluidScript); + } + + return writeState; +} + +bool CFluidDynodeDB::GetLastFluidDynodeRecord(CFluidDynode& entry) +{ + LOCK(cs_fluid_dynode); + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToLast(); + pcursor->GetValue(entry); + return true; +} + +bool CFluidDynodeDB::GetAllFluidDynodeRecords(std::vector& entries) +{ + LOCK(cs_fluid_dynode); + std::pair > key; + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CFluidDynode entry; + try { + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + if (!entry.IsNull()) + { + entries.push_back(entry); + } + } + pcursor->Next(); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +bool CheckFluidDynodeDB() +{ + if (!pFluidDynodeDB) + return false; + + return true; +} \ No newline at end of file diff --git a/src/fluid/fluiddynode.h b/src/fluid/fluiddynode.h new file mode 100644 index 0000000000..2110a47184 --- /dev/null +++ b/src/fluid/fluiddynode.h @@ -0,0 +1,108 @@ +// Copyright (c) 2017 Duality Blockchain Solutions Developers + +#ifndef FLUID_DB_H +#define FLUID_DB_H + +#include "amount.h" +#include "dbwrapper.h" +#include "serialize.h" + +#include "sync.h" +#include "uint256.h" + +class CScript; +class CTransaction; + +class CFluidDynode { +public: + static const int CURRENT_VERSION=1; + int nVersion; + std::vector FluidScript; + CAmount DynodeReward; + int64_t nTimeStamp; + std::vector> SovereignAddresses; + uint256 txHash; + unsigned int nHeight; + + CFluidDynode() { + SetNull(); + } + + CFluidDynode(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + CFluidDynode(const CScript& fluidScript) { + SetNull(); + UnserializeFromScript(fluidScript); + } + + inline void SetNull() + { + nVersion = CFluidDynode::CURRENT_VERSION; + FluidScript.clear(); + DynodeReward = -1; + nTimeStamp = 0; + SovereignAddresses.clear(); + txHash.SetNull(); + nHeight = 0; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(FluidScript); + READWRITE(DynodeReward); + READWRITE(VARINT(nTimeStamp)); + READWRITE(SovereignAddresses); + READWRITE(txHash); + READWRITE(VARINT(nHeight)); + } + + inline friend bool operator==(const CFluidDynode& a, const CFluidDynode& b) { + return (a.FluidScript == b.FluidScript && a.DynodeReward == b.DynodeReward && a.nTimeStamp == b.nTimeStamp); + } + + inline friend bool operator!=(const CFluidDynode& a, const CFluidDynode& b) { + return !(a == b); + } + + inline CFluidDynode operator=(const CFluidDynode& b) { + FluidScript = b.FluidScript; + DynodeReward = b.DynodeReward; + nTimeStamp = b.nTimeStamp; + for (const std::vector& vchAddress : b.SovereignAddresses) + { + SovereignAddresses.push_back(vchAddress); + } + txHash = b.txHash; + nHeight = b.nHeight; + return *this; + } + + inline bool IsNull() const { return (nTimeStamp == 0); } + bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromScript(const CScript& fluidScript); + void Serialize(std::vector& vchData); +}; + +static CCriticalSection cs_fluid_dynode; + +class CFluidDynodeDB : public CDBWrapper { +public: + CFluidDynodeDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); + bool AddFluidDynodeEntry(const CFluidDynode& entry, const int op); + bool GetLastFluidDynodeRecord(CFluidDynode& entry); + bool GetAllFluidDynodeRecords(std::vector& entries); +}; + +bool GetFluidDynodeData(const CScript& scriptPubKey, CFluidDynode& entry); +bool GetFluidDynodeData(const CTransaction& tx, CFluidDynode& entry, int& nOut); +bool CheckFluidDynodeDB(); + +extern CFluidDynodeDB *pFluidDynodeDB; + +#endif // FLUID_DB_H diff --git a/src/rpcfluid.cpp b/src/fluid/rpcfluid.cpp similarity index 93% rename from src/rpcfluid.cpp rename to src/fluid/rpcfluid.cpp index 458428e16e..97fe90be0b 100644 --- a/src/rpcfluid.cpp +++ b/src/fluid/rpcfluid.cpp @@ -4,6 +4,7 @@ #include "chain.h" #include "core_io.h" +#include "fluiddynode.h" #include "init.h" #include "keepass.h" #include "net.h" @@ -293,18 +294,20 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) + HelpExampleRpc("getfluidhistoryraw", "") ); + UniValue ret(UniValue::VARR); GetLastBlockIndex(chainActive.Tip()); CBlockIndex* pindex = chainActive.Tip(); + //TODO fluid + /* CFluidEntry fluidIndex = pindex->fluidParams; std::vector transactionRecord = fluidIndex.fluidHistory; - UniValue ret(UniValue::VARR); for(const std::string& existingRecord : transactionRecord) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("fluid command", existingRecord)); ret.push_back(obj); } - + */ return ret; } @@ -332,12 +335,43 @@ UniValue getfluidhistory(const JSONRPCRequest& request) + HelpExampleRpc("getfluidhistory", "") ); + UniValue ret(UniValue::VARR); + std::vector dynodeEntries; + if (CheckFluidDynodeDB) { + if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid dynode entries")); + } + } + else { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4001 - " + _("Error opening fluid dynode db")); + } + + // load Dynode fluid transaction history + for (const CFluidDynode& dynEntry : dynodeEntries) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("operation", "Dynode Reward Update")); + obj.push_back(Pair("amount", dynEntry.DynodeReward)); //TODO fluid convert to decimal value + obj.push_back(Pair("timestamp", dynEntry.nTimeStamp)); + obj.push_back(Pair("address_count", dynEntry.SovereignAddresses.size())); + int index = 1; + for (const std::vector& vchAddress : dynEntry.SovereignAddresses) + { + std::string addLabel = "sovereign_address_" + std::to_string(index); + obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); + index ++; + } + obj.push_back(Pair("raw", StringFromCharVector(dynEntry.FluidScript))); + ret.push_back(obj); + } + //TODO fluid + /* GetLastBlockIndex(chainActive.Tip()); CBlockIndex* pindex = chainActive.Tip(); CFluidEntry fluidIndex = pindex->fluidParams; std::vector transactionRecord = fluidIndex.fluidHistory; - UniValue ret(UniValue::VARR); + HexFunctions hexConvert; for (const std::string& existingRecord : transactionRecord) { UniValue obj(UniValue::VOBJ); @@ -385,7 +419,7 @@ UniValue getfluidhistory(const JSONRPCRequest& request) } ret.push_back(obj); } - + */ return ret; } @@ -404,19 +438,21 @@ UniValue getfluidsovereigns(const JSONRPCRequest& request) + HelpExampleRpc("getfluidsovereigns", "") ); + UniValue ret(UniValue::VARR); + /* GetLastBlockIndex(chainActive.Tip()); CBlockIndex* pindex = chainActive.Tip(); CFluidEntry fluidIndex = pindex->fluidParams; std::vector sovereignLogs = fluidIndex.fluidSovereigns; - UniValue ret(UniValue::VARR); + for (const std::string& sovereign : sovereignLogs) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("sovereign address", sovereign)); ret.push_back(obj); } - + */ return ret; } diff --git a/src/init.cpp b/src/init.cpp index 6336dccbeb..0b860e2de4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -24,6 +24,7 @@ #include "dynodeconfig.h" #include "dynodeman.h" #include "flat-database.h" +#include "fluid/fluiddynode.h" #include "governance.h" #include "instantsend.h" #include "httpserver.h" @@ -1479,18 +1480,21 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) delete pcoinsdbview; delete pcoinscatcher; delete pblocktree; + delete pFluidDynodeDB; // BDAP Services DB's delete pDomainEntryDB; - + pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); pcoinsTip = new CCoinsViewCache(pcoinscatcher); - // Init BDAP Services DB's bool obfuscate = false; + // Init Fluid DB's + pFluidDynodeDB = new CFluidDynodeDB(nTotalCache * 35, false, fReindex, obfuscate); + // Init BDAP Services DB's pDomainEntryDB = new CDomainEntryDB(nTotalCache * 35, false, fReindex, obfuscate); - + if (fReindex) { pblocktree->WriteReindexing(true); //If we're reindexing in prune mode, wipe away unusable block files and all undo data files diff --git a/src/miner.cpp b/src/miner.cpp index f4d0165b03..666c8c9dbf 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -30,7 +30,7 @@ #include "consensus/validation.h" #include "validationinterface.h" #include "wallet/wallet.h" -#include "fluid.h" +#include "fluid/fluid.h" #include #include @@ -317,11 +317,17 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, } } + //TODO fluid + CAmount fluidIssuance = 0; + CAmount blockReward = getBlockSubsidyWithOverride(nHeight, 0); CDynamicAddress address; + /* + CAmount fluidIssuance; + CAmount blockReward = getBlockSubsidyWithOverride(nHeight, prevFluidIndex.blockReward); CFluidEntry prevFluidIndex = pindexPrev->fluidParams; - CAmount fluidIssuance = 0, blockReward = getBlockSubsidyWithOverride(nHeight, prevFluidIndex.blockReward); - bool areWeMinting = fluid.GetMintingInstructions(pindexPrev, address, fluidIssuance); - + */ + bool areWeMinting = false; //fluid.GetMintingInstructions(pindexPrev, address, fluidIssuance); + // Compute regular coinbase transaction. txNew.vout[0].scriptPubKey = scriptPubKeyIn; @@ -330,12 +336,12 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, } else { txNew.vout[0].nValue = blockReward; } - + txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; CScript script; - - if (areWeMinting) { + //TODO fluid + if (areWeMinting) { // Pick out the amount of issuance txNew.vout[0].nValue -= fluidIssuance; @@ -362,7 +368,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); CAmount blockAmount = blockReward + fluidIssuance; - LogPrintf("CreateNewBlock(): Computed Miner Block Reward is %ld DYN\n", FormatMoney(blockAmount)); + LogPrintf("CreateNewBlock(): Computed Miner Block Reward is %ld DYN\n", FormatMoney(blockAmount)); // Update block coinbase pblock->vtx[0] = txNew; @@ -374,7 +380,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); - CValidationState state; + CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { LogPrintf("CreateNewBlock(): Generated Transaction:\n%s\n", txNew.ToString()); throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); @@ -477,7 +483,7 @@ void static DynamicMiner(const CChainParams& chainparams, CConnman& connman) boost::shared_ptr coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); - + try { // Throw an error if no script was provided. This can happen // due to some internal error but also if the keypool is empty. diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 910d21ceb0..350eea9bae 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -11,6 +11,7 @@ #include "consensus/consensus.h" #include "bdap/bdap.h" #include "bdap/domainentry.h" +#include "fluid/fluid.h" #include "instantsend.h" #include "validation.h" #include "privatesend.h" diff --git a/src/txdb.cpp b/src/txdb.cpp index c3b8d7a6aa..302db1101c 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -372,7 +372,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts(boost::functionnNonce = diskindex.nNonce; pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - pindexNew->fluidParams = diskindex.fluidParams; if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); diff --git a/src/validation.cpp b/src/validation.cpp index 30ece322fb..83b0884f3b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -16,7 +16,8 @@ #include "consensus/consensus.h" #include "dynode-payments.h" #include "dynode-sync.h" -#include "fluid.h" +#include "fluid/fluid.h" +#include "fluid/fluiddynode.h" #include "hash.h" #include "init.h" #include "instantsend.h" @@ -229,19 +230,19 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) return true; if (nBlockHeight >= fluid.FLUID_ACTIVATE_HEIGHT) { - if (!fluid.ProvisionalCheckTransaction(tx)) - return false; - - BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (IsTransactionFluid(txout.scriptPubKey)) { - std::string strErrorMessage; - if (!fluid.CheckFluidOperationScript(txout.scriptPubKey, nBlockTime, strErrorMessage)) { - return false; - } + if (!fluid.ProvisionalCheckTransaction(tx)) + return false; + + CScript scriptFluid; + if (IsTransactionFluid(tx, scriptFluid)) + { + std::string strErrorMessage; + if (!fluid.CheckFluidOperationScript(scriptFluid, nBlockTime, strErrorMessage)) { + return false; } - } - } - + } + } + BOOST_FOREACH(const CTxIn& txin, tx.vin) { if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL)) return false; @@ -640,10 +641,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C return false; // state filled in by CheckTransaction if (!fluid.ProvisionalCheckTransaction(tx)) - return false; + return false; - for (const CTxOut& txout : tx.vout) { - if (IsTransactionFluid(txout.scriptPubKey)) + for (const CTxOut& txout : tx.vout) { + if (IsTransactionFluid(txout.scriptPubKey)) { fluidTransaction = true; std::string strErrorMessage; @@ -659,7 +660,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C return state.DoS(100, false, REJECT_INVALID, strErrorMessage); } } - } + } if (tx.nVersion == BDAP_TX_VERSION) { std::string strErrorMessage; @@ -2193,7 +2194,15 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } - + CScript scriptFluid; + if (IsTransactionFluid(tx, scriptFluid)) { + int OpCode = GetFluidOpCode(scriptFluid); + if (OpCode == OP_REWARD_DYNODE) { + CFluidDynode fluidDynode(scriptFluid); + if (CheckFluidDynodeDB) + pFluidDynodeDB->AddFluidDynodeEntry(fluidDynode, OP_REWARD_DYNODE); + } + } if (fAddressIndex || fSpentIndex) { for (size_t j = 0; j < tx.vin.size(); j++) { @@ -2334,75 +2343,75 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd fDynodePaid = false; } - CAmount nExpectedBlockValue; - std::string strError = ""; - { - CBlockIndex* prevIndex = pindex->pprev; - CFluidEntry prevFluidIndex = pindex->pprev->fluidParams; - - CFluidEntry FluidIndex; - - CAmount fluidIssuance, newReward = 0, newDynodeReward = 0; - CDynamicAddress mintAddress; - - if (!fluid.GetProofOverrideRequest(pindex->pprev, newReward) - && prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { - FluidIndex.blockReward = (prevIndex? prevFluidIndex.blockReward : 0); - } else { - FluidIndex.blockReward = newReward; - } - - if (!fluid.GetDynodeOverrideRequest(pindex->pprev, newDynodeReward) - && prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { - FluidIndex.dynodeReward = (prevIndex? prevFluidIndex.dynodeReward : 0); - } else { - FluidIndex.dynodeReward = newDynodeReward; - } - - if (fluid.GetMintingInstructions(pindex->pprev, mintAddress, fluidIssuance) - && pindex->nHeight >= fluid.FLUID_ACTIVATE_HEIGHT) { - nExpectedBlockValue = getDynodeSubsidyWithOverride(prevFluidIndex.dynodeReward, fDynodePaid) + - getBlockSubsidyWithOverride(prevIndex->nHeight, prevFluidIndex.blockReward) + - fluidIssuance; - } else { - nExpectedBlockValue = getDynodeSubsidyWithOverride(prevFluidIndex.dynodeReward, fDynodePaid) + - getBlockSubsidyWithOverride(prevIndex->nHeight, prevFluidIndex.blockReward); - } - - std::vector fluidHistory, fluidSovereigns; - - if(!IsBlockValueValid(block, pindex->nHeight, nExpectedBlockValue, strError)) { - return state.DoS(0, error("ConnectBlock(DYN): %s", strError), REJECT_INVALID, "bad-cb-amount"); - } - - if (!IsBlockPayeeValid(block.vtx[0], pindex->nHeight, nExpectedBlockValue)) { - mapRejectedBlocks.insert(std::make_pair(block.GetHash(), GetTime())); - return state.DoS(0, error("ConnectBlock(DYN): couldn't find Dynode or Superblock payments"), - REJECT_INVALID, "bad-cb-payee"); - } - - if (prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { - fluidHistory.insert(fluidHistory.end(), prevFluidIndex.fluidHistory.begin(), prevFluidIndex.fluidHistory.end()); - fluid.AddFluidTransactionsToRecord(prevIndex, fluidHistory); - std::set setX(fluidHistory.begin(), fluidHistory.end()); - fluidHistory.assign(setX.begin(), setX.end()); - - FluidIndex.fluidHistory = fluidHistory; - - for (uint32_t x = 0; x != fluid.InitialiseSovereignIdentities().size(); x++) { - /* std::string error; - CDynamicAddress inputKey; // Reinitialise at each iteration to reset value - CNameVal val = nameValFromString(fluid.InitialiseIdentities().at(x)); - - if (!GetNameCurrentAddress(val, inputKey, error)) - fluidSovereigns.push_back(inputKey.ToString()); - else */ - fluidSovereigns.push_back(prevFluidIndex.fluidSovereigns.at(x)); - } - } - - pindex->fluidParams = FluidIndex; - } + CAmount nExpectedBlockValue; + std::string strError = ""; + { + //TODO fluid + /* + CBlockIndex* prevIndex = pindex->pprev; + CFluidEntry prevFluidIndex = pindex->pprev->fluidParams; + + CFluidEntry FluidIndex; + + CAmount fluidIssuance, newReward = 0, newDynodeReward = 0; + CDynamicAddress mintAddress; + + if (!fluid.GetProofOverrideRequest(pindex->pprev, newReward) && prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { + FluidIndex.blockReward = (prevIndex? prevFluidIndex.blockReward : 0); + } else { + FluidIndex.blockReward = newReward; + } + + if (!fluid.GetDynodeOverrideRequest(pindex->pprev, newDynodeReward) && prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { + FluidIndex.dynodeReward = (prevIndex? prevFluidIndex.dynodeReward : 0); + } else { + FluidIndex.dynodeReward = newDynodeReward; + } + + if (fluid.GetMintingInstructions(pindex->pprev, mintAddress, fluidIssuance) + && pindex->nHeight >= fluid.FLUID_ACTIVATE_HEIGHT) { + nExpectedBlockValue = getDynodeSubsidyWithOverride(prevFluidIndex.dynodeReward, fDynodePaid) + + getBlockSubsidyWithOverride(prevIndex->nHeight, prevFluidIndex.blockReward) + + fluidIssuance; + } else { + nExpectedBlockValue = getDynodeSubsidyWithOverride(prevFluidIndex.dynodeReward, fDynodePaid) + + getBlockSubsidyWithOverride(prevIndex->nHeight, prevFluidIndex.blockReward); + } + + std::vector fluidHistory, fluidSovereigns; + + if(!IsBlockValueValid(block, pindex->nHeight, nExpectedBlockValue, strError)) { + return state.DoS(0, error("ConnectBlock(DYN): %s", strError), REJECT_INVALID, "bad-cb-amount"); + } + + if (!IsBlockPayeeValid(block.vtx[0], pindex->nHeight, nExpectedBlockValue)) { + mapRejectedBlocks.insert(std::make_pair(block.GetHash(), GetTime())); + return state.DoS(0, error("ConnectBlock(DYN): couldn't find Dynode or Superblock payments"), + REJECT_INVALID, "bad-cb-payee"); + } + + if (prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { + fluidHistory.insert(fluidHistory.end(), prevFluidIndex.fluidHistory.begin(), prevFluidIndex.fluidHistory.end()); + fluid.AddFluidTransactionsToRecord(prevIndex, fluidHistory); + std::set setX(fluidHistory.begin(), fluidHistory.end()); + fluidHistory.assign(setX.begin(), setX.end()); + + FluidIndex.fluidHistory = fluidHistory; + + for (uint32_t x = 0; x != fluid.InitialiseSovereignIdentities().size(); x++) { + //std::string error; + //CDynamicAddress inputKey; // Reinitialise at each iteration to reset value + //CNameVal val = nameValFromString(fluid.InitialiseIdentities().at(x)); + + //if (!GetNameCurrentAddress(val, inputKey, error)) + // fluidSovereigns.push_back(inputKey.ToString()); + //else + fluidSovereigns.push_back(prevFluidIndex.fluidSovereigns.at(x)); + } + } + pindex->fluidParams = FluidIndex; + */ + } // END DYNAMIC @@ -3453,8 +3462,8 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo tx.GetHash().ToString(), FormatStateMessage(state)); - BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (IsTransactionFluid(txout.scriptPubKey)) { + BOOST_FOREACH(const CTxOut& txout, tx.vout) { + if (IsTransactionFluid(txout.scriptPubKey)) { std::string strErrorMessage; if (!fluid.CheckFluidOperationScript(txout.scriptPubKey, block.nTime, strErrorMessage)) { return error("CheckBlock(): %s, Block %s failed with %s", @@ -3462,12 +3471,12 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo tx.GetHash().ToString(), FormatStateMessage(state)); } - } - } - - if (!fluid.CheckTransactionToBlock(tx, block)) - return error("CheckBlock(): Fluid transaction violated filtration rules, offender %s", tx.GetHash().ToString()); - } + } + } + + if (!fluid.CheckTransactionToBlock(tx, block)) + return error("CheckBlock(): Fluid transaction violated filtration rules, offender %s", tx.GetHash().ToString()); + } unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -3540,9 +3549,10 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const CB // Check that all transactions are finalized for (const CTransaction& tx : block.vtx) { - if (!fluid.CheckTransactionToBlock(tx, pindexPrev->GetBlockHeader())) - return state.DoS(10, error("%s: contains an invalid fluid transaction", __func__), REJECT_INVALID, "invalid-fluid-txns"); - + if (pindexPrev != nullptr) { + if (!fluid.CheckTransactionToBlock(tx, pindexPrev->GetBlockHeader())) + return state.DoS(10, error("%s: contains an invalid fluid transaction", __func__), REJECT_INVALID, "invalid-fluid-txns"); + } if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 149754ce96..942fbdb6e6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -14,7 +14,7 @@ #include "chain.h" #include "wallet/coincontrol.h" #include "consensus/consensus.h" -#include "fluid.h" +#include "fluid/fluid.h" #include "governance.h" #include "init.h" #include "instantsend.h" From bac91622f181afe747eca75643c701276290c5d1 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 30 Aug 2018 03:30:56 -0500 Subject: [PATCH 0200/1653] [BDAP] Remove fluid reference from domain entry --- src/bdap/domainentry.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 03b0f126e9..6731ed0c23 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -6,7 +6,6 @@ #include "chainparams.h" #include "coins.h" -#include "fluid.h" #include "policy/policy.h" #include "rpcclient.h" #include "rpcserver.h" From e7fbf795a0791ca4bf83f2f120612544b382c6d6 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 30 Aug 2018 15:05:40 -0500 Subject: [PATCH 0201/1653] [Fluid] Add mining update and mint leveldb databases --- src/Makefile.am | 4 + src/fluid/fluiddynode.h | 6 +- src/fluid/fluidmining.cpp | 153 ++++++++++++++++++++++++ src/fluid/fluidmining.h | 108 +++++++++++++++++ src/fluid/fluidmint.cpp | 156 ++++++++++++++++++++++++ src/fluid/fluidmint.h | 112 +++++++++++++++++ src/fluid/rpcfluid.cpp | 244 +++++++++++++++++++++++++------------- src/init.cpp | 10 +- src/validation.cpp | 12 ++ 9 files changed, 716 insertions(+), 89 deletions(-) create mode 100644 src/fluid/fluidmining.cpp create mode 100644 src/fluid/fluidmining.h create mode 100644 src/fluid/fluidmint.cpp create mode 100644 src/fluid/fluidmint.h diff --git a/src/Makefile.am b/src/Makefile.am index d4be330e35..8743043fd8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -115,6 +115,8 @@ DYNAMIC_CORE_H = \ flat-database.h \ fluid/fluid.h \ fluid/fluiddynode.h \ + fluid/fluidmining.h \ + fluid/fluidmint.h \ governance.h \ governance-classes.h \ governance-exceptions.h \ @@ -245,6 +247,8 @@ libdynamic_server_a_SOURCES = \ dynodeman.cpp \ fluid/fluid.cpp \ fluid/fluiddynode.cpp \ + fluid/fluidmining.cpp \ + fluid/fluidmint.cpp \ fluid/rpcfluid.cpp \ governance.cpp \ governance-classes.cpp \ diff --git a/src/fluid/fluiddynode.h b/src/fluid/fluiddynode.h index 2110a47184..97f06bf9f0 100644 --- a/src/fluid/fluiddynode.h +++ b/src/fluid/fluiddynode.h @@ -1,7 +1,7 @@ // Copyright (c) 2017 Duality Blockchain Solutions Developers -#ifndef FLUID_DB_H -#define FLUID_DB_H +#ifndef FLUID_DYNODE_H +#define FLUID_DYNODE_H #include "amount.h" #include "dbwrapper.h" @@ -105,4 +105,4 @@ bool CheckFluidDynodeDB(); extern CFluidDynodeDB *pFluidDynodeDB; -#endif // FLUID_DB_H +#endif // FLUID_DYNODE_H diff --git a/src/fluid/fluidmining.cpp b/src/fluid/fluidmining.cpp new file mode 100644 index 0000000000..5683bd2b05 --- /dev/null +++ b/src/fluid/fluidmining.cpp @@ -0,0 +1,153 @@ +// Copyright (c) 2017 Duality Blockchain Solutions Developers + + +#include "fluidmining.h" + +#include "core_io.h" +#include "fluid.h" +#include "operations.h" +#include "script/script.h" + +CFluidMiningDB *pFluidMiningDB = NULL; + +bool GetFluidMiningData(const CScript& scriptPubKey, CFluidMining& entry) +{ + std::string fluidOperationString = ScriptToAsmStr(scriptPubKey); + std::string strOperationCode = GetRidOfScriptStatement(fluidOperationString, 0); + std::string verificationWithoutOpCode = GetRidOfScriptStatement(fluidOperationString); + std::vector splitString; + HexFunctions hexConvert; + hexConvert.ConvertToString(verificationWithoutOpCode); + SeparateString(verificationWithoutOpCode, splitString, false); + std::string messageTokenKey = splitString.at(0); + std::vector vecSplitScript; + SeparateFluidOpString(verificationWithoutOpCode, vecSplitScript); + + if (vecSplitScript.size() == 5 && strOperationCode == "OP_REWARD_MINING") { + std::vector vchFluidOperation = CharVectorFromString(fluidOperationString); + entry.FluidScript.insert(entry.FluidScript.end(), vchFluidOperation.begin(), vchFluidOperation.end()); + std::string strAmount = vecSplitScript[0]; + CAmount fluidAmount; + if (ParseFixedPoint(strAmount, 8, &fluidAmount)) { + entry.MiningReward = fluidAmount; + } + std::string strTimeStamp = vecSplitScript[1]; + int64_t tokenTimeStamp; + if (ParseInt64(strTimeStamp, &tokenTimeStamp)) { + entry.nTimeStamp = tokenTimeStamp; + } + entry.SovereignAddresses.clear(); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[2], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[3], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[4], messageTokenKey).ToString())); + + LogPrintf("GetFluidMiningData: strAmount = %s, strTimeStamp = %d, Addresses1 = %s, Addresses2 = %s, Addresses3 = %s \n", + strAmount, entry.nTimeStamp, StringFromCharVector(entry.SovereignAddresses[0]), + StringFromCharVector(entry.SovereignAddresses[1]), StringFromCharVector(entry.SovereignAddresses[2])); + + return true; + } + return false; +} + +bool GetFluidMiningData(const CTransaction& tx, CFluidMining& entry, int& nOut) +{ + int n = 0; + for (const CTxOut& txout : tx.vout) { + CScript txOut = txout.scriptPubKey; + if (IsTransactionFluid(txOut)) { + nOut = n; + return GetFluidMiningData(txOut, entry); + } + n++; + } + return false; +} + +bool CFluidMining::UnserializeFromTx(const CTransaction& tx) { + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetFluidMiningData(tx, *this, nOut)) + { + SetNull(); + return false; + } + return true; +} + +bool CFluidMining::UnserializeFromScript(const CScript& fluidScript) { + std::vector vchData; + std::vector vchHash; + if(!GetFluidMiningData(fluidScript, *this)) + { + SetNull(); + return false; + } + return true; +} + +void CFluidMining::Serialize(std::vector& vchData) { + CDataStream dsFluidOp(SER_NETWORK, PROTOCOL_VERSION); + dsFluidOp << *this; + vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); +} + +CFluidMiningDB::CFluidMiningDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-mining", nCacheSize, fMemory, fWipe, obfuscate) +{ +} + +bool CFluidMiningDB::AddFluidMiningEntry(const CFluidMining& entry, const int op) +{ + bool writeState = false; + { + LOCK(cs_fluid_mining); + writeState = Write(make_pair(std::string("script"), entry.FluidScript), entry) + && Write(make_pair(std::string("txid"), entry.txHash), entry.FluidScript); + } + + return writeState; +} + +bool CFluidMiningDB::GetLastFluidMiningRecord(CFluidMining& entry) +{ + LOCK(cs_fluid_mining); + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToLast(); + pcursor->GetValue(entry); + return true; +} + +bool CFluidMiningDB::GetAllFluidMiningRecords(std::vector& entries) +{ + LOCK(cs_fluid_mining); + std::pair > key; + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CFluidMining entry; + try { + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + if (!entry.IsNull()) + { + entries.push_back(entry); + } + } + pcursor->Next(); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +bool CheckFluidMiningDB() +{ + if (!pFluidMiningDB) + return false; + + return true; +} \ No newline at end of file diff --git a/src/fluid/fluidmining.h b/src/fluid/fluidmining.h new file mode 100644 index 0000000000..c2d507db84 --- /dev/null +++ b/src/fluid/fluidmining.h @@ -0,0 +1,108 @@ +// Copyright (c) 2017 Duality Blockchain Solutions Developers + +#ifndef FLUID_MINER +#define FLUID_MINER + +#include "amount.h" +#include "dbwrapper.h" +#include "serialize.h" + +#include "sync.h" +#include "uint256.h" + +class CScript; +class CTransaction; + +class CFluidMining { +public: + static const int CURRENT_VERSION=1; + int nVersion; + std::vector FluidScript; + CAmount MiningReward; + int64_t nTimeStamp; + std::vector> SovereignAddresses; + uint256 txHash; + unsigned int nHeight; + + CFluidMining() { + SetNull(); + } + + CFluidMining(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + CFluidMining(const CScript& fluidScript) { + SetNull(); + UnserializeFromScript(fluidScript); + } + + inline void SetNull() + { + nVersion = CFluidMining::CURRENT_VERSION; + FluidScript.clear(); + MiningReward = -1; + nTimeStamp = 0; + SovereignAddresses.clear(); + txHash.SetNull(); + nHeight = 0; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(FluidScript); + READWRITE(MiningReward); + READWRITE(VARINT(nTimeStamp)); + READWRITE(SovereignAddresses); + READWRITE(txHash); + READWRITE(VARINT(nHeight)); + } + + inline friend bool operator==(const CFluidMining& a, const CFluidMining& b) { + return (a.FluidScript == b.FluidScript && a.MiningReward == b.MiningReward && a.nTimeStamp == b.nTimeStamp); + } + + inline friend bool operator!=(const CFluidMining& a, const CFluidMining& b) { + return !(a == b); + } + + inline CFluidMining operator=(const CFluidMining& b) { + FluidScript = b.FluidScript; + MiningReward = b.MiningReward; + nTimeStamp = b.nTimeStamp; + for (const std::vector& vchAddress : b.SovereignAddresses) + { + SovereignAddresses.push_back(vchAddress); + } + txHash = b.txHash; + nHeight = b.nHeight; + return *this; + } + + inline bool IsNull() const { return (nTimeStamp == 0); } + bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromScript(const CScript& fluidScript); + void Serialize(std::vector& vchData); +}; + +static CCriticalSection cs_fluid_mining; + +class CFluidMiningDB : public CDBWrapper { +public: + CFluidMiningDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); + bool AddFluidMiningEntry(const CFluidMining& entry, const int op); + bool GetLastFluidMiningRecord(CFluidMining& entry); + bool GetAllFluidMiningRecords(std::vector& entries); +}; + +bool GetFluidMiningData(const CScript& scriptPubKey, CFluidMining& entry); +bool GetFluidMiningData(const CTransaction& tx, CFluidMining& entry, int& nOut); +bool CheckFluidMiningDB(); + +extern CFluidMiningDB *pFluidMiningDB; + +#endif // FLUID_MINER diff --git a/src/fluid/fluidmint.cpp b/src/fluid/fluidmint.cpp new file mode 100644 index 0000000000..3927507915 --- /dev/null +++ b/src/fluid/fluidmint.cpp @@ -0,0 +1,156 @@ +// Copyright (c) 2017 Duality Blockchain Solutions Developers + + +#include "fluidmint.h" + +#include "core_io.h" +#include "fluid.h" +#include "operations.h" +#include "script/script.h" + +CFluidMintDB *pFluidMintDB = NULL; + +bool GetFluidMintData(const CScript& scriptPubKey, CFluidMint& entry) +{ + std::string fluidOperationString = ScriptToAsmStr(scriptPubKey); + std::string strOperationCode = GetRidOfScriptStatement(fluidOperationString, 0); + std::string verificationWithoutOpCode = GetRidOfScriptStatement(fluidOperationString); + std::vector splitString; + HexFunctions hexConvert; + hexConvert.ConvertToString(verificationWithoutOpCode); + SeparateString(verificationWithoutOpCode, splitString, false); + std::string messageTokenKey = splitString.at(0); + std::vector vecSplitScript; + SeparateFluidOpString(verificationWithoutOpCode, vecSplitScript); + + if (vecSplitScript.size() == 5 && strOperationCode == "OP_MINT") { + std::vector vchFluidOperation = CharVectorFromString(fluidOperationString); + entry.FluidScript.insert(entry.FluidScript.end(), vchFluidOperation.begin(), vchFluidOperation.end()); + std::string strAmount = vecSplitScript[0]; + CAmount fluidAmount; + if (ParseFixedPoint(strAmount, 8, &fluidAmount)) { + entry.MintAmount = fluidAmount; + } + std::string strTimeStamp = vecSplitScript[1]; + int64_t tokenTimeStamp; + if (ParseInt64(strTimeStamp, &tokenTimeStamp)) { + entry.nTimeStamp = tokenTimeStamp; + } + std::vector vchDestinationAddress = CharVectorFromString(vecSplitScript[2]); + entry.DestinationAddress.insert(entry.DestinationAddress.end(), vchDestinationAddress.begin(), vchDestinationAddress.end()); + entry.SovereignAddresses.clear(); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[3], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[4], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[5], messageTokenKey).ToString())); + + LogPrintf("GetFluidMintData: strAmount = %s, strTimeStamp = %d, DestinationAddress = %s, Addresses1 = %s, Addresses2 = %s, Addresses3 = %s \n", + strAmount, entry.nTimeStamp, + StringFromCharVector(entry.DestinationAddress), StringFromCharVector(entry.SovereignAddresses[0]), + StringFromCharVector(entry.SovereignAddresses[1]), StringFromCharVector(entry.SovereignAddresses[2])); + + return true; + } + return false; +} + +bool GetFluidMintData(const CTransaction& tx, CFluidMint& entry, int& nOut) +{ + int n = 0; + for (const CTxOut& txout : tx.vout) { + CScript txOut = txout.scriptPubKey; + if (IsTransactionFluid(txOut)) { + nOut = n; + return GetFluidMintData(txOut, entry); + } + n++; + } + return false; +} + +bool CFluidMint::UnserializeFromTx(const CTransaction& tx) { + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetFluidMintData(tx, *this, nOut)) + { + SetNull(); + return false; + } + return true; +} + +bool CFluidMint::UnserializeFromScript(const CScript& fluidScript) { + std::vector vchData; + std::vector vchHash; + if(!GetFluidMintData(fluidScript, *this)) + { + SetNull(); + return false; + } + return true; +} + +void CFluidMint::Serialize(std::vector& vchData) { + CDataStream dsFluidOp(SER_NETWORK, PROTOCOL_VERSION); + dsFluidOp << *this; + vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); +} + +CFluidMintDB::CFluidMintDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-mint", nCacheSize, fMemory, fWipe, obfuscate) +{ +} + +bool CFluidMintDB::AddFluidMintEntry(const CFluidMint& entry, const int op) +{ + bool writeState = false; + { + LOCK(cs_fluid_mint); + writeState = Write(make_pair(std::string("script"), entry.FluidScript), entry) + && Write(make_pair(std::string("txid"), entry.txHash), entry.FluidScript); + } + + return writeState; +} + +bool CFluidMintDB::GetLastFluidMintRecord(CFluidMint& entry) +{ + LOCK(cs_fluid_mint); + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToLast(); + pcursor->GetValue(entry); + return true; +} + +bool CFluidMintDB::GetAllFluidMintRecords(std::vector& entries) +{ + LOCK(cs_fluid_mint); + std::pair > key; + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CFluidMint entry; + try { + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + if (!entry.IsNull()) + { + entries.push_back(entry); + } + } + pcursor->Next(); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +bool CheckFluidMintDB() +{ + if (!pFluidMintDB) + return false; + + return true; +} \ No newline at end of file diff --git a/src/fluid/fluidmint.h b/src/fluid/fluidmint.h new file mode 100644 index 0000000000..6223ff7c70 --- /dev/null +++ b/src/fluid/fluidmint.h @@ -0,0 +1,112 @@ +// Copyright (c) 2017 Duality Blockchain Solutions Developers + +#ifndef FLUID_MINT_H +#define FLUID_MINT_H + +#include "amount.h" +#include "dbwrapper.h" +#include "serialize.h" + +#include "sync.h" +#include "uint256.h" + +class CScript; +class CTransaction; + +class CFluidMint { +public: + static const int CURRENT_VERSION=1; + int nVersion; + std::vector FluidScript; + CAmount MintAmount; + std::vector DestinationAddress; + int64_t nTimeStamp; + std::vector> SovereignAddresses; + uint256 txHash; + unsigned int nHeight; + + CFluidMint() { + SetNull(); + } + + CFluidMint(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + CFluidMint(const CScript& fluidScript) { + SetNull(); + UnserializeFromScript(fluidScript); + } + + inline void SetNull() + { + nVersion = CFluidMint::CURRENT_VERSION; + FluidScript.clear(); + MintAmount = -1; + DestinationAddress.clear(); + nTimeStamp = 0; + SovereignAddresses.clear(); + txHash.SetNull(); + nHeight = 0; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(FluidScript); + READWRITE(MintAmount); + READWRITE(DestinationAddress); + READWRITE(VARINT(nTimeStamp)); + READWRITE(SovereignAddresses); + READWRITE(txHash); + READWRITE(VARINT(nHeight)); + } + + inline friend bool operator==(const CFluidMint& a, const CFluidMint& b) { + return (a.FluidScript == b.FluidScript && a.MintAmount == b.MintAmount && a.DestinationAddress == b.DestinationAddress && a.nTimeStamp == b.nTimeStamp); + } + + inline friend bool operator!=(const CFluidMint& a, const CFluidMint& b) { + return !(a == b); + } + + inline CFluidMint operator=(const CFluidMint& b) { + FluidScript = b.FluidScript; + MintAmount = b.MintAmount; + DestinationAddress = b.DestinationAddress; + nTimeStamp = b.nTimeStamp; + for (const std::vector& vchAddress : b.SovereignAddresses) + { + SovereignAddresses.push_back(vchAddress); + } + txHash = b.txHash; + nHeight = b.nHeight; + return *this; + } + + inline bool IsNull() const { return (nTimeStamp == 0); } + bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromScript(const CScript& fluidScript); + void Serialize(std::vector& vchData); +}; + +static CCriticalSection cs_fluid_mint; + +class CFluidMintDB : public CDBWrapper { +public: + CFluidMintDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); + bool AddFluidMintEntry(const CFluidMint& entry, const int op); + bool GetLastFluidMintRecord(CFluidMint& entry); + bool GetAllFluidMintRecords(std::vector& entries); +}; + +bool GetFluidMintData(const CScript& scriptPubKey, CFluidMint& entry); +bool GetFluidMintData(const CTransaction& tx, CFluidMint& entry, int& nOut); +bool CheckFluidMintDB(); + +extern CFluidMintDB *pFluidMintDB; + +#endif // FLUID_MINT_H \ No newline at end of file diff --git a/src/fluid/rpcfluid.cpp b/src/fluid/rpcfluid.cpp index 97fe90be0b..30dd3a0d34 100644 --- a/src/fluid/rpcfluid.cpp +++ b/src/fluid/rpcfluid.cpp @@ -5,6 +5,8 @@ #include "chain.h" #include "core_io.h" #include "fluiddynode.h" +#include "fluidmining.h" +#include "fluidmint.h" #include "init.h" #include "keepass.h" #include "net.h" @@ -287,7 +289,7 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) "\nReturns raw data about each fluid command confirmed on the Dynamic blockchain.\n" "\nResult:\n" "{ (json array of string)\n" - " \"fluid command\" (string) The operation code and raw fluid script command\n" + " \"fluid_command\" (string) The operation code and raw fluid script command\n" "}, ...\n" "\nExamples\n" + HelpExampleCli("getfluidhistoryraw", "") @@ -295,19 +297,63 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) ); UniValue ret(UniValue::VARR); - GetLastBlockIndex(chainActive.Tip()); - CBlockIndex* pindex = chainActive.Tip(); - //TODO fluid - /* - CFluidEntry fluidIndex = pindex->fluidParams; - std::vector transactionRecord = fluidIndex.fluidHistory; + // load fluid mint transaction history + { + std::vector mintEntries; + if (CheckFluidMintDB) { + if (!pFluidMintDB->GetAllFluidMintRecords(mintEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid mint entries")); + } + } + else { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4001 - " + _("Error opening fluid mint db")); + } - for(const std::string& existingRecord : transactionRecord) { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("fluid command", existingRecord)); - ret.push_back(obj); + for (const CFluidMint& mintEntry : mintEntries) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("fluid_mint_command", StringFromCharVector(mintEntry.FluidScript))); + ret.push_back(obj); + } + } + // load fluid dynode update reward transaction history + { + std::vector dynodeEntries; + if (CheckFluidDynodeDB) { + if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid dynode entries")); + } + } + else { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4001 - " + _("Error opening fluid dynode db")); + } + + for (const CFluidDynode& dynEntry : dynodeEntries) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("fluid_dynode_command", StringFromCharVector(dynEntry.FluidScript))); + ret.push_back(obj); + } + } + // load fluid mining update reward transaction history + { + std::vector miningEntries; + if (CheckFluidMiningDB) { + if (!pFluidMiningDB->GetAllFluidMiningRecords(miningEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4004 - " + _("Error getting fluid mining entries")); + } + } + else { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4005 - " + _("Error opening fluid mining db")); + } + + for (const CFluidMining& miningEntry : miningEntries) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("fluid_mining_command", StringFromCharVector(miningEntry.FluidScript))); + ret.push_back(obj); + } } - */ return ret; } @@ -336,90 +382,118 @@ UniValue getfluidhistory(const JSONRPCRequest& request) ); UniValue ret(UniValue::VARR); - std::vector dynodeEntries; - if (CheckFluidDynodeDB) { - if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid dynode entries")); + CAmount totalMintedCoins = 0; + CAmount totalFluidTxCost = 0; + // load fluid mint transaction history + { + std::vector mintEntries; + if (CheckFluidMintDB) { + if (!pFluidMintDB->GetAllFluidMintRecords(mintEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid mint entries")); + } + } + else { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4001 - " + _("Error opening fluid mint db")); } - } - else { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4001 - " + _("Error opening fluid dynode db")); - } - // load Dynode fluid transaction history - for (const CFluidDynode& dynEntry : dynodeEntries) + for (const CFluidMint& mintEntry : mintEntries) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("operation", "Mint")); + obj.push_back(Pair("amount", mintEntry.MintAmount)); //TODO fluid convert to decimal value + obj.push_back(Pair("timestamp", mintEntry.nTimeStamp)); + obj.push_back(Pair("address_count", mintEntry.SovereignAddresses.size())); + obj.push_back(Pair("destination_address)", StringFromCharVector(mintEntry.DestinationAddress))); + int index = 1; + for (const std::vector& vchAddress : mintEntry.SovereignAddresses) + { + std::string addLabel = "sovereign_address_" + std::to_string(index); + obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); + index ++; + } + ret.push_back(obj); + totalMintedCoins = totalMintedCoins + mintEntry.MintAmount; + totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; + } + } + // load fluid dynode update reward transaction history { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("operation", "Dynode Reward Update")); - obj.push_back(Pair("amount", dynEntry.DynodeReward)); //TODO fluid convert to decimal value - obj.push_back(Pair("timestamp", dynEntry.nTimeStamp)); - obj.push_back(Pair("address_count", dynEntry.SovereignAddresses.size())); - int index = 1; - for (const std::vector& vchAddress : dynEntry.SovereignAddresses) + std::vector dynodeEntries; + if (CheckFluidDynodeDB) { + if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4002 - " + _("Error getting fluid dynode entries")); + } + } + else { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4003 - " + _("Error opening fluid dynode db")); + } + for (const CFluidDynode& dynEntry : dynodeEntries) { - std::string addLabel = "sovereign_address_" + std::to_string(index); - obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); - index ++; + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("operation", "Dynode Reward Update")); + obj.push_back(Pair("amount", dynEntry.DynodeReward)); //TODO fluid convert to decimal value + obj.push_back(Pair("timestamp", dynEntry.nTimeStamp)); + obj.push_back(Pair("address_count", dynEntry.SovereignAddresses.size())); + int index = 1; + for (const std::vector& vchAddress : dynEntry.SovereignAddresses) + { + std::string addLabel = "sovereign_address_" + std::to_string(index); + obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); + index ++; + } + ret.push_back(obj); + totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; } - obj.push_back(Pair("raw", StringFromCharVector(dynEntry.FluidScript))); - ret.push_back(obj); } - //TODO fluid - /* - GetLastBlockIndex(chainActive.Tip()); - CBlockIndex* pindex = chainActive.Tip(); - CFluidEntry fluidIndex = pindex->fluidParams; - std::vector transactionRecord = fluidIndex.fluidHistory; - - - HexFunctions hexConvert; - for (const std::string& existingRecord : transactionRecord) { - UniValue obj(UniValue::VOBJ); - std::string strOperationCode = GetRidOfScriptStatement(existingRecord, 0); - obj.push_back(Pair("operation", strOperationCode)); - std::string verificationWithoutOpCode = GetRidOfScriptStatement(existingRecord); - std::vector splitString; - hexConvert.ConvertToString(verificationWithoutOpCode); - SeparateString(verificationWithoutOpCode, splitString, false); - std::string messageTokenKey = splitString.at(0); - std::vector vecSplitScript; - SeparateFluidOpString(verificationWithoutOpCode, vecSplitScript); - if (vecSplitScript.size() > 1) { - if (strOperationCode == "OP_MINT" && vecSplitScript.size() >= 6) { - std::string strAmount = vecSplitScript[0]; - std::string strTimeStamp = vecSplitScript[1]; - CAmount fluidAmount; - if (ParseFixedPoint(strAmount, 8, &fluidAmount)) { - obj.push_back(Pair("amount", strAmount)); - } - int64_t tokenTimeStamp; - if (ParseInt64(strTimeStamp, &tokenTimeStamp)) { - obj.push_back(Pair("timestamp", tokenTimeStamp)); - } - obj.push_back(Pair("payment address", vecSplitScript[2])); - obj.push_back(Pair("sovereign address 1", fluid.GetAddressFromDigestSignature(vecSplitScript[3], messageTokenKey).ToString())); - obj.push_back(Pair("sovereign address 2", fluid.GetAddressFromDigestSignature(vecSplitScript[4], messageTokenKey).ToString())); - obj.push_back(Pair("sovereign address 3", fluid.GetAddressFromDigestSignature(vecSplitScript[5], messageTokenKey).ToString())); + // load fluid mining update reward transaction history + { + std::vector miningEntries; + if (CheckFluidMiningDB) { + if (!pFluidMiningDB->GetAllFluidMiningRecords(miningEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4004 - " + _("Error getting fluid mining entries")); } - else if ((strOperationCode == "OP_REWARD_MINING" || strOperationCode == "OP_REWARD_DYNODE") && vecSplitScript.size() == 5) { - std::string strAmount = vecSplitScript[0]; - std::string strTimeStamp = vecSplitScript[1]; - CAmount fluidAmount; - if (ParseFixedPoint(strAmount, 8, &fluidAmount)) { - obj.push_back(Pair("amount", strAmount)); - } - int64_t tokenTimeStamp; - if (ParseInt64(strTimeStamp, &tokenTimeStamp)) { - obj.push_back(Pair("timestamp", tokenTimeStamp)); - } - obj.push_back(Pair("sovereign address 1", fluid.GetAddressFromDigestSignature(vecSplitScript[2], messageTokenKey).ToString())); - obj.push_back(Pair("sovereign address 2", fluid.GetAddressFromDigestSignature(vecSplitScript[3], messageTokenKey).ToString())); - obj.push_back(Pair("sovereign address 3", fluid.GetAddressFromDigestSignature(vecSplitScript[4], messageTokenKey).ToString())); + } + else { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4005 - " + _("Error opening fluid mining db")); + } + + for (const CFluidMining& miningEntry : miningEntries) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("operation", "Mining Reward Update")); + obj.push_back(Pair("amount", miningEntry.MiningReward)); //TODO fluid convert to decimal value + obj.push_back(Pair("timestamp", miningEntry.nTimeStamp)); + obj.push_back(Pair("address_count", miningEntry.SovereignAddresses.size())); + int index = 1; + for (const std::vector& vchAddress : miningEntry.SovereignAddresses) + { + std::string addLabel = "sovereign_address_" + std::to_string(index); + obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); + index ++; } + ret.push_back(obj); + totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; } + } + // load fluid transaction summary + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("total_minted", totalMintedCoins)); //TODO fluid convert to decimal value + obj.push_back(Pair("total_fluid_fee_cost", totalFluidTxCost)); //TODO fluid convert to decimal value + CFluidDynode lastDynodeRecord; + if (!pFluidDynodeDB->GetLastFluidDynodeRecord(lastDynodeRecord)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4006 - " + _("Error getting last fluid dynode entry")); + } + obj.push_back(Pair("current_dynode_reward", lastDynodeRecord.DynodeReward)); //TODO fluid convert to decimal value + + CFluidMining lastMiningRecord; + if (!pFluidMiningDB->GetLastFluidMiningRecord(lastMiningRecord)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4007 - " + _("Error getting last fluid mining entry")); + } + obj.push_back(Pair("current_mining_reward", lastMiningRecord.MiningReward)); //TODO fluid convert to decimal value + ret.push_back(obj); } - */ return ret; } diff --git a/src/init.cpp b/src/init.cpp index 0b860e2de4..b5867e5d44 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -25,6 +25,8 @@ #include "dynodeman.h" #include "flat-database.h" #include "fluid/fluiddynode.h" +#include "fluid/fluidmining.h" +#include "fluid/fluidmint.h" #include "governance.h" #include "instantsend.h" #include "httpserver.h" @@ -1480,7 +1482,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) delete pcoinsdbview; delete pcoinscatcher; delete pblocktree; + // Fluid transaction DB's delete pFluidDynodeDB; + delete pFluidMiningDB; + delete pFluidMintDB; // BDAP Services DB's delete pDomainEntryDB; @@ -1490,8 +1495,11 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) pcoinsTip = new CCoinsViewCache(pcoinscatcher); bool obfuscate = false; - // Init Fluid DB's + // Init Fluid transaction DB's pFluidDynodeDB = new CFluidDynodeDB(nTotalCache * 35, false, fReindex, obfuscate); + pFluidMiningDB = new CFluidMiningDB(nTotalCache * 35, false, fReindex, obfuscate); + pFluidMintDB = new CFluidMintDB(nTotalCache * 35, false, fReindex, obfuscate); + // Init BDAP Services DB's pDomainEntryDB = new CDomainEntryDB(nTotalCache * 35, false, fReindex, obfuscate); diff --git a/src/validation.cpp b/src/validation.cpp index 83b0884f3b..bb321304a5 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -18,6 +18,8 @@ #include "dynode-sync.h" #include "fluid/fluid.h" #include "fluid/fluiddynode.h" +#include "fluid/fluidmining.h" +#include "fluid/fluidmint.h" #include "hash.h" #include "init.h" #include "instantsend.h" @@ -2202,6 +2204,16 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd if (CheckFluidDynodeDB) pFluidDynodeDB->AddFluidDynodeEntry(fluidDynode, OP_REWARD_DYNODE); } + else if (OpCode == OP_REWARD_MINING) { + CFluidMining fluidMining(scriptFluid); + if (CheckFluidMiningDB) + pFluidMiningDB->AddFluidMiningEntry(fluidMining, OP_REWARD_MINING); + } + else if (OpCode == OP_MINT) { + CFluidMint fluidMint(scriptFluid); + if (CheckFluidMintDB) + pFluidMintDB->AddFluidMintEntry(fluidMint, OP_MINT); + } } if (fAddressIndex || fSpentIndex) { From 050fb6276085d8dc7e1e1c892b91046e2eb8664b Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 30 Aug 2018 16:47:50 -0500 Subject: [PATCH 0202/1653] [Fluid] Implement new fluid databases --- src/Makefile.am | 2 ++ src/bdap/domainentrydb.cpp | 3 +- src/dynode-payments.cpp | 10 ++----- src/dynode.cpp | 6 ++-- src/fluid/fluid.cpp | 40 ++++++-------------------- src/fluid/fluid.h | 10 ++----- src/fluid/fluiddb.cpp | 50 ++++++++++++++++++++++++++++++++ src/fluid/fluiddb.h | 14 +++++++++ src/fluid/fluiddynode.cpp | 11 +++++-- src/fluid/fluiddynode.h | 2 +- src/fluid/fluidmining.cpp | 11 +++++-- src/fluid/fluidmining.h | 3 +- src/fluid/fluidmint.cpp | 16 ++++++++++- src/fluid/fluidmint.h | 4 ++- src/fluid/rpcfluid.cpp | 59 ++++++++++++++++++-------------------- src/miner.cpp | 29 +++++++++---------- src/validation.cpp | 6 ++-- 17 files changed, 169 insertions(+), 107 deletions(-) create mode 100644 src/fluid/fluiddb.cpp create mode 100644 src/fluid/fluiddb.h diff --git a/src/Makefile.am b/src/Makefile.am index 8743043fd8..3abb1f7bc6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -114,6 +114,7 @@ DYNAMIC_CORE_H = \ dynodeconfig.h \ flat-database.h \ fluid/fluid.h \ + fluid/fluiddb.h \ fluid/fluiddynode.h \ fluid/fluidmining.h \ fluid/fluidmint.h \ @@ -246,6 +247,7 @@ libdynamic_server_a_SOURCES = \ dynodeconfig.cpp \ dynodeman.cpp \ fluid/fluid.cpp \ + fluid/fluiddb.cpp \ fluid/fluiddynode.cpp \ fluid/fluidmining.cpp \ fluid/fluidmint.cpp \ diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index 1a693af315..bd9f224c88 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -100,8 +100,7 @@ bool CDomainEntryDB::RemoveExpired(int& entriesRemoved) { entriesRemoved++; EraseDomainEntry(key.second); - } - + } } else if (pcursor->GetKey(key) && key.first == "txid") { std::vector value; diff --git a/src/dynode-payments.cpp b/src/dynode-payments.cpp index 63d114728e..2b0858d212 100644 --- a/src/dynode-payments.cpp +++ b/src/dynode-payments.cpp @@ -10,7 +10,7 @@ #include "dynode-sync.h" #include "dynodeman.h" #include "policy/fees.h" -#include "fluid/fluid.h" +#include "fluid/fluiddb.h" #include "governance-classes.h" #include "messagesigner.h" #include "netfulfilledman.h" @@ -315,8 +315,7 @@ void CDynodePayments::FillBlockPayee(CMutableTransaction& txNew, int nBlockHeigh // make sure it's not filled yet txoutDynodeRet = CTxOut(); - //TODO fluid - CAmount dynodePayment = GetDynodePayment(true);//getDynodeSubsidyWithOverride(pindexPrev->fluidParams.dynodeReward); + CAmount dynodePayment = GetFluidDynodeReward(); txoutDynodeRet = CTxOut(dynodePayment, payee); txNew.vout.push_back(txoutDynodeRet); @@ -583,10 +582,7 @@ bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew) int nMaxSignatures = 0; std::string strPayeesPossible = ""; - - /* Dirtiest trick in the book */ - //TODO fluid - CAmount nDynodePayment = GetDynodePayment(true); //getDynodeSubsidyWithOverride(chainActive.Tip()->fluidParams.dynodeReward); + CAmount nDynodePayment = GetFluidDynodeReward(); //require at least DNPAYMENTS_SIGNATURES_REQUIRED signatures diff --git a/src/dynode.cpp b/src/dynode.cpp index 311ac370e7..86c22977b3 100644 --- a/src/dynode.cpp +++ b/src/dynode.cpp @@ -11,7 +11,7 @@ #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeman.h" -#include "fluid/fluid.h" +#include "fluid/fluiddb.h" #include "init.h" #include "messagesigner.h" #include "netbase.h" @@ -301,8 +301,8 @@ void CDynode::UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack CBlock block; if(!ReadBlockFromDisk(block, BlockReading, Params().GetConsensus())) // shouldn't really happen continue; - //TODO fluid. - CAmount nDynodePayment = GetDynodePayment(true); //getDynodeSubsidyWithOverride(BlockReading->fluidParams.dynodeReward); + + CAmount nDynodePayment = GetFluidDynodeReward(); BOOST_FOREACH(CTxOut txout, block.vtx[0].vout) if(dnpayee == txout.scriptPubKey && nDynodePayment == txout.nValue) { diff --git a/src/fluid/fluid.cpp b/src/fluid/fluid.cpp index 1ba7bb3d79..05c2f4cb7c 100644 --- a/src/fluid/fluid.cpp +++ b/src/fluid/fluid.cpp @@ -575,61 +575,39 @@ bool CFluid::InsertTransactionToRecord(CScript fluidInstruction, std::vector= 1 && chainActive.Height() <= Params().GetConsensus().nRewardsStart) { - LogPrint("zero-reward block creation", "GetPoWBlockPayment() : create=%s nSubsidy=%d\n", FormatMoney(BLOCKCHAIN_INIT_REWARD), BLOCKCHAIN_INIT_REWARD); + LogPrint("zero-reward block creation", "GetStandardPoWBlockPayment() : create=%s nSubsidy=%d\n", FormatMoney(BLOCKCHAIN_INIT_REWARD), BLOCKCHAIN_INIT_REWARD); return BLOCKCHAIN_INIT_REWARD; // Burn transaction fees } else if (chainActive.Height() > Params().GetConsensus().nRewardsStart) { - LogPrint("creation", "GetPoWBlockPayment() : create=%s PoW Reward=%d\n", FormatMoney(PHASE_1_POW_REWARD), PHASE_1_POW_REWARD); + LogPrint("creation", "GetStandardPoWBlockPayment() : create=%s PoW Reward=%d\n", FormatMoney(PHASE_1_POW_REWARD), PHASE_1_POW_REWARD); return PHASE_1_POW_REWARD; // 1 DYN and burn transaction fees } else return BLOCKCHAIN_INIT_REWARD; // Burn transaction fees } -CAmount GetDynodePayment(bool fDynode) +CAmount GetStandardDynodePayment() { - if (fDynode && chainActive.Height() > Params().GetConsensus().nDynodePaymentsStartBlock && chainActive.Height() < Params().GetConsensus().nUpdateDiffAlgoHeight) { - LogPrint("creation", "GetDynodePayment() : create=%s DN Payment=%d\n", FormatMoney(PHASE_1_DYNODE_PAYMENT), PHASE_1_DYNODE_PAYMENT); + if (chainActive.Height() > Params().GetConsensus().nDynodePaymentsStartBlock && chainActive.Height() < Params().GetConsensus().nUpdateDiffAlgoHeight) { + LogPrint("creation", "GetStandardDynodePayment() : create=%s DN Payment=%d\n", FormatMoney(PHASE_1_DYNODE_PAYMENT), PHASE_1_DYNODE_PAYMENT); return PHASE_1_DYNODE_PAYMENT; // 0.382 DYN } - else if (fDynode && chainActive.Height() > Params().GetConsensus().nDynodePaymentsStartBlock && chainActive.Height() >= Params().GetConsensus().nUpdateDiffAlgoHeight) { - LogPrint("creation", "GetDynodePayment() : create=%s DN Payment=%d\n", FormatMoney(PHASE_2_DYNODE_PAYMENT), PHASE_2_DYNODE_PAYMENT); + else if (chainActive.Height() > Params().GetConsensus().nDynodePaymentsStartBlock && chainActive.Height() >= Params().GetConsensus().nUpdateDiffAlgoHeight) { + LogPrint("creation", "GetStandardDynodePayment() : create=%s DN Payment=%d\n", FormatMoney(PHASE_2_DYNODE_PAYMENT), PHASE_2_DYNODE_PAYMENT); return PHASE_2_DYNODE_PAYMENT; // 1.618 DYN } - else if ((fDynode && !fDynode) && chainActive.Height() <= Params().GetConsensus().nDynodePaymentsStartBlock) { - LogPrint("creation", "GetDynodePayment() : create=%s DN Payment=%d\n", FormatMoney(BLOCKCHAIN_INIT_REWARD), BLOCKCHAIN_INIT_REWARD); - return BLOCKCHAIN_INIT_REWARD; - } else return BLOCKCHAIN_INIT_REWARD; } -/** Passover code that will act as a switch to check if override did occur for Proof of Work Rewards **/ -CAmount getBlockSubsidyWithOverride(const int& nHeight, CAmount lastOverrideCommand) { - if (lastOverrideCommand != 0) { - return lastOverrideCommand; - } else { - return GetPoWBlockPayment(nHeight); - } -} - -/** Passover code that will act as a switch to check if override did occur for Dynode Rewards **/ -CAmount getDynodeSubsidyWithOverride(CAmount lastOverrideCommand, bool fDynode) { - if (lastOverrideCommand != 0) { - return lastOverrideCommand; - } else { - return GetDynodePayment(fDynode); - } -} - bool CFluid::ValidationProcesses(CValidationState& state, CScript txOut, CAmount txValue) { std::string message; CAmount mintAmount; diff --git a/src/fluid/fluid.h b/src/fluid/fluid.h index 37a744c682..6c601afc40 100644 --- a/src/fluid/fluid.h +++ b/src/fluid/fluid.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Duality Blockchain Solutions Developers +// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers #ifndef FLUID_PROTOCOL_H #define FLUID_PROTOCOL_H @@ -77,12 +77,8 @@ class CFluid : public CFluidParameters, public COperations { }; /** Standard Reward Payment Determination Functions */ -CAmount GetPoWBlockPayment(const int& nHeight); -CAmount GetDynodePayment(bool fDynode = true); - -/** Override Logic Switch for Reward Payment Determination Functions */ -CAmount getBlockSubsidyWithOverride(const int& nHeight, CAmount lastOverrideCommand); -CAmount getDynodeSubsidyWithOverride(CAmount lastOverrideCommand, bool fDynode = true); +CAmount GetStandardPoWBlockPayment(); +CAmount GetStandardDynodePayment(); void BuildFluidInformationIndex(CBlockIndex* pindex, CAmount &nExpectedBlockValue, bool fDynodePaid); bool IsTransactionFluid(const CScript& txOut); diff --git a/src/fluid/fluiddb.cpp b/src/fluid/fluiddb.cpp new file mode 100644 index 0000000000..cff84cc8b5 --- /dev/null +++ b/src/fluid/fluiddb.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers + +#include "fluiddb.h" + +#include "fluid.h" +#include "fluiddynode.h" +#include "fluidmining.h" +#include "fluidmint.h" + +CAmount GetFluidDynodeReward() +{ + if (!CheckFluidDynodeDB()) + return GetStandardDynodePayment(); + + CFluidDynode lastDynodeRecord; + if (!pFluidDynodeDB->GetLastFluidDynodeRecord(lastDynodeRecord)) { + return GetStandardDynodePayment(); + } + return lastDynodeRecord.DynodeReward; +} + +CAmount GetFluidMiningReward() +{ + if (!CheckFluidMiningDB()) + return GetStandardPoWBlockPayment(); + + CFluidMining lastMiningRecord; + if (!pFluidMiningDB->GetLastFluidMiningRecord(lastMiningRecord)) { + return GetStandardPoWBlockPayment(); + } + return lastMiningRecord.MiningReward; +} + +bool GetMintingInstructions(const int nHeight, CFluidMint& fluidMint) +{ + if (!CheckFluidMintDB()) + return false; + + CFluidMint getFluidMint; + if (!pFluidMintDB->GetLastFluidMintRecord(getFluidMint)) { + return false; + } + + if ((int)getFluidMint.nHeight == (nHeight -1)) + { + fluidMint = getFluidMint; + return true; + } + return false; +} \ No newline at end of file diff --git a/src/fluid/fluiddb.h b/src/fluid/fluiddb.h new file mode 100644 index 0000000000..41cc8c856a --- /dev/null +++ b/src/fluid/fluiddb.h @@ -0,0 +1,14 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers + +#ifndef FLUID_DB_H +#define FLUID_DB_H + +#include "amount.h" + +class CFluidMint; + +CAmount GetFluidDynodeReward(); +CAmount GetFluidMiningReward(); +bool GetMintingInstructions(const int nHeight, CFluidMint& fluidMint); + +#endif // FLUID_DYNODE_H diff --git a/src/fluid/fluiddynode.cpp b/src/fluid/fluiddynode.cpp index 0915584a53..a5a3e4f158 100644 --- a/src/fluid/fluiddynode.cpp +++ b/src/fluid/fluiddynode.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Duality Blockchain Solutions Developers +// Copyright (c) 2018 Duality Blockchain Solutions Developers #include "fluiddynode.h" @@ -114,7 +114,14 @@ bool CFluidDynodeDB::GetLastFluidDynodeRecord(CFluidDynode& entry) LOCK(cs_fluid_dynode); std::unique_ptr pcursor(NewIterator()); pcursor->SeekToLast(); - pcursor->GetValue(entry); + if (pcursor->Valid()) { + try { + pcursor->GetValue(entry); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } return true; } diff --git a/src/fluid/fluiddynode.h b/src/fluid/fluiddynode.h index 97f06bf9f0..1feba2d6ab 100644 --- a/src/fluid/fluiddynode.h +++ b/src/fluid/fluiddynode.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Duality Blockchain Solutions Developers +// Copyright (c) 2018 Duality Blockchain Solutions Developers #ifndef FLUID_DYNODE_H #define FLUID_DYNODE_H diff --git a/src/fluid/fluidmining.cpp b/src/fluid/fluidmining.cpp index 5683bd2b05..bacb796463 100644 --- a/src/fluid/fluidmining.cpp +++ b/src/fluid/fluidmining.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Duality Blockchain Solutions Developers +// Copyright (c) 2018 Duality Blockchain Solutions Developers #include "fluidmining.h" @@ -114,7 +114,14 @@ bool CFluidMiningDB::GetLastFluidMiningRecord(CFluidMining& entry) LOCK(cs_fluid_mining); std::unique_ptr pcursor(NewIterator()); pcursor->SeekToLast(); - pcursor->GetValue(entry); + if (pcursor->Valid()) { + try { + pcursor->GetValue(entry); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } return true; } diff --git a/src/fluid/fluidmining.h b/src/fluid/fluidmining.h index c2d507db84..c32312d14e 100644 --- a/src/fluid/fluidmining.h +++ b/src/fluid/fluidmining.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Duality Blockchain Solutions Developers +// Copyright (c) 2018 Duality Blockchain Solutions Developers #ifndef FLUID_MINER #define FLUID_MINER @@ -102,6 +102,7 @@ class CFluidMiningDB : public CDBWrapper { bool GetFluidMiningData(const CScript& scriptPubKey, CFluidMining& entry); bool GetFluidMiningData(const CTransaction& tx, CFluidMining& entry, int& nOut); bool CheckFluidMiningDB(); +CAmount GetFluidMiningReward(); extern CFluidMiningDB *pFluidMiningDB; diff --git a/src/fluid/fluidmint.cpp b/src/fluid/fluidmint.cpp index 3927507915..e33278ec8a 100644 --- a/src/fluid/fluidmint.cpp +++ b/src/fluid/fluidmint.cpp @@ -3,6 +3,7 @@ #include "fluidmint.h" +#include "base58.h" #include "core_io.h" #include "fluid.h" #include "operations.h" @@ -96,6 +97,11 @@ void CFluidMint::Serialize(std::vector& vchData) { vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); } +CDynamicAddress CFluidMint::GetDestinationAddress() const +{ + return CDynamicAddress(StringFromCharVector(DestinationAddress)); +} + CFluidMintDB::CFluidMintDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-mint", nCacheSize, fMemory, fWipe, obfuscate) { } @@ -117,7 +123,15 @@ bool CFluidMintDB::GetLastFluidMintRecord(CFluidMint& entry) LOCK(cs_fluid_mint); std::unique_ptr pcursor(NewIterator()); pcursor->SeekToLast(); - pcursor->GetValue(entry); + if (pcursor->Valid()) { + try { + pcursor->GetValue(entry); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + LogPrintf("GetLastFluidMintRecord 4\n"); return true; } diff --git a/src/fluid/fluidmint.h b/src/fluid/fluidmint.h index 6223ff7c70..cdb0298b06 100644 --- a/src/fluid/fluidmint.h +++ b/src/fluid/fluidmint.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Duality Blockchain Solutions Developers +// Copyright (c) 2018 Duality Blockchain Solutions Developers #ifndef FLUID_MINT_H #define FLUID_MINT_H @@ -10,6 +10,7 @@ #include "sync.h" #include "uint256.h" +class CDynamicAddress; class CScript; class CTransaction; @@ -91,6 +92,7 @@ class CFluidMint { bool UnserializeFromTx(const CTransaction& tx); bool UnserializeFromScript(const CScript& fluidScript); void Serialize(std::vector& vchData); + CDynamicAddress GetDestinationAddress() const; }; static CCriticalSection cs_fluid_mint; diff --git a/src/fluid/rpcfluid.cpp b/src/fluid/rpcfluid.cpp index 30dd3a0d34..6091b1a91a 100644 --- a/src/fluid/rpcfluid.cpp +++ b/src/fluid/rpcfluid.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Duality Blockchain Solutions Developers +// Copyright (c) 2017-2018 Duality Blockchain Solutions Developers #include "fluid.h" @@ -296,11 +296,11 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) + HelpExampleRpc("getfluidhistoryraw", "") ); - UniValue ret(UniValue::VARR); + UniValue ret(UniValue::VOBJ); // load fluid mint transaction history { std::vector mintEntries; - if (CheckFluidMintDB) { + if (CheckFluidMintDB()) { if (!pFluidMintDB->GetAllFluidMintRecords(mintEntries)) { throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid mint entries")); } @@ -312,14 +312,14 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) for (const CFluidMint& mintEntry : mintEntries) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("fluid_mint_command", StringFromCharVector(mintEntry.FluidScript))); - ret.push_back(obj); + obj.push_back(Pair("raw_script", StringFromCharVector(mintEntry.FluidScript))); + ret.push_back(Pair("mint", obj)); } } // load fluid dynode update reward transaction history { std::vector dynodeEntries; - if (CheckFluidDynodeDB) { + if (CheckFluidDynodeDB()) { if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid dynode entries")); } @@ -331,14 +331,14 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) for (const CFluidDynode& dynEntry : dynodeEntries) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("fluid_dynode_command", StringFromCharVector(dynEntry.FluidScript))); - ret.push_back(obj); + obj.push_back(Pair("raw_script", StringFromCharVector(dynEntry.FluidScript))); + ret.push_back(Pair("dynode", obj)); } } // load fluid mining update reward transaction history { std::vector miningEntries; - if (CheckFluidMiningDB) { + if (CheckFluidMiningDB()) { if (!pFluidMiningDB->GetAllFluidMiningRecords(miningEntries)) { throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4004 - " + _("Error getting fluid mining entries")); } @@ -350,8 +350,8 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) for (const CFluidMining& miningEntry : miningEntries) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("fluid_mining_command", StringFromCharVector(miningEntry.FluidScript))); - ret.push_back(obj); + obj.push_back(Pair("raw_script", StringFromCharVector(miningEntry.FluidScript))); + ret.push_back(Pair("miner", obj)); } } return ret; @@ -381,13 +381,13 @@ UniValue getfluidhistory(const JSONRPCRequest& request) + HelpExampleRpc("getfluidhistory", "") ); - UniValue ret(UniValue::VARR); + UniValue ret(UniValue::VOBJ); CAmount totalMintedCoins = 0; CAmount totalFluidTxCost = 0; // load fluid mint transaction history { std::vector mintEntries; - if (CheckFluidMintDB) { + if (CheckFluidMintDB()) { if (!pFluidMintDB->GetAllFluidMintRecords(mintEntries)) { throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid mint entries")); } @@ -400,9 +400,8 @@ UniValue getfluidhistory(const JSONRPCRequest& request) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("operation", "Mint")); - obj.push_back(Pair("amount", mintEntry.MintAmount)); //TODO fluid convert to decimal value + obj.push_back(Pair("amount", FormatMoney(mintEntry.MintAmount))); obj.push_back(Pair("timestamp", mintEntry.nTimeStamp)); - obj.push_back(Pair("address_count", mintEntry.SovereignAddresses.size())); obj.push_back(Pair("destination_address)", StringFromCharVector(mintEntry.DestinationAddress))); int index = 1; for (const std::vector& vchAddress : mintEntry.SovereignAddresses) @@ -411,7 +410,7 @@ UniValue getfluidhistory(const JSONRPCRequest& request) obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); index ++; } - ret.push_back(obj); + ret.push_back(Pair("mint", obj)); totalMintedCoins = totalMintedCoins + mintEntry.MintAmount; totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; } @@ -419,7 +418,7 @@ UniValue getfluidhistory(const JSONRPCRequest& request) // load fluid dynode update reward transaction history { std::vector dynodeEntries; - if (CheckFluidDynodeDB) { + if (CheckFluidDynodeDB()) { if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4002 - " + _("Error getting fluid dynode entries")); } @@ -431,9 +430,8 @@ UniValue getfluidhistory(const JSONRPCRequest& request) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("operation", "Dynode Reward Update")); - obj.push_back(Pair("amount", dynEntry.DynodeReward)); //TODO fluid convert to decimal value + obj.push_back(Pair("amount", FormatMoney(dynEntry.DynodeReward))); obj.push_back(Pair("timestamp", dynEntry.nTimeStamp)); - obj.push_back(Pair("address_count", dynEntry.SovereignAddresses.size())); int index = 1; for (const std::vector& vchAddress : dynEntry.SovereignAddresses) { @@ -441,14 +439,14 @@ UniValue getfluidhistory(const JSONRPCRequest& request) obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); index ++; } - ret.push_back(obj); + ret.push_back(Pair("dynode", obj)); totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; } } // load fluid mining update reward transaction history { std::vector miningEntries; - if (CheckFluidMiningDB) { + if (CheckFluidMiningDB()) { if (!pFluidMiningDB->GetAllFluidMiningRecords(miningEntries)) { throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4004 - " + _("Error getting fluid mining entries")); } @@ -461,9 +459,8 @@ UniValue getfluidhistory(const JSONRPCRequest& request) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("operation", "Mining Reward Update")); - obj.push_back(Pair("amount", miningEntry.MiningReward)); //TODO fluid convert to decimal value + obj.push_back(Pair("amount", FormatMoney(miningEntry.MiningReward))); obj.push_back(Pair("timestamp", miningEntry.nTimeStamp)); - obj.push_back(Pair("address_count", miningEntry.SovereignAddresses.size())); int index = 1; for (const std::vector& vchAddress : miningEntry.SovereignAddresses) { @@ -471,28 +468,27 @@ UniValue getfluidhistory(const JSONRPCRequest& request) obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); index ++; } - ret.push_back(obj); + ret.push_back(Pair("miner", obj)); totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; } } // load fluid transaction summary { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("total_minted", totalMintedCoins)); //TODO fluid convert to decimal value - obj.push_back(Pair("total_fluid_fee_cost", totalFluidTxCost)); //TODO fluid convert to decimal value + obj.push_back(Pair("total_minted", FormatMoney(totalMintedCoins))); + obj.push_back(Pair("total_fluid_fee_cost", FormatMoney(totalFluidTxCost))); CFluidDynode lastDynodeRecord; if (!pFluidDynodeDB->GetLastFluidDynodeRecord(lastDynodeRecord)) { throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4006 - " + _("Error getting last fluid dynode entry")); } - obj.push_back(Pair("current_dynode_reward", lastDynodeRecord.DynodeReward)); //TODO fluid convert to decimal value + obj.push_back(Pair("current_dynode_reward", FormatMoney(lastDynodeRecord.DynodeReward))); CFluidMining lastMiningRecord; if (!pFluidMiningDB->GetLastFluidMiningRecord(lastMiningRecord)) { throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4007 - " + _("Error getting last fluid mining entry")); } - obj.push_back(Pair("current_mining_reward", lastMiningRecord.MiningReward)); //TODO fluid convert to decimal value - - ret.push_back(obj); + obj.push_back(Pair("current_mining_reward", FormatMoney(lastMiningRecord.MiningReward))); + ret.push_back(Pair("summary", obj)); } return ret; } @@ -512,7 +508,8 @@ UniValue getfluidsovereigns(const JSONRPCRequest& request) + HelpExampleRpc("getfluidsovereigns", "") ); - UniValue ret(UniValue::VARR); + UniValue ret(UniValue::VOBJ); + //TODO fluid /* GetLastBlockIndex(chainActive.Tip()); CBlockIndex* pindex = chainActive.Tip(); diff --git a/src/miner.cpp b/src/miner.cpp index 666c8c9dbf..6a9f782957 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -14,6 +14,8 @@ #include "consensus/consensus.h" #include "dynode-payments.h" #include "dynode-sync.h" +#include "fluid/fluiddb.h" +#include "fluid/fluidmint.h" #include "governance-classes.h" #include "hash.h" #include "validation.h" @@ -318,20 +320,19 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, } //TODO fluid + CAmount blockReward = GetFluidMiningReward(); + CDynamicAddress mintAddress; CAmount fluidIssuance = 0; - CAmount blockReward = getBlockSubsidyWithOverride(nHeight, 0); - CDynamicAddress address; - /* - CAmount fluidIssuance; - CAmount blockReward = getBlockSubsidyWithOverride(nHeight, prevFluidIndex.blockReward); - CFluidEntry prevFluidIndex = pindexPrev->fluidParams; - */ - bool areWeMinting = false; //fluid.GetMintingInstructions(pindexPrev, address, fluidIssuance); + CFluidMint fluidMint; + bool areWeMinting = GetMintingInstructions(nHeight, fluidMint); // Compute regular coinbase transaction. txNew.vout[0].scriptPubKey = scriptPubKeyIn; - if (areWeMinting) { + if (areWeMinting) + { + mintAddress = fluidMint.GetDestinationAddress(); + fluidIssuance = fluidMint.MintAmount; txNew.vout[0].nValue = blockReward + fluidIssuance; } else { txNew.vout[0].nValue = blockReward; @@ -340,19 +341,17 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; CScript script; - //TODO fluid if (areWeMinting) { // Pick out the amount of issuance txNew.vout[0].nValue -= fluidIssuance; - assert(address.IsValid()); - if (!address.IsScript()) { - script = GetScriptForDestination(address.Get()); + assert(mintAddress.IsValid()); + if (!mintAddress.IsScript()) { + script = GetScriptForDestination(mintAddress.Get()); } else { - CScriptID fluidScriptID = boost::get(address.Get()); + CScriptID fluidScriptID = boost::get(mintAddress.Get()); script = CScript() << OP_HASH160 << ToByteVector(fluidScriptID) << OP_EQUAL; } - txNew.vout.push_back(CTxOut(fluidIssuance, script)); LogPrintf("CreateNewBlock(): Generated Fluid Issuance Transaction:\n%s\n", txNew.ToString()); } diff --git a/src/validation.cpp b/src/validation.cpp index bb321304a5..49f7cc9052 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2201,17 +2201,17 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd int OpCode = GetFluidOpCode(scriptFluid); if (OpCode == OP_REWARD_DYNODE) { CFluidDynode fluidDynode(scriptFluid); - if (CheckFluidDynodeDB) + if (CheckFluidDynodeDB()) pFluidDynodeDB->AddFluidDynodeEntry(fluidDynode, OP_REWARD_DYNODE); } else if (OpCode == OP_REWARD_MINING) { CFluidMining fluidMining(scriptFluid); - if (CheckFluidMiningDB) + if (CheckFluidMiningDB()) pFluidMiningDB->AddFluidMiningEntry(fluidMining, OP_REWARD_MINING); } else if (OpCode == OP_MINT) { CFluidMint fluidMint(scriptFluid); - if (CheckFluidMintDB) + if (CheckFluidMintDB()) pFluidMintDB->AddFluidMintEntry(fluidMint, OP_MINT); } } From 422b120fa0f1e725ed0c823d407a07db6f3cbf6e Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 31 Aug 2018 03:51:56 -0500 Subject: [PATCH 0203/1653] [Fluid] Fix get fluid sovereigns RPC --- src/Makefile.am | 2 + src/fluid/fluid.cpp | 10 ++ src/fluid/fluid.h | 1 + src/fluid/fluiddb.cpp | 21 ++-- src/fluid/fluidsovereign.cpp | 193 +++++++++++++++++++++++++++++++++++ src/fluid/fluidsovereign.h | 106 +++++++++++++++++++ src/fluid/rpcfluid.cpp | 44 +++++--- src/init.cpp | 3 + 8 files changed, 357 insertions(+), 23 deletions(-) create mode 100644 src/fluid/fluidsovereign.cpp create mode 100644 src/fluid/fluidsovereign.h diff --git a/src/Makefile.am b/src/Makefile.am index 3abb1f7bc6..28bd44e88b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -118,6 +118,7 @@ DYNAMIC_CORE_H = \ fluid/fluiddynode.h \ fluid/fluidmining.h \ fluid/fluidmint.h \ + fluid/fluidsovereign.h \ governance.h \ governance-classes.h \ governance-exceptions.h \ @@ -252,6 +253,7 @@ libdynamic_server_a_SOURCES = \ fluid/fluidmining.cpp \ fluid/fluidmint.cpp \ fluid/rpcfluid.cpp \ + fluid/fluidsovereign.cpp \ governance.cpp \ governance-classes.cpp \ governance-object.cpp \ diff --git a/src/fluid/fluid.cpp b/src/fluid/fluid.cpp index 05c2f4cb7c..b46a6fc0c1 100644 --- a/src/fluid/fluid.cpp +++ b/src/fluid/fluid.cpp @@ -126,6 +126,16 @@ std::vector CFluidParameters::InitialiseAddresses() { return initialSovereignAddresses; } +std::vector> CFluidParameters::InitialiseAddressCharVector() +{ + std::vector> initialSovereignAddresses; + std::vector> fluidIdentities = InitialiseSovereignIdentities(); + for (const std::pair& sovereignId : fluidIdentities) { + initialSovereignAddresses.push_back(CharVectorFromString(sovereignId.second.ToString())); + } + return initialSovereignAddresses; +} + /** Checks fluid transactoin operation script amount for invalid values. */ bool CFluid::CheckFluidOperationScript(const CScript& fluidScriptPubKey, const int64_t timeStamp, std::string& errorMessage, bool fSkipTimeStampCheck) { std::string strFluidOpScript = ScriptToAsmStr(fluidScriptPubKey); diff --git a/src/fluid/fluid.h b/src/fluid/fluid.h index 6c601afc40..f341957ea8 100644 --- a/src/fluid/fluid.h +++ b/src/fluid/fluid.h @@ -36,6 +36,7 @@ class CFluidParameters { std::vector> InitialiseSovereignIdentities(); std::vector InitialiseAddresses(); + std::vector> InitialiseAddressCharVector(); }; std::vector InitialiseAddresses(); diff --git a/src/fluid/fluiddb.cpp b/src/fluid/fluiddb.cpp index cff84cc8b5..902dab1af3 100644 --- a/src/fluid/fluiddb.cpp +++ b/src/fluid/fluiddb.cpp @@ -6,6 +6,7 @@ #include "fluiddynode.h" #include "fluidmining.h" #include "fluidmint.h" +#include "fluidsovereign.h" CAmount GetFluidDynodeReward() { @@ -14,7 +15,7 @@ CAmount GetFluidDynodeReward() CFluidDynode lastDynodeRecord; if (!pFluidDynodeDB->GetLastFluidDynodeRecord(lastDynodeRecord)) { - return GetStandardDynodePayment(); + return GetStandardDynodePayment(); } return lastDynodeRecord.DynodeReward; } @@ -26,7 +27,7 @@ CAmount GetFluidMiningReward() CFluidMining lastMiningRecord; if (!pFluidMiningDB->GetLastFluidMiningRecord(lastMiningRecord)) { - return GetStandardPoWBlockPayment(); + return GetStandardPoWBlockPayment(); } return lastMiningRecord.MiningReward; } @@ -35,16 +36,16 @@ bool GetMintingInstructions(const int nHeight, CFluidMint& fluidMint) { if (!CheckFluidMintDB()) return false; - - CFluidMint getFluidMint; + + CFluidMint getFluidMint; if (!pFluidMintDB->GetLastFluidMintRecord(getFluidMint)) { return false; } - - if ((int)getFluidMint.nHeight == (nHeight -1)) - { - fluidMint = getFluidMint; - return true; - } + + if ((int)getFluidMint.nHeight == (nHeight -1)) + { + fluidMint = getFluidMint; + return true; + } return false; } \ No newline at end of file diff --git a/src/fluid/fluidsovereign.cpp b/src/fluid/fluidsovereign.cpp new file mode 100644 index 0000000000..810b7320ba --- /dev/null +++ b/src/fluid/fluidsovereign.cpp @@ -0,0 +1,193 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers + + +#include "fluidsovereign.h" + +#include "core_io.h" +#include "fluid.h" +#include "operations.h" +#include "script/script.h" + +CFluidSovereignDB *pFluidSovereignDB = NULL; + +bool GetFluidSovereignData(const CScript& scriptPubKey, CFluidSovereign& entry) +{ + std::string fluidOperationString = ScriptToAsmStr(scriptPubKey); + std::string strOperationCode = GetRidOfScriptStatement(fluidOperationString, 0); + std::string verificationWithoutOpCode = GetRidOfScriptStatement(fluidOperationString); + std::vector splitString; + HexFunctions hexConvert; + hexConvert.ConvertToString(verificationWithoutOpCode); + SeparateString(verificationWithoutOpCode, splitString, false); + std::string messageTokenKey = splitString.at(0); + std::vector vecSplitScript; + SeparateFluidOpString(verificationWithoutOpCode, vecSplitScript); + + if (vecSplitScript.size() == 5 && strOperationCode == "OP_SWAP_SOVEREIGN_ADDRESS") { + std::vector vchFluidOperation = CharVectorFromString(fluidOperationString); + entry.FluidScript.insert(entry.FluidScript.end(), vchFluidOperation.begin(), vchFluidOperation.end()); + entry.SovereignAddresses.clear(); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[0], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[1], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[2], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[3], messageTokenKey).ToString())); + entry.SovereignAddresses.push_back(CharVectorFromString(fluid.GetAddressFromDigestSignature(vecSplitScript[4], messageTokenKey).ToString())); + std::string strTimeStamp = vecSplitScript[5]; + int64_t tokenTimeStamp; + if (ParseInt64(strTimeStamp, &tokenTimeStamp)) { + entry.nTimeStamp = tokenTimeStamp; + } + return true; + } + return false; +} + +bool GetFluidSovereignData(const CTransaction& tx, CFluidSovereign& entry, int& nOut) +{ + int n = 0; + for (const CTxOut& txout : tx.vout) { + CScript txOut = txout.scriptPubKey; + if (IsTransactionFluid(txOut)) { + nOut = n; + return GetFluidSovereignData(txOut, entry); + } + n++; + } + return false; +} + +bool CFluidSovereign::UnserializeFromTx(const CTransaction& tx) { + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetFluidSovereignData(tx, *this, nOut)) + { + SetNull(); + return false; + } + return true; +} + +bool CFluidSovereign::UnserializeFromScript(const CScript& fluidScript) { + std::vector vchData; + std::vector vchHash; + if(!GetFluidSovereignData(fluidScript, *this)) + { + SetNull(); + return false; + } + return true; +} + +void CFluidSovereign::Serialize(std::vector& vchData) { + CDataStream dsFluidOp(SER_NETWORK, PROTOCOL_VERSION); + dsFluidOp << *this; + vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); +} + +CFluidSovereignDB::CFluidSovereignDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-sovereign", nCacheSize, fMemory, fWipe, obfuscate) +{ + InitEmpty(); +} + +void CFluidSovereignDB::InitEmpty() +{ + if (IsEmpty()) { + LOCK(cs_fluid_sovereign); + CFluidParameters initSovereign; + std::vector> vchAddresses = initSovereign.InitialiseAddressCharVector(); + CFluidSovereign fluidSovereign; + for (const std::vector& sovereignId : vchAddresses) { + fluidSovereign.SovereignAddresses.push_back(sovereignId); + } + fluidSovereign.FluidScript = CharVectorFromString("init sovereign"); + fluidSovereign.nTimeStamp = 1; + if (!AddFluidSovereignEntry(fluidSovereign)) + { + LogPrintf("CFluidSovereignDB::InitEmpty add failed.\n"); + } + } +} + +bool CFluidSovereignDB::AddFluidSovereignEntry(const CFluidSovereign& entry) +{ + bool writeState = false; + { + LOCK(cs_fluid_sovereign); + writeState = Write(make_pair(std::string("script"), entry.FluidScript), entry) + && Write(make_pair(std::string("txid"), entry.txHash), entry.FluidScript); + } + return writeState; +} + +bool CFluidSovereignDB::GetLastFluidSovereignRecord(CFluidSovereign& entry) +{ + LOCK(cs_fluid_sovereign); + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToLast(); + if (pcursor->Valid()) { + try { + pcursor->GetValue(entry); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +bool CFluidSovereignDB::GetAllFluidSovereignRecords(std::vector& entries) +{ + LOCK(cs_fluid_sovereign); + std::pair > key; + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CFluidSovereign entry; + try { + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + if (!entry.IsNull()) + { + entries.push_back(entry); + } + } + pcursor->Next(); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; +} + +bool CFluidSovereignDB::IsEmpty() +{ + LOCK(cs_fluid_sovereign); + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + if (pcursor->Valid()) { + CFluidSovereign entry; + try { + std::pair > key; + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + } + pcursor->Next(); + } + catch (std::exception& e) { + return true; + } + return false; + } + return true; +} + +bool CheckFluidSovereignDB() +{ + if (!pFluidSovereignDB) + return false; + + return true; +} \ No newline at end of file diff --git a/src/fluid/fluidsovereign.h b/src/fluid/fluidsovereign.h new file mode 100644 index 0000000000..b7627a284b --- /dev/null +++ b/src/fluid/fluidsovereign.h @@ -0,0 +1,106 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers + +#ifndef FLUID_SOVEREIGN_H +#define FLUID_SOVEREIGN_H + +#include "amount.h" +#include "dbwrapper.h" +#include "serialize.h" + +#include "sync.h" +#include "uint256.h" + +class CScript; +class CTransaction; + +class CFluidSovereign { +public: + static const int CURRENT_VERSION=1; + int nVersion; + std::vector FluidScript; + int64_t nTimeStamp; + std::vector> SovereignAddresses; + uint256 txHash; + unsigned int nHeight; + + CFluidSovereign() { + SetNull(); + } + + CFluidSovereign(const CTransaction& tx) { + SetNull(); + UnserializeFromTx(tx); + } + + CFluidSovereign(const CScript& fluidScript) { + SetNull(); + UnserializeFromScript(fluidScript); + } + + inline void SetNull() + { + nVersion = CFluidSovereign::CURRENT_VERSION; + FluidScript.clear(); + nTimeStamp = 0; + SovereignAddresses.clear(); + txHash.SetNull(); + nHeight = 0; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(FluidScript); + READWRITE(VARINT(nTimeStamp)); + READWRITE(SovereignAddresses); + READWRITE(txHash); + READWRITE(VARINT(nHeight)); + } + + inline friend bool operator==(const CFluidSovereign& a, const CFluidSovereign& b) { + return (a.FluidScript == b.FluidScript && a.SovereignAddresses == b.SovereignAddresses && a.nTimeStamp == b.nTimeStamp); + } + + inline friend bool operator!=(const CFluidSovereign& a, const CFluidSovereign& b) { + return !(a == b); + } + + inline CFluidSovereign operator=(const CFluidSovereign& b) { + FluidScript = b.FluidScript; + nTimeStamp = b.nTimeStamp; + for (const std::vector& vchAddress : b.SovereignAddresses) + { + SovereignAddresses.push_back(vchAddress); + } + txHash = b.txHash; + nHeight = b.nHeight; + return *this; + } + + inline bool IsNull() const { return (nTimeStamp == 0); } + bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromScript(const CScript& fluidScript); + void Serialize(std::vector& vchData); +}; + +static CCriticalSection cs_fluid_sovereign; + +class CFluidSovereignDB : public CDBWrapper { +public: + CFluidSovereignDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); + bool AddFluidSovereignEntry(const CFluidSovereign& entry); + bool GetLastFluidSovereignRecord(CFluidSovereign& entry); + bool GetAllFluidSovereignRecords(std::vector& entries); + bool IsEmpty(); +private: + void InitEmpty(); +}; +bool GetFluidSovereignData(const CScript& scriptPubKey, CFluidSovereign& entry); +bool GetFluidSovereignData(const CTransaction& tx, CFluidSovereign& entry, int& nOut); +bool CheckFluidSovereignDB(); + +extern CFluidSovereignDB *pFluidSovereignDB; + +#endif // FLUID_SOVEREIGN_H diff --git a/src/fluid/rpcfluid.cpp b/src/fluid/rpcfluid.cpp index 6091b1a91a..738ab0bba3 100644 --- a/src/fluid/rpcfluid.cpp +++ b/src/fluid/rpcfluid.cpp @@ -7,6 +7,7 @@ #include "fluiddynode.h" #include "fluidmining.h" #include "fluidmint.h" +#include "fluidsovereign.h" #include "init.h" #include "keepass.h" #include "net.h" @@ -509,21 +510,38 @@ UniValue getfluidsovereigns(const JSONRPCRequest& request) ); UniValue ret(UniValue::VOBJ); - //TODO fluid - /* - GetLastBlockIndex(chainActive.Tip()); - CBlockIndex* pindex = chainActive.Tip(); - CFluidEntry fluidIndex = pindex->fluidParams; - - std::vector sovereignLogs = fluidIndex.fluidSovereigns; + std::vector sovereignEntries; + if (CheckFluidSovereignDB()) + { + if (pFluidSovereignDB->IsEmpty()) { + throw std::runtime_error("GET_FLUID_SOVEREIGN_HISTORY_RPC_ERROR: ERRCODE: 4008 - " + _("Fluid sovereign database is empty.")); + } + if (!pFluidSovereignDB->GetAllFluidSovereignRecords(sovereignEntries)) { + throw std::runtime_error("GET_FLUID_SOVEREIGN_HISTORY_RPC_ERROR: ERRCODE: 4008 - " + _("Error getting fluid sovereign entries")); + } + } + else { + throw std::runtime_error("GET_FLUID_SOVEREIGN_HISTORY_RPC_ERROR: ERRCODE: 4009 - " + _("Error getting fluid sovereign entries")); + } - - for (const std::string& sovereign : sovereignLogs) { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("sovereign address", sovereign)); - ret.push_back(obj); + int x = 1; + UniValue obj(UniValue::VOBJ); + for (const CFluidSovereign& sovereignEntry : sovereignEntries) + { + int index = 1; + UniValue oEntry(UniValue::VOBJ); + for (const std::vector& vchAddress : sovereignEntry.SovereignAddresses) + { + std::string addLabel = "address_" + std::to_string(index); + oEntry.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); + index ++; + } + std::string addLabel = "sovereign" + std::to_string(x); + obj.push_back(Pair(addLabel, oEntry)); + x++; } - */ + ret.push_back(Pair("history", obj)); + return ret; } diff --git a/src/init.cpp b/src/init.cpp index b5867e5d44..6e320c9ad1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -27,6 +27,7 @@ #include "fluid/fluiddynode.h" #include "fluid/fluidmining.h" #include "fluid/fluidmint.h" +#include "fluid/fluidsovereign.h" #include "governance.h" #include "instantsend.h" #include "httpserver.h" @@ -1486,6 +1487,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) delete pFluidDynodeDB; delete pFluidMiningDB; delete pFluidMintDB; + delete pFluidSovereignDB; // BDAP Services DB's delete pDomainEntryDB; @@ -1499,6 +1501,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) pFluidDynodeDB = new CFluidDynodeDB(nTotalCache * 35, false, fReindex, obfuscate); pFluidMiningDB = new CFluidMiningDB(nTotalCache * 35, false, fReindex, obfuscate); pFluidMintDB = new CFluidMintDB(nTotalCache * 35, false, fReindex, obfuscate); + pFluidSovereignDB = new CFluidSovereignDB(nTotalCache * 35, false, fReindex, obfuscate); // Init BDAP Services DB's pDomainEntryDB = new CDomainEntryDB(nTotalCache * 35, false, fReindex, obfuscate); From 354277846fbc414e47c3a1c21bb304e791993a87 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 31 Aug 2018 15:40:48 -0500 Subject: [PATCH 0204/1653] [Fluid] Fixes to get last functions and RPC commands --- src/fluid/fluiddb.cpp | 92 ++++++++++++++ src/fluid/fluiddb.h | 9 ++ src/fluid/fluiddynode.cpp | 42 ++++++- src/fluid/fluiddynode.h | 3 +- src/fluid/fluidmining.cpp | 43 ++++++- src/fluid/fluidmining.h | 3 +- src/fluid/fluidmint.cpp | 48 ++++++-- src/fluid/fluidmint.h | 3 +- src/fluid/fluidsovereign.cpp | 22 +++- src/fluid/fluidsovereign.h | 2 +- src/fluid/rpcfluid.cpp | 224 +++++++++++++++++++---------------- src/validation.cpp | 6 + 12 files changed, 369 insertions(+), 128 deletions(-) diff --git a/src/fluid/fluiddb.cpp b/src/fluid/fluiddb.cpp index 902dab1af3..2073202b38 100644 --- a/src/fluid/fluiddb.cpp +++ b/src/fluid/fluiddb.cpp @@ -2,6 +2,7 @@ #include "fluiddb.h" +#include "base58.h" #include "fluid.h" #include "fluiddynode.h" #include "fluidmining.h" @@ -13,10 +14,14 @@ CAmount GetFluidDynodeReward() if (!CheckFluidDynodeDB()) return GetStandardDynodePayment(); + if (pFluidDynodeDB->IsEmpty()) + return GetStandardDynodePayment(); + CFluidDynode lastDynodeRecord; if (!pFluidDynodeDB->GetLastFluidDynodeRecord(lastDynodeRecord)) { return GetStandardDynodePayment(); } + LogPrintf("GetFluidDynodeReward: lastDynodeRecord.DynodeReward = %u\n", lastDynodeRecord.DynodeReward); return lastDynodeRecord.DynodeReward; } @@ -25,6 +30,9 @@ CAmount GetFluidMiningReward() if (!CheckFluidMiningDB()) return GetStandardPoWBlockPayment(); + if (pFluidMiningDB->IsEmpty()) + return GetStandardPoWBlockPayment(); + CFluidMining lastMiningRecord; if (!pFluidMiningDB->GetLastFluidMiningRecord(lastMiningRecord)) { return GetStandardPoWBlockPayment(); @@ -37,6 +45,9 @@ bool GetMintingInstructions(const int nHeight, CFluidMint& fluidMint) if (!CheckFluidMintDB()) return false; + if (pFluidMintDB->IsEmpty()) + return false; + CFluidMint getFluidMint; if (!pFluidMintDB->GetLastFluidMintRecord(getFluidMint)) { return false; @@ -48,4 +59,85 @@ bool GetMintingInstructions(const int nHeight, CFluidMint& fluidMint) return true; } return false; +} + +/** Checks if any given address is a current sovereign wallet address (invoked by RPC) */ +bool IsSovereignAddress(const CDynamicAddress& inputAddress) +{ + if (!inputAddress.IsValid()) { + return false; + } + + if (!CheckFluidSovereignDB()) { + return false; + } + + CFluidSovereign lastSovereign; + if (!pFluidSovereignDB->GetLastFluidSovereignRecord(lastSovereign)) { + return false; + } + + for (const std::vector& vchAddress : lastSovereign.SovereignAddresses) { + CDynamicAddress attemptKey(StringFromCharVector(vchAddress)); + if (attemptKey.IsValid() && inputAddress == attemptKey) { + return true; + } + } + return false; +} + +bool GetAllFluidDynodeRecords(std::vector& dynodeEntries) +{ + if (CheckFluidDynodeDB()) { + if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { + return false; + } + } + else { + return false; + } + return true; +} + +bool GetAllFluidMiningRecords(std::vector& miningEntries) +{ + if (CheckFluidMiningDB()) { + if (!pFluidMiningDB->GetAllFluidMiningRecords(miningEntries)) { + return false; + } + } + else { + return false; + } + return true; +} + +bool GetAllFluidMintRecords(std::vector& mintEntries) +{ + if (CheckFluidMintDB()) { + if (!pFluidMintDB->GetAllFluidMintRecords(mintEntries)) { + return false; + } + } + else { + return false; + } + return true; +} + +bool GetAllFluidSovereignRecords(std::vector& sovereignEntries) +{ + if (CheckFluidSovereignDB()) + { + if (pFluidSovereignDB->IsEmpty()) { + return false; + } + if (!pFluidSovereignDB->GetAllFluidSovereignRecords(sovereignEntries)) { + return false; + } + } + else { + return false; + } + return true; } \ No newline at end of file diff --git a/src/fluid/fluiddb.h b/src/fluid/fluiddb.h index 41cc8c856a..78fe398d0a 100644 --- a/src/fluid/fluiddb.h +++ b/src/fluid/fluiddb.h @@ -5,10 +5,19 @@ #include "amount.h" +class CDynamicAddress; +class CFluidDynode; +class CFluidMining; class CFluidMint; +class CFluidSovereign; CAmount GetFluidDynodeReward(); CAmount GetFluidMiningReward(); bool GetMintingInstructions(const int nHeight, CFluidMint& fluidMint); +bool IsSovereignAddress(const CDynamicAddress& inputAddress); +bool GetAllFluidDynodeRecords(std::vector& dynodeEntries); +bool GetAllFluidMiningRecords(std::vector& miningEntries); +bool GetAllFluidMintRecords(std::vector& mintEntries); +bool GetAllFluidSovereignRecords(std::vector& sovereignEntries); #endif // FLUID_DYNODE_H diff --git a/src/fluid/fluiddynode.cpp b/src/fluid/fluiddynode.cpp index a5a3e4f158..97a33b2e68 100644 --- a/src/fluid/fluiddynode.cpp +++ b/src/fluid/fluiddynode.cpp @@ -93,7 +93,7 @@ void CFluidDynode::Serialize(std::vector& vchData) { vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); } -CFluidDynodeDB::CFluidDynodeDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-dynode", nCacheSize, fMemory, fWipe, obfuscate) +CFluidDynodeDB::CFluidDynodeDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "fluid-dynode", nCacheSize, fMemory, fWipe, obfuscate) { } @@ -109,14 +109,24 @@ bool CFluidDynodeDB::AddFluidDynodeEntry(const CFluidDynode& entry, const int op return writeState; } -bool CFluidDynodeDB::GetLastFluidDynodeRecord(CFluidDynode& entry) +bool CFluidDynodeDB::GetLastFluidDynodeRecord(CFluidDynode& returnEntry) { LOCK(cs_fluid_dynode); + returnEntry.SetNull(); + std::pair > key; std::unique_ptr pcursor(NewIterator()); - pcursor->SeekToLast(); - if (pcursor->Valid()) { + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CFluidDynode entry; try { - pcursor->GetValue(entry); + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + if (entry.nHeight > returnEntry.nHeight) { + returnEntry = entry; + } + } + pcursor->Next(); } catch (std::exception& e) { return error("%s() : deserialize error", __PRETTY_FUNCTION__); @@ -151,6 +161,28 @@ bool CFluidDynodeDB::GetAllFluidDynodeRecords(std::vector& entries return true; } +bool CFluidDynodeDB::IsEmpty() +{ + LOCK(cs_fluid_dynode); + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + if (pcursor->Valid()) { + CFluidDynode entry; + try { + std::pair > key; + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + } + pcursor->Next(); + } + catch (std::exception& e) { + return true; + } + return false; + } + return true; +} + bool CheckFluidDynodeDB() { if (!pFluidDynodeDB) diff --git a/src/fluid/fluiddynode.h b/src/fluid/fluiddynode.h index 1feba2d6ab..bdb2311bfd 100644 --- a/src/fluid/fluiddynode.h +++ b/src/fluid/fluiddynode.h @@ -95,8 +95,9 @@ class CFluidDynodeDB : public CDBWrapper { public: CFluidDynodeDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); bool AddFluidDynodeEntry(const CFluidDynode& entry, const int op); - bool GetLastFluidDynodeRecord(CFluidDynode& entry); + bool GetLastFluidDynodeRecord(CFluidDynode& returnEntry); bool GetAllFluidDynodeRecords(std::vector& entries); + bool IsEmpty(); }; bool GetFluidDynodeData(const CScript& scriptPubKey, CFluidDynode& entry); diff --git a/src/fluid/fluidmining.cpp b/src/fluid/fluidmining.cpp index bacb796463..be14e9550e 100644 --- a/src/fluid/fluidmining.cpp +++ b/src/fluid/fluidmining.cpp @@ -93,7 +93,7 @@ void CFluidMining::Serialize(std::vector& vchData) { vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); } -CFluidMiningDB::CFluidMiningDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-mining", nCacheSize, fMemory, fWipe, obfuscate) +CFluidMiningDB::CFluidMiningDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "fluid-mining", nCacheSize, fMemory, fWipe, obfuscate) { } @@ -109,14 +109,25 @@ bool CFluidMiningDB::AddFluidMiningEntry(const CFluidMining& entry, const int op return writeState; } -bool CFluidMiningDB::GetLastFluidMiningRecord(CFluidMining& entry) +bool CFluidMiningDB::GetLastFluidMiningRecord(CFluidMining& returnEntry) { LOCK(cs_fluid_mining); + returnEntry.SetNull(); + std::pair > key; std::unique_ptr pcursor(NewIterator()); - pcursor->SeekToLast(); - if (pcursor->Valid()) { + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CFluidMining entry; try { - pcursor->GetValue(entry); + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + if (entry.nHeight > returnEntry.nHeight) + { + returnEntry = entry; + } + } + pcursor->Next(); } catch (std::exception& e) { return error("%s() : deserialize error", __PRETTY_FUNCTION__); @@ -151,6 +162,28 @@ bool CFluidMiningDB::GetAllFluidMiningRecords(std::vector& entries return true; } +bool CFluidMiningDB::IsEmpty() +{ + LOCK(cs_fluid_mining); + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + if (pcursor->Valid()) { + CFluidMining entry; + try { + std::pair > key; + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + } + pcursor->Next(); + } + catch (std::exception& e) { + return true; + } + return false; + } + return true; +} + bool CheckFluidMiningDB() { if (!pFluidMiningDB) diff --git a/src/fluid/fluidmining.h b/src/fluid/fluidmining.h index c32312d14e..8cdc03fca2 100644 --- a/src/fluid/fluidmining.h +++ b/src/fluid/fluidmining.h @@ -95,8 +95,9 @@ class CFluidMiningDB : public CDBWrapper { public: CFluidMiningDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); bool AddFluidMiningEntry(const CFluidMining& entry, const int op); - bool GetLastFluidMiningRecord(CFluidMining& entry); + bool GetLastFluidMiningRecord(CFluidMining& returnEntry); bool GetAllFluidMiningRecords(std::vector& entries); + bool IsEmpty(); }; bool GetFluidMiningData(const CScript& scriptPubKey, CFluidMining& entry); diff --git a/src/fluid/fluidmint.cpp b/src/fluid/fluidmint.cpp index e33278ec8a..4991294225 100644 --- a/src/fluid/fluidmint.cpp +++ b/src/fluid/fluidmint.cpp @@ -24,7 +24,7 @@ bool GetFluidMintData(const CScript& scriptPubKey, CFluidMint& entry) std::vector vecSplitScript; SeparateFluidOpString(verificationWithoutOpCode, vecSplitScript); - if (vecSplitScript.size() == 5 && strOperationCode == "OP_MINT") { + if (vecSplitScript.size() == 6 && strOperationCode == "OP_MINT") { std::vector vchFluidOperation = CharVectorFromString(fluidOperationString); entry.FluidScript.insert(entry.FluidScript.end(), vchFluidOperation.begin(), vchFluidOperation.end()); std::string strAmount = vecSplitScript[0]; @@ -102,12 +102,12 @@ CDynamicAddress CFluidMint::GetDestinationAddress() const return CDynamicAddress(StringFromCharVector(DestinationAddress)); } -CFluidMintDB::CFluidMintDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-mint", nCacheSize, fMemory, fWipe, obfuscate) +CFluidMintDB::CFluidMintDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "fluid-mint", nCacheSize, fMemory, fWipe, obfuscate) { } bool CFluidMintDB::AddFluidMintEntry(const CFluidMint& entry, const int op) -{ +{ bool writeState = false; { LOCK(cs_fluid_mint); @@ -118,20 +118,30 @@ bool CFluidMintDB::AddFluidMintEntry(const CFluidMint& entry, const int op) return writeState; } -bool CFluidMintDB::GetLastFluidMintRecord(CFluidMint& entry) +bool CFluidMintDB::GetLastFluidMintRecord(CFluidMint& returnEntry) { LOCK(cs_fluid_mint); + returnEntry.SetNull(); + std::pair > key; std::unique_ptr pcursor(NewIterator()); - pcursor->SeekToLast(); - if (pcursor->Valid()) { + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CFluidMint entry; try { - pcursor->GetValue(entry); + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + if (entry.nHeight > returnEntry.nHeight) + { + returnEntry = entry; + } + } + pcursor->Next(); } catch (std::exception& e) { return error("%s() : deserialize error", __PRETTY_FUNCTION__); } } - LogPrintf("GetLastFluidMintRecord 4\n"); return true; } @@ -161,6 +171,28 @@ bool CFluidMintDB::GetAllFluidMintRecords(std::vector& entries) return true; } +bool CFluidMintDB::IsEmpty() +{ + LOCK(cs_fluid_mint); + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + if (pcursor->Valid()) { + CFluidMint entry; + try { + std::pair > key; + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + } + pcursor->Next(); + } + catch (std::exception& e) { + return true; + } + return false; + } + return true; +} + bool CheckFluidMintDB() { if (!pFluidMintDB) diff --git a/src/fluid/fluidmint.h b/src/fluid/fluidmint.h index cdb0298b06..6fb1bbf9e5 100644 --- a/src/fluid/fluidmint.h +++ b/src/fluid/fluidmint.h @@ -101,8 +101,9 @@ class CFluidMintDB : public CDBWrapper { public: CFluidMintDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); bool AddFluidMintEntry(const CFluidMint& entry, const int op); - bool GetLastFluidMintRecord(CFluidMint& entry); + bool GetLastFluidMintRecord(CFluidMint& returnEntry); bool GetAllFluidMintRecords(std::vector& entries); + bool IsEmpty(); }; bool GetFluidMintData(const CScript& scriptPubKey, CFluidMint& entry); diff --git a/src/fluid/fluidsovereign.cpp b/src/fluid/fluidsovereign.cpp index 810b7320ba..026f4683f0 100644 --- a/src/fluid/fluidsovereign.cpp +++ b/src/fluid/fluidsovereign.cpp @@ -85,7 +85,7 @@ void CFluidSovereign::Serialize(std::vector& vchData) { vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); } -CFluidSovereignDB::CFluidSovereignDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "fluid-sovereign", nCacheSize, fMemory, fWipe, obfuscate) +CFluidSovereignDB::CFluidSovereignDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "fluid-sovereign", nCacheSize, fMemory, fWipe, obfuscate) { InitEmpty(); } @@ -102,6 +102,7 @@ void CFluidSovereignDB::InitEmpty() } fluidSovereign.FluidScript = CharVectorFromString("init sovereign"); fluidSovereign.nTimeStamp = 1; + fluidSovereign.nHeight = 1; if (!AddFluidSovereignEntry(fluidSovereign)) { LogPrintf("CFluidSovereignDB::InitEmpty add failed.\n"); @@ -120,14 +121,25 @@ bool CFluidSovereignDB::AddFluidSovereignEntry(const CFluidSovereign& entry) return writeState; } -bool CFluidSovereignDB::GetLastFluidSovereignRecord(CFluidSovereign& entry) +bool CFluidSovereignDB::GetLastFluidSovereignRecord(CFluidSovereign& returnEntry) { LOCK(cs_fluid_sovereign); + returnEntry.SetNull(); + std::pair > key; std::unique_ptr pcursor(NewIterator()); - pcursor->SeekToLast(); - if (pcursor->Valid()) { + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CFluidSovereign entry; try { - pcursor->GetValue(entry); + if (pcursor->GetKey(key) && key.first == "script") { + pcursor->GetValue(entry); + if (entry.nHeight > returnEntry.nHeight) + { + returnEntry = entry; + } + } + pcursor->Next(); } catch (std::exception& e) { return error("%s() : deserialize error", __PRETTY_FUNCTION__); diff --git a/src/fluid/fluidsovereign.h b/src/fluid/fluidsovereign.h index b7627a284b..844999bc46 100644 --- a/src/fluid/fluidsovereign.h +++ b/src/fluid/fluidsovereign.h @@ -91,7 +91,7 @@ class CFluidSovereignDB : public CDBWrapper { public: CFluidSovereignDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); bool AddFluidSovereignEntry(const CFluidSovereign& entry); - bool GetLastFluidSovereignRecord(CFluidSovereign& entry); + bool GetLastFluidSovereignRecord(CFluidSovereign& returnEntry); bool GetAllFluidSovereignRecords(std::vector& entries); bool IsEmpty(); private: diff --git a/src/fluid/rpcfluid.cpp b/src/fluid/rpcfluid.cpp index 738ab0bba3..1e8d6d17f9 100644 --- a/src/fluid/rpcfluid.cpp +++ b/src/fluid/rpcfluid.cpp @@ -4,6 +4,7 @@ #include "chain.h" #include "core_io.h" +#include "fluiddb.h" #include "fluiddynode.h" #include "fluidmining.h" #include "fluidmint.h" @@ -41,8 +42,6 @@ opcodetype getOpcodeFromString(std::string input) { UniValue maketoken(const JSONRPCRequest& request) { - std::string result; - if (request.fHelp || request.params.size() < 2) { throw std::runtime_error( "maketoken \"string\"\n" @@ -54,12 +53,13 @@ UniValue maketoken(const JSONRPCRequest& request) + HelpExampleRpc("maketoken", "\"Hello World!\"") ); } - - for(uint32_t iter = 0; iter != request.params.size(); iter++) { - result += request.params[iter].get_str() + SubDelimiter; - } + std::string result; + + for(uint32_t iter = 0; iter != request.params.size(); iter++) { + result += request.params[iter].get_str() + SubDelimiter; + } - result.pop_back(); + result.pop_back(); fluid.ConvertToHex(result); return result; @@ -67,13 +67,20 @@ UniValue maketoken(const JSONRPCRequest& request) UniValue gettime(const JSONRPCRequest& request) { + if (request.fHelp || request.params.size() != 0) { + throw std::runtime_error( + "gettime\n" + "\nReturns the current Epoch time (https://www.epochconverter.com).\n" + "\nExamples:\n" + + HelpExampleCli("gettime", "\"1535543210\"") + + HelpExampleRpc("gettime", "\"1535543210\"") + ); + } return GetTime(); } UniValue getrawpubkey(const JSONRPCRequest& request) { - UniValue ret(UniValue::VOBJ); - if (request.fHelp || request.params.size() != 1) throw std::runtime_error( "getrawpubkey \"address\"\n" @@ -84,6 +91,7 @@ UniValue getrawpubkey(const JSONRPCRequest& request) + HelpExampleCli("burndynamic", "123.456") + HelpExampleRpc("burndynamic", "123.456") ); + UniValue ret(UniValue::VOBJ); CDynamicAddress address(request.params[0].get_str()); bool isValid = address.IsValid(); @@ -102,8 +110,6 @@ UniValue getrawpubkey(const JSONRPCRequest& request) UniValue burndynamic(const UniValue& params, bool fHelp) { - CWalletTx wtx; - if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; @@ -117,6 +123,7 @@ UniValue burndynamic(const UniValue& params, bool fHelp) + HelpExampleCli("burndynamic", "123.456") + HelpExampleRpc("burndynamic", "123.456") ); + CWalletTx wtx; EnsureWalletIsUnlocked(); @@ -139,8 +146,6 @@ opcodetype negatif = OP_RETURN; UniValue sendfluidtransaction(const JSONRPCRequest& request) { - CScript finalScript; - if (!EnsureWalletIsAvailable(request.fHelp)) return NullUniValue; @@ -155,6 +160,7 @@ UniValue sendfluidtransaction(const JSONRPCRequest& request) + HelpExampleCli("sendfluidtransaction", "\"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") + HelpExampleRpc("sendfluidtransaction", "\"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") ); + CScript finalScript; EnsureWalletIsUnlocked(); opcodetype opcode = getOpcodeFromString(request.params[0].get_str()); @@ -184,8 +190,6 @@ UniValue sendfluidtransaction(const JSONRPCRequest& request) UniValue signtoken(const JSONRPCRequest& request) { - std::string result; - if (request.fHelp || request.params.size() != 2) throw std::runtime_error( "signtoken \"address\" \"tokenkey\"\n" @@ -197,6 +201,7 @@ UniValue signtoken(const JSONRPCRequest& request) + HelpExampleCli("signtoken", "\"D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf\" \"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") + HelpExampleRpc("signtoken", "\"D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf\" \"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") ); + std::string result; CDynamicAddress address(request.params[0].get_str()); if (!address.IsValid()) @@ -223,8 +228,6 @@ UniValue signtoken(const JSONRPCRequest& request) UniValue verifyquorum(const JSONRPCRequest& request) { - std::string message; - if (request.fHelp || request.params.size() != 1) throw std::runtime_error( "verifyquorum \"tokenkey\"\n" @@ -235,6 +238,7 @@ UniValue verifyquorum(const JSONRPCRequest& request) + HelpExampleCli("consenttoken", "\"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") + HelpExampleRpc("consenttoken", "\"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") ); + std::string message; if (!fluid.CheckNonScriptQuorum(request.params[0].get_str(), message, false)) throw std::runtime_error("Instruction does not meet minimum quorum for validity"); @@ -244,8 +248,6 @@ UniValue verifyquorum(const JSONRPCRequest& request) UniValue consenttoken(const JSONRPCRequest& request) { - std::string result; - if (request.fHelp || request.params.size() != 2) throw std::runtime_error( "consenttoken \"address\" \"tokenkey\"\n" @@ -257,6 +259,7 @@ UniValue consenttoken(const JSONRPCRequest& request) + HelpExampleCli("consenttoken", "\"D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf\" \"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") + HelpExampleRpc("consenttoken", "\"D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf\" \"3130303030303030303030303a3a313439393336353333363a3a445148697036443655376d46335761795a32747337794478737a71687779367a5a6a20494f42447a557167773\"") ); + std::string result; CDynamicAddress address(request.params[0].get_str()); if (!address.IsValid()) @@ -265,7 +268,7 @@ UniValue consenttoken(const JSONRPCRequest& request) if (!IsHex(request.params[1].get_str())) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Hex string is invalid! Token incorrect"); - if (!fluid.IsGivenKeyMaster(address)) + if (!IsSovereignAddress(address)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Address is not fluid protocol sovereign address"); if (!fluid.VerifyAddressOwnership(address)) @@ -296,65 +299,88 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) + HelpExampleCli("getfluidhistoryraw", "") + HelpExampleRpc("getfluidhistoryraw", "") ); - UniValue ret(UniValue::VOBJ); + CAmount totalMintedCoins = 0; + CAmount totalFluidTxCost = 0; + int nTotal = 0; + + UniValue oMints(UniValue::VOBJ); // load fluid mint transaction history { std::vector mintEntries; - if (CheckFluidMintDB()) { - if (!pFluidMintDB->GetAllFluidMintRecords(mintEntries)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid mint entries")); - } + if (!GetAllFluidMintRecords(mintEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid mint entries")); } - else { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4001 - " + _("Error opening fluid mint db")); - } - + int x = 1; for (const CFluidMint& mintEntry : mintEntries) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("raw_script", StringFromCharVector(mintEntry.FluidScript))); - ret.push_back(Pair("mint", obj)); + obj.push_back(Pair("fluid_script", StringFromCharVector(mintEntry.FluidScript))); + std::string addLabel = "mint_" + std::to_string(x); + oMints.push_back(Pair(addLabel, obj)); + totalMintedCoins = totalMintedCoins + mintEntry.MintAmount; + totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; + x++; + nTotal++; } } + ret.push_back(Pair("minting_history", oMints)); // load fluid dynode update reward transaction history + UniValue oDynodes(UniValue::VOBJ); { std::vector dynodeEntries; - if (CheckFluidDynodeDB()) { - if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid dynode entries")); - } - } - else { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4001 - " + _("Error opening fluid dynode db")); + if (!GetAllFluidDynodeRecords(dynodeEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4002 - " + _("Error getting fluid dynode entries")); } - + int x = 1; for (const CFluidDynode& dynEntry : dynodeEntries) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("raw_script", StringFromCharVector(dynEntry.FluidScript))); - ret.push_back(Pair("dynode", obj)); + obj.push_back(Pair("fluid_script", StringFromCharVector(dynEntry.FluidScript))); + std::string addLabel = "reward_update_" + std::to_string(x); + oDynodes.push_back(Pair(addLabel, obj)); + totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; + x++; + nTotal++; } } + ret.push_back(Pair("dynode_reward_history", oDynodes)); // load fluid mining update reward transaction history + UniValue oMining(UniValue::VOBJ); { std::vector miningEntries; - if (CheckFluidMiningDB()) { - if (!pFluidMiningDB->GetAllFluidMiningRecords(miningEntries)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4004 - " + _("Error getting fluid mining entries")); - } - } - else { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4005 - " + _("Error opening fluid mining db")); + if (!GetAllFluidMiningRecords(miningEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4004 - " + _("Error getting fluid mining entries")); } - + int x = 1; for (const CFluidMining& miningEntry : miningEntries) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("raw_script", StringFromCharVector(miningEntry.FluidScript))); - ret.push_back(Pair("miner", obj)); + obj.push_back(Pair("fluid_script", StringFromCharVector(miningEntry.FluidScript))); + std::string addLabel = "reward_update_" + std::to_string(x); + oMining.push_back(Pair(addLabel, obj)); + totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; + x++; + nTotal++; } } + ret.push_back(Pair("mining_reward_history", oMining)); + // load fluid transaction summary + UniValue oSummary(UniValue::VOBJ); + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("total_minted", FormatMoney(totalMintedCoins))); + obj.push_back(Pair("total_fluid_fee_cost", FormatMoney(totalFluidTxCost))); + CAmount dynodeReward = GetFluidDynodeReward(); + obj.push_back(Pair("current_dynode_reward", FormatMoney(dynodeReward))); + + CFluidMining lastMiningRecord; + CAmount miningAmount = GetFluidMiningReward(); + obj.push_back(Pair("current_mining_reward", FormatMoney(miningAmount))); + obj.push_back(Pair("total_fluid_transactions", nTotal)); + oSummary.push_back(Pair("summary", obj)); + } + ret.push_back(Pair("fluid_summary", oSummary)); return ret; } @@ -381,29 +407,28 @@ UniValue getfluidhistory(const JSONRPCRequest& request) + HelpExampleCli("getfluidhistory", "") + HelpExampleRpc("getfluidhistory", "") ); - UniValue ret(UniValue::VOBJ); CAmount totalMintedCoins = 0; CAmount totalFluidTxCost = 0; + int nTotal = 0; + + UniValue oMints(UniValue::VOBJ); // load fluid mint transaction history { std::vector mintEntries; - if (CheckFluidMintDB()) { - if (!pFluidMintDB->GetAllFluidMintRecords(mintEntries)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid mint entries")); - } - } - else { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4001 - " + _("Error opening fluid mint db")); + if (!GetAllFluidMintRecords(mintEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4000 - " + _("Error getting fluid mint entries")); } - + int x = 1; for (const CFluidMint& mintEntry : mintEntries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("operation", "Mint")); obj.push_back(Pair("amount", FormatMoney(mintEntry.MintAmount))); obj.push_back(Pair("timestamp", mintEntry.nTimeStamp)); - obj.push_back(Pair("destination_address)", StringFromCharVector(mintEntry.DestinationAddress))); + obj.push_back(Pair("block_height", (int)mintEntry.nHeight)); + obj.push_back(Pair("txid", mintEntry.txHash.GetHex())); + obj.push_back(Pair("destination_address", StringFromCharVector(mintEntry.DestinationAddress))); int index = 1; for (const std::vector& vchAddress : mintEntry.SovereignAddresses) { @@ -411,28 +436,31 @@ UniValue getfluidhistory(const JSONRPCRequest& request) obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); index ++; } - ret.push_back(Pair("mint", obj)); + std::string addLabel = "mint_" + std::to_string(x); + oMints.push_back(Pair(addLabel, obj)); totalMintedCoins = totalMintedCoins + mintEntry.MintAmount; totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; + x++; + nTotal++; } } + ret.push_back(Pair("minting_history", oMints)); // load fluid dynode update reward transaction history + UniValue oDynodes(UniValue::VOBJ); { std::vector dynodeEntries; - if (CheckFluidDynodeDB()) { - if (!pFluidDynodeDB->GetAllFluidDynodeRecords(dynodeEntries)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4002 - " + _("Error getting fluid dynode entries")); - } - } - else { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4003 - " + _("Error opening fluid dynode db")); + if (!GetAllFluidDynodeRecords(dynodeEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4002 - " + _("Error getting fluid dynode entries")); } + int x = 1; for (const CFluidDynode& dynEntry : dynodeEntries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("operation", "Dynode Reward Update")); obj.push_back(Pair("amount", FormatMoney(dynEntry.DynodeReward))); obj.push_back(Pair("timestamp", dynEntry.nTimeStamp)); + obj.push_back(Pair("block_height", (int)dynEntry.nHeight)); + obj.push_back(Pair("txid", dynEntry.txHash.GetHex())); int index = 1; for (const std::vector& vchAddress : dynEntry.SovereignAddresses) { @@ -440,28 +468,30 @@ UniValue getfluidhistory(const JSONRPCRequest& request) obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); index ++; } - ret.push_back(Pair("dynode", obj)); + std::string addLabel = "reward_update_" + std::to_string(x); + oDynodes.push_back(Pair(addLabel, obj)); totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; + x++; + nTotal++; } } + ret.push_back(Pair("dynode_reward_history", oDynodes)); // load fluid mining update reward transaction history + UniValue oMining(UniValue::VOBJ); { std::vector miningEntries; - if (CheckFluidMiningDB()) { - if (!pFluidMiningDB->GetAllFluidMiningRecords(miningEntries)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4004 - " + _("Error getting fluid mining entries")); - } + if (!GetAllFluidMiningRecords(miningEntries)) { + throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4004 - " + _("Error getting fluid mining entries")); } - else { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4005 - " + _("Error opening fluid mining db")); - } - + int x = 1; for (const CFluidMining& miningEntry : miningEntries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("operation", "Mining Reward Update")); obj.push_back(Pair("amount", FormatMoney(miningEntry.MiningReward))); obj.push_back(Pair("timestamp", miningEntry.nTimeStamp)); + obj.push_back(Pair("block_height", (int)miningEntry.nHeight)); + obj.push_back(Pair("txid", miningEntry.txHash.GetHex())); int index = 1; for (const std::vector& vchAddress : miningEntry.SovereignAddresses) { @@ -469,28 +499,29 @@ UniValue getfluidhistory(const JSONRPCRequest& request) obj.push_back(Pair(addLabel, StringFromCharVector(vchAddress))); index ++; } - ret.push_back(Pair("miner", obj)); + std::string addLabel = "reward_update_" + std::to_string(x); + oMining.push_back(Pair(addLabel, obj)); totalFluidTxCost = totalFluidTxCost + fluid.FLUID_TRANSACTION_COST; + x++; + nTotal++; } } + ret.push_back(Pair("mining_reward_history", oMining)); // load fluid transaction summary + UniValue oSummary(UniValue::VOBJ); { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("total_minted", FormatMoney(totalMintedCoins))); obj.push_back(Pair("total_fluid_fee_cost", FormatMoney(totalFluidTxCost))); - CFluidDynode lastDynodeRecord; - if (!pFluidDynodeDB->GetLastFluidDynodeRecord(lastDynodeRecord)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4006 - " + _("Error getting last fluid dynode entry")); - } - obj.push_back(Pair("current_dynode_reward", FormatMoney(lastDynodeRecord.DynodeReward))); - + CAmount dynodeReward = GetFluidDynodeReward(); + obj.push_back(Pair("current_dynode_reward", FormatMoney(dynodeReward))); CFluidMining lastMiningRecord; - if (!pFluidMiningDB->GetLastFluidMiningRecord(lastMiningRecord)) { - throw std::runtime_error("GET_FLUID_HISTORY_RPC_ERROR: ERRCODE: 4007 - " + _("Error getting last fluid mining entry")); - } - obj.push_back(Pair("current_mining_reward", FormatMoney(lastMiningRecord.MiningReward))); - ret.push_back(Pair("summary", obj)); + CAmount miningAmount = GetFluidMiningReward(); + obj.push_back(Pair("current_mining_reward", FormatMoney(miningAmount))); + obj.push_back(Pair("total_fluid_transactions", nTotal)); + oSummary.push_back(Pair("summary", obj)); } + ret.push_back(Pair("fluid_summary", oSummary)); return ret; } @@ -511,19 +542,10 @@ UniValue getfluidsovereigns(const JSONRPCRequest& request) UniValue ret(UniValue::VOBJ); std::vector sovereignEntries; - if (CheckFluidSovereignDB()) + if (!GetAllFluidSovereignRecords(sovereignEntries)) { - if (pFluidSovereignDB->IsEmpty()) { - throw std::runtime_error("GET_FLUID_SOVEREIGN_HISTORY_RPC_ERROR: ERRCODE: 4008 - " + _("Fluid sovereign database is empty.")); - } - if (!pFluidSovereignDB->GetAllFluidSovereignRecords(sovereignEntries)) { - throw std::runtime_error("GET_FLUID_SOVEREIGN_HISTORY_RPC_ERROR: ERRCODE: 4008 - " + _("Error getting fluid sovereign entries")); - } - } - else { - throw std::runtime_error("GET_FLUID_SOVEREIGN_HISTORY_RPC_ERROR: ERRCODE: 4009 - " + _("Error getting fluid sovereign entries")); + throw std::runtime_error("GET_FLUID_SOVEREIGN_HISTORY_RPC_ERROR: ERRCODE: 4008 - " + _("Error getting fluid sovereign entries")); } - int x = 1; UniValue obj(UniValue::VOBJ); for (const CFluidSovereign& sovereignEntry : sovereignEntries) diff --git a/src/validation.cpp b/src/validation.cpp index 49f7cc9052..ddc1070028 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2201,16 +2201,22 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd int OpCode = GetFluidOpCode(scriptFluid); if (OpCode == OP_REWARD_DYNODE) { CFluidDynode fluidDynode(scriptFluid); + fluidDynode.nHeight = pindex->nHeight; + fluidDynode.txHash = tx.GetHash(); if (CheckFluidDynodeDB()) pFluidDynodeDB->AddFluidDynodeEntry(fluidDynode, OP_REWARD_DYNODE); } else if (OpCode == OP_REWARD_MINING) { CFluidMining fluidMining(scriptFluid); + fluidMining.nHeight = pindex->nHeight; + fluidMining.txHash = tx.GetHash(); if (CheckFluidMiningDB()) pFluidMiningDB->AddFluidMiningEntry(fluidMining, OP_REWARD_MINING); } else if (OpCode == OP_MINT) { CFluidMint fluidMint(scriptFluid); + fluidMint.nHeight = pindex->nHeight; + fluidMint.txHash = tx.GetHash(); if (CheckFluidMintDB()) pFluidMintDB->AddFluidMintEntry(fluidMint, OP_MINT); } From f9bb961706ba55c304c52a555b755c49a1f93346 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sat, 1 Sep 2018 06:47:57 -0500 Subject: [PATCH 0205/1653] [Fluid] Fix consensus issues with new db code --- src/dynode-payments.cpp | 8 +-- src/dynode-payments.h | 2 +- src/dynode.cpp | 2 +- src/fluid/fluid.cpp | 23 +++--- src/fluid/fluid.h | 4 +- src/fluid/fluiddb.cpp | 98 +++++++++++++++++++++---- src/fluid/fluiddb.h | 8 ++- src/fluid/fluiddynode.cpp | 14 +++- src/fluid/fluiddynode.h | 3 +- src/fluid/fluidmining.cpp | 14 +++- src/fluid/fluidmining.h | 3 +- src/fluid/fluidmint.cpp | 9 ++- src/fluid/fluidmint.h | 1 + src/fluid/fluidsovereign.cpp | 9 +++ src/fluid/fluidsovereign.h | 1 + src/fluid/rpcfluid.cpp | 8 +-- src/miner.cpp | 2 +- src/validation.cpp | 135 +++++++++++++++-------------------- 18 files changed, 218 insertions(+), 126 deletions(-) diff --git a/src/dynode-payments.cpp b/src/dynode-payments.cpp index 2b0858d212..ba964157b0 100644 --- a/src/dynode-payments.cpp +++ b/src/dynode-payments.cpp @@ -315,7 +315,7 @@ void CDynodePayments::FillBlockPayee(CMutableTransaction& txNew, int nBlockHeigh // make sure it's not filled yet txoutDynodeRet = CTxOut(); - CAmount dynodePayment = GetFluidDynodeReward(); + CAmount dynodePayment = GetFluidDynodeReward(nBlockHeight); txoutDynodeRet = CTxOut(dynodePayment, payee); txNew.vout.push_back(txoutDynodeRet); @@ -576,13 +576,13 @@ bool CDynodeBlockPayees::HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq return false; } -bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew) +bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew, const int nHeight) { LOCK(cs_vecPayees); int nMaxSignatures = 0; std::string strPayeesPossible = ""; - CAmount nDynodePayment = GetFluidDynodeReward(); + CAmount nDynodePayment = GetFluidDynodeReward(nHeight); //require at least DNPAYMENTS_SIGNATURES_REQUIRED signatures @@ -658,7 +658,7 @@ bool CDynodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHe LOCK(cs_mapDynodeBlocks); if(mapDynodeBlocks.count(nBlockHeight)){ - return mapDynodeBlocks[nBlockHeight].IsTransactionValid(txNew); + return mapDynodeBlocks[nBlockHeight].IsTransactionValid(txNew, nBlockHeight); } return true; diff --git a/src/dynode-payments.h b/src/dynode-payments.h index 5d5da17fc6..32adda9c2f 100644 --- a/src/dynode-payments.h +++ b/src/dynode-payments.h @@ -98,7 +98,7 @@ class CDynodeBlockPayees bool GetBestPayee(CScript& payeeRet); bool HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq); - bool IsTransactionValid(const CTransaction& txNew); + bool IsTransactionValid(const CTransaction& txNew, const int nHeight); std::string GetRequiredPaymentsString(); }; diff --git a/src/dynode.cpp b/src/dynode.cpp index 86c22977b3..2290ecf908 100644 --- a/src/dynode.cpp +++ b/src/dynode.cpp @@ -302,7 +302,7 @@ void CDynode::UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack if(!ReadBlockFromDisk(block, BlockReading, Params().GetConsensus())) // shouldn't really happen continue; - CAmount nDynodePayment = GetFluidDynodeReward(); + CAmount nDynodePayment = GetFluidDynodeReward(BlockReading->nHeight); BOOST_FOREACH(CTxOut txout, block.vtx[0].vout) if(dnpayee == txout.scriptPubKey && nDynodePayment == txout.nValue) { diff --git a/src/fluid/fluid.cpp b/src/fluid/fluid.cpp index b46a6fc0c1..bb15b7460a 100644 --- a/src/fluid/fluid.cpp +++ b/src/fluid/fluid.cpp @@ -585,18 +585,18 @@ bool CFluid::InsertTransactionToRecord(CScript fluidInstruction, std::vector= 1 && chainActive.Height() <= Params().GetConsensus().nRewardsStart) { + else if (nHeight > 1 && nHeight <= Params().GetConsensus().nRewardsStart) { LogPrint("zero-reward block creation", "GetStandardPoWBlockPayment() : create=%s nSubsidy=%d\n", FormatMoney(BLOCKCHAIN_INIT_REWARD), BLOCKCHAIN_INIT_REWARD); return BLOCKCHAIN_INIT_REWARD; // Burn transaction fees } - else if (chainActive.Height() > Params().GetConsensus().nRewardsStart) { + else if (nHeight > Params().GetConsensus().nRewardsStart) { LogPrint("creation", "GetStandardPoWBlockPayment() : create=%s PoW Reward=%d\n", FormatMoney(PHASE_1_POW_REWARD), PHASE_1_POW_REWARD); return PHASE_1_POW_REWARD; // 1 DYN and burn transaction fees } @@ -604,18 +604,15 @@ CAmount GetStandardPoWBlockPayment() return BLOCKCHAIN_INIT_REWARD; // Burn transaction fees } -CAmount GetStandardDynodePayment() +CAmount GetStandardDynodePayment(const int nHeight) { - if (chainActive.Height() > Params().GetConsensus().nDynodePaymentsStartBlock && chainActive.Height() < Params().GetConsensus().nUpdateDiffAlgoHeight) { - LogPrint("creation", "GetStandardDynodePayment() : create=%s DN Payment=%d\n", FormatMoney(PHASE_1_DYNODE_PAYMENT), PHASE_1_DYNODE_PAYMENT); - return PHASE_1_DYNODE_PAYMENT; // 0.382 DYN - } - else if (chainActive.Height() > Params().GetConsensus().nDynodePaymentsStartBlock && chainActive.Height() >= Params().GetConsensus().nUpdateDiffAlgoHeight) { - LogPrint("creation", "GetStandardDynodePayment() : create=%s DN Payment=%d\n", FormatMoney(PHASE_2_DYNODE_PAYMENT), PHASE_2_DYNODE_PAYMENT); + if (nHeight > Params().GetConsensus().nDynodePaymentsStartBlock) { + LogPrintf("GetStandardDynodePayment() : create=%s DN Payment=%d\n", FormatMoney(PHASE_2_DYNODE_PAYMENT), PHASE_2_DYNODE_PAYMENT); return PHASE_2_DYNODE_PAYMENT; // 1.618 DYN } - else - return BLOCKCHAIN_INIT_REWARD; + else { + return BLOCKCHAIN_INIT_REWARD; // 0 DYN + } } bool CFluid::ValidationProcesses(CValidationState& state, CScript txOut, CAmount txValue) { diff --git a/src/fluid/fluid.h b/src/fluid/fluid.h index f341957ea8..dd1cf70d54 100644 --- a/src/fluid/fluid.h +++ b/src/fluid/fluid.h @@ -78,8 +78,8 @@ class CFluid : public CFluidParameters, public COperations { }; /** Standard Reward Payment Determination Functions */ -CAmount GetStandardPoWBlockPayment(); -CAmount GetStandardDynodePayment(); +CAmount GetStandardPoWBlockPayment(const int nHeight); +CAmount GetStandardDynodePayment(const int nHeight); void BuildFluidInformationIndex(CBlockIndex* pindex, CAmount &nExpectedBlockValue, bool fDynodePaid); bool IsTransactionFluid(const CScript& txOut); diff --git a/src/fluid/fluiddb.cpp b/src/fluid/fluiddb.cpp index 2073202b38..0c88dcafa0 100644 --- a/src/fluid/fluiddb.cpp +++ b/src/fluid/fluiddb.cpp @@ -9,33 +9,43 @@ #include "fluidmint.h" #include "fluidsovereign.h" -CAmount GetFluidDynodeReward() +CAmount GetFluidDynodeReward(const int nHeight) { + if (fluid.FLUID_ACTIVATE_HEIGHT > nHeight) + return GetStandardDynodePayment(nHeight); + if (!CheckFluidDynodeDB()) - return GetStandardDynodePayment(); + return GetStandardDynodePayment(nHeight); if (pFluidDynodeDB->IsEmpty()) - return GetStandardDynodePayment(); + return GetStandardDynodePayment(nHeight); CFluidDynode lastDynodeRecord; - if (!pFluidDynodeDB->GetLastFluidDynodeRecord(lastDynodeRecord)) { - return GetStandardDynodePayment(); + if (!pFluidDynodeDB->GetLastFluidDynodeRecord(lastDynodeRecord, nHeight)) { + return GetStandardDynodePayment(nHeight); + } + if (lastDynodeRecord.DynodeReward > 0) { + return lastDynodeRecord.DynodeReward; + } + else { + return GetStandardDynodePayment(nHeight); } - LogPrintf("GetFluidDynodeReward: lastDynodeRecord.DynodeReward = %u\n", lastDynodeRecord.DynodeReward); - return lastDynodeRecord.DynodeReward; } -CAmount GetFluidMiningReward() +CAmount GetFluidMiningReward(const int nHeight) { + if (fluid.FLUID_ACTIVATE_HEIGHT > nHeight) + return GetStandardPoWBlockPayment(nHeight); + if (!CheckFluidMiningDB()) - return GetStandardPoWBlockPayment(); + return GetStandardPoWBlockPayment(nHeight); if (pFluidMiningDB->IsEmpty()) - return GetStandardPoWBlockPayment(); + return GetStandardPoWBlockPayment(nHeight); CFluidMining lastMiningRecord; - if (!pFluidMiningDB->GetLastFluidMiningRecord(lastMiningRecord)) { - return GetStandardPoWBlockPayment(); + if (!pFluidMiningDB->GetLastFluidMiningRecord(lastMiningRecord, nHeight)) { + return GetStandardPoWBlockPayment(nHeight); } return lastMiningRecord.MiningReward; } @@ -140,4 +150,68 @@ bool GetAllFluidSovereignRecords(std::vector& sovereignEntries) return false; } return true; +} + +bool GetLastFluidSovereignAddressStrings(std::vector& sovereignAddresses) +{ + if (!CheckFluidSovereignDB()) { + return false; + } + + CFluidSovereign lastSovereign; + if (!pFluidSovereignDB->GetLastFluidSovereignRecord(lastSovereign)) { + return false; + } + sovereignAddresses = lastSovereign.SovereignAddressesStrings(); + return true; +} + +/** Checks whether 3 of 5 sovereign addresses signed the token in the script to meet the quorum requirements */ +bool CheckSignatureQuorum(const std::vector& vchFluidScript, std::string& errMessage, bool individual) +{ + std::string consentToken = StringFromCharVector(vchFluidScript); + std::vector fluidSovereigns; + if (!GetLastFluidSovereignAddressStrings(fluidSovereigns)) { + return false; + } + + std::pair keyOne; + std::pair keyTwo; + std::pair keyThree; + keyOne.second = false; + keyTwo.second = false; + keyThree.second = false; + + for (const std::string& sovereignAddress : fluidSovereigns) + { + CDynamicAddress attemptKey; + CDynamicAddress xKey(sovereignAddress); + + if (!xKey.IsValid()) + return false; + CFluid fluid; + if (fluid.GenericVerifyInstruction(consentToken, attemptKey, errMessage, 1) && xKey == attemptKey) { + keyOne = std::make_pair(attemptKey.ToString(), true); + } + + if (fluid.GenericVerifyInstruction(consentToken, attemptKey, errMessage, 2) && xKey == attemptKey) { + keyTwo = std::make_pair(attemptKey.ToString(), true); + } + + if (fluid.GenericVerifyInstruction(consentToken, attemptKey, errMessage, 3) && xKey == attemptKey) { + keyThree = std::make_pair(attemptKey.ToString(), true); + } + } + + bool fValid = (keyOne.first.ToString() != keyTwo.first.ToString() && keyTwo.first.ToString() != keyThree.first.ToString() + && keyOne.first.ToString() != keyThree.first.ToString()); + + LogPrint("fluid", "CheckSignatureQuorum(): Addresses validating this consent token are: %s, %s and %s\n", keyOne.first.ToString(), keyTwo.first.ToString(), keyThree.first.ToString()); + + if (individual) + return (keyOne.second || keyTwo.second || keyThree.second); + else if (fValid) + return (keyOne.second && keyTwo.second && keyThree.second); + + return false; } \ No newline at end of file diff --git a/src/fluid/fluiddb.h b/src/fluid/fluiddb.h index 78fe398d0a..e127113c8f 100644 --- a/src/fluid/fluiddb.h +++ b/src/fluid/fluiddb.h @@ -11,13 +11,15 @@ class CFluidMining; class CFluidMint; class CFluidSovereign; -CAmount GetFluidDynodeReward(); -CAmount GetFluidMiningReward(); +CAmount GetFluidDynodeReward(const int nHeight); +CAmount GetFluidMiningReward(const int nHeight); bool GetMintingInstructions(const int nHeight, CFluidMint& fluidMint); bool IsSovereignAddress(const CDynamicAddress& inputAddress); bool GetAllFluidDynodeRecords(std::vector& dynodeEntries); bool GetAllFluidMiningRecords(std::vector& miningEntries); bool GetAllFluidMintRecords(std::vector& mintEntries); bool GetAllFluidSovereignRecords(std::vector& sovereignEntries); +bool GetLastFluidSovereignAddressStrings(std::vector& sovereignAddresses); +bool CheckSignatureQuorum(const std::vector& vchFluidScript, std::string& errMessage, bool individual = false); -#endif // FLUID_DYNODE_H +#endif // FLUID_DB_H diff --git a/src/fluid/fluiddynode.cpp b/src/fluid/fluiddynode.cpp index 97a33b2e68..d904344572 100644 --- a/src/fluid/fluiddynode.cpp +++ b/src/fluid/fluiddynode.cpp @@ -109,7 +109,7 @@ bool CFluidDynodeDB::AddFluidDynodeEntry(const CFluidDynode& entry, const int op return writeState; } -bool CFluidDynodeDB::GetLastFluidDynodeRecord(CFluidDynode& returnEntry) +bool CFluidDynodeDB::GetLastFluidDynodeRecord(CFluidDynode& returnEntry, const int nHeight) { LOCK(cs_fluid_dynode); returnEntry.SetNull(); @@ -122,7 +122,10 @@ bool CFluidDynodeDB::GetLastFluidDynodeRecord(CFluidDynode& returnEntry) try { if (pcursor->GetKey(key) && key.first == "script") { pcursor->GetValue(entry); - if (entry.nHeight > returnEntry.nHeight) { + if (entry.IsNull()) { + return false; + } + if (entry.nHeight > returnEntry.nHeight && (int)(entry.nHeight + 1) < nHeight) { returnEntry = entry; } } @@ -183,6 +186,13 @@ bool CFluidDynodeDB::IsEmpty() return true; } +bool CFluidDynodeDB::RecordExists(const std::vector& vchFluidScript) +{ + LOCK(cs_fluid_dynode); + CFluidDynode fluidDynode; + return CDBWrapper::Read(make_pair(std::string("script"), vchFluidScript), fluidDynode); +} + bool CheckFluidDynodeDB() { if (!pFluidDynodeDB) diff --git a/src/fluid/fluiddynode.h b/src/fluid/fluiddynode.h index bdb2311bfd..4376beaa1e 100644 --- a/src/fluid/fluiddynode.h +++ b/src/fluid/fluiddynode.h @@ -95,9 +95,10 @@ class CFluidDynodeDB : public CDBWrapper { public: CFluidDynodeDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); bool AddFluidDynodeEntry(const CFluidDynode& entry, const int op); - bool GetLastFluidDynodeRecord(CFluidDynode& returnEntry); + bool GetLastFluidDynodeRecord(CFluidDynode& returnEntry, const int nHeight); bool GetAllFluidDynodeRecords(std::vector& entries); bool IsEmpty(); + bool RecordExists(const std::vector& vchFluidScript); }; bool GetFluidDynodeData(const CScript& scriptPubKey, CFluidDynode& entry); diff --git a/src/fluid/fluidmining.cpp b/src/fluid/fluidmining.cpp index be14e9550e..ba1ade66e7 100644 --- a/src/fluid/fluidmining.cpp +++ b/src/fluid/fluidmining.cpp @@ -109,7 +109,7 @@ bool CFluidMiningDB::AddFluidMiningEntry(const CFluidMining& entry, const int op return writeState; } -bool CFluidMiningDB::GetLastFluidMiningRecord(CFluidMining& returnEntry) +bool CFluidMiningDB::GetLastFluidMiningRecord(CFluidMining& returnEntry, const int nHeight) { LOCK(cs_fluid_mining); returnEntry.SetNull(); @@ -122,7 +122,10 @@ bool CFluidMiningDB::GetLastFluidMiningRecord(CFluidMining& returnEntry) try { if (pcursor->GetKey(key) && key.first == "script") { pcursor->GetValue(entry); - if (entry.nHeight > returnEntry.nHeight) + if (entry.IsNull()) { + return false; + } + if (entry.nHeight > returnEntry.nHeight && (int)(entry.nHeight + 1) < nHeight) { returnEntry = entry; } @@ -184,6 +187,13 @@ bool CFluidMiningDB::IsEmpty() return true; } +bool CFluidMiningDB::RecordExists(const std::vector& vchFluidScript) +{ + LOCK(cs_fluid_mining); + CFluidMining fluidMining; + return CDBWrapper::Read(make_pair(std::string("script"), vchFluidScript), fluidMining); +} + bool CheckFluidMiningDB() { if (!pFluidMiningDB) diff --git a/src/fluid/fluidmining.h b/src/fluid/fluidmining.h index 8cdc03fca2..a4ef53a17d 100644 --- a/src/fluid/fluidmining.h +++ b/src/fluid/fluidmining.h @@ -95,9 +95,10 @@ class CFluidMiningDB : public CDBWrapper { public: CFluidMiningDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); bool AddFluidMiningEntry(const CFluidMining& entry, const int op); - bool GetLastFluidMiningRecord(CFluidMining& returnEntry); + bool GetLastFluidMiningRecord(CFluidMining& returnEntry, const int nHeight); bool GetAllFluidMiningRecords(std::vector& entries); bool IsEmpty(); + bool RecordExists(const std::vector& vchFluidScript); }; bool GetFluidMiningData(const CScript& scriptPubKey, CFluidMining& entry); diff --git a/src/fluid/fluidmint.cpp b/src/fluid/fluidmint.cpp index 4991294225..7129603f8e 100644 --- a/src/fluid/fluidmint.cpp +++ b/src/fluid/fluidmint.cpp @@ -24,7 +24,7 @@ bool GetFluidMintData(const CScript& scriptPubKey, CFluidMint& entry) std::vector vecSplitScript; SeparateFluidOpString(verificationWithoutOpCode, vecSplitScript); - if (vecSplitScript.size() == 6 && strOperationCode == "OP_MINT") { + if (vecSplitScript.size() >= 6 && strOperationCode == "OP_MINT") { std::vector vchFluidOperation = CharVectorFromString(fluidOperationString); entry.FluidScript.insert(entry.FluidScript.end(), vchFluidOperation.begin(), vchFluidOperation.end()); std::string strAmount = vecSplitScript[0]; @@ -193,6 +193,13 @@ bool CFluidMintDB::IsEmpty() return true; } +bool CFluidMintDB::RecordExists(const std::vector& vchFluidScript) +{ + LOCK(cs_fluid_mint); + CFluidMint fluidMint; + return CDBWrapper::Read(make_pair(std::string("script"), vchFluidScript), fluidMint); +} + bool CheckFluidMintDB() { if (!pFluidMintDB) diff --git a/src/fluid/fluidmint.h b/src/fluid/fluidmint.h index 6fb1bbf9e5..403861d3df 100644 --- a/src/fluid/fluidmint.h +++ b/src/fluid/fluidmint.h @@ -104,6 +104,7 @@ class CFluidMintDB : public CDBWrapper { bool GetLastFluidMintRecord(CFluidMint& returnEntry); bool GetAllFluidMintRecords(std::vector& entries); bool IsEmpty(); + bool RecordExists(const std::vector& vchFluidScript); }; bool GetFluidMintData(const CScript& scriptPubKey, CFluidMint& entry); diff --git a/src/fluid/fluidsovereign.cpp b/src/fluid/fluidsovereign.cpp index 026f4683f0..1918ec4124 100644 --- a/src/fluid/fluidsovereign.cpp +++ b/src/fluid/fluidsovereign.cpp @@ -85,6 +85,15 @@ void CFluidSovereign::Serialize(std::vector& vchData) { vchData = std::vector(dsFluidOp.begin(), dsFluidOp.end()); } +std::vector CFluidSovereign::SovereignAddressesStrings() +{ + std::vector vchAddressStrings; + for (const std::vector& vchAddress: SovereignAddresses) { + vchAddressStrings.push_back(StringFromCharVector(vchAddress)); + } + return vchAddressStrings; +} + CFluidSovereignDB::CFluidSovereignDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "blocks" / "fluid-sovereign", nCacheSize, fMemory, fWipe, obfuscate) { InitEmpty(); diff --git a/src/fluid/fluidsovereign.h b/src/fluid/fluidsovereign.h index 844999bc46..f93283b261 100644 --- a/src/fluid/fluidsovereign.h +++ b/src/fluid/fluidsovereign.h @@ -83,6 +83,7 @@ class CFluidSovereign { bool UnserializeFromTx(const CTransaction& tx); bool UnserializeFromScript(const CScript& fluidScript); void Serialize(std::vector& vchData); + std::vector SovereignAddressesStrings(); }; static CCriticalSection cs_fluid_sovereign; diff --git a/src/fluid/rpcfluid.cpp b/src/fluid/rpcfluid.cpp index 1e8d6d17f9..dc7ff11f87 100644 --- a/src/fluid/rpcfluid.cpp +++ b/src/fluid/rpcfluid.cpp @@ -371,11 +371,11 @@ UniValue getfluidhistoryraw(const JSONRPCRequest& request) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("total_minted", FormatMoney(totalMintedCoins))); obj.push_back(Pair("total_fluid_fee_cost", FormatMoney(totalFluidTxCost))); - CAmount dynodeReward = GetFluidDynodeReward(); + CAmount dynodeReward = GetFluidDynodeReward(chainActive.Tip()->nHeight); obj.push_back(Pair("current_dynode_reward", FormatMoney(dynodeReward))); CFluidMining lastMiningRecord; - CAmount miningAmount = GetFluidMiningReward(); + CAmount miningAmount = GetFluidMiningReward(chainActive.Tip()->nHeight); obj.push_back(Pair("current_mining_reward", FormatMoney(miningAmount))); obj.push_back(Pair("total_fluid_transactions", nTotal)); oSummary.push_back(Pair("summary", obj)); @@ -513,10 +513,10 @@ UniValue getfluidhistory(const JSONRPCRequest& request) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("total_minted", FormatMoney(totalMintedCoins))); obj.push_back(Pair("total_fluid_fee_cost", FormatMoney(totalFluidTxCost))); - CAmount dynodeReward = GetFluidDynodeReward(); + CAmount dynodeReward = GetFluidDynodeReward(chainActive.Tip()->nHeight); obj.push_back(Pair("current_dynode_reward", FormatMoney(dynodeReward))); CFluidMining lastMiningRecord; - CAmount miningAmount = GetFluidMiningReward(); + CAmount miningAmount = GetFluidMiningReward(chainActive.Tip()->nHeight); obj.push_back(Pair("current_mining_reward", FormatMoney(miningAmount))); obj.push_back(Pair("total_fluid_transactions", nTotal)); oSummary.push_back(Pair("summary", obj)); diff --git a/src/miner.cpp b/src/miner.cpp index 6a9f782957..3e962cf384 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -320,7 +320,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, } //TODO fluid - CAmount blockReward = GetFluidMiningReward(); + CAmount blockReward = GetFluidMiningReward(nHeight); CDynamicAddress mintAddress; CAmount fluidIssuance = 0; CFluidMint fluidMint; diff --git a/src/validation.cpp b/src/validation.cpp index ddc1070028..abb4485d8b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -17,6 +17,7 @@ #include "dynode-payments.h" #include "dynode-sync.h" #include "fluid/fluid.h" +#include "fluid/fluiddb.h" #include "fluid/fluiddynode.h" #include "fluid/fluidmining.h" #include "fluid/fluidmint.h" @@ -2196,31 +2197,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } - CScript scriptFluid; - if (IsTransactionFluid(tx, scriptFluid)) { - int OpCode = GetFluidOpCode(scriptFluid); - if (OpCode == OP_REWARD_DYNODE) { - CFluidDynode fluidDynode(scriptFluid); - fluidDynode.nHeight = pindex->nHeight; - fluidDynode.txHash = tx.GetHash(); - if (CheckFluidDynodeDB()) - pFluidDynodeDB->AddFluidDynodeEntry(fluidDynode, OP_REWARD_DYNODE); - } - else if (OpCode == OP_REWARD_MINING) { - CFluidMining fluidMining(scriptFluid); - fluidMining.nHeight = pindex->nHeight; - fluidMining.txHash = tx.GetHash(); - if (CheckFluidMiningDB()) - pFluidMiningDB->AddFluidMiningEntry(fluidMining, OP_REWARD_MINING); - } - else if (OpCode == OP_MINT) { - CFluidMint fluidMint(scriptFluid); - fluidMint.nHeight = pindex->nHeight; - fluidMint.txHash = tx.GetHash(); - if (CheckFluidMintDB()) - pFluidMintDB->AddFluidMintEntry(fluidMint, OP_MINT); - } - } if (fAddressIndex || fSpentIndex) { for (size_t j = 0; j < tx.vin.size(); j++) { @@ -2361,77 +2337,80 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd fDynodePaid = false; } + // BEGIN FLUID CAmount nExpectedBlockValue; std::string strError = ""; { - //TODO fluid - /* CBlockIndex* prevIndex = pindex->pprev; - CFluidEntry prevFluidIndex = pindex->pprev->fluidParams; - - CFluidEntry FluidIndex; - - CAmount fluidIssuance, newReward = 0, newDynodeReward = 0; + CAmount newMiningReward = GetFluidMiningReward(pindex->nHeight); + CAmount newDynodeReward = 0; + if (fDynodePaid) + newDynodeReward = GetFluidDynodeReward(pindex->nHeight); + + CAmount newMintIssuance = 0; CDynamicAddress mintAddress; - - if (!fluid.GetProofOverrideRequest(pindex->pprev, newReward) && prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { - FluidIndex.blockReward = (prevIndex? prevFluidIndex.blockReward : 0); - } else { - FluidIndex.blockReward = newReward; + if (prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) + { + CFluidMint fluidMint; + if (GetMintingInstructions(pindex->nHeight, fluidMint)) { + newMintIssuance = fluidMint.MintAmount; + mintAddress = fluidMint.GetDestinationAddress(); + LogPrintf("ConnectBlock, GetMintingInstructions MintAmount = %u\n", fluidMint.MintAmount); + } } + nExpectedBlockValue = newMintIssuance + newMiningReward + newDynodeReward; - if (!fluid.GetDynodeOverrideRequest(pindex->pprev, newDynodeReward) && prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { - FluidIndex.dynodeReward = (prevIndex? prevFluidIndex.dynodeReward : 0); - } else { - FluidIndex.dynodeReward = newDynodeReward; - } - - if (fluid.GetMintingInstructions(pindex->pprev, mintAddress, fluidIssuance) - && pindex->nHeight >= fluid.FLUID_ACTIVATE_HEIGHT) { - nExpectedBlockValue = getDynodeSubsidyWithOverride(prevFluidIndex.dynodeReward, fDynodePaid) - + getBlockSubsidyWithOverride(prevIndex->nHeight, prevFluidIndex.blockReward) - + fluidIssuance; - } else { - nExpectedBlockValue = getDynodeSubsidyWithOverride(prevFluidIndex.dynodeReward, fDynodePaid) - + getBlockSubsidyWithOverride(prevIndex->nHeight, prevFluidIndex.blockReward); - } - - std::vector fluidHistory, fluidSovereigns; - if(!IsBlockValueValid(block, pindex->nHeight, nExpectedBlockValue, strError)) { return state.DoS(0, error("ConnectBlock(DYN): %s", strError), REJECT_INVALID, "bad-cb-amount"); } - if (!IsBlockPayeeValid(block.vtx[0], pindex->nHeight, nExpectedBlockValue)) { mapRejectedBlocks.insert(std::make_pair(block.GetHash(), GetTime())); return state.DoS(0, error("ConnectBlock(DYN): couldn't find Dynode or Superblock payments"), REJECT_INVALID, "bad-cb-payee"); } - - if (prevIndex->nHeight + 1 >= fluid.FLUID_ACTIVATE_HEIGHT) { - fluidHistory.insert(fluidHistory.end(), prevFluidIndex.fluidHistory.begin(), prevFluidIndex.fluidHistory.end()); - fluid.AddFluidTransactionsToRecord(prevIndex, fluidHistory); - std::set setX(fluidHistory.begin(), fluidHistory.end()); - fluidHistory.assign(setX.begin(), setX.end()); - - FluidIndex.fluidHistory = fluidHistory; - - for (uint32_t x = 0; x != fluid.InitialiseSovereignIdentities().size(); x++) { - //std::string error; - //CDynamicAddress inputKey; // Reinitialise at each iteration to reset value - //CNameVal val = nameValFromString(fluid.InitialiseIdentities().at(x)); - - //if (!GetNameCurrentAddress(val, inputKey, error)) - // fluidSovereigns.push_back(inputKey.ToString()); - //else - fluidSovereigns.push_back(prevFluidIndex.fluidSovereigns.at(x)); + } + for (unsigned int i = 0; i < block.vtx.size(); i++) + { + const CTransaction &tx = block.vtx[i]; + CScript scriptFluid; + if (IsTransactionFluid(tx, scriptFluid)) { + int OpCode = GetFluidOpCode(scriptFluid); + if (OpCode == OP_REWARD_DYNODE) { + CFluidDynode fluidDynode(scriptFluid); + fluidDynode.nHeight = pindex->nHeight; + fluidDynode.txHash = tx.GetHash(); + if (CheckFluidDynodeDB()) { + if (!CheckSignatureQuorum(fluidDynode.FluidScript, strError)) { + return state.DoS(0, error("ConnectBlock(DYN): %s", strError), REJECT_INVALID, "invalid-fluid-dynode-address-signature"); + } + pFluidDynodeDB->AddFluidDynodeEntry(fluidDynode, OP_REWARD_DYNODE); + } + } + else if (OpCode == OP_REWARD_MINING) { + CFluidMining fluidMining(scriptFluid); + fluidMining.nHeight = pindex->nHeight; + fluidMining.txHash = tx.GetHash(); + if (CheckFluidMiningDB()) { + if (!CheckSignatureQuorum(fluidMining.FluidScript, strError)) { + return state.DoS(0, error("ConnectBlock(DYN): %s", strError), REJECT_INVALID, "invalid-fluid-mining-address-signature"); + } + pFluidMiningDB->AddFluidMiningEntry(fluidMining, OP_REWARD_MINING); + } + } + else if (OpCode == OP_MINT) { + CFluidMint fluidMint(scriptFluid); + fluidMint.nHeight = pindex->nHeight; + fluidMint.txHash = tx.GetHash(); + if (CheckFluidMintDB()) { + if (!CheckSignatureQuorum(fluidMint.FluidScript, strError)) { + return state.DoS(0, error("ConnectBlock(DYN): %s", strError), REJECT_INVALID, "invalid-fluid-mint-address-signature"); + } + pFluidMintDB->AddFluidMintEntry(fluidMint, OP_MINT); + } } } - pindex->fluidParams = FluidIndex; - */ } - - // END DYNAMIC + // END FLUID if (!control.Wait()) return state.DoS(100, false); From 368c1c5d83e4c6a36ded00bfaa8522a0e3804bef Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Thu, 6 Sep 2018 16:12:17 -0500 Subject: [PATCH 0206/1653] [BDAP] Fix forward declaration for CRecipient (class -> struct) --- src/bdap/domainentry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index 3a657a4324..4579c32154 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -16,7 +16,7 @@ class CCoinsViewCache; class CDynamicAddress; -class CRecipient; +struct CRecipient; class CTransaction; class CTxOut; class CTxMemPool; From c66c3f19044e222eeb80a7eb027b5e823b948e4a Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Fri, 7 Sep 2018 03:01:55 +0200 Subject: [PATCH 0207/1653] Update CHANGELOG.md --- CHANGELOG.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e214042c9..b184a55bec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,81 @@ **Dynamic v2.4.0.0** +* Remove unused serialization method +* Fix consts in txmempool +* [depends] upgrade boost to 1.67.0 +* [depends] upgrade dbus to 1.13.4 +* [depends] update expad download path +* [depends] upgrade freetype to 2.9.1 +* [depends] update libevent download path +* [depends] upgrade libxcb to 1.13 +* [depends] upgrade miniupnpc to 2.1 +* [depends] upgrade native_biplist to 1.0.3 +* [depends] upgrade native_ccache to 3.4.2 +* [depends] update native_ds_store download path +* [depends] upgrade native_mac_alias to 2.0.7 +* [depends] upgrade native_protobuf to 3.6.0 +* [depends] update openssl to 1.0.1k - Add RISC-V support +* [depends] upgrade qt to 5.9.6 +* [depends] upgrade qrencode +* [depends] upgrade xcb_proto to 1.13 +* [depends] upgrade xtrans to 1.3.5 +* [depends] upgrade zeromq to 4.2.5 +* [depends] add fix_configure_mac.patch file +* [depends] add fix_no_printer.patch file +* [depends] update mac-qmake.conf patch file +* [BDAP] Add directory type function +* [BDAP] Implement add new entry validation checking +* [BDAP] Fix validation when syncing blocks from peers +* [BDAP] Implement directory entry list RPC command +* [BDAP] Add getdirectoryinfo RPC command +* [BDAP] Add leveldb update method to db wrapper class +* [BDAP] Fix validate input function; leveldb check not DOS +* [BDAP] Update getdirectoryinfo help parameter +* [BDAP] Implement update & delete entry tx validation checking +* [BDAP] Fix saving tx hash in leveldb bdap database +* [BDAP] Replace updatedirectory RPC command +* [BDAP] Fix getdirectoryinfo return when entry not found +* [BDAP] Fix expire time in RPC commands +* [BDAP] Refactor directory to domainentry +* [BDAP] Add domain entry link class for binding operations +* [BDAP] Refactor domain entry certificate and move to its own class +* [BDAP] Refactor domain entry checkpoints and move to its own class +* [BDAP] Refactor domain entry channel data and move to its own class +* [BDAP] Check if tx exists in memory pool for new domain entries +* [BDAP] Update RPC command names +* [BDAP] Check domain entry wallet address and encrypt pub key +* [BDAP] Remove SignWalletAddress in domain entry. Only use WalletAddress +* [BDAP] Check ownership in updatedomainentry RPC command +* [BDAP] Fix domain entry so it populates block height +* [BDAP] Add code to check domain entry's previous UTXO +* Remove duplicate mem pool check in wallet available coins +* [BDAP] Add link address to domain entry class +* [BDAP] Check previous wallet address for update and delete txs +* [BDAP] Add delete domain entry RPC command +* [BDAP] Allow blank link address and encrypt pub key for delete operations +* [Fluid] Fix segfault when running reindex +* Move makekeypair to BDAP and change testnet spork pub key +* [BDAP] Add identity and identity verification classes +* [BDAP] Add missing operation codes +* [BDAP] Adjust identity verification class +* [BDAP] Fix domain entry object type enum +* [BDAP] Add entry audit data class +* [BDAP] Add new public group entry RPC command +* [BDAP] Add list domain group entries RPC command +* [BDAP] Add update and delete public group RPC commands +* Corrected the documentation for Fluid RPC Calls +* [BDAP] Refactor general functions and fix get op type +* [BDAP] Improve transaction display in Qt UI +* Added more seednodes +* Remove double forcecompactdb arg +* [Fluid] Refactor fluid code and remove index database +* [BDAP] Remove fluid reference from domain entry +* [Fluid] Add mining update and mint leveldb databases +* [Fluid] Implement new fluid databases +* [Fluid] Fix get fluid sovereigns RPC +* [Fluid] Fixes to get last functions and RPC commands +* [Fluid] Fix consensus issues with new db code * Drop delayed headers logic and fix duplicate initial headers sync * replace boost iterators with for * RPC: Add description for InstantSend-related fields of mempool entry From b324ab09e566cea25e9332ef19f647089c15cb0d Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Tue, 11 Sep 2018 16:46:07 -0500 Subject: [PATCH 0208/1653] Seperate CPU and GPU miners to fix hashmeters --- src/init.cpp | 5 +- src/miner.cpp | 239 +++++++++++++++++++++++++++++------------- src/miner.h | 6 +- src/qt/miningpage.cpp | 3 +- src/rpcmining.cpp | 3 +- 5 files changed, 179 insertions(+), 77 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 7ef98558bb..dd819a7380 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -239,7 +239,7 @@ void PrepareShutdown() if (pwalletMain) pwalletMain->Flush(false); #endif - GenerateDynamics(false, 0, Params(), *g_connman); + ShutdownMiners(); MapPort(false); UnregisterValidationInterface(peerLogic.get()); peerLogic.reset(); @@ -1853,7 +1853,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Generate coins in the background if (GetBoolArg("-gen", DEFAULT_GENERATE)) { - GenerateDynamics(GetArg("-genproclimit", DEFAULT_GENERATE_THREADS_CPU), GetArg("-genproclimit-gpu", DEFAULT_GENERATE_THREADS_GPU), chainparams, connman); + GenerateDynamicsCPU(GetArg("-genproclimit", DEFAULT_GENERATE_THREADS_CPU), chainparams, connman); + GenerateDynamicsGPU(GetArg("-genproclimit-gpu", DEFAULT_GENERATE_THREADS_GPU), chainparams, connman); } // ********************************************************* Step 13: finished diff --git a/src/miner.cpp b/src/miner.cpp index a4523c5793..b089d93a47 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -403,7 +403,8 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned // double dCPUHashesPerSec = 0.0; double dGPUHashesPerSec = 0.0; -int64_t nHPSTimerStart = 0; +int64_t nCPUHPSTimerStart = 0; +int64_t nGPUHPSTimerStart = 0; int64_t GetHashRate() { @@ -412,14 +413,14 @@ int64_t GetHashRate() int64_t GetCPUHashRate() { - if (GetTimeMillis() - nHPSTimerStart > 8000) + if (GetTimeMillis() - nCPUHPSTimerStart > 8000) return (int64_t)0; return (int64_t)(dCPUHashesPerSec); } int64_t GetGPUHashRate() { - if (GetTimeMillis() - nHPSTimerStart > 8000) + if (GetTimeMillis() - nGPUHPSTimerStart > 8000) return (int64_t)0; return (int64_t)(dGPUHashesPerSec); } @@ -541,9 +542,8 @@ class BaseMiner CConnman& connman; public: - BaseMiner(const CChainParams& chainparams, CConnman& connman, double* hashesPerSec, std::string deviceName, boost::optional deviceIndex = boost::none); + BaseMiner(const CChainParams& chainparams, CConnman& connman, double* hashesPerSec, int64_t* nHPSTimerStart, std::string deviceName, boost::optional deviceIndex = boost::none); -private: std::string deviceName; boost::optional deviceIndex; @@ -551,6 +551,7 @@ class BaseMiner unsigned int nExtraNonce = 0; double* dHashesPerSec; + int64_t* nHPSTimerStart; // set by CreateNewMinerBlock CBlockIndex* pindexPrev; @@ -559,9 +560,7 @@ class BaseMiner // set in StartLoop boost::shared_ptr coinbaseScript; -private: bool IsBlockSynced(CBlock* pblock); - void IncrementHashesDone(unsigned int nHashesDone); std::unique_ptr CreateNewMinerBlock(); @@ -575,18 +574,16 @@ class BaseMiner // this is single method required to implement miner // returned number is amount of hashes processed virtual unsigned int TryMineBlock(CBlock* pblock) = 0; - -public: - // starts miner loop - void StartLoop(); }; -BaseMiner::BaseMiner(const CChainParams& chainparams, CConnman& connman, double* hashesPerSec, std::string deviceName, boost::optional deviceIndex) +BaseMiner::BaseMiner(const CChainParams& chainparams, CConnman& connman, double* hashesPerSec, int64_t* nHPSTimerStart, std::string deviceName, boost::optional deviceIndex) : chainparams(chainparams), connman(connman), deviceName(deviceName), deviceIndex(deviceIndex), - dHashesPerSec(hashesPerSec) {} + dHashesPerSec(hashesPerSec), + nHPSTimerStart(nHPSTimerStart) + {} void BaseMiner::ProcessFoundSolution(CBlock* pblock, const uint256& hash) { @@ -625,23 +622,74 @@ bool BaseMiner::IsBlockSynced(CBlock* pblock) return true; } -void BaseMiner::IncrementHashesDone(unsigned int nHashesDone) +std::unique_ptr BaseMiner::CreateNewMinerBlock() +{ + // Wait for blocks if required + WaitForNetworkInit(chainparams, connman); + // Create new block + nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + pindexPrev = chainActive.Tip(); + if (!pindexPrev) { + return nullptr; + } + return CreateNewBlock(chainparams, coinbaseScript->reserveScript); +} + +class CPUMiner : public BaseMiner +{ +public: + CPUMiner(const CChainParams& chainparams, CConnman& connman); + // starts miner loop + void StartLoop(); + +private: + void IncrementHashesDone(unsigned int nHashesDone); + +protected: + virtual unsigned int TryMineBlock(CBlock* pblock) override; + +}; + +CPUMiner::CPUMiner(const CChainParams& chainparams, CConnman& connman) + : BaseMiner(chainparams, connman, &dCPUHashesPerSec, &nCPUHPSTimerStart, "CPU") {} + +unsigned int CPUMiner::TryMineBlock(CBlock* pblock) +{ + unsigned int nHashesDone = 0; + while (true) { + uint256 hash = pblock->GetHash(); + if (UintToArith256(hash) <= hashTarget) { + this->ProcessFoundSolution(pblock, hash); + break; + } + pblock->nNonce += 1; + nHashesDone += 1; + if ((pblock->nNonce & 0xFF) == 0) + break; + } + return nHashesDone; +} + +void CPUMiner::IncrementHashesDone(unsigned int nHashesDone) { static int64_t nHashCounter = 0; static int64_t nLogTime = 0; + static CCriticalSection cs; - if (nHPSTimerStart == 0) { - nHPSTimerStart = GetTimeMillis(); + int64_t nTimerStart = *nHPSTimerStart; + if (nTimerStart == 0) { + LOCK(cs); + *nHPSTimerStart = GetTimeMillis(); nHashCounter = 0; + return; } else { nHashCounter += nHashesDone; } - - static CCriticalSection cs; - if (GetTimeMillis() - nHPSTimerStart > 4000) { + + if (GetTimeMillis() - nTimerStart > 4000) { LOCK(cs); - *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = GetTimeMillis(); + *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nTimerStart); + *nHPSTimerStart = GetTimeMillis(); nHashCounter = 0; if (GetTime() - nLogTime > 30 * 60) { nLogTime = GetTime(); @@ -650,20 +698,7 @@ void BaseMiner::IncrementHashesDone(unsigned int nHashesDone) } } -std::unique_ptr BaseMiner::CreateNewMinerBlock() -{ - // Wait for blocks if required - WaitForNetworkInit(chainparams, connman); - // Create new block - nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - pindexPrev = chainActive.Tip(); - if (!pindexPrev) { - return nullptr; - } - return CreateNewBlock(chainparams, coinbaseScript->reserveScript); -} - -void BaseMiner::StartLoop() +void CPUMiner::StartLoop() { std::size_t device = deviceIndex ? *deviceIndex : 0; LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, device); @@ -713,55 +748,31 @@ void BaseMiner::StartLoop() } } -class CPUMiner : public BaseMiner -{ -public: - CPUMiner(const CChainParams& chainparams, CConnman& connman); - -protected: - virtual unsigned int TryMineBlock(CBlock* pblock) override; -}; - -CPUMiner::CPUMiner(const CChainParams& chainparams, CConnman& connman) - : BaseMiner(chainparams, connman, &dCPUHashesPerSec, "CPU") {} - -unsigned int CPUMiner::TryMineBlock(CBlock* pblock) -{ - unsigned int nHashesDone = 0; - while (true) { - uint256 hash = pblock->GetHash(); - if (UintToArith256(hash) <= hashTarget) { - this->ProcessFoundSolution(pblock, hash); - break; - } - pblock->nNonce += 1; - nHashesDone += 1; - if ((pblock->nNonce & 0xFF) == 0) - break; - } - return nHashesDone; -} - #ifdef ENABLE_GPU class GPUMiner : public BaseMiner { public: GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex); + // starts miner loop + void StartLoop(); protected: virtual unsigned int TryMineBlock(CBlock* pblock) override; private: + void IncrementHashesDone(unsigned int nHashesDone); + Argon2GPUContext global; Argon2GPUParams params; Argon2GPUDevice device; Argon2GPUProgramContext context; std::size_t batchSizeTarget; Argon2GPU processingUnit; + }; GPUMiner::GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size_t deviceIndex) - : BaseMiner(chainparams, connman, &dGPUHashesPerSec, "GPU", deviceIndex), + : BaseMiner(chainparams, connman, &dGPUHashesPerSec, &nGPUHPSTimerStart, "GPU", deviceIndex), global(), params((std::size_t)OUTPUT_BYTES, 2, 500, 8), device(global.getAllDevices()[deviceIndex]), @@ -807,6 +818,84 @@ unsigned int GPUMiner::TryMineBlock(CBlock* pblock) } return nHashesDone; } + +void GPUMiner::IncrementHashesDone(unsigned int nHashesDone) +{ + static int64_t nHashCounter = 0; + static int64_t nLogTime = 0; + static CCriticalSection cs; + + int64_t nTimerStart = *nHPSTimerStart; + if (nTimerStart == 0) { + LOCK(cs); + *nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + return; + } else { + nHashCounter += nHashesDone; + } + + if (GetTimeMillis() - nTimerStart > 4000) { + LOCK(cs); + *dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nTimerStart); + *nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + if (GetTime() - nLogTime > 30 * 60) { + nLogTime = GetTime(); + LogPrintf("%s hashmeter %6.0f khash/s\n", deviceName, *dHashesPerSec / 1000.0); + } + } +} + +void GPUMiner::StartLoop() +{ + std::size_t device = deviceIndex ? *deviceIndex : 0; + LogPrintf("DynamicMiner%s -- started #%u\n", deviceName, device); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread(tfm::format("dynamic-%s-miner-%u", deviceName, device).data()); + GetMainSignals().ScriptForMining(coinbaseScript); + + try { + // Throw an error if no script was provided. This can happen + // due to some internal error but also if the keypool is empty. + // In the latter case, already the pointer is NULL. + if (!coinbaseScript || coinbaseScript->reserveScript.empty()) + throw std::runtime_error("No coinbase script available (mining requires a wallet)"); + + while (true) { + std::unique_ptr pblocktemplate = this->CreateNewMinerBlock(); + if (!pblocktemplate) { + LogPrintf("DynamicMiner%s -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n", deviceName); + return; + } + CBlock* pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + LogPrintf("DynamicMiner%s -- Running miner with %u transactions in block (%u bytes)\n", deviceName, pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + + // set loop start for counter + nStart = GetTime(); + hashTarget = arith_uint256().SetCompact(pblock->nBits); + // start mining the block + while (true) { + // try mining the block + auto hashesDone = this->TryMineBlock(pblock); + // increment hash statistics + this->IncrementHashesDone(hashesDone); + // check if miner is in sync with blockchain + if (!this->IsBlockSynced(pblock)) + break; + } + } + } catch (const boost::thread_interrupted&) { + LogPrintf("DynamicMiner%s -- terminated\n", deviceName); + throw; + } catch (const std::runtime_error& e) { + LogPrintf("DynamicMiner%s -- runtime error: %s\n", deviceName, e.what()); + return; + } +} #endif // ENABLE_GPU } // namespace miners @@ -825,15 +914,15 @@ static void DynamicMinerCPU(const CChainParams& chainparams, CConnman& connman) miner.StartLoop(); } -void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman) +void GenerateDynamicsCPU(int nCPUThreads, const CChainParams& chainparams, CConnman& connman) { - if (nCPUThreads == 0 && nGPUThreads == 0) { + if (nCPUThreads == 0) { LogPrintf("DynamicMiner -- disabled -- CPU and GPU Threads set to zero\n"); return; } int nNumCores = GetNumCores(); - LogPrintf("DynamicMiner -- CPU Cores: %u\n", nNumCores); + //LogPrintf("DynamicMiner -- CPU Cores: %u\n", nNumCores); if (nCPUThreads < 0 || nCPUThreads > nNumCores) nCPUThreads = nNumCores; @@ -842,13 +931,21 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai std::size_t nCPUTarget = static_cast(nCPUThreads); boost::thread_group* cpuMinerThreads = miners::ThreadGroup(); while (cpuMinerThreads->size() < nCPUTarget) { - LogPrintf("Starting CPU Miner thread #%u\n", cpuMinerThreads->size()); + //LogPrintf("Starting CPU Miner thread #%u\n", cpuMinerThreads->size()); cpuMinerThreads->create_thread(boost::bind(&DynamicMinerCPU, boost::cref(chainparams), boost::ref(connman))); } +} +void GenerateDynamicsGPU(int nGPUThreads, const CChainParams& chainparams, CConnman& connman) +{ #ifdef ENABLE_GPU + if (nGPUThreads == 0) { + LogPrintf("DynamicMiner -- disabled -- CPU and GPU Threads set to zero\n"); + return; + } + std::size_t devices = GetGPUDeviceCount(); - LogPrintf("DynamicMiner -- GPU Devices: %u\n", devices); + //LogPrintf("DynamicMiner -- GPU Devices: %u\n", devices); if (nGPUThreads < 0) nGPUThreads = 4; @@ -858,7 +955,7 @@ void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chai boost::thread_group* gpuMinerThreads = miners::ThreadGroup(); for (std::size_t device = 0; device < devices; device++) { for (std::size_t i = 0; i < nGPUTarget; i++) { - LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, device, devices); + //LogPrintf("Starting GPU Miner thread %u on device %u, total GPUs found %u\n", i, device, devices); gpuMinerThreads->create_thread(boost::bind(&DynamicMinerGPU, boost::cref(chainparams), boost::ref(connman), device)); } } diff --git a/src/miner.h b/src/miner.h index f2b3689619..37e213926a 100644 --- a/src/miner.h +++ b/src/miner.h @@ -42,8 +42,10 @@ struct CBlockTemplate { /** Check mined block */ bool CheckWork(const CChainParams& chainparams, CBlock* pblock, CWallet& wallet, CReserveKey& reservekey, CConnman* connman); #endif //ENABLE_WALLET -/** Run the miner threads */ -void GenerateDynamics(int nCPUThreads, int nGPUThreads, const CChainParams& chainparams, CConnman& connman); +/** Run the CPU miner thread(s) */ +void GenerateDynamicsCPU(int nCPUThreads, const CChainParams& chainparams, CConnman& connman); +/** Run the GPU miner thread(s) */ +void GenerateDynamicsGPU(int nGPUThreads, const CChainParams& chainparams, CConnman& connman); /** Shuts down all miner threads */ void ShutdownMiners(); /** Shuts down all CPU miner threads */ diff --git a/src/qt/miningpage.cpp b/src/qt/miningpage.cpp index 3f2928a78a..5f3d03286f 100644 --- a/src/qt/miningpage.cpp +++ b/src/qt/miningpage.cpp @@ -188,12 +188,13 @@ void MiningPage::StartMiner(bool fGPU) if (fGPU) { fGPUMinerOn = true; nGPUThreads = (int)ui->sliderGPUCores->value(); + GenerateDynamicsGPU(nGPUThreads, Params(), *g_connman); } else { fCPUMinerOn = true; nCPUThreads = (int)ui->sliderCPUCores->value(); + GenerateDynamicsCPU(nCPUThreads, Params(), *g_connman); } - GenerateDynamics(nCPUThreads, nGPUThreads, Params(), *g_connman); updateUI(); } diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 1854d19c45..7aa705f3de 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -344,7 +344,8 @@ UniValue setgenerate(const JSONRPCRequest& request) LogPrintf("setgenerate cpu = %u, gpu = %u \n", nGenProcLimit, nGenProcLimitGPU); if (fGenerate) { - GenerateDynamics(nGenProcLimit, nGenProcLimitGPU, Params(), *g_connman); + GenerateDynamicsCPU(nGenProcLimit, Params(), *g_connman); + GenerateDynamicsGPU(nGenProcLimitGPU, Params(), *g_connman); } else { ShutdownMiners(); } From 43758f46396e0cbf2f6f207b481e321de6194d64 Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Mon, 10 Sep 2018 23:40:40 +0200 Subject: [PATCH 0209/1653] Update README for GPU Mining --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 1c3a397db4..fe44a81e9b 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,19 @@ CPU's with AVX512 support: Skylake-X processor, 2017 Cannonlake processor, expected in 2018 Ice Lake processor, expected in 2018 + +GPU Mining +---------- +To enable GPU mining within the wallet, OpenCL or CUDA can be utilised. +(Please use GCC/G++ 6.4 or newer and for CUDA to be utilised please use NVCC 9.2 or newer) + +At configure time for non-Nvidia GPU's: + + --enable-gpu --disable-cuda + +At configure time for Nvidia GPU's: + + --enable-gpu --enable-cuda Example Build Command -------------------- From d47a1648a1bc9d4734b8da49a5847b8111e91f61 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Tue, 11 Sep 2018 19:59:14 -0500 Subject: [PATCH 0210/1653] Fix GPU found block nonce before ProcessFoundSolution --- src/miner.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/miner.cpp b/src/miner.cpp index b089d93a47..244150fcea 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -782,6 +782,7 @@ GPUMiner::GPUMiner(const CChainParams& chainparams, CConnman& connman, std::size unsigned int GPUMiner::TryMineBlock(CBlock* pblock) { + uint32_t startNonce = pblock->nNonce; unsigned int nHashesDone = 0; // current batch size std::size_t batchSize = batchSizeTarget; @@ -812,6 +813,7 @@ unsigned int GPUMiner::TryMineBlock(CBlock* pblock) for (std::size_t i = 0; i < batchSize; i++) { processingUnit.getHash(i, (uint8_t*)&hash); if (UintToArith256(hash) <= hashTarget) { + pblock->nNonce = startNonce + i; this->ProcessFoundSolution(pblock, hash); break; } From b1376b4a0a60f2d1e4659797b21c0d1d7b8b8469 Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Thu, 13 Sep 2018 13:43:36 +0200 Subject: [PATCH 0211/1653] Update CHANGELOG.md --- CHANGELOG.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b184a55bec..26f85ab0e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,70 @@ **Dynamic v2.4.0.0** +* [GPU] Fix GPU found block nonce before ProcessFoundSolution +* [GPU] Update README for GPU Mining +* [GPU] Seperate CPU and GPU miners to fix hashmeters +* [GPU] Fix Qt mining page layout so it expands +* [GPU] Fixes to miner UI controls +* [GPU] Hide slider until sync completes/change batch size +* [GPU] Split CPU/GPU UI thread allocation +* [GPU] fix global and order members as they appear in initializer +* [GPU] fix processingUnit batch size and minor code tweaks +* [GPU] fix autoreplace +* [GPU] move implementations out of definitions +* [GPU] fix const char* instead of std::string +* [GPU] fix unique_ptr null check +* [GPU] remove redundant comments and whitespace +* [GPU] fix thread names +* [GPU] remove redundant comments and whitespace +* [GPU] follow pattern and add this-> +* [GPU] remove redundant DynamicMiner function +* [GPU] explicit boost::none for boost::bind +* [GPU] fix boost::optional no value_or method error +* [GPU] reorder constructor initialization +* [GPU] move constructor code to base +* [GPU] move hashTarget to protected variables +* [GPU] fix non-pointer operand +* [GPU] move protected variables +* [GPU] fix CPUMiner constructor +* [GPU] track chain tip +* [GPU] remove name collison +* [GPU] add device index to base class +* [GPU] provide pblock to LoopChecks +* [GPU] remove unused template from BaseMiner +* [GPU] remove static from StartLoop +* [GPU] c++11 compatibility +* [GPU] cleanup thread constructor +* [GPU] remove unused assignment +* [GPU] nullptr comparisons +* [GPU] use boost::shared_ptr as expected +* [GPU] move transactionsUdatedLast to base class +* [GPU] enable_gpu ifdef +* [GPU] fix miner start loop call +* [GPU] rename namespace to miners +* [GPU] move threads to namespace +* [GPU] fix ptr ptr semantics +* [GPU] fix count hashes function params +* [GPU] mark function as override +* [GPU] bring back enable_gpu ifdef +* [GPU] rename processing unit +* [GPU] remove static from thread_group +* [GPU] fix optional dereference +* [GPU] rename check function and fix breaks +* [GPU] use shared_ptr to manage thread_group ptr +* [GPU] Refactor miners code +* [GPU] Process hashes in batches +* [GPU] Remove obvious type hint +* [GPU] Device get total memory method +* [GPU] OpenCL kernel static build rule +* [GPU] Remove unsigned and signed int comparison +* [GPU] Mac build fix attempt +* [GPU] Disable CUDA in Travis +* [GPU] Fix autoconf warnings +* [GPU] Apple OpenCL linker flags +* [GPU] Implement GPU Mining for both Daemon/Qt +* [GPU] Split CUDA and OpenCL libraries +* [GPU] Add CUDA/OpenCL Libraries for GPU Mining * Remove unused serialization method * Fix consts in txmempool * [depends] upgrade boost to 1.67.0 From 9713a76ea4e54ce058a3f0dfafd732d645eb5593 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Fri, 14 Sep 2018 14:45:59 +0200 Subject: [PATCH 0212/1653] Increase Min Peer Protocol Version to 70900(v2.3) for Peers/DynodePayments/InstantSend/PrivateSend --- CHANGELOG.md | 11 +++++++++++ src/dynode-payments.h | 2 +- src/dynodeman.h | 2 +- src/governance-object.h | 2 +- src/instantsend.h | 2 +- src/privatesend.h | 2 +- src/version.h | 2 +- 7 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26f85ab0e7..b488019cd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ **Dynamic v2.4.0.0** +* Increase Min Peer Protocol Version to 70900(v2.3) for Peers/DynodePayments/InstantSend/PrivateSend * [GPU] Fix GPU found block nonce before ProcessFoundSolution * [GPU] Update README for GPU Mining * [GPU] Seperate CPU and GPU miners to fix hashmeters @@ -157,6 +158,7 @@ * Bump Versioning * Update dynamic_qt.m4 (Remove ability to build with Qt4) + **Dynamic v2.3.0.0** * Skip existing Dynodes connections on mixing @@ -334,6 +336,7 @@ * Inline Argon2d code with commit fba7b9a * Update CHANGELOG + **Dynamic v2.2.0.0** * Add dynamic address label to request payment QR code @@ -357,6 +360,7 @@ * Fix fixed seeds * Update CHANGELOG + **Dynamic v2.1.0.0** * [Trivial] Shift non-Fluid specific operations to separate file @@ -442,6 +446,7 @@ * Improve handling of unconnecting headers * Update CHANGELOG + **Dynamic v2.0.0.0** * Fix Network Time Protocol (NTP) @@ -713,6 +718,7 @@ * Optimize CheckOutpoint * Update CHANGELOG + **Dynamic v1.4.0.0** * Securely erase potentially sensitive keys/values @@ -775,6 +781,7 @@ * Bump Governance/InstantSend/PrivateSend/Core Proto/Versions * Update CHANGELOG + **Dynamic v1.3.0.2** * [Sync] Fix issue with headers first sync @@ -787,11 +794,13 @@ * Bump Governance/Core Proto/Versions * Update CHANGELOG + **Dynamic v1.3.0.1** * Bump Protocols to lock out nodes at or below v1.2 to prevent any forks * Update CHANGELOG + **Dynamic v1.3.0.0** * c++11:Backport from bitcoin-core: don't throw from the reverselock destructor @@ -799,6 +808,7 @@ * Hard Fork at block 300,000 for Delta difficulty retarget algorithm * Update CHANGELOG + **Dynamic v1.2.0.0** * Make RelayWalletTransaction attempt to AcceptToMemoryPool @@ -842,6 +852,7 @@ * Added IPv4 seed nodes to chainparamsseeds.h * Update CHANGELOG + **Dynamic v1.1.0.0** * Inline with BTC 0.12 diff --git a/src/dynode-payments.h b/src/dynode-payments.h index 32adda9c2f..45e2e5cdbc 100644 --- a/src/dynode-payments.h +++ b/src/dynode-payments.h @@ -22,7 +22,7 @@ static const int DNPAYMENTS_SIGNATURES_TOTAL = 20; //! minimum peer version that can receive and send Dynode payment messages, // vote for Dynode and be elected as a payment winner -static const int MIN_DYNODE_PAYMENT_PROTO_VERSION = 70600; +static const int MIN_DYNODE_PAYMENT_PROTO_VERSION = 70900; extern CCriticalSection cs_vecPayees; extern CCriticalSection cs_mapDynodeBlocks; diff --git a/src/dynodeman.h b/src/dynodeman.h index d8c205cb8e..7540b53bb8 100644 --- a/src/dynodeman.h +++ b/src/dynodeman.h @@ -28,7 +28,7 @@ class CDynodeMan static const int LAST_PAID_SCAN_BLOCKS = 100; - static const int MIN_POSE_PROTO_VERSION = 70600; + static const int MIN_POSE_PROTO_VERSION = 70900; static const int MAX_POSE_CONNECTIONS = 10; static const int MAX_POSE_RANK = 10; static const int MAX_POSE_BLOCKS = 10; diff --git a/src/governance-object.h b/src/governance-object.h index 875071ea9c..5f410abd9b 100644 --- a/src/governance-object.h +++ b/src/governance-object.h @@ -25,7 +25,7 @@ class CGovernanceObject; class CGovernanceVote; static const int MAX_GOVERNANCE_OBJECT_DATA_SIZE = 16 * 1024; -static const int MIN_GOVERNANCE_PEER_PROTO_VERSION = 70600; +static const int MIN_GOVERNANCE_PEER_PROTO_VERSION = 70900; static const int GOVERNANCE_FILTER_PROTO_VERSION = 70500; static const double GOVERNANCE_FILTER_FP_RATE = 0.001; diff --git a/src/instantsend.h b/src/instantsend.h index bffc3d4edb..7988f0debf 100644 --- a/src/instantsend.h +++ b/src/instantsend.h @@ -30,7 +30,7 @@ extern CInstantSend instantsend; static const int INSTANTSEND_CONFIRMATIONS_REQUIRED = 11; static const int DEFAULT_INSTANTSEND_DEPTH = 10; -static const int MIN_INSTANTSEND_PROTO_VERSION = 70600; +static const int MIN_INSTANTSEND_PROTO_VERSION = 70900; // For how long we are going to accept votes/locks // after we saw the first one for a specific transaction diff --git a/src/privatesend.h b/src/privatesend.h index a2547b5bcd..1959ede0ec 100644 --- a/src/privatesend.h +++ b/src/privatesend.h @@ -24,7 +24,7 @@ static const int PRIVATESEND_QUEUE_TIMEOUT = 30; static const int PRIVATESEND_SIGNING_TIMEOUT = 15; //! minimum peer version accepted by mixing pool -static const int MIN_PRIVATESEND_PEER_PROTO_VERSION = 70600; +static const int MIN_PRIVATESEND_PEER_PROTO_VERSION = 70900; static const CAmount PRIVATESEND_ENTRY_MAX_SIZE = 9; diff --git a/src/version.h b/src/version.h index bbc8911512..8cf1fb6477 100644 --- a/src/version.h +++ b/src/version.h @@ -21,7 +21,7 @@ static const int INIT_PROTO_VERSION = 209; static const int GETHEADERS_VERSION = 60800; //! disconnect from peers older than this proto version -static const int MIN_PEER_PROTO_VERSION = 70600; +static const int MIN_PEER_PROTO_VERSION = 70900; // Only connect to v2.3 Nodes and newer //! nTime field added to CAddress, starting with this version; //! if possible, avoid requesting addresses nodes older than this From 8c780a1b9b28cdbdfb1dce5a645ec89059b706e2 Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Fri, 14 Sep 2018 14:57:19 +0200 Subject: [PATCH 0213/1653] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index fe44a81e9b..b12beadece 100644 --- a/README.md +++ b/README.md @@ -345,6 +345,10 @@ CPU's with AVX512 support: GPU Mining ---------- +To build Dynamic without GPU support: + + --disable-gpu + To enable GPU mining within the wallet, OpenCL or CUDA can be utilised. (Please use GCC/G++ 6.4 or newer and for CUDA to be utilised please use NVCC 9.2 or newer) From c3d866fa4fa89ac56c46d551292f009531519859 Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Fri, 14 Sep 2018 15:11:12 +0200 Subject: [PATCH 0214/1653] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b12beadece..3ab665b1b3 100644 --- a/README.md +++ b/README.md @@ -362,10 +362,10 @@ At configure time for Nvidia GPU's: Example Build Command -------------------- -Qt Wallet and Deamon, CLI version build: +Qt Wallet and Deamon, CLI version build without GPU support: - ./autogen.sh && ./configure --with-gui && make + ./autogen.sh && ./configure --with-gui --disable-gpu && make -CLI and Deamon Only Buld: +CLI and Deamon Only build without GPU support: - ./autogen.sh && ./configure --without-gui && make + ./autogen.sh && ./configure --without-gui --disable-gpu && make From 715d39529d2a6b67efe63e3045c592a91683e67e Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 9 Sep 2018 15:39:27 -0500 Subject: [PATCH 0215/1653] [DHT] Add libtorrent submodule --- .gitmodules | 3 +++ src/libtorrent | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 src/libtorrent diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..4ea889ba77 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/libtorrent"] + path = src/libtorrent + url = https://github.com/BlockChainTech/libtorrent.git diff --git a/src/libtorrent b/src/libtorrent new file mode 160000 index 0000000000..fc7b61a6f3 --- /dev/null +++ b/src/libtorrent @@ -0,0 +1 @@ +Subproject commit fc7b61a6f3f9b9ac8969ee039afb44457f4e32ba From 538e6061f36fbfd194713ceaaa725876a320ce1a Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 10 Sep 2018 20:39:09 -0500 Subject: [PATCH 0216/1653] [DHT] Embed LibTorrent library into core wallet build - Modifies Travis CI Boost 1.55 and GCC 5 - Adds seperate make file for libtorrent --- .travis.yml | 21 ++- configure.ac | 8 +- src/Makefile.am | 9 +- src/Makefile.libtorrent.include | 305 ++++++++++++++++++++++++++++++++ src/Makefile.qt.include | 2 +- 5 files changed, 339 insertions(+), 6 deletions(-) create mode 100644 src/Makefile.libtorrent.include diff --git a/.travis.yml b/.travis.yml index d613fde9b6..c588f757c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,28 @@ compiler: gcc os: linux sudo: required dist: trusty +sudo: required + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - [libc++-dev, gcc-5, g++-5] + - [libboost1.55-all-dev, libboost1.55-tools-dev] + - [libqt5gui5, libqt5core5a, libqt5dbus5, qttools5-dev, qttools5-dev-tools] + - [libprotobuf-dev, protobuf-compiler] + - [libcrypto++-dev, libssl-dev, libevent-dev] + +before_install: + - git submodule update --init --recursive + install: - - sudo apt-get -qq update - - sudo apt-get install -y build-essential libtool autotools-dev autoconf pkg-config libssl-dev libboost-all-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler libcrypto++-dev libevent-dev - sudo add-apt-repository -y ppa:silknetwork/silknetwork - sudo apt-get update -y && sudo apt-get install -y libdb4.8-dev libdb4.8++-dev + - sudo unlink /usr/bin/gcc && sudo ln -s /usr/bin/gcc-5 /usr/bin/gcc + - sudo unlink /usr/bin/g++ && sudo ln -s /usr/bin/g++-5 /usr/bin/g++ + script: - ./autogen.sh && ./configure --with-gui=qt5 && make diff --git a/configure.ac b/configure.ac index 90fb196a1b..6ce77ceac8 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 2) define(_CLIENT_VERSION_MINOR, 4) -define(_CLIENT_VERSION_REVISION, 0) +define(_CLIENT_VERSION_REVISION, 3) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2018) @@ -609,6 +609,12 @@ AC_SUBST(LEVELDB_CPPFLAGS) AC_SUBST(LIBLEVELDB) AC_SUBST(LIBMEMENV) +LIBTORRENT_CPPFLAGS= +LIBTORRENT= +AM_CONDITIONAL([EMBEDDED_LIBTORRENT],[true]) +AC_SUBST(LIBTORRENT_CPPFLAGS) +AC_SUBST(LIBTORRENT) + if test x$enable_wallet != xno; then dnl Check for libdb_cxx only if wallet enabled DYNAMIC_FIND_BDB48 diff --git a/src/Makefile.am b/src/Makefile.am index c31487792e..c943b3b8f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -454,7 +454,8 @@ dynamicd_LDADD = \ $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) \ $(LIBMEMENV) \ - $(LIBSECP256K1) + $(LIBSECP256K1) \ + $(LIBTORRENT) if ENABLE_ZMQ dynamicd_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) @@ -588,6 +589,10 @@ if EMBEDDED_LEVELDB include Makefile.leveldb.include endif +if EMBEDDED_LIBTORRENT +include Makefile.libtorrent.include +endif + if ENABLE_TESTS include Makefile.test.include endif @@ -602,4 +607,4 @@ endif if ENABLE_QT_TESTS include Makefile.qttest.include -endif +endif \ No newline at end of file diff --git a/src/Makefile.libtorrent.include b/src/Makefile.libtorrent.include new file mode 100644 index 0000000000..e03a675db5 --- /dev/null +++ b/src/Makefile.libtorrent.include @@ -0,0 +1,305 @@ +# Copyright (c) 2018 Duality Blockchain Solutions Developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +LIBTORRENT_INT = libtorrent/rasterbar.a + +EXTRA_LIBRARIES += $(LIBTORRENT_INT) + +LIBTORRENT += $(LIBTORRENT_INT) + +LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include +LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include/aux_ +LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include/extensions +LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include/kademlia +LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/ed25519/src + +LIBTORRENT_CPPFLAGS_INT = +LIBTORRENT_CPPFLAGS_INT += -Wno-deprecated-declarations -fstack-protector-all -I$(srcdir)/libtorrent + +if TARGET_WINDOWS +LIBTORRENT_CPPFLAGS_INT += -DWIN32_LEAN_AND_MEAN -D__USE_W32_SOCKETS -DWIN32 -D_WIN32 -D__USE_MINGW_ANSI_STDIO=1 +endif + +libtorrent_rasterbar_a_CPPFLAGS = $(CPPFLAGS) $(LIBTORRENT_CPPFLAGS_INT) $(LIBTORRENT_CPPFLAGS) +libtorrent_rasterbar_a_CXXFLAGS = $(CXXFLAGS) $(PIE_FLAGS) + + +libtorrent_rasterbar_a_SOURCES= \ + libtorrent/include/libtorrent/*.hpp \ + libtorrent/include/libtorrent/aux_/*.hpp \ + libtorrent/include/libtorrent/extensions/*.hpp \ + libtorrent/include/libtorrent/kademlia/*.hpp \ + libtorrent/ed25519/src/*.h \ + libtorrent/src/web_connection_base.cpp \ + libtorrent/src/alert.cpp \ + libtorrent/src/alert_manager.cpp \ + libtorrent/src/allocator.cpp \ + libtorrent/src/announce_entry.cpp \ + libtorrent/src/assert.cpp \ + libtorrent/src/bandwidth_limit.cpp \ + libtorrent/src/bandwidth_manager.cpp \ + libtorrent/src/bandwidth_queue_entry.cpp \ + libtorrent/src/bdecode.cpp \ + libtorrent/src/bitfield.cpp \ + libtorrent/src/bloom_filter.cpp \ + libtorrent/src/broadcast_socket.cpp \ + libtorrent/src/block_cache.cpp \ + libtorrent/src/bt_peer_connection.cpp \ + libtorrent/src/chained_buffer.cpp \ + libtorrent/src/choker.cpp \ + libtorrent/src/close_reason.cpp \ + libtorrent/src/ConvertUTF.cpp \ + libtorrent/src/cpuid.cpp \ + libtorrent/src/crc32c.cpp \ + libtorrent/src/create_torrent.cpp \ + libtorrent/src/disk_buffer_holder.cpp \ + libtorrent/src/disk_buffer_pool.cpp \ + libtorrent/src/disk_io_job.cpp \ + libtorrent/src/disk_io_thread.cpp \ + libtorrent/src/disk_io_thread_pool.cpp \ + libtorrent/src/disk_job_fence.cpp \ + libtorrent/src/disk_job_pool.cpp \ + libtorrent/src/entry.cpp \ + libtorrent/src/enum_net.cpp \ + libtorrent/src/error_code.cpp \ + libtorrent/src/escape_string.cpp \ + libtorrent/src/file.cpp \ + libtorrent/src/path.cpp \ + libtorrent/src/file_pool.cpp \ + libtorrent/src/file_storage.cpp \ + libtorrent/src/fingerprint.cpp \ + libtorrent/src/generate_peer_id.cpp \ + libtorrent/src/gzip.cpp \ + libtorrent/src/hasher.cpp \ + libtorrent/src/hasher512.cpp \ + libtorrent/src/hex.cpp \ + libtorrent/src/http_connection.cpp \ + libtorrent/src/http_parser.cpp \ + libtorrent/src/http_seed_connection.cpp \ + libtorrent/src/http_stream.cpp \ + libtorrent/src/http_tracker_connection.cpp \ + libtorrent/src/i2p_stream.cpp \ + libtorrent/src/identify_client.cpp \ + libtorrent/src/instantiate_connection.cpp \ + libtorrent/src/ip_filter.cpp \ + libtorrent/src/ip_notifier.cpp \ + libtorrent/src/ip_voter.cpp \ + libtorrent/src/lazy_bdecode.cpp \ + libtorrent/src/listen_socket_handle.cpp \ + libtorrent/src/lsd.cpp \ + libtorrent/src/magnet_uri.cpp \ + libtorrent/src/merkle.cpp \ + libtorrent/src/natpmp.cpp \ + libtorrent/src/parse_url.cpp \ + libtorrent/src/part_file.cpp \ + libtorrent/src/pe_crypto.cpp \ + libtorrent/src/performance_counters.cpp \ + libtorrent/src/peer_connection.cpp \ + libtorrent/src/peer_connection_handle.cpp \ + libtorrent/src/peer_class.cpp \ + libtorrent/src/peer_class_set.cpp \ + libtorrent/src/piece_picker.cpp \ + libtorrent/src/platform_util.cpp \ + libtorrent/src/packet_buffer.cpp \ + libtorrent/src/proxy_base.cpp \ + libtorrent/src/peer_list.cpp \ + libtorrent/src/puff.cpp \ + libtorrent/src/random.cpp \ + libtorrent/src/receive_buffer.cpp \ + libtorrent/src/read_resume_data.cpp \ + libtorrent/src/write_resume_data.cpp \ + libtorrent/src/request_blocks.cpp \ + libtorrent/src/resolve_links.cpp \ + libtorrent/src/resolver.cpp \ + libtorrent/src/session.cpp \ + libtorrent/src/session_call.cpp \ + libtorrent/src/session_handle.cpp \ + libtorrent/src/session_impl.cpp \ + libtorrent/src/session_settings.cpp \ + libtorrent/src/session_udp_sockets.cpp \ + libtorrent/src/proxy_settings.cpp \ + libtorrent/src/settings_pack.cpp \ + libtorrent/src/sha1_hash.cpp \ + libtorrent/src/smart_ban.cpp \ + libtorrent/src/socket_io.cpp \ + libtorrent/src/socket_type.cpp \ + libtorrent/src/socks5_stream.cpp \ + libtorrent/src/stat.cpp \ + libtorrent/src/stat_cache.cpp \ + libtorrent/src/storage.cpp \ + libtorrent/src/storage_piece_set.cpp \ + libtorrent/src/storage_utils.cpp \ + libtorrent/src/session_stats.cpp \ + libtorrent/src/string_util.cpp \ + libtorrent/src/torrent.cpp \ + libtorrent/src/torrent_handle.cpp \ + libtorrent/src/torrent_info.cpp \ + libtorrent/src/torrent_peer.cpp \ + libtorrent/src/torrent_peer_allocator.cpp \ + libtorrent/src/torrent_status.cpp \ + libtorrent/src/time.cpp \ + libtorrent/src/timestamp_history.cpp \ + libtorrent/src/tracker_manager.cpp \ + libtorrent/src/udp_socket.cpp \ + libtorrent/src/udp_tracker_connection.cpp \ + libtorrent/src/upnp.cpp \ + libtorrent/src/ut_metadata.cpp \ + libtorrent/src/ut_pex.cpp \ + libtorrent/src/utf8.cpp \ + libtorrent/src/utp_socket_manager.cpp \ + libtorrent/src/utp_stream.cpp \ + libtorrent/src/web_peer_connection.cpp \ + libtorrent/src/xml_parse.cpp \ + libtorrent/src/version.cpp \ + libtorrent/src/file_progress.cpp \ + libtorrent/src/ffs.cpp \ + libtorrent/src/add_torrent_params.cpp \ + libtorrent/src/peer_info.cpp \ + libtorrent/src/stack_allocator.cpp \ + libtorrent/src/kademlia/dht_state.cpp \ + libtorrent/src/kademlia/dht_storage.cpp \ + libtorrent/src/kademlia/dht_tracker.cpp \ + libtorrent/src/kademlia/find_data.cpp \ + libtorrent/src/kademlia/put_data.cpp \ + libtorrent/src/kademlia/msg.cpp \ + libtorrent/src/kademlia/node.cpp \ + libtorrent/src/kademlia/node_entry.cpp \ + libtorrent/src/kademlia/node_id.cpp \ + libtorrent/src/kademlia/refresh.cpp \ + libtorrent/src/kademlia/routing_table.cpp \ + libtorrent/src/kademlia/rpc_manager.cpp \ + libtorrent/src/kademlia/traversal_algorithm.cpp \ + libtorrent/src/kademlia/dos_blocker.cpp \ + libtorrent/src/kademlia/get_peers.cpp \ + libtorrent/src/kademlia/get_item.cpp \ + libtorrent/src/kademlia/item.cpp \ + libtorrent/src/kademlia/ed25519.cpp \ + libtorrent/src/kademlia/sample_infohashes.cpp \ + libtorrent/src/kademlia/dht_settings.cpp \ + libtorrent/ed25519/src/add_scalar.cpp \ + libtorrent/ed25519/src/fe.cpp \ + libtorrent/ed25519/src/ge.cpp \ + libtorrent/ed25519/src/key_exchange.cpp \ + libtorrent/ed25519/src/keypair.cpp \ + libtorrent/ed25519/src/sc.cpp \ + libtorrent/ed25519/src/sign.cpp \ + libtorrent/ed25519/src/verify.cpp + +LIBTORRENT_DOCS_IMAGES = \ + libtorrent/docs/client_test.png \ + libtorrent/docs/cwnd.png \ + libtorrent/docs/cwnd_thumb.png \ + libtorrent/docs/delays.png \ + libtorrent/docs/delays_thumb.png \ + libtorrent/docs/hacking.html \ + libtorrent/docs/merkle_tree.png \ + libtorrent/docs/our_delay_base.png \ + libtorrent/docs/our_delay_base_thumb.png \ + libtorrent/docs/read_disk_buffers.png \ + libtorrent/docs/read_disk_buffers.diagram \ + libtorrent/docs/storage.png \ + libtorrent/docs/todo.html \ + libtorrent/docs/write_disk_buffers.png \ + libtorrent/docs/write_disk_buffers.diagram \ + libtorrent/docs/ip_id_v4.png \ + libtorrent/docs/ip_id_v6.png \ + libtorrent/docs/hash_distribution.png \ + libtorrent/docs/complete_bit_prefixes.png \ + libtorrent/docs/troubleshooting.dot \ + libtorrent/docs/troubleshooting.png \ + libtorrent/docs/troubleshooting_thumb.png \ + libtorrent/docs/hacking.diagram \ + libtorrent/docs/hacking.png \ + libtorrent/docs/disk_cache.diagram \ + libtorrent/docs/disk_cache.png \ + libtorrent/docs/utp_stack.diagram \ + libtorrent/docs/utp_stack.png \ + libtorrent/docs/bitcoin.png \ + libtorrent/docs/style.css \ + libtorrent/docs/rst.css \ + libtorrent/docs/img/bg.png \ + libtorrent/docs/img/blue_bottom.png \ + libtorrent/docs/img/blue_top.png \ + libtorrent/docs/img/dotline.gif \ + libtorrent/docs/img/minus.gif \ + libtorrent/docs/img/orange.png + +LIBTORRENT_DOCS_PAGES = \ + libtorrent/docs/building.html \ + libtorrent/docs/client_test.html \ + libtorrent/docs/contributing.html \ + libtorrent/docs/dht_extensions.html \ + libtorrent/docs/dht_rss.html \ + libtorrent/docs/dht_sec.html \ + libtorrent/docs/dht_store.html \ + libtorrent/docs/examples.html \ + libtorrent/docs/extension_protocol.html \ + libtorrent/docs/features.html \ + libtorrent/docs/index.html \ + libtorrent/docs/manual-ref.html \ + libtorrent/docs/projects.html \ + libtorrent/docs/python_binding.html \ + libtorrent/docs/tuning.html \ + libtorrent/docs/settings.rst \ + libtorrent/docs/stats_counters.rst \ + libtorrent/docs/troubleshooting.html \ + libtorrent/docs/udp_tracker_protocol.html \ + libtorrent/docs/utp.html \ + libtorrent/docs/streaming.html \ + libtorrent/docs/building.rst \ + libtorrent/docs/client_test.rst \ + libtorrent/docs/contributing.rst \ + libtorrent/docs/dht_extensions.rst \ + libtorrent/docs/dht_rss.rst \ + libtorrent/docs/dht_sec.rst \ + libtorrent/docs/dht_store.rst \ + libtorrent/docs/examples.rst \ + libtorrent/docs/extension_protocol.rst \ + libtorrent/docs/features.rst \ + libtorrent/docs/index.rst \ + libtorrent/docs/manual-ref.rst \ + libtorrent/docs/projects.rst \ + libtorrent/docs/python_binding.rst \ + libtorrent/docs/tuning.rst \ + libtorrent/docs/troubleshooting.rst \ + libtorrent/docs/udp_tracker_protocol.rst \ + libtorrent/docs/utp.rst \ + libtorrent/docs/streaming.rst \ + libtorrent/docs/tutorial.rst \ + libtorrent/docs/tutorial.html \ + libtorrent/docs/reference-Alerts.html \ + libtorrent/docs/reference-Bdecoding.html \ + libtorrent/docs/reference-Bencoding.html \ + libtorrent/docs/reference-Core.html \ + libtorrent/docs/reference-Create_Torrents.html \ + libtorrent/docs/reference-Custom_Storage.html \ + libtorrent/docs/reference-ed25519.html \ + libtorrent/docs/reference-Error_Codes.html \ + libtorrent/docs/reference-Filter.html \ + libtorrent/docs/reference-Plugins.html \ + libtorrent/docs/reference-Settings.html \ + libtorrent/docs/reference-Storage.html \ + libtorrent/docs/reference-Utility.html \ + libtorrent/docs/reference.html \ + libtorrent/docs/single-page-ref.html + +LIBTORRENT_ED25519_SOURCE = \ + libtorrent/ed25519/readme.md \ + libtorrent/ed25519/test.c \ + libtorrent/ed25519/src/fe.h \ + libtorrent/ed25519/src/fixedint.h \ + libtorrent/ed25519/src/ge.h \ + libtorrent/ed25519/src/precomp_data.h \ + libtorrent/ed25519/src/sc.h + +LIBTORRENT_EXTRA_DIST = \ + libtorrent/Jamfile \ + libtorrent/Jamroot.jam \ + libtorrent/CMakeLists.txt \ + libtorrent/setup.py \ + libtorrent/LICENSE \ + libtorrent/README.rst \ + $(LIBTORRENT_DOCS_PAGES) \ + $(LIBTORRENT_DOCS_IMAGES) \ + $(LIBTORRENT_ED25519_SOURCE) \ No newline at end of file diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 7b8f6846cb..69be201c6c 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -238,7 +238,7 @@ RES_ICONS = \ qt/res/icons/drk/unit_satoshis.png \ qt/res/icons/drk/unit_udyn.png \ qt/res/icons/drk/fontbigger.png \ - qt/res/icons/drk/fontsmaller.png \ + qt/res/icons/drk/fontsmaller.png \ qt/res/icons/drk/verify.png \ qt/res/icons/drk/warning.png From 2c041d91ddf20568c17fe74cb23d4c49371fdba9 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 10 Sep 2018 23:40:05 -0500 Subject: [PATCH 0217/1653] Get repo submodules automatically --- autogen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/autogen.sh b/autogen.sh index 5e37212166..a9fd47a64f 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,5 @@ #!/bin/sh +git submodule update --init --recursive set -e srcdir="$(dirname $0)" cd "$srcdir" From 16c9451e9ea1dac89cc843ce79dde4bb08c0b3ff Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 13 Sep 2018 18:46:03 -0500 Subject: [PATCH 0218/1653] [DHT] Change libtorrent module path --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 4ea889ba77..d5a17ff2a1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "src/libtorrent"] path = src/libtorrent - url = https://github.com/BlockChainTech/libtorrent.git + url = https://github.com/duality-solutions/libbdaptorrent.git From 8dcf4858dfbf80cf93341df9da8050cac70bff1f Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 16 Sep 2018 14:49:26 -0500 Subject: [PATCH 0219/1653] [BDAP] Fix include for Windows for Boost threading --- src/bdap/domainentrydb.cpp | 3 +++ src/bdap/domainentrydb.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index bd9f224c88..cada0fd182 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -10,6 +10,9 @@ #include +#include + + CDomainEntryDB *pDomainEntryDB = NULL; bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntry& entry) diff --git a/src/bdap/domainentrydb.h b/src/bdap/domainentrydb.h index c083a6c0e1..abea6589c2 100644 --- a/src/bdap/domainentrydb.h +++ b/src/bdap/domainentrydb.h @@ -7,6 +7,7 @@ #include "bdap/domainentry.h" #include "dbwrapper.h" +#include "sync.h" static CCriticalSection cs_bdap_entry; From 51242d5be8a75ce38509eb5fce7f457e56b02089 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 17 Sep 2018 16:11:07 -0500 Subject: [PATCH 0220/1653] [BDAP] Shorten all RPC command names and fix error messages --- src/bdap/rpcdomainentry.cpp | 72 ++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index b7a97b8366..98a68bf26f 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -147,21 +147,21 @@ static UniValue AddDomainEntry(const JSONRPCRequest& request, BDAP::ObjectType b return oName; } -UniValue adddomainentry(const JSONRPCRequest& request) +UniValue adduser(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("adddomainentry \nAdd public name entry to blockchain directory.\n"); + throw std::runtime_error("adduser \nAdd public name entry to blockchain directory.\n"); } BDAP::ObjectType bdapType = BDAP::ObjectType::USER_ACCOUNT; return AddDomainEntry(request, bdapType); } -UniValue getdomainusers(const JSONRPCRequest& request) +UniValue getusers(const JSONRPCRequest& request) { if (request.params.size() > 2) { - throw std::runtime_error("getdomainusers \nLists all BDAP public users.\n"); + throw std::runtime_error("getusers \nLists all BDAP public users.\n"); } unsigned int nRecordsPerPage = 100; @@ -183,11 +183,11 @@ UniValue getdomainusers(const JSONRPCRequest& request) return oDomainEntryList; } -UniValue getdomaingroups(const JSONRPCRequest& request) +UniValue getgroups(const JSONRPCRequest& request) { if (request.params.size() > 2) { - throw std::runtime_error("getdomainugroups \nLists all BDAP public groups.\n"); + throw std::runtime_error("getgroups \nLists all BDAP public groups.\n"); } unsigned int nRecordsPerPage = 100; @@ -209,11 +209,11 @@ UniValue getdomaingroups(const JSONRPCRequest& request) return oDomainEntryList; } -UniValue getdomainuserinfo(const JSONRPCRequest& request) +UniValue getuserinfo(const JSONRPCRequest& request) { if (request.params.size() != 1) { - throw std::runtime_error("getdomainuserinfo \nList BDAP entry.\n"); + throw std::runtime_error("getuserinfo \nList BDAP entry.\n"); } CharString vchObjectID = vchFromValue(request.params[0]); @@ -237,11 +237,11 @@ UniValue getdomainuserinfo(const JSONRPCRequest& request) return oDomainEntryInfo; } -UniValue getdomaingroupinfo(const JSONRPCRequest& request) +UniValue getgroupinfo(const JSONRPCRequest& request) { if (request.params.size() != 1) { - throw std::runtime_error("getdomaingroupinfo \nList BDAP entry.\n"); + throw std::runtime_error("getgroupinfo \nList BDAP entry.\n"); } CharString vchObjectID = vchFromValue(request.params[0]); @@ -255,11 +255,11 @@ UniValue getdomaingroupinfo(const JSONRPCRequest& request) UniValue oDomainEntryInfo(UniValue::VOBJ); if (CheckDomainEntryDB()) { if (!pDomainEntryDB->GetDomainEntryInfo(directory.vchFullObjectPath(), oDomainEntryInfo)) { - throw std::runtime_error("BDAP_SELECT_PUBLIC_USER_RPC_ERROR: ERRCODE: 3600 - " + directory.GetFullObjectPath() + _(" can not be found. Get info failed!")); + throw std::runtime_error("BDAP_SELECT_PUBLIC_GROUP_RPC_ERROR: ERRCODE: 3600 - " + directory.GetFullObjectPath() + _(" can not be found. Get info failed!")); } } else { - throw std::runtime_error("BDAP_SELECT_PUBLIC_USER_RPC_ERROR: ERRCODE: 3601 - " + _("Can not access BDAP LevelDB database. Get info failed!")); + throw std::runtime_error("BDAP_SELECT_PUBLIC_GROUP_RPC_ERROR: ERRCODE: 3601 - " + _("Can not access BDAP LevelDB database. Get info failed!")); } return oDomainEntryInfo; @@ -285,12 +285,12 @@ static UniValue UpdateDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp // Check if name already exists if (!GetDomainEntry(txPreviousEntry.vchFullObjectPath(), txPreviousEntry)) - throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3700 - " + txPreviousEntry.GetFullObjectPath() + _(" does not exists. Can not update.")); + throw std::runtime_error("BDAP_UPDATE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3700 - " + txPreviousEntry.GetFullObjectPath() + _(" does not exists. Can not update.")); int nIn = GetBDAPOperationOutIndex(txPreviousEntry.nHeight, txPreviousEntry.txHash); COutPoint outpoint = COutPoint(txPreviousEntry.txHash, nIn); if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) - throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txPreviousEntry.GetFullObjectPath() + _(" entry. Can not update.")); + throw std::runtime_error("BDAP_UPDATE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3701 - You do not own the " + txPreviousEntry.GetFullObjectPath() + _(" entry. Can not update.")); CDomainEntry txUpdatedEntry = txPreviousEntry; CharString vchCommonName = vchFromValue(request.params[1]); @@ -330,14 +330,14 @@ static UniValue UpdateDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp // check BDAP values std::string strMessage; if (!txUpdatedEntry.ValidateValues(strMessage)) - throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3702 - " + strMessage); + throw std::runtime_error("BDAP_UPDATE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3702 - " + strMessage); SendBDAPTransaction(scriptData, scriptPubKey, wtx, nDataFee, nOperationFee); txUpdatedEntry.txHash = wtx.GetHash(); UniValue oName(UniValue::VOBJ); if(!BuildBDAPJson(txUpdatedEntry, oName)) - throw std::runtime_error("BDAP_UPDATE_PUBLIC_NAME_RPC_ERROR: ERRCODE: 3703 - " + _("Failed to read from BDAP JSON object")); + throw std::runtime_error("BDAP_UPDATE_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3703 - " + _("Failed to read from BDAP JSON object")); if (fPrintDebug) { // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class @@ -354,20 +354,20 @@ static UniValue UpdateDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp return oName; } -UniValue updatedomainuser(const JSONRPCRequest& request) { +UniValue updateuser(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("updatedomainuser \nUpdate an existing public name blockchain directory entry.\n"); + throw std::runtime_error("updateuser \nUpdate an existing public name blockchain directory entry.\n"); } BDAP::ObjectType bdapType = BDAP::ObjectType::USER_ACCOUNT; return UpdateDomainEntry(request, bdapType); } -UniValue updatedomaingroup(const JSONRPCRequest& request) { +UniValue updategroup(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("updatedomaingroup \nUpdate an existing public name blockchain directory entry.\n"); + throw std::runtime_error("updategroup \nUpdate an existing public name blockchain directory entry.\n"); } BDAP::ObjectType bdapType = BDAP::ObjectType::GROUP; @@ -452,20 +452,20 @@ static UniValue DeleteDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp return oName; } -UniValue deletedomainuser(const JSONRPCRequest& request) { +UniValue deleteuser(const JSONRPCRequest& request) { if (request.params.size() != 1) { - throw std::runtime_error("deletedomainuser \nDelete an existing public name blockchain directory entry.\n"); + throw std::runtime_error("deleteuser \nDelete an existing public name blockchain directory entry.\n"); } BDAP::ObjectType bdapType = BDAP::ObjectType::USER_ACCOUNT; return DeleteDomainEntry(request, bdapType); } -UniValue deletedomaingroup(const JSONRPCRequest& request) { +UniValue deletegroup(const JSONRPCRequest& request) { if (request.params.size() != 1) { - throw std::runtime_error("deletedomaingroup \nDelete an existing public name blockchain directory entry.\n"); + throw std::runtime_error("deletegroup \nDelete an existing public name blockchain directory entry.\n"); } BDAP::ObjectType bdapType = BDAP::ObjectType::GROUP; @@ -507,11 +507,11 @@ UniValue makekeypair(const JSONRPCRequest& request) return result; } -UniValue adddomaingroup(const JSONRPCRequest& request) +UniValue addgroup(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 3) { - throw std::runtime_error("adddomaingroup \nAdd public group entry to blockchain directory.\n"); + throw std::runtime_error("addgroup \nAdd public group entry to blockchain directory.\n"); } BDAP::ObjectType bdapType = BDAP::ObjectType::GROUP; @@ -522,16 +522,16 @@ static const CRPCCommand commands[] = { // category name actor (function) okSafeMode #ifdef ENABLE_WALLET /* BDAP */ - { "bdap", "adddomainentry", &adddomainentry, true }, - { "bdap", "getdomainusers", &getdomainusers, true }, - { "bdap", "getdomaingroups", &getdomaingroups, true }, - { "bdap", "getdomainuserinfo", &getdomainuserinfo, true }, - { "bdap", "updatedomainuser", &updatedomainuser, true }, - { "bdap", "updatedomaingroup", &updatedomaingroup, true }, - { "bdap", "deletedomainuser", &deletedomainuser, true }, - { "bdap", "deletedomaingroup", &deletedomaingroup, true }, - { "bdap", "adddomaingroup", &adddomaingroup, true }, - { "bdap", "getdomaingroupinfo", &getdomaingroupinfo, true }, + { "bdap", "adduser", &adduser, true }, + { "bdap", "getusers", &getusers, true }, + { "bdap", "getgroups", &getgroups, true }, + { "bdap", "getuserinfo", &getuserinfo, true }, + { "bdap", "updateuser", &updateuser, true }, + { "bdap", "updategroup", &updategroup, true }, + { "bdap", "deleteuser", &deleteuser, true }, + { "bdap", "deletegroup", &deletegroup, true }, + { "bdap", "addgroup", &addgroup, true }, + { "bdap", "getgroupinfo", &getgroupinfo, true }, #endif //ENABLE_WALLET { "bdap", "makekeypair", &makekeypair, true }, }; From 448041a15e8a3a88383052b31f9f372b8fc920f8 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 18 Sep 2018 00:27:20 -0500 Subject: [PATCH 0221/1653] [DHT] Add Ed25519 ECC for DHT signing and encryption - Use Ed25519 signature to update the DHT - Use Ed25519 for Diffie-Hellman encryption Using the same keypair for signing and Diffie-Hellman encryption: https://crypto.stackexchange.com/questions/3260/using-same-keypair-for-diffie-hellman-and-signing Curve25519: https://safecurves.cr.yp.to --- src/Makefile.am | 10 +- src/Makefile.libtorrent.include | 12 +-- src/bdap/keyed25519.cpp | 105 +++++++++++++++++++ src/bdap/keyed25519.h | 178 ++++++++++++++++++++++++++++++++ src/bdap/rpcdomainentry.cpp | 1 + 5 files changed, 299 insertions(+), 7 deletions(-) create mode 100644 src/bdap/keyed25519.cpp create mode 100644 src/bdap/keyed25519.h diff --git a/src/Makefile.am b/src/Makefile.am index c943b3b8f3..1cb13e41d6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -DIST_SUBDIRS = secp256k1 univalue bdap +DIST_SUBDIRS = secp256k1 univalue libtorrent AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(HARDENED_CXXFLAGS) @@ -10,6 +10,11 @@ DYNAMIC_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPP DYNAMIC_INCLUDES += -I$(srcdir)/secp256k1/include DYNAMIC_INCLUDES += -I$(srcdir)/univalue/include +DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/ed25519/src +DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/include +DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/include/aux_ +DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/include/extensions +DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/include/kademlia LIBDYNAMIC_SERVER=libdynamic_server.a LIBDYNAMIC_WALLET=libdynamic_wallet.a @@ -20,6 +25,7 @@ LIBDYNAMIC_CRYPTO=crypto/libdynamic_crypto.a LIBDYNAMICQT=qt/libdynamicqt.a LIBSECP256K1=secp256k1/libsecp256k1.la LIBUNIVALUE=univalue/libunivalue.la +#LIBTORRENT=libtorrent/librasterbar.a $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) @@ -106,6 +112,7 @@ DYNAMIC_CORE_H = \ bdap/entrycheckpoints.h \ bdap/entrylink.h \ bdap/identity.h \ + bdap/keyed25519.h \ dbwrapper.h \ dynode.h \ dynode-payments.h \ @@ -241,6 +248,7 @@ libdynamic_server_a_SOURCES = \ bdap/entrycheckpoints.cpp \ bdap/entrylink.cpp \ bdap/identity.cpp \ + bdap/keyed25519.cpp \ dbwrapper.cpp \ dynode.cpp \ dynode-payments.cpp\ diff --git a/src/Makefile.libtorrent.include b/src/Makefile.libtorrent.include index e03a675db5..c7f524dc24 100644 --- a/src/Makefile.libtorrent.include +++ b/src/Makefile.libtorrent.include @@ -2,10 +2,8 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -LIBTORRENT_INT = libtorrent/rasterbar.a - +LIBTORRENT_INT = libtorrent/librasterbar.a EXTRA_LIBRARIES += $(LIBTORRENT_INT) - LIBTORRENT += $(LIBTORRENT_INT) LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include @@ -21,11 +19,11 @@ if TARGET_WINDOWS LIBTORRENT_CPPFLAGS_INT += -DWIN32_LEAN_AND_MEAN -D__USE_W32_SOCKETS -DWIN32 -D_WIN32 -D__USE_MINGW_ANSI_STDIO=1 endif -libtorrent_rasterbar_a_CPPFLAGS = $(CPPFLAGS) $(LIBTORRENT_CPPFLAGS_INT) $(LIBTORRENT_CPPFLAGS) -libtorrent_rasterbar_a_CXXFLAGS = $(CXXFLAGS) $(PIE_FLAGS) +libtorrent_librasterbar_a_CPPFLAGS = $(CPPFLAGS) $(LIBTORRENT_CPPFLAGS_INT) $(LIBTORRENT_CPPFLAGS) +libtorrent_librasterbar_a_CXXFLAGS = $(CXXFLAGS) $(PIE_FLAGS) -libtorrent_rasterbar_a_SOURCES= \ +libtorrent_librasterbar_a_SOURCES= \ libtorrent/include/libtorrent/*.hpp \ libtorrent/include/libtorrent/aux_/*.hpp \ libtorrent/include/libtorrent/extensions/*.hpp \ @@ -120,7 +118,9 @@ libtorrent_rasterbar_a_SOURCES= \ libtorrent/src/session_udp_sockets.cpp \ libtorrent/src/proxy_settings.cpp \ libtorrent/src/settings_pack.cpp \ + libtorrent/src/sha1.cpp \ libtorrent/src/sha1_hash.cpp \ + libtorrent/src/sha512.cpp \ libtorrent/src/smart_ban.cpp \ libtorrent/src/socket_io.cpp \ libtorrent/src/socket_type.cpp \ diff --git a/src/bdap/keyed25519.cpp b/src/bdap/keyed25519.cpp new file mode 100644 index 0000000000..a18fc5068d --- /dev/null +++ b/src/bdap/keyed25519.cpp @@ -0,0 +1,105 @@ + +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#include "keyed25519.h" + +#include + +#include "libtorrent/hasher512.hpp" +#include "libtorrent/kademlia/ed25519.hpp" +#include "libtorrent/kademlia/types.hpp" + +#include +#include + +using namespace libtorrent::dht; + +struct ed25519_context +{ + ed25519_context() = default; + explicit ed25519_context(char const* b) + { std::copy(b, b + len, seed.begin()); } + bool operator==(ed25519_context const& rhs) const + { return seed == rhs.seed; } + bool operator!=(ed25519_context const& rhs) const + { return seed != rhs.seed; } + constexpr static int len = 32; + std::array seed; +}; + +static ed25519_context* ed25519_context_sign = NULL; + +// TODO (BDAP): Implement check Ed25519 keys +bool CKeyEd25519::Check(const unsigned char *vch) +{ + return true; + //return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch); +} + +//! Generate a new private key using LibTorrent's Ed25519 +// TODO (BDAP): Support compressed Ed25519 keys +void CKeyEd25519::MakeNewKeyPair() +{ + std::tuple newKeyPair; + newKeyPair = ed25519_create_keypair(ed25519_context_sign->seed); + // Load the new ed25519 private key + { + secret_key privateKey = std::get<1>(newKeyPair); + std::vector vchPrivateKey; + for (std::size_t i{0}; i < sizeof(privateKey); ++i) { + unsigned char charValue = static_cast(privateKey.bytes[i]); + vchPrivateKey.push_back(charValue); + } + Set(vchPrivateKey.begin(), vchPrivateKey.end(), false); + } + // Load the new ed25519 public key + { + public_key publicKey = std::get<0>(newKeyPair); + std::vector vchPublicKey; + for (std::size_t i{0}; i < sizeof(publicKey); ++i) { + unsigned char charValue = static_cast(publicKey.bytes[i]); + vchPublicKey.push_back(charValue); + } + SetPubKey(vchPublicKey.begin(), vchPublicKey.end()); + } + fValid = true; +} + +void CKeyEd25519::SetMaster(const unsigned char* seed, unsigned int nSeedLen) +{ + assert(nSeedLen == 32); // TODO: (BDAP) Allow larger seed size with 64 max + ed25519_context* ctx = new ed25519_context(reinterpret_cast(seed)); + assert(ctx != NULL); + ed25519_context_sign = ctx; + return; +} + +void ECC_Ed25519_Start() +{ + assert(ed25519_context_sign == NULL); + + ed25519_context* ctx = new ed25519_context(); + assert(ctx != NULL); + { + ctx->seed = ed25519_create_seed(); + } + ed25519_context_sign = ctx; +} + +/* +bool ECC_Ed25519_InitSanityCheck() +{ + CKeyEd25519 key; + key.MakeNewKey(true); + CPubKeyEd25519 pubkey = key.GetPubKey(); + return key.VerifyPubKey(pubkey); +} +*/ + +void ECC_Ed25519_Stop() +{ + ed25519_context *ctx = ed25519_context_sign; + ed25519_context_sign = NULL; + assert(ctx == NULL); +} \ No newline at end of file diff --git a/src/bdap/keyed25519.h b/src/bdap/keyed25519.h new file mode 100644 index 0000000000..05fdc9568e --- /dev/null +++ b/src/bdap/keyed25519.h @@ -0,0 +1,178 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_BDAP_KEYED25519_H +#define DYNAMIC_BDAP_KEYED25519_H + +#include "support/allocators/secure.h" + +#include + +//struct secret_key; +//struct public_key; + +/** + * ed25519: + * unsigned char seed[32]; + * unsigned char signature[64]; + * unsigned char public_key[32]; + * unsigned char private_key[64]; + * unsigned char scalar[32]; + * unsigned char shared_secret[32]; + */ + +/** + * secure_allocator is defined in support/allocators/secure.h and uses std::allocator + * CPrivKeyEd25519 is a serialized private key, with all parameters included + */ +typedef std::vector > CPrivKeyEd25519; + +/** An encapsulated ed25519 private key. */ +class CKeyEd25519 +{ +public: + /** + * ed25519: + */ + static const unsigned int PRIVATE_KEY_SIZE = 279; + static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214; + /** + * see www.keylength.com + * script supports up to 75 for single byte push + */ + static_assert( + PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE, + "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE"); + +private: + //! Whether this private key is valid. We check for correctness when modifying the key + //! data, so fValid should always correspond to the actual state. + bool fValid; + + //! Whether the public key corresponding to this private key is (to be) compressed. + bool fCompressed; + + //! The actual private key byte data + std::vector > keyData; + //! The public key byte data + std::vector publicKeyData; + + //! Check whether the 32-byte array pointed to be vch is valid keyData. + bool static Check(const unsigned char* vch); + + //! Initialize using begin and end iterators to byte data. + template + void SetPubKey(const T pbegin, const T pend) + { + if (size_t(pend - pbegin) != publicKeyData.size()) + return; + + if (Check(&pbegin[0])) { + memcpy(publicKeyData.data(), (unsigned char*)&pbegin[0], publicKeyData.size()); + } + } + +public: + //! Construct an invalid private key. + CKeyEd25519() : fValid(false), fCompressed(false) + { + // Important: vch must be 32 bytes in length to not break serialization + keyData.resize(32); + } + + //! Destructor (again necessary because of memlocking). + ~CKeyEd25519() + { + } + + friend bool operator==(const CKeyEd25519& a, const CKeyEd25519& b) + { + return a.fCompressed == b.fCompressed && + a.size() == b.size() && + memcmp(a.keyData.data(), b.keyData.data(), a.size()) == 0; + } + + //! Initialize using begin and end iterators to byte data. + template + void Set(const T pbegin, const T pend, bool fCompressedIn) + { + if (size_t(pend - pbegin) != keyData.size()) { + fValid = false; + } else if (Check(&pbegin[0])) { + memcpy(keyData.data(), (unsigned char*)&pbegin[0], keyData.size()); + fValid = true; + fCompressed = fCompressedIn; + } else { + fValid = false; + } + } + + //! Simple read-only vector-like interface. + unsigned int size() const { return (fValid ? keyData.size() : 0); } + const unsigned char* begin() const { return keyData.data(); } + const unsigned char* end() const { return keyData.data() + size(); } + + + //! Check whether this private key is valid. + bool IsValid() const { return fValid; } + + //! Check whether the public key corresponding to this private key is (to be) compressed. + bool IsCompressed() const { return fCompressed; } + + //! Initialize from a CPrivKeyEd25519 (serialized OpenSSL private key data). + //bool SetPrivKey(const CPrivKeyEd25519& vchPrivKey, bool fCompressed); + + //! Generate a new private key using LibTorrent's Ed25519 implementation + void MakeNewKeyPair(); + + /** + * Convert the private key to a CPrivKeyEd25519 (serialized OpenSSL private key data). + * This is expensive. + */ + CPrivKeyEd25519 GetPrivKey() const; + /** + * Convert the private key to a CPrivKeyEd25519 (serialized OpenSSL private key data). + * This is expensive. + */ + //secret_key GetDHTPrivKey() const; + + /** + * Compute the public key from a private key. + * This is expensive. + */ + //public_key GetPubKey() const; + + void SetMaster(const unsigned char* seed, unsigned int nSeedLen); + /** + * Create a DER-serialized signature. + * The test_case parameter tweaks the deterministic nonce. + */ + //bool Sign(const uint256& hash, std::vector& vchSig, uint32_t test_case = 0) const; + + /** + * Create a compact signature (65 bytes), which allows reconstructing the used public key. + * The format is one header byte, followed by two times 32 bytes for the serialized r and s values. + * The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, + * 0x1D = second key with even y, 0x1E = second key with odd y, + * add 0x04 for compressed keys. + */ + //bool SignCompact(const uint256& hash, std::vector& vchSig) const; + + //! Derive BIP32 child key. + //bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; + + /** + * Verify thoroughly whether a private key and a public key match. + * This is done using a different mechanism than just regenerating it. + */ + //bool VerifyPubKey(const CPubEd25519Key& vchPubKey) const; + + //! Load private key and check that public key matches. + //bool Load(CPrivKeyEd25519& privkey, CPubEd25519Key& vchPubKey, bool fSkipCheck); +}; + +bool ECC_Ed25519_InitSanityCheck(); +void ECC_Ed25519_Start(); +void ECC_Ed25519_Stop(); + +#endif // DYNAMIC_BDAP_KEYED25519_H \ No newline at end of file diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 98a68bf26f..954bd1247d 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -10,6 +10,7 @@ #include "primitives/transaction.h" #include "wallet/wallet.h" #include "validation.h" +#include "bdap/keyed25519.h" #include From 3e757030e9098c3e5a7a1d16367197f0435d846d Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 19 Sep 2018 01:17:20 -0500 Subject: [PATCH 0222/1653] [DHT] Fix Ed25519 make new key pair --- src/bdap/domainentry.cpp | 6 ++-- src/bdap/keyed25519.cpp | 57 +++++++++++++++++++++---------------- src/bdap/keyed25519.h | 20 ++++++------- src/bdap/rpcdomainentry.cpp | 27 +++++++++--------- 4 files changed, 59 insertions(+), 51 deletions(-) diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 6731ed0c23..a1ffde6a18 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -375,6 +375,8 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) errorMessage = "Invalid BDAP encryption public key. Can not have more than " + std::to_string(MAX_KEY_LENGTH) + " characters."; return false; } + //TODO (BDAP): validate Ed25519 public key if possible. + /* else { if (EncryptPublicKey.size() > 0) { CPubKey entryEncryptPublicKey(EncryptPublicKey); @@ -384,7 +386,7 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) } } } - + */ return true; } @@ -435,7 +437,7 @@ bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged) oName.push_back(Pair("object_type", entry.ObjectTypeString())); oName.push_back(Pair("wallet_address", stringFromVch(entry.WalletAddress))); oName.push_back(Pair("public", (int)entry.fPublicObject)); - oName.push_back(Pair("encryption_publickey", HexStr(entry.EncryptPublicKey))); + oName.push_back(Pair("encryption_publickey", stringFromVch(entry.EncryptPublicKey))); oName.push_back(Pair("link_address", stringFromVch(entry.LinkAddress))); oName.push_back(Pair("txid", entry.txHash.GetHex())); if ((unsigned int)chainActive.Height() >= entry.nHeight-1) { diff --git a/src/bdap/keyed25519.cpp b/src/bdap/keyed25519.cpp index a18fc5068d..228169292d 100644 --- a/src/bdap/keyed25519.cpp +++ b/src/bdap/keyed25519.cpp @@ -4,16 +4,20 @@ #include "keyed25519.h" -#include +#include "random.h" +#include "bdap/domainentry.h" +#include "util.h" -#include "libtorrent/hasher512.hpp" -#include "libtorrent/kademlia/ed25519.hpp" -#include "libtorrent/kademlia/types.hpp" +#include +#include +#include +#include +#include #include #include -using namespace libtorrent::dht; +using namespace libtorrent; struct ed25519_context { @@ -41,29 +45,32 @@ bool CKeyEd25519::Check(const unsigned char *vch) // TODO (BDAP): Support compressed Ed25519 keys void CKeyEd25519::MakeNewKeyPair() { - std::tuple newKeyPair; - newKeyPair = ed25519_create_keypair(ed25519_context_sign->seed); - // Load the new ed25519 private key + // Load seed + std::array seed; + if (ed25519_context_sign == NULL || sizeof(ed25519_context_sign->seed) == 0) { + LogPrintf("CKeyEd25519::MakeNewKeyPair -- created new seed.\n"); + seed = dht::ed25519_create_seed(); + } + else { + seed = ed25519_context_sign->seed; + } + // Load the new ed25519 private key + std::tuple newKeyPair = dht::ed25519_create_keypair(seed); { - secret_key privateKey = std::get<1>(newKeyPair); + dht::secret_key privateKey = std::get<1>(newKeyPair); std::vector vchPrivateKey; - for (std::size_t i{0}; i < sizeof(privateKey); ++i) { - unsigned char charValue = static_cast(privateKey.bytes[i]); - vchPrivateKey.push_back(charValue); - } - Set(vchPrivateKey.begin(), vchPrivateKey.end(), false); + std::string strPrivateKey = aux::to_hex(privateKey.bytes); + vchPrivateKey = vchFromString(strPrivateKey); + memcpy(keyData.data(), &vchPrivateKey[0], vchPrivateKey.size()); + //LogPrintf("CKeyEd25519::MakeNewKeyPair -- vchPrivateKey = %s, size = %u\n", stringFromVch(vchPrivateKey), vchPrivateKey.size()); } - // Load the new ed25519 public key + // Load the new ed25519 public key { - public_key publicKey = std::get<0>(newKeyPair); - std::vector vchPublicKey; - for (std::size_t i{0}; i < sizeof(publicKey); ++i) { - unsigned char charValue = static_cast(publicKey.bytes[i]); - vchPublicKey.push_back(charValue); - } - SetPubKey(vchPublicKey.begin(), vchPublicKey.end()); + dht::public_key publicKey = std::get<0>(newKeyPair); + std::string strPublicKey = aux::to_hex(publicKey.bytes); + publicKeyData = vchFromString(strPublicKey); + //LogPrintf("CKeyEd25519::MakeNewKeyPair -- vchPublicKey = %s, size = %u\n", stringFromVch(publicKeyData), publicKeyData.size()); } - fValid = true; } void CKeyEd25519::SetMaster(const unsigned char* seed, unsigned int nSeedLen) @@ -78,11 +85,10 @@ void CKeyEd25519::SetMaster(const unsigned char* seed, unsigned int nSeedLen) void ECC_Ed25519_Start() { assert(ed25519_context_sign == NULL); - ed25519_context* ctx = new ed25519_context(); assert(ctx != NULL); { - ctx->seed = ed25519_create_seed(); + ctx->seed = dht::ed25519_create_seed(); } ed25519_context_sign = ctx; } @@ -100,6 +106,7 @@ bool ECC_Ed25519_InitSanityCheck() void ECC_Ed25519_Stop() { ed25519_context *ctx = ed25519_context_sign; + //ctx->seed = NULL; ed25519_context_sign = NULL; assert(ctx == NULL); } \ No newline at end of file diff --git a/src/bdap/keyed25519.h b/src/bdap/keyed25519.h index 05fdc9568e..6044e985b3 100644 --- a/src/bdap/keyed25519.h +++ b/src/bdap/keyed25519.h @@ -66,10 +66,7 @@ class CKeyEd25519 { if (size_t(pend - pbegin) != publicKeyData.size()) return; - - if (Check(&pbegin[0])) { - memcpy(publicKeyData.data(), (unsigned char*)&pbegin[0], publicKeyData.size()); - } + memcpy(publicKeyData.data(), (unsigned char*)&pbegin[0], publicKeyData.size()); } public: @@ -111,7 +108,10 @@ class CKeyEd25519 unsigned int size() const { return (fValid ? keyData.size() : 0); } const unsigned char* begin() const { return keyData.data(); } const unsigned char* end() const { return keyData.data() + size(); } - + + unsigned int PubKeySize() const { return publicKeyData.size(); } + const unsigned char* PubKeyBegin() const { return publicKeyData.data(); } + const unsigned char* PubKeyEnd() const { return publicKeyData.data() + PubKeySize(); } //! Check whether this private key is valid. bool IsValid() const { return fValid; } @@ -130,17 +130,15 @@ class CKeyEd25519 * This is expensive. */ CPrivKeyEd25519 GetPrivKey() const; - /** - * Convert the private key to a CPrivKeyEd25519 (serialized OpenSSL private key data). - * This is expensive. - */ - //secret_key GetDHTPrivKey() const; + //std::vector GetDHTPrivKey() const { return keyData; } + + std::vector GetPubKey() const { return publicKeyData; } /** * Compute the public key from a private key. * This is expensive. */ - //public_key GetPubKey() const; + // CPubKeyEd25519 GetPubKey() const; void SetMaster(const unsigned char* seed, unsigned int nSeedLen); /** diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 954bd1247d..03437477e9 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -4,13 +4,13 @@ #include "bdap/domainentry.h" #include "bdap/domainentrydb.h" +#include "bdap/keyed25519.h" #include "core_io.h" // needed for ScriptToAsmStr #include "rpcprotocol.h" #include "rpcserver.h" #include "primitives/transaction.h" #include "wallet/wallet.h" #include "validation.h" -#include "bdap/keyed25519.h" #include @@ -67,15 +67,16 @@ static UniValue AddDomainEntry(const JSONRPCRequest& request, BDAP::ObjectType b txDomainEntry.WalletAddress = vchWalletAddress; // TODO: Add ability to pass in the encryption public key - CKey privEncryptKey; - privEncryptKey.MakeNewKey(true); - CPubKey pubEncryptKey = privEncryptKey.GetPubKey(); - std::string strPrivateEncryptKey = CDynamicSecret(privEncryptKey).ToString(); - CharString vchEncryptPriKey(strPrivateEncryptKey.begin(), strPrivateEncryptKey.end()); - CharString vchEncryptPubKey(pubEncryptKey.begin(), pubEncryptKey.end()); - if (pwalletMain && !pwalletMain->AddKeyPubKey(privEncryptKey, pubEncryptKey)) - throw std::runtime_error("BDAP_ADD_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3503 - " + _("Error adding encrypt key to wallet for BDAP")); - + // TODO: Consider renaming to DHTPublicKey since it is used to add/modify entries in the DHT and encrypt/decrypt data stored in the DHT & blockchain. + // TODO: Add Ed25519 private key to wallet. Make sure it uses the same seed as secpk256k1 + CKeyEd25519 privEncryptKey; + privEncryptKey.MakeNewKeyPair(); + //CharString vchEncryptPriKey = privEncryptKey.GetDHTPrivKey(); + CharString vchEncryptPubKey = privEncryptKey.GetPubKey(); + //if (pwalletMain && !pwalletMain->AddKeyPubKey(privEncryptKey, pubEncryptKey)) + // throw std::runtime_error("BDAP_ADD_PUBLIC_ENTRY_RPC_ERROR: ERRCODE: 3503 - " + _("Error adding encrypt key to wallet for BDAP")); + //std::string strPrivateEncryptKey = stringFromVch(vchEncryptPriKey); + LogPrintf("AddDomainEntry -- vchEncryptPubKey = %s\n", stringFromVch(vchEncryptPubKey)); txDomainEntry.EncryptPublicKey = vchEncryptPubKey; // TODO: Add ability to pass in the link address @@ -142,7 +143,7 @@ static UniValue AddDomainEntry(const JSONRPCRequest& request, BDAP::ObjectType b LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", testDomainEntry.nVersion, testDomainEntry.GetFullObjectPath(), stringFromVch(testDomainEntry.CommonName), - stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey)); + stringFromVch(testDomainEntry.OrganizationalUnit), stringFromVch(testDomainEntry.EncryptPublicKey)); } return oName; @@ -349,7 +350,7 @@ static UniValue UpdateDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", testDomainEntry.nVersion, testDomainEntry.GetFullObjectPath(), stringFromVch(testDomainEntry.CommonName), - stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey)); + stringFromVch(testDomainEntry.OrganizationalUnit), stringFromVch(testDomainEntry.EncryptPublicKey)); } return oName; @@ -447,7 +448,7 @@ static UniValue DeleteDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", testDomainEntry.nVersion, testDomainEntry.GetFullObjectPath(), stringFromVch(testDomainEntry.CommonName), - stringFromVch(testDomainEntry.OrganizationalUnit), HexStr(testDomainEntry.EncryptPublicKey)); + stringFromVch(testDomainEntry.OrganizationalUnit), stringFromVch(testDomainEntry.EncryptPublicKey)); } return oName; From 4b52ce767d2de3c785d55a60d29ae5cee14d7324 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 19 Sep 2018 01:56:25 -0500 Subject: [PATCH 0223/1653] [DHT] Fix ECC Ed25519 start and stop functions --- src/bdap/keyed25519.cpp | 29 ++++++++++++----------------- src/bdap/keyed25519.h | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/bdap/keyed25519.cpp b/src/bdap/keyed25519.cpp index 228169292d..0a69bbfc45 100644 --- a/src/bdap/keyed25519.cpp +++ b/src/bdap/keyed25519.cpp @@ -19,19 +19,6 @@ using namespace libtorrent; -struct ed25519_context -{ - ed25519_context() = default; - explicit ed25519_context(char const* b) - { std::copy(b, b + len, seed.begin()); } - bool operator==(ed25519_context const& rhs) const - { return seed == rhs.seed; } - bool operator!=(ed25519_context const& rhs) const - { return seed != rhs.seed; } - constexpr static int len = 32; - std::array seed; -}; - static ed25519_context* ed25519_context_sign = NULL; // TODO (BDAP): Implement check Ed25519 keys @@ -47,12 +34,14 @@ void CKeyEd25519::MakeNewKeyPair() { // Load seed std::array seed; - if (ed25519_context_sign == NULL || sizeof(ed25519_context_sign->seed) == 0) { - LogPrintf("CKeyEd25519::MakeNewKeyPair -- created new seed.\n"); + if (ed25519_context_sign == NULL || sizeof(ed25519_context_sign->seed) == 0 || ed25519_context_sign->IsNull()) { + //LogPrintf("CKeyEd25519::MakeNewKeyPair -- created new seed.\n"); seed = dht::ed25519_create_seed(); } else { seed = ed25519_context_sign->seed; + std::string strSeed = aux::to_hex(seed); + //LogPrintf("CKeyEd25519::MakeNewKeyPair -- used existing seed = %s.\n", strSeed); } // Load the new ed25519 private key std::tuple newKeyPair = dht::ed25519_create_keypair(seed); @@ -89,6 +78,8 @@ void ECC_Ed25519_Start() assert(ctx != NULL); { ctx->seed = dht::ed25519_create_seed(); + std::string strSeed = aux::to_hex(ctx->seed); + //LogPrintf("ECC_Ed25519_Start -- new seed created = %s.\n", strSeed); } ed25519_context_sign = ctx; } @@ -106,7 +97,11 @@ bool ECC_Ed25519_InitSanityCheck() void ECC_Ed25519_Stop() { ed25519_context *ctx = ed25519_context_sign; - //ctx->seed = NULL; + std::string strSeed = aux::to_hex(ctx->seed); + //LogPrintf("ECC_Ed25519_Stop -- before null seed = %s.\n", strSeed); + ctx->SetNull(); ed25519_context_sign = NULL; - assert(ctx == NULL); + strSeed = aux::to_hex(ctx->seed); + //LogPrintf("ECC_Ed25519_Stop -- after null seed = %s.\n", strSeed); + assert(ed25519_context_sign == NULL); } \ No newline at end of file diff --git a/src/bdap/keyed25519.h b/src/bdap/keyed25519.h index 6044e985b3..d62713f95d 100644 --- a/src/bdap/keyed25519.h +++ b/src/bdap/keyed25519.h @@ -8,8 +8,38 @@ #include -//struct secret_key; -//struct public_key; +struct ed25519_context +{ + ed25519_context() = default; + + explicit ed25519_context(char const* b) + { std::copy(b, b + len, seed.begin()); } + + bool operator==(ed25519_context const& rhs) const + { return seed == rhs.seed; } + + bool operator!=(ed25519_context const& rhs) const + { return seed != rhs.seed; } + + constexpr static int len = 32; + + std::array seed; + + void SetNull() + { + std::fill(seed.begin(),seed.end(),0); + } + + bool IsNull() + { + for(int i=0;i Date: Thu, 20 Sep 2018 04:02:23 -0500 Subject: [PATCH 0224/1653] [DHT] Fix LibTorrent linker issue with Qt - Add GetDHTPrivKey to CKeyEd25519 - Add ECC_Ed25519_Start and ECC_Ed25519_Stop to init --- src/Makefile.am | 23 +++++++++-------------- src/Makefile.libtorrent.include | 21 +-------------------- src/Makefile.qt.include | 2 +- src/Makefile.qttest.include | 2 +- src/Makefile.test.include | 2 +- src/bdap/rpcdomainentry.cpp | 2 +- src/{bdap => dht}/keyed25519.cpp | 7 +++++++ src/{bdap => dht}/keyed25519.h | 2 +- src/init.cpp | 3 +++ 9 files changed, 25 insertions(+), 39 deletions(-) rename src/{bdap => dht}/keyed25519.cpp (94%) rename src/{bdap => dht}/keyed25519.h (98%) diff --git a/src/Makefile.am b/src/Makefile.am index 1cb13e41d6..eddb5d6f50 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,15 +6,10 @@ AM_CPPFLAGS = $(HARDENED_CPPFLAGS) EXTRA_LIBRARIES = DYNAMIC_CONFIG_INCLUDES=-I$(builddir)/config -DYNAMIC_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) +DYNAMIC_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(LIBTORRENT_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) DYNAMIC_INCLUDES += -I$(srcdir)/secp256k1/include DYNAMIC_INCLUDES += -I$(srcdir)/univalue/include -DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/ed25519/src -DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/include -DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/include/aux_ -DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/include/extensions -DYNAMIC_INCLUDES += -I$(srcdir)/libtorrent/include/kademlia LIBDYNAMIC_SERVER=libdynamic_server.a LIBDYNAMIC_WALLET=libdynamic_wallet.a @@ -25,7 +20,6 @@ LIBDYNAMIC_CRYPTO=crypto/libdynamic_crypto.a LIBDYNAMICQT=qt/libdynamicqt.a LIBSECP256K1=secp256k1/libsecp256k1.la LIBUNIVALUE=univalue/libunivalue.la -#LIBTORRENT=libtorrent/librasterbar.a $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) @@ -33,6 +27,10 @@ $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) +if EMBEDDED_LIBTORRENT +include Makefile.libtorrent.include +endif + # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: EXTRA_LIBRARIES += \ @@ -112,8 +110,8 @@ DYNAMIC_CORE_H = \ bdap/entrycheckpoints.h \ bdap/entrylink.h \ bdap/identity.h \ - bdap/keyed25519.h \ dbwrapper.h \ + dht/keyed25519.h \ dynode.h \ dynode-payments.h \ dynode-sync.h \ @@ -248,8 +246,8 @@ libdynamic_server_a_SOURCES = \ bdap/entrycheckpoints.cpp \ bdap/entrylink.cpp \ bdap/identity.cpp \ - bdap/keyed25519.cpp \ dbwrapper.cpp \ + dht/keyed25519.cpp \ dynode.cpp \ dynode-payments.cpp\ dynode-sync.cpp \ @@ -507,7 +505,8 @@ dynamic_tx_LDADD = \ $(LIBDYNAMIC_COMMON) \ $(LIBDYNAMIC_UTIL) \ $(LIBDYNAMIC_CRYPTO) \ - $(LIBSECP256K1) + $(LIBSECP256K1) \ + $(LIBTORRENT) dynamic_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # @@ -597,10 +596,6 @@ if EMBEDDED_LEVELDB include Makefile.leveldb.include endif -if EMBEDDED_LIBTORRENT -include Makefile.libtorrent.include -endif - if ENABLE_TESTS include Makefile.test.include endif diff --git a/src/Makefile.libtorrent.include b/src/Makefile.libtorrent.include index c7f524dc24..fbcafe6730 100644 --- a/src/Makefile.libtorrent.include +++ b/src/Makefile.libtorrent.include @@ -7,9 +7,6 @@ EXTRA_LIBRARIES += $(LIBTORRENT_INT) LIBTORRENT += $(LIBTORRENT_INT) LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include -LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include/aux_ -LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include/extensions -LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/include/kademlia LIBTORRENT_CPPFLAGS += -I$(srcdir)/libtorrent/ed25519/src LIBTORRENT_CPPFLAGS_INT = @@ -22,13 +19,7 @@ endif libtorrent_librasterbar_a_CPPFLAGS = $(CPPFLAGS) $(LIBTORRENT_CPPFLAGS_INT) $(LIBTORRENT_CPPFLAGS) libtorrent_librasterbar_a_CXXFLAGS = $(CXXFLAGS) $(PIE_FLAGS) - libtorrent_librasterbar_a_SOURCES= \ - libtorrent/include/libtorrent/*.hpp \ - libtorrent/include/libtorrent/aux_/*.hpp \ - libtorrent/include/libtorrent/extensions/*.hpp \ - libtorrent/include/libtorrent/kademlia/*.hpp \ - libtorrent/ed25519/src/*.h \ libtorrent/src/web_connection_base.cpp \ libtorrent/src/alert.cpp \ libtorrent/src/alert_manager.cpp \ @@ -284,15 +275,6 @@ LIBTORRENT_DOCS_PAGES = \ libtorrent/docs/reference.html \ libtorrent/docs/single-page-ref.html -LIBTORRENT_ED25519_SOURCE = \ - libtorrent/ed25519/readme.md \ - libtorrent/ed25519/test.c \ - libtorrent/ed25519/src/fe.h \ - libtorrent/ed25519/src/fixedint.h \ - libtorrent/ed25519/src/ge.h \ - libtorrent/ed25519/src/precomp_data.h \ - libtorrent/ed25519/src/sc.h - LIBTORRENT_EXTRA_DIST = \ libtorrent/Jamfile \ libtorrent/Jamroot.jam \ @@ -301,5 +283,4 @@ LIBTORRENT_EXTRA_DIST = \ libtorrent/LICENSE \ libtorrent/README.rst \ $(LIBTORRENT_DOCS_PAGES) \ - $(LIBTORRENT_DOCS_IMAGES) \ - $(LIBTORRENT_ED25519_SOURCE) \ No newline at end of file + $(LIBTORRENT_DOCS_IMAGES) \ No newline at end of file diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 69be201c6c..edeff10768 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -374,7 +374,7 @@ if ENABLE_ZMQ qt_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif qt_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ - $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ + $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBTORRENT) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) qt_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_dynamic_qt_LIBTOOLFLAGS = --tag CXX diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 39a616a8a1..448077f13c 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -45,7 +45,7 @@ qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_ZMQ) $(ZMQ_LIBS) endif qt_test_test_dynamic_qt_LDADD += $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ - $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ + $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBTORRENT) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) qt_test_test_dynamic_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_test_test_dynamic_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c8222f3447..b8c98f62e9 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -108,7 +108,7 @@ endif test_test_dynamic_SOURCES = $(DYNAMIC_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_dynamic_CPPFLAGS = $(AM_CPPFLAGS) $(DYNAMIC_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) -test_test_dynamic_LDADD = $(LIBDYNAMIC_SERVER) $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) \ +test_test_dynamic_LDADD = $(LIBDYNAMIC_SERVER) $(LIBDYNAMIC_CLI) $(LIBDYNAMIC_COMMON) $(LIBDYNAMIC_UTIL) $(LIBDYNAMIC_CRYPTO) $(LIBUNIVALUE) $(LIBTORRENT) \ $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) test_test_dynamic_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) if ENABLE_WALLET diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index 03437477e9..d8e084e1b0 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -4,7 +4,7 @@ #include "bdap/domainentry.h" #include "bdap/domainentrydb.h" -#include "bdap/keyed25519.h" +#include "dht/keyed25519.h" #include "core_io.h" // needed for ScriptToAsmStr #include "rpcprotocol.h" #include "rpcserver.h" diff --git a/src/bdap/keyed25519.cpp b/src/dht/keyed25519.cpp similarity index 94% rename from src/bdap/keyed25519.cpp rename to src/dht/keyed25519.cpp index 0a69bbfc45..c46fac949d 100644 --- a/src/bdap/keyed25519.cpp +++ b/src/dht/keyed25519.cpp @@ -71,6 +71,13 @@ void CKeyEd25519::SetMaster(const unsigned char* seed, unsigned int nSeedLen) return; } +std::vector CKeyEd25519::GetDHTPrivKey() const +{ + std::vector vchPrivateKey; + memcpy(vchPrivateKey.data(), &keyData[0], keyData.size()); + return vchPrivateKey; +} + void ECC_Ed25519_Start() { assert(ed25519_context_sign == NULL); diff --git a/src/bdap/keyed25519.h b/src/dht/keyed25519.h similarity index 98% rename from src/bdap/keyed25519.h rename to src/dht/keyed25519.h index d62713f95d..7bc0b2c2a7 100644 --- a/src/bdap/keyed25519.h +++ b/src/dht/keyed25519.h @@ -161,7 +161,7 @@ class CKeyEd25519 */ CPrivKeyEd25519 GetPrivKey() const; - //std::vector GetDHTPrivKey() const { return keyData; } + std::vector GetDHTPrivKey() const; std::vector GetPubKey() const { return publicKeyData; } /** diff --git a/src/init.cpp b/src/init.cpp index b548531589..6d8cd85c36 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -19,6 +19,7 @@ #include "chainparams.h" #include "checkpoints.h" #include "bdap/domainentrydb.h" +#include "dht/keyed25519.h" #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeconfig.h" @@ -336,6 +337,7 @@ void Shutdown() #endif globalVerifyHandle.reset(); ECC_Stop(); + ECC_Ed25519_Stop(); LogPrintf("%s: done\n", __func__); } @@ -1189,6 +1191,7 @@ bool AppInitSanityChecks() // Initialize elliptic curve code ECC_Start(); + ECC_Ed25519_Start(); globalVerifyHandle.reset(new ECCVerifyHandle()); // Sanity check From 8243a0e36390cbcf1297ce881b878afb397f3ffa Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 21 Sep 2018 01:09:19 -0500 Subject: [PATCH 0225/1653] [DHT] Add stub class for hash table settings --- src/Makefile.am | 2 + src/dht/dhtsettings.cpp | 1242 +++++++++++++++++++++++++++++++++++++++ src/dht/dhtsettings.h | 27 + src/dht/keyed25519.h | 6 +- 4 files changed, 1274 insertions(+), 3 deletions(-) create mode 100644 src/dht/dhtsettings.cpp create mode 100644 src/dht/dhtsettings.h diff --git a/src/Makefile.am b/src/Makefile.am index eddb5d6f50..7a5456af13 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -111,6 +111,7 @@ DYNAMIC_CORE_H = \ bdap/entrylink.h \ bdap/identity.h \ dbwrapper.h \ + dht/dhtsettings.h \ dht/keyed25519.h \ dynode.h \ dynode-payments.h \ @@ -247,6 +248,7 @@ libdynamic_server_a_SOURCES = \ bdap/entrylink.cpp \ bdap/identity.cpp \ dbwrapper.cpp \ + dht/dhtsettings.cpp \ dht/keyed25519.cpp \ dynode.cpp \ dynode-payments.cpp\ diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp new file mode 100644 index 0000000000..898ff524d6 --- /dev/null +++ b/src/dht/dhtsettings.cpp @@ -0,0 +1,1242 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#include "dht/dhtsettings.h" + +using namespace libtorrent; + +CDHTSettings::CDHTSettings() +{ + LoadSettings(); +} + +void CDHTSettings::LoadSettings() +{ + + settings.set_bool(settings_pack::enable_dht, false); + settings.set_int(settings_pack::alert_mask, 0xffffffff); + session newSession(settings); + + // Dynamic LibTorrent Settings + + // ``enable_dht`` starts the dht node and makes the trackerless service available to + // torrents. + settings.set_bool(settings_pack::enable_dht, true); + + // ``announce_ip`` is the ip address passed along to trackers as the + // ``&ip=`` parameter. If left as the default, that parameter is + // omitted. + settings.set_bool(settings_pack::announce_ip, false); + + // ``allow_multiple_connections_per_ip`` determines if connections from the same IP address as existing + // connections should be rejected or not. Multiple connections from + // the same IP address is not allowed by default, to prevent abusive + // behavior by peers. It may be useful to allow such connections in + // cases where simulations are run on the same machine, and all peers + // in a swarm has the same IP address. + // allow_multiple_connections_per_ip + settings.set_bool(settings_pack::allow_multiple_connections_per_ip, true); + + // ``send_redundant_have`` controls if have messages will be sent to + // peers that already have the piece. This is typically not necessary, + // but it might be necessary for collecting statistics in some cases. + settings.set_bool(settings_pack::send_redundant_have, true); + + // ``use_dht_as_fallback`` determines how the DHT is used. If this is + // true, the DHT will only be used for torrents where all trackers in + // its tracker list has failed. Either by an explicit error message or + // a time out. This is false by default, which means the DHT is used + // by default regardless of if the trackers fail or not. + settings.set_bool(settings_pack::use_dht_as_fallback, false); + + // ``upnp_ignore_nonrouters`` indicates whether or not the UPnP + // implementation should ignore any broadcast response from a device + // whose address is not the configured router for this machine. i.e. + // it's a way to not talk to other people's routers by mistake. + settings.set_bool(settings_pack::upnp_ignore_nonrouters, true); + + // ``use_parole_mode`` specifies if parole mode should be used. Parole + // mode means that peers that participate in pieces that fail the hash + // check are put in a mode where they are only allowed to download + // whole pieces. If the whole piece a peer in parole mode fails the + // hash check, it is banned. If a peer participates in a piece that + // passes the hash check, it is taken out of parole mode. + settings.set_bool(settings_pack::use_parole_mode, true); + + // ``use_read_cache`` enable and disable caching of blocks read from disk. the purpose of + // the read cache is partly read-ahead of requests but also to avoid + // reading blocks back from the disk multiple times for popular + // pieces. + settings.set_bool(settings_pack::use_read_cache, true); + + // ``coalesce_reads`` ``coalesce_writes`` + // allocate separate, contiguous, buffers for read and write calls. + // Only used where writev/readv cannot be used will use more RAM but + // may improve performance + //settings.set_bool(settings_pack::coalesce_reads, false); + //settings.set_bool(settings_pack::coalesce_writes, false); + + // ``auto_manage_prefer_seeds`` + // prefer seeding torrents when determining which torrents to give + // active slots to, the default is false which gives preference to + // downloading torrents + settings.set_bool(settings_pack::auto_manage_prefer_seeds, false); + + // if ``dont_count_slow_torrents`` is true, torrents without any + // payload transfers are not subject to the ``active_seeds`` and + // ``active_downloads`` limits. This is intended to make it more + // likely to utilize all available bandwidth, and avoid having + // torrents that don't transfer anything block the active slots. + //settings.set_bool(settings_pack::dont_count_slow_torrents, false); + + // ``close_redundant_connections`` specifies whether libtorrent should + // close connections where both ends have no utility in keeping the + // connection open. For instance if both ends have completed their + // downloads, there's no point in keeping it open. + + settings.set_bool(settings_pack::close_redundant_connections, false); + // If ``prioritize_partial_pieces`` is true, partial pieces are picked + // before pieces that are more rare. If false, rare pieces are always + // prioritized, unless the number of partial pieces is growing out of + // proportion. + + settings.set_bool(settings_pack::prioritize_partial_pieces, false); + // if ``rate_limit_ip_overhead`` set to true, the estimated TCP/IP overhead is drained from the + // rate limiters, to avoid exceeding the limits with the total traffic + //settings.set_bool(settings_pack::rate_limit_ip_overhead, true); + + // ``announce_to_all_trackers`` controls how multi tracker torrents + // are treated. If this is set to true, all trackers in the same tier + // are announced to in parallel. If all trackers in tier 0 fails, all + // trackers in tier 1 are announced as well. If it's set to false, the + // behavior is as defined by the multi tracker specification. It + // defaults to false, which is the same behavior previous versions of + // libtorrent has had as well. + settings.set_bool(settings_pack::announce_to_all_trackers, true); + + // ``announce_to_all_tiers`` also controls how multi tracker torrents + // are treated. When this is set to true, one tracker from each tier + // is announced to. This is the uTorrent behavior. This is false by + // default in order to comply with the multi-tracker specification. + settings.set_bool(settings_pack::announce_to_all_tiers, true); + + // ``prefer_udp_trackers`` is true by default. It means that trackers + // may be rearranged in a way that udp trackers are always tried + // before http trackers for the same hostname. Setting this to false + // means that the trackers' tier is respected and there's no + // preference of one protocol over another. + settings.set_bool(settings_pack::prefer_udp_trackers, true); + + // ``strict_super_seeding`` when this is set to true, a piece has to + // have been forwarded to a third peer before another one is handed + // out. This is the traditional definition of super seeding. + settings.set_bool(settings_pack::strict_super_seeding, true); + + // ``disable_hash_checks`` when set to true, all data downloaded from peers will be assumed to + // be correct, and not tested to match the hashes in the torrent this + // is only useful for simulation and testing purposes (typically + // combined with disabled_storage) + settings.set_bool(settings_pack::disable_hash_checks, false); + + // ``allow_i2p_mixed`` if this is true, i2p torrents are allowed to also get peers from + // other sources than the tracker, and connect to regular IPs, not + // providing any anonymization. This may be useful if the user is not + // interested in the anonymization of i2p, but still wants to be able + // to connect to i2p peers. + settings.set_bool(settings_pack::allow_i2p_mixed, true); + + // ``volatile_read_cache``, if this is set to true, read cache blocks + // that are hit by peer read requests are removed from the disk cache + // to free up more space. This is useful if you don't expect the disk + // cache to create any cache hits from other peers than the one who + // triggered the cache line to be read into the cache in the first + // place. + //settings.set_bool(settings_pack::volatile_read_cache, true); +#ifndef WIN32 + // ``no_atime_storage`` this is a linux-only option and passes in the + // ``O_NOATIME`` to ``open()`` when opening files. This may lead to + // some disk performance improvements. + settings.set_bool(settings_pack::no_atime_storage, true); +#endif + // ``incoming_starts_queued_torrents`` defaults to false. If a torrent + // has been paused by the auto managed feature in libtorrent, i.e. the + // torrent is paused and auto managed, this feature affects whether or + // not it is automatically started on an incoming connection. The main + // reason to queue torrents, is not to make them unavailable, but to + // save on the overhead of announcing to the trackers, the DHT and to + // avoid spreading one's unchoke slots too thin. If a peer managed to + // find us, even though we're no in the torrent anymore, this setting + // can make us start the torrent and serve it. + settings.set_bool(settings_pack::incoming_starts_queued_torrents, false); //TODO: should this be true? + + // ``report_true_downloaded`` when set to true, the downloaded counter + // sent to trackers will include the actual number of payload + // bytes downloaded including redundant bytes. If set to false, it + // will not include any redundancy bytes + //settings.set_bool(settings_pack::report_true_downloaded, false); + + // ``strict_end_game_mode`` defaults to true, and controls when a + // block may be requested twice. If this is ``true``, a block may only + // be requested twice when there's ay least one request to every piece + // that's left to download in the torrent. This may slow down progress + // on some pieces sometimes, but it may also avoid downloading a lot + // of redundant bytes. If this is ``false``, libtorrent attempts to + // use each peer connection to its max, by always requesting + // something, even if it means requesting something that has been + // requested from another peer already. + settings.set_bool(settings_pack::strict_end_game_mode, true); + + // if ``broadcast_lsd`` is set to true, the local peer discovery (or + // Local Service Discovery) will not only use IP multicast, but also + // broadcast its messages. This can be useful when running on networks + // that don't support multicast. Since broadcast messages might be + // expensive and disruptive on networks, only every 8th announce uses + // broadcast. + //settings.set_bool(settings_pack::broadcast_lsd, true); + + // ``enable_outgoing_utp`` ``enable_incoming_utp`` + // ``enable_outgoing_tcp`` ``enable_incoming_tcp`` + // when set to true, libtorrent will try to make outgoing utp + // connections controls whether libtorrent will accept incoming + // connections or make outgoing connections of specific type. + settings.set_bool(settings_pack::enable_outgoing_utp, true); + settings.set_bool(settings_pack::enable_incoming_utp, true); + settings.set_bool(settings_pack::enable_outgoing_tcp, true); + settings.set_bool(settings_pack::enable_incoming_tcp, true); + + // ``seeding_outgoing_connections`` determines if seeding (and + // finished) torrents should attempt to make outgoing connections or + // not. By default this is true. It may be set to false in very + // specific applications where the cost of making outgoing connections + // is high, and there are no or small benefits of doing so. For + // instance, if no nodes are behind a firewall or a NAT, seeds don't + // need to make outgoing connections. + settings.set_bool(settings_pack::seeding_outgoing_connections, true); + + // ``no_connect_privileged_ports`` when this is true, + // libtorrent will not attempt to make outgoing connections + // to peers whose port is < 1024. This is a safety precaution + // to avoid being part of a DDoS attack + //settings.set_bool(settings_pack::no_connect_privileged_ports, true); //TODO: should this be true? + + // ``smooth_connects`` is true by default, which means the number of + // connection attempts per second may be limited to below the + // ``connection_speed``, in case we're close to bump up against the + // limit of number of connections. The intention of this setting is to + // more evenly distribute our connection attempts over time, instead + // of attempting to connect in batches, and timing them out in + // batches. + settings.set_bool(settings_pack::smooth_connects, true); + + // ``always_send_user_agent`` + // always send user-agent in every web seed request. If false, only + // the first request per http connection will include the user agent + //settings.set_bool(settings_pack::always_send_user_agent, true); + + // ``apply_ip_filter_to_trackers`` defaults to true. It determines + // whether the IP filter applies to trackers as well as peers. If this + // is set to false, trackers are exempt from the IP filter (if there + // is one). If no IP filter is set, this setting is irrelevant. + settings.set_bool(settings_pack::apply_ip_filter_to_trackers, true); + + // ``ban_web_seeds`` when true, web seeds sending bad data will be banned + //settings.set_bool(settings_pack::ban_web_seeds, true); //TODO: should this be true? + + // ``allow_partial_disk_writes`` + // when set to false, the ``write_cache_line_size`` will apply across + // piece boundaries. this is a bad idea unless the piece picker also + // is configured to have an affinity to pick pieces belonging to the + // same write cache line as is configured in the disk cache. + //settings.set_bool(settings_pack::allow_partial_disk_writes, true); + + // ``support_share_mode`` if false, prevents libtorrent to advertise share-mode support + //settings.set_bool(settings_pack::support_share_mode, true); + + // ``support_merkle_torrents`` if this is false, don't advertise support for the Tribler merkle + // tree piece message + //settings.set_bool(settings_pack::support_merkle_torrents, true); + + // ``report_redundant_bytes`` if this is true, the number of redundant bytes is sent to the + // tracker + //settings.set_bool(settings_pack::report_redundant_bytes, false); + + // ``listen_system_port_fallback`` if this is true, + // libtorrent will fall back to listening on a port chosen by the + // operating system (i.e. binding to port 0). If a failure is + // preferred, set this to false. + settings.set_bool(settings_pack::listen_system_port_fallback, true); + + // ``announce_crypto_support`` when this is true, and incoming encrypted connections are enabled, + // &supportcrypt=1 is included in http tracker announces + //settings.set_bool(settings_pack::announce_crypto_support, true); //TODO: should this be true? + + // ``enable_upnp`` + // Starts and stops the UPnP service. When started, the listen port + // and the DHT port are attempted to be forwarded on local UPnP router + // devices. + // The upnp object returned by ``start_upnp()`` can be used to add and + // remove arbitrary port mappings. Mapping status is returned through + // the portmap_alert and the portmap_error_alert. The object will be + // valid until ``stop_upnp()`` is called. See upnp-and-nat-pmp_. + //settings.set_bool(settings_pack::enable_upnp, false); + + // ``enable_natpmp`` + // Starts and stops the NAT-PMP service. When started, the listen port + // and the DHT port are attempted to be forwarded on the router + // through NAT-PMP. + // The natpmp object returned by ``start_natpmp()`` can be used to add + // and remove arbitrary port mappings. Mapping status is returned + // through the portmap_alert and the portmap_error_alert. The object + // will be valid until ``stop_natpmp()`` is called. See + // upnp-and-nat-pmp_. + //settings.set_bool(settings_pack::enable_natpmp, true); //TODO: should this be true? + + // ``enable_lsd`` + // Starts and stops Local Service Discovery. This service will + // broadcast the info-hashes of all the non-private torrents on the + // local network to look for peers on the same swarm within multicast + // reach. + //settings.set_bool(settings_pack::enable_lsd, true); + + // ``prefer_rc4`` + // if the allowed encryption level is both, setting this to true will + // prefer rc4 if both methods are offered, plaintext otherwise + //settings.set_bool(settings_pack::prefer_rc4, true); //TODO: should this be true? + + // ``proxy_hostnames`` + // if true, hostname lookups are done via the configured proxy (if + // any). This is only supported by SOCKS5 and HTTP. + //settings.set_bool(settings_pack::proxy_hostnames, true); + + // ``proxy_peer_connections`` + // if true, peer connections are made (and accepted) over the + // configured proxy, if any. Web seeds as well as regular bittorrent + // peer connections are considered "peer connections". Anything + // transporting actual torrent payload (trackers and DHT traffic are + // not considered peer connections). + //settings.set_bool(settings_pack::proxy_peer_connections, true); + + // ``auto_sequential`` + // if this setting is true, torrents with a very high availability of + // pieces (and seeds) are downloaded sequentially. This is more + // efficient for the disk I/O. With many seeds, the download order is + // unlikely to matter anyway + //settings.set_bool(settings_pack::auto_sequential, true); + + // ``proxy_tracker_connections`` + // if true, tracker connections are made over the configured proxy, if + // any. + //, + //settings.set_bool(settings_pack::proxy_tracker_connections, true); + + // Starts and stops the internal IP table route changes notifier. + // + // The current implementation supports multiple platforms, and it is + // recommended to have it enable, but you may want to disable it if + // it's supported but unreliable, or if you have a better way to + // detect the changes. In the later case, you should manually call + // ``session_handle::reopen_network_sockets`` to ensure network + // changes are taken in consideration. + //enable_ip_notifier, + + + // int params: + + // ``tracker_completion_timeout`` is the number of seconds the tracker + // connection will wait from when it sent the request until it + // considers the tracker to have timed-out. + //tracker_completion_timeout = int_type_base, + + // ``tracker_receive_timeout`` is the number of seconds to wait to + // receive any data from the tracker. If no data is received for this + // number of seconds, the tracker will be considered as having timed + // out. If a tracker is down, this is the kind of timeout that will + // occur. + //tracker_receive_timeout, + + // ``stop_tracker_timeout`` is the number of seconds to wait when + // sending a stopped message before considering a tracker to have + // timed out. This is usually shorter, to make the client quit faster. + // If the value is set to 0, the connections to trackers with the + // stopped event are suppressed. + //stop_tracker_timeout, + + // this is the maximum number of bytes in a tracker response. If a + // response size passes this number of bytes it will be rejected and + // the connection will be closed. On gzipped responses this size is + // measured on the uncompressed data. So, if you get 20 bytes of gzip + // response that'll expand to 2 megabytes, it will be interrupted + // before the entire response has been uncompressed (assuming the + // limit is lower than 2 megs). + //tracker_maximum_response_length, + + // the number of seconds from a request is sent until it times out if + // no piece response is returned. + //piece_timeout, + + // the number of seconds one block (16kB) is expected to be received + // within. If it's not, the block is requested from a different peer + //request_timeout, + + // the length of the request queue given in the number of seconds it + // should take for the other end to send all the pieces. i.e. the + // actual number of requests depends on the download rate and this + // number. + //request_queue_time, + + // the number of outstanding block requests a peer is allowed to queue + // up in the client. If a peer sends more requests than this (before + // the first one has been sent) the last request will be dropped. the + // higher this is, the faster upload speeds the client can get to a + // single peer. + //max_allowed_in_request_queue, + + // ``max_out_request_queue`` is the maximum number of outstanding + // requests to send to a peer. This limit takes precedence over + // ``request_queue_time``. i.e. no matter the download speed, the + // number of outstanding requests will never exceed this limit. + //max_out_request_queue, + + // if a whole piece can be downloaded in this number of seconds, or + // less, the peer_connection will prefer to request whole pieces at a + // time from this peer. The benefit of this is to better utilize disk + // caches by doing localized accesses and also to make it easier to + // identify bad peers if a piece fails the hash check. + //whole_pieces_threshold, + + // ``peer_timeout`` is the number of seconds the peer connection + // should wait (for any activity on the peer connection) before + // closing it due to time out. This defaults to 120 seconds, since + // that's what's specified in the protocol specification. After half + // the time out, a keep alive message is sent. + //peer_timeout, + + // same as peer_timeout, but only applies to url-seeds. this is + // usually set lower, because web servers are expected to be more + // reliable. + //urlseed_timeout, + + // controls the pipelining size of url and http seeds. i.e. the number of HTTP + // request to keep outstanding before waiting for the first one to + // complete. It's common for web servers to limit this to a relatively + // low number, like 5 + //urlseed_pipeline_size, + + // number of seconds until a new retry of a url-seed takes place. + // Default retry value for http-seeds that don't provide a valid 'retry-after' header. + //urlseed_wait_retry, + + // sets the upper limit on the total number of files this session will + // keep open. The reason why files are left open at all is that some + // anti virus software hooks on every file close, and scans the file + // for viruses. deferring the closing of the files will be the + // difference between a usable system and a completely hogged down + // system. Most operating systems also has a limit on the total number + // of file descriptors a process may have open. + //file_pool_size, + + // ``max_failcount`` is the maximum times we try to connect to a peer + // before stop connecting again. If a peer succeeds, the failcounter + // is reset. If a peer is retrieved from a peer source (other than + // DHT) the failcount is decremented by one, allowing another try. + //max_failcount, + + // the number of seconds to wait to reconnect to a peer. this time is + // multiplied with the failcount. + //min_reconnect_time, + + // ``peer_connect_timeout`` the number of seconds to wait after a + // connection attempt is initiated to a peer until it is considered as + // having timed out. This setting is especially important in case the + // number of half-open connections are limited, since stale half-open + // connection may delay the connection of other peers considerably. + //peer_connect_timeout, + + // ``connection_speed`` is the number of connection attempts that are + // made per second. If a number < 0 is specified, it will default to + // 200 connections per second. If 0 is specified, it means don't make + // outgoing connections at all. + //connection_speed, + + // if a peer is uninteresting and uninterested for longer than this + // number of seconds, it will be disconnected. default is 10 minutes + //inactivity_timeout, + + // ``unchoke_interval`` is the number of seconds between + // chokes/unchokes. On this interval, peers are re-evaluated for being + // choked/unchoked. This is defined as 30 seconds in the protocol, and + // it should be significantly longer than what it takes for TCP to + // ramp up to it's max rate. + //unchoke_interval, + + // ``optimistic_unchoke_interval`` is the number of seconds between + // each *optimistic* unchoke. On this timer, the currently + // optimistically unchoked peer will change. + //optimistic_unchoke_interval, + + // ``num_want`` is the number of peers we want from each tracker + // request. It defines what is sent as the ``&num_want=`` parameter to + // the tracker. + //num_want, + + // ``initial_picker_threshold`` specifies the number of pieces we need + // before we switch to rarest first picking. This defaults to 4, which + // means the 4 first pieces in any torrent are picked at random, the + // following pieces are picked in rarest first order. + //initial_picker_threshold, + + // the number of allowed pieces to send to peers that supports the + // fast extensions + //allowed_fast_set_size, + + // ``suggest_mode`` controls whether or not libtorrent will send out + // suggest messages to create a bias of its peers to request certain + // pieces. The modes are: + // + // * ``no_piece_suggestions`` which is the default and will not send + // out suggest messages. + // * ``suggest_read_cache`` which will send out suggest messages for + // the most recent pieces that are in the read cache. + //suggest_mode, + + // ``max_queued_disk_bytes`` is the maximum number of bytes, to + // be written to disk, that can wait in the disk I/O thread queue. + // This queue is only for waiting for the disk I/O thread to receive + // the job and either write it to disk or insert it in the write + // cache. When this limit is reached, the peer connections will stop + // reading data from their sockets, until the disk thread catches up. + // Setting this too low will severely limit your download rate. + //max_queued_disk_bytes, + + // the number of seconds to wait for a handshake response from a peer. + // If no response is received within this time, the peer is + // disconnected. + //handshake_timeout, + + // ``send_buffer_low_watermark`` the minimum send buffer target size + // (send buffer includes bytes pending being read from disk). For good + // and snappy seeding performance, set this fairly high, to at least + // fit a few blocks. This is essentially the initial window size which + // will determine how fast we can ramp up the send rate + // + // if the send buffer has fewer bytes than ``send_buffer_watermark``, + // we'll read another 16kB block onto it. If set too small, upload + // rate capacity will suffer. If set too high, memory will be wasted. + // The actual watermark may be lower than this in case the upload rate + // is low, this is the upper limit. + // + // the current upload rate to a peer is multiplied by this factor to + // get the send buffer watermark. The factor is specified as a + // percentage. i.e. 50 -> 0.5 This product is clamped to the + // ``send_buffer_watermark`` setting to not exceed the max. For high + // speed upload, this should be set to a greater value than 100. For + // high capacity connections, setting this higher can improve upload + // performance and disk throughput. Setting it too high may waste RAM + // and create a bias towards read jobs over write jobs. + //send_buffer_low_watermark, + //send_buffer_watermark, + //send_buffer_watermark_factor, + + // ``choking_algorithm`` specifies which algorithm to use to determine + // which peers to unchoke. + // + // The options for choking algorithms are: + // + // * ``fixed_slots_choker`` is the traditional choker with a fixed + // number of unchoke slots (as specified by + // ``settings_pack::unchoke_slots_limit``). + // + // * ``rate_based_choker`` opens up unchoke slots based on the upload + // rate achieved to peers. The more slots that are opened, the + // marginal upload rate required to open up another slot increases. + // + // * ``bittyrant_choker`` attempts to optimize download rate by + // finding the reciprocation rate of each peer individually and + // prefers peers that gives the highest *return on investment*. It + // still allocates all upload capacity, but shuffles it around to + // the best peers first. For this choker to be efficient, you need + // to set a global upload rate limit + // (``settings_pack::upload_rate_limit``). For more information + // about this choker, see the paper_. This choker is not fully + // implemented nor tested. + // + // .. _paper: http://bittyrant.cs.washington.edu/#papers + // + // ``seed_choking_algorithm`` controls the seeding unchoke behavior. + // The available options are: + // + // * ``round_robin`` which round-robins the peers that are unchoked + // when seeding. This distributes the upload bandwidht uniformly and + // fairly. It minimizes the ability for a peer to download everything + // without redistributing it. + // + // * ``fastest_upload`` unchokes the peers we can send to the fastest. + // This might be a bit more reliable in utilizing all available + // capacity. + // + // * ``anti_leech`` prioritizes peers who have just started or are + // just about to finish the download. The intention is to force + // peers in the middle of the download to trade with each other. + //choking_algorithm, + //seed_choking_algorithm, + + // ``cache_size`` is the disk write and read cache. It is specified + // in units of 16 KiB blocks. Buffers that are part of a peer's send + // or receive buffer also count against this limit. Send and receive + // buffers will never be denied to be allocated, but they will cause + // the actual cached blocks to be flushed or evicted. If this is set + // to -1, the cache size is automatically set based on the amount of + // physical RAM on the machine. If the amount of physical RAM cannot + // be determined, it's set to 1024 (= 16 MiB). + // + // ``cache_expiry`` is the number of seconds from the last cached write + // to a piece in the write cache, to when it's forcefully flushed to + // disk. Default is 60 second. + // + // On 32 bit builds, the effective cache size will be limited to 3/4 of + // 2 GiB to avoid exceeding the virtual address space limit. + //cache_size, + + //cache_expiry, + + // determines how files are opened when they're in read only mode + // versus read and write mode. The options are: + // + // enable_os_cache + // This is the default and files are opened normally, with the OS + // caching reads and writes. + // disable_os_cache + // This opens all files in no-cache mode. This corresponds to the + // OS not letting blocks for the files linger in the cache. This + // makes sense in order to avoid the bittorrent client to + // potentially evict all other processes' cache by simply handling + // high throughput and large files. If libtorrent's read cache is + // disabled, enabling this may reduce performance. + // + // One reason to disable caching is that it may help the operating + // system from growing its file cache indefinitely. + //disk_io_write_mode, + //disk_io_read_mode, + + // this is the first port to use for binding outgoing connections to. + // This is useful for users that have routers that allow QoS settings + // based on local port. when binding outgoing connections to specific + // ports, ``num_outgoing_ports`` is the size of the range. It should + // be more than a few + // + // .. warning:: setting outgoing ports will limit the ability to keep + // multiple connections to the same client, even for different + // torrents. It is not recommended to change this setting. Its main + // purpose is to use as an escape hatch for cheap routers with QoS + // capability but can only classify flows based on port numbers. + // + // It is a range instead of a single port because of the problems with + // failing to reconnect to peers if a previous socket to that peer and + // port is in ``TIME_WAIT`` state. + //outgoing_port, + //num_outgoing_ports, + + // ``peer_tos`` determines the TOS byte set in the IP header of every + // packet sent to peers (including web seeds). The default value for + // this is ``0x0`` (no marking). One potentially useful TOS mark is + // ``0x20``, this represents the *QBone scavenger service*. For more + // details, see QBSS_. + // + // .. _`QBSS`: http://qbone.internet2.edu/qbss/ + //peer_tos, + + // for auto managed torrents, these are the limits they are subject + // to. If there are too many torrents some of the auto managed ones + // will be paused until some slots free up. ``active_downloads`` and + // ``active_seeds`` controls how many active seeding and downloading + // torrents the queuing mechanism allows. The target number of active + // torrents is ``min(active_downloads + active_seeds, active_limit)``. + // ``active_downloads`` and ``active_seeds`` are upper limits on the + // number of downloading torrents and seeding torrents respectively. + // Setting the value to -1 means unlimited. + // + // For example if there are 10 seeding torrents and 10 downloading + // torrents, and ``active_downloads`` is 4 and ``active_seeds`` is 4, + // there will be 4 seeds active and 4 downloading torrents. If the + // settings are ``active_downloads`` = 2 and ``active_seeds`` = 4, + // then there will be 2 downloading torrents and 4 seeding torrents + // active. Torrents that are not auto managed are not counted against + // these limits. + // + // ``active_checking`` is the limit of number of simultaneous checking + // torrents. + // + // ``active_limit`` is a hard limit on the number of active (auto + // managed) torrents. This limit also applies to slow torrents. + // + // ``active_dht_limit`` is the max number of torrents to announce to + // the DHT. By default this is set to 88, which is no more than one + // DHT announce every 10 seconds. + // + // ``active_tracker_limit`` is the max number of torrents to announce + // to their trackers. By default this is 360, which is no more than + // one announce every 5 seconds. + // + // ``active_lsd_limit`` is the max number of torrents to announce to + // the local network over the local service discovery protocol. By + // default this is 80, which is no more than one announce every 5 + // seconds (assuming the default announce interval of 5 minutes). + // + // You can have more torrents *active*, even though they are not + // announced to the DHT, lsd or their tracker. If some peer knows + // about you for any reason and tries to connect, it will still be + // accepted, unless the torrent is paused, which means it won't accept + // any connections. + //active_downloads, + //active_seeds, + //active_checking, + //active_dht_limit, + //active_tracker_limit, + //active_lsd_limit, + //active_limit, + + // ``auto_manage_interval`` is the number of seconds between the + // torrent queue is updated, and rotated. + //auto_manage_interval, + + // this is the limit on the time a torrent has been an active seed + // (specified in seconds) before it is considered having met the seed + // limit criteria. See queuing_. + //seed_time_limit, + + // ``auto_scrape_interval`` is the number of seconds between scrapes + // of queued torrents (auto managed and paused torrents). Auto managed + // torrents that are paused, are scraped regularly in order to keep + // track of their downloader/seed ratio. This ratio is used to + // determine which torrents to seed and which to pause. + // + // ``auto_scrape_min_interval`` is the minimum number of seconds + // between any automatic scrape (regardless of torrent). In case there + // are a large number of paused auto managed torrents, this puts a + // limit on how often a scrape request is sent. + //auto_scrape_interval, + //auto_scrape_min_interval, + + // ``max_peerlist_size`` is the maximum number of peers in the list of + // known peers. These peers are not necessarily connected, so this + // number should be much greater than the maximum number of connected + // peers. Peers are evicted from the cache when the list grows passed + // 90% of this limit, and once the size hits the limit, peers are no + // longer added to the list. If this limit is set to 0, there is no + // limit on how many peers we'll keep in the peer list. + // + // ``max_paused_peerlist_size`` is the max peer list size used for + // torrents that are paused. This default to the same as + // ``max_peerlist_size``, but can be used to save memory for paused + // torrents, since it's not as important for them to keep a large peer + // list. + //max_peerlist_size, + //max_paused_peerlist_size, + + // this is the minimum allowed announce interval for a tracker. This + // is specified in seconds and is used as a sanity check on what is + // returned from a tracker. It mitigates hammering misconfigured + // trackers. + //min_announce_interval, + + // this is the number of seconds a torrent is considered active after + // it was started, regardless of upload and download speed. This is so + // that newly started torrents are not considered inactive until they + // have a fair chance to start downloading. + //auto_manage_startup, + + // ``seeding_piece_quota`` is the number of pieces to send to a peer, + // when seeding, before rotating in another peer to the unchoke set. + // It defaults to 3 pieces, which means that when seeding, any peer + // we've sent more than this number of pieces to will be unchoked in + // favour of a choked peer. + //seeding_piece_quota, + + // TODO: deprecate this + // ``max_rejects`` is the number of piece requests we will reject in a + // row while a peer is choked before the peer is considered abusive + // and is disconnected. + //max_rejects, + + // specifies the buffer sizes set on peer sockets. 0 (which is the + // default) means the OS default (i.e. don't change the buffer sizes). + // The socket buffer sizes are changed using setsockopt() with + // SOL_SOCKET/SO_RCVBUF and SO_SNDBUFFER. + //recv_socket_buffer_size, + //send_socket_buffer_size, + + // the max number of bytes a single peer connection's receive buffer is + // allowed to grow to. + //max_peer_recv_buffer_size, + + // ``read_cache_line_size`` is the number of blocks to read into the + // read cache when a read cache miss occurs. Setting this to 0 is + // essentially the same thing as disabling read cache. The number of + // blocks read into the read cache is always capped by the piece + // boundary. + // + // When a piece in the write cache has ``write_cache_line_size`` + // contiguous blocks in it, they will be flushed. Setting this to 1 + // effectively disables the write cache. + //read_cache_line_size, + //write_cache_line_size, + + // ``optimistic_disk_retry`` is the number of seconds from a disk + // write errors occur on a torrent until libtorrent will take it out + // of the upload mode, to test if the error condition has been fixed. + // + // libtorrent will only do this automatically for auto managed + // torrents. + // + // You can explicitly take a torrent out of upload only mode using + // set_upload_mode(). + //optimistic_disk_retry, + + // ``max_suggest_pieces`` is the max number of suggested piece indices + // received from a peer that's remembered. If a peer floods suggest + // messages, this limit prevents libtorrent from using too much RAM. + // It defaults to 10. + //max_suggest_pieces, + + // ``local_service_announce_interval`` is the time between local + // network announces for a torrent. By default, when local service + // discovery is enabled a torrent announces itself every 5 minutes. + // This interval is specified in seconds. + //local_service_announce_interval, + + // ``dht_announce_interval`` is the number of seconds between + // announcing torrents to the distributed hash table (DHT). + //dht_announce_interval, + + // ``udp_tracker_token_expiry`` is the number of seconds libtorrent + // will keep UDP tracker connection tokens around for. This is + // specified to be 60 seconds, and defaults to that. The higher this + // value is, the fewer packets have to be sent to the UDP tracker. In + // order for higher values to work, the tracker needs to be configured + // to match the expiration time for tokens. + //udp_tracker_token_expiry, + + // ``num_optimistic_unchoke_slots`` is the number of optimistic + // unchoke slots to use. It defaults to 0, which means automatic. + // Having a higher number of optimistic unchoke slots mean you will + // find the good peers faster but with the trade-off to use up more + // bandwidth. When this is set to 0, libtorrent opens up 20% of your + // allowed upload slots as optimistic unchoke slots. + //num_optimistic_unchoke_slots, + + // ``default_est_reciprocation_rate`` is the assumed reciprocation + // rate from peers when using the BitTyrant choker. This defaults to + // 14 kiB/s. If set too high, you will over-estimate your peers and be + // more altruistic while finding the true reciprocation rate, if it's + // set too low, you'll be too stingy and waste finding the true + // reciprocation rate. + // + // ``increase_est_reciprocation_rate`` specifies how many percent the + // estimated reciprocation rate should be increased by each unchoke + // interval a peer is still choking us back. This defaults to 20%. + // This only applies to the BitTyrant choker. + // + // ``decrease_est_reciprocation_rate`` specifies how many percent the + // estimated reciprocation rate should be decreased by each unchoke + // interval a peer unchokes us. This default to 3%. This only applies + // to the BitTyrant choker. + //default_est_reciprocation_rate, + //increase_est_reciprocation_rate, + //decrease_est_reciprocation_rate, + + // the max number of peers we accept from pex messages from a single + // peer. this limits the number of concurrent peers any of our peers + // claims to be connected to. If they claim to be connected to more + // than this, we'll ignore any peer that exceeds this limit + //max_pex_peers, + + // ``tick_interval`` specifies the number of milliseconds between + // internal ticks. This is the frequency with which bandwidth quota is + // distributed to peers. It should not be more than one second (i.e. + // 1000 ms). Setting this to a low value (around 100) means higher + // resolution bandwidth quota distribution, setting it to a higher + // value saves CPU cycles. + //tick_interval, + + // ``share_mode_target`` specifies the target share ratio for share + // mode torrents. This defaults to 3, meaning we'll try to upload 3 + // times as much as we download. Setting this very high, will make it + // very conservative and you might end up not downloading anything + // ever (and not affecting your share ratio). It does not make any + // sense to set this any lower than 2. For instance, if only 3 peers + // need to download the rarest piece, it's impossible to download a + // single piece and upload it more than 3 times. If the + // share_mode_target is set to more than 3, nothing is downloaded. + //share_mode_target, + + // ``upload_rate_limit`` and ``download_rate_limit`` sets + // the session-global limits of upload and download rate limits, in + // bytes per second. By default peers on the local network are not rate + // limited. + // + // A value of 0 means unlimited. + // + // For fine grained control over rate limits, including making them apply + // to local peers, see peer-classes_. + //upload_rate_limit, + //download_rate_limit, + + // ``unchoke_slots_limit`` is the max number of unchoked peers in the + // session. The number of unchoke slots may be ignored depending on + // what ``choking_algorithm`` is set to. + //unchoke_slots_limit, + + // ``connections_limit`` sets a global limit on the number of + // connections opened. The number of connections is set to a hard + // minimum of at least two per torrent, so if you set a too low + // connections limit, and open too many torrents, the limit will not + // be met. + //connections_limit, + + // ``connections_slack`` is the the number of incoming connections + // exceeding the connection limit to accept in order to potentially + // replace existing ones. + //connections_slack, + + // ``utp_target_delay`` is the target delay for uTP sockets in + // milliseconds. A high value will make uTP connections more + // aggressive and cause longer queues in the upload bottleneck. It + // cannot be too low, since the noise in the measurements would cause + // it to send too slow. The default is 50 milliseconds. + // ``utp_gain_factor`` is the number of bytes the uTP congestion + // window can increase at the most in one RTT. This defaults to 300 + // bytes. If this is set too high, the congestion controller reacts + // too hard to noise and will not be stable, if it's set too low, it + // will react slow to congestion and not back off as fast. + // + // ``utp_min_timeout`` is the shortest allowed uTP socket timeout, + // specified in milliseconds. This defaults to 500 milliseconds. The + // timeout depends on the RTT of the connection, but is never smaller + // than this value. A connection times out when every packet in a + // window is lost, or when a packet is lost twice in a row (i.e. the + // resent packet is lost as well). + // + // The shorter the timeout is, the faster the connection will recover + // from this situation, assuming the RTT is low enough. + // ``utp_syn_resends`` is the number of SYN packets that are sent (and + // timed out) before giving up and closing the socket. + // ``utp_num_resends`` is the number of times a packet is sent (and + // lost or timed out) before giving up and closing the connection. + // ``utp_connect_timeout`` is the number of milliseconds of timeout + // for the initial SYN packet for uTP connections. For each timed out + // packet (in a row), the timeout is doubled. ``utp_loss_multiplier`` + // controls how the congestion window is changed when a packet loss is + // experienced. It's specified as a percentage multiplier for + // ``cwnd``. By default it's set to 50 (i.e. cut in half). Do not + // change this value unless you know what you're doing. Never set it + // higher than 100. + //utp_target_delay, + //utp_gain_factor, + //utp_min_timeout, + //utp_syn_resends, + //utp_fin_resends, + //utp_num_resends, + //utp_connect_timeout, + + //utp_loss_multiplier, + + // The ``mixed_mode_algorithm`` determines how to treat TCP + // connections when there are uTP connections. Since uTP is designed + // to yield to TCP, there's an inherent problem when using swarms that + // have both TCP and uTP connections. If nothing is done, uTP + // connections would often be starved out for bandwidth by the TCP + // connections. This mode is ``prefer_tcp``. The ``peer_proportional`` + // mode simply looks at the current throughput and rate limits all TCP + // connections to their proportional share based on how many of the + // connections are TCP. This works best if uTP connections are not + // rate limited by the global rate limiter (which they aren't by + // default). + //mixed_mode_algorithm, + + // ``listen_queue_size`` is the value passed in to listen() for the + // listen socket. It is the number of outstanding incoming connections + // to queue up while we're not actively waiting for a connection to be + // accepted. The default is 5 which should be sufficient for any + // normal client. If this is a high performance server which expects + // to receive a lot of connections, or used in a simulator or test, it + // might make sense to raise this number. It will not take affect + // until the ``listen_interfaces`` settings is updated. + //listen_queue_size, + + // ``torrent_connect_boost`` is the number of peers to try to connect + // to immediately when the first tracker response is received for a + // torrent. This is a boost to given to new torrents to accelerate + // them starting up. The normal connect scheduler is run once every + // second, this allows peers to be connected immediately instead of + // waiting for the session tick to trigger connections. + // This may not be set higher than 255. + //torrent_connect_boost, + + // ``alert_queue_size`` is the maximum number of alerts queued up + // internally. If alerts are not popped, the queue will eventually + // fill up to this level. Once the alert queue is full, additional + // alerts will be dropped, and not delievered to the client. Once the + // client drains the queue, new alerts may be delivered again. In order + // to know that alerts have been dropped, see + // session_handle::dropped_alerts(). + //alert_queue_size, + + // ``max_metadata_size`` is the maximum allowed size (in bytes) to be + // received by the metadata extension, i.e. magnet links. + //max_metadata_size, + + // the number of blocks to keep outstanding at any given time when + // checking torrents. Higher numbers give faster re-checks but uses + // more memory. Specified in number of 16 kiB blocks + //checking_mem_usage, + + // if set to > 0, pieces will be announced to other peers before they + // are fully downloaded (and before they are hash checked). The + // intention is to gain 1.5 potential round trip times per downloaded + // piece. When non-zero, this indicates how many milliseconds in + // advance pieces should be announced, before they are expected to be + // completed. + //predictive_piece_announce, + + // for some aio back-ends, ``aio_threads`` specifies the number of + // io-threads to use, and ``aio_max`` the max number of outstanding + // jobs. + //aio_threads, + //aio_max, + + // ``tracker_backoff`` determines how aggressively to back off from + // retrying failing trackers. This value determines *x* in the + // following formula, determining the number of seconds to wait until + // the next retry: + // + // delay = 5 + 5 * x / 100 * fails^2 + // + // This setting may be useful to make libtorrent more or less + // aggressive in hitting trackers. + //tracker_backoff, + + // when a seeding torrent reaches either the share ratio (bytes up / + // bytes down) or the seed time ratio (seconds as seed / seconds as + // downloader) or the seed time limit (seconds as seed) it is + // considered done, and it will leave room for other torrents. These + // are specified as percentages. Torrents that are considered done will + // still be allowed to be seeded, they just won't have priority anymore. + // For more, see queuing_. + //share_ratio_limit, + //seed_time_ratio_limit, + + // peer_turnover is the percentage of peers to disconnect every + // turnover peer_turnover_interval (if we're at the peer limit), this + // is specified in percent when we are connected to more than limit * + // peer_turnover_cutoff peers disconnect peer_turnover fraction of the + // peers. It is specified in percent peer_turnover_interval is the + // interval (in seconds) between optimistic disconnects if the + // disconnects happen and how many peers are disconnected is + // controlled by peer_turnover and peer_turnover_cutoff + //peer_turnover, + //peer_turnover_cutoff, + //peer_turnover_interval, + + // this setting controls the priority of downloading torrents over + // seeding or finished torrents when it comes to making peer + // connections. Peer connections are throttled by the connection_speed + // and the half-open connection limit. This makes peer connections a + // limited resource. Torrents that still have pieces to download are + // prioritized by default, to avoid having many seeding torrents use + // most of the connection attempts and only give one peer every now + // and then to the downloading torrent. libtorrent will loop over the + // downloading torrents to connect a peer each, and every n:th + // connection attempt, a finished torrent is picked to be allowed to + // connect to a peer. This setting controls n. + //connect_seed_every_n_download, + + // the max number of bytes to allow an HTTP response to be when + // announcing to trackers or downloading .torrent files via the + // ``url`` provided in ``add_torrent_params``. + //max_http_recv_buffer_size, + + // if binding to a specific port fails, should the port be incremented + // by one and tried again? This setting specifies how many times to + // retry a failed port bind + //max_retry_port_bind, + + // a bitmask combining flags from alert::category_t defining which + // kinds of alerts to receive + //alert_mask, + + // control the settings for incoming and outgoing connections + // respectively. see enc_policy enum for the available options. + // Keep in mind that protocol encryption degrades performance in + // several respects: + // + // 1. It prevents "zero copy" disk buffers being sent to peers, since + // each peer needs to mutate the data (i.e. encrypt it) the data + // must be copied per peer connection rather than sending the same + // buffer to multiple peers. + // 2. The encryption itself requires more CPU than plain bittorrent + // protocol. The highest cost is the Diffie Hellman exchange on + // connection setup. + // 3. The encryption handshake adds several round-trips to the + // connection setup, and delays transferring data. + //out_enc_policy, + //in_enc_policy, + + // determines the encryption level of the connections. This setting + // will adjust which encryption scheme is offered to the other peer, + // as well as which encryption scheme is selected by the client. See + // enc_level enum for options. + //allowed_enc_level, + + // the download and upload rate limits for a torrent to be considered + // active by the queuing mechanism. A torrent whose download rate is + // less than ``inactive_down_rate`` and whose upload rate is less than + // ``inactive_up_rate`` for ``auto_manage_startup`` seconds, is + // considered inactive, and another queued torrent may be started. + // This logic is disabled if ``dont_count_slow_torrents`` is false. + //inactive_down_rate, + //inactive_up_rate, + + // proxy to use, defaults to none. see proxy_type_t. + //proxy_type, + + // the port of the proxy server + //proxy_port, + + // sets the i2p_ SAM bridge port to connect to. set the hostname with + // the ``i2p_hostname`` setting. + // + // .. _i2p: http://www.i2p2.de + //i2p_port, + + // this determines the max number of volatile disk cache blocks. If the + // number of volatile blocks exceed this limit, other volatile blocks + // will start to be evicted. A disk cache block is volatile if it has + // low priority, and should be one of the first blocks to be evicted + // under pressure. For instance, blocks pulled into the cache as the + // result of calculating a piece hash are volatile. These blocks don't + // represent potential interest among peers, so the value of keeping + // them in the cache is limited. + //cache_size_volatile, + + // The maximum request range of an url seed in bytes. This value + // defines the largest possible sequential web seed request. Default + // is 16 * 1024 * 1024. Lower values are possible but will be ignored + // if they are lower then piece size. + // This value should be related to your download speed to prevent + // libtorrent from creating too many expensive http requests per + // second. You can select a value as high as you want but keep in mind + // that libtorrent can't create parallel requests if the first request + // did already select the whole file. + // If you combine bittorrent seeds with web seeds and pick strategies + // like rarest first you may find your web seed requests split into + // smaller parts because we don't download already picked pieces + // twice. + //urlseed_max_request_bytes, + + // time to wait until a new retry of a web seed name lookup + //web_seed_name_lookup_retry, + + // the number of seconds between closing the file opened the longest + // ago. 0 means to disable the feature. The purpose of this is to + // periodically close files to trigger the operating system flushing + // disk cache. Specifically it has been observed to be required on + // windows to not have the disk cache grow indefinitely. + // This defaults to 120 seconds on windows, and disabled on other + // systems. + //close_file_interval, + + // the max number of web seeds to have connected per torrent at any + // given time. + //max_web_seed_connections, + + // the number of seconds before the internal host name resolver + // considers a cache value timed out, negative values are interpreted + // as zero. + //resolver_cache_timeout, + + settings.set_str(settings_pack::user_agent, "Dynamic"); //todo: add version to user agent + + // this is the client name and version identifier sent to peers in the + // handshake message. If this is an empty string, the user_agent is + // used instead + //settings.set_str(settings_pack:handshake_client_version, "Dynamic"); //todo: add version to user agent + + // sets the network interface this session will use when it opens + // outgoing connections. By default, it binds outgoing connections to + // INADDR_ANY and port 0 (i.e. let the OS decide). Ths parameter must + // be a string containing one or more, comma separated, adapter names. + // Adapter names on unix systems are of the form "eth0", "eth1", + // "tun0", etc. When specifying multiple interfaces, they will be + // assigned in round-robin order. This may be useful for clients that + // are multi-homed. Binding an outgoing connection to a local IP does + // not necessarily make the connection via the associated NIC/Adapter. + // Setting this to an empty string will disable binding of outgoing + // connections. + settings.set_bool(settings_pack::outgoing_interfaces, false); + // a comma-separated list of (IP or device name, port) pairs. These are + // the listen ports that will be opened for accepting incoming uTP and + // TCP connections. It is possible to listen on multiple interfaces and + // multiple ports. Binding to port 0 will make the operating system + // pick the port. The default is "0.0.0.0:6881,[::]:6881", which binds + // to all interfaces on port 6881. + // + // a port that has an "s" suffix will accept SSL connections. (note + // that SSL sockets are not enabled by default). + // + // if binding fails, the listen_failed_alert is posted. If or once a + // socket binding succeeds, the listen_succeeded_alert is posted. There + // may be multiple failures before a success. + // + // For example: + // ``[::1]:8888`` - will only accept connections on the IPv6 loopback + // address on port 8888. + // + // ``eth0:4444,eth1:4444`` - will accept connections on port 4444 on + // any IP address bound to device ``eth0`` or ``eth1``. + // + // ``[::]:0s`` - will accept SSL connections on a port chosen by the + // OS. And not accept non-SSL connections at all. + // + // Windows OS network adapter device name can be specified with GUID. + // It can be obtained from "netsh lan show interfaces" command output. + // GUID must be uppercased string embraced in curly brackets. + // ``{E4F0B674-0DFC-48BB-98A5-2AA730BDB6D6}::7777`` - will accept + // connections on port 7777 on adapter with this GUID. + //listen_interfaces, + // when using a poxy, this is the hostname where the proxy is running + // see proxy_type. + //proxy_hostname, + + // when using a proxy, these are the credentials (if any) to use when + // connecting to it. see proxy_type + //proxy_username, + //proxy_password, + + // sets the i2p_ SAM bridge to connect to. set the port with the + // ``i2p_port`` setting. + // + // .. _i2p: http://www.i2p2.de + //i2p_hostname, + + // this is the fingerprint for the client. It will be used as the + // prefix to the peer_id. If this is 20 bytes (or longer) it will be + // truncated to 20 bytes and used as the entire peer-id + // + // There is a utility function, generate_fingerprint() that can be used + // to generate a standard client peer ID fingerprint prefix. + //peer_fingerprint, + + // This is a comma-separated list of IP port-pairs. They will be added + // to the DHT node (if it's enabled) as back-up nodes in case we don't + // know of any. This setting will contain one or more bootstrap nodes + // by default. + // + // Changing these after the DHT has been started may not have any + // effect until the DHT is restarted. + //dht_bootstrap_nodes, + + //max_string_setting_internal + + newSession.apply_settings(settings); +} + diff --git a/src/dht/dhtsettings.h b/src/dht/dhtsettings.h new file mode 100644 index 0000000000..19631e0ede --- /dev/null +++ b/src/dht/dhtsettings.h @@ -0,0 +1,27 @@ + +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_DHT_DHTSETTINGS_H +#define DYNAMIC_DHT_DHTSETTINGS_H + +#include + +class CDHTSettings { +private: + + libtorrent::settings_pack settings; + +public: + + CDHTSettings(); + + libtorrent::settings_pack GetSettingsPack() const; + +private: + + void LoadSettings(); +}; + + +#endif // DYNAMIC_DHT_DHTSETTINGS_H diff --git a/src/dht/keyed25519.h b/src/dht/keyed25519.h index 7bc0b2c2a7..b91648dc76 100644 --- a/src/dht/keyed25519.h +++ b/src/dht/keyed25519.h @@ -1,8 +1,8 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#ifndef DYNAMIC_BDAP_KEYED25519_H -#define DYNAMIC_BDAP_KEYED25519_H +#ifndef DYNAMIC_DHT_KEYED25519_H +#define DYNAMIC_DHT_KEYED25519_H #include "support/allocators/secure.h" @@ -203,4 +203,4 @@ bool ECC_Ed25519_InitSanityCheck(); void ECC_Ed25519_Start(); void ECC_Ed25519_Stop(); -#endif // DYNAMIC_BDAP_KEYED25519_H \ No newline at end of file +#endif // DYNAMIC_DHT_KEYED25519_H \ No newline at end of file From f87b4ef2bd8739eec53e59429272062645d77a59 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 21 Sep 2018 00:17:05 -0500 Subject: [PATCH 0226/1653] Avoid segfault when processing a block header message --- src/net_processing.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a69613850e..ecfe627e54 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1878,7 +1878,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return error("invalid header received"); } } - + if (!pindexLast) { + LogPrintf("*** ProcessMessage Error -- ProcessNewBlockHeaders returned an invalid pindexLast. Avoid assert(pindexLast);\n"); + return error("ProcessNewBlockHeaders returned an invalid pindexLast."); + } { LOCK(cs_main); CNodeState *nodestate = State(pfrom->GetId()); From 48dd69b67fb8d3adb10e3135b0d6067deab04ff4 Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Sat, 22 Sep 2018 12:33:11 +0200 Subject: [PATCH 0227/1653] Fix styling of PrivateSend option on sendcoinsdialog.ui --- src/qt/res/css/drk.css | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/qt/res/css/drk.css b/src/qt/res/css/drk.css index 942889a661..efae433dc8 100644 --- a/src/qt/res/css/drk.css +++ b/src/qt/res/css/drk.css @@ -978,7 +978,7 @@ margin-right:5px; padding-right:5px; } -QWidget .QFrame#framePrivateSend #formLayoutWidget .QLabel#privatesendEnabled { /* PrivateSend Status */ +QWidget .QFrame#framePrivateSend #formLayoutWidget .QLabel#PrivateSendEnabled { /* PrivateSend Status */ } @@ -991,7 +991,7 @@ padding-right:5px; } -QWidget .QFrame#framePrivateSend #formLayoutWidget .QProgressBar#privatesendProgress { /* PrivateSend Completion */ +QWidget .QFrame#framePrivateSend #formLayoutWidget .QProgressBar#PrivateSendProgress { /* PrivateSend Completion */ border: 1px solid #520072; border-radius: 1px; margin-right:43px; @@ -999,7 +999,7 @@ text-align: right; color:#818181; } -QWidget .QFrame#framePrivateSend #formLayoutWidget .QProgressBar#privatesendProgress::chunk { +QWidget .QFrame#framePrivateSend #formLayoutWidget .QProgressBar#PrivateSendProgress::chunk { background-color: #520072; width:1px; } @@ -1040,7 +1040,7 @@ QWidget .QFrame#framePrivateSend #formLayoutWidget .QLabel#labelSubmittedDenom { } -QWidget .QFrame#framePrivateSend .QLabel#privatesendStatus { /* PrivateSend Status Notifications */ +QWidget .QFrame#framePrivateSend .QLabel#PrivateSendStatus { /* PrivateSend Status Notifications */ qproperty-alignment: 'AlignVCenter | AlignCenter'; qproperty-geometry: rect(70 226 395 34); font-size:11px; @@ -1077,7 +1077,7 @@ QWidget .QFrame#framePrivateSend .QPushButton#togglePrivateSend:hover { } -QWidget .QFrame#framePrivateSend .QPushButton#privatesendAuto { /* Try Mix Button */ +QWidget .QFrame#framePrivateSend .QPushButton#PrivateSendAuto { /* Try Mix Button */ qproperty-geometry: rect(120 314 140 25); background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #f6f6f6, stop: .1 rgba(250, 250, 250, 128), stop: .95 rgba(250, 250, 250, 255), stop: 1 #ebebeb); border:1px solid #d2d2d2; @@ -1087,17 +1087,17 @@ font-size:9px; padding:0px; } -QWidget .QFrame#framePrivateSend .QPushButton#privatesendAuto:hover { +QWidget .QFrame#framePrivateSend .QPushButton#PrivateSendAuto:hover { background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #f6f6f6, stop: .1 rgba(240, 240, 240, 255), stop: .95 rgba(240, 240, 240, 255), stop: 1 #ebebeb); color:#333; } -QWidget .QFrame#framePrivateSend .QPushButton#privatesendAuto:pressed { +QWidget .QFrame#framePrivateSend .QPushButton#PrivateSendAuto:pressed { background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #f6f6f6, stop: .1 rgba(250, 250, 250, 128), stop: .95 rgba(250, 250, 250, 255), stop: 1 #ebebeb); border:1px solid #d2d2d2; } -QWidget .QFrame#framePrivateSend .QPushButton#privatesendReset { /* Reset Button */ +QWidget .QFrame#framePrivateSend .QPushButton#PrivateSendReset { /* Reset Button */ qproperty-geometry: rect(265 314 140 25); background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #f6f6f6, stop: .1 rgba(250, 250, 250, 128), stop: .95 rgba(250, 250, 250, 255), stop: 1 #ebebeb); border:1px solid #d2d2d2; @@ -1107,12 +1107,12 @@ font-size:9px; padding:0px; } -QWidget .QFrame#framePrivateSend .QPushButton#privatesendReset:hover { +QWidget .QFrame#framePrivateSend .QPushButton#PrivateSendReset:hover { background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #f6f6f6, stop: .1 rgba(240, 240, 240, 255), stop: .95 rgba(240, 240, 240, 255), stop: 1 #ebebeb); color:#333; } -QWidget .QFrame#framePrivateSend .QPushButton#privatesendReset:pressed { +QWidget .QFrame#framePrivateSend .QPushButton#PrivateSendReset:pressed { background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: .01 #f6f6f6, stop: .1 rgba(250, 250, 250, 128), stop: .95 rgba(250, 250, 250, 255), stop: 1 #ebebeb); border:1px solid #d2d2d2; } @@ -1242,18 +1242,17 @@ border:1px solid #d2d2d2; } QDialog#SendCoinsDialog .QCheckBox#checkUsePrivateSend { /* PrivateSend Checkbox */ -color:#000000; -font-weight:bold; -background: #FFFFFF; +color:#FFFFFF; +background: #000000; border-radius:5px; padding-top:20px; padding-bottom:18px; +margin-left:10px; } QDialog#SendCoinsDialog .QCheckBox#checkInstantSend { /* InstantSend Checkbox */ -color:#000000; -font-weight:bold; -background: #FFFFFF; +color:#FFFFFF; +background: #000000; border-radius:5px; padding-top:20px; padding-bottom:18px; @@ -2013,4 +2012,3 @@ padding-right:25px; padding-top:5px; padding-bottom:5px; } - From 73ba79a44378875d90ec31276910bc42d95e235b Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Sat, 22 Sep 2018 12:45:38 +0200 Subject: [PATCH 0228/1653] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b488019cd1..2c18d84c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ **Dynamic v2.4.0.0** +* [Qt] Fix styling of PrivateSend option on sendcoinsdialog.ui * Increase Min Peer Protocol Version to 70900(v2.3) for Peers/DynodePayments/InstantSend/PrivateSend * [GPU] Fix GPU found block nonce before ProcessFoundSolution * [GPU] Update README for GPU Mining From b52d40d74d024f40cc416cdb3e058c820b95aa7f Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Sat, 22 Sep 2018 13:05:56 +0200 Subject: [PATCH 0229/1653] Fix for Issue #193 mining with long-poll enabled crash the wallet --- src/rpcmining.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 7aa705f3de..0223a3b465 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -718,10 +718,6 @@ UniValue getblocktemplate(const JSONRPCRequest& request) } // Release the wallet and main lock while waiting -#ifdef ENABLE_WALLET - if(pwalletMain) - LEAVE_CRITICAL_SECTION(pwalletMain->cs_wallet); -#endif LEAVE_CRITICAL_SECTION(cs_main); { checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); @@ -739,10 +735,6 @@ UniValue getblocktemplate(const JSONRPCRequest& request) } } ENTER_CRITICAL_SECTION(cs_main); -#ifdef ENABLE_WALLET - if(pwalletMain) - ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet); -#endif if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); From dcea084b174b0e1548ea40bd9ae17367499fcd3d Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sat, 22 Sep 2018 06:29:30 -0500 Subject: [PATCH 0230/1653] [DHT] Add bootstrap nodes, user agent and listen interface to settings --- src/dht/dhtsettings.cpp | 2498 ++++++++++++++++++++------------------- src/dht/dhtsettings.h | 9 +- 2 files changed, 1280 insertions(+), 1227 deletions(-) diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp index 898ff524d6..17d8084fdf 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/dhtsettings.cpp @@ -3,1240 +3,1288 @@ #include "dht/dhtsettings.h" +#include "clientversion.h" +#include "dynode.h" +#include "dynodeman.h" +#include "net.h" +#include "primitives/transaction.h" + using namespace libtorrent; CDHTSettings::CDHTSettings() { - LoadSettings(); + user_agent = "Dynamic v" + FormatFullVersion(); + // Use ports 33307, 33317, 33327, 33337 and 33347 + listen_interfaces = "0.0.0.0:33307,[::]:33307,0.0.0.0:33317,[::]:33317,0.0.0.0:33327," + "[::]:33327,0.0.0.0:33337,[::]:33337,0.0.0.0:33347,[::]:33347"; + LoadPeerList(); + LoadSettings(); } -void CDHTSettings::LoadSettings() +void CDHTSettings::LoadPeerList() { + std::string strPeerList; + // get all Dynodes above the minimum protocol version + std::map mapDynodes = dnodeman.GetFullDynodeMap(); + for (auto& dnpair : mapDynodes) { + CDynode dn = dnpair.second; + if (dn.nProtocolVersion >= MIN_DHT_PROTO_VERSION) { + strPeerList += dn.addr.ToString() + ","; + } + } + // get all peers above the minimum protocol version + if(g_connman) { + std::vector vstats; + g_connman->GetNodeStats(vstats); + for (const CNodeStats& stats : vstats) { + if (stats.nVersion >= MIN_DHT_PROTO_VERSION) { + strPeerList += stats.addrName + ","; + } + } + } + dht_bootstrap_nodes = strPeerList.substr(0, strPeerList.size()-1); +} - settings.set_bool(settings_pack::enable_dht, false); - settings.set_int(settings_pack::alert_mask, 0xffffffff); - session newSession(settings); - - // Dynamic LibTorrent Settings - - // ``enable_dht`` starts the dht node and makes the trackerless service available to - // torrents. - settings.set_bool(settings_pack::enable_dht, true); - - // ``announce_ip`` is the ip address passed along to trackers as the - // ``&ip=`` parameter. If left as the default, that parameter is - // omitted. - settings.set_bool(settings_pack::announce_ip, false); - - // ``allow_multiple_connections_per_ip`` determines if connections from the same IP address as existing - // connections should be rejected or not. Multiple connections from - // the same IP address is not allowed by default, to prevent abusive - // behavior by peers. It may be useful to allow such connections in - // cases where simulations are run on the same machine, and all peers - // in a swarm has the same IP address. - // allow_multiple_connections_per_ip - settings.set_bool(settings_pack::allow_multiple_connections_per_ip, true); - - // ``send_redundant_have`` controls if have messages will be sent to - // peers that already have the piece. This is typically not necessary, - // but it might be necessary for collecting statistics in some cases. - settings.set_bool(settings_pack::send_redundant_have, true); - - // ``use_dht_as_fallback`` determines how the DHT is used. If this is - // true, the DHT will only be used for torrents where all trackers in - // its tracker list has failed. Either by an explicit error message or - // a time out. This is false by default, which means the DHT is used - // by default regardless of if the trackers fail or not. - settings.set_bool(settings_pack::use_dht_as_fallback, false); - - // ``upnp_ignore_nonrouters`` indicates whether or not the UPnP - // implementation should ignore any broadcast response from a device - // whose address is not the configured router for this machine. i.e. - // it's a way to not talk to other people's routers by mistake. - settings.set_bool(settings_pack::upnp_ignore_nonrouters, true); - - // ``use_parole_mode`` specifies if parole mode should be used. Parole - // mode means that peers that participate in pieces that fail the hash - // check are put in a mode where they are only allowed to download - // whole pieces. If the whole piece a peer in parole mode fails the - // hash check, it is banned. If a peer participates in a piece that - // passes the hash check, it is taken out of parole mode. - settings.set_bool(settings_pack::use_parole_mode, true); - - // ``use_read_cache`` enable and disable caching of blocks read from disk. the purpose of - // the read cache is partly read-ahead of requests but also to avoid - // reading blocks back from the disk multiple times for popular - // pieces. - settings.set_bool(settings_pack::use_read_cache, true); - - // ``coalesce_reads`` ``coalesce_writes`` - // allocate separate, contiguous, buffers for read and write calls. - // Only used where writev/readv cannot be used will use more RAM but - // may improve performance - //settings.set_bool(settings_pack::coalesce_reads, false); - //settings.set_bool(settings_pack::coalesce_writes, false); - - // ``auto_manage_prefer_seeds`` - // prefer seeding torrents when determining which torrents to give - // active slots to, the default is false which gives preference to - // downloading torrents - settings.set_bool(settings_pack::auto_manage_prefer_seeds, false); - - // if ``dont_count_slow_torrents`` is true, torrents without any - // payload transfers are not subject to the ``active_seeds`` and - // ``active_downloads`` limits. This is intended to make it more - // likely to utilize all available bandwidth, and avoid having - // torrents that don't transfer anything block the active slots. - //settings.set_bool(settings_pack::dont_count_slow_torrents, false); - - // ``close_redundant_connections`` specifies whether libtorrent should - // close connections where both ends have no utility in keeping the - // connection open. For instance if both ends have completed their - // downloads, there's no point in keeping it open. - - settings.set_bool(settings_pack::close_redundant_connections, false); - // If ``prioritize_partial_pieces`` is true, partial pieces are picked - // before pieces that are more rare. If false, rare pieces are always - // prioritized, unless the number of partial pieces is growing out of - // proportion. - - settings.set_bool(settings_pack::prioritize_partial_pieces, false); - // if ``rate_limit_ip_overhead`` set to true, the estimated TCP/IP overhead is drained from the - // rate limiters, to avoid exceeding the limits with the total traffic - //settings.set_bool(settings_pack::rate_limit_ip_overhead, true); - - // ``announce_to_all_trackers`` controls how multi tracker torrents - // are treated. If this is set to true, all trackers in the same tier - // are announced to in parallel. If all trackers in tier 0 fails, all - // trackers in tier 1 are announced as well. If it's set to false, the - // behavior is as defined by the multi tracker specification. It - // defaults to false, which is the same behavior previous versions of - // libtorrent has had as well. - settings.set_bool(settings_pack::announce_to_all_trackers, true); - - // ``announce_to_all_tiers`` also controls how multi tracker torrents - // are treated. When this is set to true, one tracker from each tier - // is announced to. This is the uTorrent behavior. This is false by - // default in order to comply with the multi-tracker specification. - settings.set_bool(settings_pack::announce_to_all_tiers, true); - - // ``prefer_udp_trackers`` is true by default. It means that trackers - // may be rearranged in a way that udp trackers are always tried - // before http trackers for the same hostname. Setting this to false - // means that the trackers' tier is respected and there's no - // preference of one protocol over another. - settings.set_bool(settings_pack::prefer_udp_trackers, true); - - // ``strict_super_seeding`` when this is set to true, a piece has to - // have been forwarded to a third peer before another one is handed - // out. This is the traditional definition of super seeding. - settings.set_bool(settings_pack::strict_super_seeding, true); - - // ``disable_hash_checks`` when set to true, all data downloaded from peers will be assumed to - // be correct, and not tested to match the hashes in the torrent this - // is only useful for simulation and testing purposes (typically - // combined with disabled_storage) - settings.set_bool(settings_pack::disable_hash_checks, false); - - // ``allow_i2p_mixed`` if this is true, i2p torrents are allowed to also get peers from - // other sources than the tracker, and connect to regular IPs, not - // providing any anonymization. This may be useful if the user is not - // interested in the anonymization of i2p, but still wants to be able - // to connect to i2p peers. - settings.set_bool(settings_pack::allow_i2p_mixed, true); - - // ``volatile_read_cache``, if this is set to true, read cache blocks - // that are hit by peer read requests are removed from the disk cache - // to free up more space. This is useful if you don't expect the disk - // cache to create any cache hits from other peers than the one who - // triggered the cache line to be read into the cache in the first - // place. - //settings.set_bool(settings_pack::volatile_read_cache, true); +void CDHTSettings::LoadSettings() +{ + settings.set_bool(settings_pack::enable_dht, false); + settings.set_int(settings_pack::alert_mask, 0xffffffff); + session newSession(settings); + + // Dynamic LibTorrent Settings + + // ``enable_dht`` + // starts the dht node and makes the trackerless service + // available to torrents. + settings.set_bool(settings_pack::enable_dht, true); + + // ``user_agent`` + // this is the client identification to the tracker. The recommended + // format of this string is: "ClientName/ClientVersion + // libtorrent/libtorrentVersion". This name will not only be used when + // making HTTP requests, but also when sending extended headers to + // peers that support that extension. It may not contain \r or \n + settings.set_str(settings_pack::user_agent, user_agent); + + // ``dht_bootstrap_nodes`` + // This is a comma-separated list of IP port-pairs. They will be added + // to the DHT node (if it's enabled) as back-up nodes in case we don't + // know of any. This setting will contain one or more bootstrap nodes + // by default. + // Changing these after the DHT has been started may not have any + // effect until the DHT is restarted. + settings.set_str(settings_pack::dht_bootstrap_nodes, dht_bootstrap_nodes); + + // ``listen_interfaces`` + // a comma-separated list of (IP or device name, port) pairs. These are + // the listen ports that will be opened for accepting incoming uTP and + // TCP connections. It is possible to listen on multiple interfaces and + // multiple ports. Binding to port 0 will make the operating system + // pick the port. The default is "0.0.0.0:6881,[::]:6881", which binds + // to all interfaces on port 6881. + // + // a port that has an "s" suffix will accept SSL connections. (note + // that SSL sockets are not enabled by default). + // + // if binding fails, the listen_failed_alert is posted. If or once a + // socket binding succeeds, the listen_succeeded_alert is posted. There + // may be multiple failures before a success. + // + // For example: + // ``[::1]:8888`` - will only accept connections on the IPv6 loopback + // address on port 8888. + // + // ``eth0:4444,eth1:4444`` - will accept connections on port 4444 on + // any IP address bound to device ``eth0`` or ``eth1``. + // + // ``[::]:0s`` - will accept SSL connections on a port chosen by the + // OS. And not accept non-SSL connections at all. + // + // Windows OS network adapter device name can be specified with GUID. + // It can be obtained from "netsh lan show interfaces" command output. + // GUID must be uppercased string embraced in curly brackets. + // ``{E4F0B674-0DFC-48BB-98A5-2AA730BDB6D6}::7777`` - will accept + // connections on port 7777 on adapter with this GUID. + // TODO: Add peers and dynodes to the dht_bootstrap_nodes list. + settings.set_str(settings_pack::listen_interfaces, listen_interfaces); + + // Apply settings. + newSession.apply_settings(settings); + + // TODO: (DHT) Evaluate and test the rest of these settings. + + // ``announce_ip`` is the ip address passed along to trackers as the + // ``&ip=`` parameter. If left as the default, that parameter is + // omitted. + //settings.set_bool(settings_pack::announce_ip, false); + + // ``allow_multiple_connections_per_ip`` determines if connections from the same IP address as existing + // connections should be rejected or not. Multiple connections from + // the same IP address is not allowed by default, to prevent abusive + // behavior by peers. It may be useful to allow such connections in + // cases where simulations are run on the same machine, and all peers + // in a swarm has the same IP address. + // allow_multiple_connections_per_ip + //settings.set_bool(settings_pack::allow_multiple_connections_per_ip, true); + + // ``send_redundant_have`` controls if have messages will be sent to + // peers that already have the piece. This is typically not necessary, + // but it might be necessary for collecting statistics in some cases. + //settings.set_bool(settings_pack::send_redundant_have, true); + + // ``use_dht_as_fallback`` determines how the DHT is used. If this is + // true, the DHT will only be used for torrents where all trackers in + // its tracker list has failed. Either by an explicit error message or + // a time out. This is false by default, which means the DHT is used + // by default regardless of if the trackers fail or not. + //settings.set_bool(settings_pack::use_dht_as_fallback, false); + + // ``upnp_ignore_nonrouters`` indicates whether or not the UPnP + // implementation should ignore any broadcast response from a device + // whose address is not the configured router for this machine. i.e. + // it's a way to not talk to other people's routers by mistake. + //settings.set_bool(settings_pack::upnp_ignore_nonrouters, true); + + // ``use_parole_mode`` specifies if parole mode should be used. Parole + // mode means that peers that participate in pieces that fail the hash + // check are put in a mode where they are only allowed to download + // whole pieces. If the whole piece a peer in parole mode fails the + // hash check, it is banned. If a peer participates in a piece that + // passes the hash check, it is taken out of parole mode. + //settings.set_bool(settings_pack::use_parole_mode, true); + + // ``use_read_cache`` enable and disable caching of blocks read from disk. the purpose of + // the read cache is partly read-ahead of requests but also to avoid + // reading blocks back from the disk multiple times for popular + // pieces. + //settings.set_bool(settings_pack::use_read_cache, true); + + // ``coalesce_reads`` ``coalesce_writes`` + // allocate separate, contiguous, buffers for read and write calls. + // Only used where writev/readv cannot be used will use more RAM but + // may improve performance + //settings.set_bool(settings_pack::coalesce_reads, false); + //settings.set_bool(settings_pack::coalesce_writes, false); + + // ``auto_manage_prefer_seeds`` + // prefer seeding torrents when determining which torrents to give + // active slots to, the default is false which gives preference to + // downloading torrents + //settings.set_bool(settings_pack::auto_manage_prefer_seeds, false); + + // if ``dont_count_slow_torrents`` is true, torrents without any + // payload transfers are not subject to the ``active_seeds`` and + // ``active_downloads`` limits. This is intended to make it more + // likely to utilize all available bandwidth, and avoid having + // torrents that don't transfer anything block the active slots. + //settings.set_bool(settings_pack::dont_count_slow_torrents, false); + + // ``close_redundant_connections`` specifies whether libtorrent should + // close connections where both ends have no utility in keeping the + // connection open. For instance if both ends have completed their + // downloads, there's no point in keeping it open. + //settings.set_bool(settings_pack::close_redundant_connections, false); + + // If ``prioritize_partial_pieces`` is true, partial pieces are picked + // before pieces that are more rare. If false, rare pieces are always + // prioritized, unless the number of partial pieces is growing out of + // proportion. + //settings.set_bool(settings_pack::prioritize_partial_pieces, false); + + // if ``rate_limit_ip_overhead`` set to true, the estimated TCP/IP overhead is drained from the + // rate limiters, to avoid exceeding the limits with the total traffic + //settings.set_bool(settings_pack::rate_limit_ip_overhead, true); + + // ``announce_to_all_trackers`` controls how multi tracker torrents + // are treated. If this is set to true, all trackers in the same tier + // are announced to in parallel. If all trackers in tier 0 fails, all + // trackers in tier 1 are announced as well. If it's set to false, the + // behavior is as defined by the multi tracker specification. It + // defaults to false, which is the same behavior previous versions of + // libtorrent has had as well. + //settings.set_bool(settings_pack::announce_to_all_trackers, true); + + // ``announce_to_all_tiers`` also controls how multi tracker torrents + // are treated. When this is set to true, one tracker from each tier + // is announced to. This is the uTorrent behavior. This is false by + // default in order to comply with the multi-tracker specification. + //settings.set_bool(settings_pack::announce_to_all_tiers, true); + + // ``prefer_udp_trackers`` is true by default. It means that trackers + // may be rearranged in a way that udp trackers are always tried + // before http trackers for the same hostname. Setting this to false + // means that the trackers' tier is respected and there's no + // preference of one protocol over another. + //settings.set_bool(settings_pack::prefer_udp_trackers, true); + + // ``strict_super_seeding`` when this is set to true, a piece has to + // have been forwarded to a third peer before another one is handed + // out. This is the traditional definition of super seeding. + //settings.set_bool(settings_pack::strict_super_seeding, true); + + // ``disable_hash_checks`` when set to true, all data downloaded from peers will be assumed to + // be correct, and not tested to match the hashes in the torrent this + // is only useful for simulation and testing purposes (typically + // combined with disabled_storage) + //settings.set_bool(settings_pack::disable_hash_checks, false); + + // ``allow_i2p_mixed`` if this is true, i2p torrents are allowed to also get peers from + // other sources than the tracker, and connect to regular IPs, not + // providing any anonymization. This may be useful if the user is not + // interested in the anonymization of i2p, but still wants to be able + // to connect to i2p peers. + //settings.set_bool(settings_pack::allow_i2p_mixed, true); + + // ``volatile_read_cache``, if this is set to true, read cache blocks + // that are hit by peer read requests are removed from the disk cache + // to free up more space. This is useful if you don't expect the disk + // cache to create any cache hits from other peers than the one who + // triggered the cache line to be read into the cache in the first + // place. + //settings.set_bool(settings_pack::volatile_read_cache, true); #ifndef WIN32 - // ``no_atime_storage`` this is a linux-only option and passes in the - // ``O_NOATIME`` to ``open()`` when opening files. This may lead to - // some disk performance improvements. - settings.set_bool(settings_pack::no_atime_storage, true); + // ``no_atime_storage`` this is a linux-only option and passes in the + // ``O_NOATIME`` to ``open()`` when opening files. This may lead to + // some disk performance improvements. + //settings.set_bool(settings_pack::no_atime_storage, true); #endif - // ``incoming_starts_queued_torrents`` defaults to false. If a torrent - // has been paused by the auto managed feature in libtorrent, i.e. the - // torrent is paused and auto managed, this feature affects whether or - // not it is automatically started on an incoming connection. The main - // reason to queue torrents, is not to make them unavailable, but to - // save on the overhead of announcing to the trackers, the DHT and to - // avoid spreading one's unchoke slots too thin. If a peer managed to - // find us, even though we're no in the torrent anymore, this setting - // can make us start the torrent and serve it. - settings.set_bool(settings_pack::incoming_starts_queued_torrents, false); //TODO: should this be true? - - // ``report_true_downloaded`` when set to true, the downloaded counter - // sent to trackers will include the actual number of payload - // bytes downloaded including redundant bytes. If set to false, it - // will not include any redundancy bytes - //settings.set_bool(settings_pack::report_true_downloaded, false); - - // ``strict_end_game_mode`` defaults to true, and controls when a - // block may be requested twice. If this is ``true``, a block may only - // be requested twice when there's ay least one request to every piece - // that's left to download in the torrent. This may slow down progress - // on some pieces sometimes, but it may also avoid downloading a lot - // of redundant bytes. If this is ``false``, libtorrent attempts to - // use each peer connection to its max, by always requesting - // something, even if it means requesting something that has been - // requested from another peer already. - settings.set_bool(settings_pack::strict_end_game_mode, true); - - // if ``broadcast_lsd`` is set to true, the local peer discovery (or - // Local Service Discovery) will not only use IP multicast, but also - // broadcast its messages. This can be useful when running on networks - // that don't support multicast. Since broadcast messages might be - // expensive and disruptive on networks, only every 8th announce uses - // broadcast. - //settings.set_bool(settings_pack::broadcast_lsd, true); - - // ``enable_outgoing_utp`` ``enable_incoming_utp`` - // ``enable_outgoing_tcp`` ``enable_incoming_tcp`` - // when set to true, libtorrent will try to make outgoing utp - // connections controls whether libtorrent will accept incoming - // connections or make outgoing connections of specific type. - settings.set_bool(settings_pack::enable_outgoing_utp, true); - settings.set_bool(settings_pack::enable_incoming_utp, true); - settings.set_bool(settings_pack::enable_outgoing_tcp, true); - settings.set_bool(settings_pack::enable_incoming_tcp, true); - - // ``seeding_outgoing_connections`` determines if seeding (and - // finished) torrents should attempt to make outgoing connections or - // not. By default this is true. It may be set to false in very - // specific applications where the cost of making outgoing connections - // is high, and there are no or small benefits of doing so. For - // instance, if no nodes are behind a firewall or a NAT, seeds don't - // need to make outgoing connections. - settings.set_bool(settings_pack::seeding_outgoing_connections, true); - - // ``no_connect_privileged_ports`` when this is true, - // libtorrent will not attempt to make outgoing connections - // to peers whose port is < 1024. This is a safety precaution - // to avoid being part of a DDoS attack - //settings.set_bool(settings_pack::no_connect_privileged_ports, true); //TODO: should this be true? - - // ``smooth_connects`` is true by default, which means the number of - // connection attempts per second may be limited to below the - // ``connection_speed``, in case we're close to bump up against the - // limit of number of connections. The intention of this setting is to - // more evenly distribute our connection attempts over time, instead - // of attempting to connect in batches, and timing them out in - // batches. - settings.set_bool(settings_pack::smooth_connects, true); - - // ``always_send_user_agent`` - // always send user-agent in every web seed request. If false, only - // the first request per http connection will include the user agent - //settings.set_bool(settings_pack::always_send_user_agent, true); - - // ``apply_ip_filter_to_trackers`` defaults to true. It determines - // whether the IP filter applies to trackers as well as peers. If this - // is set to false, trackers are exempt from the IP filter (if there - // is one). If no IP filter is set, this setting is irrelevant. - settings.set_bool(settings_pack::apply_ip_filter_to_trackers, true); - - // ``ban_web_seeds`` when true, web seeds sending bad data will be banned - //settings.set_bool(settings_pack::ban_web_seeds, true); //TODO: should this be true? - - // ``allow_partial_disk_writes`` - // when set to false, the ``write_cache_line_size`` will apply across - // piece boundaries. this is a bad idea unless the piece picker also - // is configured to have an affinity to pick pieces belonging to the - // same write cache line as is configured in the disk cache. - //settings.set_bool(settings_pack::allow_partial_disk_writes, true); - - // ``support_share_mode`` if false, prevents libtorrent to advertise share-mode support - //settings.set_bool(settings_pack::support_share_mode, true); - - // ``support_merkle_torrents`` if this is false, don't advertise support for the Tribler merkle - // tree piece message - //settings.set_bool(settings_pack::support_merkle_torrents, true); - - // ``report_redundant_bytes`` if this is true, the number of redundant bytes is sent to the - // tracker - //settings.set_bool(settings_pack::report_redundant_bytes, false); - - // ``listen_system_port_fallback`` if this is true, - // libtorrent will fall back to listening on a port chosen by the - // operating system (i.e. binding to port 0). If a failure is - // preferred, set this to false. - settings.set_bool(settings_pack::listen_system_port_fallback, true); - - // ``announce_crypto_support`` when this is true, and incoming encrypted connections are enabled, - // &supportcrypt=1 is included in http tracker announces - //settings.set_bool(settings_pack::announce_crypto_support, true); //TODO: should this be true? - - // ``enable_upnp`` - // Starts and stops the UPnP service. When started, the listen port - // and the DHT port are attempted to be forwarded on local UPnP router - // devices. - // The upnp object returned by ``start_upnp()`` can be used to add and - // remove arbitrary port mappings. Mapping status is returned through - // the portmap_alert and the portmap_error_alert. The object will be - // valid until ``stop_upnp()`` is called. See upnp-and-nat-pmp_. - //settings.set_bool(settings_pack::enable_upnp, false); - - // ``enable_natpmp`` - // Starts and stops the NAT-PMP service. When started, the listen port - // and the DHT port are attempted to be forwarded on the router - // through NAT-PMP. - // The natpmp object returned by ``start_natpmp()`` can be used to add - // and remove arbitrary port mappings. Mapping status is returned - // through the portmap_alert and the portmap_error_alert. The object - // will be valid until ``stop_natpmp()`` is called. See - // upnp-and-nat-pmp_. - //settings.set_bool(settings_pack::enable_natpmp, true); //TODO: should this be true? - - // ``enable_lsd`` - // Starts and stops Local Service Discovery. This service will - // broadcast the info-hashes of all the non-private torrents on the - // local network to look for peers on the same swarm within multicast - // reach. - //settings.set_bool(settings_pack::enable_lsd, true); - - // ``prefer_rc4`` - // if the allowed encryption level is both, setting this to true will - // prefer rc4 if both methods are offered, plaintext otherwise - //settings.set_bool(settings_pack::prefer_rc4, true); //TODO: should this be true? - - // ``proxy_hostnames`` - // if true, hostname lookups are done via the configured proxy (if - // any). This is only supported by SOCKS5 and HTTP. - //settings.set_bool(settings_pack::proxy_hostnames, true); - - // ``proxy_peer_connections`` - // if true, peer connections are made (and accepted) over the - // configured proxy, if any. Web seeds as well as regular bittorrent - // peer connections are considered "peer connections". Anything - // transporting actual torrent payload (trackers and DHT traffic are - // not considered peer connections). - //settings.set_bool(settings_pack::proxy_peer_connections, true); - - // ``auto_sequential`` - // if this setting is true, torrents with a very high availability of - // pieces (and seeds) are downloaded sequentially. This is more - // efficient for the disk I/O. With many seeds, the download order is - // unlikely to matter anyway - //settings.set_bool(settings_pack::auto_sequential, true); - - // ``proxy_tracker_connections`` - // if true, tracker connections are made over the configured proxy, if - // any. - //, - //settings.set_bool(settings_pack::proxy_tracker_connections, true); - - // Starts and stops the internal IP table route changes notifier. - // - // The current implementation supports multiple platforms, and it is - // recommended to have it enable, but you may want to disable it if - // it's supported but unreliable, or if you have a better way to - // detect the changes. In the later case, you should manually call - // ``session_handle::reopen_network_sockets`` to ensure network - // changes are taken in consideration. - //enable_ip_notifier, - - - // int params: - - // ``tracker_completion_timeout`` is the number of seconds the tracker - // connection will wait from when it sent the request until it - // considers the tracker to have timed-out. - //tracker_completion_timeout = int_type_base, - - // ``tracker_receive_timeout`` is the number of seconds to wait to - // receive any data from the tracker. If no data is received for this - // number of seconds, the tracker will be considered as having timed - // out. If a tracker is down, this is the kind of timeout that will - // occur. - //tracker_receive_timeout, - - // ``stop_tracker_timeout`` is the number of seconds to wait when - // sending a stopped message before considering a tracker to have - // timed out. This is usually shorter, to make the client quit faster. - // If the value is set to 0, the connections to trackers with the - // stopped event are suppressed. - //stop_tracker_timeout, - - // this is the maximum number of bytes in a tracker response. If a - // response size passes this number of bytes it will be rejected and - // the connection will be closed. On gzipped responses this size is - // measured on the uncompressed data. So, if you get 20 bytes of gzip - // response that'll expand to 2 megabytes, it will be interrupted - // before the entire response has been uncompressed (assuming the - // limit is lower than 2 megs). - //tracker_maximum_response_length, - - // the number of seconds from a request is sent until it times out if - // no piece response is returned. - //piece_timeout, - - // the number of seconds one block (16kB) is expected to be received - // within. If it's not, the block is requested from a different peer - //request_timeout, - - // the length of the request queue given in the number of seconds it - // should take for the other end to send all the pieces. i.e. the - // actual number of requests depends on the download rate and this - // number. - //request_queue_time, - - // the number of outstanding block requests a peer is allowed to queue - // up in the client. If a peer sends more requests than this (before - // the first one has been sent) the last request will be dropped. the - // higher this is, the faster upload speeds the client can get to a - // single peer. - //max_allowed_in_request_queue, - - // ``max_out_request_queue`` is the maximum number of outstanding - // requests to send to a peer. This limit takes precedence over - // ``request_queue_time``. i.e. no matter the download speed, the - // number of outstanding requests will never exceed this limit. - //max_out_request_queue, - - // if a whole piece can be downloaded in this number of seconds, or - // less, the peer_connection will prefer to request whole pieces at a - // time from this peer. The benefit of this is to better utilize disk - // caches by doing localized accesses and also to make it easier to - // identify bad peers if a piece fails the hash check. - //whole_pieces_threshold, - - // ``peer_timeout`` is the number of seconds the peer connection - // should wait (for any activity on the peer connection) before - // closing it due to time out. This defaults to 120 seconds, since - // that's what's specified in the protocol specification. After half - // the time out, a keep alive message is sent. - //peer_timeout, - - // same as peer_timeout, but only applies to url-seeds. this is - // usually set lower, because web servers are expected to be more - // reliable. - //urlseed_timeout, - - // controls the pipelining size of url and http seeds. i.e. the number of HTTP - // request to keep outstanding before waiting for the first one to - // complete. It's common for web servers to limit this to a relatively - // low number, like 5 - //urlseed_pipeline_size, - - // number of seconds until a new retry of a url-seed takes place. - // Default retry value for http-seeds that don't provide a valid 'retry-after' header. - //urlseed_wait_retry, - - // sets the upper limit on the total number of files this session will - // keep open. The reason why files are left open at all is that some - // anti virus software hooks on every file close, and scans the file - // for viruses. deferring the closing of the files will be the - // difference between a usable system and a completely hogged down - // system. Most operating systems also has a limit on the total number - // of file descriptors a process may have open. - //file_pool_size, - - // ``max_failcount`` is the maximum times we try to connect to a peer - // before stop connecting again. If a peer succeeds, the failcounter - // is reset. If a peer is retrieved from a peer source (other than - // DHT) the failcount is decremented by one, allowing another try. - //max_failcount, - - // the number of seconds to wait to reconnect to a peer. this time is - // multiplied with the failcount. - //min_reconnect_time, - - // ``peer_connect_timeout`` the number of seconds to wait after a - // connection attempt is initiated to a peer until it is considered as - // having timed out. This setting is especially important in case the - // number of half-open connections are limited, since stale half-open - // connection may delay the connection of other peers considerably. - //peer_connect_timeout, - - // ``connection_speed`` is the number of connection attempts that are - // made per second. If a number < 0 is specified, it will default to - // 200 connections per second. If 0 is specified, it means don't make - // outgoing connections at all. - //connection_speed, - - // if a peer is uninteresting and uninterested for longer than this - // number of seconds, it will be disconnected. default is 10 minutes - //inactivity_timeout, - - // ``unchoke_interval`` is the number of seconds between - // chokes/unchokes. On this interval, peers are re-evaluated for being - // choked/unchoked. This is defined as 30 seconds in the protocol, and - // it should be significantly longer than what it takes for TCP to - // ramp up to it's max rate. - //unchoke_interval, - - // ``optimistic_unchoke_interval`` is the number of seconds between - // each *optimistic* unchoke. On this timer, the currently - // optimistically unchoked peer will change. - //optimistic_unchoke_interval, - - // ``num_want`` is the number of peers we want from each tracker - // request. It defines what is sent as the ``&num_want=`` parameter to - // the tracker. - //num_want, - - // ``initial_picker_threshold`` specifies the number of pieces we need - // before we switch to rarest first picking. This defaults to 4, which - // means the 4 first pieces in any torrent are picked at random, the - // following pieces are picked in rarest first order. - //initial_picker_threshold, - - // the number of allowed pieces to send to peers that supports the - // fast extensions - //allowed_fast_set_size, - - // ``suggest_mode`` controls whether or not libtorrent will send out - // suggest messages to create a bias of its peers to request certain - // pieces. The modes are: - // - // * ``no_piece_suggestions`` which is the default and will not send - // out suggest messages. - // * ``suggest_read_cache`` which will send out suggest messages for - // the most recent pieces that are in the read cache. - //suggest_mode, - - // ``max_queued_disk_bytes`` is the maximum number of bytes, to - // be written to disk, that can wait in the disk I/O thread queue. - // This queue is only for waiting for the disk I/O thread to receive - // the job and either write it to disk or insert it in the write - // cache. When this limit is reached, the peer connections will stop - // reading data from their sockets, until the disk thread catches up. - // Setting this too low will severely limit your download rate. - //max_queued_disk_bytes, - - // the number of seconds to wait for a handshake response from a peer. - // If no response is received within this time, the peer is - // disconnected. - //handshake_timeout, - - // ``send_buffer_low_watermark`` the minimum send buffer target size - // (send buffer includes bytes pending being read from disk). For good - // and snappy seeding performance, set this fairly high, to at least - // fit a few blocks. This is essentially the initial window size which - // will determine how fast we can ramp up the send rate - // - // if the send buffer has fewer bytes than ``send_buffer_watermark``, - // we'll read another 16kB block onto it. If set too small, upload - // rate capacity will suffer. If set too high, memory will be wasted. - // The actual watermark may be lower than this in case the upload rate - // is low, this is the upper limit. - // - // the current upload rate to a peer is multiplied by this factor to - // get the send buffer watermark. The factor is specified as a - // percentage. i.e. 50 -> 0.5 This product is clamped to the - // ``send_buffer_watermark`` setting to not exceed the max. For high - // speed upload, this should be set to a greater value than 100. For - // high capacity connections, setting this higher can improve upload - // performance and disk throughput. Setting it too high may waste RAM - // and create a bias towards read jobs over write jobs. - //send_buffer_low_watermark, - //send_buffer_watermark, - //send_buffer_watermark_factor, - - // ``choking_algorithm`` specifies which algorithm to use to determine - // which peers to unchoke. - // - // The options for choking algorithms are: - // - // * ``fixed_slots_choker`` is the traditional choker with a fixed - // number of unchoke slots (as specified by - // ``settings_pack::unchoke_slots_limit``). - // - // * ``rate_based_choker`` opens up unchoke slots based on the upload - // rate achieved to peers. The more slots that are opened, the - // marginal upload rate required to open up another slot increases. - // - // * ``bittyrant_choker`` attempts to optimize download rate by - // finding the reciprocation rate of each peer individually and - // prefers peers that gives the highest *return on investment*. It - // still allocates all upload capacity, but shuffles it around to - // the best peers first. For this choker to be efficient, you need - // to set a global upload rate limit - // (``settings_pack::upload_rate_limit``). For more information - // about this choker, see the paper_. This choker is not fully - // implemented nor tested. - // - // .. _paper: http://bittyrant.cs.washington.edu/#papers - // - // ``seed_choking_algorithm`` controls the seeding unchoke behavior. - // The available options are: - // - // * ``round_robin`` which round-robins the peers that are unchoked - // when seeding. This distributes the upload bandwidht uniformly and - // fairly. It minimizes the ability for a peer to download everything - // without redistributing it. - // - // * ``fastest_upload`` unchokes the peers we can send to the fastest. - // This might be a bit more reliable in utilizing all available - // capacity. - // - // * ``anti_leech`` prioritizes peers who have just started or are - // just about to finish the download. The intention is to force - // peers in the middle of the download to trade with each other. - //choking_algorithm, - //seed_choking_algorithm, - - // ``cache_size`` is the disk write and read cache. It is specified - // in units of 16 KiB blocks. Buffers that are part of a peer's send - // or receive buffer also count against this limit. Send and receive - // buffers will never be denied to be allocated, but they will cause - // the actual cached blocks to be flushed or evicted. If this is set - // to -1, the cache size is automatically set based on the amount of - // physical RAM on the machine. If the amount of physical RAM cannot - // be determined, it's set to 1024 (= 16 MiB). - // - // ``cache_expiry`` is the number of seconds from the last cached write - // to a piece in the write cache, to when it's forcefully flushed to - // disk. Default is 60 second. - // - // On 32 bit builds, the effective cache size will be limited to 3/4 of - // 2 GiB to avoid exceeding the virtual address space limit. - //cache_size, - - //cache_expiry, - - // determines how files are opened when they're in read only mode - // versus read and write mode. The options are: - // - // enable_os_cache - // This is the default and files are opened normally, with the OS - // caching reads and writes. - // disable_os_cache - // This opens all files in no-cache mode. This corresponds to the - // OS not letting blocks for the files linger in the cache. This - // makes sense in order to avoid the bittorrent client to - // potentially evict all other processes' cache by simply handling - // high throughput and large files. If libtorrent's read cache is - // disabled, enabling this may reduce performance. - // - // One reason to disable caching is that it may help the operating - // system from growing its file cache indefinitely. - //disk_io_write_mode, - //disk_io_read_mode, - - // this is the first port to use for binding outgoing connections to. - // This is useful for users that have routers that allow QoS settings - // based on local port. when binding outgoing connections to specific - // ports, ``num_outgoing_ports`` is the size of the range. It should - // be more than a few - // - // .. warning:: setting outgoing ports will limit the ability to keep - // multiple connections to the same client, even for different - // torrents. It is not recommended to change this setting. Its main - // purpose is to use as an escape hatch for cheap routers with QoS - // capability but can only classify flows based on port numbers. - // - // It is a range instead of a single port because of the problems with - // failing to reconnect to peers if a previous socket to that peer and - // port is in ``TIME_WAIT`` state. - //outgoing_port, - //num_outgoing_ports, - - // ``peer_tos`` determines the TOS byte set in the IP header of every - // packet sent to peers (including web seeds). The default value for - // this is ``0x0`` (no marking). One potentially useful TOS mark is - // ``0x20``, this represents the *QBone scavenger service*. For more - // details, see QBSS_. - // - // .. _`QBSS`: http://qbone.internet2.edu/qbss/ - //peer_tos, - - // for auto managed torrents, these are the limits they are subject - // to. If there are too many torrents some of the auto managed ones - // will be paused until some slots free up. ``active_downloads`` and - // ``active_seeds`` controls how many active seeding and downloading - // torrents the queuing mechanism allows. The target number of active - // torrents is ``min(active_downloads + active_seeds, active_limit)``. - // ``active_downloads`` and ``active_seeds`` are upper limits on the - // number of downloading torrents and seeding torrents respectively. - // Setting the value to -1 means unlimited. - // - // For example if there are 10 seeding torrents and 10 downloading - // torrents, and ``active_downloads`` is 4 and ``active_seeds`` is 4, - // there will be 4 seeds active and 4 downloading torrents. If the - // settings are ``active_downloads`` = 2 and ``active_seeds`` = 4, - // then there will be 2 downloading torrents and 4 seeding torrents - // active. Torrents that are not auto managed are not counted against - // these limits. - // - // ``active_checking`` is the limit of number of simultaneous checking - // torrents. - // - // ``active_limit`` is a hard limit on the number of active (auto - // managed) torrents. This limit also applies to slow torrents. - // - // ``active_dht_limit`` is the max number of torrents to announce to - // the DHT. By default this is set to 88, which is no more than one - // DHT announce every 10 seconds. - // - // ``active_tracker_limit`` is the max number of torrents to announce - // to their trackers. By default this is 360, which is no more than - // one announce every 5 seconds. - // - // ``active_lsd_limit`` is the max number of torrents to announce to - // the local network over the local service discovery protocol. By - // default this is 80, which is no more than one announce every 5 - // seconds (assuming the default announce interval of 5 minutes). - // - // You can have more torrents *active*, even though they are not - // announced to the DHT, lsd or their tracker. If some peer knows - // about you for any reason and tries to connect, it will still be - // accepted, unless the torrent is paused, which means it won't accept - // any connections. - //active_downloads, - //active_seeds, - //active_checking, - //active_dht_limit, - //active_tracker_limit, - //active_lsd_limit, - //active_limit, - - // ``auto_manage_interval`` is the number of seconds between the - // torrent queue is updated, and rotated. - //auto_manage_interval, - - // this is the limit on the time a torrent has been an active seed - // (specified in seconds) before it is considered having met the seed - // limit criteria. See queuing_. - //seed_time_limit, - - // ``auto_scrape_interval`` is the number of seconds between scrapes - // of queued torrents (auto managed and paused torrents). Auto managed - // torrents that are paused, are scraped regularly in order to keep - // track of their downloader/seed ratio. This ratio is used to - // determine which torrents to seed and which to pause. - // - // ``auto_scrape_min_interval`` is the minimum number of seconds - // between any automatic scrape (regardless of torrent). In case there - // are a large number of paused auto managed torrents, this puts a - // limit on how often a scrape request is sent. - //auto_scrape_interval, - //auto_scrape_min_interval, - - // ``max_peerlist_size`` is the maximum number of peers in the list of - // known peers. These peers are not necessarily connected, so this - // number should be much greater than the maximum number of connected - // peers. Peers are evicted from the cache when the list grows passed - // 90% of this limit, and once the size hits the limit, peers are no - // longer added to the list. If this limit is set to 0, there is no - // limit on how many peers we'll keep in the peer list. - // - // ``max_paused_peerlist_size`` is the max peer list size used for - // torrents that are paused. This default to the same as - // ``max_peerlist_size``, but can be used to save memory for paused - // torrents, since it's not as important for them to keep a large peer - // list. - //max_peerlist_size, - //max_paused_peerlist_size, - - // this is the minimum allowed announce interval for a tracker. This - // is specified in seconds and is used as a sanity check on what is - // returned from a tracker. It mitigates hammering misconfigured - // trackers. - //min_announce_interval, - - // this is the number of seconds a torrent is considered active after - // it was started, regardless of upload and download speed. This is so - // that newly started torrents are not considered inactive until they - // have a fair chance to start downloading. - //auto_manage_startup, - - // ``seeding_piece_quota`` is the number of pieces to send to a peer, - // when seeding, before rotating in another peer to the unchoke set. - // It defaults to 3 pieces, which means that when seeding, any peer - // we've sent more than this number of pieces to will be unchoked in - // favour of a choked peer. - //seeding_piece_quota, - - // TODO: deprecate this - // ``max_rejects`` is the number of piece requests we will reject in a - // row while a peer is choked before the peer is considered abusive - // and is disconnected. - //max_rejects, - - // specifies the buffer sizes set on peer sockets. 0 (which is the - // default) means the OS default (i.e. don't change the buffer sizes). - // The socket buffer sizes are changed using setsockopt() with - // SOL_SOCKET/SO_RCVBUF and SO_SNDBUFFER. - //recv_socket_buffer_size, - //send_socket_buffer_size, - - // the max number of bytes a single peer connection's receive buffer is - // allowed to grow to. - //max_peer_recv_buffer_size, - - // ``read_cache_line_size`` is the number of blocks to read into the - // read cache when a read cache miss occurs. Setting this to 0 is - // essentially the same thing as disabling read cache. The number of - // blocks read into the read cache is always capped by the piece - // boundary. - // - // When a piece in the write cache has ``write_cache_line_size`` - // contiguous blocks in it, they will be flushed. Setting this to 1 - // effectively disables the write cache. - //read_cache_line_size, - //write_cache_line_size, - - // ``optimistic_disk_retry`` is the number of seconds from a disk - // write errors occur on a torrent until libtorrent will take it out - // of the upload mode, to test if the error condition has been fixed. - // - // libtorrent will only do this automatically for auto managed - // torrents. - // - // You can explicitly take a torrent out of upload only mode using - // set_upload_mode(). - //optimistic_disk_retry, - - // ``max_suggest_pieces`` is the max number of suggested piece indices - // received from a peer that's remembered. If a peer floods suggest - // messages, this limit prevents libtorrent from using too much RAM. - // It defaults to 10. - //max_suggest_pieces, - - // ``local_service_announce_interval`` is the time between local - // network announces for a torrent. By default, when local service - // discovery is enabled a torrent announces itself every 5 minutes. - // This interval is specified in seconds. - //local_service_announce_interval, - - // ``dht_announce_interval`` is the number of seconds between - // announcing torrents to the distributed hash table (DHT). - //dht_announce_interval, - - // ``udp_tracker_token_expiry`` is the number of seconds libtorrent - // will keep UDP tracker connection tokens around for. This is - // specified to be 60 seconds, and defaults to that. The higher this - // value is, the fewer packets have to be sent to the UDP tracker. In - // order for higher values to work, the tracker needs to be configured - // to match the expiration time for tokens. - //udp_tracker_token_expiry, - - // ``num_optimistic_unchoke_slots`` is the number of optimistic - // unchoke slots to use. It defaults to 0, which means automatic. - // Having a higher number of optimistic unchoke slots mean you will - // find the good peers faster but with the trade-off to use up more - // bandwidth. When this is set to 0, libtorrent opens up 20% of your - // allowed upload slots as optimistic unchoke slots. - //num_optimistic_unchoke_slots, - - // ``default_est_reciprocation_rate`` is the assumed reciprocation - // rate from peers when using the BitTyrant choker. This defaults to - // 14 kiB/s. If set too high, you will over-estimate your peers and be - // more altruistic while finding the true reciprocation rate, if it's - // set too low, you'll be too stingy and waste finding the true - // reciprocation rate. - // - // ``increase_est_reciprocation_rate`` specifies how many percent the - // estimated reciprocation rate should be increased by each unchoke - // interval a peer is still choking us back. This defaults to 20%. - // This only applies to the BitTyrant choker. - // - // ``decrease_est_reciprocation_rate`` specifies how many percent the - // estimated reciprocation rate should be decreased by each unchoke - // interval a peer unchokes us. This default to 3%. This only applies - // to the BitTyrant choker. - //default_est_reciprocation_rate, - //increase_est_reciprocation_rate, - //decrease_est_reciprocation_rate, - - // the max number of peers we accept from pex messages from a single - // peer. this limits the number of concurrent peers any of our peers - // claims to be connected to. If they claim to be connected to more - // than this, we'll ignore any peer that exceeds this limit - //max_pex_peers, - - // ``tick_interval`` specifies the number of milliseconds between - // internal ticks. This is the frequency with which bandwidth quota is - // distributed to peers. It should not be more than one second (i.e. - // 1000 ms). Setting this to a low value (around 100) means higher - // resolution bandwidth quota distribution, setting it to a higher - // value saves CPU cycles. - //tick_interval, - - // ``share_mode_target`` specifies the target share ratio for share - // mode torrents. This defaults to 3, meaning we'll try to upload 3 - // times as much as we download. Setting this very high, will make it - // very conservative and you might end up not downloading anything - // ever (and not affecting your share ratio). It does not make any - // sense to set this any lower than 2. For instance, if only 3 peers - // need to download the rarest piece, it's impossible to download a - // single piece and upload it more than 3 times. If the - // share_mode_target is set to more than 3, nothing is downloaded. - //share_mode_target, - - // ``upload_rate_limit`` and ``download_rate_limit`` sets - // the session-global limits of upload and download rate limits, in - // bytes per second. By default peers on the local network are not rate - // limited. - // - // A value of 0 means unlimited. - // - // For fine grained control over rate limits, including making them apply - // to local peers, see peer-classes_. - //upload_rate_limit, - //download_rate_limit, - - // ``unchoke_slots_limit`` is the max number of unchoked peers in the - // session. The number of unchoke slots may be ignored depending on - // what ``choking_algorithm`` is set to. - //unchoke_slots_limit, - - // ``connections_limit`` sets a global limit on the number of - // connections opened. The number of connections is set to a hard - // minimum of at least two per torrent, so if you set a too low - // connections limit, and open too many torrents, the limit will not - // be met. - //connections_limit, - - // ``connections_slack`` is the the number of incoming connections - // exceeding the connection limit to accept in order to potentially - // replace existing ones. - //connections_slack, - - // ``utp_target_delay`` is the target delay for uTP sockets in - // milliseconds. A high value will make uTP connections more - // aggressive and cause longer queues in the upload bottleneck. It - // cannot be too low, since the noise in the measurements would cause - // it to send too slow. The default is 50 milliseconds. - // ``utp_gain_factor`` is the number of bytes the uTP congestion - // window can increase at the most in one RTT. This defaults to 300 - // bytes. If this is set too high, the congestion controller reacts - // too hard to noise and will not be stable, if it's set too low, it - // will react slow to congestion and not back off as fast. - // - // ``utp_min_timeout`` is the shortest allowed uTP socket timeout, - // specified in milliseconds. This defaults to 500 milliseconds. The - // timeout depends on the RTT of the connection, but is never smaller - // than this value. A connection times out when every packet in a - // window is lost, or when a packet is lost twice in a row (i.e. the - // resent packet is lost as well). - // - // The shorter the timeout is, the faster the connection will recover - // from this situation, assuming the RTT is low enough. - // ``utp_syn_resends`` is the number of SYN packets that are sent (and - // timed out) before giving up and closing the socket. - // ``utp_num_resends`` is the number of times a packet is sent (and - // lost or timed out) before giving up and closing the connection. - // ``utp_connect_timeout`` is the number of milliseconds of timeout - // for the initial SYN packet for uTP connections. For each timed out - // packet (in a row), the timeout is doubled. ``utp_loss_multiplier`` - // controls how the congestion window is changed when a packet loss is - // experienced. It's specified as a percentage multiplier for - // ``cwnd``. By default it's set to 50 (i.e. cut in half). Do not - // change this value unless you know what you're doing. Never set it - // higher than 100. - //utp_target_delay, - //utp_gain_factor, - //utp_min_timeout, - //utp_syn_resends, - //utp_fin_resends, - //utp_num_resends, - //utp_connect_timeout, - - //utp_loss_multiplier, - - // The ``mixed_mode_algorithm`` determines how to treat TCP - // connections when there are uTP connections. Since uTP is designed - // to yield to TCP, there's an inherent problem when using swarms that - // have both TCP and uTP connections. If nothing is done, uTP - // connections would often be starved out for bandwidth by the TCP - // connections. This mode is ``prefer_tcp``. The ``peer_proportional`` - // mode simply looks at the current throughput and rate limits all TCP - // connections to their proportional share based on how many of the - // connections are TCP. This works best if uTP connections are not - // rate limited by the global rate limiter (which they aren't by - // default). - //mixed_mode_algorithm, - - // ``listen_queue_size`` is the value passed in to listen() for the - // listen socket. It is the number of outstanding incoming connections - // to queue up while we're not actively waiting for a connection to be - // accepted. The default is 5 which should be sufficient for any - // normal client. If this is a high performance server which expects - // to receive a lot of connections, or used in a simulator or test, it - // might make sense to raise this number. It will not take affect - // until the ``listen_interfaces`` settings is updated. - //listen_queue_size, - - // ``torrent_connect_boost`` is the number of peers to try to connect - // to immediately when the first tracker response is received for a - // torrent. This is a boost to given to new torrents to accelerate - // them starting up. The normal connect scheduler is run once every - // second, this allows peers to be connected immediately instead of - // waiting for the session tick to trigger connections. - // This may not be set higher than 255. - //torrent_connect_boost, - - // ``alert_queue_size`` is the maximum number of alerts queued up - // internally. If alerts are not popped, the queue will eventually - // fill up to this level. Once the alert queue is full, additional - // alerts will be dropped, and not delievered to the client. Once the - // client drains the queue, new alerts may be delivered again. In order - // to know that alerts have been dropped, see - // session_handle::dropped_alerts(). - //alert_queue_size, - - // ``max_metadata_size`` is the maximum allowed size (in bytes) to be - // received by the metadata extension, i.e. magnet links. - //max_metadata_size, - - // the number of blocks to keep outstanding at any given time when - // checking torrents. Higher numbers give faster re-checks but uses - // more memory. Specified in number of 16 kiB blocks - //checking_mem_usage, - - // if set to > 0, pieces will be announced to other peers before they - // are fully downloaded (and before they are hash checked). The - // intention is to gain 1.5 potential round trip times per downloaded - // piece. When non-zero, this indicates how many milliseconds in - // advance pieces should be announced, before they are expected to be - // completed. - //predictive_piece_announce, - - // for some aio back-ends, ``aio_threads`` specifies the number of - // io-threads to use, and ``aio_max`` the max number of outstanding - // jobs. - //aio_threads, - //aio_max, - - // ``tracker_backoff`` determines how aggressively to back off from - // retrying failing trackers. This value determines *x* in the - // following formula, determining the number of seconds to wait until - // the next retry: - // - // delay = 5 + 5 * x / 100 * fails^2 - // - // This setting may be useful to make libtorrent more or less - // aggressive in hitting trackers. - //tracker_backoff, - - // when a seeding torrent reaches either the share ratio (bytes up / - // bytes down) or the seed time ratio (seconds as seed / seconds as - // downloader) or the seed time limit (seconds as seed) it is - // considered done, and it will leave room for other torrents. These - // are specified as percentages. Torrents that are considered done will - // still be allowed to be seeded, they just won't have priority anymore. - // For more, see queuing_. - //share_ratio_limit, - //seed_time_ratio_limit, - - // peer_turnover is the percentage of peers to disconnect every - // turnover peer_turnover_interval (if we're at the peer limit), this - // is specified in percent when we are connected to more than limit * - // peer_turnover_cutoff peers disconnect peer_turnover fraction of the - // peers. It is specified in percent peer_turnover_interval is the - // interval (in seconds) between optimistic disconnects if the - // disconnects happen and how many peers are disconnected is - // controlled by peer_turnover and peer_turnover_cutoff - //peer_turnover, - //peer_turnover_cutoff, - //peer_turnover_interval, - - // this setting controls the priority of downloading torrents over - // seeding or finished torrents when it comes to making peer - // connections. Peer connections are throttled by the connection_speed - // and the half-open connection limit. This makes peer connections a - // limited resource. Torrents that still have pieces to download are - // prioritized by default, to avoid having many seeding torrents use - // most of the connection attempts and only give one peer every now - // and then to the downloading torrent. libtorrent will loop over the - // downloading torrents to connect a peer each, and every n:th - // connection attempt, a finished torrent is picked to be allowed to - // connect to a peer. This setting controls n. - //connect_seed_every_n_download, - - // the max number of bytes to allow an HTTP response to be when - // announcing to trackers or downloading .torrent files via the - // ``url`` provided in ``add_torrent_params``. - //max_http_recv_buffer_size, - - // if binding to a specific port fails, should the port be incremented - // by one and tried again? This setting specifies how many times to - // retry a failed port bind - //max_retry_port_bind, - - // a bitmask combining flags from alert::category_t defining which - // kinds of alerts to receive - //alert_mask, - - // control the settings for incoming and outgoing connections - // respectively. see enc_policy enum for the available options. - // Keep in mind that protocol encryption degrades performance in - // several respects: - // - // 1. It prevents "zero copy" disk buffers being sent to peers, since - // each peer needs to mutate the data (i.e. encrypt it) the data - // must be copied per peer connection rather than sending the same - // buffer to multiple peers. - // 2. The encryption itself requires more CPU than plain bittorrent - // protocol. The highest cost is the Diffie Hellman exchange on - // connection setup. - // 3. The encryption handshake adds several round-trips to the - // connection setup, and delays transferring data. - //out_enc_policy, - //in_enc_policy, - - // determines the encryption level of the connections. This setting - // will adjust which encryption scheme is offered to the other peer, - // as well as which encryption scheme is selected by the client. See - // enc_level enum for options. - //allowed_enc_level, - - // the download and upload rate limits for a torrent to be considered - // active by the queuing mechanism. A torrent whose download rate is - // less than ``inactive_down_rate`` and whose upload rate is less than - // ``inactive_up_rate`` for ``auto_manage_startup`` seconds, is - // considered inactive, and another queued torrent may be started. - // This logic is disabled if ``dont_count_slow_torrents`` is false. - //inactive_down_rate, - //inactive_up_rate, - - // proxy to use, defaults to none. see proxy_type_t. - //proxy_type, - - // the port of the proxy server - //proxy_port, - - // sets the i2p_ SAM bridge port to connect to. set the hostname with - // the ``i2p_hostname`` setting. - // - // .. _i2p: http://www.i2p2.de - //i2p_port, - - // this determines the max number of volatile disk cache blocks. If the - // number of volatile blocks exceed this limit, other volatile blocks - // will start to be evicted. A disk cache block is volatile if it has - // low priority, and should be one of the first blocks to be evicted - // under pressure. For instance, blocks pulled into the cache as the - // result of calculating a piece hash are volatile. These blocks don't - // represent potential interest among peers, so the value of keeping - // them in the cache is limited. - //cache_size_volatile, - - // The maximum request range of an url seed in bytes. This value - // defines the largest possible sequential web seed request. Default - // is 16 * 1024 * 1024. Lower values are possible but will be ignored - // if they are lower then piece size. - // This value should be related to your download speed to prevent - // libtorrent from creating too many expensive http requests per - // second. You can select a value as high as you want but keep in mind - // that libtorrent can't create parallel requests if the first request - // did already select the whole file. - // If you combine bittorrent seeds with web seeds and pick strategies - // like rarest first you may find your web seed requests split into - // smaller parts because we don't download already picked pieces - // twice. - //urlseed_max_request_bytes, - - // time to wait until a new retry of a web seed name lookup - //web_seed_name_lookup_retry, - - // the number of seconds between closing the file opened the longest - // ago. 0 means to disable the feature. The purpose of this is to - // periodically close files to trigger the operating system flushing - // disk cache. Specifically it has been observed to be required on - // windows to not have the disk cache grow indefinitely. - // This defaults to 120 seconds on windows, and disabled on other - // systems. - //close_file_interval, - - // the max number of web seeds to have connected per torrent at any - // given time. - //max_web_seed_connections, - - // the number of seconds before the internal host name resolver - // considers a cache value timed out, negative values are interpreted - // as zero. - //resolver_cache_timeout, - - settings.set_str(settings_pack::user_agent, "Dynamic"); //todo: add version to user agent - - // this is the client name and version identifier sent to peers in the - // handshake message. If this is an empty string, the user_agent is - // used instead - //settings.set_str(settings_pack:handshake_client_version, "Dynamic"); //todo: add version to user agent - - // sets the network interface this session will use when it opens - // outgoing connections. By default, it binds outgoing connections to - // INADDR_ANY and port 0 (i.e. let the OS decide). Ths parameter must - // be a string containing one or more, comma separated, adapter names. - // Adapter names on unix systems are of the form "eth0", "eth1", - // "tun0", etc. When specifying multiple interfaces, they will be - // assigned in round-robin order. This may be useful for clients that - // are multi-homed. Binding an outgoing connection to a local IP does - // not necessarily make the connection via the associated NIC/Adapter. - // Setting this to an empty string will disable binding of outgoing - // connections. - settings.set_bool(settings_pack::outgoing_interfaces, false); - // a comma-separated list of (IP or device name, port) pairs. These are - // the listen ports that will be opened for accepting incoming uTP and - // TCP connections. It is possible to listen on multiple interfaces and - // multiple ports. Binding to port 0 will make the operating system - // pick the port. The default is "0.0.0.0:6881,[::]:6881", which binds - // to all interfaces on port 6881. - // - // a port that has an "s" suffix will accept SSL connections. (note - // that SSL sockets are not enabled by default). - // - // if binding fails, the listen_failed_alert is posted. If or once a - // socket binding succeeds, the listen_succeeded_alert is posted. There - // may be multiple failures before a success. - // - // For example: - // ``[::1]:8888`` - will only accept connections on the IPv6 loopback - // address on port 8888. - // - // ``eth0:4444,eth1:4444`` - will accept connections on port 4444 on - // any IP address bound to device ``eth0`` or ``eth1``. - // - // ``[::]:0s`` - will accept SSL connections on a port chosen by the - // OS. And not accept non-SSL connections at all. - // - // Windows OS network adapter device name can be specified with GUID. - // It can be obtained from "netsh lan show interfaces" command output. - // GUID must be uppercased string embraced in curly brackets. - // ``{E4F0B674-0DFC-48BB-98A5-2AA730BDB6D6}::7777`` - will accept - // connections on port 7777 on adapter with this GUID. - //listen_interfaces, - // when using a poxy, this is the hostname where the proxy is running - // see proxy_type. - //proxy_hostname, - - // when using a proxy, these are the credentials (if any) to use when - // connecting to it. see proxy_type - //proxy_username, - //proxy_password, - - // sets the i2p_ SAM bridge to connect to. set the port with the - // ``i2p_port`` setting. - // - // .. _i2p: http://www.i2p2.de - //i2p_hostname, - - // this is the fingerprint for the client. It will be used as the - // prefix to the peer_id. If this is 20 bytes (or longer) it will be - // truncated to 20 bytes and used as the entire peer-id - // - // There is a utility function, generate_fingerprint() that can be used - // to generate a standard client peer ID fingerprint prefix. - //peer_fingerprint, - - // This is a comma-separated list of IP port-pairs. They will be added - // to the DHT node (if it's enabled) as back-up nodes in case we don't - // know of any. This setting will contain one or more bootstrap nodes - // by default. - // - // Changing these after the DHT has been started may not have any - // effect until the DHT is restarted. - //dht_bootstrap_nodes, - - //max_string_setting_internal - - newSession.apply_settings(settings); + // ``incoming_starts_queued_torrents`` defaults to false. If a torrent + // has been paused by the auto managed feature in libtorrent, i.e. the + // torrent is paused and auto managed, this feature affects whether or + // not it is automatically started on an incoming connection. The main + // reason to queue torrents, is not to make them unavailable, but to + // save on the overhead of announcing to the trackers, the DHT and to + // avoid spreading one's unchoke slots too thin. If a peer managed to + // find us, even though we're no in the torrent anymore, this setting + // can make us start the torrent and serve it. + //settings.set_bool(settings_pack::incoming_starts_queued_torrents, false); //TODO: should this be true? + + // ``report_true_downloaded`` when set to true, the downloaded counter + // sent to trackers will include the actual number of payload + // bytes downloaded including redundant bytes. If set to false, it + // will not include any redundancy bytes + //settings.set_bool(settings_pack::report_true_downloaded, false); + + // ``strict_end_game_mode`` defaults to true, and controls when a + // block may be requested twice. If this is ``true``, a block may only + // be requested twice when there's ay least one request to every piece + // that's left to download in the torrent. This may slow down progress + // on some pieces sometimes, but it may also avoid downloading a lot + // of redundant bytes. If this is ``false``, libtorrent attempts to + // use each peer connection to its max, by always requesting + // something, even if it means requesting something that has been + // requested from another peer already. + //settings.set_bool(settings_pack::strict_end_game_mode, true); + + // if ``broadcast_lsd`` is set to true, the local peer discovery (or + // Local Service Discovery) will not only use IP multicast, but also + // broadcast its messages. This can be useful when running on networks + // that don't support multicast. Since broadcast messages might be + // expensive and disruptive on networks, only every 8th announce uses + // broadcast. + //settings.set_bool(settings_pack::broadcast_lsd, true); + + // ``enable_outgoing_utp`` ``enable_incoming_utp`` + // ``enable_outgoing_tcp`` ``enable_incoming_tcp`` + // when set to true, libtorrent will try to make outgoing utp + // connections controls whether libtorrent will accept incoming + // connections or make outgoing connections of specific type. + //settings.set_bool(settings_pack::enable_outgoing_utp, true); + //settings.set_bool(settings_pack::enable_incoming_utp, true); + //settings.set_bool(settings_pack::enable_outgoing_tcp, true); + //settings.set_bool(settings_pack::enable_incoming_tcp, true); + + // ``seeding_outgoing_connections`` determines if seeding (and + // finished) torrents should attempt to make outgoing connections or + // not. By default this is true. It may be set to false in very + // specific applications where the cost of making outgoing connections + // is high, and there are no or small benefits of doing so. For + // instance, if no nodes are behind a firewall or a NAT, seeds don't + // need to make outgoing connections. + //settings.set_bool(settings_pack::seeding_outgoing_connections, true); + + // ``no_connect_privileged_ports`` when this is true, + // libtorrent will not attempt to make outgoing connections + // to peers whose port is < 1024. This is a safety precaution + // to avoid being part of a DDoS attack + //settings.set_bool(settings_pack::no_connect_privileged_ports, true); //TODO: should this be true? + + // ``smooth_connects`` is true by default, which means the number of + // connection attempts per second may be limited to below the + // ``connection_speed``, in case we're close to bump up against the + // limit of number of connections. The intention of this setting is to + // more evenly distribute our connection attempts over time, instead + // of attempting to connect in batches, and timing them out in + // batches. + //settings.set_bool(settings_pack::smooth_connects, true); + + // ``always_send_user_agent`` + // always send user-agent in every web seed request. If false, only + // the first request per http connection will include the user agent + //settings.set_bool(settings_pack::always_send_user_agent, true); + + // ``apply_ip_filter_to_trackers`` defaults to true. It determines + // whether the IP filter applies to trackers as well as peers. If this + // is set to false, trackers are exempt from the IP filter (if there + // is one). If no IP filter is set, this setting is irrelevant. + //settings.set_bool(settings_pack::apply_ip_filter_to_trackers, true); + + // ``ban_web_seeds`` when true, web seeds sending bad data will be banned + //settings.set_bool(settings_pack::ban_web_seeds, true); //TODO: should this be true? + + // ``allow_partial_disk_writes`` + // when set to false, the ``write_cache_line_size`` will apply across + // piece boundaries. this is a bad idea unless the piece picker also + // is configured to have an affinity to pick pieces belonging to the + // same write cache line as is configured in the disk cache. + //settings.set_bool(settings_pack::allow_partial_disk_writes, true); + + // ``support_share_mode`` if false, prevents libtorrent to advertise share-mode support + //settings.set_bool(settings_pack::support_share_mode, true); + + // ``support_merkle_torrents`` if this is false, don't advertise support for the Tribler merkle + // tree piece message + //settings.set_bool(settings_pack::support_merkle_torrents, true); + + // ``report_redundant_bytes`` if this is true, the number of redundant bytes is sent to the + // tracker + //settings.set_bool(settings_pack::report_redundant_bytes, false); + + // ``listen_system_port_fallback`` if this is true, + // libtorrent will fall back to listening on a port chosen by the + // operating system (i.e. binding to port 0). If a failure is + // preferred, set this to false. + //settings.set_bool(settings_pack::listen_system_port_fallback, true); + + // ``announce_crypto_support`` when this is true, and incoming encrypted connections are enabled, + // &supportcrypt=1 is included in http tracker announces + //settings.set_bool(settings_pack::announce_crypto_support, true); //TODO: should this be true? + + // ``enable_upnp`` + // Starts and stops the UPnP service. When started, the listen port + // and the DHT port are attempted to be forwarded on local UPnP router + // devices. + // The upnp object returned by ``start_upnp()`` can be used to add and + // remove arbitrary port mappings. Mapping status is returned through + // the portmap_alert and the portmap_error_alert. The object will be + // valid until ``stop_upnp()`` is called. See upnp-and-nat-pmp_. + //settings.set_bool(settings_pack::enable_upnp, false); + + // ``enable_natpmp`` + // Starts and stops the NAT-PMP service. When started, the listen port + // and the DHT port are attempted to be forwarded on the router + // through NAT-PMP. + // The natpmp object returned by ``start_natpmp()`` can be used to add + // and remove arbitrary port mappings. Mapping status is returned + // through the portmap_alert and the portmap_error_alert. The object + // will be valid until ``stop_natpmp()`` is called. See + // upnp-and-nat-pmp_. + //settings.set_bool(settings_pack::enable_natpmp, true); //TODO: should this be true? + + // ``enable_lsd`` + // Starts and stops Local Service Discovery. This service will + // broadcast the info-hashes of all the non-private torrents on the + // local network to look for peers on the same swarm within multicast + // reach. + //settings.set_bool(settings_pack::enable_lsd, true); + + // ``prefer_rc4`` + // if the allowed encryption level is both, setting this to true will + // prefer rc4 if both methods are offered, plaintext otherwise + //settings.set_bool(settings_pack::prefer_rc4, true); //TODO: should this be true? + + // ``proxy_hostnames`` + // if true, hostname lookups are done via the configured proxy (if + // any). This is only supported by SOCKS5 and HTTP. + //settings.set_bool(settings_pack::proxy_hostnames, true); + + // ``proxy_peer_connections`` + // if true, peer connections are made (and accepted) over the + // configured proxy, if any. Web seeds as well as regular bittorrent + // peer connections are considered "peer connections". Anything + // transporting actual torrent payload (trackers and DHT traffic are + // not considered peer connections). + //settings.set_bool(settings_pack::proxy_peer_connections, true); + + // ``auto_sequential`` + // if this setting is true, torrents with a very high availability of + // pieces (and seeds) are downloaded sequentially. This is more + // efficient for the disk I/O. With many seeds, the download order is + // unlikely to matter anyway + //settings.set_bool(settings_pack::auto_sequential, true); + + // ``proxy_tracker_connections`` + // if true, tracker connections are made over the configured proxy, if + // any. + //, + //settings.set_bool(settings_pack::proxy_tracker_connections, true); + + // Starts and stops the internal IP table route changes notifier. + // + // The current implementation supports multiple platforms, and it is + // recommended to have it enable, but you may want to disable it if + // it's supported but unreliable, or if you have a better way to + // detect the changes. In the later case, you should manually call + // ``session_handle::reopen_network_sockets`` to ensure network + // changes are taken in consideration. + //enable_ip_notifier, + + + // int params: + + // ``tracker_completion_timeout`` is the number of seconds the tracker + // connection will wait from when it sent the request until it + // considers the tracker to have timed-out. + //tracker_completion_timeout = int_type_base, + + // ``tracker_receive_timeout`` is the number of seconds to wait to + // receive any data from the tracker. If no data is received for this + // number of seconds, the tracker will be considered as having timed + // out. If a tracker is down, this is the kind of timeout that will + // occur. + //tracker_receive_timeout, + + // ``stop_tracker_timeout`` is the number of seconds to wait when + // sending a stopped message before considering a tracker to have + // timed out. This is usually shorter, to make the client quit faster. + // If the value is set to 0, the connections to trackers with the + // stopped event are suppressed. + //stop_tracker_timeout, + + // this is the maximum number of bytes in a tracker response. If a + // response size passes this number of bytes it will be rejected and + // the connection will be closed. On gzipped responses this size is + // measured on the uncompressed data. So, if you get 20 bytes of gzip + // response that'll expand to 2 megabytes, it will be interrupted + // before the entire response has been uncompressed (assuming the + // limit is lower than 2 megs). + //tracker_maximum_response_length, + + // the number of seconds from a request is sent until it times out if + // no piece response is returned. + //piece_timeout, + + // the number of seconds one block (16kB) is expected to be received + // within. If it's not, the block is requested from a different peer + //request_timeout, + + // the length of the request queue given in the number of seconds it + // should take for the other end to send all the pieces. i.e. the + // actual number of requests depends on the download rate and this + // number. + //request_queue_time, + + // the number of outstanding block requests a peer is allowed to queue + // up in the client. If a peer sends more requests than this (before + // the first one has been sent) the last request will be dropped. the + // higher this is, the faster upload speeds the client can get to a + // single peer. + //max_allowed_in_request_queue, + + // ``max_out_request_queue`` is the maximum number of outstanding + // requests to send to a peer. This limit takes precedence over + // ``request_queue_time``. i.e. no matter the download speed, the + // number of outstanding requests will never exceed this limit. + //max_out_request_queue, + + // if a whole piece can be downloaded in this number of seconds, or + // less, the peer_connection will prefer to request whole pieces at a + // time from this peer. The benefit of this is to better utilize disk + // caches by doing localized accesses and also to make it easier to + // identify bad peers if a piece fails the hash check. + //whole_pieces_threshold, + + // ``peer_timeout`` is the number of seconds the peer connection + // should wait (for any activity on the peer connection) before + // closing it due to time out. This defaults to 120 seconds, since + // that's what's specified in the protocol specification. After half + // the time out, a keep alive message is sent. + //peer_timeout, + + // same as peer_timeout, but only applies to url-seeds. this is + // usually set lower, because web servers are expected to be more + // reliable. + //urlseed_timeout, + + // controls the pipelining size of url and http seeds. i.e. the number of HTTP + // request to keep outstanding before waiting for the first one to + // complete. It's common for web servers to limit this to a relatively + // low number, like 5 + //urlseed_pipeline_size, + + // number of seconds until a new retry of a url-seed takes place. + // Default retry value for http-seeds that don't provide a valid 'retry-after' header. + //urlseed_wait_retry, + + // sets the upper limit on the total number of files this session will + // keep open. The reason why files are left open at all is that some + // anti virus software hooks on every file close, and scans the file + // for viruses. deferring the closing of the files will be the + // difference between a usable system and a completely hogged down + // system. Most operating systems also has a limit on the total number + // of file descriptors a process may have open. + //file_pool_size, + + // ``max_failcount`` is the maximum times we try to connect to a peer + // before stop connecting again. If a peer succeeds, the failcounter + // is reset. If a peer is retrieved from a peer source (other than + // DHT) the failcount is decremented by one, allowing another try. + //max_failcount, + + // the number of seconds to wait to reconnect to a peer. this time is + // multiplied with the failcount. + //min_reconnect_time, + + // ``peer_connect_timeout`` the number of seconds to wait after a + // connection attempt is initiated to a peer until it is considered as + // having timed out. This setting is especially important in case the + // number of half-open connections are limited, since stale half-open + // connection may delay the connection of other peers considerably. + //peer_connect_timeout, + + // ``connection_speed`` is the number of connection attempts that are + // made per second. If a number < 0 is specified, it will default to + // 200 connections per second. If 0 is specified, it means don't make + // outgoing connections at all. + //connection_speed, + + // if a peer is uninteresting and uninterested for longer than this + // number of seconds, it will be disconnected. default is 10 minutes + //inactivity_timeout, + + // ``unchoke_interval`` is the number of seconds between + // chokes/unchokes. On this interval, peers are re-evaluated for being + // choked/unchoked. This is defined as 30 seconds in the protocol, and + // it should be significantly longer than what it takes for TCP to + // ramp up to it's max rate. + //unchoke_interval, + + // ``optimistic_unchoke_interval`` is the number of seconds between + // each *optimistic* unchoke. On this timer, the currently + // optimistically unchoked peer will change. + //optimistic_unchoke_interval, + + // ``num_want`` is the number of peers we want from each tracker + // request. It defines what is sent as the ``&num_want=`` parameter to + // the tracker. + //num_want, + + // ``initial_picker_threshold`` specifies the number of pieces we need + // before we switch to rarest first picking. This defaults to 4, which + // means the 4 first pieces in any torrent are picked at random, the + // following pieces are picked in rarest first order. + //initial_picker_threshold, + + // the number of allowed pieces to send to peers that supports the + // fast extensions + //allowed_fast_set_size, + + // ``suggest_mode`` controls whether or not libtorrent will send out + // suggest messages to create a bias of its peers to request certain + // pieces. The modes are: + // + // * ``no_piece_suggestions`` which is the default and will not send + // out suggest messages. + // * ``suggest_read_cache`` which will send out suggest messages for + // the most recent pieces that are in the read cache. + //suggest_mode, + + // ``max_queued_disk_bytes`` is the maximum number of bytes, to + // be written to disk, that can wait in the disk I/O thread queue. + // This queue is only for waiting for the disk I/O thread to receive + // the job and either write it to disk or insert it in the write + // cache. When this limit is reached, the peer connections will stop + // reading data from their sockets, until the disk thread catches up. + // Setting this too low will severely limit your download rate. + //max_queued_disk_bytes, + + // the number of seconds to wait for a handshake response from a peer. + // If no response is received within this time, the peer is + // disconnected. + //handshake_timeout, + + // ``send_buffer_low_watermark`` the minimum send buffer target size + // (send buffer includes bytes pending being read from disk). For good + // and snappy seeding performance, set this fairly high, to at least + // fit a few blocks. This is essentially the initial window size which + // will determine how fast we can ramp up the send rate + // + // if the send buffer has fewer bytes than ``send_buffer_watermark``, + // we'll read another 16kB block onto it. If set too small, upload + // rate capacity will suffer. If set too high, memory will be wasted. + // The actual watermark may be lower than this in case the upload rate + // is low, this is the upper limit. + // + // the current upload rate to a peer is multiplied by this factor to + // get the send buffer watermark. The factor is specified as a + // percentage. i.e. 50 -> 0.5 This product is clamped to the + // ``send_buffer_watermark`` setting to not exceed the max. For high + // speed upload, this should be set to a greater value than 100. For + // high capacity connections, setting this higher can improve upload + // performance and disk throughput. Setting it too high may waste RAM + // and create a bias towards read jobs over write jobs. + //send_buffer_low_watermark, + //send_buffer_watermark, + //send_buffer_watermark_factor, + + // ``choking_algorithm`` specifies which algorithm to use to determine + // which peers to unchoke. + // + // The options for choking algorithms are: + // + // * ``fixed_slots_choker`` is the traditional choker with a fixed + // number of unchoke slots (as specified by + // ``settings_pack::unchoke_slots_limit``). + // + // * ``rate_based_choker`` opens up unchoke slots based on the upload + // rate achieved to peers. The more slots that are opened, the + // marginal upload rate required to open up another slot increases. + // + // * ``bittyrant_choker`` attempts to optimize download rate by + // finding the reciprocation rate of each peer individually and + // prefers peers that gives the highest *return on investment*. It + // still allocates all upload capacity, but shuffles it around to + // the best peers first. For this choker to be efficient, you need + // to set a global upload rate limit + // (``settings_pack::upload_rate_limit``). For more information + // about this choker, see the paper_. This choker is not fully + // implemented nor tested. + // + // .. _paper: http://bittyrant.cs.washington.edu/#papers + // + // ``seed_choking_algorithm`` controls the seeding unchoke behavior. + // The available options are: + // + // * ``round_robin`` which round-robins the peers that are unchoked + // when seeding. This distributes the upload bandwidht uniformly and + // fairly. It minimizes the ability for a peer to download everything + // without redistributing it. + // + // * ``fastest_upload`` unchokes the peers we can send to the fastest. + // This might be a bit more reliable in utilizing all available + // capacity. + // + // * ``anti_leech`` prioritizes peers who have just started or are + // just about to finish the download. The intention is to force + // peers in the middle of the download to trade with each other. + //choking_algorithm, + //seed_choking_algorithm, + + // ``cache_size`` is the disk write and read cache. It is specified + // in units of 16 KiB blocks. Buffers that are part of a peer's send + // or receive buffer also count against this limit. Send and receive + // buffers will never be denied to be allocated, but they will cause + // the actual cached blocks to be flushed or evicted. If this is set + // to -1, the cache size is automatically set based on the amount of + // physical RAM on the machine. If the amount of physical RAM cannot + // be determined, it's set to 1024 (= 16 MiB). + // + // ``cache_expiry`` is the number of seconds from the last cached write + // to a piece in the write cache, to when it's forcefully flushed to + // disk. Default is 60 second. + // + // On 32 bit builds, the effective cache size will be limited to 3/4 of + // 2 GiB to avoid exceeding the virtual address space limit. + //cache_size, + + //cache_expiry, + + // determines how files are opened when they're in read only mode + // versus read and write mode. The options are: + // + // enable_os_cache + // This is the default and files are opened normally, with the OS + // caching reads and writes. + // disable_os_cache + // This opens all files in no-cache mode. This corresponds to the + // OS not letting blocks for the files linger in the cache. This + // makes sense in order to avoid the bittorrent client to + // potentially evict all other processes' cache by simply handling + // high throughput and large files. If libtorrent's read cache is + // disabled, enabling this may reduce performance. + // + // One reason to disable caching is that it may help the operating + // system from growing its file cache indefinitely. + //disk_io_write_mode, + //disk_io_read_mode, + + // this is the first port to use for binding outgoing connections to. + // This is useful for users that have routers that allow QoS settings + // based on local port. when binding outgoing connections to specific + // ports, ``num_outgoing_ports`` is the size of the range. It should + // be more than a few + // + // .. warning:: setting outgoing ports will limit the ability to keep + // multiple connections to the same client, even for different + // torrents. It is not recommended to change this setting. Its main + // purpose is to use as an escape hatch for cheap routers with QoS + // capability but can only classify flows based on port numbers. + // + // It is a range instead of a single port because of the problems with + // failing to reconnect to peers if a previous socket to that peer and + // port is in ``TIME_WAIT`` state. + //outgoing_port, + //num_outgoing_ports, + + // ``peer_tos`` determines the TOS byte set in the IP header of every + // packet sent to peers (including web seeds). The default value for + // this is ``0x0`` (no marking). One potentially useful TOS mark is + // ``0x20``, this represents the *QBone scavenger service*. For more + // details, see QBSS_. + // + // .. _`QBSS`: http://qbone.internet2.edu/qbss/ + //peer_tos, + + // for auto managed torrents, these are the limits they are subject + // to. If there are too many torrents some of the auto managed ones + // will be paused until some slots free up. ``active_downloads`` and + // ``active_seeds`` controls how many active seeding and downloading + // torrents the queuing mechanism allows. The target number of active + // torrents is ``min(active_downloads + active_seeds, active_limit)``. + // ``active_downloads`` and ``active_seeds`` are upper limits on the + // number of downloading torrents and seeding torrents respectively. + // Setting the value to -1 means unlimited. + // + // For example if there are 10 seeding torrents and 10 downloading + // torrents, and ``active_downloads`` is 4 and ``active_seeds`` is 4, + // there will be 4 seeds active and 4 downloading torrents. If the + // settings are ``active_downloads`` = 2 and ``active_seeds`` = 4, + // then there will be 2 downloading torrents and 4 seeding torrents + // active. Torrents that are not auto managed are not counted against + // these limits. + // + // ``active_checking`` is the limit of number of simultaneous checking + // torrents. + // + // ``active_limit`` is a hard limit on the number of active (auto + // managed) torrents. This limit also applies to slow torrents. + // + // ``active_dht_limit`` is the max number of torrents to announce to + // the DHT. By default this is set to 88, which is no more than one + // DHT announce every 10 seconds. + // + // ``active_tracker_limit`` is the max number of torrents to announce + // to their trackers. By default this is 360, which is no more than + // one announce every 5 seconds. + // + // ``active_lsd_limit`` is the max number of torrents to announce to + // the local network over the local service discovery protocol. By + // default this is 80, which is no more than one announce every 5 + // seconds (assuming the default announce interval of 5 minutes). + // + // You can have more torrents *active*, even though they are not + // announced to the DHT, lsd or their tracker. If some peer knows + // about you for any reason and tries to connect, it will still be + // accepted, unless the torrent is paused, which means it won't accept + // any connections. + //active_downloads, + //active_seeds, + //active_checking, + //active_dht_limit, + //active_tracker_limit, + //active_lsd_limit, + //active_limit, + + // ``auto_manage_interval`` is the number of seconds between the + // torrent queue is updated, and rotated. + //auto_manage_interval, + + // this is the limit on the time a torrent has been an active seed + // (specified in seconds) before it is considered having met the seed + // limit criteria. See queuing_. + //seed_time_limit, + + // ``auto_scrape_interval`` is the number of seconds between scrapes + // of queued torrents (auto managed and paused torrents). Auto managed + // torrents that are paused, are scraped regularly in order to keep + // track of their downloader/seed ratio. This ratio is used to + // determine which torrents to seed and which to pause. + // + // ``auto_scrape_min_interval`` is the minimum number of seconds + // between any automatic scrape (regardless of torrent). In case there + // are a large number of paused auto managed torrents, this puts a + // limit on how often a scrape request is sent. + //auto_scrape_interval, + //auto_scrape_min_interval, + + // ``max_peerlist_size`` is the maximum number of peers in the list of + // known peers. These peers are not necessarily connected, so this + // number should be much greater than the maximum number of connected + // peers. Peers are evicted from the cache when the list grows passed + // 90% of this limit, and once the size hits the limit, peers are no + // longer added to the list. If this limit is set to 0, there is no + // limit on how many peers we'll keep in the peer list. + // + // ``max_paused_peerlist_size`` is the max peer list size used for + // torrents that are paused. This default to the same as + // ``max_peerlist_size``, but can be used to save memory for paused + // torrents, since it's not as important for them to keep a large peer + // list. + //max_peerlist_size, + //max_paused_peerlist_size, + + // this is the minimum allowed announce interval for a tracker. This + // is specified in seconds and is used as a sanity check on what is + // returned from a tracker. It mitigates hammering misconfigured + // trackers. + //min_announce_interval, + + // this is the number of seconds a torrent is considered active after + // it was started, regardless of upload and download speed. This is so + // that newly started torrents are not considered inactive until they + // have a fair chance to start downloading. + //auto_manage_startup, + + // ``seeding_piece_quota`` is the number of pieces to send to a peer, + // when seeding, before rotating in another peer to the unchoke set. + // It defaults to 3 pieces, which means that when seeding, any peer + // we've sent more than this number of pieces to will be unchoked in + // favour of a choked peer. + //seeding_piece_quota, + + // TODO: deprecate this + // ``max_rejects`` is the number of piece requests we will reject in a + // row while a peer is choked before the peer is considered abusive + // and is disconnected. + //max_rejects, + + // specifies the buffer sizes set on peer sockets. 0 (which is the + // default) means the OS default (i.e. don't change the buffer sizes). + // The socket buffer sizes are changed using setsockopt() with + // SOL_SOCKET/SO_RCVBUF and SO_SNDBUFFER. + //recv_socket_buffer_size, + //send_socket_buffer_size, + + // the max number of bytes a single peer connection's receive buffer is + // allowed to grow to. + //max_peer_recv_buffer_size, + + // ``read_cache_line_size`` is the number of blocks to read into the + // read cache when a read cache miss occurs. Setting this to 0 is + // essentially the same thing as disabling read cache. The number of + // blocks read into the read cache is always capped by the piece + // boundary. + // + // When a piece in the write cache has ``write_cache_line_size`` + // contiguous blocks in it, they will be flushed. Setting this to 1 + // effectively disables the write cache. + //read_cache_line_size, + //write_cache_line_size, + + // ``optimistic_disk_retry`` is the number of seconds from a disk + // write errors occur on a torrent until libtorrent will take it out + // of the upload mode, to test if the error condition has been fixed. + // + // libtorrent will only do this automatically for auto managed + // torrents. + // + // You can explicitly take a torrent out of upload only mode using + // set_upload_mode(). + //optimistic_disk_retry, + + // ``max_suggest_pieces`` is the max number of suggested piece indices + // received from a peer that's remembered. If a peer floods suggest + // messages, this limit prevents libtorrent from using too much RAM. + // It defaults to 10. + //max_suggest_pieces, + + // ``local_service_announce_interval`` is the time between local + // network announces for a torrent. By default, when local service + // discovery is enabled a torrent announces itself every 5 minutes. + // This interval is specified in seconds. + //local_service_announce_interval, + + // ``dht_announce_interval`` is the number of seconds between + // announcing torrents to the distributed hash table (DHT). + //dht_announce_interval, + + // ``udp_tracker_token_expiry`` is the number of seconds libtorrent + // will keep UDP tracker connection tokens around for. This is + // specified to be 60 seconds, and defaults to that. The higher this + // value is, the fewer packets have to be sent to the UDP tracker. In + // order for higher values to work, the tracker needs to be configured + // to match the expiration time for tokens. + //udp_tracker_token_expiry, + + // ``num_optimistic_unchoke_slots`` is the number of optimistic + // unchoke slots to use. It defaults to 0, which means automatic. + // Having a higher number of optimistic unchoke slots mean you will + // find the good peers faster but with the trade-off to use up more + // bandwidth. When this is set to 0, libtorrent opens up 20% of your + // allowed upload slots as optimistic unchoke slots. + //num_optimistic_unchoke_slots, + + // ``default_est_reciprocation_rate`` is the assumed reciprocation + // rate from peers when using the BitTyrant choker. This defaults to + // 14 kiB/s. If set too high, you will over-estimate your peers and be + // more altruistic while finding the true reciprocation rate, if it's + // set too low, you'll be too stingy and waste finding the true + // reciprocation rate. + // + // ``increase_est_reciprocation_rate`` specifies how many percent the + // estimated reciprocation rate should be increased by each unchoke + // interval a peer is still choking us back. This defaults to 20%. + // This only applies to the BitTyrant choker. + // + // ``decrease_est_reciprocation_rate`` specifies how many percent the + // estimated reciprocation rate should be decreased by each unchoke + // interval a peer unchokes us. This default to 3%. This only applies + // to the BitTyrant choker. + //default_est_reciprocation_rate, + //increase_est_reciprocation_rate, + //decrease_est_reciprocation_rate, + + // the max number of peers we accept from pex messages from a single + // peer. this limits the number of concurrent peers any of our peers + // claims to be connected to. If they claim to be connected to more + // than this, we'll ignore any peer that exceeds this limit + //max_pex_peers, + + // ``tick_interval`` specifies the number of milliseconds between + // internal ticks. This is the frequency with which bandwidth quota is + // distributed to peers. It should not be more than one second (i.e. + // 1000 ms). Setting this to a low value (around 100) means higher + // resolution bandwidth quota distribution, setting it to a higher + // value saves CPU cycles. + //tick_interval, + + // ``share_mode_target`` specifies the target share ratio for share + // mode torrents. This defaults to 3, meaning we'll try to upload 3 + // times as much as we download. Setting this very high, will make it + // very conservative and you might end up not downloading anything + // ever (and not affecting your share ratio). It does not make any + // sense to set this any lower than 2. For instance, if only 3 peers + // need to download the rarest piece, it's impossible to download a + // single piece and upload it more than 3 times. If the + // share_mode_target is set to more than 3, nothing is downloaded. + //share_mode_target, + + // ``upload_rate_limit`` and ``download_rate_limit`` sets + // the session-global limits of upload and download rate limits, in + // bytes per second. By default peers on the local network are not rate + // limited. + // + // A value of 0 means unlimited. + // + // For fine grained control over rate limits, including making them apply + // to local peers, see peer-classes_. + //upload_rate_limit, + //download_rate_limit, + + // ``unchoke_slots_limit`` is the max number of unchoked peers in the + // session. The number of unchoke slots may be ignored depending on + // what ``choking_algorithm`` is set to. + //unchoke_slots_limit, + + // ``connections_limit`` sets a global limit on the number of + // connections opened. The number of connections is set to a hard + // minimum of at least two per torrent, so if you set a too low + // connections limit, and open too many torrents, the limit will not + // be met. + //connections_limit, + + // ``connections_slack`` is the the number of incoming connections + // exceeding the connection limit to accept in order to potentially + // replace existing ones. + //connections_slack, + + // ``utp_target_delay`` is the target delay for uTP sockets in + // milliseconds. A high value will make uTP connections more + // aggressive and cause longer queues in the upload bottleneck. It + // cannot be too low, since the noise in the measurements would cause + // it to send too slow. The default is 50 milliseconds. + // ``utp_gain_factor`` is the number of bytes the uTP congestion + // window can increase at the most in one RTT. This defaults to 300 + // bytes. If this is set too high, the congestion controller reacts + // too hard to noise and will not be stable, if it's set too low, it + // will react slow to congestion and not back off as fast. + // + // ``utp_min_timeout`` is the shortest allowed uTP socket timeout, + // specified in milliseconds. This defaults to 500 milliseconds. The + // timeout depends on the RTT of the connection, but is never smaller + // than this value. A connection times out when every packet in a + // window is lost, or when a packet is lost twice in a row (i.e. the + // resent packet is lost as well). + // + // The shorter the timeout is, the faster the connection will recover + // from this situation, assuming the RTT is low enough. + // ``utp_syn_resends`` is the number of SYN packets that are sent (and + // timed out) before giving up and closing the socket. + // ``utp_num_resends`` is the number of times a packet is sent (and + // lost or timed out) before giving up and closing the connection. + // ``utp_connect_timeout`` is the number of milliseconds of timeout + // for the initial SYN packet for uTP connections. For each timed out + // packet (in a row), the timeout is doubled. ``utp_loss_multiplier`` + // controls how the congestion window is changed when a packet loss is + // experienced. It's specified as a percentage multiplier for + // ``cwnd``. By default it's set to 50 (i.e. cut in half). Do not + // change this value unless you know what you're doing. Never set it + // higher than 100. + //utp_target_delay, + //utp_gain_factor, + //utp_min_timeout, + //utp_syn_resends, + //utp_fin_resends, + //utp_num_resends, + //utp_connect_timeout, + + //utp_loss_multiplier, + + // The ``mixed_mode_algorithm`` determines how to treat TCP + // connections when there are uTP connections. Since uTP is designed + // to yield to TCP, there's an inherent problem when using swarms that + // have both TCP and uTP connections. If nothing is done, uTP + // connections would often be starved out for bandwidth by the TCP + // connections. This mode is ``prefer_tcp``. The ``peer_proportional`` + // mode simply looks at the current throughput and rate limits all TCP + // connections to their proportional share based on how many of the + // connections are TCP. This works best if uTP connections are not + // rate limited by the global rate limiter (which they aren't by + // default). + //mixed_mode_algorithm, + + // ``listen_queue_size`` is the value passed in to listen() for the + // listen socket. It is the number of outstanding incoming connections + // to queue up while we're not actively waiting for a connection to be + // accepted. The default is 5 which should be sufficient for any + // normal client. If this is a high performance server which expects + // to receive a lot of connections, or used in a simulator or test, it + // might make sense to raise this number. It will not take affect + // until the ``listen_interfaces`` settings is updated. + //listen_queue_size, + + // ``torrent_connect_boost`` is the number of peers to try to connect + // to immediately when the first tracker response is received for a + // torrent. This is a boost to given to new torrents to accelerate + // them starting up. The normal connect scheduler is run once every + // second, this allows peers to be connected immediately instead of + // waiting for the session tick to trigger connections. + // This may not be set higher than 255. + //torrent_connect_boost, + + // ``alert_queue_size`` is the maximum number of alerts queued up + // internally. If alerts are not popped, the queue will eventually + // fill up to this level. Once the alert queue is full, additional + // alerts will be dropped, and not delievered to the client. Once the + // client drains the queue, new alerts may be delivered again. In order + // to know that alerts have been dropped, see + // session_handle::dropped_alerts(). + //alert_queue_size, + + // ``max_metadata_size`` is the maximum allowed size (in bytes) to be + // received by the metadata extension, i.e. magnet links. + //max_metadata_size, + + // the number of blocks to keep outstanding at any given time when + // checking torrents. Higher numbers give faster re-checks but uses + // more memory. Specified in number of 16 kiB blocks + //checking_mem_usage, + + // if set to > 0, pieces will be announced to other peers before they + // are fully downloaded (and before they are hash checked). The + // intention is to gain 1.5 potential round trip times per downloaded + // piece. When non-zero, this indicates how many milliseconds in + // advance pieces should be announced, before they are expected to be + // completed. + //predictive_piece_announce, + + // for some aio back-ends, ``aio_threads`` specifies the number of + // io-threads to use, and ``aio_max`` the max number of outstanding + // jobs. + //aio_threads, + //aio_max, + + // ``tracker_backoff`` determines how aggressively to back off from + // retrying failing trackers. This value determines *x* in the + // following formula, determining the number of seconds to wait until + // the next retry: + // + // delay = 5 + 5 * x / 100 * fails^2 + // + // This setting may be useful to make libtorrent more or less + // aggressive in hitting trackers. + //tracker_backoff, + + // when a seeding torrent reaches either the share ratio (bytes up / + // bytes down) or the seed time ratio (seconds as seed / seconds as + // downloader) or the seed time limit (seconds as seed) it is + // considered done, and it will leave room for other torrents. These + // are specified as percentages. Torrents that are considered done will + // still be allowed to be seeded, they just won't have priority anymore. + // For more, see queuing_. + //share_ratio_limit, + //seed_time_ratio_limit, + + // peer_turnover is the percentage of peers to disconnect every + // turnover peer_turnover_interval (if we're at the peer limit), this + // is specified in percent when we are connected to more than limit * + // peer_turnover_cutoff peers disconnect peer_turnover fraction of the + // peers. It is specified in percent peer_turnover_interval is the + // interval (in seconds) between optimistic disconnects if the + // disconnects happen and how many peers are disconnected is + // controlled by peer_turnover and peer_turnover_cutoff + //peer_turnover, + //peer_turnover_cutoff, + //peer_turnover_interval, + + // this setting controls the priority of downloading torrents over + // seeding or finished torrents when it comes to making peer + // connections. Peer connections are throttled by the connection_speed + // and the half-open connection limit. This makes peer connections a + // limited resource. Torrents that still have pieces to download are + // prioritized by default, to avoid having many seeding torrents use + // most of the connection attempts and only give one peer every now + // and then to the downloading torrent. libtorrent will loop over the + // downloading torrents to connect a peer each, and every n:th + // connection attempt, a finished torrent is picked to be allowed to + // connect to a peer. This setting controls n. + //connect_seed_every_n_download, + + // the max number of bytes to allow an HTTP response to be when + // announcing to trackers or downloading .torrent files via the + // ``url`` provided in ``add_torrent_params``. + //max_http_recv_buffer_size, + + // if binding to a specific port fails, should the port be incremented + // by one and tried again? This setting specifies how many times to + // retry a failed port bind + //max_retry_port_bind, + + // a bitmask combining flags from alert::category_t defining which + // kinds of alerts to receive + //alert_mask, + + // control the settings for incoming and outgoing connections + // respectively. see enc_policy enum for the available options. + // Keep in mind that protocol encryption degrades performance in + // several respects: + // + // 1. It prevents "zero copy" disk buffers being sent to peers, since + // each peer needs to mutate the data (i.e. encrypt it) the data + // must be copied per peer connection rather than sending the same + // buffer to multiple peers. + // 2. The encryption itself requires more CPU than plain bittorrent + // protocol. The highest cost is the Diffie Hellman exchange on + // connection setup. + // 3. The encryption handshake adds several round-trips to the + // connection setup, and delays transferring data. + //out_enc_policy, + //in_enc_policy, + + // determines the encryption level of the connections. This setting + // will adjust which encryption scheme is offered to the other peer, + // as well as which encryption scheme is selected by the client. See + // enc_level enum for options. + //allowed_enc_level, + + // the download and upload rate limits for a torrent to be considered + // active by the queuing mechanism. A torrent whose download rate is + // less than ``inactive_down_rate`` and whose upload rate is less than + // ``inactive_up_rate`` for ``auto_manage_startup`` seconds, is + // considered inactive, and another queued torrent may be started. + // This logic is disabled if ``dont_count_slow_torrents`` is false. + //inactive_down_rate, + //inactive_up_rate, + + // proxy to use, defaults to none. see proxy_type_t. + //proxy_type, + + // the port of the proxy server + //proxy_port, + + // sets the i2p_ SAM bridge port to connect to. set the hostname with + // the ``i2p_hostname`` setting. + // + // .. _i2p: http://www.i2p2.de + //i2p_port, + + // this determines the max number of volatile disk cache blocks. If the + // number of volatile blocks exceed this limit, other volatile blocks + // will start to be evicted. A disk cache block is volatile if it has + // low priority, and should be one of the first blocks to be evicted + // under pressure. For instance, blocks pulled into the cache as the + // result of calculating a piece hash are volatile. These blocks don't + // represent potential interest among peers, so the value of keeping + // them in the cache is limited. + //cache_size_volatile, + + // The maximum request range of an url seed in bytes. This value + // defines the largest possible sequential web seed request. Default + // is 16 * 1024 * 1024. Lower values are possible but will be ignored + // if they are lower then piece size. + // This value should be related to your download speed to prevent + // libtorrent from creating too many expensive http requests per + // second. You can select a value as high as you want but keep in mind + // that libtorrent can't create parallel requests if the first request + // did already select the whole file. + // If you combine bittorrent seeds with web seeds and pick strategies + // like rarest first you may find your web seed requests split into + // smaller parts because we don't download already picked pieces + // twice. + //urlseed_max_request_bytes, + + // time to wait until a new retry of a web seed name lookup + //web_seed_name_lookup_retry, + + // the number of seconds between closing the file opened the longest + // ago. 0 means to disable the feature. The purpose of this is to + // periodically close files to trigger the operating system flushing + // disk cache. Specifically it has been observed to be required on + // windows to not have the disk cache grow indefinitely. + // This defaults to 120 seconds on windows, and disabled on other + // systems. + //close_file_interval, + + // the max number of web seeds to have connected per torrent at any + // given time. + //max_web_seed_connections, + + // the number of seconds before the internal host name resolver + // considers a cache value timed out, negative values are interpreted + // as zero. + //resolver_cache_timeout, + + // this is the client name and version identifier sent to peers in the + // handshake message. If this is an empty string, the user_agent is + // used instead + //settings.set_str(settings_pack:handshake_client_version, "Dynamic"); //todo: add version to user agent + + // ``outgoing_interfaces`` + // sets the network interface this session will use when it opens + // outgoing connections. By default, it binds outgoing connections to + // INADDR_ANY and port 0 (i.e. let the OS decide). Ths parameter must + // be a string containing one or more, comma separated, adapter names. + // Adapter names on unix systems are of the form "eth0", "eth1", + // "tun0", etc. When specifying multiple interfaces, they will be + // assigned in round-robin order. This may be useful for clients that + // are multi-homed. Binding an outgoing connection to a local IP does + // not necessarily make the connection via the associated NIC/Adapter. + // Setting this to an empty string will disable binding of outgoing + // connections. + //settings.set_bool(settings_pack::outgoing_interfaces, false); + + // ``proxy_hostname`` + // when using a poxy, this is the hostname where the proxy is running + // see proxy_type. + //proxy_hostname, + + // when using a proxy, these are the credentials (if any) to use when + // connecting to it. see proxy_type + //proxy_username, + //proxy_password, + + // sets the i2p_ SAM bridge to connect to. set the port with the + // ``i2p_port`` setting. + // + // .. _i2p: http://www.i2p2.de + //i2p_hostname, + + // this is the fingerprint for the client. It will be used as the + // prefix to the peer_id. If this is 20 bytes (or longer) it will be + // truncated to 20 bytes and used as the entire peer-id + // + // There is a utility function, generate_fingerprint() that can be used + // to generate a standard client peer ID fingerprint prefix. + //peer_fingerprint, } diff --git a/src/dht/dhtsettings.h b/src/dht/dhtsettings.h index 19631e0ede..373282dc03 100644 --- a/src/dht/dhtsettings.h +++ b/src/dht/dhtsettings.h @@ -7,10 +7,14 @@ #include +static const int MIN_DHT_PROTO_VERSION = 71000; + class CDHTSettings { private: - libtorrent::settings_pack settings; + std::string listen_interfaces; + std::string dht_bootstrap_nodes; + std::string user_agent; public: @@ -20,7 +24,8 @@ class CDHTSettings { private: - void LoadSettings(); + void LoadSettings(); + void LoadPeerList(); }; From a302f8aabe588c1cf0d1830db01e9494c6de9ff2 Mon Sep 17 00:00:00 2001 From: Spencer Lievens <36229929+Duality-CDOO@users.noreply.github.com> Date: Sat, 22 Sep 2018 22:28:35 +0200 Subject: [PATCH 0231/1653] Fix horizontal spacer names --- src/qt/forms/sendcoinsdialog.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index fba05800d1..e301e9203f 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -1343,7 +1343,7 @@ border-radius: 4px; - + Qt::Horizontal @@ -1377,7 +1377,7 @@ border-radius: 4px; - + Qt::Horizontal @@ -1465,7 +1465,7 @@ border-radius: 4px; - + From 3bb39cb69a73c54958ad9dbd3410b8c16730263f Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sat, 22 Sep 2018 22:24:49 -0500 Subject: [PATCH 0232/1653] [DHT] Add LibTorrent network bootstrap functions - Start LibTorrent DHT network with boost threads - Log DHT status in dht-state.log file - Add DHT mutable key value pair put data function - Add DHT mutable key value pair get data function --- src/Makefile.am | 2 + src/dht/bootstrap.cpp | 259 ++++++++++++++++++++++++++++++++++++++++ src/dht/bootstrap.h | 25 ++++ src/dht/dhtsettings.cpp | 11 +- src/dht/dhtsettings.h | 13 +- src/init.cpp | 11 +- 6 files changed, 308 insertions(+), 13 deletions(-) create mode 100644 src/dht/bootstrap.cpp create mode 100644 src/dht/bootstrap.h diff --git a/src/Makefile.am b/src/Makefile.am index 7a5456af13..bb5902f27c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -111,6 +111,7 @@ DYNAMIC_CORE_H = \ bdap/entrylink.h \ bdap/identity.h \ dbwrapper.h \ + dht/bootstrap.h \ dht/dhtsettings.h \ dht/keyed25519.h \ dynode.h \ @@ -248,6 +249,7 @@ libdynamic_server_a_SOURCES = \ bdap/entrylink.cpp \ bdap/identity.cpp \ dbwrapper.cpp \ + dht/bootstrap.cpp \ dht/dhtsettings.cpp \ dht/keyed25519.cpp \ dynode.cpp \ diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp new file mode 100644 index 0000000000..7e377cbdf8 --- /dev/null +++ b/src/dht/bootstrap.cpp @@ -0,0 +1,259 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#include "dht/bootstrap.h" + +#include "chainparams.h" +#include "dht/dhtsettings.h" +#include "dynode-sync.h" +#include "net.h" +#include "util.h" +#include "validation.h" + +#include "libtorrent/hex.hpp" // for to_hex +#include "libtorrent/alert_types.hpp" +#include "libtorrent/bencode.hpp" // for bencode() +#include "libtorrent/kademlia/item.hpp" // for sign_mutable_item +#include "libtorrent/kademlia/ed25519.hpp" +#include "libtorrent/span.hpp" + +#include +#include + +#include +#include // for snprintf +#include // for PRId64 et.al. +#include +#include + +using namespace libtorrent; + +session *pTorrentDHTSession = NULL; + +static alert* wait_for_alert(session* dhtSession, int alert_type) +{ + LogPrintf("DHTTorrentNetwork -- wait_for_alert start.\n"); + alert* ret = nullptr; + bool found = false; + while (!found) + { + dhtSession->wait_for_alert(seconds(5)); + + std::vector alerts; + dhtSession->pop_alerts(&alerts); + for (std::vector::iterator i = alerts.begin() + , end(alerts.end()); i != end; ++i) + { + if ((*i)->type() != alert_type) + { + //print some alerts? + // LogPrintf("DHTTorrentNetwork -- alert = .\n"); + continue; + } + ret = *i; + found = true; + } + } + LogPrintf("DHTTorrentNetwork -- wait_for_alert complete.\n"); + return ret; +} + +static void bootstrap(lt::session* dhtSession) +{ + LogPrintf("DHTTorrentNetwork -- bootstrapping.\n"); + wait_for_alert(dhtSession, dht_bootstrap_alert::alert_type); + LogPrintf("DHTTorrentNetwork -- bootstrap done.\n"); +} + +static std::string get_log_path() +{ + boost::filesystem::path path = GetDataDir() / "dht-state.dat"; + return path.string(); +} + +static int save_dht_state(session* dhtSession) +{ + entry torrentEntry; + dhtSession->save_state(torrentEntry, session::save_dht_state); + std::vector state; + bencode(std::back_inserter(state), torrentEntry); + std::fstream f(get_log_path().c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); + f.write(state.data(), state.size()); + return 0; +} + +static void load_dht_state(session* dhtSession) +{ + std::fstream f(get_log_path().c_str(), std::ios_base::in | std::ios_base::binary | std::ios_base::ate); + + auto const size = f.tellg(); + if (static_cast(size) <= 0) return; + f.seekg(0, std::ios_base::beg); + + std::vector state; + state.resize(static_cast(size)); + + f.read(state.data(), state.size()); + if (f.fail()) + { + LogPrintf("DHTTorrentNetwork -- failed to read dht-state.log\n"); + return; + } + + bdecode_node e; + error_code ec; + bdecode(state.data(), state.data() + state.size(), e, ec); + if (ec) { + LogPrintf("DHTTorrentNetwork -- failed to parse dht-state.log file: (%d) %s\n", ec.value(), ec.message()); + } + else + { + LogPrintf("DHTTorrentNetwork -- load dht state from dht-state.log\n"); + dhtSession->load_state(e); + } +} + +void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman) +{ + LogPrintf("DHTTorrentNetwork -- started\n"); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("dht-torrent-network"); + + boost::shared_ptr coinbaseScript; + + try { + CDHTSettings settings; + // Busy-wait for the network to come online so we get a full list of Dynodes + do { + bool fvNodesEmpty = connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0; + if (!fvNodesEmpty && !IsInitialBlockDownload() && dynodeSync.IsSynced() && dynodeSync.IsBlockchainSynced()) + break; + MilliSleep(1000); + } while (true); + + // boot strap the DHT LibTorrent network + // with current peers and Dynodes + settings.LoadSettings(); + pTorrentDHTSession = new session(settings.GetSettingsPack()); + load_dht_state(pTorrentDHTSession); + bootstrap(pTorrentDHTSession); + save_dht_state(pTorrentDHTSession); + if (!pTorrentDHTSession) { + throw std::runtime_error("DHT Torrent network bootstraping error."); + } + while (true) {} + } + catch (const boost::thread_interrupted&) + { + LogPrintf("DHTTorrentNetwork -- terminated\n"); + throw; + } + catch (const std::runtime_error& e) + { + LogPrintf("DHTTorrentNetwork -- runtime error: %s\n", e.what()); + return; + } +} + +void StopTorrentDHTNetwork() +{ + static boost::thread_group* dhtTorrentThreads; + if (dhtTorrentThreads != NULL) + { + dhtTorrentThreads->interrupt_all(); + delete dhtTorrentThreads; + dhtTorrentThreads = NULL; + LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork stopped.\n"); + } + else { + LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork dhtTorrentThreads is null. Stop not needed.\n"); + } +} + +void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman) +{ + LogPrintf("DHTTorrentNetwork -- Log file = %s.\n", get_log_path()); + static boost::thread_group* dhtTorrentThreads; + + StopTorrentDHTNetwork(); + + dhtTorrentThreads = new boost::thread_group(); + dhtTorrentThreads->create_thread(boost::bind(&DHTTorrentNetwork, boost::cref(chainparams), boost::ref(connman))); +} + +bool GetDHTMutableData(std::array public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence) +{ + //TODO: DHT add locks + LogPrintf("DHTTorrentNetwork -- PutMutableData started.\n"); + + if (!pTorrentDHTSession) + return false; + + bootstrap(pTorrentDHTSession); + + pTorrentDHTSession->dht_get_item(public_key, entrySalt); + LogPrintf("DHTTorrentNetwork -- MGET: %s, salt = %s\n", aux::to_hex(public_key), entrySalt); + + bool authoritative = false; + while (!authoritative) + { + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); + + dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); + + authoritative = dhtGetAlert->authoritative; + entryValue = dhtGetAlert->item.to_string(); + lastSequence = dhtGetAlert->seq; + LogPrintf("%s: %s\n", authoritative ? "auth" : "non-auth", entryValue); + } + save_dht_state(pTorrentDHTSession); + + return true; +} + +static void put_string( + entry& e + ,std::array& sig + ,std::int64_t& seq + ,std::string const& salt + ,std::array const& pk + ,std::array const& sk + ,char const* str) +{ + using dht::sign_mutable_item; + + e = std::string(str); + std::vector buf; + bencode(std::back_inserter(buf), e); + dht::signature sign; + ++seq; + sign = sign_mutable_item(buf, salt, dht::sequence_number(seq) + , dht::public_key(pk.data()) + , dht::secret_key(sk.data())); + sig = sign.bytes; +} + +bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence + ,char const* dhtValue, std::string& message) +{ + //TODO: (DHT) add locks + LogPrintf("DHTTorrentNetwork -- PutMutableData started.\n"); + + if (!pTorrentDHTSession) + return false; + + bootstrap(pTorrentDHTSession); + + entry e; + std::array sig; + pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_string, e, sig, lastSequence + 1, entrySalt, public_key, private_key, dhtValue)); + + LogPrintf("DHTTorrentNetwork -- MPUT public key: %s, salt = %s\n", aux::to_hex(public_key), entrySalt); + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_put_alert::alert_type); + dht_put_alert* dhtPutAlert = alert_cast(dhtAlert); + message = dhtPutAlert->message(); + LogPrintf("%s\n", message); + save_dht_state(pTorrentDHTSession); + + return true; +} \ No newline at end of file diff --git a/src/dht/bootstrap.h b/src/dht/bootstrap.h new file mode 100644 index 0000000000..101fd0f9b8 --- /dev/null +++ b/src/dht/bootstrap.h @@ -0,0 +1,25 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_DHT_BOOTSTRAP_H +#define DYNAMIC_DHT_BOOTSTRAP_H + +#include "libtorrent/session.hpp" + +class CChainParams; +class CConnman; +class CKeyEd25519; + +/** Start the DHT libtorrent network threads */ +void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman); +/** Stop the DHT libtorrent network threads */ +void StopTorrentDHTNetwork(); +/** Get a mutable entry in the libtorrent DHT */ +bool GetDHTMutableData(std::array public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence); +/** Set a mutable entry in the libtorrent DHT */ +bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence + ,char const* dhtValue, std::string& message); + +extern libtorrent::session *pTorrentDHTSession; + +#endif // DYNAMIC_DHT_BOOTSTRAP_H diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp index 17d8084fdf..e3c4269b71 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/dhtsettings.cpp @@ -8,6 +8,7 @@ #include "dynodeman.h" #include "net.h" #include "primitives/transaction.h" +#include "util.h" using namespace libtorrent; @@ -17,8 +18,6 @@ CDHTSettings::CDHTSettings() // Use ports 33307, 33317, 33327, 33337 and 33347 listen_interfaces = "0.0.0.0:33307,[::]:33307,0.0.0.0:33317,[::]:33317,0.0.0.0:33327," "[::]:33327,0.0.0.0:33337,[::]:33337,0.0.0.0:33347,[::]:33347"; - LoadPeerList(); - LoadSettings(); } void CDHTSettings::LoadPeerList() @@ -42,11 +41,17 @@ void CDHTSettings::LoadPeerList() } } } - dht_bootstrap_nodes = strPeerList.substr(0, strPeerList.size()-1); + if (strPeerList.size() > 1) { + dht_bootstrap_nodes = strPeerList.substr(0, strPeerList.size()-1); + } + // TODO: (DHT) Remove port number and do not add duplicates + LogPrintf("CDHTSettings::LoadPeerList -- dht_bootstrap_nodes = %s.\n", dht_bootstrap_nodes); } void CDHTSettings::LoadSettings() { + LoadPeerList(); + settings.set_bool(settings_pack::enable_dht, false); settings.set_int(settings_pack::alert_mask, 0xffffffff); session newSession(settings); diff --git a/src/dht/dhtsettings.h b/src/dht/dhtsettings.h index 373282dc03..72e7e54613 100644 --- a/src/dht/dhtsettings.h +++ b/src/dht/dhtsettings.h @@ -1,4 +1,3 @@ - // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License @@ -7,7 +6,7 @@ #include -static const int MIN_DHT_PROTO_VERSION = 71000; +static constexpr int MIN_DHT_PROTO_VERSION = 71000; class CDHTSettings { private: @@ -19,14 +18,12 @@ class CDHTSettings { public: CDHTSettings(); - - libtorrent::settings_pack GetSettingsPack() const; + void LoadSettings(); + libtorrent::settings_pack GetSettingsPack() const { return settings; } private: - - void LoadSettings(); void LoadPeerList(); -}; +}; -#endif // DYNAMIC_DHT_DHTSETTINGS_H +#endif // DYNAMIC_DHT_DHTSETTINGS_H \ No newline at end of file diff --git a/src/init.cpp b/src/init.cpp index 6d8cd85c36..22c60d2a2d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -20,6 +20,7 @@ #include "checkpoints.h" #include "bdap/domainentrydb.h" #include "dht/keyed25519.h" +#include "dht/bootstrap.h" #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeconfig.h" @@ -236,6 +237,7 @@ void PrepareShutdown() StopREST(); StopRPC(); StopHTTPServer(); + StopTorrentDHTNetwork(); #ifdef ENABLE_WALLET if (pwalletMain) pwalletMain->Flush(false); @@ -1498,7 +1500,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) delete pFluidSovereignDB; // BDAP Services DB's delete pDomainEntryDB; - + + // LibTorrent DHT Netowrk Services + delete pTorrentDHTSession; + pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); @@ -1513,7 +1518,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Init BDAP Services DB's pDomainEntryDB = new CDomainEntryDB(nTotalCache * 35, false, fReindex, obfuscate); - + if (fReindex) { pblocktree->WriteReindexing(true); //If we're reindexing in prune mode, wipe away unusable block files and all undo data files @@ -1854,6 +1859,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Generate coins in the background GenerateDynamics(GetBoolArg("-gen", DEFAULT_GENERATE), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), chainparams, connman); + // Start the DHT Torrent network in the background + StartTorrentDHTNetwork(chainparams, connman); // ********************************************************* Step 13: finished SetRPCWarmupFinished(); From 842bfa8631337250edf48bfe00d79648a2b4def9 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 20 Sep 2018 17:25:40 -0500 Subject: [PATCH 0233/1653] [DHT] Bump min protocol --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index bbc8911512..2da0b25d14 100644 --- a/src/version.h +++ b/src/version.h @@ -21,7 +21,7 @@ static const int INIT_PROTO_VERSION = 209; static const int GETHEADERS_VERSION = 60800; //! disconnect from peers older than this proto version -static const int MIN_PEER_PROTO_VERSION = 70600; +static const int MIN_PEER_PROTO_VERSION = 71000; //! nTime field added to CAddress, starting with this version; //! if possible, avoid requesting addresses nodes older than this From 89d86c3da30b29b79a6400a729b353193387220e Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 23 Sep 2018 03:12:36 -0500 Subject: [PATCH 0234/1653] [BDAP] Add recipient link and accept link classes --- src/Makefile.am | 2 + src/bdap/linking.cpp | 121 ++++++++++++++++++++++++++++++ src/bdap/linking.h | 173 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 296 insertions(+) create mode 100644 src/bdap/linking.cpp create mode 100644 src/bdap/linking.h diff --git a/src/Makefile.am b/src/Makefile.am index bb5902f27c..c505248dca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,6 +110,7 @@ DYNAMIC_CORE_H = \ bdap/entrycheckpoints.h \ bdap/entrylink.h \ bdap/identity.h \ + bdap/linking.h \ dbwrapper.h \ dht/bootstrap.h \ dht/dhtsettings.h \ @@ -248,6 +249,7 @@ libdynamic_server_a_SOURCES = \ bdap/entrycheckpoints.cpp \ bdap/entrylink.cpp \ bdap/identity.cpp \ + bdap/linking.cpp \ dbwrapper.cpp \ dht/bootstrap.cpp \ dht/dhtsettings.cpp \ diff --git a/src/bdap/linking.cpp b/src/bdap/linking.cpp new file mode 100644 index 0000000000..776763f312 --- /dev/null +++ b/src/bdap/linking.cpp @@ -0,0 +1,121 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: license + +#include "bdap/linking.h" + +#include "bdap/domainentry.h" +#include "hash.h" +#include "script/script.h" +#include "streams.h" + +bool CRequestLink::UnserializeFromTx(const CTransaction& tx) +{ + std::vector vchData; + std::vector vchHash; + int nOut; + if(!GetBDAPData(tx, vchData, vchHash, nOut)) + { + SetNull(); + return false; + } + if(!UnserializeFromData(vchData, vchHash)) + { + return false; + } + return true; +} + +void CRequestLink::Serialize(std::vector& vchData) +{ + CDataStream dsRequestLink(SER_NETWORK, PROTOCOL_VERSION); + dsRequestLink << *this; + vchData = std::vector(dsRequestLink.begin(), dsRequestLink.end()); +} + +bool CRequestLink::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsRequestLink(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsRequestLink >> *this; + + std::vector vchRequestLinkData; + Serialize(vchRequestLinkData); + const uint256 &calculatedHash = Hash(vchRequestLinkData.begin(), vchRequestLinkData.end()); + const std::vector &vchRandRequestLink = vchFromValue(calculatedHash.GetHex()); + if(vchRandRequestLink != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +CharString CRequestLink::SharedSignPublicKey() +{ + CharString vchReturn; + return vchReturn; +} + +bool CRequestLink::ValidateValues(std::string& errorMessage) +{ + return true; +} + + +bool CRequestLink::IsMyLinkRequest(const CTransaction& tx) +{ + return false; +} + +void CAcceptLink::Serialize(std::vector& vchData) +{ + CDataStream dsAcceptLink(SER_NETWORK, PROTOCOL_VERSION); + dsAcceptLink << *this; + vchData = std::vector(dsAcceptLink.begin(), dsAcceptLink.end()); +} + +bool CAcceptLink::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsAcceptLink(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsAcceptLink >> *this; + + std::vector vchAcceptLinkData; + Serialize(vchAcceptLinkData); + const uint256 &calculatedHash = Hash(vchAcceptLinkData.begin(), vchAcceptLinkData.end()); + const std::vector &vchRandAcceptLink = vchFromValue(calculatedHash.GetHex()); + if(vchRandAcceptLink != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CAcceptLink::ValidateValues(std::string& errorMessage) +{ + // TODO: (BDAP) implement validation + return true; +} + +// TODO: (BDAP) implement BDAP encryption by converting ed25519 private key to curve25519 +/* +CharString GetEncryptedLinkMessage(const CRequestLink& requestLink) +{ + +} + +CharString GetEncryptedLinkMessage(const CRequestLink& requestLink, const CAcceptLink& acceptLink) +{ + + +} +*/ \ No newline at end of file diff --git a/src/bdap/linking.h b/src/bdap/linking.h new file mode 100644 index 0000000000..526777e0dc --- /dev/null +++ b/src/bdap/linking.h @@ -0,0 +1,173 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: license + +#ifndef DYNAMIC_BDAP_LINKING_H +#define DYNAMIC_BDAP_LINKING_H + +#include "bdap.h" +#include "serialize.h" +#include "uint256.h" + +class CTransaction; + +// CRequestLink are stored serilzed and encrypted in a BDAP OP_RETURN transaction. +// The link request recipient can decrypt the BDAP OP_RETURN transaction +// and get the needed information to accept the link request +// It is used to bootstrap the linkage relationship with a new set of public keys + +// OP_RETURN Format: +// CAcceptLink.RecipientPublicKey.Encrypt(CRequestLink.SharedSymmetricPrivKey).ToHex() + space + +// CRequestLink.RequestorPublicKey.Encrypt(CRequestLink.SharedSymmetricPrivKey).ToHex() + spcae + +// CRequestLink.SharedSymmetricPrivKey.Encrypt(Serialize(CRequestLink)).ToHex() +class CRequestLink { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString RequestorFullObjectPath; // Requestor's BDAP object path + CharString RecipientFullObjectPath; // Recipient's BDAP object path + // The SharedPrivateKey will allow both parties to update mutable entries on DHT torrent network + CharString SharedPrivateKey; // ed25519 derived key new/unique for this link + CharString RequestorPublicKey; // ed25519 derived public key new/unique for this link + CharString SharedSymmetricPrivKey; // AES symmetric private key unique to this link request + + unsigned int nHeight; + uint64_t nExpireTime; + uint256 txHash; + + CRequestLink() { + SetNull(); + } + + CRequestLink(const CTransaction &tx) { + SetNull(); + UnserializeFromTx(tx); + } + + inline void SetNull() + { + nVersion = CRequestLink::CURRENT_VERSION; + RequestorFullObjectPath.clear(); + RecipientFullObjectPath.clear(); + SharedPrivateKey.clear(); + RequestorPublicKey.clear(); + SharedSymmetricPrivKey.clear(); + nHeight = 0; + nExpireTime = 0; + txHash.SetNull(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(RequestorFullObjectPath); + READWRITE(RecipientFullObjectPath); + READWRITE(SharedPrivateKey); + READWRITE(RequestorPublicKey); + READWRITE(SharedSymmetricPrivKey); + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nExpireTime)); + READWRITE(txHash); + } + + inline friend bool operator==(const CRequestLink &a, const CRequestLink &b) { + return (a.RequestorFullObjectPath == b.RequestorFullObjectPath && a.RecipientFullObjectPath == b.RecipientFullObjectPath + && a.SharedPrivateKey == b.SharedPrivateKey && a.RequestorPublicKey == b.RequestorPublicKey + && a.SharedSymmetricPrivKey == b.SharedSymmetricPrivKey); + } + + inline friend bool operator!=(const CRequestLink &a, const CRequestLink &b) { + return !(a == b); + } + + inline CRequestLink operator=(const CRequestLink &b) { + nVersion = b.nVersion; + RequestorFullObjectPath = b.RequestorFullObjectPath; + RecipientFullObjectPath = b.RecipientFullObjectPath; + SharedPrivateKey = b.SharedPrivateKey; + RequestorPublicKey = b.RequestorPublicKey; + SharedSymmetricPrivKey = b.SharedSymmetricPrivKey; + nHeight = b.nHeight; + nExpireTime = b.nExpireTime; + txHash = b.txHash; + return *this; + } + + inline bool IsNull() const { return (RequestorFullObjectPath.empty()); } + bool UnserializeFromTx(const CTransaction &tx); + bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); + void Serialize(std::vector& vchData); + + CharString SharedSignPublicKey(); //derive from SharedPrivateKey + bool ValidateValues(std::string& errorMessage); + bool IsMyLinkRequest(const CTransaction& tx); +}; + +// CAcceptLink are stored serilzed and encrypted in a LibTorrent DHT key value pair entry +// Stored in the Torrent DHT for a limited time. +// This is only used when the link recipient wants to accepts the request. + +// DHT Data Format (must be under 1000 bytes): +// CRequestLink.RequestorPublicKey.Encrypt(CRequestLink.SharedSymmetricPrivKey).ToHex() + spcae + +// CAcceptLink.RecipientPublicKey.Encrypt(CRequestLink.SharedSymmetricPrivKey).ToHex() + space + +// CRequestLink.SharedSymmetricPrivKey.Encrypt(Serialize(CAcceptLink)).ToHex() +class CAcceptLink { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString RequestorFullObjectPath; // Requestor's BDAP object path + CharString RecipientFullObjectPath; // Recipient's BDAP object path + CharString RecipientPublicKey; // ed25519 derived public key new/unique for this link + + CAcceptLink() { + SetNull(); + } + + inline void SetNull() + { + nVersion = CAcceptLink::CURRENT_VERSION; + RequestorFullObjectPath.clear(); + RecipientFullObjectPath.clear(); + RecipientPublicKey.clear(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(RequestorFullObjectPath); + READWRITE(RecipientFullObjectPath); + READWRITE(RecipientPublicKey); + } + + inline friend bool operator==(const CAcceptLink &a, const CAcceptLink &b) { + return (a.RequestorFullObjectPath == b.RequestorFullObjectPath && a.RecipientFullObjectPath == b.RecipientFullObjectPath + && a.RecipientPublicKey == b.RecipientPublicKey); + } + + inline friend bool operator!=(const CAcceptLink &a, const CAcceptLink &b) { + return !(a == b); + } + + inline CAcceptLink operator=(const CAcceptLink &b) { + nVersion = b.nVersion; + RequestorFullObjectPath = b.RequestorFullObjectPath; + RecipientFullObjectPath = b.RecipientFullObjectPath; + RecipientPublicKey = b.RecipientPublicKey; + return *this; + } + + inline bool IsNull() const { return (RequestorFullObjectPath.empty()); } + bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); + void Serialize(std::vector& vchData); + + bool ValidateValues(std::string& errorMessage); +}; + +// TODO (BDAP): Implement +CharString GetEncryptedRequestMessage(const CRequestLink& requestLink); // stored in an OP_RETURN transaction +CharString GetEncryptedAcceptMessage(const CRequestLink& requestLink, const CAcceptLink& acceptLink); // stored on BitTorrent DHT network + +#endif // DYNAMIC_BDAP_LINKING_H \ No newline at end of file From e89ec4ba787bbb5a6bc175de5c87ab04b3449afd Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 24 Sep 2018 01:24:10 +0200 Subject: [PATCH 0235/1653] Supress MacOS build warnings --- src/crypto/argon2gpu/opencl/cl.hpp | 3 +++ src/dynamicd.cpp | 7 +++++++ src/qt/notificator.cpp | 3 +++ 3 files changed, 13 insertions(+) diff --git a/src/crypto/argon2gpu/opencl/cl.hpp b/src/crypto/argon2gpu/opencl/cl.hpp index e7d86da4fe..4d5a646ec3 100644 --- a/src/crypto/argon2gpu/opencl/cl.hpp +++ b/src/crypto/argon2gpu/opencl/cl.hpp @@ -4162,6 +4162,9 @@ class Image2D : public Image #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) if (!useCreateImage) { +#if defined(MAC_OSX) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif object_ = ::clCreateImage2D( context(), flags, &format, width, height, row_pitch, host_ptr, &error); diff --git a/src/dynamicd.cpp b/src/dynamicd.cpp index 78013cb517..c540668986 100644 --- a/src/dynamicd.cpp +++ b/src/dynamicd.cpp @@ -165,6 +165,10 @@ bool AppInit(int argc, char* argv[]) if (GetBoolArg("-daemon", false)) { #if HAVE_DECL_DAEMON +#if defined(MAC_OSX) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif fprintf(stdout, "Dynamic server starting\n"); // Daemonize @@ -172,6 +176,9 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno)); return false; } +#if defined(MAC_OSX) +#pragma GCC diagnostic pop +#endif #else fprintf(stderr, "Error: -daemon is not supported on this operating system\n"); return false; diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 1796a4735e..2efc0b921e 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -64,6 +64,9 @@ Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon mode = UserNotificationCenter; } else { +#if defined(MAC_OSX) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif // Check if Growl is installed (based on Qt's tray icon implementation) CFURLRef cfurl; OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); From 0c8979235f35fc1f348dd18aaa06843c6e86a66d Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 24 Sep 2018 01:27:03 +0200 Subject: [PATCH 0236/1653] Fix comparator warning --- src/net_processing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a69613850e..f3d9ebc43a 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -57,7 +57,7 @@ extern FeeFilterRounder filterRounder; struct IteratorComparator { template - bool operator()(const I& a, const I& b) + bool operator()(const I& a, const I& b) const { return &(*a) < &(*b); } From 1a78a44fc84f1338651814067fac38b68068cddc Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 24 Sep 2018 01:44:24 +0200 Subject: [PATCH 0237/1653] Supress OSX private field warnings --- src/crypto/argon2gpu/opencl/processing-unit.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/crypto/argon2gpu/opencl/processing-unit.h b/src/crypto/argon2gpu/opencl/processing-unit.h index c77f37a941..edcd2f70ac 100644 --- a/src/crypto/argon2gpu/opencl/processing-unit.h +++ b/src/crypto/argon2gpu/opencl/processing-unit.h @@ -22,6 +22,10 @@ #include "crypto/argon2gpu/opencl/kernel-runner.h" +#if defined(MAC_OSX) +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif + namespace argon2gpu { namespace opencl From b3fcbe4e68630d83a8d8a76f0af5ab7527df3a92 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 24 Sep 2018 01:45:16 +0200 Subject: [PATCH 0238/1653] Fix copy elision warning in opencl device.cpp --- src/crypto/argon2gpu/opencl/device.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/argon2gpu/opencl/device.cpp b/src/crypto/argon2gpu/opencl/device.cpp index e598c615c6..c3c4e079bb 100644 --- a/src/crypto/argon2gpu/opencl/device.cpp +++ b/src/crypto/argon2gpu/opencl/device.cpp @@ -232,7 +232,7 @@ std::string Device::getInfo() const {CL_QUEUE_PROFILING_ENABLE, "Profiling"}, }) << std::endl; - return std::move(out.str()); + return out.str(); } } // namespace opencl From 37a01a711b08c238174decc39b0c96d6a1c6a612 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 24 Sep 2018 01:49:44 +0200 Subject: [PATCH 0239/1653] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c18d84c17..078a36005b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ **Dynamic v2.4.0.0** +* Fix copy elision warning in opencl device.cpp +* Supress OSX private field warnings +* Fix comparator and supress warning +* Supress MacOS build warnings for deprecated code * [Qt] Fix styling of PrivateSend option on sendcoinsdialog.ui * Increase Min Peer Protocol Version to 70900(v2.3) for Peers/DynodePayments/InstantSend/PrivateSend * [GPU] Fix GPU found block nonce before ProcessFoundSolution From ff873d3b0ca2a883bc6f3b72da675e757d03d48e Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Mon, 24 Sep 2018 02:12:53 +0200 Subject: [PATCH 0240/1653] [GPU] Optimise GPU Miner --- src/qt/guiutil.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 4d8da85223..464474f93f 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1099,8 +1099,8 @@ int CPUMaxThreads() { } int GPUMaxThreads() { - int nUseThreads = 1; - if (nUseThreads < 1) { + int nUseThreads = 8; + if (nUseThreads < 0) { nUseThreads = 1; } return nUseThreads; From 1ef9e419c7b9c536873fec30f0ef8838075c68ce Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 23 Sep 2018 21:10:29 -0500 Subject: [PATCH 0241/1653] [DHT] Remove duplicate addresses and port numbers in dht_bootstrap_nodes --- src/dht/dhtsettings.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp index e3c4269b71..8cf678f076 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/dhtsettings.cpp @@ -22,13 +22,22 @@ CDHTSettings::CDHTSettings() void CDHTSettings::LoadPeerList() { - std::string strPeerList; + std::string strPeerList = ""; // get all Dynodes above the minimum protocol version std::map mapDynodes = dnodeman.GetFullDynodeMap(); for (auto& dnpair : mapDynodes) { CDynode dn = dnpair.second; if (dn.nProtocolVersion >= MIN_DHT_PROTO_VERSION) { - strPeerList += dn.addr.ToString() + ","; + std::string strDynodeIP = dn.addr.ToString(); + size_t pos = strDynodeIP.find(":"); + if (pos != std::string::npos && strDynodeIP.size() > 5) { + // remove port from IP address string + strDynodeIP = strDynodeIP.substr(0, pos); + } + pos = strPeerList.find(strDynodeIP); + if (pos == std::string::npos) { + strPeerList += strDynodeIP + ","; + } } } // get all peers above the minimum protocol version @@ -37,15 +46,23 @@ void CDHTSettings::LoadPeerList() g_connman->GetNodeStats(vstats); for (const CNodeStats& stats : vstats) { if (stats.nVersion >= MIN_DHT_PROTO_VERSION) { - strPeerList += stats.addrName + ","; + std::string strPeerIP = stats.addrName; + size_t pos = strPeerIP.find(":"); + if (pos != std::string::npos && strPeerIP.size() > 5) { + // remove port from IP address string + strPeerIP = strPeerIP.substr(0, pos); + } + pos = strPeerList.find(strPeerIP); + if (pos == std::string::npos) { + strPeerList += strPeerIP + ","; + } } } } if (strPeerList.size() > 1) { dht_bootstrap_nodes = strPeerList.substr(0, strPeerList.size()-1); } - // TODO: (DHT) Remove port number and do not add duplicates - LogPrintf("CDHTSettings::LoadPeerList -- dht_bootstrap_nodes = %s.\n", dht_bootstrap_nodes); + LogPrintf("CDHTSettings::LoadPeerList -- dht_bootstrap_nodes = %s\n", dht_bootstrap_nodes); } void CDHTSettings::LoadSettings() From 7331a95bb7e2539054396adcc633fb15b93a55e0 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Sun, 23 Sep 2018 22:02:21 -0500 Subject: [PATCH 0242/1653] [DHT] Fix bootstrap session threading --- src/dht/bootstrap.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index 7e377cbdf8..2241507eed 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -28,6 +28,7 @@ using namespace libtorrent; +static boost::thread *dhtTorrentThread; session *pTorrentDHTSession = NULL; static alert* wait_for_alert(session* dhtSession, int alert_type) @@ -141,7 +142,12 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman if (!pTorrentDHTSession) { throw std::runtime_error("DHT Torrent network bootstraping error."); } - while (true) {} + while (true) { + MilliSleep(60000); + load_dht_state(pTorrentDHTSession); + bootstrap(pTorrentDHTSession); + save_dht_state(pTorrentDHTSession); + } } catch (const boost::thread_interrupted&) { @@ -157,12 +163,11 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman void StopTorrentDHTNetwork() { - static boost::thread_group* dhtTorrentThreads; - if (dhtTorrentThreads != NULL) + if (dhtTorrentThread != NULL) { - dhtTorrentThreads->interrupt_all(); - delete dhtTorrentThreads; - dhtTorrentThreads = NULL; + dhtTorrentThread->interrupt(); + delete dhtTorrentThread; + dhtTorrentThread = NULL; LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork stopped.\n"); } else { @@ -173,12 +178,10 @@ void StopTorrentDHTNetwork() void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman) { LogPrintf("DHTTorrentNetwork -- Log file = %s.\n", get_log_path()); - static boost::thread_group* dhtTorrentThreads; - - StopTorrentDHTNetwork(); + if (dhtTorrentThread != NULL) + StopTorrentDHTNetwork(); - dhtTorrentThreads = new boost::thread_group(); - dhtTorrentThreads->create_thread(boost::bind(&DHTTorrentNetwork, boost::cref(chainparams), boost::ref(connman))); + dhtTorrentThread = new boost::thread(DHTTorrentNetwork, boost::cref(chainparams), boost::ref(connman)); } bool GetDHTMutableData(std::array public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence) From ea82670a20c65a2b3129b0f4ef135909d595a888 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 24 Sep 2018 00:44:03 -0500 Subject: [PATCH 0243/1653] [DHT] Update Ed25519 key class for put and get functions --- src/dht/keyed25519.cpp | 34 ++++++----- src/dht/keyed25519.h | 127 +++++------------------------------------ 2 files changed, 29 insertions(+), 132 deletions(-) diff --git a/src/dht/keyed25519.cpp b/src/dht/keyed25519.cpp index c46fac949d..221dbebe1c 100644 --- a/src/dht/keyed25519.cpp +++ b/src/dht/keyed25519.cpp @@ -22,18 +22,14 @@ using namespace libtorrent; static ed25519_context* ed25519_context_sign = NULL; // TODO (BDAP): Implement check Ed25519 keys -bool CKeyEd25519::Check(const unsigned char *vch) -{ - return true; - //return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch); -} //! Generate a new private key using LibTorrent's Ed25519 // TODO (BDAP): Support compressed Ed25519 keys void CKeyEd25519::MakeNewKeyPair() { // Load seed - std::array seed; + seed = dht::ed25519_create_seed(); + /* if (ed25519_context_sign == NULL || sizeof(ed25519_context_sign->seed) == 0 || ed25519_context_sign->IsNull()) { //LogPrintf("CKeyEd25519::MakeNewKeyPair -- created new seed.\n"); seed = dht::ed25519_create_seed(); @@ -43,21 +39,18 @@ void CKeyEd25519::MakeNewKeyPair() std::string strSeed = aux::to_hex(seed); //LogPrintf("CKeyEd25519::MakeNewKeyPair -- used existing seed = %s.\n", strSeed); } + */ // Load the new ed25519 private key std::tuple newKeyPair = dht::ed25519_create_keypair(seed); { - dht::secret_key privateKey = std::get<1>(newKeyPair); - std::vector vchPrivateKey; - std::string strPrivateKey = aux::to_hex(privateKey.bytes); - vchPrivateKey = vchFromString(strPrivateKey); - memcpy(keyData.data(), &vchPrivateKey[0], vchPrivateKey.size()); + dht::secret_key sk = std::get<1>(newKeyPair); + privateKey = sk.bytes; //LogPrintf("CKeyEd25519::MakeNewKeyPair -- vchPrivateKey = %s, size = %u\n", stringFromVch(vchPrivateKey), vchPrivateKey.size()); } // Load the new ed25519 public key { - dht::public_key publicKey = std::get<0>(newKeyPair); - std::string strPublicKey = aux::to_hex(publicKey.bytes); - publicKeyData = vchFromString(strPublicKey); + dht::public_key pk = std::get<0>(newKeyPair); + publicKey = pk.bytes; //LogPrintf("CKeyEd25519::MakeNewKeyPair -- vchPublicKey = %s, size = %u\n", stringFromVch(publicKeyData), publicKeyData.size()); } } @@ -71,11 +64,16 @@ void CKeyEd25519::SetMaster(const unsigned char* seed, unsigned int nSeedLen) return; } -std::vector CKeyEd25519::GetDHTPrivKey() const +std::vector CKeyEd25519::GetPrivKey() const +{ + std::string strPrivateKey = aux::to_hex(privateKey); + return vchFromString(strPrivateKey); +} + +std::vector CKeyEd25519::GetPubKey() const { - std::vector vchPrivateKey; - memcpy(vchPrivateKey.data(), &keyData[0], keyData.size()); - return vchPrivateKey; + std::string strPublicKey = aux::to_hex(publicKey); + return vchFromString(strPublicKey); } void ECC_Ed25519_Start() diff --git a/src/dht/keyed25519.h b/src/dht/keyed25519.h index b91648dc76..dbc75e5efe 100644 --- a/src/dht/keyed25519.h +++ b/src/dht/keyed25519.h @@ -64,139 +64,38 @@ class CKeyEd25519 /** * ed25519: */ - static const unsigned int PRIVATE_KEY_SIZE = 279; - static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214; - /** - * see www.keylength.com - * script supports up to 75 for single byte push - */ - static_assert( - PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE, - "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE"); - -private: - //! Whether this private key is valid. We check for correctness when modifying the key - //! data, so fValid should always correspond to the actual state. - bool fValid; - - //! Whether the public key corresponding to this private key is (to be) compressed. - bool fCompressed; - - //! The actual private key byte data - std::vector > keyData; - //! The public key byte data - std::vector publicKeyData; - - //! Check whether the 32-byte array pointed to be vch is valid keyData. - bool static Check(const unsigned char* vch); - - //! Initialize using begin and end iterators to byte data. - template - void SetPubKey(const T pbegin, const T pend) - { - if (size_t(pend - pbegin) != publicKeyData.size()) - return; - memcpy(publicKeyData.data(), (unsigned char*)&pbegin[0], publicKeyData.size()); - } + std::array seed; + //TODO (DHT): store privateKey in a secure allocator: + std::array privateKey; + //std::vector > keyData; + std::array publicKey; public: //! Construct an invalid private key. - CKeyEd25519() : fValid(false), fCompressed(false) + CKeyEd25519() { - // Important: vch must be 32 bytes in length to not break serialization - keyData.resize(32); } - //! Destructor (again necessary because of memlocking). + //! Destructor (necessary because of memlocking). ?? ~CKeyEd25519() { } - - friend bool operator==(const CKeyEd25519& a, const CKeyEd25519& b) - { - return a.fCompressed == b.fCompressed && - a.size() == b.size() && - memcmp(a.keyData.data(), b.keyData.data(), a.size()) == 0; - } - - //! Initialize using begin and end iterators to byte data. - template - void Set(const T pbegin, const T pend, bool fCompressedIn) - { - if (size_t(pend - pbegin) != keyData.size()) { - fValid = false; - } else if (Check(&pbegin[0])) { - memcpy(keyData.data(), (unsigned char*)&pbegin[0], keyData.size()); - fValid = true; - fCompressed = fCompressedIn; - } else { - fValid = false; - } - } - - //! Simple read-only vector-like interface. - unsigned int size() const { return (fValid ? keyData.size() : 0); } - const unsigned char* begin() const { return keyData.data(); } - const unsigned char* end() const { return keyData.data() + size(); } - - unsigned int PubKeySize() const { return publicKeyData.size(); } - const unsigned char* PubKeyBegin() const { return publicKeyData.data(); } - const unsigned char* PubKeyEnd() const { return publicKeyData.data() + PubKeySize(); } - - //! Check whether this private key is valid. - bool IsValid() const { return fValid; } - - //! Check whether the public key corresponding to this private key is (to be) compressed. - bool IsCompressed() const { return fCompressed; } - - //! Initialize from a CPrivKeyEd25519 (serialized OpenSSL private key data). - //bool SetPrivKey(const CPrivKeyEd25519& vchPrivKey, bool fCompressed); //! Generate a new private key using LibTorrent's Ed25519 implementation void MakeNewKeyPair(); + std::vector GetPrivKey() const; + std::vector GetPubKey() const; /** - * Convert the private key to a CPrivKeyEd25519 (serialized OpenSSL private key data). - * This is expensive. + * Used for the Torrent DHT. */ - CPrivKeyEd25519 GetPrivKey() const; - - std::vector GetDHTPrivKey() const; - - std::vector GetPubKey() const { return publicKeyData; } + std::array GetDHTPrivKey() const { return privateKey; } /** - * Compute the public key from a private key. - * This is expensive. + * Used for the Torrent DHT. */ - // CPubKeyEd25519 GetPubKey() const; + std::array GetDHTPubKey() const { return publicKey; } void SetMaster(const unsigned char* seed, unsigned int nSeedLen); - /** - * Create a DER-serialized signature. - * The test_case parameter tweaks the deterministic nonce. - */ - //bool Sign(const uint256& hash, std::vector& vchSig, uint32_t test_case = 0) const; - - /** - * Create a compact signature (65 bytes), which allows reconstructing the used public key. - * The format is one header byte, followed by two times 32 bytes for the serialized r and s values. - * The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, - * 0x1D = second key with even y, 0x1E = second key with odd y, - * add 0x04 for compressed keys. - */ - //bool SignCompact(const uint256& hash, std::vector& vchSig) const; - - //! Derive BIP32 child key. - //bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; - - /** - * Verify thoroughly whether a private key and a public key match. - * This is done using a different mechanism than just regenerating it. - */ - //bool VerifyPubKey(const CPubEd25519Key& vchPubKey) const; - - //! Load private key and check that public key matches. - //bool Load(CPrivKeyEd25519& privkey, CPubEd25519Key& vchPubKey, bool fSkipCheck); }; bool ECC_Ed25519_InitSanityCheck(); From e2a41e4df800c48ca11d0b96966d390c7ac04007 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 24 Sep 2018 04:21:30 -0500 Subject: [PATCH 0244/1653] [DHT] Fixes to bootstrap and settings --- src/dht/bootstrap.cpp | 63 +++++++++++++++++++++++++---------------- src/dht/bootstrap.h | 2 +- src/dht/dhtsettings.cpp | 35 ++++++++++++----------- 3 files changed, 58 insertions(+), 42 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index 2241507eed..6150f74a78 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -29,6 +29,7 @@ using namespace libtorrent; static boost::thread *dhtTorrentThread; +static bool fShutdown; session *pTorrentDHTSession = NULL; static alert* wait_for_alert(session* dhtSession, int alert_type) @@ -45,15 +46,18 @@ static alert* wait_for_alert(session* dhtSession, int alert_type) for (std::vector::iterator i = alerts.begin() , end(alerts.end()); i != end; ++i) { + LogPrintf("DHTTorrentNetwork -- message = %s, type =%d, alert_type =%d\n", (*i)->message(), (*i)->type(), alert_type); if ((*i)->type() != alert_type) { //print some alerts? - // LogPrintf("DHTTorrentNetwork -- alert = .\n"); + continue; } ret = *i; found = true; } + if (fShutdown) + return ret; } LogPrintf("DHTTorrentNetwork -- wait_for_alert complete.\n"); return ret; @@ -83,12 +87,12 @@ static int save_dht_state(session* dhtSession) return 0; } -static void load_dht_state(session* dhtSession) +static bool load_dht_state(session* dhtSession) { std::fstream f(get_log_path().c_str(), std::ios_base::in | std::ios_base::binary | std::ios_base::ate); auto const size = f.tellg(); - if (static_cast(size) <= 0) return; + if (static_cast(size) <= 0) return false; f.seekg(0, std::ios_base::beg); std::vector state; @@ -98,7 +102,7 @@ static void load_dht_state(session* dhtSession) if (f.fail()) { LogPrintf("DHTTorrentNetwork -- failed to read dht-state.log\n"); - return; + return false; } bdecode_node e; @@ -106,12 +110,14 @@ static void load_dht_state(session* dhtSession) bdecode(state.data(), state.data() + state.size(), e, ec); if (ec) { LogPrintf("DHTTorrentNetwork -- failed to parse dht-state.log file: (%d) %s\n", ec.value(), ec.message()); + return false; } else { LogPrintf("DHTTorrentNetwork -- load dht state from dht-state.log\n"); dhtSession->load_state(e); } + return true; } void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman) @@ -130,6 +136,9 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman if (!fvNodesEmpty && !IsInitialBlockDownload() && dynodeSync.IsSynced() && dynodeSync.IsBlockchainSynced()) break; MilliSleep(1000); + if (fShutdown) + break; + } while (true); // boot strap the DHT LibTorrent network @@ -142,11 +151,11 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman if (!pTorrentDHTSession) { throw std::runtime_error("DHT Torrent network bootstraping error."); } - while (true) { + while (!fShutdown) { MilliSleep(60000); - load_dht_state(pTorrentDHTSession); - bootstrap(pTorrentDHTSession); - save_dht_state(pTorrentDHTSession); + //load_dht_state(pTorrentDHTSession); + //bootstrap(pTorrentDHTSession); + //save_dht_state(pTorrentDHTSession); } } catch (const boost::thread_interrupted&) @@ -163,6 +172,7 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman void StopTorrentDHTNetwork() { + fShutdown = true; if (dhtTorrentThread != NULL) { dhtTorrentThread->interrupt(); @@ -178,21 +188,23 @@ void StopTorrentDHTNetwork() void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman) { LogPrintf("DHTTorrentNetwork -- Log file = %s.\n", get_log_path()); + fShutdown = false; if (dhtTorrentThread != NULL) StopTorrentDHTNetwork(); dhtTorrentThread = new boost::thread(DHTTorrentNetwork, boost::cref(chainparams), boost::ref(connman)); } -bool GetDHTMutableData(std::array public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence) +bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence) { //TODO: DHT add locks - LogPrintf("DHTTorrentNetwork -- PutMutableData started.\n"); + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData started.\n"); if (!pTorrentDHTSession) return false; - bootstrap(pTorrentDHTSession); + if (!load_dht_state(pTorrentDHTSession)) + bootstrap(pTorrentDHTSession); pTorrentDHTSession->dht_get_item(public_key, entrySalt); LogPrintf("DHTTorrentNetwork -- MGET: %s, salt = %s\n", aux::to_hex(public_key), entrySalt); @@ -207,10 +219,10 @@ bool GetDHTMutableData(std::array public_key, const std::string& entry authoritative = dhtGetAlert->authoritative; entryValue = dhtGetAlert->item.to_string(); lastSequence = dhtGetAlert->seq; - LogPrintf("%s: %s\n", authoritative ? "auth" : "non-auth", entryValue); + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); } save_dht_state(pTorrentDHTSession); - + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData end.\n"); return true; } @@ -224,16 +236,17 @@ static void put_string( ,char const* str) { using dht::sign_mutable_item; - - e = std::string(str); - std::vector buf; - bencode(std::back_inserter(buf), e); - dht::signature sign; - ++seq; - sign = sign_mutable_item(buf, salt, dht::sequence_number(seq) - , dht::public_key(pk.data()) - , dht::secret_key(sk.data())); - sig = sign.bytes; + if (str != NULL) { + e = std::string(str); + std::vector buf; + bencode(std::back_inserter(buf), e); + dht::signature sign; + ++seq; + sign = sign_mutable_item(buf, salt, dht::sequence_number(seq) + , dht::public_key(pk.data()) + , dht::secret_key(sk.data())); + sig = sign.bytes; + } } bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence @@ -245,7 +258,8 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< if (!pTorrentDHTSession) return false; - bootstrap(pTorrentDHTSession); + if (!load_dht_state(pTorrentDHTSession)) + bootstrap(pTorrentDHTSession); entry e; std::array sig; @@ -257,6 +271,7 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< message = dhtPutAlert->message(); LogPrintf("%s\n", message); save_dht_state(pTorrentDHTSession); + LogPrintf("DHTTorrentNetwork -- PutMutableData end.\n"); return true; } \ No newline at end of file diff --git a/src/dht/bootstrap.h b/src/dht/bootstrap.h index 101fd0f9b8..5e3ee623b0 100644 --- a/src/dht/bootstrap.h +++ b/src/dht/bootstrap.h @@ -15,7 +15,7 @@ void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman); /** Stop the DHT libtorrent network threads */ void StopTorrentDHTNetwork(); /** Get a mutable entry in the libtorrent DHT */ -bool GetDHTMutableData(std::array public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence); +bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence); /** Set a mutable entry in the libtorrent DHT */ bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence ,char const* dhtValue, std::string& message); diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp index 8cf678f076..7a7b7e6c0b 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/dhtsettings.cpp @@ -36,7 +36,7 @@ void CDHTSettings::LoadPeerList() } pos = strPeerList.find(strDynodeIP); if (pos == std::string::npos) { - strPeerList += strDynodeIP + ","; + strPeerList += strDynodeIP + ":33307,"; } } } @@ -54,7 +54,7 @@ void CDHTSettings::LoadPeerList() } pos = strPeerList.find(strPeerIP); if (pos == std::string::npos) { - strPeerList += strPeerIP + ","; + strPeerList += strPeerIP + ":33307,"; } } } @@ -129,6 +129,20 @@ void CDHTSettings::LoadSettings() // connections on port 7777 on adapter with this GUID. // TODO: Add peers and dynodes to the dht_bootstrap_nodes list. settings.set_str(settings_pack::listen_interfaces, listen_interfaces); + + // ``dht_announce_interval`` is the number of seconds between + // announcing torrents to the distributed hash table (DHT). + //settings.set_int(settings_pack::dht_announce_interval, 30); + + // ``enable_outgoing_utp`` ``enable_incoming_utp`` + // ``enable_outgoing_tcp`` ``enable_incoming_tcp`` + // when set to true, libtorrent will try to make outgoing utp + // connections controls whether libtorrent will accept incoming + // connections or make outgoing connections of specific type. + //settings.set_bool(settings_pack::enable_outgoing_utp, true); + //settings.set_bool(settings_pack::enable_incoming_utp, true); + //settings.set_bool(settings_pack::enable_outgoing_tcp, true); + //settings.set_bool(settings_pack::enable_incoming_tcp, true); // Apply settings. newSession.apply_settings(settings); @@ -140,7 +154,8 @@ void CDHTSettings::LoadSettings() // omitted. //settings.set_bool(settings_pack::announce_ip, false); - // ``allow_multiple_connections_per_ip`` determines if connections from the same IP address as existing + // ``allow_multiple_connections_per_ip`` + // determines if connections from the same IP address as existing // connections should be rejected or not. Multiple connections from // the same IP address is not allowed by default, to prevent abusive // behavior by peers. It may be useful to allow such connections in @@ -306,16 +321,6 @@ void CDHTSettings::LoadSettings() // broadcast. //settings.set_bool(settings_pack::broadcast_lsd, true); - // ``enable_outgoing_utp`` ``enable_incoming_utp`` - // ``enable_outgoing_tcp`` ``enable_incoming_tcp`` - // when set to true, libtorrent will try to make outgoing utp - // connections controls whether libtorrent will accept incoming - // connections or make outgoing connections of specific type. - //settings.set_bool(settings_pack::enable_outgoing_utp, true); - //settings.set_bool(settings_pack::enable_incoming_utp, true); - //settings.set_bool(settings_pack::enable_outgoing_tcp, true); - //settings.set_bool(settings_pack::enable_incoming_tcp, true); - // ``seeding_outgoing_connections`` determines if seeding (and // finished) torrents should attempt to make outgoing connections or // not. By default this is true. It may be set to false in very @@ -916,10 +921,6 @@ void CDHTSettings::LoadSettings() // This interval is specified in seconds. //local_service_announce_interval, - // ``dht_announce_interval`` is the number of seconds between - // announcing torrents to the distributed hash table (DHT). - //dht_announce_interval, - // ``udp_tracker_token_expiry`` is the number of seconds libtorrent // will keep UDP tracker connection tokens around for. This is // specified to be 60 seconds, and defaults to that. The higher this From a30808481076ccd9a89ce58f4cbf9e2d9a5e16d2 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Mon, 24 Sep 2018 23:43:33 -0500 Subject: [PATCH 0245/1653] [DHT] Updates to bootstrap code --- src/dht/bootstrap.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index 6150f74a78..d0c5e2eb7d 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -125,8 +125,6 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman LogPrintf("DHTTorrentNetwork -- started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("dht-torrent-network"); - - boost::shared_ptr coinbaseScript; try { CDHTSettings settings; @@ -229,7 +227,7 @@ bool GetDHTMutableData(const std::array& public_key, const std::string static void put_string( entry& e ,std::array& sig - ,std::int64_t& seq + ,std::int64_t const& seq ,std::string const& salt ,std::array const& pk ,std::array const& sk @@ -241,7 +239,6 @@ static void put_string( std::vector buf; bencode(std::back_inserter(buf), e); dht::signature sign; - ++seq; sign = sign_mutable_item(buf, salt, dht::sequence_number(seq) , dht::public_key(pk.data()) , dht::secret_key(sk.data())); @@ -263,13 +260,13 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< entry e; std::array sig; - pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_string, e, sig, lastSequence + 1, entrySalt, public_key, private_key, dhtValue)); + pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_string, e, sig, lastSequence, entrySalt, public_key, private_key, dhtValue)); - LogPrintf("DHTTorrentNetwork -- MPUT public key: %s, salt = %s\n", aux::to_hex(public_key), entrySalt); + LogPrintf("DHTTorrentNetwork -- MPUT public key: %s, salt = %s, sig=%s, seq=%d\n", aux::to_hex(public_key), entrySalt, aux::to_hex(sig), lastSequence); alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_put_alert::alert_type); dht_put_alert* dhtPutAlert = alert_cast(dhtAlert); message = dhtPutAlert->message(); - LogPrintf("%s\n", message); + LogPrintf("DHTTorrentNetwork -- PutMutableData %s\n", message); save_dht_state(pTorrentDHTSession); LogPrintf("DHTTorrentNetwork -- PutMutableData end.\n"); From 560115e4a16c3968fc93a2244075e7de9db1006b Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Mon, 24 Sep 2018 23:34:55 -0500 Subject: [PATCH 0246/1653] [GPU] Prevent crash when changing the slidebar too fast --- src/miner.cpp | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 244150fcea..9c3f047301 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -938,19 +938,31 @@ void GenerateDynamicsCPU(int nCPUThreads, const CChainParams& chainparams, CConn } } -void GenerateDynamicsGPU(int nGPUThreads, const CChainParams& chainparams, CConnman& connman) -{ #ifdef ENABLE_GPU +static int lastGPUChangeTime; +static boost::thread *gpuStartThread; + +void static GenerateDynamicsGPULocal(int nGPUThreads, const CChainParams& chainparams, CConnman& connman) +{ + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("gpu-miner-controller"); if (nGPUThreads == 0) { - LogPrintf("DynamicMiner -- disabled -- CPU and GPU Threads set to zero\n"); + LogPrintf("GenerateDynamicsGPU -- disabled -- CPU and GPU Threads set to zero\n"); return; } + if (GetTime() - lastGPUChangeTime < 2000) { + lastGPUChangeTime = GetTime(); + //LogPrintf("GenerateDynamicsGPULocal -- waiting to make changes.\n"); + ShutdownGPUMiners(); + MilliSleep(2000); + } + std::size_t devices = GetGPUDeviceCount(); //LogPrintf("DynamicMiner -- GPU Devices: %u\n", devices); if (nGPUThreads < 0) - nGPUThreads = 4; + nGPUThreads = 8; // Start GPU threads std::size_t nGPUTarget = static_cast(nGPUThreads); @@ -961,6 +973,21 @@ void GenerateDynamicsGPU(int nGPUThreads, const CChainParams& chainparams, CConn gpuMinerThreads->create_thread(boost::bind(&DynamicMinerGPU, boost::cref(chainparams), boost::ref(connman), device)); } } + lastGPUChangeTime = GetTime(); +} +#endif // ENABLE_GPU + +void GenerateDynamicsGPU(int nGPUThreads, const CChainParams& chainparams, CConnman& connman) +{ +#ifdef ENABLE_GPU + if (gpuStartThread != NULL) { + //ShutdownGPUMiners(); + MilliSleep(30); + gpuStartThread->interrupt(); + delete gpuStartThread; + gpuStartThread = NULL; + } + gpuStartThread = new boost::thread(GenerateDynamicsGPULocal, nGPUThreads, boost::cref(chainparams), boost::ref(connman)); #else LogPrintf("DynamicMiner -- GPU no support\n"); #endif From d4ea4ca76a59a104050fc0c1de66009c96dece2a Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Tue, 25 Sep 2018 00:54:42 -0500 Subject: [PATCH 0247/1653] [GPU] Update obsolete macro AC_HELP_STRING --- build-aux/m4/ax_check_cuda.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-aux/m4/ax_check_cuda.m4 b/build-aux/m4/ax_check_cuda.m4 index e626b36679..ce123afae0 100644 --- a/build-aux/m4/ax_check_cuda.m4 +++ b/build-aux/m4/ax_check_cuda.m4 @@ -81,7 +81,7 @@ then NVCCFLAGS+=" -O3" fi AC_ARG_ENABLE([emu], - AC_HELP_STRING([--enable-emu],[turn on device emulation for CUDA]), + AS_HELP_STRING([--enable-emu],[turn on device emulation for CUDA]), [case "${enableval}" in yes) EMULATION=true;; no) EMULATION=false;; From 2aada5e9977fcb26d712ff39320c2c087d0f624d Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 25 Sep 2018 22:21:19 -0500 Subject: [PATCH 0248/1653] [DHT] Fix put mutable data item function --- src/dht/bootstrap.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index d0c5e2eb7d..4510239cdc 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -224,14 +224,17 @@ bool GetDHTMutableData(const std::array& public_key, const std::string return true; } -static void put_string( +static void put_mutable +( entry& e ,std::array& sig - ,std::int64_t const& seq + ,std::int64_t& seq ,std::string const& salt ,std::array const& pk ,std::array const& sk - ,char const* str) + ,char const* str + ,std::int64_t const& iSeq +) { using dht::sign_mutable_item; if (str != NULL) { @@ -239,6 +242,7 @@ static void put_string( std::vector buf; bencode(std::back_inserter(buf), e); dht::signature sign; + seq = iSeq + 1; sign = sign_mutable_item(buf, salt, dht::sequence_number(seq) , dht::public_key(pk.data()) , dht::secret_key(sk.data())); @@ -258,11 +262,10 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< if (!load_dht_state(pTorrentDHTSession)) bootstrap(pTorrentDHTSession); - entry e; - std::array sig; - pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_string, e, sig, lastSequence, entrySalt, public_key, private_key, dhtValue)); + pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_mutable, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, public_key, private_key, dhtValue, lastSequence), entrySalt); - LogPrintf("DHTTorrentNetwork -- MPUT public key: %s, salt = %s, sig=%s, seq=%d\n", aux::to_hex(public_key), entrySalt, aux::to_hex(sig), lastSequence); + LogPrintf("DHTTorrentNetwork -- MPUT public key: %s, salt = %s, seq=%d\n", aux::to_hex(public_key), entrySalt, lastSequence); alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_put_alert::alert_type); dht_put_alert* dhtPutAlert = alert_cast(dhtAlert); message = dhtPutAlert->message(); From f3e0a0ae1e23d6ec44ee3ccda9056081d992afcd Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 26 Sep 2018 00:01:03 -0500 Subject: [PATCH 0249/1653] [DHT] Add put and get mutable data RPC commands --- src/Makefile.am | 1 + src/dht/rpcdht.cpp | 107 +++++++++++++++++++++++++++++++++++++++++++++ src/rpcregister.h | 4 ++ 3 files changed, 112 insertions(+) create mode 100644 src/dht/rpcdht.cpp diff --git a/src/Makefile.am b/src/Makefile.am index c505248dca..bef8693756 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -294,6 +294,7 @@ libdynamic_server_a_SOURCES = \ rest.cpp \ rpcblockchain.cpp \ bdap/rpcdomainentry.cpp \ + dht/rpcdht.cpp \ rpcdynode.cpp \ rpcgovernance.cpp \ rpcmining.cpp \ diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp new file mode 100644 index 0000000000..62c6127039 --- /dev/null +++ b/src/dht/rpcdht.cpp @@ -0,0 +1,107 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#include "bdap/domainentry.h" +#include "dht/bootstrap.h" +#include "dht/keyed25519.h" +#include "libtorrent/hex.hpp" // for to_hex and from_hex +#include "rpcprotocol.h" +#include "rpcserver.h" +#include "util.h" +#include "utilstrencodings.h" + +#include + + +UniValue getdhtmutable(const JSONRPCRequest& request) +{ + if (request.params.size() != 2) + throw std::runtime_error( + "getdhtdata\n" + "\n"); + + UniValue result(UniValue::VOBJ); + if (!pTorrentDHTSession) + return result; + + const std::string strPubKey = request.params[0].get_str(); + const std::string strSalt = request.params[1].get_str(); + + bool fRet = false; + int64_t iSequence = 0; + std::string strValue = ""; + std::array pubKey; + libtorrent::aux::from_hex(strPubKey, pubKey.data()); + fRet = GetDHTMutableData(pubKey, strSalt, strValue, iSequence); + if (fRet) { + result.push_back(Pair("Get_PubKey", strPubKey)); + result.push_back(Pair("Get_Salt", strSalt)); + result.push_back(Pair("Get_Seq", iSequence)); + result.push_back(Pair("Get_Value", strValue)); + } + + return result; +} + +UniValue putdhtmutable(const JSONRPCRequest& request) +{ + if (request.params.size() < 2 || request.params.size() > 4 || request.params.size() == 3) + throw std::runtime_error( + "putdhtdata\n" + "\n"); + + UniValue result(UniValue::VOBJ); + if (!pTorrentDHTSession) + return result; + + char const* putValue = request.params[0].get_str().c_str(); + const std::string strSalt = request.params[1].get_str(); + std::string strPrivKey; + std::string strPubKey; + if (request.params.size() == 4) { + strPubKey = request.params[2].get_str(); + strPrivKey = request.params[3].get_str(); + } + else if (request.params.size() == 2) { + CKeyEd25519 key; + key.MakeNewKeyPair(); + strPubKey = stringFromVch(key.GetPubKey()); + strPrivKey = stringFromVch(key.GetPrivKey()); + } + + bool fRet = false; + int64_t iSequence = 0; + std::string strPutValue = ""; + std::array pubKey; + libtorrent::aux::from_hex(strPubKey, pubKey.data()); + + std::array privKey; + libtorrent::aux::from_hex(strPrivKey, privKey.data()); + + fRet = GetDHTMutableData(pubKey, strSalt, strPutValue, iSequence); + std::string dhtMessage = ""; + fRet = PutDHTMutableData(pubKey, privKey, strSalt, iSequence, putValue, dhtMessage); + if (fRet) { + result.push_back(Pair("Put_PubKey", strPubKey)); + result.push_back(Pair("Put_PrivKey", strPrivKey)); + result.push_back(Pair("Put_Salt", strSalt)); + result.push_back(Pair("Put_Seq", iSequence)); + result.push_back(Pair("Put_Value", request.params[0].get_str())); + result.push_back(Pair("Put_Message", dhtMessage)); + } + + return result; +} + +static const CRPCCommand commands[] = +{ // category name actor (function) okSafeMode + /* DHT */ + { "dht", "getdhtmutable", &getdhtmutable, true }, + { "dht", "putdhtmutable", &putdhtmutable, true }, +}; + +void RegisterDHTRPCCommands(CRPCTable &tableRPC) +{ + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); +} \ No newline at end of file diff --git a/src/rpcregister.h b/src/rpcregister.h index e91835181a..eefe466605 100644 --- a/src/rpcregister.h +++ b/src/rpcregister.h @@ -28,6 +28,9 @@ void RegisterGovernanceRPCCommands(CRPCTable &tableRPC); void RegisterFluidRPCCommands(CRPCTable &tableRPC); /** Register BDAP RPC commands */ void RegisterDomainEntryRPCCommands(CRPCTable &tableRPC); +/** Register DHT RPC commands */ +void RegisterDHTRPCCommands(CRPCTable &tableRPC); + static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) { RegisterBlockchainRPCCommands(tableRPC); @@ -39,6 +42,7 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) RegisterGovernanceRPCCommands(tableRPC); RegisterFluidRPCCommands(tableRPC); RegisterDomainEntryRPCCommands(tableRPC); + RegisterDHTRPCCommands(tableRPC); } #endif // DYNAMIC_RPCREGISTER_H \ No newline at end of file From 615e9a4947ded8de7eba39de55b59e9708d748d4 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Thu, 27 Sep 2018 01:51:49 -0500 Subject: [PATCH 0250/1653] [DHT] Add Ed/Curve25519 coversion functions for pub and priv keys --- src/Makefile.am | 2 + src/dht/curve25519.cpp | 244 +++++++++++++++++++++++++++++++++++++++++ src/dht/curve25519.h | 23 ++++ 3 files changed, 269 insertions(+) create mode 100644 src/dht/curve25519.cpp create mode 100644 src/dht/curve25519.h diff --git a/src/Makefile.am b/src/Makefile.am index bef8693756..05cd79f743 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -113,6 +113,7 @@ DYNAMIC_CORE_H = \ bdap/linking.h \ dbwrapper.h \ dht/bootstrap.h \ + dht/curve25519.h \ dht/dhtsettings.h \ dht/keyed25519.h \ dynode.h \ @@ -252,6 +253,7 @@ libdynamic_server_a_SOURCES = \ bdap/linking.cpp \ dbwrapper.cpp \ dht/bootstrap.cpp \ + dht/curve25519.cpp \ dht/dhtsettings.cpp \ dht/keyed25519.cpp \ dynode.cpp \ diff --git a/src/dht/curve25519.cpp b/src/dht/curve25519.cpp new file mode 100644 index 0000000000..0a4761765b --- /dev/null +++ b/src/dht/curve25519.cpp @@ -0,0 +1,244 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License +// +// Curve25519 code from LibSodium reference implementation: https://github.com/jedisct1/libsodium +// src/libsodium/crypto_sign/ed25519/ref10/keypair.c +// master branch commit hash: 350a23ae5d0fb793c98e0a35b3c0f2c4828521ae + +#include "curve25519.h" + +#include +#include +//#include "libtorrent/hasher512.hpp" // for deterministic keys + +#ifdef WIN32 +# include +# include +#else +# include +#endif + +#include + +#ifdef HAVE_WEAK_SYMBOLS +__attribute__((weak)) void +_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1, + const unsigned char *b2, + const size_t len); +__attribute__((weak)) void +_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1, + const unsigned char *b2, + const size_t len) +{ + (void) b1; + (void) b2; + (void) len; +} +#endif + +static int ge_has_small_order(const unsigned char s[32]) +{ + CRYPTO_ALIGN(16) + static const unsigned char blacklist[][32] = { + /* 0 (order 4) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 1 (order 1) */ + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 + (order 8) */ + { 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, + 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, + 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 }, + /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 + (order 8) */ + { 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, + 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, + 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a }, + /* p-1 (order 2) */ + { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p (=0, order 4) */ + { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p+1 (=1, order 1) */ + { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f } + }; + unsigned char c[7] = { 0 }; + unsigned int k; + std::size_t i, j; + + COMPILER_ASSERT(7 == sizeof blacklist / sizeof blacklist[0]); + for (j = 0; j < 31; j++) { + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= s[j] ^ blacklist[i][j]; + } + } + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= (s[j] & 0x7f) ^ blacklist[i][j]; + } + k = 0; + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + k |= (c[i] - 1); + } + return (int) ((k >> 8) & 1); +} + +/* multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493 */ +static void ge_mul_l(ge_p3 *r, const ge_p3 *A) +{ + static const signed char aslide[253] = { + 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + }; + ge_cached Ai[8]; + ge_p1p1 t; + ge_p3 u; + ge_p3 A2; + int i; + + ge_p3_to_cached(&Ai[0], A); + ge_p3_dbl(&t, A); + ge_p1p1_to_p3(&A2, &t); + ge_add(&t, &A2, &Ai[0]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[1], &u); + ge_add(&t, &A2, &Ai[1]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[2], &u); + ge_add(&t, &A2, &Ai[2]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[3], &u); + ge_add(&t, &A2, &Ai[3]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[4], &u); + ge_add(&t, &A2, &Ai[4]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[5], &u); + ge_add(&t, &A2, &Ai[5]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[6], &u); + ge_add(&t, &A2, &Ai[6]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[7], &u); + + ge_p3_0(r); + + for (i = 252; i >= 0; --i) { + ge_p3_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i] / 2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); + } + + ge_p1p1_to_p3(r, &t); + } +} + +//sodium_is_zero: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/sodium/utils.c +static int is_zero(const unsigned char *n, const std::size_t nlen) +{ + std::size_t i; + volatile unsigned char d = 0U; + + for (i = 0U; i < nlen; i++) { + d |= n[i]; + } + return 1 & ((d - 1) >> 8); +} + +static inline int fe_iszero(const fe f) +{ + unsigned char s[32]; + + fe_tobytes(s, f); + + return is_zero(s, 32); +} + +static int ge_is_on_main_subgroup(const ge_p3 *p) +{ + ge_p3 pl; + + ge_mul_l(&pl, p); + + return fe_iszero(pl.X); +} + +//sodium_memzero: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/sodium/utils.c +static void memzero(void *const pnt, const std::size_t len) +{ +#ifdef WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + if (len > 0U && memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif HAVE_WEAK_SYMBOLS + memset(pnt, 0, len); + _dummy_symbol_to_prevent_memzero_lto(pnt, len); +# ifdef HAVE_INLINE_ASM + __asm__ __volatile__ ("" : : "r"(pnt) : "memory"); +# endif +#else + volatile unsigned char *volatile pnt_ = + (volatile unsigned char *volatile) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif +} + +int Ed25519_To_Curve25519_PubKey(unsigned char* curve25519_pubkey, const unsigned char* ed25519_pubkey) +{ + ge_p3 A; + fe x; + fe one_minus_y; + + if (ge_has_small_order(ed25519_pubkey) != 0 || + ge_frombytes_negate_vartime(&A, ed25519_pubkey) != 0 || + ge_is_on_main_subgroup(&A) == 0) { + return -1; + } + fe_1(one_minus_y); + fe_sub(one_minus_y, one_minus_y, A.Y); + fe_1(x); + fe_add(x, x, A.Y); + fe_invert(one_minus_y, one_minus_y); + fe_mul(x, x, one_minus_y); + fe_tobytes(curve25519_pubkey, x); + + return 0; +} + +int Ed25519_To_Curve25519_PrivKey(unsigned char* curve25519_privkey, const unsigned char* ed25519_privkey) +{ + unsigned char h[crypto_hash_sha512_BYTES]; + +//#ifdef ED25519_NONDETERMINISTIC + std::memcpy(h, ed25519_privkey, 32); +//#else +// crypto_hash_sha512(h, ed25519_privkey, 32); +//#endif + h[0] &= 248; + h[31] &= 127; + h[31] |= 64; + std::memcpy(curve25519_privkey, h, crypto_scalarmult_curve25519_BYTES); + memzero(h, sizeof h); + + return 0; +} \ No newline at end of file diff --git a/src/dht/curve25519.h b/src/dht/curve25519.h new file mode 100644 index 0000000000..bba3c25e9d --- /dev/null +++ b/src/dht/curve25519.h @@ -0,0 +1,23 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_DHT_CURVE25519_H +#define DYNAMIC_DHT_CURVE25519_H + +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + +#ifndef CRYPTO_ALIGN +# if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +# else +# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) +# endif +#endif + +#define crypto_hash_sha512_BYTES 64U +#define crypto_scalarmult_curve25519_BYTES 32U + +int Ed25519_To_Curve25519_PubKey(unsigned char* curve25519_pubkey, const unsigned char* ed25519_pubkey); +int Ed25519_To_Curve25519_PrivKey(unsigned char* curve25519_privkey, const unsigned char* ed25519_privkey); + +#endif // DYNAMIC_DHT_CURVE25519_H \ No newline at end of file From cd5b3bca751c3b91118bedad2823e26c8af4630f Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Thu, 27 Sep 2018 16:20:43 -0500 Subject: [PATCH 0251/1653] [DHT] Fix settings and alert logging --- src/dht/bootstrap.cpp | 103 ++++++++++++++++++++------- src/dht/bootstrap.h | 2 +- src/dht/dhtsettings.cpp | 153 ++++++++++++++-------------------------- src/dht/dhtsettings.h | 10 +-- src/dht/rpcdht.cpp | 41 +++++++---- 5 files changed, 167 insertions(+), 142 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index 4510239cdc..2979d6deee 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -40,26 +40,34 @@ static alert* wait_for_alert(session* dhtSession, int alert_type) while (!found) { dhtSession->wait_for_alert(seconds(5)); - std::vector alerts; dhtSession->pop_alerts(&alerts); for (std::vector::iterator i = alerts.begin() , end(alerts.end()); i != end; ++i) { - LogPrintf("DHTTorrentNetwork -- message = %s, type =%d, alert_type =%d\n", (*i)->message(), (*i)->type(), alert_type); + if ((*i)->category() == 0x1) { + LogPrintf("DHTTorrentNetwork -- error alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + } + else if ((*i)->category() == 0x80) { + LogPrintf("DHTTorrentNetwork -- progress alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + } + else if ((*i)->category() == 0x200) { + LogPrintf("DHTTorrentNetwork -- performance warning alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + } + else if ((*i)->category() == 0x400) { + LogPrintf("DHTTorrentNetwork -- dht alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + } if ((*i)->type() != alert_type) { - //print some alerts? - continue; } + LogPrintf("DHTTorrentNetwork -- wait alert complete. message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); ret = *i; found = true; } if (fShutdown) return ret; } - LogPrintf("DHTTorrentNetwork -- wait_for_alert complete.\n"); return ret; } @@ -84,6 +92,7 @@ static int save_dht_state(session* dhtSession) bencode(std::back_inserter(state), torrentEntry); std::fstream f(get_log_path().c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); f.write(state.data(), state.size()); + LogPrintf("DHTTorrentNetwork -- save_dht_state complete.\n"); return 0; } @@ -150,10 +159,13 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman throw std::runtime_error("DHT Torrent network bootstraping error."); } while (!fShutdown) { - MilliSleep(60000); - //load_dht_state(pTorrentDHTSession); - //bootstrap(pTorrentDHTSession); - //save_dht_state(pTorrentDHTSession); + MilliSleep(5000); + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- not running. Loading from file and restarting bootstrap.\n"); + load_dht_state(pTorrentDHTSession); + bootstrap(pTorrentDHTSession); + save_dht_state(pTorrentDHTSession); + } } } catch (const boost::thread_interrupted&) @@ -170,6 +182,7 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman void StopTorrentDHTNetwork() { + save_dht_state(pTorrentDHTSession); fShutdown = true; if (dhtTorrentThread != NULL) { @@ -179,7 +192,7 @@ void StopTorrentDHTNetwork() LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork stopped.\n"); } else { - LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork dhtTorrentThreads is null. Stop not needed.\n"); + LogPrintf("DHTTorrentNetwork --StopTorrentDHTNetwork dhtTorrentThreads is null. Stop not needed.\n"); } } @@ -193,34 +206,58 @@ void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman) dhtTorrentThread = new boost::thread(DHTTorrentNetwork, boost::cref(chainparams), boost::ref(connman)); } -bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence) +bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative) { //TODO: DHT add locks LogPrintf("DHTTorrentNetwork -- GetDHTMutableData started.\n"); - if (!pTorrentDHTSession) + if (!pTorrentDHTSession) { + //message = "DHTTorrentNetwork -- GetDHTMutableData Error. pTorrentDHTSession is null."; return false; + } - if (!load_dht_state(pTorrentDHTSession)) - bootstrap(pTorrentDHTSession); + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData Restarting DHT.\n"); + if (!load_dht_state(pTorrentDHTSession)) { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData Couldn't load previous settings. Trying to bootstrap again.\n"); + bootstrap(pTorrentDHTSession); + } + else { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData setting loaded from file.\n"); + } + } + else { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData DHT already running. Bootstrap not needed.\n"); + } pTorrentDHTSession->dht_get_item(public_key, entrySalt); LogPrintf("DHTTorrentNetwork -- MGET: %s, salt = %s\n", aux::to_hex(public_key), entrySalt); bool authoritative = false; - while (!authoritative) - { - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); + if (fWaitForAuthoritative) { + while (!authoritative) + { + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); + dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); + authoritative = dhtGetAlert->authoritative; + entryValue = dhtGetAlert->item.to_string(); + lastSequence = dhtGetAlert->seq; + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); + } + } + else { + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); - authoritative = dhtGetAlert->authoritative; entryValue = dhtGetAlert->item.to_string(); lastSequence = dhtGetAlert->seq; LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); } - save_dht_state(pTorrentDHTSession); - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData end.\n"); + + if (entryValue == "") + return false; + return true; } @@ -256,12 +293,25 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< //TODO: (DHT) add locks LogPrintf("DHTTorrentNetwork -- PutMutableData started.\n"); - if (!pTorrentDHTSession) + if (!pTorrentDHTSession) { + message = "DHTTorrentNetwork -- PutDHTMutableData Error. pTorrentDHTSession is null."; return false; + } - if (!load_dht_state(pTorrentDHTSession)) - bootstrap(pTorrentDHTSession); - + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData Restarting DHT.\n"); + if (!load_dht_state(pTorrentDHTSession)) { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData Couldn't load previous settings. Trying to bootstrap again.\n"); + bootstrap(pTorrentDHTSession); + } + else { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData setting loaded from file.\n"); + } + } + else { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData DHT already running. Bootstrap not needed.\n"); + } + pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_mutable, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, public_key, private_key, dhtValue, lastSequence), entrySalt); @@ -270,8 +320,9 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< dht_put_alert* dhtPutAlert = alert_cast(dhtAlert); message = dhtPutAlert->message(); LogPrintf("DHTTorrentNetwork -- PutMutableData %s\n", message); - save_dht_state(pTorrentDHTSession); - LogPrintf("DHTTorrentNetwork -- PutMutableData end.\n"); + + if (dhtPutAlert->num_success == 0) + return false; return true; } \ No newline at end of file diff --git a/src/dht/bootstrap.h b/src/dht/bootstrap.h index 5e3ee623b0..2e62607a70 100644 --- a/src/dht/bootstrap.h +++ b/src/dht/bootstrap.h @@ -15,7 +15,7 @@ void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman); /** Stop the DHT libtorrent network threads */ void StopTorrentDHTNetwork(); /** Get a mutable entry in the libtorrent DHT */ -bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence); +bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative); /** Set a mutable entry in the libtorrent DHT */ bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence ,char const* dhtValue, std::string& message); diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp index 7a7b7e6c0b..9757a49d15 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/dhtsettings.cpp @@ -15,9 +15,8 @@ using namespace libtorrent; CDHTSettings::CDHTSettings() { user_agent = "Dynamic v" + FormatFullVersion(); - // Use ports 33307, 33317, 33327, 33337 and 33347 - listen_interfaces = "0.0.0.0:33307,[::]:33307,0.0.0.0:33317,[::]:33317,0.0.0.0:33327," - "[::]:33327,0.0.0.0:33337,[::]:33337,0.0.0.0:33347,[::]:33347"; + // Use ports 33307 and 33337 + listen_interfaces = "0.0.0.0:33307,[::]:33307,0.0.0.0:33337,[::]:33337"; } void CDHTSettings::LoadPeerList() @@ -69,85 +68,64 @@ void CDHTSettings::LoadSettings() { LoadPeerList(); - settings.set_bool(settings_pack::enable_dht, false); - settings.set_int(settings_pack::alert_mask, 0xffffffff); - session newSession(settings); + params.settings.set_bool(settings_pack::enable_dht, false); + params.settings.set_int(settings_pack::alert_mask, 0xffffffff); + session newSession(params.settings); // Dynamic LibTorrent Settings - - // ``enable_dht`` - // starts the dht node and makes the trackerless service - // available to torrents. - settings.set_bool(settings_pack::enable_dht, true); - - // ``user_agent`` - // this is the client identification to the tracker. The recommended - // format of this string is: "ClientName/ClientVersion - // libtorrent/libtorrentVersion". This name will not only be used when - // making HTTP requests, but also when sending extended headers to - // peers that support that extension. It may not contain \r or \n - settings.set_str(settings_pack::user_agent, user_agent); - - // ``dht_bootstrap_nodes`` - // This is a comma-separated list of IP port-pairs. They will be added - // to the DHT node (if it's enabled) as back-up nodes in case we don't - // know of any. This setting will contain one or more bootstrap nodes - // by default. - // Changing these after the DHT has been started may not have any - // effect until the DHT is restarted. - settings.set_str(settings_pack::dht_bootstrap_nodes, dht_bootstrap_nodes); - - // ``listen_interfaces`` - // a comma-separated list of (IP or device name, port) pairs. These are - // the listen ports that will be opened for accepting incoming uTP and - // TCP connections. It is possible to listen on multiple interfaces and - // multiple ports. Binding to port 0 will make the operating system - // pick the port. The default is "0.0.0.0:6881,[::]:6881", which binds - // to all interfaces on port 6881. - // - // a port that has an "s" suffix will accept SSL connections. (note - // that SSL sockets are not enabled by default). - // - // if binding fails, the listen_failed_alert is posted. If or once a - // socket binding succeeds, the listen_succeeded_alert is posted. There - // may be multiple failures before a success. - // - // For example: - // ``[::1]:8888`` - will only accept connections on the IPv6 loopback - // address on port 8888. - // - // ``eth0:4444,eth1:4444`` - will accept connections on port 4444 on - // any IP address bound to device ``eth0`` or ``eth1``. - // - // ``[::]:0s`` - will accept SSL connections on a port chosen by the - // OS. And not accept non-SSL connections at all. - // - // Windows OS network adapter device name can be specified with GUID. - // It can be obtained from "netsh lan show interfaces" command output. - // GUID must be uppercased string embraced in curly brackets. - // ``{E4F0B674-0DFC-48BB-98A5-2AA730BDB6D6}::7777`` - will accept - // connections on port 7777 on adapter with this GUID. - // TODO: Add peers and dynodes to the dht_bootstrap_nodes list. - settings.set_str(settings_pack::listen_interfaces, listen_interfaces); - - // ``dht_announce_interval`` is the number of seconds between - // announcing torrents to the distributed hash table (DHT). - //settings.set_int(settings_pack::dht_announce_interval, 30); - - // ``enable_outgoing_utp`` ``enable_incoming_utp`` - // ``enable_outgoing_tcp`` ``enable_incoming_tcp`` - // when set to true, libtorrent will try to make outgoing utp - // connections controls whether libtorrent will accept incoming - // connections or make outgoing connections of specific type. - //settings.set_bool(settings_pack::enable_outgoing_utp, true); - //settings.set_bool(settings_pack::enable_incoming_utp, true); - //settings.set_bool(settings_pack::enable_outgoing_tcp, true); - //settings.set_bool(settings_pack::enable_incoming_tcp, true); + // see https://www.libtorrent.org/reference-Settings.html#dht_settings + // DHT Settings + params.dht_settings.max_peers_reply = 100; // default = 100 + params.dht_settings.search_branching = 10; // default = 5 + params.dht_settings.max_fail_count = 100; // default = 20 + params.dht_settings.max_torrents = 2000; + params.dht_settings.max_dht_items = 5000; // default = 700 + params.dht_settings.max_peers = 1000; // default = 5000 + params.dht_settings.max_torrent_search_reply = 20; // default = 20 + + params.dht_settings.restrict_routing_ips = true; // default = true + params.dht_settings.restrict_search_ips = true; // default = true + + params.dht_settings.extended_routing_table = true; // default = true + params.dht_settings.aggressive_lookups = true; // default = true + params.dht_settings.privacy_lookups = false; // default = false + params.dht_settings.enforce_node_id = true; // default = false + + params.dht_settings.ignore_dark_internet = true; // default = true + params.dht_settings.block_timeout = (5 * 60); // default = (5 * 60) + params.dht_settings.block_ratelimit = 10; // default = 5 + params.dht_settings.read_only = false; // default = false + params.dht_settings.item_lifetime = 0; // default = 0 + + // General LibTorrent Settings + params.settings.set_int(settings_pack::alert_mask, 0xffffffff); // receive all alerts + params.settings.set_bool(settings_pack::enable_dht, true); + params.settings.set_str(settings_pack::user_agent, user_agent); + params.settings.set_str(settings_pack::dht_bootstrap_nodes, dht_bootstrap_nodes); + params.settings.set_str(settings_pack::listen_interfaces, listen_interfaces); + params.settings.set_bool(settings_pack::enable_natpmp, true); + params.settings.set_int(settings_pack::dht_announce_interval, (60)); + params.settings.set_bool(settings_pack::enable_outgoing_utp, true); + params.settings.set_bool(settings_pack::enable_incoming_utp, true); + params.settings.set_bool(settings_pack::enable_outgoing_tcp, false); + params.settings.set_bool(settings_pack::enable_incoming_tcp, false); // Apply settings. - newSession.apply_settings(settings); + newSession.set_dht_settings(params.dht_settings); + newSession.apply_settings(params.settings); // TODO: (DHT) Evaluate and test the rest of these settings. + // ``enable_lsd`` + // Starts and stops Local Service Discovery. This service will + // broadcast the info-hashes of all the non-private torrents on the + // local network to look for peers on the same swarm within multicast + // reach. + //params.settings.set_bool(settings_pack::enable_lsd, false); + + // ``prefer_rc4`` + // if the allowed encryption level is both, setting this to true will + // prefer rc4 if both methods are offered, plaintext otherwise + //params.settings.set_bool(settings_pack::prefer_rc4, true); // ``announce_ip`` is the ip address passed along to trackers as the // ``&ip=`` parameter. If left as the default, that parameter is @@ -397,29 +375,6 @@ void CDHTSettings::LoadSettings() // valid until ``stop_upnp()`` is called. See upnp-and-nat-pmp_. //settings.set_bool(settings_pack::enable_upnp, false); - // ``enable_natpmp`` - // Starts and stops the NAT-PMP service. When started, the listen port - // and the DHT port are attempted to be forwarded on the router - // through NAT-PMP. - // The natpmp object returned by ``start_natpmp()`` can be used to add - // and remove arbitrary port mappings. Mapping status is returned - // through the portmap_alert and the portmap_error_alert. The object - // will be valid until ``stop_natpmp()`` is called. See - // upnp-and-nat-pmp_. - //settings.set_bool(settings_pack::enable_natpmp, true); //TODO: should this be true? - - // ``enable_lsd`` - // Starts and stops Local Service Discovery. This service will - // broadcast the info-hashes of all the non-private torrents on the - // local network to look for peers on the same swarm within multicast - // reach. - //settings.set_bool(settings_pack::enable_lsd, true); - - // ``prefer_rc4`` - // if the allowed encryption level is both, setting this to true will - // prefer rc4 if both methods are offered, plaintext otherwise - //settings.set_bool(settings_pack::prefer_rc4, true); //TODO: should this be true? - // ``proxy_hostnames`` // if true, hostname lookups are done via the configured proxy (if // any). This is only supported by SOCKS5 and HTTP. diff --git a/src/dht/dhtsettings.h b/src/dht/dhtsettings.h index 72e7e54613..e8c7945ec4 100644 --- a/src/dht/dhtsettings.h +++ b/src/dht/dhtsettings.h @@ -10,16 +10,18 @@ static constexpr int MIN_DHT_PROTO_VERSION = 71000; class CDHTSettings { private: - libtorrent::settings_pack settings; + libtorrent::session_params params; std::string listen_interfaces; std::string dht_bootstrap_nodes; std::string user_agent; - public: - CDHTSettings(); + void LoadSettings(); - libtorrent::settings_pack GetSettingsPack() const { return settings; } + + libtorrent::settings_pack GetSettingsPack() const { return params.settings; } + libtorrent::dht_settings GetDHTSettings() const { return params.dht_settings; } + libtorrent::session_params GetSessionParams() const { return params; } private: void LoadPeerList(); diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index 62c6127039..670ba2b423 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -32,13 +32,16 @@ UniValue getdhtmutable(const JSONRPCRequest& request) std::string strValue = ""; std::array pubKey; libtorrent::aux::from_hex(strPubKey, pubKey.data()); - fRet = GetDHTMutableData(pubKey, strSalt, strValue, iSequence); + fRet = GetDHTMutableData(pubKey, strSalt, strValue, iSequence, false); if (fRet) { result.push_back(Pair("Get_PubKey", strPubKey)); result.push_back(Pair("Get_Salt", strSalt)); result.push_back(Pair("Get_Seq", iSequence)); result.push_back(Pair("Get_Value", strValue)); } + else { + throw std::runtime_error("getdhtdata failed. Check the debug.log for details.\n"); + } return result; } @@ -54,6 +57,7 @@ UniValue putdhtmutable(const JSONRPCRequest& request) if (!pTorrentDHTSession) return result; + bool fNewEntry = false; char const* putValue = request.params[0].get_str().c_str(); const std::string strSalt = request.params[1].get_str(); std::string strPrivKey; @@ -67,6 +71,7 @@ UniValue putdhtmutable(const JSONRPCRequest& request) key.MakeNewKeyPair(); strPubKey = stringFromVch(key.GetPubKey()); strPrivKey = stringFromVch(key.GetPrivKey()); + fNewEntry = true; } bool fRet = false; @@ -77,19 +82,31 @@ UniValue putdhtmutable(const JSONRPCRequest& request) std::array privKey; libtorrent::aux::from_hex(strPrivKey, privKey.data()); - - fRet = GetDHTMutableData(pubKey, strSalt, strPutValue, iSequence); - std::string dhtMessage = ""; - fRet = PutDHTMutableData(pubKey, privKey, strSalt, iSequence, putValue, dhtMessage); + if (!fNewEntry) { + // we need the last sequence number to update an existing DHT entry. + fRet = GetDHTMutableData(pubKey, strSalt, strPutValue, iSequence, true); + } + else { + fRet = true; + } if (fRet) { - result.push_back(Pair("Put_PubKey", strPubKey)); - result.push_back(Pair("Put_PrivKey", strPrivKey)); - result.push_back(Pair("Put_Salt", strSalt)); - result.push_back(Pair("Put_Seq", iSequence)); - result.push_back(Pair("Put_Value", request.params[0].get_str())); - result.push_back(Pair("Put_Message", dhtMessage)); + std::string dhtMessage = ""; + fRet = PutDHTMutableData(pubKey, privKey, strSalt, iSequence, putValue, dhtMessage); + if (fRet) { + result.push_back(Pair("Put_PubKey", strPubKey)); + result.push_back(Pair("Put_PrivKey", strPrivKey)); + result.push_back(Pair("Put_Salt", strSalt)); + result.push_back(Pair("Put_Seq", iSequence)); + result.push_back(Pair("Put_Value", request.params[0].get_str())); + result.push_back(Pair("Put_Message", dhtMessage)); + } + else { + throw std::runtime_error("putdhtmutable failed. Put failed. Check the debug.log for details.\n"); + } + } + else { + throw std::runtime_error("putdhtmutable failed. Get failed. Check the debug.log for details.\n"); } - return result; } From 36044454b8b835af5e87842b81e7e81ce7fead8d Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Thu, 27 Sep 2018 01:51:49 -0500 Subject: [PATCH 0252/1653] [DHT] Add Ed/Curve25519 coversion functions for pub and priv keys --- src/Makefile.am | 2 + src/dht/curve25519.cpp | 244 +++++++++++++++++++++++++++++++++++++++++ src/dht/curve25519.h | 23 ++++ 3 files changed, 269 insertions(+) create mode 100644 src/dht/curve25519.cpp create mode 100644 src/dht/curve25519.h diff --git a/src/Makefile.am b/src/Makefile.am index bef8693756..05cd79f743 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -113,6 +113,7 @@ DYNAMIC_CORE_H = \ bdap/linking.h \ dbwrapper.h \ dht/bootstrap.h \ + dht/curve25519.h \ dht/dhtsettings.h \ dht/keyed25519.h \ dynode.h \ @@ -252,6 +253,7 @@ libdynamic_server_a_SOURCES = \ bdap/linking.cpp \ dbwrapper.cpp \ dht/bootstrap.cpp \ + dht/curve25519.cpp \ dht/dhtsettings.cpp \ dht/keyed25519.cpp \ dynode.cpp \ diff --git a/src/dht/curve25519.cpp b/src/dht/curve25519.cpp new file mode 100644 index 0000000000..0a4761765b --- /dev/null +++ b/src/dht/curve25519.cpp @@ -0,0 +1,244 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License +// +// Curve25519 code from LibSodium reference implementation: https://github.com/jedisct1/libsodium +// src/libsodium/crypto_sign/ed25519/ref10/keypair.c +// master branch commit hash: 350a23ae5d0fb793c98e0a35b3c0f2c4828521ae + +#include "curve25519.h" + +#include +#include +//#include "libtorrent/hasher512.hpp" // for deterministic keys + +#ifdef WIN32 +# include +# include +#else +# include +#endif + +#include + +#ifdef HAVE_WEAK_SYMBOLS +__attribute__((weak)) void +_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1, + const unsigned char *b2, + const size_t len); +__attribute__((weak)) void +_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1, + const unsigned char *b2, + const size_t len) +{ + (void) b1; + (void) b2; + (void) len; +} +#endif + +static int ge_has_small_order(const unsigned char s[32]) +{ + CRYPTO_ALIGN(16) + static const unsigned char blacklist[][32] = { + /* 0 (order 4) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 1 (order 1) */ + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 + (order 8) */ + { 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, + 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, + 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 }, + /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 + (order 8) */ + { 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, + 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, + 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a }, + /* p-1 (order 2) */ + { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p (=0, order 4) */ + { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p+1 (=1, order 1) */ + { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f } + }; + unsigned char c[7] = { 0 }; + unsigned int k; + std::size_t i, j; + + COMPILER_ASSERT(7 == sizeof blacklist / sizeof blacklist[0]); + for (j = 0; j < 31; j++) { + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= s[j] ^ blacklist[i][j]; + } + } + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= (s[j] & 0x7f) ^ blacklist[i][j]; + } + k = 0; + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + k |= (c[i] - 1); + } + return (int) ((k >> 8) & 1); +} + +/* multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493 */ +static void ge_mul_l(ge_p3 *r, const ge_p3 *A) +{ + static const signed char aslide[253] = { + 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + }; + ge_cached Ai[8]; + ge_p1p1 t; + ge_p3 u; + ge_p3 A2; + int i; + + ge_p3_to_cached(&Ai[0], A); + ge_p3_dbl(&t, A); + ge_p1p1_to_p3(&A2, &t); + ge_add(&t, &A2, &Ai[0]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[1], &u); + ge_add(&t, &A2, &Ai[1]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[2], &u); + ge_add(&t, &A2, &Ai[2]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[3], &u); + ge_add(&t, &A2, &Ai[3]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[4], &u); + ge_add(&t, &A2, &Ai[4]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[5], &u); + ge_add(&t, &A2, &Ai[5]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[6], &u); + ge_add(&t, &A2, &Ai[6]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[7], &u); + + ge_p3_0(r); + + for (i = 252; i >= 0; --i) { + ge_p3_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i] / 2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); + } + + ge_p1p1_to_p3(r, &t); + } +} + +//sodium_is_zero: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/sodium/utils.c +static int is_zero(const unsigned char *n, const std::size_t nlen) +{ + std::size_t i; + volatile unsigned char d = 0U; + + for (i = 0U; i < nlen; i++) { + d |= n[i]; + } + return 1 & ((d - 1) >> 8); +} + +static inline int fe_iszero(const fe f) +{ + unsigned char s[32]; + + fe_tobytes(s, f); + + return is_zero(s, 32); +} + +static int ge_is_on_main_subgroup(const ge_p3 *p) +{ + ge_p3 pl; + + ge_mul_l(&pl, p); + + return fe_iszero(pl.X); +} + +//sodium_memzero: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/sodium/utils.c +static void memzero(void *const pnt, const std::size_t len) +{ +#ifdef WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + if (len > 0U && memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif HAVE_WEAK_SYMBOLS + memset(pnt, 0, len); + _dummy_symbol_to_prevent_memzero_lto(pnt, len); +# ifdef HAVE_INLINE_ASM + __asm__ __volatile__ ("" : : "r"(pnt) : "memory"); +# endif +#else + volatile unsigned char *volatile pnt_ = + (volatile unsigned char *volatile) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif +} + +int Ed25519_To_Curve25519_PubKey(unsigned char* curve25519_pubkey, const unsigned char* ed25519_pubkey) +{ + ge_p3 A; + fe x; + fe one_minus_y; + + if (ge_has_small_order(ed25519_pubkey) != 0 || + ge_frombytes_negate_vartime(&A, ed25519_pubkey) != 0 || + ge_is_on_main_subgroup(&A) == 0) { + return -1; + } + fe_1(one_minus_y); + fe_sub(one_minus_y, one_minus_y, A.Y); + fe_1(x); + fe_add(x, x, A.Y); + fe_invert(one_minus_y, one_minus_y); + fe_mul(x, x, one_minus_y); + fe_tobytes(curve25519_pubkey, x); + + return 0; +} + +int Ed25519_To_Curve25519_PrivKey(unsigned char* curve25519_privkey, const unsigned char* ed25519_privkey) +{ + unsigned char h[crypto_hash_sha512_BYTES]; + +//#ifdef ED25519_NONDETERMINISTIC + std::memcpy(h, ed25519_privkey, 32); +//#else +// crypto_hash_sha512(h, ed25519_privkey, 32); +//#endif + h[0] &= 248; + h[31] &= 127; + h[31] |= 64; + std::memcpy(curve25519_privkey, h, crypto_scalarmult_curve25519_BYTES); + memzero(h, sizeof h); + + return 0; +} \ No newline at end of file diff --git a/src/dht/curve25519.h b/src/dht/curve25519.h new file mode 100644 index 0000000000..bba3c25e9d --- /dev/null +++ b/src/dht/curve25519.h @@ -0,0 +1,23 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_DHT_CURVE25519_H +#define DYNAMIC_DHT_CURVE25519_H + +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + +#ifndef CRYPTO_ALIGN +# if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +# else +# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) +# endif +#endif + +#define crypto_hash_sha512_BYTES 64U +#define crypto_scalarmult_curve25519_BYTES 32U + +int Ed25519_To_Curve25519_PubKey(unsigned char* curve25519_pubkey, const unsigned char* ed25519_pubkey); +int Ed25519_To_Curve25519_PrivKey(unsigned char* curve25519_privkey, const unsigned char* ed25519_privkey); + +#endif // DYNAMIC_DHT_CURVE25519_H \ No newline at end of file From be4df2f2863574f75b77dfb3483413d4e174f273 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Thu, 27 Sep 2018 16:20:43 -0500 Subject: [PATCH 0253/1653] [DHT] Fix settings and alert logging --- src/dht/bootstrap.cpp | 103 ++++++++++++++++++++------- src/dht/bootstrap.h | 2 +- src/dht/dhtsettings.cpp | 153 ++++++++++++++-------------------------- src/dht/dhtsettings.h | 10 +-- src/dht/rpcdht.cpp | 41 +++++++---- 5 files changed, 167 insertions(+), 142 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index 4510239cdc..2979d6deee 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -40,26 +40,34 @@ static alert* wait_for_alert(session* dhtSession, int alert_type) while (!found) { dhtSession->wait_for_alert(seconds(5)); - std::vector alerts; dhtSession->pop_alerts(&alerts); for (std::vector::iterator i = alerts.begin() , end(alerts.end()); i != end; ++i) { - LogPrintf("DHTTorrentNetwork -- message = %s, type =%d, alert_type =%d\n", (*i)->message(), (*i)->type(), alert_type); + if ((*i)->category() == 0x1) { + LogPrintf("DHTTorrentNetwork -- error alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + } + else if ((*i)->category() == 0x80) { + LogPrintf("DHTTorrentNetwork -- progress alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + } + else if ((*i)->category() == 0x200) { + LogPrintf("DHTTorrentNetwork -- performance warning alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + } + else if ((*i)->category() == 0x400) { + LogPrintf("DHTTorrentNetwork -- dht alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + } if ((*i)->type() != alert_type) { - //print some alerts? - continue; } + LogPrintf("DHTTorrentNetwork -- wait alert complete. message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); ret = *i; found = true; } if (fShutdown) return ret; } - LogPrintf("DHTTorrentNetwork -- wait_for_alert complete.\n"); return ret; } @@ -84,6 +92,7 @@ static int save_dht_state(session* dhtSession) bencode(std::back_inserter(state), torrentEntry); std::fstream f(get_log_path().c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); f.write(state.data(), state.size()); + LogPrintf("DHTTorrentNetwork -- save_dht_state complete.\n"); return 0; } @@ -150,10 +159,13 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman throw std::runtime_error("DHT Torrent network bootstraping error."); } while (!fShutdown) { - MilliSleep(60000); - //load_dht_state(pTorrentDHTSession); - //bootstrap(pTorrentDHTSession); - //save_dht_state(pTorrentDHTSession); + MilliSleep(5000); + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- not running. Loading from file and restarting bootstrap.\n"); + load_dht_state(pTorrentDHTSession); + bootstrap(pTorrentDHTSession); + save_dht_state(pTorrentDHTSession); + } } } catch (const boost::thread_interrupted&) @@ -170,6 +182,7 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman void StopTorrentDHTNetwork() { + save_dht_state(pTorrentDHTSession); fShutdown = true; if (dhtTorrentThread != NULL) { @@ -179,7 +192,7 @@ void StopTorrentDHTNetwork() LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork stopped.\n"); } else { - LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork dhtTorrentThreads is null. Stop not needed.\n"); + LogPrintf("DHTTorrentNetwork --StopTorrentDHTNetwork dhtTorrentThreads is null. Stop not needed.\n"); } } @@ -193,34 +206,58 @@ void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman) dhtTorrentThread = new boost::thread(DHTTorrentNetwork, boost::cref(chainparams), boost::ref(connman)); } -bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence) +bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative) { //TODO: DHT add locks LogPrintf("DHTTorrentNetwork -- GetDHTMutableData started.\n"); - if (!pTorrentDHTSession) + if (!pTorrentDHTSession) { + //message = "DHTTorrentNetwork -- GetDHTMutableData Error. pTorrentDHTSession is null."; return false; + } - if (!load_dht_state(pTorrentDHTSession)) - bootstrap(pTorrentDHTSession); + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData Restarting DHT.\n"); + if (!load_dht_state(pTorrentDHTSession)) { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData Couldn't load previous settings. Trying to bootstrap again.\n"); + bootstrap(pTorrentDHTSession); + } + else { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData setting loaded from file.\n"); + } + } + else { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData DHT already running. Bootstrap not needed.\n"); + } pTorrentDHTSession->dht_get_item(public_key, entrySalt); LogPrintf("DHTTorrentNetwork -- MGET: %s, salt = %s\n", aux::to_hex(public_key), entrySalt); bool authoritative = false; - while (!authoritative) - { - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); + if (fWaitForAuthoritative) { + while (!authoritative) + { + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); + dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); + authoritative = dhtGetAlert->authoritative; + entryValue = dhtGetAlert->item.to_string(); + lastSequence = dhtGetAlert->seq; + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); + } + } + else { + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); - authoritative = dhtGetAlert->authoritative; entryValue = dhtGetAlert->item.to_string(); lastSequence = dhtGetAlert->seq; LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); } - save_dht_state(pTorrentDHTSession); - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData end.\n"); + + if (entryValue == "") + return false; + return true; } @@ -256,12 +293,25 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< //TODO: (DHT) add locks LogPrintf("DHTTorrentNetwork -- PutMutableData started.\n"); - if (!pTorrentDHTSession) + if (!pTorrentDHTSession) { + message = "DHTTorrentNetwork -- PutDHTMutableData Error. pTorrentDHTSession is null."; return false; + } - if (!load_dht_state(pTorrentDHTSession)) - bootstrap(pTorrentDHTSession); - + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData Restarting DHT.\n"); + if (!load_dht_state(pTorrentDHTSession)) { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData Couldn't load previous settings. Trying to bootstrap again.\n"); + bootstrap(pTorrentDHTSession); + } + else { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData setting loaded from file.\n"); + } + } + else { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData DHT already running. Bootstrap not needed.\n"); + } + pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_mutable, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, public_key, private_key, dhtValue, lastSequence), entrySalt); @@ -270,8 +320,9 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< dht_put_alert* dhtPutAlert = alert_cast(dhtAlert); message = dhtPutAlert->message(); LogPrintf("DHTTorrentNetwork -- PutMutableData %s\n", message); - save_dht_state(pTorrentDHTSession); - LogPrintf("DHTTorrentNetwork -- PutMutableData end.\n"); + + if (dhtPutAlert->num_success == 0) + return false; return true; } \ No newline at end of file diff --git a/src/dht/bootstrap.h b/src/dht/bootstrap.h index 5e3ee623b0..2e62607a70 100644 --- a/src/dht/bootstrap.h +++ b/src/dht/bootstrap.h @@ -15,7 +15,7 @@ void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman); /** Stop the DHT libtorrent network threads */ void StopTorrentDHTNetwork(); /** Get a mutable entry in the libtorrent DHT */ -bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence); +bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative); /** Set a mutable entry in the libtorrent DHT */ bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence ,char const* dhtValue, std::string& message); diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp index 7a7b7e6c0b..9757a49d15 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/dhtsettings.cpp @@ -15,9 +15,8 @@ using namespace libtorrent; CDHTSettings::CDHTSettings() { user_agent = "Dynamic v" + FormatFullVersion(); - // Use ports 33307, 33317, 33327, 33337 and 33347 - listen_interfaces = "0.0.0.0:33307,[::]:33307,0.0.0.0:33317,[::]:33317,0.0.0.0:33327," - "[::]:33327,0.0.0.0:33337,[::]:33337,0.0.0.0:33347,[::]:33347"; + // Use ports 33307 and 33337 + listen_interfaces = "0.0.0.0:33307,[::]:33307,0.0.0.0:33337,[::]:33337"; } void CDHTSettings::LoadPeerList() @@ -69,85 +68,64 @@ void CDHTSettings::LoadSettings() { LoadPeerList(); - settings.set_bool(settings_pack::enable_dht, false); - settings.set_int(settings_pack::alert_mask, 0xffffffff); - session newSession(settings); + params.settings.set_bool(settings_pack::enable_dht, false); + params.settings.set_int(settings_pack::alert_mask, 0xffffffff); + session newSession(params.settings); // Dynamic LibTorrent Settings - - // ``enable_dht`` - // starts the dht node and makes the trackerless service - // available to torrents. - settings.set_bool(settings_pack::enable_dht, true); - - // ``user_agent`` - // this is the client identification to the tracker. The recommended - // format of this string is: "ClientName/ClientVersion - // libtorrent/libtorrentVersion". This name will not only be used when - // making HTTP requests, but also when sending extended headers to - // peers that support that extension. It may not contain \r or \n - settings.set_str(settings_pack::user_agent, user_agent); - - // ``dht_bootstrap_nodes`` - // This is a comma-separated list of IP port-pairs. They will be added - // to the DHT node (if it's enabled) as back-up nodes in case we don't - // know of any. This setting will contain one or more bootstrap nodes - // by default. - // Changing these after the DHT has been started may not have any - // effect until the DHT is restarted. - settings.set_str(settings_pack::dht_bootstrap_nodes, dht_bootstrap_nodes); - - // ``listen_interfaces`` - // a comma-separated list of (IP or device name, port) pairs. These are - // the listen ports that will be opened for accepting incoming uTP and - // TCP connections. It is possible to listen on multiple interfaces and - // multiple ports. Binding to port 0 will make the operating system - // pick the port. The default is "0.0.0.0:6881,[::]:6881", which binds - // to all interfaces on port 6881. - // - // a port that has an "s" suffix will accept SSL connections. (note - // that SSL sockets are not enabled by default). - // - // if binding fails, the listen_failed_alert is posted. If or once a - // socket binding succeeds, the listen_succeeded_alert is posted. There - // may be multiple failures before a success. - // - // For example: - // ``[::1]:8888`` - will only accept connections on the IPv6 loopback - // address on port 8888. - // - // ``eth0:4444,eth1:4444`` - will accept connections on port 4444 on - // any IP address bound to device ``eth0`` or ``eth1``. - // - // ``[::]:0s`` - will accept SSL connections on a port chosen by the - // OS. And not accept non-SSL connections at all. - // - // Windows OS network adapter device name can be specified with GUID. - // It can be obtained from "netsh lan show interfaces" command output. - // GUID must be uppercased string embraced in curly brackets. - // ``{E4F0B674-0DFC-48BB-98A5-2AA730BDB6D6}::7777`` - will accept - // connections on port 7777 on adapter with this GUID. - // TODO: Add peers and dynodes to the dht_bootstrap_nodes list. - settings.set_str(settings_pack::listen_interfaces, listen_interfaces); - - // ``dht_announce_interval`` is the number of seconds between - // announcing torrents to the distributed hash table (DHT). - //settings.set_int(settings_pack::dht_announce_interval, 30); - - // ``enable_outgoing_utp`` ``enable_incoming_utp`` - // ``enable_outgoing_tcp`` ``enable_incoming_tcp`` - // when set to true, libtorrent will try to make outgoing utp - // connections controls whether libtorrent will accept incoming - // connections or make outgoing connections of specific type. - //settings.set_bool(settings_pack::enable_outgoing_utp, true); - //settings.set_bool(settings_pack::enable_incoming_utp, true); - //settings.set_bool(settings_pack::enable_outgoing_tcp, true); - //settings.set_bool(settings_pack::enable_incoming_tcp, true); + // see https://www.libtorrent.org/reference-Settings.html#dht_settings + // DHT Settings + params.dht_settings.max_peers_reply = 100; // default = 100 + params.dht_settings.search_branching = 10; // default = 5 + params.dht_settings.max_fail_count = 100; // default = 20 + params.dht_settings.max_torrents = 2000; + params.dht_settings.max_dht_items = 5000; // default = 700 + params.dht_settings.max_peers = 1000; // default = 5000 + params.dht_settings.max_torrent_search_reply = 20; // default = 20 + + params.dht_settings.restrict_routing_ips = true; // default = true + params.dht_settings.restrict_search_ips = true; // default = true + + params.dht_settings.extended_routing_table = true; // default = true + params.dht_settings.aggressive_lookups = true; // default = true + params.dht_settings.privacy_lookups = false; // default = false + params.dht_settings.enforce_node_id = true; // default = false + + params.dht_settings.ignore_dark_internet = true; // default = true + params.dht_settings.block_timeout = (5 * 60); // default = (5 * 60) + params.dht_settings.block_ratelimit = 10; // default = 5 + params.dht_settings.read_only = false; // default = false + params.dht_settings.item_lifetime = 0; // default = 0 + + // General LibTorrent Settings + params.settings.set_int(settings_pack::alert_mask, 0xffffffff); // receive all alerts + params.settings.set_bool(settings_pack::enable_dht, true); + params.settings.set_str(settings_pack::user_agent, user_agent); + params.settings.set_str(settings_pack::dht_bootstrap_nodes, dht_bootstrap_nodes); + params.settings.set_str(settings_pack::listen_interfaces, listen_interfaces); + params.settings.set_bool(settings_pack::enable_natpmp, true); + params.settings.set_int(settings_pack::dht_announce_interval, (60)); + params.settings.set_bool(settings_pack::enable_outgoing_utp, true); + params.settings.set_bool(settings_pack::enable_incoming_utp, true); + params.settings.set_bool(settings_pack::enable_outgoing_tcp, false); + params.settings.set_bool(settings_pack::enable_incoming_tcp, false); // Apply settings. - newSession.apply_settings(settings); + newSession.set_dht_settings(params.dht_settings); + newSession.apply_settings(params.settings); // TODO: (DHT) Evaluate and test the rest of these settings. + // ``enable_lsd`` + // Starts and stops Local Service Discovery. This service will + // broadcast the info-hashes of all the non-private torrents on the + // local network to look for peers on the same swarm within multicast + // reach. + //params.settings.set_bool(settings_pack::enable_lsd, false); + + // ``prefer_rc4`` + // if the allowed encryption level is both, setting this to true will + // prefer rc4 if both methods are offered, plaintext otherwise + //params.settings.set_bool(settings_pack::prefer_rc4, true); // ``announce_ip`` is the ip address passed along to trackers as the // ``&ip=`` parameter. If left as the default, that parameter is @@ -397,29 +375,6 @@ void CDHTSettings::LoadSettings() // valid until ``stop_upnp()`` is called. See upnp-and-nat-pmp_. //settings.set_bool(settings_pack::enable_upnp, false); - // ``enable_natpmp`` - // Starts and stops the NAT-PMP service. When started, the listen port - // and the DHT port are attempted to be forwarded on the router - // through NAT-PMP. - // The natpmp object returned by ``start_natpmp()`` can be used to add - // and remove arbitrary port mappings. Mapping status is returned - // through the portmap_alert and the portmap_error_alert. The object - // will be valid until ``stop_natpmp()`` is called. See - // upnp-and-nat-pmp_. - //settings.set_bool(settings_pack::enable_natpmp, true); //TODO: should this be true? - - // ``enable_lsd`` - // Starts and stops Local Service Discovery. This service will - // broadcast the info-hashes of all the non-private torrents on the - // local network to look for peers on the same swarm within multicast - // reach. - //settings.set_bool(settings_pack::enable_lsd, true); - - // ``prefer_rc4`` - // if the allowed encryption level is both, setting this to true will - // prefer rc4 if both methods are offered, plaintext otherwise - //settings.set_bool(settings_pack::prefer_rc4, true); //TODO: should this be true? - // ``proxy_hostnames`` // if true, hostname lookups are done via the configured proxy (if // any). This is only supported by SOCKS5 and HTTP. diff --git a/src/dht/dhtsettings.h b/src/dht/dhtsettings.h index 72e7e54613..e8c7945ec4 100644 --- a/src/dht/dhtsettings.h +++ b/src/dht/dhtsettings.h @@ -10,16 +10,18 @@ static constexpr int MIN_DHT_PROTO_VERSION = 71000; class CDHTSettings { private: - libtorrent::settings_pack settings; + libtorrent::session_params params; std::string listen_interfaces; std::string dht_bootstrap_nodes; std::string user_agent; - public: - CDHTSettings(); + void LoadSettings(); - libtorrent::settings_pack GetSettingsPack() const { return settings; } + + libtorrent::settings_pack GetSettingsPack() const { return params.settings; } + libtorrent::dht_settings GetDHTSettings() const { return params.dht_settings; } + libtorrent::session_params GetSessionParams() const { return params; } private: void LoadPeerList(); diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index 62c6127039..670ba2b423 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -32,13 +32,16 @@ UniValue getdhtmutable(const JSONRPCRequest& request) std::string strValue = ""; std::array pubKey; libtorrent::aux::from_hex(strPubKey, pubKey.data()); - fRet = GetDHTMutableData(pubKey, strSalt, strValue, iSequence); + fRet = GetDHTMutableData(pubKey, strSalt, strValue, iSequence, false); if (fRet) { result.push_back(Pair("Get_PubKey", strPubKey)); result.push_back(Pair("Get_Salt", strSalt)); result.push_back(Pair("Get_Seq", iSequence)); result.push_back(Pair("Get_Value", strValue)); } + else { + throw std::runtime_error("getdhtdata failed. Check the debug.log for details.\n"); + } return result; } @@ -54,6 +57,7 @@ UniValue putdhtmutable(const JSONRPCRequest& request) if (!pTorrentDHTSession) return result; + bool fNewEntry = false; char const* putValue = request.params[0].get_str().c_str(); const std::string strSalt = request.params[1].get_str(); std::string strPrivKey; @@ -67,6 +71,7 @@ UniValue putdhtmutable(const JSONRPCRequest& request) key.MakeNewKeyPair(); strPubKey = stringFromVch(key.GetPubKey()); strPrivKey = stringFromVch(key.GetPrivKey()); + fNewEntry = true; } bool fRet = false; @@ -77,19 +82,31 @@ UniValue putdhtmutable(const JSONRPCRequest& request) std::array privKey; libtorrent::aux::from_hex(strPrivKey, privKey.data()); - - fRet = GetDHTMutableData(pubKey, strSalt, strPutValue, iSequence); - std::string dhtMessage = ""; - fRet = PutDHTMutableData(pubKey, privKey, strSalt, iSequence, putValue, dhtMessage); + if (!fNewEntry) { + // we need the last sequence number to update an existing DHT entry. + fRet = GetDHTMutableData(pubKey, strSalt, strPutValue, iSequence, true); + } + else { + fRet = true; + } if (fRet) { - result.push_back(Pair("Put_PubKey", strPubKey)); - result.push_back(Pair("Put_PrivKey", strPrivKey)); - result.push_back(Pair("Put_Salt", strSalt)); - result.push_back(Pair("Put_Seq", iSequence)); - result.push_back(Pair("Put_Value", request.params[0].get_str())); - result.push_back(Pair("Put_Message", dhtMessage)); + std::string dhtMessage = ""; + fRet = PutDHTMutableData(pubKey, privKey, strSalt, iSequence, putValue, dhtMessage); + if (fRet) { + result.push_back(Pair("Put_PubKey", strPubKey)); + result.push_back(Pair("Put_PrivKey", strPrivKey)); + result.push_back(Pair("Put_Salt", strSalt)); + result.push_back(Pair("Put_Seq", iSequence)); + result.push_back(Pair("Put_Value", request.params[0].get_str())); + result.push_back(Pair("Put_Message", dhtMessage)); + } + else { + throw std::runtime_error("putdhtmutable failed. Put failed. Check the debug.log for details.\n"); + } + } + else { + throw std::runtime_error("putdhtmutable failed. Get failed. Check the debug.log for details.\n"); } - return result; } From 6497fe91ecee29cc7b972e8f2ba0d396e45c8cce Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 28 Sep 2018 03:35:04 -0500 Subject: [PATCH 0254/1653] [DHT] Fix get mutable data alert --- src/dht/bootstrap.cpp | 61 ++++++++++++++++++++++++++++++------------- src/dht/rpcdht.cpp | 32 +++++++++-------------- 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index 2979d6deee..7349948851 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -32,38 +32,56 @@ static boost::thread *dhtTorrentThread; static bool fShutdown; session *pTorrentDHTSession = NULL; -static alert* wait_for_alert(session* dhtSession, int alert_type) + +static void empty_public_key(std::array& public_key) +{ + for( unsigned int i = 0; i < sizeof(public_key); i++) { + public_key[i] = 0; + } +} + +static alert* wait_for_alert(session* dhtSession, int alert_type, const std::array public_key, const std::string strSalt) { LogPrintf("DHTTorrentNetwork -- wait_for_alert start.\n"); alert* ret = nullptr; bool found = false; + std::array emptyKey; + empty_public_key(emptyKey); + std::string strEmpty = aux::to_hex(emptyKey); + std::string strPublicKey = aux::to_hex(public_key); while (!found) { dhtSession->wait_for_alert(seconds(5)); std::vector alerts; dhtSession->pop_alerts(&alerts); - for (std::vector::iterator i = alerts.begin() - , end(alerts.end()); i != end; ++i) + for (std::vector::iterator iAlert = alerts.begin(), end(alerts.end()); iAlert != end; ++iAlert) { - if ((*i)->category() == 0x1) { - LogPrintf("DHTTorrentNetwork -- error alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + std::string strAlertMessage = (*iAlert)->message(); + int iAlertType = (*iAlert)->type(); + if ((*iAlert)->category() == 0x1) { + LogPrintf("DHTTorrentNetwork -- error alert message = %s, alert_type =%d\n", strAlertMessage, iAlertType); } - else if ((*i)->category() == 0x80) { - LogPrintf("DHTTorrentNetwork -- progress alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + else if ((*iAlert)->category() == 0x80) { + LogPrintf("DHTTorrentNetwork -- progress alert message = %s, alert_type =%d\n", strAlertMessage, iAlertType); } - else if ((*i)->category() == 0x200) { - LogPrintf("DHTTorrentNetwork -- performance warning alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + else if ((*iAlert)->category() == 0x200) { + LogPrintf("DHTTorrentNetwork -- performance warning alert message = %s, alert_type =%d\n", strAlertMessage, iAlertType); } - else if ((*i)->category() == 0x400) { - LogPrintf("DHTTorrentNetwork -- dht alert message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); + else if ((*iAlert)->category() == 0x400) { + LogPrintf("DHTTorrentNetwork -- dht alert message = %s, alert_type =%d\n", strAlertMessage, iAlertType); } - if ((*i)->type() != alert_type) + if (iAlertType != alert_type) { continue; } - LogPrintf("DHTTorrentNetwork -- wait alert complete. message = %s, alert_type =%d\n", (*i)->message(), (*i)->type()); - ret = *i; - found = true; + + size_t posKey = strAlertMessage.find("key=" + strPublicKey); + size_t posSalt = strAlertMessage.find("salt=" + strSalt); + if (strPublicKey == strEmpty || (posKey != std::string::npos && posSalt != std::string::npos)) { + LogPrintf("DHTTorrentNetwork -- wait alert complete. message = %s, alert_type =%d\n", strAlertMessage, iAlertType); + ret = *iAlert; + found = true; + } } if (fShutdown) return ret; @@ -71,6 +89,13 @@ static alert* wait_for_alert(session* dhtSession, int alert_type) return ret; } +static alert* wait_for_alert(session* dhtSession, int alert_type) +{ + std::array emptyKey; + empty_public_key(emptyKey); + return wait_for_alert(dhtSession, alert_type, emptyKey, ""); +} + static void bootstrap(lt::session* dhtSession) { LogPrintf("DHTTorrentNetwork -- bootstrapping.\n"); @@ -237,7 +262,7 @@ bool GetDHTMutableData(const std::array& public_key, const std::string if (fWaitForAuthoritative) { while (!authoritative) { - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type, public_key, entrySalt); dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); authoritative = dhtGetAlert->authoritative; @@ -247,7 +272,7 @@ bool GetDHTMutableData(const std::array& public_key, const std::string } } else { - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type); + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type, public_key, entrySalt); dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); authoritative = dhtGetAlert->authoritative; entryValue = dhtGetAlert->item.to_string(); @@ -316,7 +341,7 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< std::placeholders::_3, std::placeholders::_4, public_key, private_key, dhtValue, lastSequence), entrySalt); LogPrintf("DHTTorrentNetwork -- MPUT public key: %s, salt = %s, seq=%d\n", aux::to_hex(public_key), entrySalt, lastSequence); - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_put_alert::alert_type); + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_put_alert::alert_type, public_key, entrySalt); dht_put_alert* dhtPutAlert = alert_cast(dhtAlert); message = dhtPutAlert->message(); LogPrintf("DHTTorrentNetwork -- PutMutableData %s\n", message); diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index 670ba2b423..4d9f4dcc5a 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -22,7 +22,7 @@ UniValue getdhtmutable(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); if (!pTorrentDHTSession) - return result; + throw std::runtime_error("getdhtmutable failed. Session is null.\n"); const std::string strPubKey = request.params[0].get_str(); const std::string strSalt = request.params[1].get_str(); @@ -55,7 +55,7 @@ UniValue putdhtmutable(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); if (!pTorrentDHTSession) - return result; + throw std::runtime_error("putdhtmutable failed. Session is null.\n"); bool fNewEntry = false; char const* putValue = request.params[0].get_str().c_str(); @@ -84,28 +84,20 @@ UniValue putdhtmutable(const JSONRPCRequest& request) libtorrent::aux::from_hex(strPrivKey, privKey.data()); if (!fNewEntry) { // we need the last sequence number to update an existing DHT entry. - fRet = GetDHTMutableData(pubKey, strSalt, strPutValue, iSequence, true); - } - else { - fRet = true; + GetDHTMutableData(pubKey, strSalt, strPutValue, iSequence, true); } + std::string dhtMessage = ""; + fRet = PutDHTMutableData(pubKey, privKey, strSalt, iSequence, putValue, dhtMessage); if (fRet) { - std::string dhtMessage = ""; - fRet = PutDHTMutableData(pubKey, privKey, strSalt, iSequence, putValue, dhtMessage); - if (fRet) { - result.push_back(Pair("Put_PubKey", strPubKey)); - result.push_back(Pair("Put_PrivKey", strPrivKey)); - result.push_back(Pair("Put_Salt", strSalt)); - result.push_back(Pair("Put_Seq", iSequence)); - result.push_back(Pair("Put_Value", request.params[0].get_str())); - result.push_back(Pair("Put_Message", dhtMessage)); - } - else { - throw std::runtime_error("putdhtmutable failed. Put failed. Check the debug.log for details.\n"); - } + result.push_back(Pair("Put_PubKey", strPubKey)); + result.push_back(Pair("Put_PrivKey", strPrivKey)); + result.push_back(Pair("Put_Salt", strSalt)); + result.push_back(Pair("Put_Seq", iSequence)); + result.push_back(Pair("Put_Value", request.params[0].get_str())); + result.push_back(Pair("Put_Message", dhtMessage)); } else { - throw std::runtime_error("putdhtmutable failed. Get failed. Check the debug.log for details.\n"); + throw std::runtime_error("putdhtmutable failed. Put failed. Check the debug.log for details.\n"); } return result; } From 05c1b310481e9b6325645462431cdfd5ace4a744 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 28 Sep 2018 04:10:05 -0500 Subject: [PATCH 0255/1653] [DHT] Add stub hash table stats function --- src/dht/bootstrap.cpp | 19 ++++++++- src/dht/bootstrap.h | 4 ++ src/dht/rpcdht.cpp | 95 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index 7349948851..cf78d6e797 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -32,7 +32,6 @@ static boost::thread *dhtTorrentThread; static bool fShutdown; session *pTorrentDHTSession = NULL; - static void empty_public_key(std::array& public_key) { for( unsigned int i = 0; i < sizeof(public_key); i++) { @@ -350,4 +349,22 @@ bool PutDHTMutableData(const std::array& public_key, const std::array< return false; return true; +} + +void GetDHTStats(session_status& stats, std::vector& vchDHTLookup, std::vector& vchDHTBuckets) +{ + LogPrintf("DHTTorrentNetwork -- GetDHTStats started.\n"); + + if (!pTorrentDHTSession) + return; + + if (!load_dht_state(pTorrentDHTSession)) + bootstrap(pTorrentDHTSession); + + pTorrentDHTSession->post_dht_stats(); + alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_stats_alert::alert_type); + dht_stats_alert* dhtStatsAlert = alert_cast(dhtAlert); + vchDHTLookup = dhtStatsAlert->active_requests; + vchDHTBuckets = dhtStatsAlert->routing_table; + stats = pTorrentDHTSession->status(); } \ No newline at end of file diff --git a/src/dht/bootstrap.h b/src/dht/bootstrap.h index 2e62607a70..ce9ca2c8ca 100644 --- a/src/dht/bootstrap.h +++ b/src/dht/bootstrap.h @@ -4,7 +4,9 @@ #ifndef DYNAMIC_DHT_BOOTSTRAP_H #define DYNAMIC_DHT_BOOTSTRAP_H +#include "libtorrent/alert_types.hpp" #include "libtorrent/session.hpp" +#include "libtorrent/session_status.hpp" class CChainParams; class CConnman; @@ -20,6 +22,8 @@ bool GetDHTMutableData(const std::array& public_key, const std::string bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence ,char const* dhtValue, std::string& message); +void GetDHTStats(libtorrent::session_status& stats, std::vector& vchDHTLookup, std::vector& vchDHTBuckets); + extern libtorrent::session *pTorrentDHTSession; #endif // DYNAMIC_DHT_BOOTSTRAP_H diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index 4d9f4dcc5a..af085d6a4d 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -4,12 +4,14 @@ #include "bdap/domainentry.h" #include "dht/bootstrap.h" #include "dht/keyed25519.h" -#include "libtorrent/hex.hpp" // for to_hex and from_hex #include "rpcprotocol.h" #include "rpcserver.h" #include "util.h" #include "utilstrencodings.h" +#include +#include // for to_hex and from_hex + #include @@ -22,7 +24,7 @@ UniValue getdhtmutable(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); if (!pTorrentDHTSession) - throw std::runtime_error("getdhtmutable failed. Session is null.\n"); + throw std::runtime_error("getdhtmutable failed. DHT session not started.\n"); const std::string strPubKey = request.params[0].get_str(); const std::string strSalt = request.params[1].get_str(); @@ -55,8 +57,9 @@ UniValue putdhtmutable(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); if (!pTorrentDHTSession) - throw std::runtime_error("putdhtmutable failed. Session is null.\n"); + throw std::runtime_error("putdhtmutable failed. DHT session not started.\n"); + //TODO: Check putValue is not > 1000 bytes. bool fNewEntry = false; char const* putValue = request.params[0].get_str().c_str(); const std::string strSalt = request.params[1].get_str(); @@ -102,11 +105,97 @@ UniValue putdhtmutable(const JSONRPCRequest& request) return result; } +UniValue dhtinfo(const JSONRPCRequest& request) +{ + if (request.params.size() != 0) + throw std::runtime_error( + "dhtinfo\n" + "\n"); + + if (!pTorrentDHTSession) + throw std::runtime_error("dhtinfo failed. DHT session not started.\n"); + + libtorrent::session_status stats; + std::vector vchDHTLookup; + std::vector vchDHTBuckets; + GetDHTStats(stats, vchDHTLookup, vchDHTBuckets); + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("num_peers", stats.num_peers)); + result.push_back(Pair("peerlist_size", stats.peerlist_size)); + result.push_back(Pair("active_request_size", (int)stats.active_requests.size())); + result.push_back(Pair("dht_node_cache", stats.dht_node_cache)); + result.push_back(Pair("dht_global_nodes", stats.dht_global_nodes)); + result.push_back(Pair("dht_download_rate", stats.dht_download_rate)); + result.push_back(Pair("dht_upload_rate", stats.dht_upload_rate)); + result.push_back(Pair("dht_total_allocations", stats.dht_total_allocations)); + result.push_back(Pair("download_rate", stats.download_rate)); + result.push_back(Pair("upload_rate", stats.upload_rate)); + result.push_back(Pair("total_download", stats.total_download)); + result.push_back(Pair("total_upload", stats.total_upload)); + result.push_back(Pair("total_dht_download", stats.total_dht_download)); + result.push_back(Pair("total_dht_upload", stats.total_dht_upload)); + result.push_back(Pair("total_ip_overhead_download", stats.total_ip_overhead_download)); + result.push_back(Pair("total_ip_overhead_upload", stats.total_ip_overhead_upload)); + result.push_back(Pair("total_payload_download", stats.total_payload_download)); + result.push_back(Pair("total_payload_upload", stats.total_payload_upload)); + result.push_back(Pair("dht_nodes", stats.dht_nodes)); + result.push_back(Pair("dht_torrents", stats.dht_torrents)); + + for (const libtorrent::dht_routing_bucket& bucket : vchDHTBuckets){ + UniValue oBucket(UniValue::VOBJ); + oBucket.push_back(Pair("num_nodes", bucket.num_nodes)); + oBucket.push_back(Pair("num_replacements", bucket.num_replacements)); + oBucket.push_back(Pair("last_active", bucket.last_active)); + result.push_back(Pair("bucket", oBucket)); + } + + for (const libtorrent::dht_lookup& lookup : vchDHTLookup) { + UniValue oLookup(UniValue::VOBJ); + oLookup.push_back(Pair("outstanding_requests", lookup.outstanding_requests)); + oLookup.push_back(Pair("timeouts", lookup.timeouts)); + oLookup.push_back(Pair("responses", lookup.responses)); + oLookup.push_back(Pair("branch_factor", lookup.branch_factor)); + oLookup.push_back(Pair("nodes_left", lookup.nodes_left)); + oLookup.push_back(Pair("last_sent", lookup.last_sent)); + oLookup.push_back(Pair("first_timeout", lookup.first_timeout)); + // string literal indicating which kind of lookup this is + // char const* type; + // the node-id or info-hash target for this lookup + //sha1_hash target; + result.push_back(oLookup); + result.push_back(Pair("lookup", oLookup)); + } +/* + result.push_back(Pair("ip_overhead_download_rate", stats.ip_overhead_download_rate)); + result.push_back(Pair("ip_overhead_upload_rate", stats.ip_overhead_upload_rate)); + result.push_back(Pair("payload_download_rate", stats.payload_download_rate)); + result.push_back(Pair("payload_upload_rate", stats.payload_upload_rate)); + result.push_back(Pair("tracker_upload_rate", stats.tracker_upload_rate)); + result.push_back(Pair("tracker_download_rate", stats.tracker_download_rate)); + result.push_back(Pair("total_tracker_download", stats.total_tracker_download)); + result.push_back(Pair("total_tracker_upload", stats.total_tracker_upload)); + result.push_back(Pair("total_redundant_bytes", stats.total_redundant_bytes)); + result.push_back(Pair("total_failed_bytes", stats.total_failed_bytes)); + result.push_back(Pair("num_unchoked", stats.num_unchoked)); + result.push_back(Pair("allowed_upload_slots", stats.allowed_upload_slots)); + result.push_back(Pair("up_bandwidth_queue", stats.up_bandwidth_queue)); + result.push_back(Pair("down_bandwidth_queue", stats.down_bandwidth_queue)); + result.push_back(Pair("up_bandwidth_bytes_queue", stats.up_bandwidth_bytes_queue)); + result.push_back(Pair("down_bandwidth_bytes_queue", stats.down_bandwidth_bytes_queue)); + result.push_back(Pair("optimistic_unchoke_counter", stats.optimistic_unchoke_counter)); + result.push_back(Pair("unchoke_counter", stats.unchoke_counter)); + result.push_back(Pair("has_incoming_connections", stats.has_incoming_connections)); +*/ + return result; +} + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode /* DHT */ { "dht", "getdhtmutable", &getdhtmutable, true }, { "dht", "putdhtmutable", &putdhtmutable, true }, + { "dht", "dhtinfo", &dhtinfo, true }, }; void RegisterDHTRPCCommands(CRPCTable &tableRPC) From ae693c79ff6eb41eb8c665a3fbca6f2166740c29 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Fri, 28 Sep 2018 20:40:09 -0500 Subject: [PATCH 0256/1653] [DHT] Update to use standard thread pointer and shutdown safely --- src/dht/bootstrap.cpp | 67 +++++++++++++++++++++++++++++-------------- src/init.cpp | 2 +- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index cf78d6e797..30b332bb62 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -17,7 +17,6 @@ #include "libtorrent/kademlia/ed25519.hpp" #include "libtorrent/span.hpp" -#include #include #include @@ -28,7 +27,8 @@ using namespace libtorrent; -static boost::thread *dhtTorrentThread; +static std::shared_ptr pDHTTorrentThread; + static bool fShutdown; session *pTorrentDHTSession = NULL; @@ -50,7 +50,7 @@ static alert* wait_for_alert(session* dhtSession, int alert_type, const std::arr std::string strPublicKey = aux::to_hex(public_key); while (!found) { - dhtSession->wait_for_alert(seconds(5)); + dhtSession->wait_for_alert(seconds(1)); std::vector alerts; dhtSession->pop_alerts(&alerts); for (std::vector::iterator iAlert = alerts.begin(), end(alerts.end()); iAlert != end; ++iAlert) @@ -95,7 +95,7 @@ static alert* wait_for_alert(session* dhtSession, int alert_type) return wait_for_alert(dhtSession, alert_type, emptyKey, ""); } -static void bootstrap(lt::session* dhtSession) +static void bootstrap(libtorrent::session* dhtSession) { LogPrintf("DHTTorrentNetwork -- bootstrapping.\n"); wait_for_alert(dhtSession, dht_bootstrap_alert::alert_type); @@ -174,6 +174,7 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman // boot strap the DHT LibTorrent network // with current peers and Dynodes + unsigned int iCounter = 0; settings.LoadSettings(); pTorrentDHTSession = new session(settings.GetSettingsPack()); load_dht_state(pTorrentDHTSession); @@ -183,22 +184,26 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman throw std::runtime_error("DHT Torrent network bootstraping error."); } while (!fShutdown) { - MilliSleep(5000); + MilliSleep(1000); + iCounter ++; if (!pTorrentDHTSession->is_dht_running()) { LogPrintf("DHTTorrentNetwork -- not running. Loading from file and restarting bootstrap.\n"); load_dht_state(pTorrentDHTSession); bootstrap(pTorrentDHTSession); save_dht_state(pTorrentDHTSession); } + else { + if (iCounter >= 300) { + // save DHT state every 5 minutes + save_dht_state(pTorrentDHTSession); + iCounter = 0; + } + } } } - catch (const boost::thread_interrupted&) - { - LogPrintf("DHTTorrentNetwork -- terminated\n"); - throw; - } catch (const std::runtime_error& e) { + fShutdown = true; LogPrintf("DHTTorrentNetwork -- runtime error: %s\n", e.what()); return; } @@ -206,28 +211,34 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman void StopTorrentDHTNetwork() { - save_dht_state(pTorrentDHTSession); + LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork begin.\n"); fShutdown = true; - if (dhtTorrentThread != NULL) + MilliSleep(1100); + if (pDHTTorrentThread != NULL) { - dhtTorrentThread->interrupt(); - delete dhtTorrentThread; - dhtTorrentThread = NULL; - LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork stopped.\n"); + LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork trying to stop.\n"); + libtorrent::session_params params; + params.settings.set_bool(settings_pack::enable_dht, false); + params.settings.set_int(settings_pack::alert_mask, 0x0); + pTorrentDHTSession->apply_settings(params.settings); + pTorrentDHTSession->abort(); + pDHTTorrentThread->join(); + LogPrintf("DHTTorrentNetwork -- StopTorrentDHTNetwork abort.\n"); } else { - LogPrintf("DHTTorrentNetwork --StopTorrentDHTNetwork dhtTorrentThreads is null. Stop not needed.\n"); + LogPrintf("DHTTorrentNetwork --StopTorrentDHTNetwork pDHTTorrentThreads is null. Stop not needed.\n"); } + pDHTTorrentThread = NULL; } void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman) { LogPrintf("DHTTorrentNetwork -- Log file = %s.\n", get_log_path()); fShutdown = false; - if (dhtTorrentThread != NULL) + if (pDHTTorrentThread != NULL) StopTorrentDHTNetwork(); - dhtTorrentThread = new boost::thread(DHTTorrentNetwork, boost::cref(chainparams), boost::ref(connman)); + pDHTTorrentThread = std::make_shared(std::bind(&DHTTorrentNetwork, std::cref(chainparams), std::ref(connman))); } bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative) @@ -355,11 +366,23 @@ void GetDHTStats(session_status& stats, std::vector& vchDHTLookup, s { LogPrintf("DHTTorrentNetwork -- GetDHTStats started.\n"); - if (!pTorrentDHTSession) + if (!pTorrentDHTSession) { return; + } - if (!load_dht_state(pTorrentDHTSession)) - bootstrap(pTorrentDHTSession); + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- GetDHTStats Restarting DHT.\n"); + if (!load_dht_state(pTorrentDHTSession)) { + LogPrintf("DHTTorrentNetwork -- GetDHTStats Couldn't load previous settings. Trying to bootstrap again.\n"); + bootstrap(pTorrentDHTSession); + } + else { + LogPrintf("DHTTorrentNetwork -- GetDHTStats setting loaded from file.\n"); + } + } + else { + LogPrintf("DHTTorrentNetwork -- GetDHTStats DHT already running. Bootstrap not needed.\n"); + } pTorrentDHTSession->post_dht_stats(); alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_stats_alert::alert_type); diff --git a/src/init.cpp b/src/init.cpp index 22c60d2a2d..275b21b861 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -233,11 +233,11 @@ void PrepareShutdown() /// module was initialized. RenameThread("dynamic-shutoff"); mempool.AddTransactionsUpdated(1); + StopTorrentDHTNetwork(); StopHTTPRPC(); StopREST(); StopRPC(); StopHTTPServer(); - StopTorrentDHTNetwork(); #ifdef ENABLE_WALLET if (pwalletMain) pwalletMain->Flush(false); From 6aa784bdaf449e2e05b181ea38ab74a531e2d21c Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 2 Oct 2018 04:50:19 -0500 Subject: [PATCH 0257/1653] [DHT] Add and use custom storage class for dht --- src/Makefile.am | 2 + src/dht/bootstrap.cpp | 3 +- src/dht/dhtsettings.cpp | 88 ++++---- src/dht/dhtsettings.h | 2 + src/dht/persistence.cpp | 436 ++++++++++++++++++++++++++++++++++++++++ src/dht/persistence.h | 188 +++++++++++++++++ 6 files changed, 677 insertions(+), 42 deletions(-) create mode 100644 src/dht/persistence.cpp create mode 100644 src/dht/persistence.h diff --git a/src/Makefile.am b/src/Makefile.am index 05cd79f743..084eb99a64 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -116,6 +116,7 @@ DYNAMIC_CORE_H = \ dht/curve25519.h \ dht/dhtsettings.h \ dht/keyed25519.h \ + dht/persistence.h \ dynode.h \ dynode-payments.h \ dynode-sync.h \ @@ -256,6 +257,7 @@ libdynamic_server_a_SOURCES = \ dht/curve25519.cpp \ dht/dhtsettings.cpp \ dht/keyed25519.cpp \ + dht/persistence.cpp \ dynode.cpp \ dynode-payments.cpp\ dynode-sync.cpp \ diff --git a/src/dht/bootstrap.cpp b/src/dht/bootstrap.cpp index 30b332bb62..ab794c3382 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/bootstrap.cpp @@ -176,8 +176,7 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman // with current peers and Dynodes unsigned int iCounter = 0; settings.LoadSettings(); - pTorrentDHTSession = new session(settings.GetSettingsPack()); - load_dht_state(pTorrentDHTSession); + pTorrentDHTSession = settings.GetSession(); bootstrap(pTorrentDHTSession); save_dht_state(pTorrentDHTSession); if (!pTorrentDHTSession) { diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp index 9757a49d15..a9156d5553 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/dhtsettings.cpp @@ -3,6 +3,7 @@ #include "dht/dhtsettings.h" +#include "dht/persistence.h" #include "clientversion.h" #include "dynode.h" #include "dynodeman.h" @@ -10,6 +11,8 @@ #include "primitives/transaction.h" #include "util.h" +#include + using namespace libtorrent; CDHTSettings::CDHTSettings() @@ -67,52 +70,57 @@ void CDHTSettings::LoadPeerList() void CDHTSettings::LoadSettings() { LoadPeerList(); - + params.settings.set_bool(settings_pack::enable_dht, false); - params.settings.set_int(settings_pack::alert_mask, 0xffffffff); - session newSession(params.settings); - + session* newSession = new session(params.settings); + ses = newSession; + if (!ses->is_dht_running()) { + ses->set_dht_storage(dht::dht_bdap_storage_constructor); + // General LibTorrent Settings + params.settings.set_int(settings_pack::alert_mask, 0xffffffff); // receive all alerts + params.settings.set_bool(settings_pack::enable_dht, true); + params.settings.set_str(settings_pack::user_agent, user_agent); + params.settings.set_str(settings_pack::dht_bootstrap_nodes, dht_bootstrap_nodes); + params.settings.set_str(settings_pack::listen_interfaces, listen_interfaces); + params.dht_settings.max_peers_reply = 100; // default = 100 + params.dht_settings.search_branching = 10; // default = 5 + params.dht_settings.max_fail_count = 100; // default = 20 + params.dht_settings.max_torrents = 2000; + params.dht_settings.max_dht_items = 5000; // default = 700 + params.dht_settings.max_peers = 1000; // default = 5000 + params.dht_settings.max_torrent_search_reply = 20; // default = 20 + + params.dht_settings.restrict_routing_ips = true; // default = true + params.dht_settings.restrict_search_ips = true; // default = true + + params.dht_settings.extended_routing_table = true; // default = true + params.dht_settings.aggressive_lookups = true; // default = true + params.dht_settings.privacy_lookups = false; // default = false + params.dht_settings.enforce_node_id = true; // default = false + + params.dht_settings.ignore_dark_internet = true; // default = true + params.dht_settings.block_timeout = (5 * 60); // default = (5 * 60) + params.dht_settings.block_ratelimit = 10; // default = 5 + params.dht_settings.read_only = false; // default = false + params.dht_settings.item_lifetime = 0; // default = 0 + + params.settings.set_bool(settings_pack::enable_natpmp, true); + params.settings.set_int(settings_pack::dht_announce_interval, (60)); + params.settings.set_bool(settings_pack::enable_outgoing_utp, true); + params.settings.set_bool(settings_pack::enable_incoming_utp, true); + params.settings.set_bool(settings_pack::enable_outgoing_tcp, false); + params.settings.set_bool(settings_pack::enable_incoming_tcp, false); + + ses->apply_settings(params.settings); + ses->set_dht_storage(dht::dht_bdap_storage_constructor); + } // Dynamic LibTorrent Settings // see https://www.libtorrent.org/reference-Settings.html#dht_settings // DHT Settings - params.dht_settings.max_peers_reply = 100; // default = 100 - params.dht_settings.search_branching = 10; // default = 5 - params.dht_settings.max_fail_count = 100; // default = 20 - params.dht_settings.max_torrents = 2000; - params.dht_settings.max_dht_items = 5000; // default = 700 - params.dht_settings.max_peers = 1000; // default = 5000 - params.dht_settings.max_torrent_search_reply = 20; // default = 20 - - params.dht_settings.restrict_routing_ips = true; // default = true - params.dht_settings.restrict_search_ips = true; // default = true - - params.dht_settings.extended_routing_table = true; // default = true - params.dht_settings.aggressive_lookups = true; // default = true - params.dht_settings.privacy_lookups = false; // default = false - params.dht_settings.enforce_node_id = true; // default = false - - params.dht_settings.ignore_dark_internet = true; // default = true - params.dht_settings.block_timeout = (5 * 60); // default = (5 * 60) - params.dht_settings.block_ratelimit = 10; // default = 5 - params.dht_settings.read_only = false; // default = false - params.dht_settings.item_lifetime = 0; // default = 0 - - // General LibTorrent Settings - params.settings.set_int(settings_pack::alert_mask, 0xffffffff); // receive all alerts - params.settings.set_bool(settings_pack::enable_dht, true); - params.settings.set_str(settings_pack::user_agent, user_agent); - params.settings.set_str(settings_pack::dht_bootstrap_nodes, dht_bootstrap_nodes); - params.settings.set_str(settings_pack::listen_interfaces, listen_interfaces); - params.settings.set_bool(settings_pack::enable_natpmp, true); - params.settings.set_int(settings_pack::dht_announce_interval, (60)); - params.settings.set_bool(settings_pack::enable_outgoing_utp, true); - params.settings.set_bool(settings_pack::enable_incoming_utp, true); - params.settings.set_bool(settings_pack::enable_outgoing_tcp, false); - params.settings.set_bool(settings_pack::enable_incoming_tcp, false); // Apply settings. - newSession.set_dht_settings(params.dht_settings); - newSession.apply_settings(params.settings); + ses->set_dht_settings(params.dht_settings); + ses->apply_settings(params.settings); // TODO: (DHT) Evaluate and test the rest of these settings. // ``enable_lsd`` diff --git a/src/dht/dhtsettings.h b/src/dht/dhtsettings.h index e8c7945ec4..7ed99247bc 100644 --- a/src/dht/dhtsettings.h +++ b/src/dht/dhtsettings.h @@ -10,6 +10,7 @@ static constexpr int MIN_DHT_PROTO_VERSION = 71000; class CDHTSettings { private: + libtorrent::session* ses; libtorrent::session_params params; std::string listen_interfaces; std::string dht_bootstrap_nodes; @@ -22,6 +23,7 @@ class CDHTSettings { libtorrent::settings_pack GetSettingsPack() const { return params.settings; } libtorrent::dht_settings GetDHTSettings() const { return params.dht_settings; } libtorrent::session_params GetSessionParams() const { return params; } + libtorrent::session* GetSession() const { return ses; } private: void LoadPeerList(); diff --git a/src/dht/persistence.cpp b/src/dht/persistence.cpp new file mode 100644 index 0000000000..1f2a0221f1 --- /dev/null +++ b/src/dht/persistence.cpp @@ -0,0 +1,436 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#include "persistence.h" + +#include "util.h" + +#include +#include // for ip_v4 +#include +#include +#include + +namespace libtorrent { +namespace dht { + +// internal +bool operator<(peer_entry const& lhs, peer_entry const& rhs) +{ + return lhs.addr.address() == rhs.addr.address() + ? lhs.addr.port() < rhs.addr.port() + : lhs.addr.address() < rhs.addr.address(); +} + +// TODO: 2 make this configurable in dht_settings +constexpr time_duration announce_interval = minutes(30); + +void set_value(dht_immutable_item& item, span buf) +{ + int const size = int(buf.size()); + if (item.size != size) + { + item.value.reset(new char[std::size_t(size)]); + item.size = size; + } + std::memcpy(item.value.get(), buf.data(), buf.size()); +} + +void touch_item(dht_immutable_item& f, address const& addr) +{ + f.last_seen = aux::time_now(); + + // maybe increase num_announcers if we haven't seen this IP before + sha1_hash const iphash = hash_address(addr); + if (!f.ips.find(iphash)) + { + f.ips.set(iphash); + ++f.num_announcers; + } +} + +size_t dht_bdap_storage::num_torrents() const +{ + LogPrintf("********** dht_bdap_storage -- num_torrents ********** \n"); + return m_map.size(); +} + +size_t dht_bdap_storage::num_peers() const +{ + LogPrintf("********** dht_bdap_storage -- num_peers ********** \n"); + size_t ret = 0; + for (auto const& t : m_map) + ret += t.second.peers4.size() + t.second.peers6.size(); + return ret; +} + +void dht_bdap_storage::update_node_ids(std::vector const& ids) +{ + LogPrintf("********** dht_bdap_storage -- update_node_ids ********** \n"); + m_node_ids = ids; +} + +bool dht_bdap_storage::get_peers(sha1_hash const& info_hash, bool const noseed, bool const scrape, address const& requester, entry& peers) const +{ + LogPrintf("********** dht_bdap_storage -- get_peers ********** \n"); + auto const i = m_map.find(info_hash); + if (i == m_map.end()) return int(m_map.size()) >= m_settings.max_torrents; + + torrent_entry const& v = i->second; + auto const& peersv = requester.is_v4() ? v.peers4 : v.peers6; + + if (!v.name.empty()) peers["n"] = v.name; + + if (scrape) + { + bloom_filter<256> downloaders; + bloom_filter<256> seeds; + + for (auto const& p : peersv) + { + sha1_hash const iphash = hash_address(p.addr.address()); + if (p.seed) seeds.set(iphash); + else downloaders.set(iphash); + } + + peers["BFpe"] = downloaders.to_string(); + peers["BFsd"] = seeds.to_string(); + } + else + { + tcp const protocol = requester.is_v4() ? tcp::v4() : tcp::v6(); + int to_pick = m_settings.max_peers_reply; + TORRENT_ASSERT(to_pick >= 0); + // if these are IPv6 peers their addresses are 4x the size of IPv4 + // so reduce the max peers 4 fold to compensate + // max_peers_reply should probably be specified in bytes + if (!peersv.empty() && protocol == tcp::v6()) + to_pick /= 4; + entry::list_type& pe = peers["values"].list(); + + int candidates = int(std::count_if(peersv.begin(), peersv.end() + , [=](peer_entry const& e) { return !(noseed && e.seed); })); + + to_pick = std::min(to_pick, candidates); + + for (auto iter = peersv.begin(); to_pick > 0; ++iter) + { + // if the node asking for peers is a seed, skip seeds from the + // peer list + if (noseed && iter->seed) continue; + + TORRENT_ASSERT(candidates >= to_pick); + + // pick this peer with probability + // / + if (random(std::uint32_t(candidates--)) > std::uint32_t(to_pick)) + continue; + + pe.emplace_back(); + std::string& str = pe.back().string(); + + str.resize(18); + std::string::iterator out = str.begin(); + detail::write_endpoint(iter->addr, out); + str.resize(std::size_t(out - str.begin())); + + --to_pick; + } + } + + if (int(peersv.size()) < m_settings.max_peers) + return false; + + // we're at the max peers stored for this torrent + // only send a write token if the requester is already in the set + // only check for a match on IP because the peer may be announcing + // a different port than the one it is using to send DHT messages + peer_entry requester_entry; + requester_entry.addr.address(requester); + auto requester_iter = std::lower_bound(peersv.begin(), peersv.end(), requester_entry); + return requester_iter == peersv.end() + || requester_iter->addr.address() != requester; +} + +void dht_bdap_storage::announce_peer(sha1_hash const& info_hash, tcp::endpoint const& endp, string_view name, bool const seed) +{ + LogPrintf("********** dht_bdap_storage -- announce_peer ********** \n"); + auto const ti = m_map.find(info_hash); + torrent_entry* v; + if (ti == m_map.end()) + { + if (int(m_map.size()) >= m_settings.max_torrents) + { + // we're at capacity, drop the announce + return; + } + + m_counters.torrents += 1; + v = &m_map[info_hash]; + } + else + { + v = &ti->second; + } + + // the peer announces a torrent name, and we don't have a name + // for this torrent. Store it. + if (!name.empty() && v->name.empty()) + { + v->name = name.substr(0, 100).to_string(); + } + + auto& peersv = is_v4(endp) ? v->peers4 : v->peers6; + + peer_entry peer; + peer.addr = endp; + peer.added = aux::time_now(); + peer.seed = seed; + auto i = std::lower_bound(peersv.begin(), peersv.end(), peer); + if (i != peersv.end() && i->addr == endp) + { + *i = peer; + } + else if (int(peersv.size()) >= m_settings.max_peers) + { + // we're at capacity, drop the announce + return; + } + else + { + peersv.insert(i, peer); + m_counters.peers += 1; + } +} + +// Do not support get immutable item +bool dht_bdap_storage::get_immutable_item(sha1_hash const& target, entry& item) const +{ + LogPrintf("********** dht_bdap_storage -- get_immutable_item ********** \n"); + return false; +} + +void dht_bdap_storage::put_immutable_item(sha1_hash const& target, span buf, address const& addr) +{ + LogPrintf("********** dht_bdap_storage -- put_immutable_item ********** \n"); +} + +bool dht_bdap_storage::get_mutable_item_seq(sha1_hash const& target, sequence_number& seq) const +{ + LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq ********** \n"); + auto const i = m_mutable_table.find(target); + if (i == m_mutable_table.end()) return false; + + seq = i->second.seq; + return true; +} + +bool dht_bdap_storage::get_mutable_item(sha1_hash const& target, sequence_number const seq, bool const force_fill, entry& item) const +{ + LogPrintf("********** dht_bdap_storage -- get_mutable_item ********** \n"); + auto const i = m_mutable_table.find(target); + if (i == m_mutable_table.end()) return false; + + dht_mutable_item const& f = i->second; + item["seq"] = f.seq.value; + if (force_fill || (sequence_number(0) <= seq && seq < f.seq)) + { + item["v"] = bdecode(f.value.get(), f.value.get() + f.size); + item["sig"] = f.sig.bytes; + item["k"] = f.key.bytes; + } + return true; +} + +void dht_bdap_storage::put_mutable_item(sha1_hash const& target + , span buf + , signature const& sig + , sequence_number const seq + , public_key const& pk + , span salt + , address const& addr) +{ + LogPrintf("********** dht_bdap_storage -- put_mutable_item ********** \n"); + TORRENT_ASSERT(!m_node_ids.empty()); + auto i = m_mutable_table.find(target); + if (i == m_mutable_table.end()) + { + // this is the case where we don't have an item in this slot + // make sure we don't add too many items + if (int(m_mutable_table.size()) >= m_settings.max_dht_items) + { + auto const j = pick_least_important_item(m_node_ids + , m_mutable_table); + + TORRENT_ASSERT(j != m_mutable_table.end()); + m_mutable_table.erase(j); + m_counters.mutable_data -= 1; + } + dht_mutable_item to_add; + set_value(to_add, buf); + to_add.seq = seq; + to_add.salt = {salt.begin(), salt.end()}; + to_add.sig = sig; + to_add.key = pk; + + std::tie(i, std::ignore) = m_mutable_table.insert( + std::make_pair(target, std::move(to_add))); + m_counters.mutable_data += 1; + } + else + { + // this is the case where we already + dht_mutable_item& item = i->second; + + if (item.seq < seq) + { + set_value(item, buf); + item.seq = seq; + item.sig = sig; + } + } + + touch_item(i->second, addr); +} + + +int dht_bdap_storage::get_infohashes_sample(entry& item) +{ + LogPrintf("********** dht_bdap_storage -- get_infohashes_sample ********** \n"); + item["interval"] = aux::clamp(m_settings.sample_infohashes_interval + , 0, sample_infohashes_interval_max); + item["num"] = int(m_map.size()); + + refresh_infohashes_sample(); + + aux::vector const& samples = m_infohashes_sample.samples; + item["samples"] = span( + reinterpret_cast(samples.data()), samples.size() * 20); + + return m_infohashes_sample.count(); +} + +void dht_bdap_storage::tick() +{ + LogPrintf("********** dht_bdap_storage -- tick ********** \n"); + // look through all peers and see if any have timed out + for (auto i = m_map.begin(), end(m_map.end()); i != end;) + { + torrent_entry& t = i->second; + purge_peers(t.peers4); + purge_peers(t.peers6); + + if (!t.peers4.empty() || !t.peers6.empty()) + { + ++i; + continue; + } + + // if there are no more peers, remove the entry altogether + i = m_map.erase(i); + m_counters.torrents -= 1;// peers is decreased by purge_peers + } + + if (0 == m_settings.item_lifetime) return; + + time_point const now = aux::time_now(); + time_duration lifetime = seconds(m_settings.item_lifetime); + // item lifetime must >= 120 minutes. + if (lifetime < minutes(120)) lifetime = minutes(120); + + for (auto i = m_immutable_table.begin(); i != m_immutable_table.end();) + { + if (i->second.last_seen + lifetime > now) + { + ++i; + continue; + } + i = m_immutable_table.erase(i); + m_counters.immutable_data -= 1; + } + + for (auto i = m_mutable_table.begin(); i != m_mutable_table.end();) + { + if (i->second.last_seen + lifetime > now) + { + ++i; + continue; + } + i = m_mutable_table.erase(i); + m_counters.mutable_data -= 1; + } +} + +dht_storage_counters dht_bdap_storage::counters() const +{ + LogPrintf("********** dht_bdap_storage -- counters ********** \n"); + return m_counters; +} + +void dht_bdap_storage::purge_peers(std::vector& peers) +{ + LogPrintf("********** dht_bdap_storage -- purge_peers ********** \n"); + auto now = aux::time_now(); + auto new_end = std::remove_if(peers.begin(), peers.end() + , [=](peer_entry const& e) + { + return e.added + announce_interval * 3 / 2 < now; + }); + + m_counters.peers -= std::int32_t(std::distance(new_end, peers.end())); + peers.erase(new_end, peers.end()); + // if we're using less than 1/4 of the capacity free up the excess + if (!peers.empty() && peers.capacity() / peers.size() >= 4U) + peers.shrink_to_fit(); +} + +void dht_bdap_storage::refresh_infohashes_sample() +{ + LogPrintf("********** dht_bdap_storage -- refresh_infohashes_sample ********** \n"); + time_point const now = aux::time_now(); + int const interval = aux::clamp(m_settings.sample_infohashes_interval + , 0, sample_infohashes_interval_max); + + int const max_count = aux::clamp(m_settings.max_infohashes_sample_count + , 0, infohashes_sample_count_max); + int const count = std::min(max_count, int(m_map.size())); + + if (interval > 0 + && m_infohashes_sample.created + seconds(interval) > now + && m_infohashes_sample.count() >= max_count) + return; + + aux::vector& samples = m_infohashes_sample.samples; + samples.clear(); + samples.reserve(count); + + int to_pick = count; + int candidates = int(m_map.size()); + + for (auto const& t : m_map) + { + if (to_pick == 0) + break; + + TORRENT_ASSERT(candidates >= to_pick); + + // pick this key with probability + // / + if (random(std::uint32_t(candidates--)) > std::uint32_t(to_pick)) + continue; + + samples.push_back(t.first); + --to_pick; + } + + TORRENT_ASSERT(int(samples.size()) == count); + m_infohashes_sample.created = now; +} + +std::unique_ptr dht_bdap_storage_constructor(dht_settings const& settings) +{ + return std::unique_ptr(new dht_bdap_storage(settings)); +} + +} // namespace dht +} // namespace libtorrent \ No newline at end of file diff --git a/src/dht/persistence.h b/src/dht/persistence.h new file mode 100644 index 0000000000..77df9ef1c4 --- /dev/null +++ b/src/dht/persistence.h @@ -0,0 +1,188 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_DHT_PERSISTENCE_H +#define DYNAMIC_DHT_PERSISTENCE_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace libtorrent { +namespace dht { + +struct dht_immutable_item +{ + // the actual value + std::unique_ptr value; + // this counts the number of IPs we have seen + // announcing this item, this is used to determine + // popularity if we reach the limit of items to store + bloom_filter<128> ips; + // the last time we heard about this item + // the correct interpretation of this field + // requires a time reference + time_point last_seen; + // number of IPs in the bloom filter + int num_announcers = 0; + // size of malloced space pointed to by value + int size = 0; +}; + +struct dht_mutable_item : dht_immutable_item +{ + signature sig{}; + sequence_number seq{}; + public_key key{}; + std::string salt; +}; + +// this is the entry for every peer +// the timestamp is there to make it possible +// to remove stale peers +struct peer_entry +{ + time_point added; + tcp::endpoint addr; + bool seed = 0; +}; + +// this is a group. It contains a set of group members +struct torrent_entry +{ + std::string name; + std::vector peers4; + std::vector peers6; +}; + +struct infohashes_sample +{ + aux::vector samples; + time_point created = min_time(); + + int count() const { return int(samples.size()); } +}; + +// return true of the first argument is a better candidate for removal, i.e. +// less important to keep +struct immutable_item_comparator +{ + explicit immutable_item_comparator(std::vector const& node_ids) : m_node_ids(node_ids) {} + immutable_item_comparator(immutable_item_comparator const&) = default; + + template + bool operator()(std::pair const& lhs + , std::pair const& rhs) const + { + int const l_distance = min_distance_exp(lhs.first, m_node_ids); + int const r_distance = min_distance_exp(rhs.first, m_node_ids); + + // this is a score taking the popularity (number of announcers) and the + // fit, in terms of distance from ideal storing node, into account. + // each additional 5 announcers is worth one extra bit in the distance. + // that is, an item with 10 announcers is allowed to be twice as far + // from another item with 5 announcers, from our node ID. Twice as far + // because it gets one more bit. + return lhs.second.num_announcers / 5 - l_distance < rhs.second.num_announcers / 5 - r_distance; + } + +private: + // explicitly disallow assignment, to silence msvc warning + immutable_item_comparator& operator=(immutable_item_comparator const&) = delete; + + std::vector const& m_node_ids; +}; + +void set_value(dht_immutable_item& item, span buf); +void touch_item(dht_immutable_item& f, address const& addr); + +using node_id = libtorrent::sha1_hash; + +// picks the least important one (i.e. the one +// the fewest peers are announcing, and farthest +// from our node IDs) +template +typename std::map::const_iterator pick_least_important_item( + std::vector const& node_ids, std::map const& table) +{ + return std::min_element(table.begin(), table.end(), immutable_item_comparator(node_ids)); +} + +constexpr int sample_infohashes_interval_max = 21600; +constexpr int infohashes_sample_count_max = 20; + +class dht_bdap_storage final : public dht_storage_interface +{ +public: + + explicit dht_bdap_storage(dht_settings const& settings) + : m_settings(settings) + { + //LogPrintf("********** dht_bdap_storage -- constructor ********** \n"); + m_counters.reset(); + } + + ~dht_bdap_storage() override + { + //LogPrintf("********** dht_bdap_storage -- destructor ********** \n"); + }; + + dht_bdap_storage(dht_bdap_storage const&) = delete; + dht_bdap_storage& operator=(dht_bdap_storage const&) = delete; + + size_t num_torrents() const override; + size_t num_peers() const override; + void update_node_ids(std::vector const& ids) override; + bool get_peers(sha1_hash const& info_hash, bool const noseed, bool const scrape, address const& requester, entry& peers) const override; + void announce_peer(sha1_hash const& info_hash, tcp::endpoint const& endp, string_view name, bool const seed) override; + // Do not support get immutable item + bool get_immutable_item(sha1_hash const& target, entry& item) const override; + // Do not support put immutable item + void put_immutable_item(sha1_hash const& target, span buf, address const& addr) override; + bool get_mutable_item_seq(sha1_hash const& target, sequence_number& seq) const override; + bool get_mutable_item(sha1_hash const& target, sequence_number const seq, bool const force_fill, entry& item) const override; + void put_mutable_item(sha1_hash const& target + , span buf + , signature const& sig + , sequence_number const seq + , public_key const& pk + , span salt + , address const& addr) override; + + int get_infohashes_sample(entry& item) override; + void tick() override; + dht_storage_counters counters() const override; + +private: + dht_settings const& m_settings; + dht_storage_counters m_counters; + + std::vector m_node_ids; + std::map m_map; + std::map m_immutable_table; + std::map m_mutable_table; + + infohashes_sample m_infohashes_sample; + + void purge_peers(std::vector& peers); + void refresh_infohashes_sample(); +}; + +std::unique_ptr dht_bdap_storage_constructor(dht_settings const& settings); + +} // namespace dht +} // namespace libtorrent + + +#endif // DYNAMIC_DHT_PERSISTENCE_H From 4dae404b9a74e648efd6b2dfdbfa788abf24ed06 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Tue, 2 Oct 2018 09:01:13 -0500 Subject: [PATCH 0258/1653] [DHT] Use LevelDB for dht persistence instead of memory --- src/Makefile.am | 2 + src/dht/mutabledata.cpp | 134 ++++++++++++++++++++++++++++++++++++++++ src/dht/mutabledata.h | 94 ++++++++++++++++++++++++++++ src/dht/persistence.cpp | 93 ++++++++++++---------------- src/dht/persistence.h | 2 + 5 files changed, 273 insertions(+), 52 deletions(-) create mode 100644 src/dht/mutabledata.cpp create mode 100644 src/dht/mutabledata.h diff --git a/src/Makefile.am b/src/Makefile.am index 084eb99a64..b7ce8f8572 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -116,6 +116,7 @@ DYNAMIC_CORE_H = \ dht/curve25519.h \ dht/dhtsettings.h \ dht/keyed25519.h \ + dht/mutabledata.h \ dht/persistence.h \ dynode.h \ dynode-payments.h \ @@ -257,6 +258,7 @@ libdynamic_server_a_SOURCES = \ dht/curve25519.cpp \ dht/dhtsettings.cpp \ dht/keyed25519.cpp \ + dht/mutabledata.cpp \ dht/persistence.cpp \ dynode.cpp \ dynode-payments.cpp\ diff --git a/src/dht/mutabledata.cpp b/src/dht/mutabledata.cpp new file mode 100644 index 0000000000..a5c1762aa2 --- /dev/null +++ b/src/dht/mutabledata.cpp @@ -0,0 +1,134 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#include "dht/mutabledata.h" + +#include "bdap/domainentry.h" +#include "hash.h" + +#include + +#include + +static CMutableDataDB *pMutableDataDB = NULL; + +static std::shared_ptr pMutableDataDBThread; + +bool AddMutableData(const std::vector& vchInfoHash,const CMutableData& data) +{ + if (!pMutableDataDB) { + return false; + } + if (!pMutableDataDB->AddMutableData(data)) { + return false; + } + return true; +} + +bool UpdateMutableData(const std::vector& vchInfoHash,const CMutableData& data) +{ + if (!pMutableDataDB) { + return false; + } + if (!pMutableDataDB->UpdateMutableData(data)) { + return false; + } + return true; +} + +bool GetMutableData(const std::vector& vchInfoHash, CMutableData& data) +{ + if (!pMutableDataDB || !pMutableDataDB->ReadMutableData(vchInfoHash, data)) { + return false; + } + return !data.IsNull(); +} + +bool PutMutableData(const std::vector& vchInfoHash, const CMutableData& data) +{ + if (!pMutableDataDB) { + return false; + } + CMutableData readMutableData; + if (pMutableDataDB->ReadMutableData(vchInfoHash, readMutableData)) { + UpdateMutableData(vchInfoHash, data); + } + else { + AddMutableData(vchInfoHash, data); + } + return !data.IsNull(); +} + +bool EraseMutableData(const std::vector& vchInfoHash) +{ + if (!pMutableDataDB) { + return false; + } + if (!pMutableDataDB->EraseMutableData(vchInfoHash)) { + return false; + } + return true; +} + +void CMutableData::Serialize(std::vector& vchData) +{ + CDataStream dsMutableData(SER_NETWORK, PROTOCOL_VERSION); + dsMutableData << *this; + vchData = std::vector(dsMutableData.begin(), dsMutableData.end()); +} + +bool CMutableData::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsMutableData(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsMutableData >> *this; + + std::vector vchMutableData; + Serialize(vchMutableData); + const uint256 &calculatedHash = Hash(vchMutableData.begin(), vchMutableData.end()); + const std::vector &vchRandMutableData = vchFromValue(calculatedHash.GetHex()); + if(vchRandMutableData != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +bool CMutableDataDB::AddMutableData(const CMutableData& data) +{ + bool writeState = false; + { + LOCK(cs_dht_entry); + writeState = CDBWrapper::Write(make_pair(std::string("ih"), data.InfoHash), data); // use info hash as key + } + return writeState; +} + +bool CMutableDataDB::ReadMutableData(const std::vector& vchInfoHash, CMutableData& data) +{ + LOCK(cs_dht_entry); + return CDBWrapper::Read(make_pair(std::string("ih"), vchInfoHash), data); +} + +bool CMutableDataDB::EraseMutableData(const std::vector& vchInfoHash) +{ + LOCK(cs_dht_entry); + return CDBWrapper::Erase(make_pair(std::string("ih"), vchInfoHash)); +} + +bool CMutableDataDB::UpdateMutableData(const CMutableData& data) +{ + LOCK(cs_dht_entry); + + if (!EraseMutableData(data.InfoHash)) + return false; + + bool writeState = false; + writeState = CDBWrapper::Update(make_pair(std::string("ih"), data.InfoHash), data); + return writeState; +} \ No newline at end of file diff --git a/src/dht/mutabledata.h b/src/dht/mutabledata.h new file mode 100644 index 0000000000..6fb1fe5b6d --- /dev/null +++ b/src/dht/mutabledata.h @@ -0,0 +1,94 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_DHT_MUTABLE_DATA_H +#define DYNAMIC_DHT_MUTABLE_DATA_H + +#include "bdap/bdap.h" +#include "dbwrapper.h" +#include "serialize.h" +#include "sync.h" +#include "uint256.h" + +static CCriticalSection cs_dht_entry; + +class CMutableData { +public: + static const int CURRENT_VERSION=1; + int nVersion; + CharString InfoHash; // key + CharString PublicKey; + CharString Signature; + std::int64_t SequenceNumber; + CharString Salt; + CharString Value; + + CMutableData() { + SetNull(); + } + + inline void SetNull() + { + nVersion = CMutableData::CURRENT_VERSION; + InfoHash.clear(); + PublicKey.clear(); + Signature.clear(); + SequenceNumber = 0; + Salt.clear(); + Value.clear(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(this->nVersion); + READWRITE(InfoHash); + READWRITE(PublicKey); + READWRITE(Signature); + READWRITE(VARINT(SequenceNumber)); + READWRITE(Salt); + READWRITE(Value); + } + + inline friend bool operator==(const CMutableData &a, const CMutableData &b) { + return (a.InfoHash == b.InfoHash && a.PublicKey == b.PublicKey && a.Signature == b.Signature); + } + + inline friend bool operator!=(const CMutableData &a, const CMutableData &b) { + return !(a == b); + } + + inline CMutableData operator=(const CMutableData &b) { + nVersion = b.nVersion; + InfoHash = b.InfoHash; + PublicKey = b.PublicKey; + Signature = b.Signature; + SequenceNumber = b.SequenceNumber; + Salt = b.Salt; + Value = b.Value; + return *this; + } + + inline bool IsNull() const { return (Signature.empty()); } + void Serialize(std::vector& vchData); + bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); +}; + +class CMutableDataDB : public CDBWrapper { +public: + CMutableDataDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "dht", nCacheSize, fMemory, fWipe, obfuscate) { + } + + bool AddMutableData(const CMutableData& data); + bool UpdateMutableData(const CMutableData& data); + bool ReadMutableData(const std::vector& vchInfoHash, CMutableData& data); + bool EraseMutableData(const std::vector& vchInfoHash); +}; + +bool AddMutableData(const std::vector& vchInfoHash, const CMutableData& data); +bool UpdateMutableData(const std::vector& vchInfoHash, const CMutableData& data); +bool GetMutableData(const std::vector& vchInfoHash, CMutableData& data); +bool PutMutableData(const std::vector& vchInfoHash, const CMutableData& data); + +#endif // DYNAMIC_DHT_MUTABLE_DATA_H diff --git a/src/dht/persistence.cpp b/src/dht/persistence.cpp index 1f2a0221f1..d06289f468 100644 --- a/src/dht/persistence.cpp +++ b/src/dht/persistence.cpp @@ -3,6 +3,8 @@ #include "persistence.h" +#include "bdap/domainentry.h" +#include "dht/mutabledata.h" #include "util.h" #include @@ -22,8 +24,7 @@ bool operator<(peer_entry const& lhs, peer_entry const& rhs) : lhs.addr.address() < rhs.addr.address(); } -// TODO: 2 make this configurable in dht_settings -constexpr time_duration announce_interval = minutes(30); +constexpr time_duration announce_interval = minutes(ANNOUNCE_INTERVAL_MINUTES); void set_value(dht_immutable_item& item, span buf) { @@ -218,27 +219,30 @@ void dht_bdap_storage::put_immutable_item(sha1_hash const& target, spansecond.seq; + CMutableData mutableData; + std::string strInfoHash = target.to_string(); + CharString vchInfoHash = vchFromString(strInfoHash); + if (!GetMutableData(vchInfoHash, mutableData)) { + return false; + } + seq = dht::sequence_number(mutableData.SequenceNumber); return true; } bool dht_bdap_storage::get_mutable_item(sha1_hash const& target, sequence_number const seq, bool const force_fill, entry& item) const { LogPrintf("********** dht_bdap_storage -- get_mutable_item ********** \n"); - auto const i = m_mutable_table.find(target); - if (i == m_mutable_table.end()) return false; - dht_mutable_item const& f = i->second; - item["seq"] = f.seq.value; - if (force_fill || (sequence_number(0) <= seq && seq < f.seq)) - { - item["v"] = bdecode(f.value.get(), f.value.get() + f.size); - item["sig"] = f.sig.bytes; - item["k"] = f.key.bytes; + CMutableData mutableData; + std::string strInfoHash = target.to_string(); + CharString vchInfoHash = vchFromString(strInfoHash); + if (!GetMutableData(vchInfoHash, mutableData)) { + return false; } + if (!(seq == dht::sequence_number(mutableData.SequenceNumber))) { + return false; + } + item = stringFromVch(mutableData.Value); return true; } @@ -251,49 +255,34 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target , address const& addr) { LogPrintf("********** dht_bdap_storage -- put_mutable_item ********** \n"); - TORRENT_ASSERT(!m_node_ids.empty()); - auto i = m_mutable_table.find(target); - if (i == m_mutable_table.end()) - { - // this is the case where we don't have an item in this slot - // make sure we don't add too many items - if (int(m_mutable_table.size()) >= m_settings.max_dht_items) - { - auto const j = pick_least_important_item(m_node_ids - , m_mutable_table); - - TORRENT_ASSERT(j != m_mutable_table.end()); - m_mutable_table.erase(j); - m_counters.mutable_data -= 1; + CMutableData mutableData; + //TODO: convert these variables + //mutableData.Value = buf; + //mutableData.Signature = sig.bytes(); + //mutableData.SequenceNumber = seq; + //mutableData.PublicKey = pk.bytes(); + //mutableData.Salt = salt; + CMutableData getData; + std::string strInfoHash = target.to_string(); + CharString vchInfoHash = vchFromString(strInfoHash); + if (!GetMutableData(vchInfoHash, getData)) { + if (!PutMutableData(vchInfoHash, mutableData)) { + return; } - dht_mutable_item to_add; - set_value(to_add, buf); - to_add.seq = seq; - to_add.salt = {salt.begin(), salt.end()}; - to_add.sig = sig; - to_add.key = pk; - - std::tie(i, std::ignore) = m_mutable_table.insert( - std::make_pair(target, std::move(to_add))); - m_counters.mutable_data += 1; } - else - { - // this is the case where we already - dht_mutable_item& item = i->second; - - if (item.seq < seq) - { - set_value(item, buf); - item.seq = seq; - item.sig = sig; + else { + if ((seq < dht::sequence_number(mutableData.SequenceNumber))) { + return; + } + else { + if (!PutMutableData(vchInfoHash, mutableData)) { + return; + } } } - - touch_item(i->second, addr); + return; } - int dht_bdap_storage::get_infohashes_sample(entry& item) { LogPrintf("********** dht_bdap_storage -- get_infohashes_sample ********** \n"); diff --git a/src/dht/persistence.h b/src/dht/persistence.h index 77df9ef1c4..2821207c2d 100644 --- a/src/dht/persistence.h +++ b/src/dht/persistence.h @@ -19,6 +19,8 @@ #include #include +static constexpr unsigned int ANNOUNCE_INTERVAL_MINUTES = 30; + namespace libtorrent { namespace dht { From 0f0003b0bdac831a5c7671bc09301c380c360586 Mon Sep 17 00:00:00 2001 From: Amir Abrams Date: Tue, 2 Oct 2018 17:53:36 -0500 Subject: [PATCH 0259/1653] Fix MacOS build error and warning --- src/bdap/domainentry.h | 2 +- src/dht/rpcdht.cpp | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index 3a657a4324..4579c32154 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -16,7 +16,7 @@ class CCoinsViewCache; class CDynamicAddress; -class CRecipient; +struct CRecipient; class CTransaction; class CTxOut; class CTxMemPool; diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index 88a3451798..de850f0291 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -106,9 +106,6 @@ UniValue putdhtmutable(const JSONRPCRequest& request) throw std::runtime_error("putdhtmutable failed. Put failed. Check the debug.log for details.\n"); } } - else { - throw std::runtime_error("putdhtmutable failed. Get failed. Check the debug.log for details.\n"); - } else { throw std::runtime_error("putdhtmutable failed. Put failed. Check the debug.log for details.\n"); } From dad673a8a3b3a3b6bdcfb54a0f37d45564f8ac24 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 3 Oct 2018 01:21:01 -0500 Subject: [PATCH 0260/1653] [DHT] Implement LevelDB storage for DHT mutable entries --- src/dht/dhtsettings.cpp | 14 +++++- src/dht/mutabledata.cpp | 6 +-- src/dht/mutabledata.h | 6 +++ src/dht/persistence.cpp | 99 ++++++++++++++++++++++++++--------------- src/init.cpp | 7 ++- 5 files changed, 89 insertions(+), 43 deletions(-) diff --git a/src/dht/dhtsettings.cpp b/src/dht/dhtsettings.cpp index a9156d5553..94eb58cdfe 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/dhtsettings.cpp @@ -19,7 +19,9 @@ CDHTSettings::CDHTSettings() { user_agent = "Dynamic v" + FormatFullVersion(); // Use ports 33307 and 33337 - listen_interfaces = "0.0.0.0:33307,[::]:33307,0.0.0.0:33337,[::]:33337"; + listen_interfaces = "0.0.0.0:33307,[::]:33307,0.0.0.0:33317,[::]:33317"; + //"0.0.0.0:33327,[::]:33327,0.0.0.0:33337,[::]:33337" + //"0.0.0.0:33347,[::]:33347"; } void CDHTSettings::LoadPeerList() @@ -38,7 +40,11 @@ void CDHTSettings::LoadPeerList() } pos = strPeerList.find(strDynodeIP); if (pos == std::string::npos) { - strPeerList += strDynodeIP + ":33307,"; + strPeerList += strDynodeIP + ":33307,"; + //strPeerList += strDynodeIP + ":33317,"; + //strPeerList += strDynodeIP + ":33327,"; + //strPeerList += strDynodeIP + ":33337,"; + //strPeerList += strDynodeIP + ":33347,"; } } } @@ -57,6 +63,10 @@ void CDHTSettings::LoadPeerList() pos = strPeerList.find(strPeerIP); if (pos == std::string::npos) { strPeerList += strPeerIP + ":33307,"; + //strPeerList += strPeerIP + ":33317,"; + //strPeerList += strPeerIP + ":33327,"; + //strPeerList += strPeerIP + ":33337,"; + //strPeerList += strPeerIP + ":33347,"; } } } diff --git a/src/dht/mutabledata.cpp b/src/dht/mutabledata.cpp index a5c1762aa2..fed92ac378 100644 --- a/src/dht/mutabledata.cpp +++ b/src/dht/mutabledata.cpp @@ -8,11 +8,7 @@ #include -#include - -static CMutableDataDB *pMutableDataDB = NULL; - -static std::shared_ptr pMutableDataDBThread; +CMutableDataDB *pMutableDataDB = NULL; bool AddMutableData(const std::vector& vchInfoHash,const CMutableData& data) { diff --git a/src/dht/mutabledata.h b/src/dht/mutabledata.h index 6fb1fe5b6d..b00fcf17ea 100644 --- a/src/dht/mutabledata.h +++ b/src/dht/mutabledata.h @@ -27,6 +27,10 @@ class CMutableData { SetNull(); } + CMutableData(const CharString& infoHash, const CharString& publicKey, const CharString& signature, + const std::int64_t& sequenceNumber, const CharString& salt, const CharString& value) : + InfoHash(infoHash), PublicKey(publicKey), Signature(signature), SequenceNumber(sequenceNumber), Salt(salt), Value(value){} + inline void SetNull() { nVersion = CMutableData::CURRENT_VERSION; @@ -91,4 +95,6 @@ bool UpdateMutableData(const std::vector& vchInfoHash, const CMut bool GetMutableData(const std::vector& vchInfoHash, CMutableData& data); bool PutMutableData(const std::vector& vchInfoHash, const CMutableData& data); +extern CMutableDataDB* pMutableDataDB; + #endif // DYNAMIC_DHT_MUTABLE_DATA_H diff --git a/src/dht/persistence.cpp b/src/dht/persistence.cpp index d06289f468..98c0efc824 100644 --- a/src/dht/persistence.cpp +++ b/src/dht/persistence.cpp @@ -10,6 +10,7 @@ #include #include // for ip_v4 #include +#include #include #include @@ -52,13 +53,13 @@ void touch_item(dht_immutable_item& f, address const& addr) size_t dht_bdap_storage::num_torrents() const { - LogPrintf("********** dht_bdap_storage -- num_torrents ********** \n"); + LogPrintf("********** dht_bdap_storage -- num_torrents **********\n"); return m_map.size(); } size_t dht_bdap_storage::num_peers() const { - LogPrintf("********** dht_bdap_storage -- num_peers ********** \n"); + LogPrintf("********** dht_bdap_storage -- num_peers **********\n"); size_t ret = 0; for (auto const& t : m_map) ret += t.second.peers4.size() + t.second.peers6.size(); @@ -67,13 +68,13 @@ size_t dht_bdap_storage::num_peers() const void dht_bdap_storage::update_node_ids(std::vector const& ids) { - LogPrintf("********** dht_bdap_storage -- update_node_ids ********** \n"); + LogPrintf("********** dht_bdap_storage -- update_node_ids **********\n"); m_node_ids = ids; } bool dht_bdap_storage::get_peers(sha1_hash const& info_hash, bool const noseed, bool const scrape, address const& requester, entry& peers) const { - LogPrintf("********** dht_bdap_storage -- get_peers ********** \n"); + LogPrintf("********** dht_bdap_storage -- get_peers **********\n"); auto const i = m_map.find(info_hash); if (i == m_map.end()) return int(m_map.size()) >= m_settings.max_torrents; @@ -155,7 +156,7 @@ bool dht_bdap_storage::get_peers(sha1_hash const& info_hash, bool const noseed, void dht_bdap_storage::announce_peer(sha1_hash const& info_hash, tcp::endpoint const& endp, string_view name, bool const seed) { - LogPrintf("********** dht_bdap_storage -- announce_peer ********** \n"); + LogPrintf("********** dht_bdap_storage -- announce_peer **********\n"); auto const ti = m_map.find(info_hash); torrent_entry* v; if (ti == m_map.end()) @@ -207,45 +208,69 @@ void dht_bdap_storage::announce_peer(sha1_hash const& info_hash, tcp::endpoint c // Do not support get immutable item bool dht_bdap_storage::get_immutable_item(sha1_hash const& target, entry& item) const { - LogPrintf("********** dht_bdap_storage -- get_immutable_item ********** \n"); + //TODO: this is not the best place to reject an immutable_item, we should ban the sender as well + LogPrintf("********** dht_bdap_storage -- get_immutable_item **********\n"); return false; } void dht_bdap_storage::put_immutable_item(sha1_hash const& target, span buf, address const& addr) { - LogPrintf("********** dht_bdap_storage -- put_immutable_item ********** \n"); + //TODO: this is not the best place to reject an immutable_item, we should ban the sender as well + LogPrintf("********** dht_bdap_storage -- put_immutable_item **********\n"); } bool dht_bdap_storage::get_mutable_item_seq(sha1_hash const& target, sequence_number& seq) const { - LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq ********** \n"); CMutableData mutableData; - std::string strInfoHash = target.to_string(); + std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); if (!GetMutableData(vchInfoHash, mutableData)) { return false; } seq = dht::sequence_number(mutableData.SequenceNumber); + LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq seq = %u\n", mutableData.SequenceNumber); return true; } bool dht_bdap_storage::get_mutable_item(sha1_hash const& target, sequence_number const seq, bool const force_fill, entry& item) const { - LogPrintf("********** dht_bdap_storage -- get_mutable_item ********** \n"); - CMutableData mutableData; - std::string strInfoHash = target.to_string(); + std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); if (!GetMutableData(vchInfoHash, mutableData)) { + LogPrintf("********** dht_bdap_storage -- get_mutable_item failed to get mutable data from leveldb.\n"); return false; } - if (!(seq == dht::sequence_number(mutableData.SequenceNumber))) { - return false; - } item = stringFromVch(mutableData.Value); + LogPrintf("********** dht_bdap_storage -- get_mutable_item, Value = %s, seq_found = %d, seq_query = %d\n", + stringFromVch(mutableData.Value), mutableData.SequenceNumber, seq.value); return true; } +static std::string CleanPutValue(std::string value) +{ + std::string strReturn = ""; + size_t posStart = 3; // always start at the third char + size_t posEnd = 0; + if (!(posStart == std::string::npos)) { + posEnd = value.find("e1:q3:put1:t"); + if (!(posEnd == std::string::npos) && value.size() > posEnd) { + strReturn = value.substr(posStart, posEnd - posStart); + } + } + return strReturn; +} + +static std::string CleanSalt(std::string salt) +{ + std::string strReturn = ""; + size_t posEnd = salt.find("3:seqi1e3:"); + if (!(posEnd == std::string::npos) && salt.size() > posEnd) { + strReturn = salt.substr(0, posEnd); + } + return strReturn; +} + void dht_bdap_storage::put_mutable_item(sha1_hash const& target , span buf , signature const& sig @@ -254,38 +279,42 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target , span salt , address const& addr) { - LogPrintf("********** dht_bdap_storage -- put_mutable_item ********** \n"); - CMutableData mutableData; - //TODO: convert these variables - //mutableData.Value = buf; - //mutableData.Signature = sig.bytes(); - //mutableData.SequenceNumber = seq; - //mutableData.PublicKey = pk.bytes(); - //mutableData.Salt = salt; - CMutableData getData; - std::string strInfoHash = target.to_string(); + std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); - if (!GetMutableData(vchInfoHash, getData)) { - if (!PutMutableData(vchInfoHash, mutableData)) { + std::string strValue = CleanPutValue(std::string(buf.data())); + CharString vchValue = vchFromString(strValue); + std::string strSignature = aux::to_hex(std::string(sig.bytes.data())); + CharString vchSignature = vchFromString(strSignature); + std::string strPublicKey = aux::to_hex(std::string(pk.bytes.data())); + CharString vchPublicKey = vchFromString(strPublicKey); + std::string strSalt = CleanSalt(std::string(salt.data())); + CharString vchSalt = vchFromString(strSalt); + CMutableData putMutableData(vchInfoHash, vchPublicKey, vchSignature, seq.value, vchSalt, vchValue); + LogPrintf("********** dht_bdap_storage -- put_mutable_item info_hash = %s, buf_value = %s, sig = %s, pubkey = %s, salt = %s, seq = %d \n", + strInfoHash, strValue, strSignature, strPublicKey, strSalt, putMutableData.SequenceNumber); + CMutableData previousData; + if (!GetMutableData(vchInfoHash, previousData)) { + if (!PutMutableData(vchInfoHash, putMutableData)) { return; } } else { - if ((seq < dht::sequence_number(mutableData.SequenceNumber))) { + if ((seq < dht::sequence_number(putMutableData.SequenceNumber))) { return; } else { - if (!PutMutableData(vchInfoHash, mutableData)) { + if (!UpdateMutableData(vchInfoHash, putMutableData)) { return; } } } - return; + LogPrintf("********** dht_bdap_storage -- put_mutable_item completed successfully**********\n"); + return; } int dht_bdap_storage::get_infohashes_sample(entry& item) { - LogPrintf("********** dht_bdap_storage -- get_infohashes_sample ********** \n"); + LogPrintf("********** dht_bdap_storage -- get_infohashes_sample **********\n"); item["interval"] = aux::clamp(m_settings.sample_infohashes_interval , 0, sample_infohashes_interval_max); item["num"] = int(m_map.size()); @@ -301,7 +330,7 @@ int dht_bdap_storage::get_infohashes_sample(entry& item) void dht_bdap_storage::tick() { - LogPrintf("********** dht_bdap_storage -- tick ********** \n"); + LogPrintf("********** dht_bdap_storage -- tick **********\n"); // look through all peers and see if any have timed out for (auto i = m_map.begin(), end(m_map.end()); i != end;) { @@ -352,13 +381,13 @@ void dht_bdap_storage::tick() dht_storage_counters dht_bdap_storage::counters() const { - LogPrintf("********** dht_bdap_storage -- counters ********** \n"); + LogPrintf("********** dht_bdap_storage -- counters **********\n"); return m_counters; } void dht_bdap_storage::purge_peers(std::vector& peers) { - LogPrintf("********** dht_bdap_storage -- purge_peers ********** \n"); + LogPrintf("********** dht_bdap_storage -- purge_peers **********\n"); auto now = aux::time_now(); auto new_end = std::remove_if(peers.begin(), peers.end() , [=](peer_entry const& e) @@ -375,7 +404,7 @@ void dht_bdap_storage::purge_peers(std::vector& peers) void dht_bdap_storage::refresh_infohashes_sample() { - LogPrintf("********** dht_bdap_storage -- refresh_infohashes_sample ********** \n"); + LogPrintf("********** dht_bdap_storage -- refresh_infohashes_sample **********\n"); time_point const now = aux::time_now(); int const interval = aux::clamp(m_settings.sample_infohashes_interval , 0, sample_infohashes_interval_max); diff --git a/src/init.cpp b/src/init.cpp index 275b21b861..5173155c79 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -21,6 +21,7 @@ #include "bdap/domainentrydb.h" #include "dht/keyed25519.h" #include "dht/bootstrap.h" +#include "dht/mutabledata.h" #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeconfig.h" @@ -1503,6 +1504,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // LibTorrent DHT Netowrk Services delete pTorrentDHTSession; + delete pMutableDataDB; pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); @@ -1516,9 +1518,12 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) pFluidMintDB = new CFluidMintDB(nTotalCache * 35, false, fReindex, obfuscate); pFluidSovereignDB = new CFluidSovereignDB(nTotalCache * 35, false, fReindex, obfuscate); - // Init BDAP Services DB's + // Init BDAP Services DBs pDomainEntryDB = new CDomainEntryDB(nTotalCache * 35, false, fReindex, obfuscate); + // Init DHT Services DB + pMutableDataDB = new CMutableDataDB(nTotalCache * 35, false, fReindex, obfuscate); + if (fReindex) { pblocktree->WriteReindexing(true); //If we're reindexing in prune mode, wipe away unusable block files and all undo data files From ba868da689d7faed6fdae6733865507f0e2b3963 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 3 Oct 2018 08:21:14 -0500 Subject: [PATCH 0261/1653] [DHT] Fix value parsing for leveldb storage - shorten RPC commands to getdht and putdht --- src/dht/persistence.cpp | 29 ++++++++++++++--------------- src/dht/rpcdht.cpp | 12 ++++++------ 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/dht/persistence.cpp b/src/dht/persistence.cpp index 98c0efc824..3d637949e6 100644 --- a/src/dht/persistence.cpp +++ b/src/dht/persistence.cpp @@ -228,7 +228,7 @@ bool dht_bdap_storage::get_mutable_item_seq(sha1_hash const& target, sequence_nu return false; } seq = dht::sequence_number(mutableData.SequenceNumber); - LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq seq = %u\n", mutableData.SequenceNumber); + LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq found seq = %u\n", mutableData.SequenceNumber); return true; } @@ -242,15 +242,15 @@ bool dht_bdap_storage::get_mutable_item(sha1_hash const& target, sequence_number return false; } item = stringFromVch(mutableData.Value); - LogPrintf("********** dht_bdap_storage -- get_mutable_item, Value = %s, seq_found = %d, seq_query = %d\n", + LogPrintf("********** dht_bdap_storage -- get_mutable_item found, Value = %s, seq_found = %d, seq_query = %d\n", stringFromVch(mutableData.Value), mutableData.SequenceNumber, seq.value); return true; } -static std::string CleanPutValue(std::string value) +static std::string ExtractPutValue(std::string value) { std::string strReturn = ""; - size_t posStart = 3; // always start at the third char + size_t posStart = value.find(":") + 1; size_t posEnd = 0; if (!(posStart == std::string::npos)) { posEnd = value.find("e1:q3:put1:t"); @@ -261,7 +261,7 @@ static std::string CleanPutValue(std::string value) return strReturn; } -static std::string CleanSalt(std::string salt) +static std::string ExtractSalt(std::string salt) { std::string strReturn = ""; size_t posEnd = salt.find("3:seqi1e3:"); @@ -281,34 +281,33 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target { std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); - std::string strValue = CleanPutValue(std::string(buf.data())); + std::string strValue = ExtractPutValue(std::string(buf.data())); CharString vchValue = vchFromString(strValue); std::string strSignature = aux::to_hex(std::string(sig.bytes.data())); CharString vchSignature = vchFromString(strSignature); std::string strPublicKey = aux::to_hex(std::string(pk.bytes.data())); CharString vchPublicKey = vchFromString(strPublicKey); - std::string strSalt = CleanSalt(std::string(salt.data())); + std::string strSalt = ExtractSalt(std::string(salt.data())); CharString vchSalt = vchFromString(strSalt); CMutableData putMutableData(vchInfoHash, vchPublicKey, vchSignature, seq.value, vchSalt, vchValue); LogPrintf("********** dht_bdap_storage -- put_mutable_item info_hash = %s, buf_value = %s, sig = %s, pubkey = %s, salt = %s, seq = %d \n", strInfoHash, strValue, strSignature, strPublicKey, strSalt, putMutableData.SequenceNumber); CMutableData previousData; if (!GetMutableData(vchInfoHash, previousData)) { - if (!PutMutableData(vchInfoHash, putMutableData)) { - return; + if (PutMutableData(vchInfoHash, putMutableData)) { + LogPrintf("********** dht_bdap_storage -- put_mutable_item added successfully**********\n"); } } else { - if ((seq < dht::sequence_number(putMutableData.SequenceNumber))) { - return; + if (putMutableData.Value != previousData.Value || putMutableData.SequenceNumber != previousData.SequenceNumber) { + if (UpdateMutableData(vchInfoHash, putMutableData)) { + LogPrintf("********** dht_bdap_storage -- put_mutable_item updated successfully**********\n"); + } } else { - if (!UpdateMutableData(vchInfoHash, putMutableData)) { - return; - } + LogPrintf("********** dht_bdap_storage -- put_mutable_item value unchanged. No database operation needed. **********\n"); } } - LogPrintf("********** dht_bdap_storage -- put_mutable_item completed successfully**********\n"); return; } diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index af085d6a4d..ed3f230c0e 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -15,11 +15,11 @@ #include -UniValue getdhtmutable(const JSONRPCRequest& request) +UniValue getdht(const JSONRPCRequest& request) { if (request.params.size() != 2) throw std::runtime_error( - "getdhtdata\n" + "getdht\n" "\n"); UniValue result(UniValue::VOBJ); @@ -48,11 +48,11 @@ UniValue getdhtmutable(const JSONRPCRequest& request) return result; } -UniValue putdhtmutable(const JSONRPCRequest& request) +UniValue putdht(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 4 || request.params.size() == 3) throw std::runtime_error( - "putdhtdata\n" + "putdht\n" "\n"); UniValue result(UniValue::VOBJ); @@ -193,8 +193,8 @@ UniValue dhtinfo(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode /* DHT */ - { "dht", "getdhtmutable", &getdhtmutable, true }, - { "dht", "putdhtmutable", &putdhtmutable, true }, + { "dht", "getdht", &getdht, true }, + { "dht", "putdht", &putdht, true }, { "dht", "dhtinfo", &dhtinfo, true }, }; From 54122641e902a7c28b0166ac7417b6e778bb2e55 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 3 Oct 2018 08:21:14 -0500 Subject: [PATCH 0262/1653] [DHT] Fix value parsing for leveldb storage - shorten RPC commands to getdht and putdht --- src/dht/persistence.cpp | 41 +++++++++++++++++++++-------------------- src/dht/persistence.h | 3 +++ src/dht/rpcdht.cpp | 12 ++++++------ 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/dht/persistence.cpp b/src/dht/persistence.cpp index 98c0efc824..ee8f571b8e 100644 --- a/src/dht/persistence.cpp +++ b/src/dht/persistence.cpp @@ -74,7 +74,7 @@ void dht_bdap_storage::update_node_ids(std::vector const& ids) bool dht_bdap_storage::get_peers(sha1_hash const& info_hash, bool const noseed, bool const scrape, address const& requester, entry& peers) const { - LogPrintf("********** dht_bdap_storage -- get_peers **********\n"); + //LogPrintf("********** dht_bdap_storage -- get_peers **********\n"); auto const i = m_map.find(info_hash); if (i == m_map.end()) return int(m_map.size()) >= m_settings.max_torrents; @@ -224,11 +224,13 @@ bool dht_bdap_storage::get_mutable_item_seq(sha1_hash const& target, sequence_nu CMutableData mutableData; std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); + LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq infohash = %s\n", strInfoHash); if (!GetMutableData(vchInfoHash, mutableData)) { + LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq failed to get sequence_number for infohash = %s.\n", strInfoHash); return false; } seq = dht::sequence_number(mutableData.SequenceNumber); - LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq seq = %u\n", mutableData.SequenceNumber); + LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq found seq = %u\n", mutableData.SequenceNumber); return true; } @@ -242,15 +244,15 @@ bool dht_bdap_storage::get_mutable_item(sha1_hash const& target, sequence_number return false; } item = stringFromVch(mutableData.Value); - LogPrintf("********** dht_bdap_storage -- get_mutable_item, Value = %s, seq_found = %d, seq_query = %d\n", - stringFromVch(mutableData.Value), mutableData.SequenceNumber, seq.value); + LogPrintf("********** dht_bdap_storage -- get_mutable_item found, Value = %s, seq_found = %d, seq_query = %d\n", + ExtractPutValue(stringFromVch(mutableData.Value)), mutableData.SequenceNumber, seq.value); return true; } -static std::string CleanPutValue(std::string value) +std::string ExtractPutValue(std::string value) { std::string strReturn = ""; - size_t posStart = 3; // always start at the third char + size_t posStart = value.find(":") + 1; size_t posEnd = 0; if (!(posStart == std::string::npos)) { posEnd = value.find("e1:q3:put1:t"); @@ -261,7 +263,7 @@ static std::string CleanPutValue(std::string value) return strReturn; } -static std::string CleanSalt(std::string salt) +std::string ExtractSalt(std::string salt) { std::string strReturn = ""; size_t posEnd = salt.find("3:seqi1e3:"); @@ -281,34 +283,33 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target { std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); - std::string strValue = CleanPutValue(std::string(buf.data())); - CharString vchValue = vchFromString(strValue); + std::string strPutValue = std::string(buf.data()); + CharString vchPutValue = vchFromString(strPutValue); std::string strSignature = aux::to_hex(std::string(sig.bytes.data())); CharString vchSignature = vchFromString(strSignature); std::string strPublicKey = aux::to_hex(std::string(pk.bytes.data())); CharString vchPublicKey = vchFromString(strPublicKey); - std::string strSalt = CleanSalt(std::string(salt.data())); + std::string strSalt = std::string(salt.data()); CharString vchSalt = vchFromString(strSalt); - CMutableData putMutableData(vchInfoHash, vchPublicKey, vchSignature, seq.value, vchSalt, vchValue); + CMutableData putMutableData(vchInfoHash, vchPublicKey, vchSignature, seq.value, vchSalt, vchPutValue); LogPrintf("********** dht_bdap_storage -- put_mutable_item info_hash = %s, buf_value = %s, sig = %s, pubkey = %s, salt = %s, seq = %d \n", - strInfoHash, strValue, strSignature, strPublicKey, strSalt, putMutableData.SequenceNumber); + strInfoHash, ExtractPutValue(strPutValue), strSignature, strPublicKey, ExtractSalt(strSalt), putMutableData.SequenceNumber); CMutableData previousData; if (!GetMutableData(vchInfoHash, previousData)) { - if (!PutMutableData(vchInfoHash, putMutableData)) { - return; + if (PutMutableData(vchInfoHash, putMutableData)) { + LogPrintf("********** dht_bdap_storage -- put_mutable_item added successfully**********\n"); } } else { - if ((seq < dht::sequence_number(putMutableData.SequenceNumber))) { - return; + if (putMutableData.Value != previousData.Value || putMutableData.SequenceNumber != previousData.SequenceNumber) { + if (UpdateMutableData(vchInfoHash, putMutableData)) { + LogPrintf("********** dht_bdap_storage -- put_mutable_item updated successfully**********\n"); + } } else { - if (!UpdateMutableData(vchInfoHash, putMutableData)) { - return; - } + LogPrintf("********** dht_bdap_storage -- put_mutable_item value unchanged. No database operation needed. **********\n"); } } - LogPrintf("********** dht_bdap_storage -- put_mutable_item completed successfully**********\n"); return; } diff --git a/src/dht/persistence.h b/src/dht/persistence.h index 2821207c2d..773c651e25 100644 --- a/src/dht/persistence.h +++ b/src/dht/persistence.h @@ -183,6 +183,9 @@ class dht_bdap_storage final : public dht_storage_interface std::unique_ptr dht_bdap_storage_constructor(dht_settings const& settings); +std::string ExtractPutValue(std::string value); +std::string ExtractSalt(std::string salt); + } // namespace dht } // namespace libtorrent diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index af085d6a4d..ed3f230c0e 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -15,11 +15,11 @@ #include -UniValue getdhtmutable(const JSONRPCRequest& request) +UniValue getdht(const JSONRPCRequest& request) { if (request.params.size() != 2) throw std::runtime_error( - "getdhtdata\n" + "getdht\n" "\n"); UniValue result(UniValue::VOBJ); @@ -48,11 +48,11 @@ UniValue getdhtmutable(const JSONRPCRequest& request) return result; } -UniValue putdhtmutable(const JSONRPCRequest& request) +UniValue putdht(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 4 || request.params.size() == 3) throw std::runtime_error( - "putdhtdata\n" + "putdht\n" "\n"); UniValue result(UniValue::VOBJ); @@ -193,8 +193,8 @@ UniValue dhtinfo(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode /* DHT */ - { "dht", "getdhtmutable", &getdhtmutable, true }, - { "dht", "putdhtmutable", &putdhtmutable, true }, + { "dht", "getdht", &getdht, true }, + { "dht", "putdht", &putdht, true }, { "dht", "dhtinfo", &dhtinfo, true }, }; From cb592999697d7099fdf95957671987c9e82b2d87 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 3 Oct 2018 14:16:57 -0500 Subject: [PATCH 0263/1653] [DHT] Fix put and get storage functions - adds `dhtdb` RPC command to view all DHT entries in local leveldb --- src/dht/mutabledata.cpp | 66 +++++++++++++++++++++++++++++++++++++++-- src/dht/mutabledata.h | 54 +++++++++++++++++++-------------- src/dht/persistence.cpp | 43 ++++++++++----------------- src/dht/persistence.h | 3 -- src/dht/rpcdht.cpp | 37 +++++++++++++++++++++++ 5 files changed, 147 insertions(+), 56 deletions(-) diff --git a/src/dht/mutabledata.cpp b/src/dht/mutabledata.cpp index fed92ac378..5ebfe42215 100644 --- a/src/dht/mutabledata.cpp +++ b/src/dht/mutabledata.cpp @@ -8,6 +8,8 @@ #include +#include + CMutableDataDB *pMutableDataDB = NULL; bool AddMutableData(const std::vector& vchInfoHash,const CMutableData& data) @@ -66,6 +68,17 @@ bool EraseMutableData(const std::vector& vchInfoHash) return true; } +bool GetAllMutableData(std::vector& vchMutableData) +{ + if (!pMutableDataDB) { + return false; + } + if (!pMutableDataDB->ListMutableData(vchMutableData)) { + return false; + } + return true; +} + void CMutableData::Serialize(std::vector& vchData) { CDataStream dsMutableData(SER_NETWORK, PROTOCOL_VERSION); @@ -95,12 +108,37 @@ bool CMutableData::UnserializeFromData(const std::vector& vchData return true; } +std::string CMutableData::InfoHash() const +{ + return stringFromVch(vchInfoHash); +} + +std::string CMutableData::PublicKey() const +{ + return stringFromVch(vchPublicKey); +} + +std::string CMutableData::Signature() const +{ + return stringFromVch(vchSignature); +} + +std::string CMutableData::Salt() const +{ + return stringFromVch(vchSalt); +} + +std::string CMutableData::Value() const +{ + return stringFromVch(vchValue); +} + bool CMutableDataDB::AddMutableData(const CMutableData& data) { bool writeState = false; { LOCK(cs_dht_entry); - writeState = CDBWrapper::Write(make_pair(std::string("ih"), data.InfoHash), data); // use info hash as key + writeState = CDBWrapper::Write(make_pair(std::string("ih"), data.vchInfoHash), data); // use info hash as key } return writeState; } @@ -121,10 +159,32 @@ bool CMutableDataDB::UpdateMutableData(const CMutableData& data) { LOCK(cs_dht_entry); - if (!EraseMutableData(data.InfoHash)) + if (!EraseMutableData(data.vchInfoHash)) return false; bool writeState = false; - writeState = CDBWrapper::Update(make_pair(std::string("ih"), data.InfoHash), data); + writeState = CDBWrapper::Update(make_pair(std::string("ih"), data.vchInfoHash), data); return writeState; +} + +bool CMutableDataDB::ListMutableData(std::vector& vchMutableData) +{ + std::pair infoHash; + std::unique_ptr pcursor(NewIterator()); + pcursor->SeekToFirst(); + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + CMutableData data; + try { + if (pcursor->GetKey(infoHash) && infoHash.first == "ih") { + pcursor->GetValue(data); + vchMutableData.push_back(data); + } + pcursor->Next(); + } + catch (std::exception& e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + return true; } \ No newline at end of file diff --git a/src/dht/mutabledata.h b/src/dht/mutabledata.h index b00fcf17ea..c2f87990ee 100644 --- a/src/dht/mutabledata.h +++ b/src/dht/mutabledata.h @@ -16,12 +16,12 @@ class CMutableData { public: static const int CURRENT_VERSION=1; int nVersion; - CharString InfoHash; // key - CharString PublicKey; - CharString Signature; + CharString vchInfoHash; // key + CharString vchPublicKey; + CharString vchSignature; std::int64_t SequenceNumber; - CharString Salt; - CharString Value; + CharString vchSalt; + CharString vchValue; CMutableData() { SetNull(); @@ -29,17 +29,17 @@ class CMutableData { CMutableData(const CharString& infoHash, const CharString& publicKey, const CharString& signature, const std::int64_t& sequenceNumber, const CharString& salt, const CharString& value) : - InfoHash(infoHash), PublicKey(publicKey), Signature(signature), SequenceNumber(sequenceNumber), Salt(salt), Value(value){} + vchInfoHash(infoHash), vchPublicKey(publicKey), vchSignature(signature), SequenceNumber(sequenceNumber), vchSalt(salt), vchValue(value){} inline void SetNull() { nVersion = CMutableData::CURRENT_VERSION; - InfoHash.clear(); - PublicKey.clear(); - Signature.clear(); + vchInfoHash.clear(); + vchPublicKey.clear(); + vchSignature.clear(); SequenceNumber = 0; - Salt.clear(); - Value.clear(); + vchSalt.clear(); + vchValue.clear(); } ADD_SERIALIZE_METHODS; @@ -47,16 +47,16 @@ class CMutableData { template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); - READWRITE(InfoHash); - READWRITE(PublicKey); - READWRITE(Signature); + READWRITE(vchInfoHash); + READWRITE(vchPublicKey); + READWRITE(vchSignature); READWRITE(VARINT(SequenceNumber)); - READWRITE(Salt); - READWRITE(Value); + READWRITE(vchSalt); + READWRITE(vchValue); } inline friend bool operator==(const CMutableData &a, const CMutableData &b) { - return (a.InfoHash == b.InfoHash && a.PublicKey == b.PublicKey && a.Signature == b.Signature); + return (a.vchInfoHash == b.vchInfoHash && a.vchPublicKey == b.vchPublicKey && a.vchSalt == b.vchSalt); } inline friend bool operator!=(const CMutableData &a, const CMutableData &b) { @@ -65,18 +65,24 @@ class CMutableData { inline CMutableData operator=(const CMutableData &b) { nVersion = b.nVersion; - InfoHash = b.InfoHash; - PublicKey = b.PublicKey; - Signature = b.Signature; + vchInfoHash = b.vchInfoHash; + vchPublicKey = b.vchPublicKey; + vchSignature = b.vchSignature; SequenceNumber = b.SequenceNumber; - Salt = b.Salt; - Value = b.Value; + vchSalt = b.vchSalt; + vchValue = b.vchValue; return *this; } - inline bool IsNull() const { return (Signature.empty()); } + inline bool IsNull() const { return (vchInfoHash.empty()); } void Serialize(std::vector& vchData); bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); + + std::string InfoHash() const; + std::string PublicKey() const; + std::string Signature() const; + std::string Salt() const; + std::string Value() const; }; class CMutableDataDB : public CDBWrapper { @@ -88,12 +94,14 @@ class CMutableDataDB : public CDBWrapper { bool UpdateMutableData(const CMutableData& data); bool ReadMutableData(const std::vector& vchInfoHash, CMutableData& data); bool EraseMutableData(const std::vector& vchInfoHash); + bool ListMutableData(std::vector& vchMutableData); }; bool AddMutableData(const std::vector& vchInfoHash, const CMutableData& data); bool UpdateMutableData(const std::vector& vchInfoHash, const CMutableData& data); bool GetMutableData(const std::vector& vchInfoHash, CMutableData& data); bool PutMutableData(const std::vector& vchInfoHash, const CMutableData& data); +bool GetAllMutableData(std::vector& vchMutableData); extern CMutableDataDB* pMutableDataDB; diff --git a/src/dht/persistence.cpp b/src/dht/persistence.cpp index ee8f571b8e..ba45017c19 100644 --- a/src/dht/persistence.cpp +++ b/src/dht/persistence.cpp @@ -27,30 +27,6 @@ bool operator<(peer_entry const& lhs, peer_entry const& rhs) constexpr time_duration announce_interval = minutes(ANNOUNCE_INTERVAL_MINUTES); -void set_value(dht_immutable_item& item, span buf) -{ - int const size = int(buf.size()); - if (item.size != size) - { - item.value.reset(new char[std::size_t(size)]); - item.size = size; - } - std::memcpy(item.value.get(), buf.data(), buf.size()); -} - -void touch_item(dht_immutable_item& f, address const& addr) -{ - f.last_seen = aux::time_now(); - - // maybe increase num_announcers if we haven't seen this IP before - sha1_hash const iphash = hash_address(addr); - if (!f.ips.find(iphash)) - { - f.ips.set(iphash); - ++f.num_announcers; - } -} - size_t dht_bdap_storage::num_torrents() const { LogPrintf("********** dht_bdap_storage -- num_torrents **********\n"); @@ -243,9 +219,19 @@ bool dht_bdap_storage::get_mutable_item(sha1_hash const& target, sequence_number LogPrintf("********** dht_bdap_storage -- get_mutable_item failed to get mutable data from leveldb.\n"); return false; } - item = stringFromVch(mutableData.Value); + item["seq"] = mutableData.SequenceNumber; + if (force_fill || (sequence_number(0) <= seq && seq < sequence_number(mutableData.SequenceNumber))) + { + item["v"] = bdecode(mutableData.vchValue.begin(), mutableData.vchValue.end()); + std::array sig; + aux::from_hex(mutableData.Signature(), sig.data()); + item["sig"] = sig; + std::array pubKey; + aux::from_hex(mutableData.PublicKey(), pubKey.data()); + item["k"] = pubKey; + } LogPrintf("********** dht_bdap_storage -- get_mutable_item found, Value = %s, seq_found = %d, seq_query = %d\n", - ExtractPutValue(stringFromVch(mutableData.Value)), mutableData.SequenceNumber, seq.value); + ExtractPutValue(mutableData.Value()), mutableData.SequenceNumber, seq.value); return true; } @@ -281,6 +267,7 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target , span salt , address const& addr) { + std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); std::string strPutValue = std::string(buf.data()); @@ -294,6 +281,7 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target CMutableData putMutableData(vchInfoHash, vchPublicKey, vchSignature, seq.value, vchSalt, vchPutValue); LogPrintf("********** dht_bdap_storage -- put_mutable_item info_hash = %s, buf_value = %s, sig = %s, pubkey = %s, salt = %s, seq = %d \n", strInfoHash, ExtractPutValue(strPutValue), strSignature, strPublicKey, ExtractSalt(strSalt), putMutableData.SequenceNumber); + CMutableData previousData; if (!GetMutableData(vchInfoHash, previousData)) { if (PutMutableData(vchInfoHash, putMutableData)) { @@ -301,7 +289,7 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target } } else { - if (putMutableData.Value != previousData.Value || putMutableData.SequenceNumber != previousData.SequenceNumber) { + if (putMutableData.Value() != previousData.Value() || putMutableData.SequenceNumber != previousData.SequenceNumber) { if (UpdateMutableData(vchInfoHash, putMutableData)) { LogPrintf("********** dht_bdap_storage -- put_mutable_item updated successfully**********\n"); } @@ -310,6 +298,7 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target LogPrintf("********** dht_bdap_storage -- put_mutable_item value unchanged. No database operation needed. **********\n"); } } + // TODO: Log from address (addr). See touch_item in the default storage implementation. return; } diff --git a/src/dht/persistence.h b/src/dht/persistence.h index 773c651e25..5d86d27120 100644 --- a/src/dht/persistence.h +++ b/src/dht/persistence.h @@ -106,9 +106,6 @@ struct immutable_item_comparator std::vector const& m_node_ids; }; -void set_value(dht_immutable_item& item, span buf); -void touch_item(dht_immutable_item& f, address const& addr); - using node_id = libtorrent::sha1_hash; // picks the least important one (i.e. the one diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index ed3f230c0e..1c50e832d6 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -4,6 +4,7 @@ #include "bdap/domainentry.h" #include "dht/bootstrap.h" #include "dht/keyed25519.h" +#include "dht/mutabledata.h" #include "rpcprotocol.h" #include "rpcserver.h" #include "util.h" @@ -190,12 +191,48 @@ UniValue dhtinfo(const JSONRPCRequest& request) return result; } +UniValue dhtdb(const JSONRPCRequest& request) +{ + if (request.params.size() != 0) + throw std::runtime_error( + "dhtdb\n" + "\n"); + + UniValue result(UniValue::VOBJ); + + std::vector vchMutableData; + + bool fRet = GetAllMutableData(vchMutableData); + int nCounter = 0; + if (fRet) { + for(const CMutableData& data : vchMutableData) { + UniValue oMutableData(UniValue::VOBJ); + oMutableData.push_back(Pair("info_hash", data.InfoHash())); + oMutableData.push_back(Pair("public_key", data.PublicKey())); + oMutableData.push_back(Pair("signature", data.Signature())); + oMutableData.push_back(Pair("seq_num", data.SequenceNumber)); + oMutableData.push_back(Pair("salt", data.Salt())); + oMutableData.push_back(Pair("value", data.Value())); + result.push_back(Pair("dht_entry_" + std::to_string(nCounter + 1), oMutableData)); + nCounter++; + } + } + else { + throw std::runtime_error("dhtdb failed. Check the debug.log for details.\n"); + } + UniValue oCounter(UniValue::VOBJ); + oCounter.push_back(Pair("record_count", nCounter)); + result.push_back(Pair("summary", oCounter)); + return result; +} + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode /* DHT */ { "dht", "getdht", &getdht, true }, { "dht", "putdht", &putdht, true }, { "dht", "dhtinfo", &dhtinfo, true }, + { "dht", "dhtdb", &dhtdb, true }, }; void RegisterDHTRPCCommands(CRPCTable &tableRPC) From 220740a44d4e11b3f5dc92eee569566650f809c8 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Wed, 3 Oct 2018 15:12:27 -0500 Subject: [PATCH 0264/1653] [DHT] Fix RPC daemon output for the command --- src/dht/rpcdht.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index 1c50e832d6..cb14de05e2 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -5,6 +5,7 @@ #include "dht/bootstrap.h" #include "dht/keyed25519.h" #include "dht/mutabledata.h" +#include "dht/persistence.h" #include "rpcprotocol.h" #include "rpcserver.h" #include "util.h" @@ -211,8 +212,8 @@ UniValue dhtdb(const JSONRPCRequest& request) oMutableData.push_back(Pair("public_key", data.PublicKey())); oMutableData.push_back(Pair("signature", data.Signature())); oMutableData.push_back(Pair("seq_num", data.SequenceNumber)); - oMutableData.push_back(Pair("salt", data.Salt())); - oMutableData.push_back(Pair("value", data.Value())); + oMutableData.push_back(Pair("salt", libtorrent::dht::ExtractSalt(data.Salt()))); + oMutableData.push_back(Pair("value", libtorrent::dht::ExtractPutValue(data.Value()))); result.push_back(Pair("dht_entry_" + std::to_string(nCounter + 1), oMutableData)); nCounter++; } From 5ebce4e0a402903e40214d437f6874bdb3b9b756 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 4 Oct 2018 08:07:49 -0500 Subject: [PATCH 0265/1653] [DHT] Refactor code files and function names --- src/Makefile.am | 24 +-- src/bdap/rpcdomainentry.cpp | 2 +- src/dht/{keyed25519.cpp => ed25519.cpp} | 2 +- src/dht/{keyed25519.h => ed25519.h} | 7 +- src/dht/mutable.cpp | 62 +++++++ src/dht/{mutabledata.h => mutable.h} | 29 +--- src/dht/{mutabledata.cpp => mutabledb.cpp} | 75 ++------- src/dht/mutabledb.h | 34 ++++ src/dht/operations.cpp | 135 ++++++++++++++++ src/dht/operations.h | 16 ++ src/dht/rpcdht.cpp | 30 ++-- src/dht/{bootstrap.cpp => session.cpp} | 178 ++++----------------- src/dht/{bootstrap.h => session.h} | 18 ++- src/dht/{dhtsettings.cpp => settings.cpp} | 4 +- src/dht/{dhtsettings.h => settings.h} | 6 +- src/dht/{persistence.cpp => storage.cpp} | 15 +- src/dht/{persistence.h => storage.h} | 6 +- src/init.cpp | 6 +- 18 files changed, 353 insertions(+), 296 deletions(-) rename src/dht/{keyed25519.cpp => ed25519.cpp} (99%) rename src/dht/{keyed25519.h => ed25519.h} (95%) create mode 100644 src/dht/mutable.cpp rename src/dht/{mutabledata.h => mutable.h} (68%) rename src/dht/{mutabledata.cpp => mutabledb.cpp} (57%) create mode 100644 src/dht/mutabledb.h create mode 100644 src/dht/operations.cpp create mode 100644 src/dht/operations.h rename src/dht/{bootstrap.cpp => session.cpp} (53%) rename src/dht/{bootstrap.h => session.h} (56%) rename src/dht/{dhtsettings.cpp => settings.cpp} (99%) rename src/dht/{dhtsettings.h => settings.h} (88%) rename src/dht/{persistence.cpp => storage.cpp} (97%) rename src/dht/{persistence.h => storage.h} (98%) diff --git a/src/Makefile.am b/src/Makefile.am index b7ce8f8572..2e89329967 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,12 +112,14 @@ DYNAMIC_CORE_H = \ bdap/identity.h \ bdap/linking.h \ dbwrapper.h \ - dht/bootstrap.h \ dht/curve25519.h \ - dht/dhtsettings.h \ - dht/keyed25519.h \ - dht/mutabledata.h \ - dht/persistence.h \ + dht/ed25519.h \ + dht/mutable.h \ + dht/mutabledb.h \ + dht/operations.h \ + dht/session.h \ + dht/settings.h \ + dht/storage.h \ dynode.h \ dynode-payments.h \ dynode-sync.h \ @@ -254,12 +256,14 @@ libdynamic_server_a_SOURCES = \ bdap/identity.cpp \ bdap/linking.cpp \ dbwrapper.cpp \ - dht/bootstrap.cpp \ dht/curve25519.cpp \ - dht/dhtsettings.cpp \ - dht/keyed25519.cpp \ - dht/mutabledata.cpp \ - dht/persistence.cpp \ + dht/ed25519.cpp \ + dht/mutable.cpp \ + dht/mutabledb.cpp \ + dht/operations.cpp \ + dht/session.cpp \ + dht/settings.cpp \ + dht/storage.cpp \ dynode.cpp \ dynode-payments.cpp\ dynode-sync.cpp \ diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index d8e084e1b0..4abbbdf9ec 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -4,7 +4,7 @@ #include "bdap/domainentry.h" #include "bdap/domainentrydb.h" -#include "dht/keyed25519.h" +#include "dht/ed25519.h" #include "core_io.h" // needed for ScriptToAsmStr #include "rpcprotocol.h" #include "rpcserver.h" diff --git a/src/dht/keyed25519.cpp b/src/dht/ed25519.cpp similarity index 99% rename from src/dht/keyed25519.cpp rename to src/dht/ed25519.cpp index 221dbebe1c..192da28c21 100644 --- a/src/dht/keyed25519.cpp +++ b/src/dht/ed25519.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#include "keyed25519.h" +#include "ed25519.h" #include "random.h" #include "bdap/domainentry.h" diff --git a/src/dht/keyed25519.h b/src/dht/ed25519.h similarity index 95% rename from src/dht/keyed25519.h rename to src/dht/ed25519.h index dbc75e5efe..6cab8bcf3f 100644 --- a/src/dht/keyed25519.h +++ b/src/dht/ed25519.h @@ -1,11 +1,12 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#ifndef DYNAMIC_DHT_KEYED25519_H -#define DYNAMIC_DHT_KEYED25519_H +#ifndef DYNAMIC_DHT_ED25519_H +#define DYNAMIC_DHT_ED25519_H #include "support/allocators/secure.h" +#include #include struct ed25519_context @@ -102,4 +103,4 @@ bool ECC_Ed25519_InitSanityCheck(); void ECC_Ed25519_Start(); void ECC_Ed25519_Stop(); -#endif // DYNAMIC_DHT_KEYED25519_H \ No newline at end of file +#endif // DYNAMIC_DHT_ED25519_H \ No newline at end of file diff --git a/src/dht/mutable.cpp b/src/dht/mutable.cpp new file mode 100644 index 0000000000..2bde776dd5 --- /dev/null +++ b/src/dht/mutable.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#include "dht/mutable.h" + +#include "bdap/domainentry.h" +#include "hash.h" +#include "streams.h" + +void CMutableData::Serialize(std::vector& vchData) +{ + CDataStream dsMutableData(SER_NETWORK, PROTOCOL_VERSION); + dsMutableData << *this; + vchData = std::vector(dsMutableData.begin(), dsMutableData.end()); +} + +bool CMutableData::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) +{ + try { + CDataStream dsMutableData(vchData, SER_NETWORK, PROTOCOL_VERSION); + dsMutableData >> *this; + + std::vector vchMutableData; + Serialize(vchMutableData); + const uint256 &calculatedHash = Hash(vchMutableData.begin(), vchMutableData.end()); + const std::vector &vchRandMutableData = vchFromValue(calculatedHash.GetHex()); + if(vchRandMutableData != vchHash) + { + SetNull(); + return false; + } + } catch (std::exception &e) { + SetNull(); + return false; + } + return true; +} + +std::string CMutableData::InfoHash() const +{ + return stringFromVch(vchInfoHash); +} + +std::string CMutableData::PublicKey() const +{ + return stringFromVch(vchPublicKey); +} + +std::string CMutableData::Signature() const +{ + return stringFromVch(vchSignature); +} + +std::string CMutableData::Salt() const +{ + return stringFromVch(vchSalt); +} + +std::string CMutableData::Value() const +{ + return stringFromVch(vchValue); +} \ No newline at end of file diff --git a/src/dht/mutabledata.h b/src/dht/mutable.h similarity index 68% rename from src/dht/mutabledata.h rename to src/dht/mutable.h index c2f87990ee..5b318cd353 100644 --- a/src/dht/mutabledata.h +++ b/src/dht/mutable.h @@ -1,16 +1,13 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#ifndef DYNAMIC_DHT_MUTABLE_DATA_H -#define DYNAMIC_DHT_MUTABLE_DATA_H +#ifndef DYNAMIC_DHT_MUTABLE_H +#define DYNAMIC_DHT_MUTABLE_H #include "bdap/bdap.h" -#include "dbwrapper.h" #include "serialize.h" -#include "sync.h" -#include "uint256.h" -static CCriticalSection cs_dht_entry; +#include "uint256.h" class CMutableData { public: @@ -85,24 +82,4 @@ class CMutableData { std::string Value() const; }; -class CMutableDataDB : public CDBWrapper { -public: - CMutableDataDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "dht", nCacheSize, fMemory, fWipe, obfuscate) { - } - - bool AddMutableData(const CMutableData& data); - bool UpdateMutableData(const CMutableData& data); - bool ReadMutableData(const std::vector& vchInfoHash, CMutableData& data); - bool EraseMutableData(const std::vector& vchInfoHash); - bool ListMutableData(std::vector& vchMutableData); -}; - -bool AddMutableData(const std::vector& vchInfoHash, const CMutableData& data); -bool UpdateMutableData(const std::vector& vchInfoHash, const CMutableData& data); -bool GetMutableData(const std::vector& vchInfoHash, CMutableData& data); -bool PutMutableData(const std::vector& vchInfoHash, const CMutableData& data); -bool GetAllMutableData(std::vector& vchMutableData); - -extern CMutableDataDB* pMutableDataDB; - #endif // DYNAMIC_DHT_MUTABLE_DATA_H diff --git a/src/dht/mutabledata.cpp b/src/dht/mutabledb.cpp similarity index 57% rename from src/dht/mutabledata.cpp rename to src/dht/mutabledb.cpp index 5ebfe42215..cb10280e35 100644 --- a/src/dht/mutabledata.cpp +++ b/src/dht/mutabledb.cpp @@ -1,10 +1,9 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#include "dht/mutabledata.h" +#include "dht/mutabledb.h" -#include "bdap/domainentry.h" -#include "hash.h" +#include "dht/mutable.h" #include @@ -12,7 +11,7 @@ CMutableDataDB *pMutableDataDB = NULL; -bool AddMutableData(const std::vector& vchInfoHash,const CMutableData& data) +bool AddLocalMutableData(const std::vector& vchInfoHash,const CMutableData& data) { if (!pMutableDataDB) { return false; @@ -23,7 +22,7 @@ bool AddMutableData(const std::vector& vchInfoHash,const CMutabl return true; } -bool UpdateMutableData(const std::vector& vchInfoHash,const CMutableData& data) +bool UpdateLocalMutableData(const std::vector& vchInfoHash,const CMutableData& data) { if (!pMutableDataDB) { return false; @@ -34,7 +33,7 @@ bool UpdateMutableData(const std::vector& vchInfoHash,const CMut return true; } -bool GetMutableData(const std::vector& vchInfoHash, CMutableData& data) +bool GetLocalMutableData(const std::vector& vchInfoHash, CMutableData& data) { if (!pMutableDataDB || !pMutableDataDB->ReadMutableData(vchInfoHash, data)) { return false; @@ -42,22 +41,22 @@ bool GetMutableData(const std::vector& vchInfoHash, CMutableData& return !data.IsNull(); } -bool PutMutableData(const std::vector& vchInfoHash, const CMutableData& data) +bool PutLocalMutableData(const std::vector& vchInfoHash, const CMutableData& data) { if (!pMutableDataDB) { return false; } CMutableData readMutableData; if (pMutableDataDB->ReadMutableData(vchInfoHash, readMutableData)) { - UpdateMutableData(vchInfoHash, data); + UpdateLocalMutableData(vchInfoHash, data); } else { - AddMutableData(vchInfoHash, data); + AddLocalMutableData(vchInfoHash, data); } return !data.IsNull(); } -bool EraseMutableData(const std::vector& vchInfoHash) +bool EraseLocalMutableData(const std::vector& vchInfoHash) { if (!pMutableDataDB) { return false; @@ -68,7 +67,7 @@ bool EraseMutableData(const std::vector& vchInfoHash) return true; } -bool GetAllMutableData(std::vector& vchMutableData) +bool GetAllLocalMutableData(std::vector& vchMutableData) { if (!pMutableDataDB) { return false; @@ -79,60 +78,6 @@ bool GetAllMutableData(std::vector& vchMutableData) return true; } -void CMutableData::Serialize(std::vector& vchData) -{ - CDataStream dsMutableData(SER_NETWORK, PROTOCOL_VERSION); - dsMutableData << *this; - vchData = std::vector(dsMutableData.begin(), dsMutableData.end()); -} - -bool CMutableData::UnserializeFromData(const std::vector& vchData, const std::vector& vchHash) -{ - try { - CDataStream dsMutableData(vchData, SER_NETWORK, PROTOCOL_VERSION); - dsMutableData >> *this; - - std::vector vchMutableData; - Serialize(vchMutableData); - const uint256 &calculatedHash = Hash(vchMutableData.begin(), vchMutableData.end()); - const std::vector &vchRandMutableData = vchFromValue(calculatedHash.GetHex()); - if(vchRandMutableData != vchHash) - { - SetNull(); - return false; - } - } catch (std::exception &e) { - SetNull(); - return false; - } - return true; -} - -std::string CMutableData::InfoHash() const -{ - return stringFromVch(vchInfoHash); -} - -std::string CMutableData::PublicKey() const -{ - return stringFromVch(vchPublicKey); -} - -std::string CMutableData::Signature() const -{ - return stringFromVch(vchSignature); -} - -std::string CMutableData::Salt() const -{ - return stringFromVch(vchSalt); -} - -std::string CMutableData::Value() const -{ - return stringFromVch(vchValue); -} - bool CMutableDataDB::AddMutableData(const CMutableData& data) { bool writeState = false; diff --git a/src/dht/mutabledb.h b/src/dht/mutabledb.h new file mode 100644 index 0000000000..0a42d2c42e --- /dev/null +++ b/src/dht/mutabledb.h @@ -0,0 +1,34 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_DHT_MUTABLE_DB_H +#define DYNAMIC_DHT_MUTABLE_DB_H + +#include "dbwrapper.h" +#include "sync.h" + +static CCriticalSection cs_dht_entry; + +class CMutableData; + +class CMutableDataDB : public CDBWrapper { +public: + CMutableDataDB(size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) : CDBWrapper(GetDataDir() / "dht", nCacheSize, fMemory, fWipe, obfuscate) { + } + + bool AddMutableData(const CMutableData& data); + bool UpdateMutableData(const CMutableData& data); + bool ReadMutableData(const std::vector& vchInfoHash, CMutableData& data); + bool EraseMutableData(const std::vector& vchInfoHash); + bool ListMutableData(std::vector& vchMutableData); +}; + +bool AddLocalMutableData(const std::vector& vchInfoHash, const CMutableData& data); +bool UpdateLocalMutableData(const std::vector& vchInfoHash, const CMutableData& data); +bool GetLocalMutableData(const std::vector& vchInfoHash, CMutableData& data); +bool PutLocalMutableData(const std::vector& vchInfoHash, const CMutableData& data); +bool GetAllLocalMutableData(std::vector& vchMutableData); + +extern CMutableDataDB* pMutableDataDB; + +#endif // DYNAMIC_DHT_MUTABLE_DB_H diff --git a/src/dht/operations.cpp b/src/dht/operations.cpp new file mode 100644 index 0000000000..edc75b685f --- /dev/null +++ b/src/dht/operations.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#include "dht/operations.h" + +#include "dht/session.h" +#include "util.h" + + +#include // for to_hex +#include +#include "libtorrent/kademlia/item.hpp" // for sign_mutable_item + +using namespace libtorrent; + +bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative) +{ + //TODO: DHT add locks + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData started.\n"); + + if (!pTorrentDHTSession) { + //message = "DHTTorrentNetwork -- GetDHTMutableData Error. pTorrentDHTSession is null."; + return false; + } + + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData Restarting DHT.\n"); + if (!LoadSessionState(pTorrentDHTSession)) { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData Couldn't load previous settings. Trying to Bootstrap again.\n"); + Bootstrap(pTorrentDHTSession); + } + else { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData setting loaded from file.\n"); + } + } + else { + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData DHT already running. Bootstrap not needed.\n"); + } + + pTorrentDHTSession->dht_get_item(public_key, entrySalt); + LogPrintf("DHTTorrentNetwork -- MGET: %s, salt = %s\n", aux::to_hex(public_key), entrySalt); + + bool authoritative = false; + if (fWaitForAuthoritative) { + while (!authoritative) + { + alert* dhtAlert = WaitForResponse(pTorrentDHTSession, dht_mutable_item_alert::alert_type, public_key, entrySalt); + + dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); + authoritative = dhtGetAlert->authoritative; + entryValue = dhtGetAlert->item.to_string(); + lastSequence = dhtGetAlert->seq; + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); + } + } + else { + alert* dhtAlert = WaitForResponse(pTorrentDHTSession, dht_mutable_item_alert::alert_type, public_key, entrySalt); + dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); + authoritative = dhtGetAlert->authoritative; + entryValue = dhtGetAlert->item.to_string(); + lastSequence = dhtGetAlert->seq; + LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); + } + + if (entryValue == "") + return false; + + return true; +} + +static void put_mutable +( + entry& e + ,std::array& sig + ,std::int64_t& seq + ,std::string const& salt + ,std::array const& pk + ,std::array const& sk + ,char const* str + ,std::int64_t const& iSeq +) +{ + using dht::sign_mutable_item; + if (str != NULL) { + e = std::string(str); + std::vector buf; + bencode(std::back_inserter(buf), e); + dht::signature sign; + seq = iSeq + 1; + sign = sign_mutable_item(buf, salt, dht::sequence_number(seq) + , dht::public_key(pk.data()) + , dht::secret_key(sk.data())); + sig = sign.bytes; + } +} + +bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence + ,char const* dhtValue, std::string& message) +{ + //TODO: (DHT) add locks + LogPrintf("DHTTorrentNetwork -- PutMutableData started.\n"); + + if (!pTorrentDHTSession) { + message = "DHTTorrentNetwork -- PutDHTMutableData Error. pTorrentDHTSession is null."; + return false; + } + + if (!pTorrentDHTSession->is_dht_running()) { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData Restarting DHT.\n"); + if (!LoadSessionState(pTorrentDHTSession)) { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData Couldn't load previous settings. Trying to Bootstrap again.\n"); + Bootstrap(pTorrentDHTSession); + } + else { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData setting loaded from file.\n"); + } + } + else { + LogPrintf("DHTTorrentNetwork -- PutDHTMutableData DHT already running. Bootstrap not needed.\n"); + } + + pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_mutable, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, public_key, private_key, dhtValue, lastSequence), entrySalt); + + LogPrintf("DHTTorrentNetwork -- MPUT public key: %s, salt = %s, seq=%d\n", aux::to_hex(public_key), entrySalt, lastSequence); + alert* dhtAlert = WaitForResponse(pTorrentDHTSession, dht_put_alert::alert_type, public_key, entrySalt); + dht_put_alert* dhtPutAlert = alert_cast(dhtAlert); + message = dhtPutAlert->message(); + LogPrintf("DHTTorrentNetwork -- PutMutableData %s\n", message); + + if (dhtPutAlert->num_success == 0) + return false; + + return true; +} \ No newline at end of file diff --git a/src/dht/operations.h b/src/dht/operations.h new file mode 100644 index 0000000000..4c9995e097 --- /dev/null +++ b/src/dht/operations.h @@ -0,0 +1,16 @@ +// Copyright (c) 2018 Duality Blockchain Solutions Developers +// TODO: Add License + +#ifndef DYNAMIC_DHT_OPERATIONS_H +#define DYNAMIC_DHT_OPERATIONS_H + +#include "dht/session.h" + +/** Get a mutable entry in the libtorrent DHT */ +bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative); + +/** Set a mutable entry in the libtorrent DHT */ +bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence + ,char const* dhtValue, std::string& message); + +#endif // DYNAMIC_DHT_OPERATIONS_H diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index cb14de05e2..16a9cd8f28 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -2,10 +2,11 @@ // TODO: Add License #include "bdap/domainentry.h" -#include "dht/bootstrap.h" -#include "dht/keyed25519.h" -#include "dht/mutabledata.h" -#include "dht/persistence.h" +#include "dht/ed25519.h" +#include "dht/mutable.h" +#include "dht/mutabledb.h" +#include "dht/storage.h" +#include "dht/operations.h" #include "rpcprotocol.h" #include "rpcserver.h" #include "util.h" @@ -16,12 +17,11 @@ #include - -UniValue getdht(const JSONRPCRequest& request) +UniValue getmutable(const JSONRPCRequest& request) { if (request.params.size() != 2) throw std::runtime_error( - "getdht\n" + "getmutable\n" "\n"); UniValue result(UniValue::VOBJ); @@ -44,22 +44,22 @@ UniValue getdht(const JSONRPCRequest& request) result.push_back(Pair("Get_Value", strValue)); } else { - throw std::runtime_error("getdhtdata failed. Check the debug.log for details.\n"); + throw std::runtime_error("getmutable failed. Check the debug.log for details.\n"); } return result; } -UniValue putdht(const JSONRPCRequest& request) +UniValue putmutable(const JSONRPCRequest& request) { if (request.params.size() < 2 || request.params.size() > 4 || request.params.size() == 3) throw std::runtime_error( - "putdht\n" + "putmutable\n" "\n"); UniValue result(UniValue::VOBJ); if (!pTorrentDHTSession) - throw std::runtime_error("putdhtmutable failed. DHT session not started.\n"); + throw std::runtime_error("putmutable failed. DHT session not started.\n"); //TODO: Check putValue is not > 1000 bytes. bool fNewEntry = false; @@ -102,7 +102,7 @@ UniValue putdht(const JSONRPCRequest& request) result.push_back(Pair("Put_Message", dhtMessage)); } else { - throw std::runtime_error("putdhtmutable failed. Put failed. Check the debug.log for details.\n"); + throw std::runtime_error("putmutable failed. Put failed. Check the debug.log for details.\n"); } return result; } @@ -203,7 +203,7 @@ UniValue dhtdb(const JSONRPCRequest& request) std::vector vchMutableData; - bool fRet = GetAllMutableData(vchMutableData); + bool fRet = GetAllLocalMutableData(vchMutableData); int nCounter = 0; if (fRet) { for(const CMutableData& data : vchMutableData) { @@ -230,8 +230,8 @@ UniValue dhtdb(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode /* DHT */ - { "dht", "getdht", &getdht, true }, - { "dht", "putdht", &putdht, true }, + { "dht", "getmutable", &getmutable, true }, + { "dht", "putmutable", &putmutable, true }, { "dht", "dhtinfo", &dhtinfo, true }, { "dht", "dhtdb", &dhtdb, true }, }; diff --git a/src/dht/bootstrap.cpp b/src/dht/session.cpp similarity index 53% rename from src/dht/bootstrap.cpp rename to src/dht/session.cpp index ab794c3382..dfa4c3feb6 100644 --- a/src/dht/bootstrap.cpp +++ b/src/dht/session.cpp @@ -1,10 +1,10 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#include "dht/bootstrap.h" +#include "dht/session.h" #include "chainparams.h" -#include "dht/dhtsettings.h" +#include "dht/settings.h" #include "dynode-sync.h" #include "net.h" #include "util.h" @@ -13,7 +13,6 @@ #include "libtorrent/hex.hpp" // for to_hex #include "libtorrent/alert_types.hpp" #include "libtorrent/bencode.hpp" // for bencode() -#include "libtorrent/kademlia/item.hpp" // for sign_mutable_item #include "libtorrent/kademlia/ed25519.hpp" #include "libtorrent/span.hpp" @@ -39,9 +38,9 @@ static void empty_public_key(std::array& public_key) } } -static alert* wait_for_alert(session* dhtSession, int alert_type, const std::array public_key, const std::string strSalt) +alert* WaitForResponse(session* dhtSession, const int alert_type, const std::array public_key, const std::string strSalt) { - LogPrintf("DHTTorrentNetwork -- wait_for_alert start.\n"); + LogPrintf("DHTTorrentNetwork -- WaitForResponse start.\n"); alert* ret = nullptr; bool found = false; std::array emptyKey; @@ -88,41 +87,41 @@ static alert* wait_for_alert(session* dhtSession, int alert_type, const std::arr return ret; } -static alert* wait_for_alert(session* dhtSession, int alert_type) +static alert* WaitForResponse(session* dhtSession, const int alert_type) { std::array emptyKey; empty_public_key(emptyKey); - return wait_for_alert(dhtSession, alert_type, emptyKey, ""); + return WaitForResponse(dhtSession, alert_type, emptyKey, ""); } -static void bootstrap(libtorrent::session* dhtSession) +void Bootstrap(libtorrent::session* dhtSession) { LogPrintf("DHTTorrentNetwork -- bootstrapping.\n"); - wait_for_alert(dhtSession, dht_bootstrap_alert::alert_type); + WaitForResponse(dhtSession, dht_bootstrap_alert::alert_type); LogPrintf("DHTTorrentNetwork -- bootstrap done.\n"); } -static std::string get_log_path() +std::string GetSessionStatePath() { - boost::filesystem::path path = GetDataDir() / "dht-state.dat"; + boost::filesystem::path path = GetDataDir() / "dht_state.dat"; return path.string(); } -static int save_dht_state(session* dhtSession) +int SaveSessionState(session* dhtSession) { entry torrentEntry; dhtSession->save_state(torrentEntry, session::save_dht_state); std::vector state; bencode(std::back_inserter(state), torrentEntry); - std::fstream f(get_log_path().c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); + std::fstream f(GetSessionStatePath().c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); f.write(state.data(), state.size()); - LogPrintf("DHTTorrentNetwork -- save_dht_state complete.\n"); + LogPrintf("DHTTorrentNetwork -- SaveSessionState complete.\n"); return 0; } -static bool load_dht_state(session* dhtSession) +bool LoadSessionState(session* dhtSession) { - std::fstream f(get_log_path().c_str(), std::ios_base::in | std::ios_base::binary | std::ios_base::ate); + std::fstream f(GetSessionStatePath().c_str(), std::ios_base::in | std::ios_base::binary | std::ios_base::ate); auto const size = f.tellg(); if (static_cast(size) <= 0) return false; @@ -134,7 +133,7 @@ static bool load_dht_state(session* dhtSession) f.read(state.data(), state.size()); if (f.fail()) { - LogPrintf("DHTTorrentNetwork -- failed to read dht-state.log\n"); + LogPrintf("DHTTorrentNetwork -- LoadSessionState failed to read dht-state.log\n"); return false; } @@ -142,12 +141,12 @@ static bool load_dht_state(session* dhtSession) error_code ec; bdecode(state.data(), state.data() + state.size(), e, ec); if (ec) { - LogPrintf("DHTTorrentNetwork -- failed to parse dht-state.log file: (%d) %s\n", ec.value(), ec.message()); + LogPrintf("DHTTorrentNetwork -- LoadSessionState failed to parse dht-state.log file: (%d) %s\n", ec.value(), ec.message()); return false; } else { - LogPrintf("DHTTorrentNetwork -- load dht state from dht-state.log\n"); + LogPrintf("DHTTorrentNetwork -- LoadSessionState load dht state from dht-state.log\n"); dhtSession->load_state(e); } return true; @@ -177,8 +176,8 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman unsigned int iCounter = 0; settings.LoadSettings(); pTorrentDHTSession = settings.GetSession(); - bootstrap(pTorrentDHTSession); - save_dht_state(pTorrentDHTSession); + Bootstrap(pTorrentDHTSession); + SaveSessionState(pTorrentDHTSession); if (!pTorrentDHTSession) { throw std::runtime_error("DHT Torrent network bootstraping error."); } @@ -187,14 +186,14 @@ void static DHTTorrentNetwork(const CChainParams& chainparams, CConnman& connman iCounter ++; if (!pTorrentDHTSession->is_dht_running()) { LogPrintf("DHTTorrentNetwork -- not running. Loading from file and restarting bootstrap.\n"); - load_dht_state(pTorrentDHTSession); - bootstrap(pTorrentDHTSession); - save_dht_state(pTorrentDHTSession); + LoadSessionState(pTorrentDHTSession); + Bootstrap(pTorrentDHTSession); + SaveSessionState(pTorrentDHTSession); } else { if (iCounter >= 300) { // save DHT state every 5 minutes - save_dht_state(pTorrentDHTSession); + SaveSessionState(pTorrentDHTSession); iCounter = 0; } } @@ -232,7 +231,7 @@ void StopTorrentDHTNetwork() void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman) { - LogPrintf("DHTTorrentNetwork -- Log file = %s.\n", get_log_path()); + LogPrintf("DHTTorrentNetwork -- Log file = %s.\n", GetSessionStatePath()); fShutdown = false; if (pDHTTorrentThread != NULL) StopTorrentDHTNetwork(); @@ -240,127 +239,6 @@ void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman) pDHTTorrentThread = std::make_shared(std::bind(&DHTTorrentNetwork, std::cref(chainparams), std::ref(connman))); } -bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative) -{ - //TODO: DHT add locks - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData started.\n"); - - if (!pTorrentDHTSession) { - //message = "DHTTorrentNetwork -- GetDHTMutableData Error. pTorrentDHTSession is null."; - return false; - } - - if (!pTorrentDHTSession->is_dht_running()) { - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData Restarting DHT.\n"); - if (!load_dht_state(pTorrentDHTSession)) { - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData Couldn't load previous settings. Trying to bootstrap again.\n"); - bootstrap(pTorrentDHTSession); - } - else { - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData setting loaded from file.\n"); - } - } - else { - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData DHT already running. Bootstrap not needed.\n"); - } - - pTorrentDHTSession->dht_get_item(public_key, entrySalt); - LogPrintf("DHTTorrentNetwork -- MGET: %s, salt = %s\n", aux::to_hex(public_key), entrySalt); - - bool authoritative = false; - if (fWaitForAuthoritative) { - while (!authoritative) - { - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type, public_key, entrySalt); - - dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); - authoritative = dhtGetAlert->authoritative; - entryValue = dhtGetAlert->item.to_string(); - lastSequence = dhtGetAlert->seq; - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); - } - } - else { - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_mutable_item_alert::alert_type, public_key, entrySalt); - dht_mutable_item_alert* dhtGetAlert = alert_cast(dhtAlert); - authoritative = dhtGetAlert->authoritative; - entryValue = dhtGetAlert->item.to_string(); - lastSequence = dhtGetAlert->seq; - LogPrintf("DHTTorrentNetwork -- GetDHTMutableData %s: %s\n", authoritative ? "auth" : "non-auth", entryValue); - } - - if (entryValue == "") - return false; - - return true; -} - -static void put_mutable -( - entry& e - ,std::array& sig - ,std::int64_t& seq - ,std::string const& salt - ,std::array const& pk - ,std::array const& sk - ,char const* str - ,std::int64_t const& iSeq -) -{ - using dht::sign_mutable_item; - if (str != NULL) { - e = std::string(str); - std::vector buf; - bencode(std::back_inserter(buf), e); - dht::signature sign; - seq = iSeq + 1; - sign = sign_mutable_item(buf, salt, dht::sequence_number(seq) - , dht::public_key(pk.data()) - , dht::secret_key(sk.data())); - sig = sign.bytes; - } -} - -bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence - ,char const* dhtValue, std::string& message) -{ - //TODO: (DHT) add locks - LogPrintf("DHTTorrentNetwork -- PutMutableData started.\n"); - - if (!pTorrentDHTSession) { - message = "DHTTorrentNetwork -- PutDHTMutableData Error. pTorrentDHTSession is null."; - return false; - } - - if (!pTorrentDHTSession->is_dht_running()) { - LogPrintf("DHTTorrentNetwork -- PutDHTMutableData Restarting DHT.\n"); - if (!load_dht_state(pTorrentDHTSession)) { - LogPrintf("DHTTorrentNetwork -- PutDHTMutableData Couldn't load previous settings. Trying to bootstrap again.\n"); - bootstrap(pTorrentDHTSession); - } - else { - LogPrintf("DHTTorrentNetwork -- PutDHTMutableData setting loaded from file.\n"); - } - } - else { - LogPrintf("DHTTorrentNetwork -- PutDHTMutableData DHT already running. Bootstrap not needed.\n"); - } - - pTorrentDHTSession->dht_put_item(public_key, std::bind(&put_mutable, std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4, public_key, private_key, dhtValue, lastSequence), entrySalt); - - LogPrintf("DHTTorrentNetwork -- MPUT public key: %s, salt = %s, seq=%d\n", aux::to_hex(public_key), entrySalt, lastSequence); - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_put_alert::alert_type, public_key, entrySalt); - dht_put_alert* dhtPutAlert = alert_cast(dhtAlert); - message = dhtPutAlert->message(); - LogPrintf("DHTTorrentNetwork -- PutMutableData %s\n", message); - - if (dhtPutAlert->num_success == 0) - return false; - - return true; -} - void GetDHTStats(session_status& stats, std::vector& vchDHTLookup, std::vector& vchDHTBuckets) { LogPrintf("DHTTorrentNetwork -- GetDHTStats started.\n"); @@ -371,9 +249,9 @@ void GetDHTStats(session_status& stats, std::vector& vchDHTLookup, s if (!pTorrentDHTSession->is_dht_running()) { LogPrintf("DHTTorrentNetwork -- GetDHTStats Restarting DHT.\n"); - if (!load_dht_state(pTorrentDHTSession)) { + if (!LoadSessionState(pTorrentDHTSession)) { LogPrintf("DHTTorrentNetwork -- GetDHTStats Couldn't load previous settings. Trying to bootstrap again.\n"); - bootstrap(pTorrentDHTSession); + Bootstrap(pTorrentDHTSession); } else { LogPrintf("DHTTorrentNetwork -- GetDHTStats setting loaded from file.\n"); @@ -384,7 +262,7 @@ void GetDHTStats(session_status& stats, std::vector& vchDHTLookup, s } pTorrentDHTSession->post_dht_stats(); - alert* dhtAlert = wait_for_alert(pTorrentDHTSession, dht_stats_alert::alert_type); + alert* dhtAlert = WaitForResponse(pTorrentDHTSession, dht_stats_alert::alert_type); dht_stats_alert* dhtStatsAlert = alert_cast(dhtAlert); vchDHTLookup = dhtStatsAlert->active_requests; vchDHTBuckets = dhtStatsAlert->routing_table; diff --git a/src/dht/bootstrap.h b/src/dht/session.h similarity index 56% rename from src/dht/bootstrap.h rename to src/dht/session.h index ce9ca2c8ca..30aa683465 100644 --- a/src/dht/bootstrap.h +++ b/src/dht/session.h @@ -1,9 +1,10 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#ifndef DYNAMIC_DHT_BOOTSTRAP_H -#define DYNAMIC_DHT_BOOTSTRAP_H +#ifndef DYNAMIC_DHT_SESSION_H +#define DYNAMIC_DHT_SESSION_H +#include "libtorrent/alert.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/session.hpp" #include "libtorrent/session_status.hpp" @@ -12,18 +13,21 @@ class CChainParams; class CConnman; class CKeyEd25519; +libtorrent::alert* WaitForResponse(libtorrent::session* dhtSession, const int alert_type, const std::array public_key, const std::string strSalt); + +void Bootstrap(libtorrent::session* dhtSession); +bool LoadSessionState(libtorrent::session* dhtSession); +int SaveSessionState(libtorrent::session* dhtSession); +std::string GetSessionStatePath(); + /** Start the DHT libtorrent network threads */ void StartTorrentDHTNetwork(const CChainParams& chainparams, CConnman& connman); /** Stop the DHT libtorrent network threads */ void StopTorrentDHTNetwork(); /** Get a mutable entry in the libtorrent DHT */ -bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative); -/** Set a mutable entry in the libtorrent DHT */ -bool PutDHTMutableData(const std::array& public_key, const std::array& private_key, const std::string& entrySalt, const int64_t& lastSequence - ,char const* dhtValue, std::string& message); void GetDHTStats(libtorrent::session_status& stats, std::vector& vchDHTLookup, std::vector& vchDHTBuckets); extern libtorrent::session *pTorrentDHTSession; -#endif // DYNAMIC_DHT_BOOTSTRAP_H +#endif // DYNAMIC_DHT_SESSION_H diff --git a/src/dht/dhtsettings.cpp b/src/dht/settings.cpp similarity index 99% rename from src/dht/dhtsettings.cpp rename to src/dht/settings.cpp index 94eb58cdfe..28c516fe61 100644 --- a/src/dht/dhtsettings.cpp +++ b/src/dht/settings.cpp @@ -1,9 +1,9 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#include "dht/dhtsettings.h" +#include "dht/settings.h" -#include "dht/persistence.h" +#include "dht/storage.h" #include "clientversion.h" #include "dynode.h" #include "dynodeman.h" diff --git a/src/dht/dhtsettings.h b/src/dht/settings.h similarity index 88% rename from src/dht/dhtsettings.h rename to src/dht/settings.h index 7ed99247bc..d1b1f5872e 100644 --- a/src/dht/dhtsettings.h +++ b/src/dht/settings.h @@ -1,8 +1,8 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#ifndef DYNAMIC_DHT_DHTSETTINGS_H -#define DYNAMIC_DHT_DHTSETTINGS_H +#ifndef DYNAMIC_DHT_SETTINGS_H +#define DYNAMIC_DHT_SETTINGS_H #include @@ -30,4 +30,4 @@ class CDHTSettings { }; -#endif // DYNAMIC_DHT_DHTSETTINGS_H \ No newline at end of file +#endif // DYNAMIC_DHT_SETTINGS_H \ No newline at end of file diff --git a/src/dht/persistence.cpp b/src/dht/storage.cpp similarity index 97% rename from src/dht/persistence.cpp rename to src/dht/storage.cpp index ba45017c19..6c9c3edf8e 100644 --- a/src/dht/persistence.cpp +++ b/src/dht/storage.cpp @@ -1,10 +1,11 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#include "persistence.h" +#include "storage.h" #include "bdap/domainentry.h" -#include "dht/mutabledata.h" +#include "dht/mutable.h" +#include "dht/mutabledb.h" #include "util.h" #include @@ -201,7 +202,7 @@ bool dht_bdap_storage::get_mutable_item_seq(sha1_hash const& target, sequence_nu std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq infohash = %s\n", strInfoHash); - if (!GetMutableData(vchInfoHash, mutableData)) { + if (!GetLocalMutableData(vchInfoHash, mutableData)) { LogPrintf("********** dht_bdap_storage -- get_mutable_item_seq failed to get sequence_number for infohash = %s.\n", strInfoHash); return false; } @@ -215,7 +216,7 @@ bool dht_bdap_storage::get_mutable_item(sha1_hash const& target, sequence_number CMutableData mutableData; std::string strInfoHash = aux::to_hex(target.to_string()); CharString vchInfoHash = vchFromString(strInfoHash); - if (!GetMutableData(vchInfoHash, mutableData)) { + if (!GetLocalMutableData(vchInfoHash, mutableData)) { LogPrintf("********** dht_bdap_storage -- get_mutable_item failed to get mutable data from leveldb.\n"); return false; } @@ -283,14 +284,14 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target strInfoHash, ExtractPutValue(strPutValue), strSignature, strPublicKey, ExtractSalt(strSalt), putMutableData.SequenceNumber); CMutableData previousData; - if (!GetMutableData(vchInfoHash, previousData)) { - if (PutMutableData(vchInfoHash, putMutableData)) { + if (!GetLocalMutableData(vchInfoHash, previousData)) { + if (PutLocalMutableData(vchInfoHash, putMutableData)) { LogPrintf("********** dht_bdap_storage -- put_mutable_item added successfully**********\n"); } } else { if (putMutableData.Value() != previousData.Value() || putMutableData.SequenceNumber != previousData.SequenceNumber) { - if (UpdateMutableData(vchInfoHash, putMutableData)) { + if (UpdateLocalMutableData(vchInfoHash, putMutableData)) { LogPrintf("********** dht_bdap_storage -- put_mutable_item updated successfully**********\n"); } } diff --git a/src/dht/persistence.h b/src/dht/storage.h similarity index 98% rename from src/dht/persistence.h rename to src/dht/storage.h index 5d86d27120..28a6fb5899 100644 --- a/src/dht/persistence.h +++ b/src/dht/storage.h @@ -1,8 +1,8 @@ // Copyright (c) 2018 Duality Blockchain Solutions Developers // TODO: Add License -#ifndef DYNAMIC_DHT_PERSISTENCE_H -#define DYNAMIC_DHT_PERSISTENCE_H +#ifndef DYNAMIC_DHT_STORAGE_H +#define DYNAMIC_DHT_STORAGE_H #include #include @@ -187,4 +187,4 @@ std::string ExtractSalt(std::string salt); } // namespace libtorrent -#endif // DYNAMIC_DHT_PERSISTENCE_H +#endif // DYNAMIC_DHT_STORAGE_H diff --git a/src/init.cpp b/src/init.cpp index 5173155c79..139414c88d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -19,9 +19,9 @@ #include "chainparams.h" #include "checkpoints.h" #include "bdap/domainentrydb.h" -#include "dht/keyed25519.h" -#include "dht/bootstrap.h" -#include "dht/mutabledata.h" +#include "dht/ed25519.h" +#include "dht/session.h" +#include "dht/mutabledb.h" #include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeconfig.h" From 7dd60168f776f9eb7b4f72df5d4e1a7ecac3d753 Mon Sep 17 00:00:00 2001 From: AmirAbrams Date: Thu, 4 Oct 2018 10:49:10 -0500 Subject: [PATCH 0266/1653] [DHT] Fix seq_num to start at 0 and fix salt storage --- src/dht/operations.cpp | 4 +++- src/dht/rpcdht.cpp | 3 ++- src/dht/session.cpp | 2 +- src/dht/storage.cpp | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/dht/operations.cpp b/src/dht/operations.cpp index edc75b685f..6b4b7c0b0f 100644 --- a/src/dht/operations.cpp +++ b/src/dht/operations.cpp @@ -11,6 +11,8 @@ #include #include "libtorrent/kademlia/item.hpp" // for sign_mutable_item +#include + using namespace libtorrent; bool GetDHTMutableData(const std::array& public_key, const std::string& entrySalt, std::string& entryValue, int64_t& lastSequence, bool fWaitForAuthoritative) @@ -86,7 +88,7 @@ static void put_mutable std::vector buf; bencode(std::back_inserter(buf), e); dht::signature sign; - seq = iSeq + 1; + seq = iSeq; sign = sign_mutable_item(buf, salt, dht::sequence_number(seq) , dht::public_key(pk.data()) , dht::secret_key(sk.data())); diff --git a/src/dht/rpcdht.cpp b/src/dht/rpcdht.cpp index 16a9cd8f28..edb555ea63 100644 --- a/src/dht/rpcdht.cpp +++ b/src/dht/rpcdht.cpp @@ -90,6 +90,7 @@ UniValue putmutable(const JSONRPCRequest& request) if (!fNewEntry) { // we need the last sequence number to update an existing DHT entry. GetDHTMutableData(pubKey, strSalt, strPutValue, iSequence, true); + iSequence++; } std::string dhtMessage = ""; fRet = PutDHTMutableData(pubKey, privKey, strSalt, iSequence, putValue, dhtMessage); @@ -212,7 +213,7 @@ UniValue dhtdb(const JSONRPCRequest& request) oMutableData.push_back(Pair("public_key", data.PublicKey())); oMutableData.push_back(Pair("signature", data.Signature())); oMutableData.push_back(Pair("seq_num", data.SequenceNumber)); - oMutableData.push_back(Pair("salt", libtorrent::dht::ExtractSalt(data.Salt()))); + oMutableData.push_back(Pair("salt", data.Salt())); oMutableData.push_back(Pair("value", libtorrent::dht::ExtractPutValue(data.Value()))); result.push_back(Pair("dht_entry_" + std::to_string(nCounter + 1), oMutableData)); nCounter++; diff --git a/src/dht/session.cpp b/src/dht/session.cpp index dfa4c3feb6..a6deb868c5 100644 --- a/src/dht/session.cpp +++ b/src/dht/session.cpp @@ -18,11 +18,11 @@ #include -#include #include // for snprintf #include // for PRId64 et.al. #include #include +#include using namespace libtorrent; diff --git a/src/dht/storage.cpp b/src/dht/storage.cpp index 6c9c3edf8e..40fe2c0ca6 100644 --- a/src/dht/storage.cpp +++ b/src/dht/storage.cpp @@ -277,11 +277,11 @@ void dht_bdap_storage::put_mutable_item(sha1_hash const& target CharString vchSignature = vchFromString(strSignature); std::string strPublicKey = aux::to_hex(std::string(pk.bytes.data())); CharString vchPublicKey = vchFromString(strPublicKey); - std::string strSalt = std::string(salt.data()); + std::string strSalt = ExtractSalt(std::string(salt.data())); CharString vchSalt = vchFromString(strSalt); CMutableData putMutableData(vchInfoHash, vchPublicKey, vchSignature, seq.value, vchSalt, vchPutValue); LogPrintf("********** dht_bdap_storage -- put_mutable_item info_hash = %s, buf_value = %s, sig = %s, pubkey = %s, salt = %s, seq = %d \n", - strInfoHash, ExtractPutValue(strPutValue), strSignature, strPublicKey, ExtractSalt(strSalt), putMutableData.SequenceNumber); + strInfoHash, ExtractPutValue(strPutValue), strSignature, strPublicKey, strSalt, putMutableData.SequenceNumber); CMutableData previousData; if (!GetLocalMutableData(vchInfoHash, previousData)) { From cce6f7b620b6753e2ce1874885b09d2bd138f3f0 Mon Sep 17 00:00:00 2001 From: Duality-CDOO Date: Tue, 25 Sep 2018 22:19:17 +0200 Subject: [PATCH 0267/1653] Initial update of entire wallet to inline with Dash 0.12.4.0 --- dynamic-qt.pro | 1 - src/Makefile.am | 22 +- src/Makefile.test.include | 1 + src/activedynode.cpp | 2 +- src/activedynode.h | 2 + src/addrman.cpp | 32 +- src/addrman.h | 10 +- src/alert.cpp | 3 +- src/bdap/auditdata.cpp | 2 +- src/bdap/auditdata.h | 4 +- src/bdap/domainentry.cpp | 54 +- src/bdap/domainentry.h | 22 +- src/bdap/domainentrydb.cpp | 40 +- src/bdap/domainentrydb.h | 4 +- src/bdap/entrycertificate.cpp | 2 +- src/bdap/entrycertificate.h | 4 +- src/bdap/entrychannel.cpp | 2 +- src/bdap/entrychannel.h | 4 +- src/bdap/entrycheckpoints.cpp | 2 +- src/bdap/entrycheckpoints.h | 4 +- src/bdap/entrylink.cpp | 2 +- src/bdap/entrylink.h | 8 +- src/bdap/identity.cpp | 4 +- src/bdap/identity.h | 9 +- src/bdap/rpcdomainentry.cpp | 35 +- src/blockencodings.cpp | 221 +++++ src/blockencodings.h | 209 +++++ src/cachemap.h | 33 +- src/cachemultimap.h | 38 +- src/chain.cpp | 4 +- src/chain.h | 13 +- src/chainparams.cpp | 128 ++- src/chainparams.h | 28 +- src/checkpoints.cpp | 52 +- src/checkpoints.h | 6 - src/checkqueue.h | 16 +- src/coins.cpp | 2 +- src/coins.h | 12 +- src/consensus/merkle.cpp | 4 +- src/consensus/params.h | 9 + src/core_io.h | 3 +- src/core_memusage.h | 4 +- src/core_read.cpp | 2 +- src/cuckoocache.h | 457 ++++++++++ src/drafted/governance-types.cpp | 8 +- src/dynamic-cli.cpp | 57 +- src/dynamic-tx.cpp | 206 ++++- src/dynode-payments.cpp | 588 +++++++------ src/dynode-payments.h | 106 ++- src/dynode-sync.cpp | 64 +- src/dynode-sync.h | 11 +- src/dynode.cpp | 342 +++++--- src/dynode.h | 214 +++-- src/dynodeconfig.cpp | 2 +- src/dynodeconfig.h | 4 +- src/dynodeman.cpp | 757 +++++++++++------ src/dynodeman.h | 42 +- src/fluid/fluid.cpp | 16 +- src/fluid/rpcfluid.cpp | 23 +- src/governance-classes.cpp | 302 ++++--- src/governance-classes.h | 23 +- src/governance-misc.h | 55 -- src/governance-object.cpp | 511 ++++++------ src/governance-object.h | 86 +- src/governance-validators.cpp | 136 ++- src/governance-validators.h | 57 +- src/governance-vote.cpp | 292 +++---- src/governance-vote.h | 143 +--- src/governance-votedb.cpp | 24 +- src/governance-votedb.h | 7 +- src/governance.cpp | 686 ++++++++------- src/governance.h | 88 +- src/init.cpp | 287 +++++-- src/init.h | 2 - src/instantsend.cpp | 565 +++++++------ src/instantsend.h | 171 +++- src/keystore.h | 26 +- src/merkleblock.cpp | 6 +- src/messagesigner.cpp | 26 +- src/messagesigner.h | 14 +- src/miner.cpp | 77 +- src/net.cpp | 442 ++++++---- src/net.h | 161 ++-- src/net_processing.cpp | 1146 +++++++++++++++++++------- src/net_processing.h | 13 +- src/netbase.cpp | 6 +- src/netfulfilledman.cpp | 15 +- src/netfulfilledman.h | 14 +- src/netmessagemaker.h | 37 + src/policy/fees.cpp | 93 +-- src/policy/fees.h | 21 +- src/policy/policy.cpp | 3 + src/policy/policy.h | 12 + src/primitives/block.cpp | 7 +- src/primitives/block.h | 7 +- src/primitives/transaction.cpp | 23 +- src/primitives/transaction.h | 56 +- src/privatesend-client.cpp | 464 ++++++----- src/privatesend-client.h | 56 +- src/privatesend-server.cpp | 315 +++---- src/privatesend-server.h | 14 +- src/privatesend-util.cpp | 43 +- src/privatesend-util.h | 2 +- src/privatesend.cpp | 235 +++--- src/privatesend.h | 148 +++- src/protocol.cpp | 10 +- src/protocol.h | 46 +- src/psnotificationinterface.cpp | 9 +- src/psnotificationinterface.h | 2 +- src/pubkey.cpp | 2 +- src/pubkey.h | 11 +- src/qt/clientmodel.cpp | 2 +- src/qt/coincontroldialog.cpp | 18 +- src/qt/coincontroltreewidget.h | 2 +- src/qt/dynamicgui.cpp | 4 +- src/qt/dynamicgui.h | 2 +- src/qt/dynodelist.cpp | 25 +- src/qt/guiutil.cpp | 75 +- src/qt/guiutil.h | 5 +- src/qt/receivecoinsdialog.h | 8 +- src/qt/receiverequestdialog.h | 4 +- src/qt/transactiondesc.cpp | 30 +- src/qt/transactionrecord.cpp | 31 +- src/qt/transactionview.h | 4 +- src/qt/walletmodel.cpp | 16 +- src/qt/walletmodeltransaction.cpp | 4 +- src/rest.cpp | 4 +- src/rpcblockchain.cpp | 287 ++++++- src/rpcclient.cpp | 270 +++--- src/rpcclient.h | 7 + src/rpcdynode.cpp | 111 ++- src/rpcgovernance.cpp | 208 +++-- src/rpcmining.cpp | 62 +- src/rpcmisc.cpp | 58 +- src/rpcnet.cpp | 48 +- src/rpcrawtransaction.cpp | 95 ++- src/rpcregister.h | 21 +- src/rpcserver.cpp | 113 ++- src/rpcserver.h | 23 +- src/script/dynamicconsensus.cpp | 3 +- src/script/interpreter.h | 6 +- src/script/script.cpp | 12 +- src/script/script.h | 50 +- src/script/sigcache.cpp | 79 +- src/script/sigcache.h | 11 +- src/script/sign.cpp | 73 -- src/script/sign.h | 12 +- src/script/standard.cpp | 5 - src/script/standard.h | 1 - src/sendalert.cpp | 2 +- src/serialize.h | 91 +- src/spork.cpp | 182 ++-- src/spork.h | 44 +- src/streams.h | 73 ++ src/support/events.h | 58 ++ src/sync.h | 1 - src/test/DoS_tests.cpp | 31 +- src/test/mempool_tests.cpp | 74 +- src/test/merkle_tests.cpp | 10 +- src/txdb.h | 10 +- src/txmempool.cpp | 124 +-- src/txmempool.h | 90 +- src/uint256.cpp | 31 - src/uint256.h | 9 - src/util.cpp | 2 +- src/validation.cpp | 723 +++++++++------- src/validation.h | 72 +- src/validationinterface.cpp | 9 + src/validationinterface.h | 31 +- src/version.h | 4 +- src/versionbits.cpp | 47 +- src/versionbits.h | 2 + src/wallet/coincontrol.h | 6 + src/wallet/crypter.h | 12 +- src/wallet/db.cpp | 86 +- src/wallet/rpcdump.cpp | 277 +++++-- src/wallet/rpcwallet.cpp | 390 ++++++--- src/wallet/rpcwallet.h | 2 +- src/wallet/wallet.cpp | 853 ++++++++++++------- src/wallet/wallet.h | 325 ++++---- src/wallet/walletdb.cpp | 138 ++-- src/wallet/walletdb.h | 13 +- src/zmq/zmqabstractnotifier.cpp | 11 +- src/zmq/zmqabstractnotifier.h | 5 + src/zmq/zmqconfig.h | 13 +- src/zmq/zmqnotificationinterface.cpp | 51 +- src/zmq/zmqnotificationinterface.h | 10 +- src/zmq/zmqpublishnotifier.cpp | 47 +- src/zmq/zmqpublishnotifier.h | 43 +- 189 files changed, 10450 insertions(+), 6294 deletions(-) create mode 100644 src/blockencodings.cpp create mode 100644 src/blockencodings.h create mode 100644 src/cuckoocache.h delete mode 100644 src/governance-misc.h create mode 100644 src/netmessagemaker.h create mode 100644 src/support/events.h diff --git a/dynamic-qt.pro b/dynamic-qt.pro index 275f641adc..9b359ee6e7 100644 --- a/dynamic-qt.pro +++ b/dynamic-qt.pro @@ -376,7 +376,6 @@ HEADERS += \ src/flat-database.h \ src/governance-classes.h \ src/governance-exceptions.h \ - src/governance-misc.h \ src/governance-object.h \ src/governance-vote.h \ src/governance-votedb.h \ diff --git a/src/Makefile.am b/src/Makefile.am index 5c15f88331..9a71095c6d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -73,8 +73,18 @@ DYNAMIC_CORE_H = \ amount.h \ arith_uint256.h \ base58.h \ + bdap/auditdata.h \ + bdap/bdap.h \ + bdap/domainentry.h \ + bdap/domainentrydb.h \ + bdap/entrycertificate.h \ + bdap/entrychannel.h \ + bdap/entrycheckpoints.h \ + bdap/entrylink.h \ + bdap/identity.h \ bip39_english.h \ bip39.h \ + blockencodings.h \ bloom.h \ cachemap.h \ cachemultimap.h \ @@ -97,15 +107,7 @@ DYNAMIC_CORE_H = \ consensus/validation.h \ core_io.h \ core_memusage.h \ - bdap/auditdata.h \ - bdap/bdap.h \ - bdap/domainentry.h \ - bdap/domainentrydb.h \ - bdap/entrycertificate.h \ - bdap/entrychannel.h \ - bdap/entrycheckpoints.h \ - bdap/entrylink.h \ - bdap/identity.h \ + cuckoocache.h \ dbwrapper.h \ dynode.h \ dynode-payments.h \ @@ -147,6 +149,7 @@ DYNAMIC_CORE_H = \ netaddress.h \ netbase.h \ netfulfilledman.h \ + netmessagemaker.h \ noui.h \ ntp.h \ operations.h \ @@ -231,6 +234,7 @@ libdynamic_server_a_SOURCES = \ addrdb.cpp \ addrman.cpp \ alert.cpp \ + blockencodings.cpp \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 6a3e5239fc..1db247cae7 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -46,6 +46,7 @@ DYNAMIC_TESTS =\ test/base64_tests.cpp \ test/bip32_tests.cpp \ test/bip39_tests.cpp \ + test/blockencodings_tests.cpp \ test/bloom_tests.cpp \ test/bswap_tests.cpp \ test/cachemap_tests.cpp \ diff --git a/src/activedynode.cpp b/src/activedynode.cpp index 75553a5483..87e1f12f85 100644 --- a/src/activedynode.cpp +++ b/src/activedynode.cpp @@ -251,7 +251,7 @@ void CActiveDynode::ManageStateRemote() } if(nState != ACTIVE_DYNODE_STARTED) { LogPrintf("CActiveDynode::ManageStateRemote -- STARTED!\n"); - outpoint = infoDn.vin.prevout; + outpoint = infoDn.outpoint; service = infoDn.addr; fPingerEnabled = true; nState = ACTIVE_DYNODE_STARTED; diff --git a/src/activedynode.h b/src/activedynode.h index aeedc123ed..c791584617 100644 --- a/src/activedynode.h +++ b/src/activedynode.h @@ -82,6 +82,8 @@ class CActiveDynode bool UpdateSentinelPing(int version); + void DoMaintenance(CConnman &connman) { ManageState(connman); } + private: void ManageStateInitial(CConnman& connman); void ManageStateRemote(); diff --git a/src/addrman.cpp b/src/addrman.cpp index c0fb208403..1e310021f6 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -56,14 +56,7 @@ bool CAddrInfo::IsTerrible(int64_t nNow) const double CAddrInfo::GetChance(int64_t nNow) const { double fChance = 1.0; - - int64_t nSinceLastSeen = nNow - nTime; - int64_t nSinceLastTry = nNow - nLastTry; - - if (nSinceLastSeen < 0) - nSinceLastSeen = 0; - if (nSinceLastTry < 0) - nSinceLastTry = 0; + int64_t nSinceLastTry = std::max(nNow - nLastTry, 0); // deprioritize very recent attempts away if (nSinceLastTry < 60 * 10) @@ -75,9 +68,14 @@ double CAddrInfo::GetChance(int64_t nNow) const return fChance; } -CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId) +CAddrInfo* CAddrMan::Find(const CService& addr, int* pnId) { - std::map::iterator it = mapAddr.find(addr); + CService addr2 = addr; + if (!discriminatePorts) { + addr2.SetPort(0); + } + + std::map::iterator it = mapAddr.find(addr2); if (it == mapAddr.end()) return NULL; if (pnId) @@ -90,9 +88,14 @@ CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId) CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId) { + CService addr2 = addr; + if (!discriminatePorts) { + addr2.SetPort(0); + } + int nId = nIdCount++; mapInfo[nId] = CAddrInfo(addr, addrSource); - mapAddr[addr] = nId; + mapAddr[addr2] = nId; mapInfo[nId].nRandomPos = vRandom.size(); vRandom.push_back(nId); if (pnId) @@ -127,9 +130,14 @@ void CAddrMan::Delete(int nId) assert(!info.fInTried); assert(info.nRefCount == 0); + CService addr = info; + if (!discriminatePorts) { + addr.SetPort(0); + } + SwapRandom(info.nRandomPos, vRandom.size() - 1); vRandom.pop_back(); - mapAddr.erase(info); + mapAddr.erase(addr); mapInfo.erase(nId); nNew--; } diff --git a/src/addrman.h b/src/addrman.h index 7fbbcef1cf..594f7fb919 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -189,7 +189,7 @@ class CAddrMan std::map mapInfo; //! find an nId based on its network address - std::map mapAddr; + std::map mapAddr; //! randomly-ordered vector of all nIds std::vector vRandom; @@ -209,6 +209,9 @@ class CAddrMan //! last time Good was called (memory only) int64_t nLastGood; + // discriminate entries based on port. Should be false on mainnet/testnet and can be true on devnet/regtest + bool discriminatePorts; + protected: //! secret key to randomize bucket select with uint256 nKey; @@ -217,7 +220,7 @@ class CAddrMan FastRandomContext insecure_rand; //! Find an entry. - CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL); + CAddrInfo* Find(const CService& addr, int *pnId = NULL); //! find an entry, creating it if necessary. //! nTime and nServices of the found node are updated, if necessary. @@ -471,7 +474,8 @@ class CAddrMan nLastGood = 1; //Initially at 1 so that "never" is strictly worse. } - CAddrMan() + CAddrMan(bool _discriminatePorts = false) : + discriminatePorts(_discriminatePorts) { Clear(); } diff --git a/src/alert.cpp b/src/alert.cpp index 223c50b133..a315a18da4 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -10,6 +10,7 @@ #include "base58.h" #include "clientversion.h" #include "net.h" +#include "netmessagemaker.h" #include "pubkey.h" #include "timedata.h" #include "ui_interface.h" @@ -139,7 +140,7 @@ bool CAlert::RelayTo(CNode* pnode, CConnman& connman) const AppliesToMe() || GetAdjustedTime() < nRelayUntil) { - connman.PushMessage(pnode, NetMsgType::ALERT, *this); + connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::ALERT, *this)); return true; } } diff --git a/src/bdap/auditdata.cpp b/src/bdap/auditdata.cpp index 571d083312..0a9b429dec 100644 --- a/src/bdap/auditdata.cpp +++ b/src/bdap/auditdata.cpp @@ -52,7 +52,7 @@ bool CAuditData::UnserializeFromData(const std::vector& vchData, return true; } -bool CAuditData::UnserializeFromTx(const CTransaction& tx) +bool CAuditData::UnserializeFromTx(const CTransactionRef& tx) { std::vector vchData; std::vector vchHash; diff --git a/src/bdap/auditdata.h b/src/bdap/auditdata.h index dd34974fdd..b37ad6778e 100644 --- a/src/bdap/auditdata.h +++ b/src/bdap/auditdata.h @@ -38,7 +38,7 @@ class CAuditData { SetNull(); } - CAuditData(const CTransaction& tx) { + CAuditData(const CTransactionRef& tx) { SetNull(); UnserializeFromTx(tx); } @@ -89,7 +89,7 @@ class CAuditData { inline bool IsNull() const { return (OwnerFullPath.empty()); } void Serialize(std::vector& vchData); bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); - bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromTx(const CTransactionRef& tx); BDAP::AuditType AuditType() { return (BDAP::AuditType)nAuditType; } std::string AuditTypeString() { return BDAP::GetAuditTypeString(nAuditType); } diff --git a/src/bdap/domainentry.cpp b/src/bdap/domainentry.cpp index 6731ed0c23..7b74107ca2 100644 --- a/src/bdap/domainentry.cpp +++ b/src/bdap/domainentry.cpp @@ -113,18 +113,22 @@ bool IsBDAPDataOutput(const CTxOut& out) { return false; } -bool GetBDAPTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams) +bool GetBDAPTransaction(int nHeight, const uint256& hash, CTransactionRef &txOut, const Consensus::Params& consensusParams) { if(nHeight < 0 || nHeight > chainActive.Height()) return false; - CBlockIndex *pindexSlow = NULL; + + CBlockIndex *pindexSlow = NULL; + LOCK(cs_main); + pindexSlow = chainActive[nHeight]; + if (pindexSlow) { CBlock block; if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - if (tx.GetHash() == hash) { + for (const auto& tx : block.vtx) { + if (tx->GetHash() == hash) { txOut = tx; return true; } @@ -155,9 +159,9 @@ std::vector vchFromString(const std::string& str) return std::vector(str.begin(), str.end()); } -int GetBDAPDataOutput(const CTransaction& tx) { - for(unsigned int i = 0; ivout.size();i++) { + if(IsBDAPDataOutput(tx->vout[i])) return i; } return -1; @@ -181,13 +185,13 @@ bool GetBDAPData(const CScript& scriptPubKey, std::vector& vchDat return true; } -bool GetBDAPData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut) +bool GetBDAPData(const CTransactionRef& tx, std::vector& vchData, std::vector& vchHash, int& nOut) { nOut = GetBDAPDataOutput(tx); if(nOut == -1) return false; - const CScript &scriptPubKey = tx.vout[nOut].scriptPubKey; + const CScript &scriptPubKey = tx->vout[nOut].scriptPubKey; return GetBDAPData(scriptPubKey, vchData, vchHash); } @@ -196,7 +200,7 @@ bool GetBDAPData(const CTxOut& out, std::vector& vchData, std::ve return GetBDAPData(out.scriptPubKey, vchData, vchHash); } -bool CDomainEntry::UnserializeFromTx(const CTransaction& tx) { +bool CDomainEntry::UnserializeFromTx(const CTransactionRef& tx) { std::vector vchData; std::vector vchHash; int nOut; @@ -392,8 +396,8 @@ bool CDomainEntry::ValidateValues(std::string& errorMessage) bool CDomainEntry::CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& errorMessage) { for (const CTxMemPoolEntry& e : pool.mapTx) { - const CTransaction& tx = e.GetTx(); - for (const CTxOut& txOut : tx.vout) { + const CTransactionRef& tx = e.GetSharedTx(); + for (const CTxOut& txOut : tx->vout) { if (IsBDAPDataOutput(txOut)) { CDomainEntry domainEntry(tx); if (this->GetFullObjectPath() == domainEntry.GetFullObjectPath()) { @@ -407,11 +411,11 @@ bool CDomainEntry::CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& e } /** Checks if the domain entry transaction uses the entry's UTXO */ -bool CDomainEntry::TxUsesPreviousUTXO(const CTransaction& tx) +bool CDomainEntry::TxUsesPreviousUTXO(const CTransactionRef& tx) { int nIn = GetBDAPOperationOutIndex(tx); COutPoint entryOutpoint = COutPoint(txHash, nIn); - for (const CTxIn& txIn : tx.vin) { + for (const CTxIn& txIn : tx->vin) { if (txIn.prevout == entryOutpoint) return true; } @@ -522,12 +526,12 @@ CAmount GetBDAPFee(const CScript& scriptPubKey) return recp.nAmount; } -bool DecodeBDAPTx(const CTransaction& tx, int& op, std::vector >& vvch) +bool DecodeBDAPTx(const CTransactionRef& tx, int& op, std::vector >& vvch) { bool found = false; - for (unsigned int i = 0; i < tx.vout.size(); i++) { - const CTxOut& out = tx.vout[i]; + for (unsigned int i = 0; i < tx->vout.size(); i++) { + const CTxOut& out = tx->vout[i]; vchCharString vvchRead; if (DecodeBDAPScript(out.scriptPubKey, op, vvchRead)) { found = true; @@ -606,11 +610,11 @@ std::string GetBDAPOpTypeString(const CScript& script) return BDAPFromOp(GetBDAPOpType(script)); } -bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp, vchCharString& vvchOpParameters, int& op) +bool GetBDAPOpScript(const CTransactionRef& tx, CScript& scriptBDAPOp, vchCharString& vvchOpParameters, int& op) { - for (unsigned int i = 0; i < tx.vout.size(); i++) + for (unsigned int i = 0; i < tx->vout.size(); i++) { - const CTxOut& out = tx.vout[i]; + const CTxOut& out = tx->vout[i]; if (DecodeBDAPScript(out.scriptPubKey, op, vvchOpParameters)) { scriptBDAPOp = out.scriptPubKey; @@ -620,7 +624,7 @@ bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp, vchCharStrin return false; } -bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp) +bool GetBDAPOpScript(const CTransactionRef& tx, CScript& scriptBDAPOp) { int op; vchCharString vvchOpParameters; @@ -662,10 +666,10 @@ std::string GetBDAPOpStringFromOutput(const CTxOut& out) return GetBDAPOpTypeString(out.scriptPubKey); } -int GetBDAPOperationOutIndex(const CTransaction& tx) +int GetBDAPOperationOutIndex(const CTransactionRef& tx) { - for(unsigned int i = 0; ivout.size();i++) { + if(IsBDAPOperationOutput(tx->vout[i])) return i; } return -1; @@ -673,7 +677,7 @@ int GetBDAPOperationOutIndex(const CTransaction& tx) int GetBDAPOperationOutIndex(int nHeight, const uint256& txHash) { - CTransaction tx; + CTransactionRef tx; const Consensus::Params& consensusParams = Params().GetConsensus(); if (!GetBDAPTransaction(nHeight, txHash, tx, consensusParams)) { diff --git a/src/bdap/domainentry.h b/src/bdap/domainentry.h index 4579c32154..f4846b06dd 100644 --- a/src/bdap/domainentry.h +++ b/src/bdap/domainentry.h @@ -8,6 +8,7 @@ #include "bdap.h" #include "amount.h" #include "consensus/params.h" +#include "primitives/transaction.h" #include "script/script.h" #include "serialize.h" #include "sync.h" @@ -17,7 +18,6 @@ class CCoinsViewCache; class CDynamicAddress; struct CRecipient; -class CTransaction; class CTxOut; class CTxMemPool; @@ -79,7 +79,7 @@ class CDomainEntry { SetNull(); } - CDomainEntry(const CTransaction &tx) { + CDomainEntry(const CTransactionRef& tx) { SetNull(); UnserializeFromTx(tx); } @@ -152,7 +152,7 @@ class CDomainEntry { } inline bool IsNull() const { return (DomainComponent.empty()); } - bool UnserializeFromTx(const CTransaction &tx); + bool UnserializeFromTx(const CTransactionRef &tx); bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); void Serialize(std::vector& vchData); @@ -163,15 +163,15 @@ class CDomainEntry { std::vector vchObjectLocation() const; // OU . Domain Name bool ValidateValues(std::string& errorMessage); bool CheckIfExistsInMemPool(const CTxMemPool& pool, std::string& errorMessage); - bool TxUsesPreviousUTXO(const CTransaction& tx); + bool TxUsesPreviousUTXO(const CTransactionRef& tx); BDAP::ObjectType ObjectType() const { return (BDAP::ObjectType)nObjectType; } std::string ObjectTypeString() const { return BDAP::GetObjectTypeString(nObjectType); }; }; std::string BDAPFromOp(const int op); bool IsBDAPDataOutput(const CTxOut& out); -int GetBDAPDataOutput(const CTransaction& tx); -bool GetBDAPData(const CTransaction& tx, std::vector& vchData, std::vector& vchHash, int& nOut); +int GetBDAPDataOutput(const CTransactionRef& tx); +bool GetBDAPData(const CTransactionRef& tx, std::vector& vchData, std::vector& vchHash, int& nOut); bool GetBDAPData(const CScript& scriptPubKey, std::vector& vchData, std::vector& vchHash); bool GetBDAPData(const CTxOut& out, std::vector& vchData, std::vector& vchHash); bool BuildBDAPJson(const CDomainEntry& entry, UniValue& oName, bool fAbridged = false); @@ -183,18 +183,18 @@ void CreateRecipient(const CScript& scriptPubKey, CRecipient& recipient); void ToLowerCase(CharString& vchValue); void ToLowerCase(std::string& strValue); CAmount GetBDAPFee(const CScript& scriptPubKey); -bool DecodeBDAPTx(const CTransaction& tx, int& op, std::vector >& vvch); +bool DecodeBDAPTx(const CTransactionRef& tx, int& op, std::vector >& vvch); bool FindBDAPInTx(const CCoinsViewCache &inputs, const CTransaction& tx, std::vector >& vvch); int GetBDAPOpType(const CScript& script); int GetBDAPOpType(const CTxOut& out); std::string GetBDAPOpTypeString(const CScript& script); -bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp, vchCharString& vvchOpParameters, int& op); -bool GetBDAPOpScript(const CTransaction& tx, CScript& scriptBDAPOp); +bool GetBDAPOpScript(const CTransactionRef& tx, CScript& scriptBDAPOp, vchCharString& vvchOpParameters, int& op); +bool GetBDAPOpScript(const CTransactionRef& tx, CScript& scriptBDAPOp); bool GetBDAPDataScript(const CTransaction& tx, CScript& scriptBDAPData); bool IsBDAPOperationOutput(const CTxOut& out); -int GetBDAPOperationOutIndex(const CTransaction& tx); +int GetBDAPOperationOutIndex(const CTransactionRef& tx); int GetBDAPOperationOutIndex(int nHeight, const uint256& txHash); -bool GetBDAPTransaction(int nHeight, const uint256& hash, CTransaction& txOut, const Consensus::Params& consensusParams); +bool GetBDAPTransaction(int nHeight, const uint256& hash, CTransactionRef &txOut, const Consensus::Params& consensusParams); bool GetDomainEntryFromRecipient(const std::vector& vecSend, CDomainEntry& entry, std::string& strOpType); CDynamicAddress GetScriptAddress(const CScript& pubScript); int GetBDAPOpCodeFromOutput(const CTxOut& out); diff --git a/src/bdap/domainentrydb.cpp b/src/bdap/domainentrydb.cpp index bd9f224c88..b6613d9926 100644 --- a/src/bdap/domainentrydb.cpp +++ b/src/bdap/domainentrydb.cpp @@ -348,7 +348,7 @@ static bool CommonDataCheck(const CDomainEntry& entry, const vchCharString& vvch return true; } -bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckNewDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck) { if (!CommonDataCheck(entry, vvchOpParameters, errorMessage)) @@ -379,7 +379,7 @@ bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& ent return FlushLevelDB(); } -bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckDeleteDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck) { //if exists, check for owner's signature @@ -404,7 +404,7 @@ bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } else { - CTransaction prevTx; + CTransactionRef prevTx = MakeTransactionRef(); uint256 hashBlock; if (!GetTransaction(prevDomainEntry.txHash, prevTx, Params().GetConsensus(), hashBlock, true)) { errorMessage = "CheckDeleteDomainEntryTxInputs: - " + _("Cannot extract previous transaction from BDAP output; this delete operation failed!"); @@ -433,7 +433,7 @@ bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& return FlushLevelDB(); } -bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckUpdateDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck) { //if exists, check for owner's signature @@ -458,7 +458,7 @@ bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& } else { - CTransaction prevTx; + CTransactionRef prevTx = MakeTransactionRef(); uint256 hashBlock; if (!GetTransaction(prevDomainEntry.txHash, prevTx, Params().GetConsensus(), hashBlock, true)) { errorMessage = "CheckUpdateDomainEntryTxInputs: - " + _("Cannot extract previous transaction from BDAP output; this update operation failed!"); @@ -487,7 +487,7 @@ bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& return FlushLevelDB(); } -bool CheckMoveDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckMoveDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck) { //check name in operation matches entry data in leveldb @@ -496,7 +496,7 @@ bool CheckMoveDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& en return false; } -bool CheckExecuteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckExecuteDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck) { //check name in operation matches entry data in leveldb @@ -505,7 +505,7 @@ bool CheckExecuteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& return false; } -bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckBindDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck) { //check names in operation matches entry data in leveldb @@ -515,7 +515,7 @@ bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& en return false; } -bool CheckRevokeDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckRevokeDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck) { //check name in operation matches entry data in leveldb @@ -524,17 +524,17 @@ bool CheckRevokeDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& return false; } -bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, +bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransactionRef& tx, int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck) { - if (tx.IsCoinBase() && !fJustCheck && !bSanityCheck) + if (tx->IsCoinBase() && !fJustCheck && !bSanityCheck) { LogPrintf("*Trying to add BDAP entry in coinbase transaction, skipping..."); return true; } //if (fDebug && !bSanityCheck) - LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op).c_str(), tx.GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); + LogPrintf("*** BDAP nHeight=%d, chainActive.Tip()=%d, op=%s, hash=%s justcheck=%s\n", nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op).c_str(), tx->GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK"); CScript scriptOp; vchCharString vvchOpParameters; @@ -566,23 +566,23 @@ bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& return error(errorMessage.c_str()); } - entry.txHash = tx.GetHash(); + entry.txHash = tx->GetHash(); entry.nHeight = nHeight; if (strOperationType == "bdap_new") - return CheckNewDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); + return CheckNewDomainEntryTxInputs(entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_delete") - return CheckDeleteDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); + return CheckDeleteDomainEntryTxInputs(entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_update") - return CheckUpdateDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); + return CheckUpdateDomainEntryTxInputs(entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_move") - return CheckMoveDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); + return CheckMoveDomainEntryTxInputs(entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_execute") - return CheckExecuteDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); + return CheckExecuteDomainEntryTxInputs(entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_bind") - return CheckBindDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); + return CheckBindDomainEntryTxInputs(entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); else if (strOperationType == "bdap_revoke") - return CheckRevokeDomainEntryTxInputs(tx, entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); + return CheckRevokeDomainEntryTxInputs(entry, scriptOp, vvchOpParameters, errorMessage, fJustCheck); return false; } \ No newline at end of file diff --git a/src/bdap/domainentrydb.h b/src/bdap/domainentrydb.h index c083a6c0e1..095be52ef3 100644 --- a/src/bdap/domainentrydb.h +++ b/src/bdap/domainentrydb.h @@ -40,7 +40,7 @@ bool GetDomainEntry(const std::vector& vchObjectPath, CDomainEntr bool CheckDomainEntryDB(); bool FlushLevelDB(); void CleanupLevelDB(int& nRemoved); -bool CheckNewDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, +bool CheckNewDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck); bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck); @@ -54,7 +54,7 @@ bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& en std::string& errorMessage, bool fJustCheck); bool CheckRevokeDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, std::string& errorMessage, bool fJustCheck); -bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransaction& tx, +bool CheckDomainEntryTxInputs(const CCoinsViewCache& inputs, const CTransactionRef& tx, int op, const std::vector >& vvchArgs, bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck); extern CDomainEntryDB *pDomainEntryDB; diff --git a/src/bdap/entrycertificate.cpp b/src/bdap/entrycertificate.cpp index 34721a3f65..4b731224f2 100644 --- a/src/bdap/entrycertificate.cpp +++ b/src/bdap/entrycertificate.cpp @@ -38,7 +38,7 @@ bool CEntryCertificate::UnserializeFromData(const std::vector& vc return true; } -bool CEntryCertificate::UnserializeFromTx(const CTransaction& tx) +bool CEntryCertificate::UnserializeFromTx(const CTransactionRef& tx) { std::vector vchData; std::vector vchHash; diff --git a/src/bdap/entrycertificate.h b/src/bdap/entrycertificate.h index 6a2b258a35..de0531181b 100644 --- a/src/bdap/entrycertificate.h +++ b/src/bdap/entrycertificate.h @@ -31,7 +31,7 @@ class CEntryCertificate { SetNull(); } - CEntryCertificate(const CTransaction& tx) { + CEntryCertificate(const CTransactionRef& tx) { SetNull(); UnserializeFromTx(tx); } @@ -89,7 +89,7 @@ class CEntryCertificate { inline bool IsNull() const { return (OwnerFullPath.empty()); } void Serialize(std::vector& vchData); bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); - bool UnserializeFromTx(const CTransaction &tx); + bool UnserializeFromTx(const CTransactionRef& tx); bool SelfSignedCertificate() const { if (OwnerDomainEntry == nullptr || AuthorityDomainEntry == nullptr) diff --git a/src/bdap/entrychannel.cpp b/src/bdap/entrychannel.cpp index 092f6f474a..c625f0b031 100644 --- a/src/bdap/entrychannel.cpp +++ b/src/bdap/entrychannel.cpp @@ -38,7 +38,7 @@ bool CEntryChannel::UnserializeFromData(const std::vector& vchDat return true; } -bool CEntryChannel::UnserializeFromTx(const CTransaction& tx) +bool CEntryChannel::UnserializeFromTx(const CTransactionRef& tx) { std::vector vchData; std::vector vchHash; diff --git a/src/bdap/entrychannel.h b/src/bdap/entrychannel.h index 96d9a03255..52c1af8c77 100644 --- a/src/bdap/entrychannel.h +++ b/src/bdap/entrychannel.h @@ -44,7 +44,7 @@ class CEntryChannel { SetNull(); } - CEntryChannel(const CTransaction& tx) { + CEntryChannel(const CTransactionRef& tx) { SetNull(); UnserializeFromTx(tx); } @@ -110,7 +110,7 @@ class CEntryChannel { inline bool IsNull() const { return (OwnerFullPath.empty()); } void Serialize(std::vector& vchData); bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); - bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromTx(const CTransactionRef& tx); bool ValidateValues(std::string& errorMessage); }; diff --git a/src/bdap/entrycheckpoints.cpp b/src/bdap/entrycheckpoints.cpp index 206d26db6f..8bd16d1cee 100644 --- a/src/bdap/entrycheckpoints.cpp +++ b/src/bdap/entrycheckpoints.cpp @@ -38,7 +38,7 @@ bool CEntryCheckpoints::UnserializeFromData(const std::vector& vc return true; } -bool CEntryCheckpoints::UnserializeFromTx(const CTransaction& tx) +bool CEntryCheckpoints::UnserializeFromTx(const CTransactionRef& tx) { std::vector vchData; std::vector vchHash; diff --git a/src/bdap/entrycheckpoints.h b/src/bdap/entrycheckpoints.h index 0eeeb5361e..c683a0ea9d 100644 --- a/src/bdap/entrycheckpoints.h +++ b/src/bdap/entrycheckpoints.h @@ -27,7 +27,7 @@ class CEntryCheckpoints { SetNull(); } - CEntryCheckpoints(const CTransaction& tx) { + CEntryCheckpoints(const CTransactionRef& tx) { SetNull(); UnserializeFromTx(tx); } @@ -75,7 +75,7 @@ class CEntryCheckpoints { inline bool IsNull() const { return (OwnerFullPath.empty()); } void Serialize(std::vector& vchData); bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); - bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromTx(const CTransactionRef& tx); bool ValidateValues(std::string& errorMessage); void AddCheckpoint(const uint32_t& height, const CharString& vchHash); diff --git a/src/bdap/entrylink.cpp b/src/bdap/entrylink.cpp index 256e6c9ada..bdfce385e1 100644 --- a/src/bdap/entrylink.cpp +++ b/src/bdap/entrylink.cpp @@ -39,7 +39,7 @@ bool CEntryLink::UnserializeFromData(const std::vector& vchData, return true; } -bool CEntryLink::UnserializeFromTx(const CTransaction& tx) +bool CEntryLink::UnserializeFromTx(const CTransactionRef& tx) { std::vector vchData; std::vector vchHash; diff --git a/src/bdap/entrylink.h b/src/bdap/entrylink.h index 5de8c9d4a1..01ca3910ca 100644 --- a/src/bdap/entrylink.h +++ b/src/bdap/entrylink.h @@ -6,6 +6,7 @@ #define DYNAMIC_BDAP_ENTRYLINK_H #include "bdap.h" +#include "primitives/transaction.h" #include "serialize.h" #include "uint256.h" @@ -15,7 +16,6 @@ manage domain entry link requests. When linking entries, we want to use stealth addresses so the linkage requests are not public. */ -class CTransaction; class CEntryLink { public: @@ -33,7 +33,7 @@ class CEntryLink { SetNull(); } - CEntryLink(const CTransaction& tx) { + CEntryLink(const CTransactionRef& tx) { SetNull(); UnserializeFromTx(tx); } @@ -87,9 +87,9 @@ class CEntryLink { inline bool IsNull() const { return (SenderFullPath.empty()); } void Serialize(std::vector& vchData); bool UnserializeFromData(const std::vector &vchData, const std::vector &vchHash); - bool UnserializeFromTx(const CTransaction &tx); + bool UnserializeFromTx(const CTransactionRef& tx); - bool IsMyRequest(const CTransaction& tx); + bool IsMyRequest(const CTransactionRef& tx); CharString SenderFileName(unsigned int nTime); CharString RecipientFileName(unsigned int nTime); }; diff --git a/src/bdap/identity.cpp b/src/bdap/identity.cpp index fd4e5b8975..16e5e5c768 100644 --- a/src/bdap/identity.cpp +++ b/src/bdap/identity.cpp @@ -36,7 +36,7 @@ bool CIdentity::UnserializeFromData(const std::vector& vchData, c return true; } -bool CIdentity::UnserializeFromTx(const CTransaction& tx) +bool CIdentity::UnserializeFromTx(const CTransactionRef& tx) { std::vector vchData; std::vector vchHash; @@ -82,7 +82,7 @@ bool CIdentityVerification::UnserializeFromData(const std::vector return true; } -bool CIdentityVerification::UnserializeFromTx(const CTransaction& tx) +bool CIdentityVerification::UnserializeFromTx(const CTransactionRef& tx) { std::vector vchData; std::vector vchHash; diff --git a/src/bdap/identity.h b/src/bdap/identity.h index eb0cd1d69f..1438dc54bd 100644 --- a/src/bdap/identity.h +++ b/src/bdap/identity.h @@ -7,6 +7,7 @@ #include "bdap.h" #include "domainentry.h" +#include "primitives/transaction.h" #include "serialize.h" #include "uint256.h" @@ -26,7 +27,7 @@ class CIdentity { SetNull(); } - CIdentity(const CTransaction& tx) { + CIdentity(const CTransactionRef& tx) { SetNull(); UnserializeFromTx(tx); } @@ -71,7 +72,7 @@ class CIdentity { inline bool IsNull() const { return (OwnerFullPath.empty()); } void Serialize(std::vector& vchData); bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); - bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromTx(const CTransactionRef& tx); }; class CIdentityVerification { @@ -92,7 +93,7 @@ class CIdentityVerification { SetNull(); } - CIdentityVerification(const CTransaction& tx) { + CIdentityVerification(const CTransactionRef& tx) { SetNull(); UnserializeFromTx(tx); } @@ -143,7 +144,7 @@ class CIdentityVerification { inline bool IsNull() const { return (VerifierFullPath.empty()); } void Serialize(std::vector& vchData); bool UnserializeFromData(const std::vector& vchData, const std::vector& vchHash); - bool UnserializeFromTx(const CTransaction& tx); + bool UnserializeFromTx(const CTransactionRef& tx); }; diff --git a/src/bdap/rpcdomainentry.cpp b/src/bdap/rpcdomainentry.cpp index b7a97b8366..b1dd6d2fcb 100644 --- a/src/bdap/rpcdomainentry.cpp +++ b/src/bdap/rpcdomainentry.cpp @@ -136,7 +136,7 @@ static UniValue AddDomainEntry(const JSONRPCRequest& request, BDAP::ObjectType b // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class LogPrintf("DomainEntry Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); - const CTransaction testTx = (CTransaction)wtx; + const CTransactionRef testTx = MakeTransactionRef((CTransaction)wtx); CDomainEntry testDomainEntry(testTx); //loads the class from a transaction LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", @@ -343,7 +343,7 @@ static UniValue UpdateDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class LogPrintf("DomainEntry Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); - const CTransaction testTx = (CTransaction)wtx; + const CTransactionRef testTx = MakeTransactionRef((CTransaction)wtx); CDomainEntry testDomainEntry(testTx); //loads the class from a transaction LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", @@ -441,7 +441,7 @@ static UniValue DeleteDomainEntry(const JSONRPCRequest& request, BDAP::ObjectTyp // make sure we can deserialize the transaction from the scriptData and get a valid CDomainEntry class LogPrintf("DomainEntry Scripts:\nscriptData = %s\n", ScriptToAsmStr(scriptData, true)); - const CTransaction testTx = (CTransaction)wtx; + const CTransactionRef testTx = MakeTransactionRef((CTransaction)wtx); CDomainEntry testDomainEntry(testTx); //loads the class from a transaction LogPrintf("CDomainEntry Values:\nnVersion = %u\nFullObjectPath = %s\nCommonName = %s\nOrganizationalUnit = %s\nEncryptPublicKey = %s\n", @@ -519,25 +519,26 @@ UniValue adddomaingroup(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ -------------------- #ifdef ENABLE_WALLET /* BDAP */ - { "bdap", "adddomainentry", &adddomainentry, true }, - { "bdap", "getdomainusers", &getdomainusers, true }, - { "bdap", "getdomaingroups", &getdomaingroups, true }, - { "bdap", "getdomainuserinfo", &getdomainuserinfo, true }, - { "bdap", "updatedomainuser", &updatedomainuser, true }, - { "bdap", "updatedomaingroup", &updatedomaingroup, true }, - { "bdap", "deletedomainuser", &deletedomainuser, true }, - { "bdap", "deletedomaingroup", &deletedomaingroup, true }, - { "bdap", "adddomaingroup", &adddomaingroup, true }, - { "bdap", "getdomaingroupinfo", &getdomaingroupinfo, true }, + { "bdap", "adddomainentry", &adddomainentry, true, {"userid","common name", "registration days"} }, + { "bdap", "getdomainusers", &getdomainusers, true, {"records per page","page returned"} }, + { "bdap", "getdomaingroups", &getdomaingroups, true, {"records per page","page returned"} }, + { "bdap", "getdomainuserinfo", &getdomainuserinfo, true, {"public name"} }, + { "bdap", "updatedomainuser", &updatedomainuser, true, {"userid","common name", "registration days"} }, + { "bdap", "updatedomaingroup", &updatedomaingroup, true, {"groupid","common name", "registration days"} }, + { "bdap", "deletedomainuser", &deletedomainuser, true, {"userid"} }, + { "bdap", "deletedomaingroup", &deletedomaingroup, true, {"groupid"} }, + { "bdap", "adddomaingroup", &adddomaingroup, true, {"groupid","common name"} }, + { "bdap", "getdomaingroupinfo", &getdomaingroupinfo, true, {} }, #endif //ENABLE_WALLET - { "bdap", "makekeypair", &makekeypair, true }, + { "bdap", "makekeypair", &makekeypair, true, {} }, }; -void RegisterDomainEntryRPCCommands(CRPCTable &tableRPC) +void RegisterDomainEntryRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } \ No newline at end of file diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp new file mode 100644 index 0000000000..2e9bc2c84e --- /dev/null +++ b/src/blockencodings.cpp @@ -0,0 +1,221 @@ +// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers +// Copyright (c) 2009-2018 The Bitcoin Developers +// Copyright (c) 2009-2018 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "blockencodings.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" +#include "chainparams.h" +#include "hash.h" +#include "random.h" +#include "streams.h" +#include "txmempool.h" +#include "validation.h" +#include "util.h" + +#include + +#define MIN_TRANSACTION_SIZE (::GetSerializeSize(CTransaction(), SER_NETWORK, PROTOCOL_VERSION)) + +CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block) : + nonce(GetRand(std::numeric_limits::max())), + shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) { + FillShortTxIDSelector(); + //TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase + prefilledtxn[0] = {0, block.vtx[0]}; + for (size_t i = 1; i < block.vtx.size(); i++) { + const CTransaction& tx = *block.vtx[i]; + shorttxids[i - 1] = GetShortID(tx.GetHash()); + } +} + +void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const { + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << header << nonce; + CSHA256 hasher; + hasher.Write((unsigned char*)&(*stream.begin()), stream.end() - stream.begin()); + uint256 shorttxidhash; + hasher.Finalize(shorttxidhash.begin()); + shorttxidk0 = shorttxidhash.GetUint64(0); + shorttxidk1 = shorttxidhash.GetUint64(1); +} + +uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const { + static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids calculation assumes 6-byte shorttxids"); + return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL; +} + + + +ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector>& extra_txn) { + if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty())) + return READ_STATUS_INVALID; + if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_SIZE / MIN_TRANSACTION_SIZE) + return READ_STATUS_INVALID; + + assert(header.IsNull() && txn_available.empty()); + header = cmpctblock.header; + txn_available.resize(cmpctblock.BlockTxCount()); + + int32_t lastprefilledindex = -1; + for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) { + if (cmpctblock.prefilledtxn[i].tx->IsNull()) + return READ_STATUS_INVALID; + + lastprefilledindex += cmpctblock.prefilledtxn[i].index + 1; //index is a uint16_t, so can't overflow here + if (lastprefilledindex > std::numeric_limits::max()) + return READ_STATUS_INVALID; + if ((uint32_t)lastprefilledindex > cmpctblock.shorttxids.size() + i) { + // If we are inserting a tx at an index greater than our full list of shorttxids + // plus the number of prefilled txn we've inserted, then we have txn for which we + // have neither a prefilled txn or a shorttxid! + return READ_STATUS_INVALID; + } + txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx; + } + prefilled_count = cmpctblock.prefilledtxn.size(); + + // Calculate map of txids -> positions and check mempool to see what we have (or don't) + // Because well-formed cmpctblock messages will have a (relatively) uniform distribution + // of short IDs, any highly-uneven distribution of elements can be safely treated as a + // READ_STATUS_FAILED. + std::unordered_map shorttxids(cmpctblock.shorttxids.size()); + uint16_t index_offset = 0; + for (size_t i = 0; i < cmpctblock.shorttxids.size(); i++) { + while (txn_available[i + index_offset]) + index_offset++; + shorttxids[cmpctblock.shorttxids[i]] = i + index_offset; + // To determine the chance that the number of entries in a bucket exceeds N, + // we use the fact that the number of elements in a single bucket is + // binomially distributed (with n = the number of shorttxids S, and p = + // 1 / the number of buckets), that in the worst case the number of buckets is + // equal to S (due to std::unordered_map having a default load factor of 1.0), + // and that the chance for any bucket to exceed N elements is at most + // buckets * (the chance that any given bucket is above N elements). + // Thus: P(max_elements_per_bucket > N) <= S * (1 - cdf(binomial(n=S,p=1/S), N)). + // If we assume blocks of up to 16000, allowing 12 elements per bucket should + // only fail once per ~1 million block transfers (per peer and connection). + if (shorttxids.bucket_size(shorttxids.bucket(cmpctblock.shorttxids[i])) > 12) + return READ_STATUS_FAILED; + } + // TODO: in the shortid-collision case, we should instead request both transactions + // which collided. Falling back to full-block-request here is overkill. + if (shorttxids.size() != cmpctblock.shorttxids.size()) + return READ_STATUS_FAILED; // Short ID collision + + std::vector have_txn(txn_available.size()); + { + LOCK(pool->cs); + const std::vector >& vTxHashes = pool->vTxHashes; + for (size_t i = 0; i < vTxHashes.size(); i++) { + uint64_t shortid = cmpctblock.GetShortID(vTxHashes[i].first); + std::unordered_map::iterator idit = shorttxids.find(shortid); + if (idit != shorttxids.end()) { + if (!have_txn[idit->second]) { + txn_available[idit->second] = vTxHashes[i].second->GetSharedTx(); + have_txn[idit->second] = true; + mempool_count++; + } else { + // If we find two mempool txn that match the short id, just request it. + // This should be rare enough that the extra bandwidth doesn't matter, + // but eating a round-trip due to FillBlock failure would be annoying + if (txn_available[idit->second]) { + txn_available[idit->second].reset(); + mempool_count--; + } + } + } + // Though ideally we'd continue scanning for the two-txn-match-shortid case, + // the performance win of an early exit here is too good to pass up and worth + // the extra risk. + if (mempool_count == shorttxids.size()) + break; + } + } + + for (size_t i = 0; i < extra_txn.size(); i++) { + uint64_t shortid = cmpctblock.GetShortID(extra_txn[i].first); + std::unordered_map::iterator idit = shorttxids.find(shortid); + if (idit != shorttxids.end()) { + if (!have_txn[idit->second]) { + txn_available[idit->second] = extra_txn[i].second; + have_txn[idit->second] = true; + mempool_count++; + extra_count++; + } else { + // If we find two mempool/extra txn that match the short id, just + // request it. + // This should be rare enough that the extra bandwidth doesn't matter, + // but eating a round-trip due to FillBlock failure would be annoying + // Note that we dont want duplication between extra_txn and mempool to + // trigger this case, so we compare hashes first + if (txn_available[idit->second] && + txn_available[idit->second]->GetHash() != extra_txn[i].second->GetHash()) { + txn_available[idit->second].reset(); + mempool_count--; + extra_count--; + } + } + } + // Though ideally we'd continue scanning for the two-txn-match-shortid case, + // the performance win of an early exit here is too good to pass up and worth + // the extra risk. + if (mempool_count == shorttxids.size()) + break; + } + + LogPrint("cmpctblock", "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION)); + + return READ_STATUS_OK; +} + +bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const { + assert(!header.IsNull()); + assert(index < txn_available.size()); + return txn_available[index] ? true : false; +} + +ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector& vtx_missing) { + assert(!header.IsNull()); + uint256 hash = header.GetHash(); + block = header; + block.vtx.resize(txn_available.size()); + + size_t tx_missing_offset = 0; + for (size_t i = 0; i < txn_available.size(); i++) { + if (!txn_available[i]) { + if (vtx_missing.size() <= tx_missing_offset) + return READ_STATUS_INVALID; + block.vtx[i] = vtx_missing[tx_missing_offset++]; + } else + block.vtx[i] = std::move(txn_available[i]); + } + + // Make sure we can't call FillBlock again. + header.SetNull(); + txn_available.clear(); + + if (vtx_missing.size() != tx_missing_offset) + return READ_STATUS_INVALID; + + CValidationState state; + if (!CheckBlock(block, state, Params().GetConsensus())) { + // TODO: We really want to just check merkle tree manually here, + // but that is expensive, and CheckBlock caches a block's + // "checked-status" (in the CBlock?). CBlock should be able to + // check its own merkle root and cache that check. + if (state.CorruptionPossible()) + return READ_STATUS_FAILED; // Possible Short ID collision + return READ_STATUS_CHECKBLOCK_FAILED; + } + + LogPrint("cmpctblock", "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool (incl at least %lu from extra pool) and %lu txn requested\n", hash.ToString(), prefilled_count, mempool_count, extra_count, vtx_missing.size()); + if (vtx_missing.size() < 5) { + for (const auto& tx : vtx_missing) + LogPrint("cmpctblock", "Reconstructed block %s required tx %s\n", hash.ToString(), tx->GetHash().ToString()); + } + + return READ_STATUS_OK; +} diff --git a/src/blockencodings.h b/src/blockencodings.h new file mode 100644 index 0000000000..a768a753f5 --- /dev/null +++ b/src/blockencodings.h @@ -0,0 +1,209 @@ +// Copyright (c) 2016 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_BLOCK_ENCODINGS_H +#define BITCOIN_BLOCK_ENCODINGS_H + +#include "primitives/block.h" + +#include + +class CTxMemPool; + +// Dumb helper to handle CTransaction compression at serialize-time +struct TransactionCompressor { +private: + CTransactionRef& tx; +public: + TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {} + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(tx); //TODO: Compress tx encoding + } +}; + +class BlockTransactionsRequest { +public: + // A BlockTransactionsRequest message + uint256 blockhash; + std::vector indexes; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(blockhash); + uint64_t indexes_size = (uint64_t)indexes.size(); + READWRITE(COMPACTSIZE(indexes_size)); + if (ser_action.ForRead()) { + size_t i = 0; + while (indexes.size() < indexes_size) { + indexes.resize(std::min((uint64_t)(1000 + indexes.size()), indexes_size)); + for (; i < indexes.size(); i++) { + uint64_t index = 0; + READWRITE(COMPACTSIZE(index)); + if (index > std::numeric_limits::max()) + throw std::ios_base::failure("index overflowed 16 bits"); + indexes[i] = index; + } + } + + uint16_t offset = 0; + for (size_t j = 0; j < indexes.size(); j++) { + if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits::max()) + throw std::ios_base::failure("indexes overflowed 16 bits"); + indexes[j] = indexes[j] + offset; + offset = indexes[j] + 1; + } + } else { + for (size_t i = 0; i < indexes.size(); i++) { + uint64_t index = indexes[i] - (i == 0 ? 0 : (indexes[i - 1] + 1)); + READWRITE(COMPACTSIZE(index)); + } + } + } +}; + +class BlockTransactions { +public: + // A BlockTransactions message + uint256 blockhash; + std::vector txn; + + BlockTransactions() {} + BlockTransactions(const BlockTransactionsRequest& req) : + blockhash(req.blockhash), txn(req.indexes.size()) {} + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(blockhash); + uint64_t txn_size = (uint64_t)txn.size(); + READWRITE(COMPACTSIZE(txn_size)); + if (ser_action.ForRead()) { + size_t i = 0; + while (txn.size() < txn_size) { + txn.resize(std::min((uint64_t)(1000 + txn.size()), txn_size)); + for (; i < txn.size(); i++) + READWRITE(REF(TransactionCompressor(txn[i]))); + } + } else { + for (size_t i = 0; i < txn.size(); i++) + READWRITE(REF(TransactionCompressor(txn[i]))); + } + } +}; + +// Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock +struct PrefilledTransaction { + // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs, + // as a proper transaction-in-block-index in PartiallyDownloadedBlock + uint16_t index; + CTransactionRef tx; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + uint64_t idx = index; + READWRITE(COMPACTSIZE(idx)); + if (idx > std::numeric_limits::max()) + throw std::ios_base::failure("index overflowed 16-bits"); + index = idx; + READWRITE(REF(TransactionCompressor(tx))); + } +}; + +typedef enum ReadStatus_t +{ + READ_STATUS_OK, + READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap + READ_STATUS_FAILED, // Failed to process object + READ_STATUS_CHECKBLOCK_FAILED, // Used only by FillBlock to indicate a + // failure in CheckBlock. +} ReadStatus; + +class CBlockHeaderAndShortTxIDs { +private: + mutable uint64_t shorttxidk0, shorttxidk1; + uint64_t nonce; + + void FillShortTxIDSelector() const; + + friend class PartiallyDownloadedBlock; + + static const int SHORTTXIDS_LENGTH = 6; +protected: + std::vector shorttxids; + std::vector prefilledtxn; + +public: + CBlockHeader header; + + // Dummy for deserialization + CBlockHeaderAndShortTxIDs() {} + + CBlockHeaderAndShortTxIDs(const CBlock& block); + + uint64_t GetShortID(const uint256& txhash) const; + + size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(header); + READWRITE(nonce); + + uint64_t shorttxids_size = (uint64_t)shorttxids.size(); + READWRITE(COMPACTSIZE(shorttxids_size)); + if (ser_action.ForRead()) { + size_t i = 0; + while (shorttxids.size() < shorttxids_size) { + shorttxids.resize(std::min((uint64_t)(1000 + shorttxids.size()), shorttxids_size)); + for (; i < shorttxids.size(); i++) { + uint32_t lsb = 0; uint16_t msb = 0; + READWRITE(lsb); + READWRITE(msb); + shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb); + static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids serialization assumes 6-byte shorttxids"); + } + } + } else { + for (size_t i = 0; i < shorttxids.size(); i++) { + uint32_t lsb = shorttxids[i] & 0xffffffff; + uint16_t msb = (shorttxids[i] >> 32) & 0xffff; + READWRITE(lsb); + READWRITE(msb); + } + } + + READWRITE(prefilledtxn); + + if (ser_action.ForRead()) + FillShortTxIDSelector(); + } +}; + +class PartiallyDownloadedBlock { +protected: + std::vector txn_available; + size_t prefilled_count = 0, mempool_count = 0, extra_count = 0; + CTxMemPool* pool; +public: + CBlockHeader header; + PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {} + + // extra_txn is a list of extra transactions to look at, in form + ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector>& extra_txn); + bool IsTxAvailable(size_t index) const; + ReadStatus FillBlock(CBlock& block, const std::vector& vtx_missing); +}; + +#endif diff --git a/src/cachemap.h b/src/cachemap.h index 0b7c52e22b..aef17668e7 100644 --- a/src/cachemap.h +++ b/src/cachemap.h @@ -68,8 +68,6 @@ class CacheMap private: size_type nMaxSize; - size_type nCurrentSize; - list_t listItems; map_t mapIndex; @@ -77,14 +75,12 @@ class CacheMap public: CacheMap(size_type nMaxSizeIn = 0) : nMaxSize(nMaxSizeIn), - nCurrentSize(0), listItems(), mapIndex() {} CacheMap(const CacheMap& other) : nMaxSize(other.nMaxSize), - nCurrentSize(other.nCurrentSize), listItems(other.listItems), mapIndex() { @@ -95,7 +91,6 @@ class CacheMap { mapIndex.clear(); listItems.clear(); - nCurrentSize = 0; } void SetMaxSize(size_type nMaxSizeIn) @@ -108,29 +103,25 @@ class CacheMap } size_type GetSize() const { - return nCurrentSize; + return listItems.size(); } - void Insert(const K& key, const V& value) + bool Insert(const K& key, const V& value) { - map_it it = mapIndex.find(key); - if(it != mapIndex.end()) { - item_t& item = *(it->second); - item.value = value; - return; + if(mapIndex.find(key) != mapIndex.end()) { + return false; } - if(nCurrentSize == nMaxSize) { + if(listItems.size() == nMaxSize) { PruneLast(); } listItems.push_front(item_t(key, value)); - mapIndex[key] = listItems.begin(); - ++nCurrentSize; + mapIndex.emplace(key, listItems.begin()); + return true; } bool HasKey(const K& key) const { - map_cit it = mapIndex.find(key); - return (it != mapIndex.end()); + return (mapIndex.find(key) != mapIndex.end()); } bool Get(const K& key, V& value) const @@ -152,7 +143,6 @@ class CacheMap } listItems.erase(it->second); mapIndex.erase(it); - --nCurrentSize; } const list_t& GetItemList() const { @@ -162,7 +152,6 @@ class CacheMap CacheMap& operator=(const CacheMap& other) { nMaxSize = other.nMaxSize; - nCurrentSize = other.nCurrentSize; listItems = other.listItems; RebuildIndex(); return *this; @@ -174,7 +163,6 @@ class CacheMap inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nMaxSize); - READWRITE(nCurrentSize); READWRITE(listItems); if(ser_action.ForRead()) { RebuildIndex(); @@ -184,20 +172,19 @@ class CacheMap private: void PruneLast() { - if(nCurrentSize < 1) { + if(listItems.empty()) { return; } item_t& item = listItems.back(); mapIndex.erase(item.key); listItems.pop_back(); - --nCurrentSize; } void RebuildIndex() { mapIndex.clear(); for(list_it it = listItems.begin(); it != listItems.end(); ++it) { - mapIndex[it->key] = it; + mapIndex.emplace(it->key, it); } } }; diff --git a/src/cachemultimap.h b/src/cachemultimap.h index a617b7035d..0e9142d230 100644 --- a/src/cachemultimap.h +++ b/src/cachemultimap.h @@ -48,8 +48,6 @@ class CacheMultiMap private: size_type nMaxSize; - size_type nCurrentSize; - list_t listItems; map_t mapIndex; @@ -57,14 +55,12 @@ class CacheMultiMap public: CacheMultiMap(size_type nMaxSizeIn = 0) : nMaxSize(nMaxSizeIn), - nCurrentSize(0), listItems(), mapIndex() {} CacheMultiMap(const CacheMap& other) : nMaxSize(other.nMaxSize), - nCurrentSize(other.nCurrentSize), listItems(other.listItems), mapIndex() { @@ -75,7 +71,6 @@ class CacheMultiMap { mapIndex.clear(); listItems.clear(); - nCurrentSize = 0; } void SetMaxSize(size_type nMaxSizeIn) @@ -88,17 +83,14 @@ class CacheMultiMap } size_type GetSize() const { - return nCurrentSize; + return listItems.size(); } bool Insert(const K& key, const V& value) { - if(nCurrentSize == nMaxSize) { - PruneLast(); - } map_it mit = mapIndex.find(key); if(mit == mapIndex.end()) { - mit = mapIndex.insert(std::pair(key, it_map_t())).first; + mit = mapIndex.emplace(key, it_map_t()).first; } it_map_t& mapIt = mit->second; @@ -107,18 +99,17 @@ class CacheMultiMap return false; } + if(listItems.size() == nMaxSize) { + PruneLast(); + } listItems.push_front(item_t(key, value)); - list_it lit = listItems.begin(); - - mapIt[value] = lit; - ++nCurrentSize; + mapIt.emplace(value, listItems.begin()); return true; } bool HasKey(const K& key) const { - map_cit it = mapIndex.find(key); - return (it != mapIndex.end()); + return (mapIndex.find(key) != mapIndex.end()); } bool Get(const K& key, V& value) const @@ -165,7 +156,6 @@ class CacheMultiMap for(it_map_it it = mapIt.begin(); it != mapIt.end(); ++it) { listItems.erase(it->second); - --nCurrentSize; } mapIndex.erase(mit); @@ -185,10 +175,9 @@ class CacheMultiMap } listItems.erase(it->second); - --nCurrentSize; mapIt.erase(it); - if(mapIt.size() < 1) { + if(mapIt.empty()) { mapIndex.erase(mit); } } @@ -200,7 +189,6 @@ class CacheMultiMap CacheMap& operator=(const CacheMap& other) { nMaxSize = other.nMaxSize; - nCurrentSize = other.nCurrentSize; listItems = other.listItems; RebuildIndex(); return *this; @@ -212,7 +200,6 @@ class CacheMultiMap inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nMaxSize); - READWRITE(nCurrentSize); READWRITE(listItems); if(ser_action.ForRead()) { RebuildIndex(); @@ -222,7 +209,7 @@ class CacheMultiMap private: void PruneLast() { - if(nCurrentSize < 1) { + if(listItems.empty()) { return; } @@ -237,13 +224,12 @@ class CacheMultiMap mapIt.erase(item.value); - if(mapIt.size() < 1) { + if(mapIt.empty()) { mapIndex.erase(item.key); } } listItems.pop_back(); - --nCurrentSize; } void RebuildIndex() @@ -253,10 +239,10 @@ class CacheMultiMap item_t& item = *lit; map_it mit = mapIndex.find(item.key); if(mit == mapIndex.end()) { - mit = mapIndex.insert(std::pair(item.key, it_map_t())).first; + mit = mapIndex.emplace(item.key, it_map_t()).first; } it_map_t& mapIt = mit->second; - mapIt[item.value] = lit; + mapIt.emplace(item.value, lit); } } }; diff --git a/src/chain.cpp b/src/chain.cpp index 70a8f2c471..66f1747ec7 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -61,10 +61,10 @@ const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const { return pindex; } -CBlockIndex* CChain::FindLatestBefore(int64_t nTime) const +CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const { std::vector::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime, - [](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTime() < time; }); + [](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; }); return (lower == vChain.end() ? NULL : *lower); } diff --git a/src/chain.h b/src/chain.h index 067776be52..d15be3baf9 100644 --- a/src/chain.h +++ b/src/chain.h @@ -202,6 +202,9 @@ class CBlockIndex //! (memory only) Sequential id assigned to distinguish order in which blocks are received. int32_t nSequenceId; + //! (memory only) Maximum nTime in the chain upto and including this block. + unsigned int nTimeMax; + void SetNull() { phashBlock = NULL; @@ -216,6 +219,7 @@ class CBlockIndex nChainTx = 0; nStatus = 0; nSequenceId = 0; + nTimeMax = 0; nVersion = 0; hashMerkleRoot = uint256(); @@ -281,7 +285,12 @@ class CBlockIndex return (int64_t)nTime; } - enum { nMedianTimeSpan=11 }; + int64_t GetBlockTimeMax() const + { + return (int64_t)nTimeMax; + } + + static constexpr int nMedianTimeSpan = 11; int64_t GetMedianTimePast() const { @@ -471,7 +480,7 @@ class CChain { const CBlockIndex *FindFork(const CBlockIndex *pindex) const; /** Find the most recent block with timestamp lower than the given. */ - CBlockIndex* FindLatestBefore(int64_t nTime) const; + CBlockIndex* FindEarliestAtLeast(int64_t nTime) const; }; #endif // DYNAMIC_CHAIN_H diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5942ef307e..0a37512c3c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -41,7 +41,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi genesis.nBits = nBits; genesis.nNonce = nNonce; genesis.nVersion = nVersion; - genesis.vtx.push_back(txNew); + genesis.vtx.push_back(MakeTransactionRef(std::move(txNew))); genesis.hashPrevBlock.SetNull(); genesis.hashMerkleRoot = BlockMerkleRoot(genesis); return genesis; @@ -115,19 +115,28 @@ class CMainParams : public CChainParams { consensus.nRewardsStart = 5137; // PoW Rewards begin on block 5137 consensus.nDynodePaymentsStartBlock = 10273; // Dynode Payments begin on block 10273 consensus.nMinCountDynodesPaymentStart = 500; // Dynode Payments begin once 500 Dynodes exist or more. + + consensus.nInstantSendConfirmationsRequired = 11; consensus.nInstantSendKeepLock = 24; + consensus.nBudgetPaymentsStartBlock = 2055; // actual historical value consensus.nBudgetPaymentsCycleBlocks = 20545; //Blocks per month consensus.nBudgetPaymentsWindowBlocks = 100; consensus.nBudgetProposalEstablishingTime = 24 * 60 * 60; + consensus.nSuperblockStartBlock = 2055; + consensus.nSuperblockStartHash = uint256S("0000008d283128ffecb10803a3317348908fd23bc9dceaba26f6d520a387de28"); consensus.nSuperblockCycle = 20545; // 675 (Blocks per day) x 365.25 (Days per Year) / 12 = 20545 + consensus.nGovernanceMinQuorum = 10; consensus.nGovernanceFilterElements = 20000; + consensus.nDynodeMinimumConfirmations = 15; + consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; + consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 30 * 64; // Dynamic: 1920 seconds consensus.nPowTargetSpacing = DEFAULT_AVERAGE_POW_BLOCK_TIME; @@ -140,6 +149,7 @@ class CMainParams : public CChainParams { consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 321; // 95% of nMinerConfirmationWindow consensus.nMinerConfirmationWindow = 30; // nPowTargetTimespan / nPowTargetSpacing + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 @@ -149,6 +159,12 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1513591800; // Dec 18th 2017 10:10:00 consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1545134400; // Dec 18th 2018 12:00:00 + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000178cc646f309d"); // 190513 + + // By default assume that the signatures in ancestors of this block are valid. + consensus.defaultAssumeValid = uint256S("0x000000007c0622b0ace74790759127570d8396f38cab674c959ed4a5c315fb6d"); // 190513 + /** * The message start string is designed to be unlikely to occur in normal data. * The characters are rarely used upper ASCII, not valid as UTF-8, and produce @@ -160,7 +176,6 @@ class CMainParams : public CChainParams { pchMessageStart[3] = 0x80; vAlertPubKey = ParseHex("04bf1391ff0c61a5d9a02cd2e997b707ced89bb48514e26d89f2464c98295ffef3f587263c94e6024d4e455802ad73e1e9694f3e482ff6e074736cb2327f9cd3e7"); nDefaultPort = DEFAULT_P2P_PORT; - nMaxTipAge = 24 * 60 * 64; nPruneAfterHeight = 20545; startNewChain = false; @@ -174,10 +189,7 @@ class CMainParams : public CChainParams { assert(genesis.hashMerkleRoot == uint256S("0xfa0e753db5a853ebbc52594eb62fa8219155547b426fba8789fa96dbf07e6ed5")); } - vSeeds.push_back(CDNSSeedData("dnsseeder.io", "dyn2.dnsseeder.io")); - vSeeds.push_back(CDNSSeedData("dnsseeder.com", "dyn2.dnsseeder.com")); - vSeeds.push_back(CDNSSeedData("dnsseeder.host", "dyn2.dnsseeder.host")); - vSeeds.push_back(CDNSSeedData("dnsseeder.net", "dyn2.dnsseeder.net")); + vSeeds.push_back(CDNSSeedData("quasar.servies", "dnsseeder-dyn.quasar.services")); // Dynamic addresses start with 'D' base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,30); @@ -197,12 +209,15 @@ class CMainParams : public CChainParams { fMiningRequiresPeers = true; fDefaultConsistencyChecks = false; fRequireStandard = true; + fRequireRoutableExternalIP = true; fMineBlocksOnDemand = false; fAllowMultipleAddressesFromGroup = false; + fAllowMultiplePorts = false; nPoolMaxTransactions = 3; nFulfilledRequestExpireTime = 60 * 60; // fulfilled requests expire in 1 hour - strSporkPubKey = "04bf1391ff0c61a5d9a02cd2e997b707ced89bb48514e26d89f2464c98295ffef3f587263c94e6024d4e455802ad73e1e9694f3e482ff6e074736cb2327f9cd3e7"; + + strSporkAddress = "DDDax6fjzoCqHj9nwTgNdAQsucFBJUJ3Jk"; checkpointData = (CCheckpointData) { boost::assign::map_list_of @@ -213,11 +228,14 @@ class CMainParams : public CChainParams { ( 10000, uint256S("0x000000043989ffa9fc3fb37663e32b81f8da490d9d38808cd8455ca5996415f4")) ( 40000, uint256S("0x0000000385a212537b0048c47d5cbce3fc6a12f16d8b9afcd13c129c9abc768f")) ( 80000, uint256S("0x0000000094c0ca21a4a4b8ad76ab76a3751759627d3be47d885389672818d5a8")) - ( 100000, uint256S("0x000000006403817b5efdb846e0dacf5959dbb65439531bf8ab0aa0c7c41837f1")), - 1513619300, // * UNIX timestamp of last checkpoint block - 0, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - 2000 // * estimated number of transactions per day after checkpoint + ( 100000, uint256S("0x000000006403817b5efdb846e0dacf5959dbb65439531bf8ab0aa0c7c41837f1")) + }; + + chainTxData = ChainTxData{ + 0, // * UNIX timestamp of last known number of transactions + 0, // * total number of transactions between genesis and that timestamp + // (the tx=... number in the SetBestChain debug.log lines) + 0.1 // * estimated number of transactions per second after that timestamp }; } }; @@ -230,22 +248,32 @@ class CTestNetParams : public CChainParams { public: CTestNetParams() { strNetworkID = "test"; + consensus.nRewardsStart = 0; // Rewards starts on block 0 consensus.nDynodePaymentsStartBlock = 0; consensus.nMinCountDynodesPaymentStart = 1; // Dynode Payments begin once 1 Dynode exists or more. + + consensus.nInstantSendConfirmationsRequired = 11; consensus.nInstantSendKeepLock = 24; + consensus.nBudgetPaymentsStartBlock = 200; consensus.nBudgetPaymentsCycleBlocks = 50; consensus.nBudgetPaymentsWindowBlocks = 10; consensus.nBudgetProposalEstablishingTime = 60 * 20; + consensus.nSuperblockStartBlock = 0; + consensus.nSuperblockStartHash = uint256(); // do not check this on testnet consensus.nSuperblockCycle = 24; // Superblocks can be issued hourly on testnet + consensus.nGovernanceMinQuorum = 1; consensus.nGovernanceFilterElements = 500; + consensus.nDynodeMinimumConfirmations = 1; + consensus.nMajorityEnforceBlockUpgrade = 510; consensus.nMajorityRejectBlockOutdated = 750; consensus.nMajorityWindow = 1000; + consensus.powLimit = uint256S("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowAveragingWindow = 5; consensus.nPowMaxAdjustUp = 32; @@ -253,12 +281,12 @@ class CTestNetParams : public CChainParams { consensus.nPowTargetTimespan = 30 * 64; // Dynamic: 1920 seconds consensus.nPowTargetSpacing = DEFAULT_AVERAGE_POW_BLOCK_TIME; consensus.nUpdateDiffAlgoHeight = 10; // Dynamic: Algorithm fork block - assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 254; // 75% of nMinerConfirmationWindow consensus.nMinerConfirmationWindow = 30; // nPowTargetTimespan / nPowTargetSpacing + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 @@ -268,6 +296,12 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1513591800; // Dec 18th 2017 10:10:00 consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1545134400; // Dec 18th 2018 12:00:00 + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000000e1e0da27"); // + + // By default assume that the signatures in ancestors of this block are valid. + consensus.defaultAssumeValid = uint256S("0x00000e993db635ffbc0449a42da04344c70bbfec5e5c242f43e1b961afa9d4a1"); // 8000 + pchMessageStart[0] = 0x2f; pchMessageStart[1] = 0x32; pchMessageStart[2] = 0x15; @@ -275,7 +309,6 @@ class CTestNetParams : public CChainParams { // To import alter key: importprivkey 6Jjb9DG1cr71VWiwxg97zVEyZUBhFzzGhqE7GY9DrbYYM6gVgxS vAlertPubKey = ParseHex("043d9e8440ea8fe66b0c2639f0a0931c9d7c41132ec9ee04cdf5d9e88ada2c2df52d93a0c1983958d3aea56df9fb3d1a61ca4eb6f72c27456fc313be80cdc70032"); nDefaultPort = DEFAULT_P2P_PORT + 100; - nMaxTipAge = 24 * 60 * 64; nPruneAfterHeight = 100; startNewChain = false; @@ -313,21 +346,26 @@ class CTestNetParams : public CChainParams { fMiningRequiresPeers = false; fDefaultConsistencyChecks = false; fRequireStandard = false; + fRequireRoutableExternalIP = true; fMineBlocksOnDemand = false; fAllowMultipleAddressesFromGroup = false; + fAllowMultiplePorts = false; nPoolMaxTransactions = 3; nFulfilledRequestExpireTime = 5 * 60; // fulfilled requests expire in 5 minutes // To import spork key: importprivkey 6Jjb9DG1cr71VWiwxg97zVEyZUBhFzzGhqE7GY9DrbYYM6gVgxS - strSporkPubKey = "043d9e8440ea8fe66b0c2639f0a0931c9d7c41132ec9ee04cdf5d9e88ada2c2df52d93a0c1983958d3aea56df9fb3d1a61ca4eb6f72c27456fc313be80cdc70032"; + strSporkAddress = "DGjj2YB4c988rpgVQbhkLnwthRDbmZF2ie"; // Must have this converted to an address "043d9e8440ea8fe66b0c2639f0a0931c9d7c41132ec9ee04cdf5d9e88ada2c2df52d93a0c1983958d3aea56df9fb3d1a61ca4eb6f72c27456fc313be80cdc70032"; checkpointData = (CCheckpointData) { boost::assign::map_list_of - ( 0, uint256S("0x00ff3a06390940bc3fffb7948cc6d0ede8fde544a5fa9eeeafbc4ac65d21f087")), - 1515641597, // * UNIX timestamp of last checkpoint block - 0, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - 1350 // * estimated number of transactions per day after checkpoint + ( 0, uint256S("0x00ff3a06390940bc3fffb7948cc6d0ede8fde544a5fa9eeeafbc4ac65d21f087")) + }; + + chainTxData = ChainTxData{ + 0, // * UNIX timestamp of last known number of transactions + 0, // * total number of transactions between genesis and that timestamp + // (the tx=... number in the SetBestChain debug.log lines) + 0.1 // * estimated number of transactions per second after that timestamp }; } }; @@ -343,19 +381,28 @@ class CRegTestParams : public CChainParams { consensus.nRewardsStart = 0; // Rewards starts on block 0 consensus.nDynodePaymentsStartBlock = 0; consensus.nMinCountDynodesPaymentStart = 1; // Dynode Payments begin once 1 Dynode exists or more. + + consensus.nInstantSendConfirmationsRequired = 11; consensus.nInstantSendKeepLock = 24; + consensus.nBudgetPaymentsStartBlock = 1000; consensus.nBudgetPaymentsCycleBlocks = 50; consensus.nBudgetPaymentsWindowBlocks = 10; consensus.nBudgetProposalEstablishingTime = 60 * 20; + consensus.nSuperblockStartBlock = 0; + consensus.nSuperblockStartHash = uint256(); // do not check this on regtest consensus.nSuperblockCycle = 10; + consensus.nGovernanceMinQuorum = 1; consensus.nGovernanceFilterElements = 100; + consensus.nDynodeMinimumConfirmations = 1; + consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; + consensus.powLimit = uint256S("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowAveragingWindow = 5; consensus.nPowMaxAdjustUp = 32; @@ -363,25 +410,31 @@ class CRegTestParams : public CChainParams { consensus.nPowTargetTimespan = 30 * 64; // Dynamic: 1920 seconds consensus.nPowTargetSpacing = DEFAULT_AVERAGE_POW_BLOCK_TIME; consensus.nUpdateDiffAlgoHeight = 10; // Dynamic: Algorithm fork block - assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; consensus.nRuleChangeActivationThreshold = 254; // 75% of nMinerConfirmationWindow consensus.nMinerConfirmationWindow = 30; // nPowTargetTimespan / nPowTargetSpacing + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL; + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S(""); // + + // By default assume that the signatures in ancestors of this block are valid. + consensus.defaultAssumeValid = uint256S(""); // + pchMessageStart[0] = 0x2f; pchMessageStart[1] = 0x32; pchMessageStart[2] = 0x15; pchMessageStart[3] = 0x3f; vAlertPubKey = ParseHex("04e8118b469667861157f3b2b28056ae92581ce61ce2db80d04a701f5ec5391b751e6136bafdcca7b8d0b564a5afce213e8069bdd1d17131f61d116b73dbf7e2d6"); - nMaxTipAge = 24 * 60 * 64; nDefaultPort = DEFAULT_P2P_PORT + 200; nPruneAfterHeight = 100; startNewChain = false; @@ -404,20 +457,27 @@ class CRegTestParams : public CChainParams { fMiningRequiresPeers = false; fDefaultConsistencyChecks = true; fRequireStandard = false; + fRequireRoutableExternalIP = true; fMineBlocksOnDemand = true; fAllowMultipleAddressesFromGroup = false; + fAllowMultiplePorts = false; nFulfilledRequestExpireTime = 5 * 60; // fulfilled requests expire in 5 minutes - strSporkPubKey = "04e8118b469667861157f3b2b28056ae92581ce61ce2db80d04a701f5ec5391b751e6136bafdcca7b8d0b564a5afce213e8069bdd1d17131f61d116b73dbf7e2d6"; - + + strSporkAddress = "DHfZ3yoTNjwbemKkDtBByNS3ztKXUNmDPq"; + checkpointData = (CCheckpointData) { boost::assign::map_list_of - ( 0, uint256S("0x000ab751d858e116043e741d097311f2382e600c219483cfda8f25c7f369cc2c")), - 1513619951, // * UNIX timestamp of last checkpoint block - 0, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - 500 // * estimated number of transactions per day after checkpoint + ( 0, uint256S("0x000ab751d858e116043e741d097311f2382e600c219483cfda8f25c7f369cc2c")) + }; + + chainTxData = ChainTxData{ + 0, // * UNIX timestamp of last known number of transactions + 0, // * total number of transactions between genesis and that timestamp + // (the tx=... number in the SetBestChain debug.log lines) + 0.1 // * estimated number of transactions per second after that timestamp }; + // Regtest Dynamic addresses start with 'y' base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,140); // Regtest Dynamic script addresses start with '8' or '9' @@ -431,6 +491,11 @@ class CRegTestParams : public CChainParams { // Regtest Dynamic BIP44 coin type is '1' (All coin's testnet default) nExtCoinType = 1; } + void UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) + { + consensus.vDeployments[d].nStartTime = nStartTime; + consensus.vDeployments[d].nTimeout = nTimeout; + } }; static CRegTestParams regTestParams; @@ -458,3 +523,8 @@ void SelectParams(const std::string& network) SelectBaseParams(network); pCurrentParams = &Params(network); } + +void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) +{ + regTestParams.UpdateBIP9Parameters(d, nStartTime, nTimeout); +} diff --git a/src/chainparams.h b/src/chainparams.h index 5697cd6e38..e0273ffa95 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -30,9 +30,12 @@ typedef std::map MapCheckpoints; struct CCheckpointData { MapCheckpoints mapCheckpoints; - int64_t nTimeLastCheckpoint; - int64_t nTransactionsLastCheckpoint; - double fTransactionsPerDay; +}; + +struct ChainTxData { + int64_t nTime; + int64_t nTxCount; + double dTxRate; }; /** @@ -67,12 +70,15 @@ class CChainParams bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } - int64_t MaxTipAge() const { return nMaxTipAge; } + /** Require addresses specified with "-externalip" parameter to be routable */ + bool RequireRoutableExternalIP() const { return fRequireRoutableExternalIP; } uint64_t PruneAfterHeight() const { return nPruneAfterHeight; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } /** Allow multiple addresses to be selected from the same network group (e.g. 192.168.x.x) */ bool AllowMultipleAddressesFromGroup() const { return fAllowMultipleAddressesFromGroup; } + /** Allow nodes with the same address and multiple ports */ + bool AllowMultiplePorts() const { return fAllowMultiplePorts; } /** Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } const std::vector& DNSSeeds() const { return vSeeds; } @@ -80,9 +86,10 @@ class CChainParams int ExtCoinType() const { return nExtCoinType; } const std::vector& FixedSeeds() const { return vFixedSeeds; } const CCheckpointData& Checkpoints() const { return checkpointData; } + const ChainTxData& TxData() const { return chainTxData; } int PoolMaxTransactions() const { return nPoolMaxTransactions; } int FulfilledRequestExpireTime() const { return nFulfilledRequestExpireTime; } - std::string SporkPubKey() const { return strSporkPubKey; } + const std::string& SporkAddress() const { return strSporkAddress; } protected: CChainParams() {} @@ -91,7 +98,6 @@ class CChainParams //! Raw pub key bytes for the broadcast alert signing key. std::vector vAlertPubKey; int nDefaultPort; - long nMaxTipAge; uint64_t nPruneAfterHeight; std::vector vSeeds; std::vector base58Prefixes[MAX_BASE58_TYPES]; @@ -102,13 +108,16 @@ class CChainParams bool fMiningRequiresPeers; bool fDefaultConsistencyChecks; bool fRequireStandard; + bool fRequireRoutableExternalIP; bool fMineBlocksOnDemand; bool fAllowMultipleAddressesFromGroup; + bool fAllowMultiplePorts; bool startNewChain; CCheckpointData checkpointData; + ChainTxData chainTxData; int nPoolMaxTransactions; int nFulfilledRequestExpireTime; - std::string strSporkPubKey; + std::string strSporkAddress; std::string strDynodePaymentsPubKey; }; @@ -129,4 +138,9 @@ CChainParams& Params(const std::string& chain); */ void SelectParams(const std::string& chain); +/** + * Allows modifying the BIP9 regtest parameters. + */ +void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout); + #endif // DYNAMIC_CHAINPARAMS_H diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 16415e16af..f7d06d2af4 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -18,56 +18,6 @@ namespace Checkpoints { - /** - * How many times slower we expect checking transactions after the last - * checkpoint to be (from checking signatures, which is skipped up to the - * last checkpoint). This number is a compromise, as it can't be accurate - * for every system. When reindexing from a fast disk with a slow CPU, it - * can be up to 20, while when downloading from a slow network with a - * fast multicore CPU, it won't be much higher than 1. - */ - static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; - - //! Guess how far we are in the verification process at the given block index - double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) { - if (pindex==NULL) - return 0.0; - - int64_t nNow = time(NULL); - - double fSigcheckVerificationFactor = fSigchecks ? SIGCHECK_VERIFICATION_FACTOR : 1.0; - double fWorkBefore = 0.0; // Amount of work done before pindex - double fWorkAfter = 0.0; // Amount of work left after pindex (estimated) - // Work is defined as: 1.0 per transaction before the last checkpoint, and - // fSigcheckVerificationFactor per transaction after. - - if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) { - double nCheapBefore = pindex->nChainTx; - double nCheapAfter = data.nTransactionsLastCheckpoint - pindex->nChainTx; - double nExpensiveAfter = (nNow - data.nTimeLastCheckpoint)/86400.0*data.fTransactionsPerDay; - fWorkBefore = nCheapBefore; - fWorkAfter = nCheapAfter + nExpensiveAfter*fSigcheckVerificationFactor; - } else { - double nCheapBefore = data.nTransactionsLastCheckpoint; - double nExpensiveBefore = pindex->nChainTx - data.nTransactionsLastCheckpoint; - double nExpensiveAfter = (nNow - pindex->GetBlockTime())/86400.0*data.fTransactionsPerDay; - fWorkBefore = nCheapBefore + nExpensiveBefore*fSigcheckVerificationFactor; - fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor; - } - - return fWorkBefore / (fWorkBefore + fWorkAfter); - } - - int GetTotalBlocksEstimate(const CCheckpointData& data) - { - const MapCheckpoints& checkpoints = data.mapCheckpoints; - - if (checkpoints.empty()) - return 0; - - return checkpoints.rbegin()->first; - } - CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) { const MapCheckpoints& checkpoints = data.mapCheckpoints; @@ -82,4 +32,4 @@ namespace Checkpoints { return NULL; } -} // namespace Checkpoints +} // namespace Checkpoints \ No newline at end of file diff --git a/src/checkpoints.h b/src/checkpoints.h index abc3b69b25..832ae472bb 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -13,7 +13,6 @@ #include class CBlockIndex; - struct CCheckpointData; /** @@ -23,14 +22,9 @@ struct CCheckpointData; namespace Checkpoints { -//! Return conservative estimate of total number of blocks, 0 if unknown -int GetTotalBlocksEstimate(const CCheckpointData& data); - //! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint CBlockIndex* GetLastCheckpoint(const CCheckpointData& data); -double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex* pindex, bool fSigchecks = true); - } //namespace Checkpoints #endif // DYNAMIC_CHECKPOINTS_H diff --git a/src/checkqueue.h b/src/checkqueue.h index bb921261df..03f4469bc5 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -130,6 +130,9 @@ class CCheckQueue } public: + //! Mutex to ensure only one concurrent CCheckQueueControl + boost::mutex ControlMutex; + //! Create a new check queue CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {} @@ -180,16 +183,18 @@ template class CCheckQueueControl { private: - CCheckQueue* pqueue; + CCheckQueue * const pqueue; bool fDone; public: - CCheckQueueControl(CCheckQueue* pqueueIn) : pqueue(pqueueIn), fDone(false) + CCheckQueueControl() = delete; + CCheckQueueControl(const CCheckQueueControl&) = delete; + CCheckQueueControl& operator=(const CCheckQueueControl&) = delete; + explicit CCheckQueueControl(CCheckQueue * const pqueueIn) : pqueue(pqueueIn), fDone(false) { // passed queue is supposed to be unused, or NULL if (pqueue != NULL) { - bool isIdle = pqueue->IsIdle(); - assert(isIdle); + ENTER_CRITICAL_SECTION(pqueue->ControlMutex); } } @@ -212,6 +217,9 @@ class CCheckQueueControl { if (!fDone) Wait(); + if (pqueue != NULL) { + LEAVE_CRITICAL_SECTION(pqueue->ControlMutex); + } } }; diff --git a/src/coins.cpp b/src/coins.cpp index 8ce197e291..d2d868aa05 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -263,7 +263,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount return tx.ComputePriority(dResult); } -static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_SIZE / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h. +static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_SIZE / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h. const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid) { diff --git a/src/coins.h b/src/coins.h index 8b8f3d807c..e603779a8a 100644 --- a/src/coins.h +++ b/src/coins.h @@ -211,12 +211,14 @@ class CCoinsViewCache : public CCoinsViewBacked CCoinsViewCache(CCoinsView *baseIn); // Standard CCoinsView methods - bool GetCoin(const COutPoint &outpoint, Coin &coin) const; - bool HaveCoin(const COutPoint &outpoint) const; - uint256 GetBestBlock() const; + bool GetCoin(const COutPoint &outpoint, Coin &coin) const override; + bool HaveCoin(const COutPoint &outpoint) const override; + uint256 GetBestBlock() const override; void SetBestBlock(const uint256 &hashBlock); - bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); - + bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override; + CCoinsViewCursor* Cursor() const override { + throw std::logic_error("CCoinsViewCache cursor iteration not supported."); + } /** * Check if we have the given utxo already loaded in this cache. * The semantics are the same as HaveCoin(), but no calls to diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp index cdc7070158..e7c0531945 100644 --- a/src/consensus/merkle.cpp +++ b/src/consensus/merkle.cpp @@ -157,7 +157,7 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated) std::vector leaves; leaves.resize(block.vtx.size()); for (size_t s = 0; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s].GetHash(); + leaves[s] = block.vtx[s]->GetHash(); } return ComputeMerkleRoot(leaves, mutated); } @@ -167,7 +167,7 @@ std::vector BlockMerkleBranch(const CBlock& block, uint32_t position) std::vector leaves; leaves.resize(block.vtx.size()); for (size_t s = 0; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s].GetHash(); + leaves[s] = block.vtx[s]->GetHash(); } return ComputeMerkleBranch(leaves, position); } diff --git a/src/consensus/params.h b/src/consensus/params.h index 27e19d0cb1..1ebc2884f7 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -30,6 +30,10 @@ struct BIP9Deployment { int64_t nStartTime; /** Timeout/expiry MedianTime for the deployment attempt. */ int64_t nTimeout; + /** The number of past blocks (including the block under consideration) to be taken into account for locking in a fork. */ + int64_t nWindowSize; + /** A number of blocks, in the range of 1..nWindowSize, which must signal for a fork in order to lock it in. */ + int64_t nThreshold; }; /** @@ -40,12 +44,14 @@ struct Params { int nRewardsStart; int nDynodePaymentsStartBlock; int nMinCountDynodesPaymentStart; + int nInstantSendConfirmationsRequired; // in blocks int nInstantSendKeepLock; // in blocks int nBudgetPaymentsStartBlock; int nBudgetPaymentsCycleBlocks; int nBudgetPaymentsWindowBlocks; int nBudgetProposalEstablishingTime; // in seconds int nSuperblockStartBlock; + uint256 nSuperblockStartHash; int nSuperblockCycle; // in blocks int nGovernanceMinQuorum; // Min absolute vote count to trigger an action int nGovernanceFilterElements; @@ -54,6 +60,7 @@ struct Params { int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; int nMajorityWindow; + /** * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargetting period, * (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments. @@ -72,6 +79,8 @@ struct Params { int64_t nPowMaxAdjustUp; int64_t nPowMaxAdjustDown; int64_t nUpdateDiffAlgoHeight; + uint256 nMinimumChainWork; + uint256 defaultAssumeValid; int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; } int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; } diff --git a/src/core_io.h b/src/core_io.h index 048a5a01f6..e0473de2e9 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -14,13 +14,14 @@ class CBlock; class CScript; class CTransaction; +struct CMutableTransaction; class uint256; class UniValue; // core_read.cpp CScript ParseScript(const std::string& s); std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false); -bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); +bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx); bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); uint256 ParseHashUV(const UniValue& v, const std::string& strName); uint256 ParseHashStr(const std::string&, const std::string& strName); diff --git a/src/core_memusage.h b/src/core_memusage.h index 19636d7f11..3273323574 100644 --- a/src/core_memusage.h +++ b/src/core_memusage.h @@ -53,8 +53,8 @@ static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) { static inline size_t RecursiveDynamicUsage(const CBlock& block) { size_t mem = memusage::DynamicUsage(block.vtx); - for (std::vector::const_iterator it = block.vtx.begin(); it != block.vtx.end(); it++) { - mem += RecursiveDynamicUsage(*it); + for (const auto& tx : block.vtx) { + mem += memusage::DynamicUsage(tx) + RecursiveDynamicUsage(*tx); } return mem; } diff --git a/src/core_read.cpp b/src/core_read.cpp index 04192b1095..f6ae62fa39 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -92,7 +92,7 @@ CScript ParseScript(const std::string& s) return result; } -bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx) +bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx) { if (!IsHex(strHexTx)) return false; diff --git a/src/cuckoocache.h b/src/cuckoocache.h new file mode 100644 index 0000000000..ff47e9776b --- /dev/null +++ b/src/cuckoocache.h @@ -0,0 +1,457 @@ +// Copyright (c) 2016 Jeremy Rubin +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _BITCOIN_CUCKOOCACHE_H_ +#define _BITCOIN_CUCKOOCACHE_H_ + +#include +#include +#include +#include +#include +#include +#include + + +/** namespace CuckooCache provides high performance cache primitives + * + * Summary: + * + * 1) bit_packed_atomic_flags is bit-packed atomic flags for garbage collection + * + * 2) cache is a cache which is performant in memory usage and lookup speed. It + * is lockfree for erase operations. Elements are lazily erased on the next + * insert. + */ +namespace CuckooCache +{ +/** bit_packed_atomic_flags implements a container for garbage collection flags + * that is only thread unsafe on calls to setup. This class bit-packs collection + * flags for memory efficiency. + * + * All operations are std::memory_order_relaxed so external mechanisms must + * ensure that writes and reads are properly synchronized. + * + * On setup(n), all bits up to n are marked as collected. + * + * Under the hood, because it is an 8-bit type, it makes sense to use a multiple + * of 8 for setup, but it will be safe if that is not the case as well. + * + */ +class bit_packed_atomic_flags +{ + std::unique_ptr[]> mem; + +public: + /** No default constructor as there must be some size */ + bit_packed_atomic_flags() = delete; + + /** + * bit_packed_atomic_flags constructor creates memory to sufficiently + * keep track of garbage collection information for size entries. + * + * @param size the number of elements to allocate space for + * + * @post bit_set, bit_unset, and bit_is_set function properly forall x. x < + * size + * @post All calls to bit_is_set (without subsequent bit_unset) will return + * true. + */ + bit_packed_atomic_flags(uint32_t size) + { + // pad out the size if needed + size = (size + 7) / 8; + mem.reset(new std::atomic[size]); + for (uint32_t i = 0; i < size; ++i) + mem[i].store(0xFF); + }; + + /** setup marks all entries and ensures that bit_packed_atomic_flags can store + * at least size entries + * + * @param b the number of elements to allocate space for + * @post bit_set, bit_unset, and bit_is_set function properly forall x. x < + * b + * @post All calls to bit_is_set (without subsequent bit_unset) will return + * true. + */ + inline void setup(uint32_t b) + { + bit_packed_atomic_flags d(b); + std::swap(mem, d.mem); + } + + /** bit_set sets an entry as discardable. + * + * @param s the index of the entry to bit_set. + * @post immediately subsequent call (assuming proper external memory + * ordering) to bit_is_set(s) == true. + * + */ + inline void bit_set(uint32_t s) + { + mem[s >> 3].fetch_or(1 << (s & 7), std::memory_order_relaxed); + } + + /** bit_unset marks an entry as something that should not be overwritten + * + * @param s the index of the entry to bit_unset. + * @post immediately subsequent call (assuming proper external memory + * ordering) to bit_is_set(s) == false. + */ + inline void bit_unset(uint32_t s) + { + mem[s >> 3].fetch_and(~(1 << (s & 7)), std::memory_order_relaxed); + } + + /** bit_is_set queries the table for discardability at s + * + * @param s the index of the entry to read. + * @returns if the bit at index s was set. + * */ + inline bool bit_is_set(uint32_t s) const + { + return (1 << (s & 7)) & mem[s >> 3].load(std::memory_order_relaxed); + } +}; + +/** cache implements a cache with properties similar to a cuckoo-set + * + * The cache is able to hold up to (~(uint32_t)0) - 1 elements. + * + * Read Operations: + * - contains(*, false) + * + * Read+Erase Operations: + * - contains(*, true) + * + * Erase Operations: + * - allow_erase() + * + * Write Operations: + * - setup() + * - setup_bytes() + * - insert() + * - please_keep() + * + * Synchronization Free Operations: + * - invalid() + * - compute_hashes() + * + * User Must Guarantee: + * + * 1) Write Requires synchronized access (e.g., a lock) + * 2) Read Requires no concurrent Write, synchronized with the last insert. + * 3) Erase requires no concurrent Write, synchronized with last insert. + * 4) An Erase caller must release all memory before allowing a new Writer. + * + * + * Note on function names: + * - The name "allow_erase" is used because the real discard happens later. + * - The name "please_keep" is used because elements may be erased anyways on insert. + * + * @tparam Element should be a movable and copyable type + * @tparam Hash should be a function/callable which takes a template parameter + * hash_select and an Element and extracts a hash from it. Should return + * high-entropy hashes for `Hash h; h<0>(e) ... h<7>(e)`. + */ +template +class cache +{ +private: + /** table stores all the elements */ + std::vector table; + + /** size stores the total available slots in the hash table */ + uint32_t size; + + /** The bit_packed_atomic_flags array is marked mutable because we want + * garbage collection to be allowed to occur from const methods */ + mutable bit_packed_atomic_flags collection_flags; + + /** epoch_flags tracks how recently an element was inserted into + * the cache. true denotes recent, false denotes not-recent. See insert() + * method for full semantics. + */ + mutable std::vector epoch_flags; + + /** epoch_heuristic_counter is used to determine when a epoch might be aged + * & an expensive scan should be done. epoch_heuristic_counter is + * decremented on insert and reset to the new number of inserts which would + * cause the epoch to reach epoch_size when it reaches zero. + */ + uint32_t epoch_heuristic_counter; + + /** epoch_size is set to be the number of elements supposed to be in a + * epoch. When the number of non-erased elements in a epoch + * exceeds epoch_size, a new epoch should be started and all + * current entries demoted. epoch_size is set to be 45% of size because + * we want to keep load around 90%, and we support 3 epochs at once -- + * one "dead" which has been erased, one "dying" which has been marked to be + * erased next, and one "living" which new inserts add to. + */ + uint32_t epoch_size; + + /** hash_mask should be set to appropriately mask out a hash such that every + * masked hash is [0,size), eg, if floor(log2(size)) == 20, then hash_mask + * should be (1<<20)-1 + */ + uint32_t hash_mask; + + /** depth_limit determines how many elements insert should try to replace. + * Should be set to log2(n)*/ + uint8_t depth_limit; + + /** hash_function is a const instance of the hash function. It cannot be + * static or initialized at call time as it may have internal state (such as + * a nonce). + * */ + const Hash hash_function; + + /** compute_hashes is convenience for not having to write out this + * expression everywhere we use the hash values of an Element. + * + * @param e the element whose hashes will be returned + * @returns std::array of deterministic hashes derived from e + */ + inline std::array compute_hashes(const Element& e) const + { + return {{hash_function.template operator()<0>(e) & hash_mask, + hash_function.template operator()<1>(e) & hash_mask, + hash_function.template operator()<2>(e) & hash_mask, + hash_function.template operator()<3>(e) & hash_mask, + hash_function.template operator()<4>(e) & hash_mask, + hash_function.template operator()<5>(e) & hash_mask, + hash_function.template operator()<6>(e) & hash_mask, + hash_function.template operator()<7>(e) & hash_mask}}; + } + + /* end + * @returns a constexpr index that can never be inserted to */ + constexpr uint32_t invalid() const + { + return ~(uint32_t)0; + } + + /** allow_erase marks the element at index n as discardable. Threadsafe + * without any concurrent insert. + * @param n the index to allow erasure of + */ + inline void allow_erase(uint32_t n) const + { + collection_flags.bit_set(n); + } + + /** please_keep marks the element at index n as an entry that should be kept. + * Threadsafe without any concurrent insert. + * @param n the index to prioritize keeping + */ + inline void please_keep(uint32_t n) const + { + collection_flags.bit_unset(n); + } + + /** epoch_check handles the changing of epochs for elements stored in the + * cache. epoch_check should be run before every insert. + * + * First, epoch_check decrements and checks the cheap heuristic, and then does + * a more expensive scan if the cheap heuristic runs out. If the expensive + * scan succeeds, the epochs are aged and old elements are allow_erased. The + * cheap heuristic is reset to retrigger after the worst case growth of the + * current epoch's elements would exceed the epoch_size. + */ + void epoch_check() + { + if (epoch_heuristic_counter != 0) { + --epoch_heuristic_counter; + return; + } + // count the number of elements from the latest epoch which + // have not been erased. + uint32_t epoch_unused_count = 0; + for (uint32_t i = 0; i < size; ++i) + epoch_unused_count += epoch_flags[i] && + !collection_flags.bit_is_set(i); + // If there are more non-deleted entries in the current epoch than the + // epoch size, then allow_erase on all elements in the old epoch (marked + // false) and move all elements in the current epoch to the old epoch + // but do not call allow_erase on their indices. + if (epoch_unused_count >= epoch_size) { + for (uint32_t i = 0; i < size; ++i) + if (epoch_flags[i]) + epoch_flags[i] = false; + else + allow_erase(i); + epoch_heuristic_counter = epoch_size; + } else + // reset the epoch_heuristic_counter to next do a scan when worst + // case behavior (no intermittent erases) would exceed epoch size, + // with a reasonable minimum scan size. + // Ordinarily, we would have to sanity check std::min(epoch_size, + // epoch_unused_count), but we already know that `epoch_unused_count + // < epoch_size` in this branch + epoch_heuristic_counter = std::max(1u, std::max(epoch_size / 16, + epoch_size - epoch_unused_count)); + } + +public: + /** You must always construct a cache with some elements via a subsequent + * call to setup or setup_bytes, otherwise operations may segfault. + */ + cache() : table(), size(), collection_flags(0), epoch_flags(), + epoch_heuristic_counter(), epoch_size(), depth_limit(0), hash_function() + { + } + + /** setup initializes the container to store no more than new_size + * elements. setup rounds down to a power of two size. + * + * setup should only be called once. + * + * @param new_size the desired number of elements to store + * @returns the maximum number of elements storable + **/ + uint32_t setup(uint32_t new_size) + { + // depth_limit must be at least one otherwise errors can occur. + depth_limit = static_cast(std::log2(static_cast(std::max((uint32_t)2, new_size)))); + size = 1 << depth_limit; + hash_mask = size-1; + table.resize(size); + collection_flags.setup(size); + epoch_flags.resize(size); + // Set to 45% as described above + epoch_size = std::max((uint32_t)1, (45 * size) / 100); + // Initially set to wait for a whole epoch + epoch_heuristic_counter = epoch_size; + return size; + } + + /** setup_bytes is a convenience function which accounts for internal memory + * usage when deciding how many elements to store. It isn't perfect because + * it doesn't account for any overhead (struct size, MallocUsage, collection + * and epoch flags). This was done to simplify selecting a power of two + * size. In the expected use case, an extra two bits per entry should be + * negligible compared to the size of the elements. + * + * @param bytes the approximate number of bytes to use for this data + * structure. + * @returns the maximum number of elements storable (see setup() + * documentation for more detail) + */ + uint32_t setup_bytes(size_t bytes) + { + return setup(bytes/sizeof(Element)); + } + + /** insert loops at most depth_limit times trying to insert a hash + * at various locations in the table via a variant of the Cuckoo Algorithm + * with eight hash locations. + * + * It drops the last tried element if it runs out of depth before + * encountering an open slot. + * + * Thus + * + * insert(x); + * return contains(x, false); + * + * is not guaranteed to return true. + * + * @param e the element to insert + * @post one of the following: All previously inserted elements and e are + * now in the table, one previously inserted element is evicted from the + * table, the entry attempted to be inserted is evicted. + * + */ + inline void insert(Element e) + { + epoch_check(); + uint32_t last_loc = invalid(); + bool last_epoch = true; + std::array locs = compute_hashes(e); + // Make sure we have not already inserted this element + // If we have, make sure that it does not get deleted + for (uint32_t loc : locs) + if (table[loc] == e) { + please_keep(loc); + epoch_flags[loc] = last_epoch; + return; + } + for (uint8_t depth = 0; depth < depth_limit; ++depth) { + // First try to insert to an empty slot, if one exists + for (uint32_t loc : locs) { + if (!collection_flags.bit_is_set(loc)) + continue; + table[loc] = std::move(e); + please_keep(loc); + epoch_flags[loc] = last_epoch; + return; + } + /** Swap with the element at the location that was + * not the last one looked at. Example: + * + * 1) On first iteration, last_loc == invalid(), find returns last, so + * last_loc defaults to locs[0]. + * 2) On further iterations, where last_loc == locs[k], last_loc will + * go to locs[k+1 % 8], i.e., next of the 8 indices wrapping around + * to 0 if needed. + * + * This prevents moving the element we just put in. + * + * The swap is not a move -- we must switch onto the evicted element + * for the next iteration. + */ + last_loc = locs[(1 + (std::find(locs.begin(), locs.end(), last_loc) - locs.begin())) & 7]; + std::swap(table[last_loc], e); + // Can't std::swap a std::vector::reference and a bool&. + bool epoch = last_epoch; + last_epoch = epoch_flags[last_loc]; + epoch_flags[last_loc] = epoch; + + // Recompute the locs -- unfortunately happens one too many times! + locs = compute_hashes(e); + } + } + + /* contains iterates through the hash locations for a given element + * and checks to see if it is present. + * + * contains does not check garbage collected state (in other words, + * garbage is only collected when the space is needed), so: + * + * insert(x); + * if (contains(x, true)) + * return contains(x, false); + * else + * return true; + * + * executed on a single thread will always return true! + * + * This is a great property for re-org performance for example. + * + * contains returns a bool set true if the element was found. + * + * @param e the element to check + * @param erase + * + * @post if erase is true and the element is found, then the garbage collect + * flag is set + * @returns true if the element is found, false otherwise + */ + inline bool contains(const Element& e, const bool erase) const + { + std::array locs = compute_hashes(e); + for (uint32_t loc : locs) + if (table[loc] == e) { + if (erase) + allow_erase(loc); + return true; + } + return false; + } +}; +} // namespace CuckooCache + +#endif diff --git a/src/drafted/governance-types.cpp b/src/drafted/governance-types.cpp index 142e4fe9d5..fd893915a0 100644 --- a/src/drafted/governance-types.cpp +++ b/src/drafted/governance-types.cpp @@ -7,8 +7,8 @@ GovernanceObjectType GovernanceStringToType(std::string strType) { if(strType == "AllTypes") type = AllTypes; if(strType == "Error") type = Error; if(strType == "ValueOverride") type = ValueOverride; - if(strType == "DashNetwork") type = DashNetwork; - if(strType == "DashNetworkVariable") type = DashNetworkVariable; + if(strType == "DynamicNetwork") type = DynamicNetwork; + if(strType == "DynamicNetworkVariable") type = DynamicNetworkVariable; if(strType == "Category") type = Category; if(strType == "Group") type = Group; if(strType == "User") type = User; @@ -28,8 +28,8 @@ std::string GovernanceTypeToString(GovernanceObjectType type) { if(type == AllTypes) s = "AllTypes"; if(type == Error) s = "Error"; if(type == ValueOverride) s = "ValueOverride"; - if(type == DashNetwork) s = "DashNetwork"; - if(type == DashNetworkVariable) s = "DashNetworkVariable"; + if(type == DynamicNetwork) s = "DynamicNetwork"; + if(type == DynamicNetworkVariable) s = "DynamicNetworkVariable"; if(type == Category) s = "Category"; if(type == Group) s = "Group"; if(type == User) s = "User"; diff --git a/src/dynamic-cli.cpp b/src/dynamic-cli.cpp index bfe390cb49..33c7c27305 100644 --- a/src/dynamic-cli.cpp +++ b/src/dynamic-cli.cpp @@ -5,26 +5,31 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include "config/dynamic-config.h" +#endif + #include "chainparamsbase.h" #include "clientversion.h" #include "rpcclient.h" #include "rpcprotocol.h" +#include "support/events.h" #include "util.h" #include "utilstrencodings.h" #include -#include - -#include -#include #include +#include #include #include +#include + static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; +static const bool DEFAULT_NAMED=false; static const int CONTINUE_EXECUTION=-1; std::string HelpMessageCli() @@ -35,6 +40,7 @@ std::string HelpMessageCli() strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), DYNAMIC_CONF_FILENAME)); strUsage += HelpMessageOpt("-datadir=", _("Specify data directory")); AppendParamsHelpMessages(strUsage); + strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED)); strUsage += HelpMessageOpt("-rpcconnect=", strprintf(_("Send commands to node running on (default: %s)"), DEFAULT_RPCCONNECT)); strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Connect to JSON-RPC on (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start")); @@ -194,24 +200,19 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params) std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT); int port = GetArg("-rpcport", BaseParams().RPCPort()); - // Create event base - struct event_base *base = event_base_new(); // TODO RAII - if (!base) - throw std::runtime_error("cannot create event_base"); + // Obtain event base + raii_event_base base = obtain_event_base(); // Synchronously look up hostname - struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII - if (evcon == NULL) - throw std::runtime_error("create connection failed"); - evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); + raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port); + evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); HTTPReply response; - struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII + raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response); if (req == NULL) throw std::runtime_error("create http request failed"); - #if LIBEVENT_VERSION_NUMBER >= 0x02010300 - evhttp_request_set_error_cb(req, http_error_cb); + evhttp_request_set_error_cb(req.get(), http_error_cb); #endif // Get credentials @@ -228,7 +229,7 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params) strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", ""); } - struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req); + struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get()); assert(output_headers); evhttp_add_header(output_headers, "Host", host.c_str()); evhttp_add_header(output_headers, "Connection", "close"); @@ -236,23 +237,20 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params) // Attach request data std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n"; - struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req); + struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get()); assert(output_buffer); evbuffer_add(output_buffer, strRequest.data(), strRequest.size()); - int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/"); + int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/"); + req.release(); // ownership moved to evcon in above call if (r != 0) { - evhttp_connection_free(evcon); - event_base_free(base); throw CConnectionFailed("send http request failed"); } - event_base_dispatch(base); - evhttp_connection_free(evcon); - event_base_free(base); + event_base_dispatch(base.get()); if (response.status == 0) - throw CConnectionFailed(strprintf("couldn't connect to server\n(make sure server is running and you are connecting to the correct RPC port: %d %s)", response.error, http_errorstring(response.error))); + throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error)); else if (response.status == HTTP_UNAUTHORIZED) throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) @@ -262,7 +260,7 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params) // Parse reply UniValue valReply(UniValue::VSTR); - if (!valReply.read(response.body)) + if (!valReply.read(response.body)) throw std::runtime_error("couldn't parse reply from server"); const UniValue& reply = valReply.get_obj(); if (reply.empty()) @@ -291,7 +289,14 @@ int CommandLineRPC(int argc, char *argv[]) if (args.size() < 1) throw std::runtime_error("too few parameters (need at least command)"); std::string strMethod = args[0]; - UniValue params = RPCConvertValues(strMethod, std::vector(args.begin()+1, args.end())); + args.erase(args.begin()); // Remove trailing method name from arguments vector + + UniValue params; + if(GetBoolArg("-named", DEFAULT_NAMED)) { + params = RPCConvertNamedValues(strMethod, args); + } else { + params = RPCConvertValues(strMethod, args); + } // Execute and handle connection failures with -rpcwait const bool fWait = GetBoolArg("-rpcwait", false); diff --git a/src/dynamic-tx.cpp b/src/dynamic-tx.cpp index a185aab811..f96c895e76 100644 --- a/src/dynamic-tx.cpp +++ b/src/dynamic-tx.cpp @@ -54,7 +54,7 @@ static int AppInitRawTx(int argc, char* argv[]) if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help")) { // First part of help message is specific to this utility - std::string strUsage = _("Dynamic dynamic-tx utility version") + " " + FormatFullVersion() + "\n\n" + + std::string strUsage = strprintf(_("%s dynamic-tx utility version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\n" + " dynamic-tx [options] [commands] " + _("Update hex-encoded dynamic transaction") + "\n" + " dynamic-tx [options] -create [commands] " + _("Create hex-encoded dynamic transaction") + "\n" + @@ -78,8 +78,13 @@ static int AppInitRawTx(int argc, char* argv[]) strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N")); strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N")); strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX")); + strUsage += HelpMessageOpt("outpubkey=VALUE:PUBKEY[:FLAGS]", _("Add pay-to-pubkey output to TX") + ". " + + _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.")); strUsage += HelpMessageOpt("outdata=[VALUE:]DATA", _("Add data-based output to TX")); - strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX")); + strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT[:FLAGS]", _("Add raw script output to TX") + ". " + + _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.")); + strUsage += HelpMessageOpt("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", _("Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS") + ". " + + _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.")); strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " + _("This command requires JSON registers:") + _("prevtxs=JSON object") + ", " + @@ -168,6 +173,14 @@ static void RegisterLoad(const std::string& strInput) RegisterSetJson(key, valStr); } +static CAmount ExtractAndValidateValue(const std::string& strValue) +{ + CAmount value; + if (!ParseMoney(strValue, value)) + throw std::runtime_error("invalid TX output value"); + return value; +} + static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal) { int64_t newVersion = atoi64(cmdVal); @@ -222,25 +235,21 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput) { - // separate VALUE:ADDRESS in string - size_t pos = strInput.find(':'); - if ((pos == std::string::npos) || - (pos == 0) || - (pos == (strInput.size() - 1))) - throw std::runtime_error("TX output missing separator"); + // Separate into VALUE:ADDRESS + std::vector vStrInputParts; + boost::split(vStrInputParts, strInput, boost::is_any_of(":")); - // extract and validate VALUE - std::string strValue = strInput.substr(0, pos); - CAmount value; - if (!ParseMoney(strValue, value)) - throw std::runtime_error("invalid TX output value"); + if (vStrInputParts.size() != 2) + throw std::runtime_error("TX output missing or too many separators"); + + // Extract and validate VALUE + CAmount value = ExtractAndValidateValue(vStrInputParts[0]); // extract and validate ADDRESS - std::string strAddr = strInput.substr(pos + 1, std::string::npos); + std::string strAddr = vStrInputParts[1]; CDynamicAddress addr(strAddr); if (!addr.IsValid()) throw std::runtime_error("invalid TX output address"); - // build standard output script via GetScriptForDestination() CScript scriptPubKey = GetScriptForDestination(addr.Get()); @@ -249,6 +258,105 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn tx.vout.push_back(txout); } +static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput) +{ + // Separate into VALUE:PUBKEY[:FLAGS] + std::vector vStrInputParts; + boost::split(vStrInputParts, strInput, boost::is_any_of(":")); + + if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3) + throw std::runtime_error("TX output missing or too many separators"); + + // Extract and validate VALUE + CAmount value = ExtractAndValidateValue(vStrInputParts[0]); + + // Extract and validate PUBKEY + CPubKey pubkey(ParseHex(vStrInputParts[1])); + if (!pubkey.IsFullyValid()) + throw std::runtime_error("invalid TX output pubkey"); + CScript scriptPubKey = GetScriptForRawPubKey(pubkey); + CDynamicAddress addr(scriptPubKey); + + // Extract and validate FLAGS + bool bScriptHash = false; + if (vStrInputParts.size() == 3) { + std::string flags = vStrInputParts[2]; + bScriptHash = (flags.find("S") != std::string::npos); + } + + if (bScriptHash) { + // Get the address for the redeem script, then call + // GetScriptForDestination() to construct a P2SH scriptPubKey. + CDynamicAddress redeemScriptAddr(scriptPubKey); + scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get()); + } + + // construct TxOut, append to transaction output list + CTxOut txout(value, scriptPubKey); + tx.vout.push_back(txout); +} + +static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput) +{ + // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS] + std::vector vStrInputParts; + boost::split(vStrInputParts, strInput, boost::is_any_of(":")); + + // Check that there are enough parameters + if (vStrInputParts.size()<3) + throw std::runtime_error("Not enough multisig parameters"); + + // Extract and validate VALUE + CAmount value = ExtractAndValidateValue(vStrInputParts[0]); + + // Extract REQUIRED + uint32_t required = stoul(vStrInputParts[1]); + + // Extract NUMKEYS + uint32_t numkeys = stoul(vStrInputParts[2]); + + // Validate there are the correct number of pubkeys + if (vStrInputParts.size() < numkeys + 3) + throw std::runtime_error("incorrect number of multisig pubkeys"); + + if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required) + throw std::runtime_error("multisig parameter mismatch. Required " \ + + std::to_string(required) + " of " + std::to_string(numkeys) + "signatures."); + + // extract and validate PUBKEYs + std::vector pubkeys; + for(int pos = 1; pos <= int(numkeys); pos++) { + CPubKey pubkey(ParseHex(vStrInputParts[pos + 2])); + if (!pubkey.IsFullyValid()) + throw std::runtime_error("invalid TX output pubkey"); + pubkeys.push_back(pubkey); + } + + // Extract FLAGS + bool bScriptHash = false; + if (vStrInputParts.size() == numkeys + 4) { + std::string flags = vStrInputParts.back(); + bScriptHash = (flags.find("S") != std::string::npos); + } + else if (vStrInputParts.size() > numkeys + 4) { + // Validate that there were no more parameters passed + throw std::runtime_error("Too many parameters"); + } + + CScript scriptPubKey = GetScriptForMultisig(required, pubkeys); + + if (bScriptHash) { + // Get the address for the redeem script, then call + // GetScriptForDestination() to construct a P2SH scriptPubKey. + CDynamicAddress addr(scriptPubKey); + scriptPubKey = GetScriptForDestination(addr.Get()); + } + + // construct TxOut, append to transaction output list + CTxOut txout(value, scriptPubKey); + tx.vout.push_back(txout); +} + static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput) { CAmount value = 0; @@ -260,10 +368,8 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn throw std::runtime_error("TX output value not specified"); if (pos != std::string::npos) { - // extract and validate VALUE - std::string strValue = strInput.substr(0, pos); - if (!ParseMoney(strValue, value)) - throw std::runtime_error("invalid TX output value"); + // Extract and validate VALUE + value = ExtractAndValidateValue(strInput.substr(0, pos)); } // extract and validate DATA @@ -280,27 +386,37 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput) { - // separate VALUE:SCRIPT in string - size_t pos = strInput.find(':'); - if ((pos == std::string::npos) || - (pos == 0)) + // separate VALUE:SCRIPT[:FLAGS] + std::vector vStrInputParts; + boost::split(vStrInputParts, strInput, boost::is_any_of(":")); + if (vStrInputParts.size() < 2) throw std::runtime_error("TX output missing separator"); - // extract and validate VALUE - std::string strValue = strInput.substr(0, pos); - CAmount value; - if (!ParseMoney(strValue, value)) - throw std::runtime_error("invalid TX output value"); + // Extract and validate VALUE + CAmount value = ExtractAndValidateValue(vStrInputParts[0]); // extract and validate script - std::string strScript = strInput.substr(pos + 1, std::string::npos); - CScript scriptPubKey = ParseScript(strScript); // throws on err + std::string strScript = vStrInputParts[1]; + CScript scriptPubKey = ParseScript(strScript); + + // Extract FLAGS + bool bScriptHash = false; + if (vStrInputParts.size() == 3) { + std::string flags = vStrInputParts.back(); + bScriptHash = (flags.find("S") != std::string::npos); + } + + if (bScriptHash) { + CDynamicAddress addr(scriptPubKey); + scriptPubKey = GetScriptForDestination(addr.Get()); + } // construct TxOut, append to transaction output list CTxOut txout(value, scriptPubKey); tx.vout.push_back(txout); } + static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx) { // parse requested deletion index @@ -354,6 +470,22 @@ static bool findSighashFlags(int& flags, const std::string& flagStr) return false; } +uint256 ParseHashUO(std::map& o, std::string strKey) +{ + if (!o.count(strKey)) + return uint256(); + return ParseHashUV(o[strKey], strKey); +} + +std::vector ParseHexUO(std::map& o, std::string strKey) +{ + if (!o.count(strKey)) { + std::vector emptyVec; + return emptyVec; + } + return ParseHexUV(o[strKey], strKey); +} + static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) { int nHashType = SIGHASH_ALL; @@ -507,10 +639,14 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command, MutateTxDelOutput(tx, commandVal); else if (command == "outaddr") MutateTxAddOutAddr(tx, commandVal); - else if (command == "outdata") - MutateTxAddOutData(tx, commandVal); + else if (command == "outpubkey") + MutateTxAddOutPubKey(tx, commandVal); + else if (command == "outmultisig") + MutateTxAddOutMultiSig(tx, commandVal); else if (command == "outscript") MutateTxAddOutScript(tx, commandVal); + else if (command == "outdata") + MutateTxAddOutData(tx, commandVal); else if (command == "sign") { if (!ecc) { ecc.reset(new Secp256k1Init()); } @@ -592,7 +728,7 @@ static int CommandLineRawTx(int argc, char* argv[]) argv++; } - CTransaction txDecodeTmp; + CMutableTransaction tx; int startArg; if (!fCreateBlank) { @@ -605,15 +741,13 @@ static int CommandLineRawTx(int argc, char* argv[]) if (strHexTx == "-") // "-" implies standard input strHexTx = readStdin(); - if (!DecodeHexTx(txDecodeTmp, strHexTx)) + if (!DecodeHexTx(tx, strHexTx)) throw std::runtime_error("invalid transaction encoding"); startArg = 2; } else startArg = 1; - CMutableTransaction tx(txDecodeTmp); - for (int i = startArg; i < argc; i++) { std::string arg = argv[i]; std::string key, value; diff --git a/src/dynode-payments.cpp b/src/dynode-payments.cpp index ba964157b0..ce0953ec59 100644 --- a/src/dynode-payments.cpp +++ b/src/dynode-payments.cpp @@ -7,6 +7,7 @@ #include "activedynode.h" #include "chain.h" +#include "consensus/validation.h" #include "dynode-sync.h" #include "dynodeman.h" #include "policy/fees.h" @@ -14,6 +15,7 @@ #include "governance-classes.h" #include "messagesigner.h" #include "netfulfilledman.h" +#include "netmessagemaker.h" #include "spork.h" #include "util.h" #include "utilmoneystr.h" @@ -38,12 +40,12 @@ CCriticalSection cs_mapDynodePaymentVotes; * - When non-superblocks are detected, the normal schedule should be maintained */ -bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward,std::string &strErrorRet) +bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward, std::string &strErrorRet) { strErrorRet = ""; - bool isBlockRewardValueMet = (block.vtx[0].GetValueOut() <= blockReward); - if(fDebug) LogPrintf("block.vtx[0].GetValueOut() %lld <= blockReward %lld\n", block.vtx[0].GetValueOut(), blockReward); + bool isBlockRewardValueMet = (block.vtx[0]->GetValueOut() <= blockReward); + if(fDebug) LogPrintf("block.vtx[0].GetValueOut() %lld <= blockReward %lld\n", block.vtx[0]->GetValueOut(), blockReward); // we are still using budgets, but we have no data about them anymore, // all we know is predefined budget cycle and window @@ -57,7 +59,7 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar LogPrint("gobject", "IsBlockValueValid -- Client synced but budget spork is disabled, checking block value against block reward\n"); if(!isBlockRewardValueMet) { strErrorRet = strprintf("coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, budgets are disabled", - nBlockHeight, block.vtx[0].GetValueOut(), blockReward); + nBlockHeight, block.vtx[0]->GetValueOut(), blockReward); } return isBlockRewardValueMet; } @@ -68,7 +70,7 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar // LogPrint("gobject", "IsBlockValueValid -- Block is not in budget cycle window, checking block value against block reward\n"); if(!isBlockRewardValueMet) { strErrorRet = strprintf("coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, block is not in budget cycle window", - nBlockHeight, block.vtx[0].GetValueOut(), blockReward); + nBlockHeight, block.vtx[0]->GetValueOut(), blockReward); } return isBlockRewardValueMet; } @@ -76,9 +78,9 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar // superblocks started CAmount nSuperblockMaxValue = blockReward + CSuperblock::GetPaymentsLimit(nBlockHeight); - bool isSuperblockMaxValueMet = (block.vtx[0].GetValueOut() <= nSuperblockMaxValue); + bool isSuperblockMaxValueMet = (block.vtx[0]->GetValueOut() <= nSuperblockMaxValue); - LogPrint("gobject", "block.vtx[0].GetValueOut() %lld <= nSuperblockMaxValue %lld\n", block.vtx[0].GetValueOut(), nSuperblockMaxValue); + LogPrint("gobject", "block.vtx[0].GetValueOut() %lld <= nSuperblockMaxValue %lld\n", block.vtx[0]->GetValueOut(), nSuperblockMaxValue); if(!dynodeSync.IsSynced()) { // not enough data but at least it must NOT exceed superblock max value @@ -86,13 +88,13 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar if(fDebug) LogPrintf("IsBlockPayeeValid -- WARNING: Client not synced, checking superblock max bounds only\n"); if(!isSuperblockMaxValueMet) { strErrorRet = strprintf("coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded superblock max value", - nBlockHeight, block.vtx[0].GetValueOut(), nSuperblockMaxValue); + nBlockHeight, block.vtx[0]->GetValueOut(), nSuperblockMaxValue); } return isSuperblockMaxValueMet; } if(!isBlockRewardValueMet) { strErrorRet = strprintf("coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, only regular blocks are allowed at this height", - nBlockHeight, block.vtx[0].GetValueOut(), blockReward); + nBlockHeight, block.vtx[0]->GetValueOut(), blockReward); } // it MUST be a regular block otherwise return isBlockRewardValueMet; @@ -101,22 +103,15 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar // we are synced, let's try to check as much data as we can if(sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED)) { - // ONLY CHECK SUPERBLOCKS WHEN INITIALLY SYNCED AND CHECKING NEW BLOCK - { - // UP TO ONE HOUR OLD, OTHERWISE LONGEST CHAIN - if(block.nTime + 60*60 < GetTime()) - return true; - } - if(CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) { - if(CSuperblockManager::IsValid(block.vtx[0], nBlockHeight, blockReward)) { - LogPrint("gobject", "IsBlockValueValid -- Valid superblock at height %d: %s", nBlockHeight, block.vtx[0].ToString()); + if(CSuperblockManager::IsValid(*block.vtx[0], nBlockHeight, blockReward)) { + LogPrint("gobject", "IsBlockValueValid -- Valid superblock at height %d: %s", nBlockHeight, block.vtx[0]->ToString()); // all checks are done in CSuperblock::IsValid, nothing to do here return true; } // triggered but invalid? that's weird - LogPrintf("IsBlockValueValid -- ERROR: Invalid superblock detected at height %d: %s", nBlockHeight, block.vtx[0].ToString()); + LogPrintf("IsBlockValueValid -- ERROR: Invalid superblock detected at height %d: %s", nBlockHeight, block.vtx[0]->ToString()); // should NOT allow invalid superblocks, when superblocks are enabled strErrorRet = strprintf("invalid superblock detected at height %d", nBlockHeight); return false; @@ -124,14 +119,14 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar LogPrint("gobject", "IsBlockValueValid -- No triggered superblock detected at height %d\n", nBlockHeight); if(!isBlockRewardValueMet) { strErrorRet = strprintf("coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, no triggered superblock detected", - nBlockHeight, block.vtx[0].GetValueOut(), blockReward); + nBlockHeight, block.vtx[0]->GetValueOut(), blockReward); } } else { // should NOT allow superblocks at all, when superblocks are disabled LogPrint("gobject", "IsBlockValueValid -- Superblocks are disabled, no superblocks allowed\n"); if(!isBlockRewardValueMet) { strErrorRet = strprintf("coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, superblocks are disabled", - nBlockHeight, block.vtx[0].GetValueOut(), blockReward); + nBlockHeight, block.vtx[0]->GetValueOut(), blockReward); } } @@ -148,43 +143,19 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc } // we are still using budgets, but we have no data about them anymore, - // we can only check Dynode payments + // we can only check dynode payments const Consensus::Params& consensusParams = Params().GetConsensus(); if(nBlockHeight < consensusParams.nSuperblockStartBlock) { - if(dnpayments.IsTransactionValid(txNew, nBlockHeight)) { - LogPrint("dnpayments", "IsBlockPayeeValid -- Valid Dynode payment at height %d: %s", nBlockHeight, txNew.ToString()); - return true; - } - - int nOffset = nBlockHeight % consensusParams.nBudgetPaymentsCycleBlocks; - if(nBlockHeight >= consensusParams.nBudgetPaymentsStartBlock && - nOffset < consensusParams.nBudgetPaymentsWindowBlocks) { - if(!sporkManager.IsSporkActive(SPORK_13_OLD_SUPERBLOCK_FLAG)) { - // no budget blocks should be accepted here, if SPORK_13_OLD_SUPERBLOCK_FLAG is disabled - LogPrint("gobject", "IsBlockPayeeValid -- ERROR: Client synced but budget spork is disabled and Dynode payment is invalid\n"); - return false; - } - // NOTE: this should never happen in real, SPORK_13_OLD_SUPERBLOCK_FLAG MUST be disabled when 12.1 starts to go live - LogPrint("gobject", "IsBlockPayeeValid -- WARNING: Probably valid budget block, have no data, accepting\n"); - // TODO: reprocess blocks to make sure they are legit? - return true; - } - - if(sporkManager.IsSporkActive(SPORK_8_DYNODE_PAYMENT_ENFORCEMENT)) { - LogPrintf("IsBlockPayeeValid -- ERROR: Invalid Dynode payment detected at height %d: %s", nBlockHeight, txNew.ToString()); - return false; - } - - LogPrintf("IsBlockPayeeValid -- WARNING: Dynode payment enforcement is disabled, accepting any payee\n"); + LogPrint("gobject", "IsBlockPayeeValid -- WARNING: Client synced but old budget system is disabled, accepting any payee\n"); return true; } // superblocks started // SEE IF THIS IS A VALID SUPERBLOCK - if(!sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED)) { + if(sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED)) { if(CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) { if(CSuperblockManager::IsValid(txNew, nBlockHeight, blockReward)) { LogPrint("gobject", "IsBlockPayeeValid -- Valid superblock at height %d: %s", nBlockHeight, txNew.ToString()); @@ -204,12 +175,12 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc // IF THIS ISN'T A SUPERBLOCK OR SUPERBLOCK IS INVALID, IT SHOULD PAY A DYNODE DIRECTLY if(dnpayments.IsTransactionValid(txNew, nBlockHeight)) { - LogPrint("dnpayments", "IsBlockPayeeValid -- Valid Dynode payment at height %d: %s", nBlockHeight, txNew.ToString()); + LogPrint("dnpayments", "IsBlockPayeeValid -- Valid dynode payment at height %d: %s", nBlockHeight, txNew.ToString()); return true; } if(sporkManager.IsSporkActive(SPORK_8_DYNODE_PAYMENT_ENFORCEMENT)) { - LogPrintf("IsBlockPayeeValid -- ERROR: Invalid Dynode payment detected at height %d: %s", nBlockHeight, txNew.ToString()); + LogPrintf("IsBlockPayeeValid -- ERROR: Invalid dynode payment detected at height %d: %s", nBlockHeight, txNew.ToString()); return false; } @@ -217,7 +188,7 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc return true; } -void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CTxOut& txoutDynodeRet, std::vector& voutSuperblockRet) +void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutDynodeRet, std::vector& voutSuperblockRet) { // only create superblocks if spork is enabled AND if superblock is actually triggered // (height should be validated inside) @@ -228,13 +199,11 @@ void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CTxOut& txo return; } - if (chainActive.Height() > Params().GetConsensus().nDynodePaymentsStartBlock) { - // FILL BLOCK PAYEE WITH DYNODE PAYMENT OTHERWISE - dnpayments.FillBlockPayee(txNew, nBlockHeight, txoutDynodeRet); - //LogPrint("dnpayments", "FillBlockPayments -- nBlockHeight %d txoutDynodeRet %s txNew %s", - // nBlockHeight, txoutDynodeRet.ToString(), txNew.ToString()); - return; - } + + // FILL BLOCK PAYEE WITH DYNODE PAYMENT OTHERWISE + dnpayments.FillBlockPayee(txNew, nBlockHeight, blockReward, txoutDynodeRet); + LogPrint("dnpayments", "FillBlockPayments -- nBlockHeight %d blockReward %lld txoutDynodeRet %s txNew %s", + nBlockHeight, blockReward, txoutDynodeRet.ToString(), txNew.ToString()); } std::string GetRequiredPaymentsString(int nBlockHeight) @@ -255,16 +224,20 @@ void CDynodePayments::Clear() mapDynodePaymentVotes.clear(); } -bool CDynodePayments::CanVote(COutPoint outDynode, int nBlockHeight) +bool CDynodePayments::UpdateLastVote(const CDynodePaymentVote& vote) { LOCK(cs_mapDynodePaymentVotes); - if (mapDynodesLastVote.count(outDynode) && mapDynodesLastVote[outDynode] == nBlockHeight) { - return false; + const auto it = mapDynodesLastVote.find(vote.dynodeOutpoint); + if (it != mapDynodesLastVote.end()) { + if (it->second == vote.nBlockHeight) + return false; + it->second = vote.nBlockHeight; + return true; } - //record this Dynode voted - mapDynodesLastVote[outDynode] = nBlockHeight; + //record this dynode voted + mapDynodesLastVote.emplace(vote.dynodeOutpoint, vote.nBlockHeight); return true; } @@ -274,87 +247,79 @@ bool CDynodePayments::CanVote(COutPoint outDynode, int nBlockHeight) * Fill Dynode ONLY payment block */ -void CDynodePayments::FillBlockPayee(CMutableTransaction& txNew, int nBlockHeight, CTxOut& txoutDynodeRet) +void CDynodePayments::FillBlockPayee(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutDynodeRet) const { - bool hasPayment = true; - CScript payee; + // make sure it's not filled yet + txoutDynodeRet = CTxOut(); - if (chainActive.Height() <= Params().GetConsensus().nDynodePaymentsStartBlock) { - LogPrintf("CDynodePayments::FillBlockPayee: No Dynode payments prior to block %u\n", Params().GetConsensus().nDynodePaymentsStartBlock); - hasPayment = false; - } + CScript payee; - int nDnCount = dnodeman.CountDynodes(); + bool hasPayment = true; - if(hasPayment && !dnpayments.GetBlockPayee(nBlockHeight, payee)){ + if(hasPayment && !dnpayments.GetBlockPayee(nBlockHeight, payee)){ + // no dynode detected... int nCount = 0; dynode_info_t dnInfo; - // Do not pay if no Dynodes detected if(!dnodeman.GetNextDynodeInQueueForPayment(nBlockHeight, true, nCount, dnInfo)) { hasPayment = false; LogPrintf("CDynodePayments::FillBlockPayee: Failed to detect Dynode to pay\n"); - } - else if (nDnCount < Params().GetConsensus().nMinCountDynodesPaymentStart) { - hasPayment = false; - LogPrintf("CreateNewBlock: Not enough Dynodes to begin payments\n"); - } - else { - // get winning Dynode payment script - payee = GetScriptForDestination(dnInfo.pubKeyCollateralAddress.GetID()); - LogPrintf("CDynodePayments::FillBlockPayee: Found Dynode to pay!\n"); + return; } - } - else { - LogPrintf("CDynodePayments::FillBlockPayee: Dynode payee found.\n"); //TODO (Amir): Remove logging. + // fill payee with locally calculated winner and hope for the best + payee = GetScriptForDestination(dnInfo.pubKeyCollateralAddress.GetID()); } - if(hasPayment){ - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) - return; - - // make sure it's not filled yet - txoutDynodeRet = CTxOut(); - CAmount dynodePayment = GetFluidDynodeReward(nBlockHeight); - - txoutDynodeRet = CTxOut(dynodePayment, payee); - txNew.vout.push_back(txoutDynodeRet); + // make sure it's not filled yet + txoutDynodeRet = CTxOut(); + CAmount dynodePayment = GetFluidDynodeReward(nBlockHeight); - CTxDestination address1; - ExtractDestination(payee, address1); - CDynamicAddress address2(address1); + // split reward between miner ... + txoutDynodeRet = CTxOut(dynodePayment, payee); + txNew.vout.push_back(txoutDynodeRet); + // ... and dynode + CTxDestination address1; + ExtractDestination(payee, address1); + CDynamicAddress address2(address1); - LogPrintf("CDynodePayments::FillBlockPayee -- Dynode payment %s to %s\n", FormatMoney(dynodePayment), address2.ToString()); - } + LogPrintf("CDynodePayments::FillBlockPayee -- Dynode payment %lld to %s\n", dynodePayment, address2.ToString()); } -int CDynodePayments::GetMinDynodePaymentsProto() { - return sporkManager.IsSporkActive(SPORK_10_DYNODE_PAY_UPDATED_NODES); +int CDynodePayments::GetMinDynodePaymentsProto() const { + return sporkManager.IsSporkActive(SPORK_10_DYNODE_PAY_UPDATED_NODES) + ? MIN_DYNODE_PAYMENT_PROTO_VERSION_2 + : MIN_DYNODE_PAYMENT_PROTO_VERSION_1; } -void CDynodePayments::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman) +void CDynodePayments::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) { if(fLiteMode) return; // disable all Dynamic specific functionality if (strCommand == NetMsgType::DYNODEPAYMENTSYNC) { //Dynode Payments Request Sync + if(pfrom->nVersion < GetMinDynodePaymentsProto()) { + LogPrint("dnpayments", "DYNODEPAYMENTSYNC -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", GetMinDynodePaymentsProto()))); + return; + } + // Ignore such requests until we are fully synced. // We could start processing this after Dynode list is synced // but this is a heavy one so it's better to finish sync first. if (!dynodeSync.IsSynced()) return; - int nCountNeeded; - vRecv >> nCountNeeded; - - int nDnCount = dnodeman.CountDynodes(); + // DEPRECATED, should be removed on next protocol bump + if(pfrom->nVersion == 70900) { + int nCountNeeded; + vRecv >> nCountNeeded; + } - if (nDnCount > 200) { - if(netfulfilledman.HasFulfilledRequest(pfrom->addr, NetMsgType::DYNODEPAYMENTSYNC)) { - // Asking for the payments list multiple times in a short period of time is no good - LogPrintf("DYNODEPAYMENTSYNC -- peer already asked me for the list, peer=%d\n", pfrom->id); - Misbehaving(pfrom->GetId(), 20); - return; - } + + if(netfulfilledman.HasFulfilledRequest(pfrom->addr, NetMsgType::DYNODEPAYMENTSYNC)) { + // Asking for the payments list multiple times in a short period of time is no good + LogPrintf("DYNODEPAYMENTSYNC -- peer already asked me for the list, peer=%d\n", pfrom->id); + Misbehaving(pfrom->GetId(), 20); + return; } netfulfilledman.AddFulfilledRequest(pfrom->addr, NetMsgType::DYNODEPAYMENTSYNC); @@ -367,7 +332,12 @@ void CDynodePayments::ProcessMessage(CNode* pfrom, std::string& strCommand, CDat CDynodePaymentVote vote; vRecv >> vote; - if(pfrom->nVersion < GetMinDynodePaymentsProto()) return; + if(pfrom->nVersion < GetMinDynodePaymentsProto()) { + LogPrint("dnpayments", "DYNODEPAYMENTVOTE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", GetMinDynodePaymentsProto()))); + return; + } uint256 nHash = vote.GetHash(); @@ -380,16 +350,19 @@ void CDynodePayments::ProcessMessage(CNode* pfrom, std::string& strCommand, CDat { LOCK(cs_mapDynodePaymentVotes); - if(mapDynodePaymentVotes.count(nHash)) { - LogPrint("dnpayments", "DYNODEPAYMENTVOTE -- hash=%s, nHeight=%d seen\n", nHash.ToString(), nCachedBlockHeight); + + auto res = mapDynodePaymentVotes.emplace(nHash, vote); + + // Avoid processing same vote multiple times if it was already verified earlier + if(!res.second && res.first->second.IsVerified()) { + LogPrint("dnpayments", "DYNODEPAYMENTVOTE -- hash=%s, nBlockHeight=%d/%d seen\n", + nHash.ToString(), vote.nBlockHeight, nCachedBlockHeight); return; } - // Avoid processing same vote multiple times - mapDynodePaymentVotes[nHash] = vote; - // but first mark vote as non-verified, - // AddPaymentVote() below should take care of it if vote is actually ok - mapDynodePaymentVotes[nHash].MarkAsNotVerified(); + // Mark vote as non-verified when it's seen for the first time, + // AddOrUpdatePaymentVote() below should take care of it if vote is actually ok + res.first->second.MarkAsNotVerified(); } int nFirstBlock = nCachedBlockHeight - GetStorageLimit(); @@ -404,22 +377,18 @@ void CDynodePayments::ProcessMessage(CNode* pfrom, std::string& strCommand, CDat return; } - if(!CanVote(vote.vinDynode.prevout, vote.nBlockHeight)) { - LogPrintf("DYNODEPAYMENTVOTE -- Dynode already voted, Dynode=%s\n", vote.vinDynode.prevout.ToStringShort()); - return; - } - dynode_info_t dnInfo; - if(!dnodeman.GetDynodeInfo(vote.vinDynode.prevout, dnInfo)) { + if(!dnodeman.GetDynodeInfo(vote.dynodeOutpoint, dnInfo)) { // dn was not found, so we can't check vote, some info is probably missing - LogPrintf("DYNODEPAYMENTVOTE -- Dynode is missing %s\n", vote.vinDynode.prevout.ToStringShort()); - dnodeman.AskForDN(pfrom, vote.vinDynode.prevout, connman); + LogPrintf("DYNODEPAYMENTVOTE -- Dynode is missing %s\n", vote.dynodeOutpoint.ToStringShort()); + dnodeman.AskForDN(pfrom, vote.dynodeOutpoint, connman); return; } int nDos = 0; if(!vote.CheckSignature(dnInfo.pubKeyDynode, nCachedBlockHeight, nDos)) { if(nDos) { + LOCK(cs_main); LogPrintf("DYNODEPAYMENTVOTE -- ERROR: invalid signature\n"); Misbehaving(pfrom->GetId(), nDos); } else { @@ -428,71 +397,106 @@ void CDynodePayments::ProcessMessage(CNode* pfrom, std::string& strCommand, CDat } // Either our info or vote info could be outdated. // In case our info is outdated, ask for an update, - dnodeman.AskForDN(pfrom, vote.vinDynode.prevout, connman); + dnodeman.AskForDN(pfrom, vote.dynodeOutpoint, connman); // but there is nothing we can do if vote info itself is outdated // (i.e. it was signed by a DN which changed its key), // so just quit here. return; } + if(!UpdateLastVote(vote)) { + LogPrintf("DYNODEPAYMENTVOTE -- dynode already voted, dynode=%s\n", vote.dynodeOutpoint.ToStringShort()); + return; + } + CTxDestination address1; ExtractDestination(vote.payee, address1); CDynamicAddress address2(address1); LogPrint("dnpayments", "DYNODEPAYMENTVOTE -- vote: address=%s, nBlockHeight=%d, nHeight=%d, prevout=%s, hash=%s new\n", - address2.ToString(), vote.nBlockHeight, nCachedBlockHeight, vote.vinDynode.prevout.ToStringShort(), nHash.ToString()); + address2.ToString(), vote.nBlockHeight, nCachedBlockHeight, vote.dynodeOutpoint.ToStringShort(), nHash.ToString()); - if(AddPaymentVote(vote)){ + if(AddOrUpdatePaymentVote(vote)){ vote.Relay(connman); dynodeSync.BumpAssetLastTime("DYNODEPAYMENTVOTE"); } } } +uint256 CDynodePaymentVote::GetHash() const +{ + // Note: doesn't match serialization + + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << *(CScriptBase*)(&payee); + ss << nBlockHeight; + ss << dynodeOutpoint; + return ss.GetHash(); +} + +uint256 CDynodePaymentVote::GetSignatureHash() const +{ + return SerializeHash(*this); +} + bool CDynodePaymentVote::Sign() { std::string strError; - std::string strMessage = vinDynode.prevout.ToStringShort() + - boost::lexical_cast(nBlockHeight) + - ScriptToAsmStr(payee); - if(!CMessageSigner::SignMessage(strMessage, vchSig, activeDynode.keyDynode)) { - LogPrintf("CDynodePaymentVote::Sign -- SignMessage() failed\n"); - return false; - } + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); - if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CDynodePaymentVote::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; + if(!CHashSigner::SignHash(hash, activeDynode.keyDynode, vchSig)) { + LogPrintf("CDynodePaymentVote::Sign -- SignHash() failed\n"); + return false; + } + + if (!CHashSigner::VerifyHash(hash, activeDynode.pubKeyDynode, vchSig, strError)) { + LogPrintf("CDynodePaymentVote::Sign -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = dynodeOutpoint.ToStringShort() + + std::to_string(nBlockHeight) + + ScriptToAsmStr(payee); + + if(!CMessageSigner::SignMessage(strMessage, vchSig, activeDynode.keyDynode)) { + LogPrintf("CDynodePaymentVote::Sign -- SignMessage() failed\n"); + return false; + } + + if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CDynodePaymentVote::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } return true; } -bool CDynodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) +bool CDynodePayments::GetBlockPayee(int nBlockHeight, CScript& payeeRet) const { - if(mapDynodeBlocks.count(nBlockHeight)){ - return mapDynodeBlocks[nBlockHeight].GetBestPayee(payee); - } + LOCK(cs_mapDynodeBlocks); - return false; + auto it = mapDynodeBlocks.find(nBlockHeight); + return it != mapDynodeBlocks.end() && it->second.GetBestPayee(payeeRet); } // Is this Dynode scheduled to get paid soon? // -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 blocks of votes -bool CDynodePayments::IsScheduled(CDynode& dn, int nNotBlockHeight) +bool CDynodePayments::IsScheduled(const dynode_info_t& dnInfo, int nNotBlockHeight) const { LOCK(cs_mapDynodeBlocks); if(!dynodeSync.IsDynodeListSynced()) return false; CScript dnpayee; - dnpayee = GetScriptForDestination(dn.pubKeyCollateralAddress.GetID()); + dnpayee = GetScriptForDestination(dnInfo.pubKeyCollateralAddress.GetID()); CScript payee; for(int64_t h = nCachedBlockHeight; h <= nCachedBlockHeight + 8; h++){ if(h == nNotBlockHeight) continue; - if(mapDynodeBlocks.count(h) && mapDynodeBlocks[h].GetBestPayee(payee) && dnpayee == payee) { + if(GetBlockPayee(h, payee) && dnpayee == payee) { return true; } } @@ -500,31 +504,31 @@ bool CDynodePayments::IsScheduled(CDynode& dn, int nNotBlockHeight) return false; } -bool CDynodePayments::AddPaymentVote(const CDynodePaymentVote& vote) +bool CDynodePayments::AddOrUpdatePaymentVote(const CDynodePaymentVote& vote) { uint256 blockHash = uint256(); if(!GetBlockHash(blockHash, vote.nBlockHeight - 101)) return false; - if(HasVerifiedPaymentVote(vote.GetHash())) return false; + uint256 nVoteHash = vote.GetHash(); + + if(HasVerifiedPaymentVote(nVoteHash)) return false; LOCK2(cs_mapDynodeBlocks, cs_mapDynodePaymentVotes); - mapDynodePaymentVotes[vote.GetHash()] = vote; + mapDynodePaymentVotes[nVoteHash] = vote; - if(!mapDynodeBlocks.count(vote.nBlockHeight)) { - CDynodeBlockPayees blockPayees(vote.nBlockHeight); - mapDynodeBlocks[vote.nBlockHeight] = blockPayees; - } + auto it = mapDynodeBlocks.emplace(vote.nBlockHeight, CDynodeBlockPayees(vote.nBlockHeight)).first; + it->second.AddPayee(vote); - mapDynodeBlocks[vote.nBlockHeight].AddPayee(vote); + LogPrint("dnpayments", "CDynodePayments::AddOrUpdatePaymentVote -- added, hash=%s\n", nVoteHash.ToString()); return true; } -bool CDynodePayments::HasVerifiedPaymentVote(uint256 hashIn) +bool CDynodePayments::HasVerifiedPaymentVote(const uint256& hashIn) const { LOCK(cs_mapDynodePaymentVotes); - std::map::iterator it = mapDynodePaymentVotes.find(hashIn); + const auto it = mapDynodePaymentVotes.find(hashIn); return it != mapDynodePaymentVotes.end() && it->second.IsVerified(); } @@ -532,17 +536,19 @@ void CDynodeBlockPayees::AddPayee(const CDynodePaymentVote& vote) { LOCK(cs_vecPayees); - BOOST_FOREACH(CDynodePayee& payee, vecPayees) { + uint256 nVoteHash = vote.GetHash(); + + for (auto& payee : vecPayees) { if (payee.GetPayee() == vote.payee) { - payee.AddVoteHash(vote.GetHash()); + payee.AddVoteHash(nVoteHash); return; } } - CDynodePayee payeeNew(vote.payee, vote.GetHash()); + CDynodePayee payeeNew(vote.payee, nVoteHash); vecPayees.push_back(payeeNew); } -bool CDynodeBlockPayees::GetBestPayee(CScript& payeeRet) +bool CDynodeBlockPayees::GetBestPayee(CScript& payeeRet) const { LOCK(cs_vecPayees); @@ -552,7 +558,7 @@ bool CDynodeBlockPayees::GetBestPayee(CScript& payeeRet) } int nVotes = -1; - BOOST_FOREACH(CDynodePayee& payee, vecPayees) { + for (const auto& payee : vecPayees) { if (payee.GetVoteCount() > nVotes) { payeeRet = payee.GetPayee(); nVotes = payee.GetVoteCount(); @@ -562,11 +568,11 @@ bool CDynodeBlockPayees::GetBestPayee(CScript& payeeRet) return (nVotes > -1); } -bool CDynodeBlockPayees::HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq) +bool CDynodeBlockPayees::HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq) const { LOCK(cs_vecPayees); - BOOST_FOREACH(CDynodePayee& payee, vecPayees) { + for (const auto& payee : vecPayees) { if (payee.GetVoteCount() >= nVotesReq && payee.GetPayee() == payeeIn) { return true; } @@ -576,7 +582,7 @@ bool CDynodeBlockPayees::HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq return false; } -bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew, const int nHeight) +bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew, const int nHeight) const { LOCK(cs_vecPayees); @@ -586,7 +592,7 @@ bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew, const int //require at least DNPAYMENTS_SIGNATURES_REQUIRED signatures - BOOST_FOREACH(CDynodePayee& payee, vecPayees) { + for (const auto& payee : vecPayees) { if (payee.GetVoteCount() >= nMaxSignatures) { nMaxSignatures = payee.GetVoteCount(); } @@ -595,9 +601,9 @@ bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew, const int // if we don't have at least DNPAYMENTS_SIGNATURES_REQUIRED signatures on a payee, approve whichever is the longest chain if(nMaxSignatures < DNPAYMENTS_SIGNATURES_REQUIRED) return true; - BOOST_FOREACH(CDynodePayee& payee, vecPayees) { + for (const auto& payee : vecPayees) { if (payee.GetVoteCount() >= DNPAYMENTS_SIGNATURES_REQUIRED) { - BOOST_FOREACH(CTxOut txout, txNew.vout) { + for (const auto& txout : txNew.vout) { if (payee.GetPayee() == txout.scriptPubKey && nDynodePayment == txout.nValue) { LogPrint("dnpayments", "CDynodeBlockPayees::IsTransactionValid -- Found required payment\n"); return true; @@ -620,48 +626,44 @@ bool CDynodeBlockPayees::IsTransactionValid(const CTransaction& txNew, const int return false; } -std::string CDynodeBlockPayees::GetRequiredPaymentsString() +std::string CDynodeBlockPayees::GetRequiredPaymentsString() const { LOCK(cs_vecPayees); - std::string strRequiredPayments = "Unknown"; + std::string strRequiredPayments = ""; - BOOST_FOREACH(CDynodePayee& payee, vecPayees) + for (const auto& payee : vecPayees) { CTxDestination address1; ExtractDestination(payee.GetPayee(), address1); CDynamicAddress address2(address1); - if (strRequiredPayments != "Unknown") { - strRequiredPayments += ", " + address2.ToString() + ":" + boost::lexical_cast(payee.GetVoteCount()); - } else { - strRequiredPayments = address2.ToString() + ":" + boost::lexical_cast(payee.GetVoteCount()); - } + if (!strRequiredPayments.empty()) + strRequiredPayments += ", "; + + strRequiredPayments += strprintf("%s:%d", address2.ToString(), payee.GetVoteCount()); } + if (strRequiredPayments.empty()) + return "Unknown"; + return strRequiredPayments; } -std::string CDynodePayments::GetRequiredPaymentsString(int nBlockHeight) +std::string CDynodePayments::GetRequiredPaymentsString(int nBlockHeight) const { LOCK(cs_mapDynodeBlocks); - if(mapDynodeBlocks.count(nBlockHeight)){ - return mapDynodeBlocks[nBlockHeight].GetRequiredPaymentsString(); - } - - return "Unknown"; + const auto it = mapDynodeBlocks.find(nBlockHeight); + return it == mapDynodeBlocks.end() ? "Unknown" : it->second.GetRequiredPaymentsString(); } -bool CDynodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight) +bool CDynodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight) const { LOCK(cs_mapDynodeBlocks); - if(mapDynodeBlocks.count(nBlockHeight)){ - return mapDynodeBlocks[nBlockHeight].IsTransactionValid(txNew, nBlockHeight); - } - - return true; + const auto it = mapDynodeBlocks.find(nBlockHeight); + return it == mapDynodeBlocks.end() ? true : it->second.IsTransactionValid(txNew, nBlockHeight); } void CDynodePayments::CheckAndRemove() @@ -687,15 +689,15 @@ void CDynodePayments::CheckAndRemove() LogPrintf("CDynodePayments::CheckAndRemove -- %s\n", ToString()); } -bool CDynodePaymentVote::IsValid(CNode* pnode, int nValidationHeight, std::string& strError, CConnman& connman) +bool CDynodePaymentVote::IsValid(CNode* pnode, int nValidationHeight, std::string& strError, CConnman& connman) const { dynode_info_t dnInfo; - if(!dnodeman.GetDynodeInfo(vinDynode.prevout, dnInfo)) { - strError = strprintf("Unknown Dynode: prevout=%s", vinDynode.prevout.ToStringShort()); + if(!dnodeman.GetDynodeInfo(dynodeOutpoint, dnInfo)) { + strError = strprintf("Unknown dynode=%s", dynodeOutpoint.ToStringShort()); // Only ask if we are already synced and still have no idea about that Dynode if(dynodeSync.IsDynodeListSynced()) { - dnodeman.AskForDN(pnode, vinDynode.prevout, connman); + dnodeman.AskForDN(pnode, dynodeOutpoint, connman); } return false; @@ -707,7 +709,7 @@ bool CDynodePaymentVote::IsValid(CNode* pnode, int nValidationHeight, std::strin nMinRequiredProtocol = dnpayments.GetMinDynodePaymentsProto(); } else { // allow non-updated dynodes for old blocks - nMinRequiredProtocol = MIN_DYNODE_PAYMENT_PROTO_VERSION; + nMinRequiredProtocol = MIN_DYNODE_PAYMENT_PROTO_VERSION_1; } if(dnInfo.nProtocolVersion < nMinRequiredProtocol) { @@ -721,20 +723,22 @@ bool CDynodePaymentVote::IsValid(CNode* pnode, int nValidationHeight, std::strin int nRank; - if(!dnodeman.GetDynodeRank(vinDynode.prevout, nRank, nBlockHeight - 101, nMinRequiredProtocol)) { + if(!dnodeman.GetDynodeRank(dynodeOutpoint, nRank, nBlockHeight - 101, nMinRequiredProtocol)) { LogPrint("dnpayments", "CDynodePaymentVote::IsValid -- Can't calculate rank for dynode %s\n", - vinDynode.prevout.ToStringShort()); + dynodeOutpoint.ToStringShort()); return false; } if(nRank > DNPAYMENTS_SIGNATURES_TOTAL) { // It's common to have dynodes mistakenly think they are in the top 10 // We don't want to print all of these messages in normal mode, debug mode should print though - strError = strprintf("Dynode is not in the top %d (%d)", DNPAYMENTS_SIGNATURES_TOTAL, nRank); + strError = strprintf("Dynode %s is not in the top %d (%d)", dynodeOutpoint.ToStringShort(), DNPAYMENTS_SIGNATURES_TOTAL, nRank); // Only ban for new dnw which is out of bounds, for old dnw DN list itself might be way too much off if(nRank > DNPAYMENTS_SIGNATURES_TOTAL*2 && nBlockHeight > nValidationHeight) { - strError = strprintf("Dynode is not in the top %d (%d)", DNPAYMENTS_SIGNATURES_TOTAL*2, nRank); + LOCK(cs_main); + strError = strprintf("Dynode %s is not in the top %d (%d)", dynodeOutpoint.ToStringShort(), DNPAYMENTS_SIGNATURES_TOTAL*2, nRank); LogPrintf("CDynodePaymentVote::IsValid -- Error: %s\n", strError); + Misbehaving(pnode->GetId(), 20); } // Still invalid however return false; @@ -780,7 +784,7 @@ bool CDynodePayments::ProcessBlock(int nBlockHeight, CConnman& connman) return false; } - LogPrintf("CDynodePayments::ProcessBlock -- Dynode found by GetNextDynodeInQueueForPayment(): %s\n", dnInfo.vin.prevout.ToStringShort()); + LogPrintf("CDynodePayments::ProcessBlock -- Dynode found by GetNextDynodeInQueueForPayment(): %s\n", dnInfo.outpoint.ToStringShort()); CScript payee = GetScriptForDestination(dnInfo.pubKeyCollateralAddress.GetID()); @@ -798,7 +802,7 @@ bool CDynodePayments::ProcessBlock(int nBlockHeight, CConnman& connman) if (voteNew.Sign()) { LogPrintf("CDynodePayments::ProcessBlock -- AddPaymentVote()\n"); - if (AddPaymentVote(voteNew)) { + if (AddOrUpdatePaymentVote(voteNew)) { voteNew.Relay(connman); return true; } @@ -807,39 +811,39 @@ bool CDynodePayments::ProcessBlock(int nBlockHeight, CConnman& connman) return false; } -void CDynodePayments::CheckPreviousBlockVotes(int nPrevBlockHeight) +void CDynodePayments::CheckBlockVotes(int nBlockHeight) { if (!dynodeSync.IsWinnersListSynced()) return; - std::string debugStr; - - debugStr += strprintf("CDynodePayments::CheckPreviousBlockVotes -- nPrevBlockHeight=%d, expected voting DNs:\n", nPrevBlockHeight); - CDynodeMan::rank_pair_vec_t dns; - if (!dnodeman.GetDynodeRanks(dns, nPrevBlockHeight - 101, GetMinDynodePaymentsProto())) { - debugStr += "CDynodePayments::CheckPreviousBlockVotes -- GetDynodeRanks failed\n"; - LogPrint("dnpayments", "%s", debugStr); + if (!dnodeman.GetDynodeRanks(dns, nBlockHeight - 101, GetMinDynodePaymentsProto())) { + LogPrintf("CDynodePayments::CheckBlockVotes -- nBlockHeight=%d, GetDynodeRanks failed\n", nBlockHeight); return; } + std::string debugStr; + + debugStr += strprintf("CDynodePayments::CheckBlockVotes -- nBlockHeight=%d,\n Expected voting DNs:\n", nBlockHeight); + LOCK2(cs_mapDynodeBlocks, cs_mapDynodePaymentVotes); - for (int i = 0; i < DNPAYMENTS_SIGNATURES_TOTAL && i < (int)dns.size(); i++) { - auto dn = dns[i]; + int i{0}; + for (const auto& dn : dns) { CScript payee; bool found = false; - if (mapDynodeBlocks.count(nPrevBlockHeight)) { - for (auto &p : mapDynodeBlocks[nPrevBlockHeight].vecPayees) { - for (auto &voteHash : p.GetVoteHashes()) { - if (!mapDynodePaymentVotes.count(voteHash)) { - debugStr += strprintf("CDynodePayments::CheckPreviousBlockVotes -- could not find vote %s\n", + const auto it = mapDynodeBlocks.find(nBlockHeight); + if (it != mapDynodeBlocks.end()) { + for (const auto& p : it->second.vecPayees) { + for (const auto& voteHash : p.GetVoteHashes()) { + const auto itVote = mapDynodePaymentVotes.find(voteHash); + if (itVote == mapDynodePaymentVotes.end()) { + debugStr += strprintf(" - could not find vote %s\n", voteHash.ToString()); continue; } - auto vote = mapDynodePaymentVotes[voteHash]; - if (vote.vinDynode.prevout == dn.second.vin.prevout) { - payee = vote.payee; + if (itVote->second.dynodeOutpoint == dn.second.outpoint) { + payee = itVote->second.payee; found = true; break; } @@ -847,54 +851,89 @@ void CDynodePayments::CheckPreviousBlockVotes(int nPrevBlockHeight) } } - if (!found) { - debugStr += strprintf("CDynodePayments::CheckPreviousBlockVotes -- %s - no vote received\n", - dn.second.vin.prevout.ToStringShort()); - mapDynodesDidNotVote[dn.second.vin.prevout]++; - continue; + if (found) { + CTxDestination address1; + ExtractDestination(payee, address1); + CDynamicAddress address2(address1); + + debugStr += strprintf(" - %s - voted for %s\n", + dn.second.outpoint.ToStringShort(), address2.ToString()); + } else { + mapDynodesDidNotVote.emplace(dn.second.outpoint, 0).first->second++; + + debugStr += strprintf(" - %s - no vote received\n", + dn.second.outpoint.ToStringShort()); } - CTxDestination address1; - ExtractDestination(payee, address1); - CDynamicAddress address2(address1); + if (++i >= DNPAYMENTS_SIGNATURES_TOTAL) break; + } - debugStr += strprintf("CDynodePayments::CheckPreviousBlockVotes -- %s - voted for %s\n", - dn.second.vin.prevout.ToStringShort(), address2.ToString()); + if (mapDynodesDidNotVote.empty()) { + LogPrint("dnpayments", "%s", debugStr); + return; } - debugStr += "CDynodePayments::CheckPreviousBlockVotes -- Dynodes which missed a vote in the past:\n"; - for (auto it : mapDynodesDidNotVote) { - debugStr += strprintf("CDynodePayments::CheckPreviousBlockVotes -- %s: %d\n", it.first.ToStringShort(), it.second); + + debugStr += " Dynodes which missed a vote in the past:\n"; + for (const auto& item : mapDynodesDidNotVote) { + debugStr += strprintf(" - %s: %d\n", item.first.ToStringShort(), item.second); } LogPrint("dnpayments", "%s", debugStr); } -void CDynodePaymentVote::Relay(CConnman& connman) +void CDynodePaymentVote::Relay(CConnman& connman) const { - // do not relay until synced - if (!dynodeSync.IsWinnersListSynced()) return; + // Do not relay until fully synced + if(!dynodeSync.IsSynced()) { + LogPrint("dnpayments", "CDynodePayments::Relay -- won't relay until fully synced\n"); + return; + } + CInv inv(MSG_DYNODE_PAYMENT_VOTE, GetHash()); connman.RelayInv(inv); } -bool CDynodePaymentVote::CheckSignature(const CPubKey& pubKeyDynode, int nValidationHeight, int &nDos) +bool CDynodePaymentVote::CheckSignature(const CPubKey& pubKeyDynode, int nValidationHeight, int &nDos) const { // do not ban by default nDos = 0; - - std::string strMessage = vinDynode.prevout.ToStringShort() + - boost::lexical_cast(nBlockHeight) + - ScriptToAsmStr(payee); - std::string strError = ""; - if (!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { - // Only ban for future block vote when we are already synced. - // Otherwise it could be the case when DN which signed this vote is using another key now - // and we have no idea about the old one. - if(dynodeSync.IsDynodeListSynced() && nBlockHeight > nValidationHeight) { - nDos = 20; + + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + // could be a signature in old format + std::string strMessage = dynodeOutpoint.ToStringShort() + + boost::lexical_cast(nBlockHeight) + + ScriptToAsmStr(payee); + if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + // nope, not in old format either + // Only ban for future block vote when we are already synced. + // Otherwise it could be the case when DN which signed this vote is using another key now + // and we have no idea about the old one. + if(dynodeSync.IsDynodeListSynced() && nBlockHeight > nValidationHeight) { + nDos = 20; + } + return error("CDynodePaymentVote::CheckSignature -- Got bad Dynode payment signature, dynode=%s, error: %s", + dynodeOutpoint.ToStringShort(), strError); + } + } + } else { + std::string strMessage = dynodeOutpoint.ToStringShort() + + boost::lexical_cast(nBlockHeight) + + ScriptToAsmStr(payee); + + if (!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + // Only ban for future block vote when we are already synced. + // Otherwise it could be the case when DN which signed this vote is using another key now + // and we have no idea about the old one. + if(dynodeSync.IsDynodeListSynced() && nBlockHeight > nValidationHeight) { + nDos = 20; + } + return error("CDynodePaymentVote::CheckSignature -- Got bad Dynode payment signature, dynode=%s, error: %s", + dynodeOutpoint.ToStringShort(), strError); } - return error("CDynodePaymentVote::CheckSignature -- Got bad Dynode payment signature, Dynode=%s, error: %s", vinDynode.prevout.ToStringShort().c_str(), strError); } return true; @@ -904,7 +943,7 @@ std::string CDynodePaymentVote::ToString() const { std::ostringstream info; - info << vinDynode.prevout.ToStringShort() << + info << dynodeOutpoint.ToStringShort() << ", " << nBlockHeight << ", " << ScriptToAsmStr(payee) << ", " << (int)vchSig.size(); @@ -913,7 +952,7 @@ std::string CDynodePaymentVote::ToString() const } // Send all votes up to nCountNeeded blocks (but not more than GetStorageLimit) -void CDynodePayments::Sync(CNode* pnode, CConnman& connman) +void CDynodePayments::Sync(CNode* pnode, CConnman& connman) const { LOCK(cs_mapDynodeBlocks); @@ -922,10 +961,11 @@ void CDynodePayments::Sync(CNode* pnode, CConnman& connman) int nInvCount = 0; for(int h = nCachedBlockHeight; h < nCachedBlockHeight + 20; h++) { - if(mapDynodeBlocks.count(h)) { - BOOST_FOREACH(CDynodePayee& payee, mapDynodeBlocks[h].vecPayees) { + const auto it = mapDynodeBlocks.find(h); + if(it != mapDynodeBlocks.end()) { + for (const auto& payee : it->second.vecPayees) { std::vector vecVoteHashes = payee.GetVoteHashes(); - BOOST_FOREACH(uint256& hash, vecVoteHashes) { + for (const auto& hash : vecVoteHashes) { if(!HasVerifiedPaymentVote(hash)) continue; pnode->PushInventory(CInv(MSG_DYNODE_PAYMENT_VOTE, hash)); nInvCount++; @@ -934,15 +974,16 @@ void CDynodePayments::Sync(CNode* pnode, CConnman& connman) } } - LogPrintf("CDynodePayments::Sync -- Sent %d votes to peer %d\n", nInvCount, pnode->id); - connman.PushMessage(pnode, NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_DNW, nInvCount); + LogPrintf("CDynodePayments::Sync -- Sent %d votes to peer=%d\n", nInvCount, pnode->id); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_DNW, nInvCount)); } - // Request low data/unknown payment blocks in batches directly from some node instead of/after preliminary Sync. -void CDynodePayments::RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connman) +void CDynodePayments::RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connman) const { if(!dynodeSync.IsDynodeListSynced()) return; + CNetMsgMaker msgMaker(pnode->GetSendVersion()); LOCK2(cs_main, cs_mapDynodeBlocks); std::vector vToFetch; @@ -957,7 +998,7 @@ void CDynodePayments::RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connma // We should not violate GETDATA rules if(vToFetch.size() == MAX_INV_SZ) { LogPrintf("CDynodePayments::SyncLowDataPaymentBlocks -- asking peer %d for %d blocks\n", pnode->id, MAX_INV_SZ); - connman.PushMessage(pnode, NetMsgType::GETDATA, vToFetch); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETDATA, vToFetch)); // Start filling new batch vToFetch.clear(); } @@ -966,29 +1007,27 @@ void CDynodePayments::RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connma pindex = pindex->pprev; } - std::map::iterator it = mapDynodeBlocks.begin(); - - while(it != mapDynodeBlocks.end()) { + for (auto& dnBlockPayees : mapDynodeBlocks) { + int nBlockHeight = dnBlockPayees.first; int nTotalVotes = 0; bool fFound = false; - BOOST_FOREACH(CDynodePayee& payee, it->second.vecPayees) { + for (const auto& payee : dnBlockPayees.second.vecPayees) { if(payee.GetVoteCount() >= DNPAYMENTS_SIGNATURES_REQUIRED) { fFound = true; break; } nTotalVotes += payee.GetVoteCount(); - } + } // A clear winner (DNPAYMENTS_SIGNATURES_REQUIRED+ votes) was found // or no clear winner was found but there are at least avg number of votes if(fFound || nTotalVotes >= (DNPAYMENTS_SIGNATURES_TOTAL + DNPAYMENTS_SIGNATURES_REQUIRED)/2) { // so just move to the next block - ++it; continue; } // DEBUG DBG ( // Let's see why this failed - BOOST_FOREACH(CDynodePayee& payee, it->second.vecPayees) { + for (const auto& payee : dnBlockPayees.second.vecPayees) { CTxDestination address1; ExtractDestination(payee.GetPayee(), address1); CDynamicAddress address2(address1); @@ -999,22 +1038,21 @@ void CDynodePayments::RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connma // END DEBUG // Low data block found, let's try to sync it uint256 hash; - if(GetBlockHash(hash, it->first)) { + if(GetBlockHash(hash, nBlockHeight)) { vToFetch.push_back(CInv(MSG_DYNODE_PAYMENT_BLOCK, hash)); } // We should not violate GETDATA rules if(vToFetch.size() == MAX_INV_SZ) { LogPrintf("CDynodePayments::SyncLowDataPaymentBlocks -- asking peer %d for %d payment blocks\n", pnode->id, MAX_INV_SZ); - connman.PushMessage(pnode, NetMsgType::GETDATA, vToFetch); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETDATA, vToFetch)); // Start filling new batch vToFetch.clear(); } - ++it; } // Ask for the rest of it if(!vToFetch.empty()) { LogPrintf("CDynodePayments::SyncLowDataPaymentBlocks -- asking peer %d for %d payment blocks\n", pnode->id, vToFetch.size()); - connman.PushMessage(pnode, NetMsgType::GETDATA, vToFetch); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETDATA, vToFetch)); } } @@ -1028,14 +1066,14 @@ std::string CDynodePayments::ToString() const return info.str(); } -bool CDynodePayments::IsEnoughData() +bool CDynodePayments::IsEnoughData() const { float nAverageVotes = (DNPAYMENTS_SIGNATURES_TOTAL + DNPAYMENTS_SIGNATURES_REQUIRED) / 2; int nStorageLimit = GetStorageLimit(); return GetBlockCount() > nStorageLimit && GetVoteCount() > nStorageLimit * nAverageVotes; } -int CDynodePayments::GetStorageLimit() +int CDynodePayments::GetStorageLimit() const { return std::max(int(dnodeman.size() * nStorageCoeff), nMinBlocksToStore); } @@ -1049,6 +1087,6 @@ void CDynodePayments::UpdatedBlockTip(const CBlockIndex *pindex, CConnman& connm int nFutureBlock = nCachedBlockHeight + 10; - CheckPreviousBlockVotes(nFutureBlock - 1); + CheckBlockVotes(nFutureBlock - 1); ProcessBlock(nFutureBlock, connman); } diff --git a/src/dynode-payments.h b/src/dynode-payments.h index 45e2e5cdbc..b215850566 100644 --- a/src/dynode-payments.h +++ b/src/dynode-payments.h @@ -20,9 +20,12 @@ class CDynodePaymentVote; static const int DNPAYMENTS_SIGNATURES_REQUIRED = 10; static const int DNPAYMENTS_SIGNATURES_TOTAL = 20; -//! minimum peer version that can receive and send Dynode payment messages, -// vote for Dynode and be elected as a payment winner -static const int MIN_DYNODE_PAYMENT_PROTO_VERSION = 70900; +//! minimum peer version that can receive and send dynode payment messages, +// vote for dynode and be elected as a payment winner +// V1 - Last protocol version before update +// V2 - Newest protocol version +static const int MIN_DYNODE_PAYMENT_PROTO_VERSION_1 = 70900; +static const int MIN_DYNODE_PAYMENT_PROTO_VERSION_2 = 71000; extern CCriticalSection cs_vecPayees; extern CCriticalSection cs_mapDynodeBlocks; @@ -33,7 +36,7 @@ extern CDynodePayments dnpayments; /// TODO: all 4 functions do not belong here really, they should be refactored/moved somewhere (main.cpp ?) bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward, std::string &strErrorRet); bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward); -void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CTxOut& txoutDynodeRet, std::vector& voutSuperblockRet); +void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutDynodeRet, std::vector& voutSuperblockRet); std::string GetRequiredPaymentsString(int nBlockHeight); class CDynodePayee @@ -63,11 +66,11 @@ class CDynodePayee READWRITE(vecVoteHashes); } - CScript GetPayee() { return scriptPubKey; } + CScript GetPayee() const { return scriptPubKey; } void AddVoteHash(uint256 hashIn) { vecVoteHashes.push_back(hashIn); } - std::vector GetVoteHashes() { return vecVoteHashes; } - int GetVoteCount() { return vecVoteHashes.size(); } + std::vector GetVoteHashes() const { return vecVoteHashes; } + int GetVoteCount() const { return vecVoteHashes.size(); } }; // Keep track of votes for payees from Dynodes @@ -95,33 +98,33 @@ class CDynodeBlockPayees } void AddPayee(const CDynodePaymentVote& vote); - bool GetBestPayee(CScript& payeeRet); - bool HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq); + bool GetBestPayee(CScript& payeeRet) const; + bool HasPayeeWithVotes(const CScript& payeeIn, int nVotesReq) const; - bool IsTransactionValid(const CTransaction& txNew, const int nHeight); + bool IsTransactionValid(const CTransaction& txNew, int nHeight) const; - std::string GetRequiredPaymentsString(); + std::string GetRequiredPaymentsString() const; }; // vote for the winning payment class CDynodePaymentVote { public: - CTxIn vinDynode; + COutPoint dynodeOutpoint; int nBlockHeight; CScript payee; std::vector vchSig; CDynodePaymentVote() : - vinDynode(), + dynodeOutpoint(), nBlockHeight(0), payee(), vchSig() {} - CDynodePaymentVote(COutPoint outpointDynode, int nBlockHeight, CScript payee) : - vinDynode(outpointDynode), + CDynodePaymentVote(COutPoint outpoint, int nBlockHeight, CScript payee) : + dynodeOutpoint(outpoint), nBlockHeight(nBlockHeight), payee(payee), vchSig() @@ -131,27 +134,38 @@ class CDynodePaymentVote template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(vinDynode); + int nVersion = s.GetVersion(); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn vinDynode{}; + if (ser_action.ForRead()) { + READWRITE(vinDynode); + dynodeOutpoint = vinDynode.prevout; + } else { + vinDynode = CTxIn(dynodeOutpoint); + READWRITE(vinDynode); + } + } else { + // using new format directly + READWRITE(dynodeOutpoint); + } READWRITE(nBlockHeight); READWRITE(*(CScriptBase*)(&payee)); - READWRITE(vchSig); + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(vchSig); + } } - uint256 GetHash() const { - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << *(CScriptBase*)(&payee); - ss << nBlockHeight; - ss << vinDynode.prevout; - return ss.GetHash(); - } + uint256 GetHash() const; + uint256 GetSignatureHash() const; bool Sign(); - bool CheckSignature(const CPubKey& pubKeyDynode, int nValidationHeight, int &nDos); + bool CheckSignature(const CPubKey& pubKeyDynode, int nValidationHeight, int &nDos) const; - bool IsValid(CNode* pnode, int nValidationHeight, std::string& strError, CConnman& connman); - void Relay(CConnman& connman); + bool IsValid(CNode* pnode, int nValidationHeight, std::string& strError, CConnman& connman) const; + void Relay(CConnman& connman) const; - bool IsVerified() { return !vchSig.empty(); } + bool IsVerified() const { return !vchSig.empty(); } void MarkAsNotVerified() { vchSig.clear(); } std::string ToString() const; @@ -191,34 +205,36 @@ class CDynodePayments void Clear(); - bool AddPaymentVote(const CDynodePaymentVote& vote); - bool HasVerifiedPaymentVote(uint256 hashIn); + bool AddOrUpdatePaymentVote(const CDynodePaymentVote& vote); + bool HasVerifiedPaymentVote(const uint256& hashIn) const; bool ProcessBlock(int nBlockHeight, CConnman& connman); - void CheckPreviousBlockVotes(int nPrevBlockHeight); + void CheckBlockVotes(int nBlockHeight); - void Sync(CNode* node, CConnman& connman); - void RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connman); + void Sync(CNode* node, CConnman& connman) const; + void RequestLowDataPaymentBlocks(CNode* pnode, CConnman& connman) const; void CheckAndRemove(); - bool GetBlockPayee(int nBlockHeight, CScript& payee); - bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight); - bool IsScheduled(CDynode& dn, int nNotBlockHeight); + bool GetBlockPayee(int nBlockHeight, CScript& payeeRet) const; + bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight) const; + bool IsScheduled(const dynode_info_t& dnInfo, int nNotBlockHeight) const; - bool CanVote(COutPoint outDynode, int nBlockHeight); + bool UpdateLastVote(const CDynodePaymentVote& vote); - int GetMinDynodePaymentsProto(); - void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman); - std::string GetRequiredPaymentsString(int nBlockHeight); - void FillBlockPayee(CMutableTransaction& txNew, int nBlockHeight, CTxOut& txoutDynodeRet); + int GetMinDynodePaymentsProto() const; + void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); + std::string GetRequiredPaymentsString(int nBlockHeight) const; + void FillBlockPayee(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutDynodeRet) const; std::string ToString() const; - int GetBlockCount() { return mapDynodeBlocks.size(); } - int GetVoteCount() { return mapDynodePaymentVotes.size(); } + int GetBlockCount() const { return mapDynodeBlocks.size(); } + int GetVoteCount() const { return mapDynodePaymentVotes.size(); } - bool IsEnoughData(); - int GetStorageLimit(); + bool IsEnoughData() const; + int GetStorageLimit() const; void UpdatedBlockTip(const CBlockIndex *pindex, CConnman& connman); + + void DoMaintenance() { CheckAndRemove(); } }; #endif // DYNAMIC_DYNODE_PAYMENTS_H diff --git a/src/dynode-sync.cpp b/src/dynode-sync.cpp index 69d55a933a..a379b31930 100644 --- a/src/dynode-sync.cpp +++ b/src/dynode-sync.cpp @@ -13,6 +13,7 @@ #include "dynodeman.h" #include "validation.h" #include "netfulfilledman.h" +#include "netmessagemaker.h" #include "spork.h" #include "ui_interface.h" #include "util.h" @@ -35,7 +36,7 @@ void CDynodeSync::Reset() nTimeLastFailure = 0; } -void CDynodeSync::BumpAssetLastTime(std::string strFuncName) +void CDynodeSync::BumpAssetLastTime(const std::string strFuncName) { if(IsSynced() || IsFailed()) return; nTimeLastBumped = GetTime(); @@ -53,7 +54,7 @@ std::string CDynodeSync::GetAssetName() case(DYNODE_SYNC_GOVERNANCE): return "DYNODE_SYNC_GOVERNANCE"; case(DYNODE_SYNC_FAILED): return "DYNODE_SYNC_FAILED"; case DYNODE_SYNC_FINISHED: return "DYNODE_SYNC_FINISHED"; - default: return "UNKNOWN"; + default: return "UNKNOWN"; } } @@ -65,12 +66,10 @@ void CDynodeSync::SwitchToNextAsset(CConnman& connman) throw std::runtime_error("Can't switch to next asset from failed, should use Reset() first!"); break; case(DYNODE_SYNC_INITIAL): - ClearFulfilledRequests(connman); nRequestedDynodeAssets = DYNODE_SYNC_WAITING; LogPrintf("CDynodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); break; case(DYNODE_SYNC_WAITING): - ClearFulfilledRequests(connman); LogPrintf("CDynodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); nRequestedDynodeAssets = DYNODE_SYNC_LIST; LogPrintf("CDynodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); @@ -122,7 +121,7 @@ std::string CDynodeSync::GetSyncStatus() } } -void CDynodeSync::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) +void CDynodeSync::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv) { if (strCommand == NetMsgType::SYNCSTATUSCOUNT) { //Sync status count @@ -137,21 +136,6 @@ void CDynodeSync::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStr } } -void CDynodeSync::ClearFulfilledRequests(CConnman& connman) -{ - // TODO: Find out whether we can just use LOCK instead of: - // TRY_LOCK(cs_vNodes, lockRecv); - // if(!lockRecv) return; - - connman.ForEachNode(CConnman::AllNodes, [](CNode* pnode) { - netfulfilledman.RemoveFulfilledRequest(pnode->addr, "spork-sync"); - netfulfilledman.RemoveFulfilledRequest(pnode->addr, "dynode-list-sync"); - netfulfilledman.RemoveFulfilledRequest(pnode->addr, "dynode-payment-sync"); - netfulfilledman.RemoveFulfilledRequest(pnode->addr, "governance-sync"); - netfulfilledman.RemoveFulfilledRequest(pnode->addr, "full-sync"); - }); -} - void CDynodeSync::ProcessTick(CConnman& connman) { static int nTick = 0; @@ -181,7 +165,7 @@ void CDynodeSync::ProcessTick(CConnman& connman) // gradually request the rest of the votes after sync finished if(IsSynced()) { - std::vector vNodesCopy = connman.CopyNodeVector(); + std::vector vNodesCopy = connman.CopyNodeVector(CConnman::FullyConnectedOnly); governance.RequestGovernanceObjectVotes(vNodesCopy, connman); connman.ReleaseNodeVector(vNodesCopy); return; @@ -192,9 +176,11 @@ void CDynodeSync::ProcessTick(CConnman& connman) LogPrintf("CDynodeSync::ProcessTick -- nTick %d nRequestedDynodeAssets %d nRequestedDynodeAttempt %d nSyncProgress %f\n", nTick, nRequestedDynodeAssets, nRequestedDynodeAttempt, nSyncProgress); uiInterface.NotifyAdditionalDataSyncProgressChanged(nSyncProgress); - std::vector vNodesCopy = connman.CopyNodeVector(); + std::vector vNodesCopy = connman.CopyNodeVector(CConnman::FullyConnectedOnly); - BOOST_FOREACH(CNode* pnode, vNodesCopy) { + for (auto& pnode : vNodesCopy) + { + CNetMsgMaker msgMaker(pnode->GetSendVersion()); // Don't try to sync any data from outbound "dynode" connections - // they are temporary and should be considered unreliable for a sync process. // Inbound connection this early is most likely a "dynode" connection @@ -204,12 +190,16 @@ void CDynodeSync::ProcessTick(CConnman& connman) if(Params().NetworkIDString() == CBaseChainParams::REGTEST) { if(nRequestedDynodeAttempt <= 2) { - connman.PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::GETSPORKS); //get current network sporks + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETSPORKS)); //get current network sporks } else if(nRequestedDynodeAttempt < 4) { dnodeman.PsegUpdate(pnode, connman); } else if(nRequestedDynodeAttempt < 6) { - int nDnCount = dnodeman.CountDynodes(); - connman.PushMessage(pnode, NetMsgType::DYNODEPAYMENTSYNC, nDnCount); //sync payment votes + //sync payment votes + if(pnode->nVersion == 70900) { + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DYNODEPAYMENTSYNC, dnpayments.GetStorageLimit())); //sync payment votes + } else { + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DYNODEPAYMENTSYNC)); //sync payment votes + } SendGovernanceSyncRequest(pnode, connman); } else { nRequestedDynodeAssets = DYNODE_SYNC_FINISHED; @@ -235,7 +225,7 @@ void CDynodeSync::ProcessTick(CConnman& connman) // always get sporks first, only request once from each peer netfulfilledman.AddFulfilledRequest(pnode->addr, "spork-sync"); // get current network sporks - connman.PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::GETSPORKS); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETSPORKS)); LogPrintf("CDynodeSync::ProcessTick -- nTick %d nRequestedDynodeAssets %d -- requesting sporks from peer %d\n", nTick, nRequestedDynodeAssets, pnode->id); } @@ -337,8 +327,11 @@ void CDynodeSync::ProcessTick(CConnman& connman) nRequestedDynodeAttempt++; // ask node for all payment votes it has (new nodes will only return votes for future payments) - connman.PushMessage(pnode, NetMsgType::DYNODEPAYMENTSYNC, dnpayments.GetStorageLimit()); - // ask node for missing pieces only (old nodes will not be asked) + if(pnode->nVersion == 70900) { + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DYNODEPAYMENTSYNC, dnpayments.GetStorageLimit())); + } else { + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DYNODEPAYMENTSYNC)); + } // ask node for missing pieces only (old nodes will not be asked) dnpayments.RequestLowDataPaymentBlocks(pnode, connman); connman.ReleaseNodeVector(vNodesCopy); @@ -376,7 +369,6 @@ void CDynodeSync::ProcessTick(CConnman& connman) } // make sure the condition below is checked only once per tick if(nLastTick == nTick) continue; - if(GetTime() - nTimeNoObjectsLeft > DYNODE_SYNC_TIMEOUT_SECONDS && governance.GetVoteCount() - nLastVotes < std::max(int(0.0001 * nLastVotes), DYNODE_SYNC_TICK_SECONDS) ) { @@ -395,6 +387,7 @@ void CDynodeSync::ProcessTick(CConnman& connman) nLastTick = nTick; nLastVotes = governance.GetVoteCount(); } + continue; } netfulfilledman.AddFulfilledRequest(pnode->addr, "governance-sync"); @@ -415,14 +408,16 @@ void CDynodeSync::ProcessTick(CConnman& connman) void CDynodeSync::SendGovernanceSyncRequest(CNode* pnode, CConnman& connman) { + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + if(pnode->nVersion >= GOVERNANCE_FILTER_PROTO_VERSION) { CBloomFilter filter; filter.clear(); - connman.PushMessage(pnode, NetMsgType::DNGOVERNANCESYNC, uint256(), filter); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DNGOVERNANCESYNC, uint256(), filter)); } else { - connman.PushMessage(pnode, NetMsgType::DNGOVERNANCESYNC, uint256()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DNGOVERNANCESYNC, uint256())); } } @@ -490,6 +485,11 @@ void CDynodeSync::UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDow pindexNew->nHeight, pindexBestHeader->nHeight, fInitialDownload, fReachedBestHeader); if (!IsBlockchainSynced() && fReachedBestHeader) { + if (fLiteMode) { + // nothing to do in lite mode, just finish the process immediately + nRequestedDynodeAssets = DYNODE_SYNC_FINISHED; + return; + } // Reached best header while being in initial mode. // We must be at the tip already, let's move to the next asset. SwitchToNextAsset(connman); diff --git a/src/dynode-sync.h b/src/dynode-sync.h index 571326ce77..b0c1adfa7f 100644 --- a/src/dynode-sync.h +++ b/src/dynode-sync.h @@ -24,7 +24,7 @@ static const int DYNODE_SYNC_GOVOBJ_VOTE = 11; static const int DYNODE_SYNC_FINISHED = 999; static const int DYNODE_SYNC_TICK_SECONDS = 6; -static const int DYNODE_SYNC_TIMEOUT_SECONDS = 10; // our blocks are 64 seconds, this needs to be fast +static const int DYNODE_SYNC_TIMEOUT_SECONDS = 25; static const int DYNODE_SYNC_ENOUGH_PEERS = 10; @@ -52,7 +52,6 @@ class CDynodeSync int64_t nTimeLastFailure; void Fail(); - void ClearFulfilledRequests(CConnman& connman); public: CDynodeSync() { Reset(); } @@ -67,20 +66,22 @@ class CDynodeSync int GetAssetID() { return nRequestedDynodeAssets; } int GetAttempt() { return nRequestedDynodeAttempt; } - - void BumpAssetLastTime(std::string strFuncName); + void BumpAssetLastTime(const std::string strFuncName); + int64_t GetAssetStartTime() { return nTimeAssetSyncStarted; } std::string GetAssetName(); std::string GetSyncStatus(); void Reset(); void SwitchToNextAsset(CConnman& connman); - void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); + void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv); void ProcessTick(CConnman& connman); void AcceptedBlockHeader(const CBlockIndex *pindexNew); void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload, CConnman& connman); void UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload, CConnman& connman); + + void DoMaintenance(CConnman &connman) { ProcessTick(connman); } }; #endif // DYNAMIC_DYNODE_SYNC_H diff --git a/src/dynode.cpp b/src/dynode.cpp index a91caa6406..7c1bd633bb 100644 --- a/src/dynode.cpp +++ b/src/dynode.cpp @@ -49,7 +49,7 @@ CDynode::CDynode(const CDynode& other) : CDynode::CDynode(const CDynodeBroadcast& dnb) : dynode_info_t{ dnb.nActiveState, dnb.nProtocolVersion, dnb.sigTime, - dnb.vin.prevout, dnb.addr, dnb.pubKeyCollateralAddress, dnb.pubKeyDynode}, + dnb.outpoint, dnb.addr, dnb.pubKeyCollateralAddress, dnb.pubKeyDynode}, lastPing(dnb.lastPing), vchSig(dnb.vchSig), fAllowMixingTx(true) @@ -71,7 +71,7 @@ bool CDynode::UpdateFromNewBroadcast(CDynodeBroadcast& dnb, CConnman& connman) nPoSeBanHeight = 0; nTimeLastChecked = 0; int nDos = 0; - if(dnb.lastPing == CDynodePing() || (dnb.lastPing != CDynodePing() && dnb.lastPing.CheckAndUpdate(this, true, nDos, connman))) { + if(!dnb.lastPing || (dnb.lastPing && dnb.lastPing.CheckAndUpdate(this, true, nDos, connman))) { lastPing = dnb.lastPing; dnodeman.mapSeenDynodePing.insert(std::make_pair(lastPing.GetHash(), lastPing)); } @@ -96,11 +96,11 @@ bool CDynode::UpdateFromNewBroadcast(CDynodeBroadcast& dnb, CConnman& connman) // the proof of work for that block. The further away they are the better, the furthest will win the election // and get paid this block // -arith_uint256 CDynode::CalculateScore(const uint256& blockHash) +arith_uint256 CDynode::CalculateScore(const uint256& blockHash) const { // Deterministically calculate a "score" for a Dynode based on any given (block)hash CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << vin.prevout << nCollateralMinConfBlockHash << blockHash; + ss << outpoint << nCollateralMinConfBlockHash << blockHash; return UintToArith256(ss.GetHash()); } @@ -141,20 +141,17 @@ void CDynode::Check(bool fForce) if(!fForce && (GetTime() - nTimeLastChecked < DYNODE_CHECK_SECONDS)) return; nTimeLastChecked = GetTime(); - LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state\n", vin.prevout.ToStringShort(), GetStateString()); + LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state\n", outpoint.ToStringShort(), GetStateString()); //once spent, stop doing the checks if(IsOutpointSpent()) return; int nHeight = 0; if(!fUnitTest) { - TRY_LOCK(cs_main, lockMain); - if(!lockMain) return; - Coin coin; - if(!GetUTXOCoin(vin.prevout, coin)) { + if(!GetUTXOCoin(outpoint, coin)) { nActiveState = DYNODE_OUTPOINT_SPENT; - LogPrint("Dynode", "CDynode::Check -- Failed to find Dynode UTXO, Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynode::Check -- Failed to find Dynode UTXO, dynode=%s\n", outpoint.ToStringShort()); return; } @@ -166,13 +163,13 @@ void CDynode::Check(bool fForce) // Otherwise give it a chance to proceed further to do all the usual checks and to change its state. // Dynode still will be on the edge and can be banned back easily if it keeps ignoring dnverify // or connect attempts. Will require few dnverify messages to strengthen its position in dn list. - LogPrintf("CDynode::Check -- Dynode %s is unbanned and back in list now\n", vin.prevout.ToStringShort()); + LogPrintf("CDynode::Check -- Dynode %s is unbanned and back in list now\n", outpoint.ToStringShort()); DecreasePoSeBanScore(); } else if(nPoSeBanScore >= DYNODE_POSE_BAN_MAX_SCORE) { nActiveState = DYNODE_POSE_BAN; // ban for the whole payment cycle nPoSeBanHeight = nHeight + dnodeman.size(); - LogPrintf("CDynode::Check -- Dynode %s is banned till block %d now\n", vin.prevout.ToStringShort(), nPoSeBanHeight); + LogPrintf("CDynode::Check -- Dynode %s is banned till block %d now\n", outpoint.ToStringShort(), nPoSeBanHeight); return; } @@ -186,7 +183,7 @@ void CDynode::Check(bool fForce) if(fRequireUpdate) { nActiveState = DYNODE_UPDATE_REQUIRED; if(nActiveStatePrev != nActiveState) { - LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); + LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } @@ -197,7 +194,7 @@ void CDynode::Check(bool fForce) if(fWaitForPing && !fOurDynode) { // ...but if it was already expired before the initial check - return right away if(IsExpired() || IsSentinelPingExpired() || IsNewStartRequired()) { - LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state, waiting for ping\n", vin.prevout.ToStringShort(), GetStateString()); + LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state, waiting for ping\n", outpoint.ToStringShort(), GetStateString()); return; } } @@ -208,7 +205,7 @@ void CDynode::Check(bool fForce) if(!IsPingedWithin(DYNODE_NEW_START_REQUIRED_SECONDS)) { nActiveState = DYNODE_NEW_START_REQUIRED; if(nActiveStatePrev != nActiveState) { - LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); + LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } @@ -216,7 +213,7 @@ void CDynode::Check(bool fForce) if(!IsPingedWithin(DYNODE_EXPIRATION_SECONDS)) { nActiveState = DYNODE_EXPIRED; if(nActiveStatePrev != nActiveState) { - LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); + LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } @@ -225,14 +222,30 @@ void CDynode::Check(bool fForce) if(lastPing.sigTime - sigTime < DYNODE_MIN_DNP_SECONDS) { nActiveState = DYNODE_PRE_ENABLED; if(nActiveStatePrev != nActiveState) { - LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); + LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } return; } nActiveState = DYNODE_ENABLED; // OK if(nActiveStatePrev != nActiveState) { - LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", vin.prevout.ToStringShort(), GetStateString()); + LogPrint("Dynode", "CDynode::Check -- Dynode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); + } + + // We require DNs to be in PRE_ENABLED until they either start to expire or receive a ping and go into ENABLED state + // Works on mainnet/testnet only and not the case on regtest/devnet. + if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { + if (lastPing.sigTime - sigTime < DYNODE_MIN_DNP_SECONDS) { + nActiveState = DYNODE_PRE_ENABLED; + if (nActiveStatePrev != nActiveState) { + LogPrint("dynode", "CDynode::Check -- Dynode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); + } + return; + } + } + nActiveState = DYNODE_ENABLED; // OK + if(nActiveStatePrev != nActiveState) { + LogPrint("dynode", "CDynode::Check -- Dynode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString()); } } @@ -249,7 +262,7 @@ bool CDynode::IsValidNetAddr(CService addrIn) (addrIn.IsIPv4() && !addrIn.IsIPv6() && IsReachable(addrIn) && addrIn.IsRoutable()); } -dynode_info_t CDynode::GetInfo() +dynode_info_t CDynode::GetInfo() const { dynode_info_t info{*this}; info.nTimeLastPing = lastPing.sigTime; @@ -265,10 +278,10 @@ std::string CDynode::StateToString(int nStateIn) case DYNODE_EXPIRED: return "EXPIRED"; case DYNODE_OUTPOINT_SPENT: return "OUTPOINT_SPENT"; case DYNODE_UPDATE_REQUIRED: return "UPDATE_REQUIRED"; - case DYNODE_SENTINEL_PING_EXPIRED: return "SENTINEL_PING_EXPIRED"; + case DYNODE_SENTINEL_PING_EXPIRED: return "SENTINEL_PING_EXPIRED"; case DYNODE_NEW_START_REQUIRED: return "NEW_START_REQUIRED"; case DYNODE_POSE_BAN: return "POSE_BAN"; - default: return "UNKNOWN"; + default: return "UNKNOWN"; } } @@ -304,16 +317,16 @@ void CDynode::UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack CAmount nDynodePayment = GetFluidDynodeReward(BlockReading->nHeight); - BOOST_FOREACH(CTxOut txout, block.vtx[0].vout) + for (const auto& txout : block.vtx[0]->vout) if(dnpayee == txout.scriptPubKey && nDynodePayment == txout.nValue) { nBlockLastPaid = BlockReading->nHeight; nTimeLastPaid = BlockReading->nTime; - LogPrint("Dynode", "CDynode::UpdateLastPaidBlock -- searching for block with payment to %s -- found new %d\n", vin.prevout.ToStringShort(), nBlockLastPaid); + LogPrint("Dynode", "CDynode::UpdateLastPaidBlock -- searching for block with payment to %s -- found new %d\n", outpoint.ToStringShort(), nBlockLastPaid); return; } } - if (BlockReading->pprev == NULL) { assert(BlockReading); break; } + if (BlockReading->pprev == nullptr) { assert(BlockReading); break; } BlockReading = BlockReading->pprev; } @@ -323,7 +336,7 @@ void CDynode::UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack } #ifdef ENABLE_WALLET -bool CDynodeBroadcast::Create(std::string strService, std::string strKeyDynode, std::string strTxHash, std::string strOutputIndex, std::string& strErrorRet, CDynodeBroadcast &dnbRet, bool fOffline) +bool CDynodeBroadcast::Create(const std::string strService, const std::string strKeyDynode, const std::string strTxHash, const std::string strOutputIndex, std::string& strErrorRet, CDynodeBroadcast &dnbRet, bool fOffline) { COutPoint outpoint; CPubKey pubKeyCollateralAddressNew; @@ -388,12 +401,9 @@ bool CDynodeBroadcast::Create(const COutPoint& outpoint, const CService& service return Log(strprintf("Invalid IP address, dynode=%s", outpoint.ToStringShort())); dnbRet.lastPing = dnp; - if(!dnbRet.Sign(keyCollateralAddressNew)) { + if (!dnbRet.Sign(keyCollateralAddressNew)) return Log(strprintf("Failed to sign broadcast, dynode=%s", outpoint.ToStringShort())); - LogPrintf("CDynodeBroadcast::Create -- %s\n", strErrorRet); - dnbRet = CDynodeBroadcast(); - return false; - } + return true; } @@ -408,25 +418,25 @@ bool CDynodeBroadcast::SimpleCheck(int& nDos) // make sure addr is valid if(!IsValidNetAddr()) { LogPrintf("CDynodeBroadcast::SimpleCheck -- Invalid addr, rejected: Dynode=%s addr=%s\n", - vin.prevout.ToStringShort(), addr.ToString()); + outpoint.ToStringShort(), addr.ToString()); return false; } // make sure signature isn't in the future (past is OK) if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("CDynodeBroadcast::SimpleCheck -- Signature rejected, too far into the future: Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrintf("CDynodeBroadcast::SimpleCheck -- Signature rejected, too far into the future: Dynode=%s\n", outpoint.ToStringShort()); nDos = 1; return false; } // empty ping or incorrect sigTime/unknown blockhash - if(lastPing == CDynodePing() || !lastPing.SimpleCheck(nDos)) { + if(!lastPing || !lastPing.SimpleCheck(nDos)) { // one of us is probably forked or smth, just mark it as expired and check the rest of the rules nActiveState = DYNODE_EXPIRED; } if(nProtocolVersion < dnpayments.GetMinDynodePaymentsProto()) { - LogPrintf("CDynodeBroadcast::SimpleCheck -- outdated Dynode: Dynode=%s nProtocolVersion=%d\n", vin.prevout.ToStringShort(), nProtocolVersion); + LogPrintf("CDynodeBroadcast::SimpleCheck -- outdated Dynode: Dynode=%s nProtocolVersion=%d\n", outpoint.ToStringShort(), nProtocolVersion); nActiveState = DYNODE_UPDATE_REQUIRED; } @@ -448,13 +458,7 @@ bool CDynodeBroadcast::SimpleCheck(int& nDos) return false; } - if(!vin.scriptSig.empty()) { - LogPrintf("CDynodeBroadcast::SimpleCheck -- Ignore Not Empty ScriptSig %s\n",vin.ToString()); - nDos = 100; - return false; - } - - int mainnetDefaultPort = DEFAULT_P2P_PORT; + int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort(); if(Params().NetworkIDString() == CBaseChainParams::MAIN) { if(addr.GetPort() != mainnetDefaultPort) return false; } else if(addr.GetPort() == mainnetDefaultPort) return false; @@ -478,7 +482,7 @@ bool CDynodeBroadcast::Update(CDynode* pdn, int& nDos, CConnman& connman) // unless someone is doing something fishy if(pdn->sigTime > sigTime) { LogPrintf("CDynodeBroadcast::Update -- Bad sigTime %d (existing broadcast is at %d) for Dynode %s %s\n", - sigTime, pdn->sigTime, vin.prevout.ToStringShort(), addr.ToString()); + sigTime, pdn->sigTime, outpoint.ToStringShort(), addr.ToString()); return false; } @@ -486,7 +490,7 @@ bool CDynodeBroadcast::Update(CDynode* pdn, int& nDos, CConnman& connman) // Dynode is banned by PoSe if(pdn->IsPoSeBanned()) { - LogPrintf("CDynodeBroadcast::Update -- Banned by PoSe, Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrintf("CDynodeBroadcast::Update -- Banned by PoSe, Dynode=%s\n", outpoint.ToStringShort()); return false; } @@ -497,12 +501,8 @@ bool CDynodeBroadcast::Update(CDynode* pdn, int& nDos, CConnman& connman) return false; } - AssertLockHeld(cs_main); - - int nHeight; - CollateralStatus err = CheckCollateral(vin.prevout, pubKeyCollateralAddress, nHeight); - if (err == COLLATERAL_UTXO_NOT_FOUND) { - LogPrint("dynode", "CDynodeBroadcast::CheckOutpoint -- Failed to find Dynode UTXO, dynode=%s\n", vin.prevout.ToStringShort()); + if (!CheckSignature(nDos)) { + LogPrintf("CDynodeBroadcast::Update -- CheckSignature() failed, dynode=%s\n", outpoint.ToStringShort()); return false; } @@ -524,35 +524,34 @@ bool CDynodeBroadcast::CheckOutpoint(int& nDos) { // we are a Dynode with the same vin (i.e. already activated) and this dnb is ours (matches our Dynodes privkey) // so nothing to do here for us - if(fDynodeMode && vin.prevout == activeDynode.outpoint && pubKeyDynode == activeDynode.pubKeyDynode) { + if(fDynodeMode && outpoint == activeDynode.outpoint && pubKeyDynode == activeDynode.pubKeyDynode) { return false; } - AssertLockHeld(cs_main); int nHeight; - CollateralStatus err = CheckCollateral(vin.prevout, pubKeyCollateralAddress, nHeight); + CollateralStatus err = CheckCollateral(outpoint, pubKeyCollateralAddress, nHeight); if (err == COLLATERAL_UTXO_NOT_FOUND) { - LogPrint("dynode", "CDynodeBroadcast::CheckOutpoint -- Failed to find Dynode UTXO, dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeBroadcast::CheckOutpoint -- Failed to find Dynode UTXO, dynode=%s\n", outpoint.ToStringShort()); return false; } if (err == COLLATERAL_INVALID_AMOUNT) { - LogPrint("dynode", "CDynodeBroadcast::CheckOutpoint -- Dynode UTXO should have 1000 DYN, dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeBroadcast::CheckOutpoint -- Dynode UTXO should have 1000 DYN, dynode=%s\n", outpoint.ToStringShort()); nDos = 33; return false; } if(err == COLLATERAL_INVALID_PUBKEY) { - LogPrint("dynode", "CDynodeBroadcast::CheckOutpoint -- Dynode UTXO should match pubKeyCollateralAddress, dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeBroadcast::CheckOutpoint -- Dynode UTXO should match pubKeyCollateralAddress, dynode=%s\n", outpoint.ToStringShort()); nDos = 33; return false; } if(chainActive.Height() - nHeight + 1 < Params().GetConsensus().nDynodeMinimumConfirmations) { LogPrintf("CDynodeBroadcast::CheckOutpoint -- Dynode UTXO must have at least %d confirmations, dynode=%s\n", - Params().GetConsensus().nDynodeMinimumConfirmations, vin.prevout.ToStringShort()); + Params().GetConsensus().nDynodeMinimumConfirmations, outpoint.ToStringShort()); // UTXO is legit but has not enough confirmations. // Maybe we miss few blocks, let this dnb be checked again later. dnodeman.mapSeenDynodeBroadcast.erase(GetHash()); @@ -567,12 +566,12 @@ bool CDynodeBroadcast::CheckOutpoint(int& nDos) CBlockIndex* pRequredConfIndex = chainActive[nHeight + Params().GetConsensus().nDynodeMinimumConfirmations - 1]; // block where tx got nDynodeMinimumConfirmations if(pRequredConfIndex->GetBlockTime() > sigTime) { LogPrintf("CDynodeBroadcast::CheckOutpoint -- Bad sigTime %d (%d conf block is at %d) for Dynode %s %s\n", - sigTime, Params().GetConsensus().nDynodeMinimumConfirmations, pRequredConfIndex->GetBlockTime(), vin.prevout.ToStringShort(), addr.ToString()); + sigTime, Params().GetConsensus().nDynodeMinimumConfirmations, pRequredConfIndex->GetBlockTime(), outpoint.ToStringShort(), addr.ToString()); return false; } if (!CheckSignature(nDos)) { - LogPrintf("CDynodeBroadcast::CheckOutpoint -- CheckSignature() failed, dynode=%s\n", vin.prevout.ToStringShort()); + LogPrintf("CDynodeBroadcast::CheckOutpoint -- CheckSignature() failed, dynode=%s\n", outpoint.ToStringShort()); return false; } @@ -582,67 +581,104 @@ bool CDynodeBroadcast::CheckOutpoint(int& nDos) return true; } -bool CDynodeBroadcast::IsVinAssociatedWithPubkey(const CTxIn& txin, const CPubKey& pubkey) +uint256 CDynodeBroadcast::GetHash() const { - CScript payee; - payee = GetScriptForDestination(pubkey.GetID()); + // Note: doesn't match serialization - CTransaction tx; - uint256 hash; - if(GetTransaction(txin.prevout.hash, tx, Params().GetConsensus(), hash, true)) { - BOOST_FOREACH(CTxOut out, tx.vout) - if(out.nValue == 1000*COIN && out.scriptPubKey == payee) return true; - } + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << outpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing format + ss << pubKeyCollateralAddress; + ss << sigTime; + return ss.GetHash(); +} - return false; +uint256 CDynodeBroadcast::GetSignatureHash() const +{ + // TODO: replace with "return SerializeHash(*this);" after migration to 70100 + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << outpoint; + ss << addr; + ss << pubKeyCollateralAddress; + ss << pubKeyDynode; + ss << sigTime; + ss << nProtocolVersion; + return ss.GetHash(); } bool CDynodeBroadcast::Sign(const CKey& keyCollateralAddress) { std::string strError; - std::string strMessage; sigTime = GetAdjustedTime(); - strMessage = addr.ToString(false) + boost::lexical_cast(sigTime) + - pubKeyCollateralAddress.GetID().ToString() + pubKeyDynode.GetID().ToString() + - boost::lexical_cast(nProtocolVersion); + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); - if(!CMessageSigner::SignMessage(strMessage, vchSig, keyCollateralAddress)) { - LogPrintf("CDynodeBroadcast::Sign -- SignMessage() failed\n"); - return false; - } + if (!CHashSigner::SignHash(hash, keyCollateralAddress, vchSig)) { + LogPrintf("CDynodeBroadcast::Sign -- SignHash() failed\n"); + return false; + } - if(!CMessageSigner::VerifyMessage(pubKeyCollateralAddress, vchSig, strMessage, strError)) { - LogPrintf("CDynodeBroadcast::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; + if (!CHashSigner::VerifyHash(hash, pubKeyCollateralAddress, vchSig, strError)) { + LogPrintf("CDynodeBroadcast::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = addr.ToString(false) + std::to_string(sigTime) + + pubKeyCollateralAddress.GetID().ToString() + pubKeyDynode.GetID().ToString() + + std::to_string(nProtocolVersion); + + if (!CMessageSigner::SignMessage(strMessage, vchSig, keyCollateralAddress)) { + LogPrintf("CDynodeBroadcast::Sign -- SignMessage() failed\n"); + return false; + } + + if (!CMessageSigner::VerifyMessage(pubKeyCollateralAddress, vchSig, strMessage, strError)) { + LogPrintf("CDynodeBroadcast::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } return true; } -bool CDynodeBroadcast::CheckSignature(int& nDos) +bool CDynodeBroadcast::CheckSignature(int& nDos) const { - std::string strMessage; std::string strError = ""; nDos = 0; - strMessage = addr.ToString(false) + boost::lexical_cast(sigTime) + - pubKeyCollateralAddress.GetID().ToString() + pubKeyDynode.GetID().ToString() + - boost::lexical_cast(nProtocolVersion); + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); - LogPrint("Dynode", "CDynodeBroadcast::CheckSignature -- strMessage: %s pubKeyCollateralAddress address: %s sig: %s\n", strMessage, CDynamicAddress(pubKeyCollateralAddress.GetID()).ToString(), EncodeBase64(&vchSig[0], vchSig.size())); + if (!CHashSigner::VerifyHash(hash, pubKeyCollateralAddress, vchSig, strError)) { + // maybe it's in old format + std::string strMessage = addr.ToString(false) + std::to_string(sigTime) + + pubKeyCollateralAddress.GetID().ToString() + pubKeyDynode.GetID().ToString() + + std::to_string(nProtocolVersion); - if(!CMessageSigner::VerifyMessage(pubKeyCollateralAddress, vchSig, strMessage, strError)){ - LogPrintf("CDynodeBroadcast::CheckSignature -- Got bad Dynode announce signature, error: %s\n", strError); - nDos = 100; - return false; + if (!CMessageSigner::VerifyMessage(pubKeyCollateralAddress, vchSig, strMessage, strError)){ + // nope, not in old format either + LogPrintf("CDynodeBroadcast::CheckSignature -- Got bad Dynode announce signature, error: %s\n", strError); + nDos = 100; + return false; + } + } + } else { + std::string strMessage = addr.ToString(false) + std::to_string(sigTime) + + pubKeyCollateralAddress.GetID().ToString() + pubKeyDynode.GetID().ToString() + + std::to_string(nProtocolVersion); + + if (!CMessageSigner::VerifyMessage(pubKeyCollateralAddress, vchSig, strMessage, strError)){ + LogPrintf("CDynodeBroadcast::CheckSignature -- Got bad Dynode announce signature, error: %s\n", strError); + nDos = 100; + return false; + } } return true; } -void CDynodeBroadcast::Relay(CConnman& connman) +void CDynodeBroadcast::Relay(CConnman& connman) const { // Do not relay until fully synced if(!dynodeSync.IsSynced()) { @@ -654,50 +690,107 @@ void CDynodeBroadcast::Relay(CConnman& connman) connman.RelayInv(inv); } +uint256 CDynodePing::GetHash() const +{ + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + // TODO: replace with "return SerializeHash(*this);" after migration to 70100 + ss << dynodeOutpoint; + ss << blockHash; + ss << sigTime; + ss << fSentinelIsCurrent; + ss << nSentinelVersion; + ss << nDaemonVersion; + } else { + // Note: doesn't match serialization + + ss << dynodeOutpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing format + ss << sigTime; + } + return ss.GetHash(); +} + +uint256 CDynodePing::GetSignatureHash() const +{ + return GetHash(); +} + CDynodePing::CDynodePing(const COutPoint& outpoint) { LOCK(cs_main); if (!chainActive.Tip() || chainActive.Height() < 12) return; - vin = CTxIn(outpoint); + dynodeOutpoint = outpoint; blockHash = chainActive[chainActive.Height() - 12]->GetBlockHash(); sigTime = GetAdjustedTime(); + nDaemonVersion = CLIENT_VERSION; } bool CDynodePing::Sign(const CKey& keyDynode, const CPubKey& pubKeyDynode) { std::string strError; - std::string strDyNodeSignMessage; - // TODO: add sentinel data sigTime = GetAdjustedTime(); - std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast(sigTime); - if(!CMessageSigner::SignMessage(strMessage, vchSig, keyDynode)) { - LogPrintf("CDynodePing::Sign -- SignMessage() failed\n"); - return false; - } + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); - if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CDynodePing::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; + if (!CHashSigner::SignHash(hash, keyDynode, vchSig)) { + LogPrintf("CDynodePing::Sign -- SignHash() failed\n"); + return false; + } + + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + LogPrintf("CDynodePing::Sign -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = CTxIn(dynodeOutpoint).ToString() + blockHash.ToString() + + std::to_string(sigTime); + + if (!CMessageSigner::SignMessage(strMessage, vchSig, keyDynode)) { + LogPrintf("CDynodePing::Sign -- SignMessage() failed\n"); + return false; + } + + if (!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CDynodePing::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } return true; } -bool CDynodePing::CheckSignature(CPubKey& pubKeyDynode, int &nDos) +bool CDynodePing::CheckSignature(const CPubKey& pubKeyDynode, int &nDos) const { - // TODO: add sentinel data - std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast(sigTime); std::string strError = ""; nDos = 0; - if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CDynodePing::CheckSignature -- Got bad Dynode ping signature, Dynode=%s, error: %s\n", vin.prevout.ToStringShort(), strError); - nDos = 33; - return false; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + std::string strMessage = CTxIn(dynodeOutpoint).ToString() + blockHash.ToString() + + std::to_string(sigTime); + + if (!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CDynodePing::CheckSignature -- Got bad Dynode ping signature, dynode=%s, error: %s\n", dynodeOutpoint.ToStringShort(), strError); + nDos = 33; + return false; + } + } + } else { + std::string strMessage = CTxIn(dynodeOutpoint).ToString() + blockHash.ToString() + + std::to_string(sigTime); + + if (!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CDynodePing::CheckSignature -- Got bad Dynode ping signature, dynode=%s, error: %s\n", dynodeOutpoint.ToStringShort(), strError); + nDos = 33; + return false; + } } + return true; } @@ -708,7 +801,7 @@ bool CDynodePing::SimpleCheck(int& nDos) nDos = 0; if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("CDynodePing::SimpleCheck -- Signature rejected, too far into the future, Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrintf("CDynodePing::SimpleCheck -- Signature rejected, too far into the future, Dynode=%s\n", dynodeOutpoint.ToStringShort()); nDos = 1; return false; } @@ -717,13 +810,13 @@ bool CDynodePing::SimpleCheck(int& nDos) AssertLockHeld(cs_main); BlockMap::iterator mi = mapBlockIndex.find(blockHash); if (mi == mapBlockIndex.end()) { - LogPrint("Dynode", "DynodePing::SimpleCheck -- Dynode ping is invalid, unknown block hash: Dynode=%s blockHash=%s\n", vin.prevout.ToStringShort(), blockHash.ToString()); + LogPrint("Dynode", "DynodePing::SimpleCheck -- Dynode ping is invalid, unknown block hash: Dynode=%s blockHash=%s\n", dynodeOutpoint.ToStringShort(), blockHash.ToString()); // maybe we stuck or forked so we shouldn't ban this node, just fail to accept this ping // TODO: or should we also request this block? return false; } } - LogPrint("Dynode", "CDynodePing::SimpleCheck -- Dynode ping verified: Dynode=%s blockHash=%s sigTime=%d\n", vin.prevout.ToStringShort(), blockHash.ToString(), sigTime); + LogPrint("Dynode", "CDynodePing::SimpleCheck -- Dynode ping verified: Dynode=%s blockHash=%s sigTime=%d\n", dynodeOutpoint.ToStringShort(), blockHash.ToString(), sigTime); return true; } @@ -738,30 +831,39 @@ bool CDynodePing::SimpleCheck(int& nDos) return false; } - if (pdn == NULL) { - LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Couldn't find Dynode entry, Dynode=%s\n", vin.prevout.ToStringShort()); + if (pdn == nullptr) { + LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Couldn't find Dynode entry, Dynode=%s\n", dynodeOutpoint.ToStringShort()); return false; } if(!fFromNewBroadcast) { if (pdn->IsUpdateRequired()) { - LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode protocol is outdated, Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode protocol is outdated, Dynode=%s\n", dynodeOutpoint.ToStringShort()); return false; } if (pdn->IsNewStartRequired()) { - LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode is completely expired, new start is required, Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode is completely expired, new start is required, Dynode=%s\n", dynodeOutpoint.ToStringShort()); return false; } } - LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- New ping: Dynode=%s blockHash=%s sigTime=%d\n", vin.prevout.ToStringShort(), blockHash.ToString(), sigTime); + { + BlockMap::iterator mi = mapBlockIndex.find(blockHash); + if ((*mi).second && (*mi).second->nHeight < chainActive.Height() - 24) { + LogPrintf("CDynodePing::CheckAndUpdate -- Dynode ping is invalid, block hash is too old: dynode=%s blockHash=%s\n", dynodeOutpoint.ToStringShort(), blockHash.ToString()); + // nDos = 1; + return false; + } + } + + LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- New ping: Dynode=%s blockHash=%s sigTime=%d\n", dynodeOutpoint.ToStringShort(), blockHash.ToString(), sigTime); // LogPrintf("dnping - Found corresponding dn for vin: %s\n", vin.prevout.ToStringShort()); // update only if there is no known ping for this Dynode or // last ping was more then DYNODE_MIN_DNP_SECONDS-60 ago comparing to this one if (pdn->IsPingedWithin(DYNODE_MIN_DNP_SECONDS - 60, sigTime)) { - LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode ping arrived too early, Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode ping arrived too early, Dynode=%s\n", dynodeOutpoint.ToStringShort()); //nDos = 1; //disable, this is happening frequently and causing banned peers return false; } @@ -774,12 +876,12 @@ bool CDynodePing::SimpleCheck(int& nDos) // (NOTE: assuming that DYNODE_EXPIRATION_SECONDS/2 should be enough to finish dn list sync) if(!dynodeSync.IsDynodeListSynced() && !pdn->IsPingedWithin(DYNODE_EXPIRATION_SECONDS/2)) { // let's bump sync timeout - LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- bumping sync timeout, dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- bumping sync timeout, dynode=%s\n", dynodeOutpoint.ToStringShort()); dynodeSync.BumpAssetLastTime("CDynodePing::CheckAndUpdate"); } // let's store this ping as the last one - LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode ping accepted, Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode ping accepted, Dynode=%s\n", dynodeOutpoint.ToStringShort()); pdn->lastPing = *this; // and update dnodeman.mapSeenDynodeBroadcast.lastPing which is probably outdated @@ -794,7 +896,7 @@ bool CDynodePing::SimpleCheck(int& nDos) // relay ping for nodes in ENABLED/EXPIRED/SENTINEL_PING_EXPIRED state only, skip everyone else if (!pdn->IsEnabled() && !pdn->IsExpired() && !pdn->IsSentinelPingExpired()) return false; - LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode ping acceepted and relayed, Dynode=%s\n", vin.prevout.ToStringShort()); + LogPrint("Dynode", "CDynodePing::CheckAndUpdate -- Dynode ping acceepted and relayed, Dynode=%s\n", dynodeOutpoint.ToStringShort()); Relay(connman); return true; diff --git a/src/dynode.h b/src/dynode.h index 48389d7f93..4f786b9504 100644 --- a/src/dynode.h +++ b/src/dynode.h @@ -28,17 +28,20 @@ static const int DYNODE_POSE_BAN_MAX_SCORE = 5; // sentinel version before sentinel ping implementation #define DEFAULT_SENTINEL_VERSION 0x010001 +// daemon version before implementation of nDaemonVersion in CDynodePing +#define DEFAULT_DAEMON_VERSION 203050 class CDynodePing { public: - CTxIn vin{}; + COutPoint dynodeOutpoint{}; uint256 blockHash{}; int64_t sigTime{}; //dnb message times std::vector vchSig{}; bool fSentinelIsCurrent = false; // true if last sentinel ping was actual // DSB is always 0, other 3 bits corresponds to x.x.x version scheme uint32_t nSentinelVersion{DEFAULT_SENTINEL_VERSION}; + uint32_t nDaemonVersion{DEFAULT_DAEMON_VERSION}; CDynodePing() = default; @@ -48,46 +51,71 @@ class CDynodePing template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(vin); + int nVersion = s.GetVersion(); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn txin{}; + if (ser_action.ForRead()) { + READWRITE(txin); + dynodeOutpoint = txin.prevout; + } else { + txin = CTxIn(dynodeOutpoint); + READWRITE(txin); + } + } else { + // using new format directly + READWRITE(dynodeOutpoint); + } READWRITE(blockHash); READWRITE(sigTime); - READWRITE(vchSig); - if(ser_action.ForRead() && (s.size() == 0)) - { + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(vchSig); + } + if(ser_action.ForRead() && s.size() == 0) { + // TODO: drop this after migration to 70100 fSentinelIsCurrent = false; nSentinelVersion = DEFAULT_SENTINEL_VERSION; - return; + nDaemonVersion = DEFAULT_DAEMON_VERSION; + return; } READWRITE(fSentinelIsCurrent); READWRITE(nSentinelVersion); + if(ser_action.ForRead() && s.size() == 0) { + // TODO: drop this after migration to 70100 + nDaemonVersion = DEFAULT_DAEMON_VERSION; + return; + } + if (!(nVersion == 70900 && (s.GetType() & SER_NETWORK))) { + READWRITE(nDaemonVersion); + } } - uint256 GetHash() const - { - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << vin; - ss << sigTime; - return ss.GetHash(); - } + uint256 GetHash() const; + uint256 GetSignatureHash() const; bool IsExpired() const { return GetAdjustedTime() - sigTime > DYNODE_NEW_START_REQUIRED_SECONDS; } bool Sign(const CKey& keyDynode, const CPubKey& pubKeyDynode); - bool CheckSignature(CPubKey& pubKeyDynode, int &nDos); + bool CheckSignature(const CPubKey& pubKeyDynode, int &nDos) const; bool SimpleCheck(int& nDos); bool CheckAndUpdate(CDynode* pdn, bool fFromNewBroadcast, int& nDos, CConnman& connman); void Relay(CConnman& connman); + explicit operator bool() const; }; inline bool operator==(const CDynodePing& a, const CDynodePing& b) { - return a.vin == b.vin && a.blockHash == b.blockHash; + return a.dynodeOutpoint == b.dynodeOutpoint && a.blockHash == b.blockHash; } inline bool operator!=(const CDynodePing& a, const CDynodePing& b) { return !(a == b); } +inline CDynodePing::operator bool() const +{ + return *this != CDynodePing(); +} struct dynode_info_t { @@ -100,17 +128,17 @@ struct dynode_info_t nActiveState{activeState}, nProtocolVersion{protoVer}, sigTime{sTime} {} dynode_info_t(int activeState, int protoVer, int64_t sTime, - COutPoint const& outpoint, CService const& addr, + COutPoint const& outpnt, CService const& addr, CPubKey const& pkCollAddr, CPubKey const& pkDN) : nActiveState{activeState}, nProtocolVersion{protoVer}, sigTime{sTime}, - vin{outpoint}, addr{addr}, + outpoint{outpnt}, addr{addr}, pubKeyCollateralAddress{pkCollAddr}, pubKeyDynode{pkDN} {} int nActiveState = 0; int nProtocolVersion = 0; int64_t sigTime = 0; //dnb message time - CTxIn vin{}; + COutPoint outpoint{}; CService addr{}; CPubKey pubKeyCollateralAddress{}; CPubKey pubKeyDynode{}; @@ -175,7 +203,21 @@ class CDynode : public dynode_info_t template inline void SerializationOp(Stream& s, Operation ser_action) { LOCK(cs); - READWRITE(vin); + int nVersion = s.GetVersion(); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn txin{}; + if (ser_action.ForRead()) { + READWRITE(txin); + outpoint = txin.prevout; + } else { + txin = CTxIn(outpoint); + READWRITE(txin); + } + } else { + // using new format directly + READWRITE(outpoint); + } READWRITE(addr); READWRITE(pubKeyCollateralAddress); READWRITE(pubKeyDynode); @@ -197,7 +239,7 @@ class CDynode : public dynode_info_t } // CALCULATE A RANK AGAINST OF GIVEN BLOCK - arith_uint256 CalculateScore(const uint256& blockHash); + arith_uint256 CalculateScore(const uint256& blockHash) const; bool UpdateFromNewBroadcast(CDynodeBroadcast& dnb, CConnman& connman); @@ -209,7 +251,7 @@ class CDynode : public dynode_info_t bool IsPingedWithin(int nSeconds, int64_t nTimeToCheckAt = -1) { - if(lastPing == CDynodePing()) return false; + if(!lastPing) return false; if(nTimeToCheckAt == -1) { nTimeToCheckAt = GetAdjustedTime(); @@ -217,16 +259,16 @@ class CDynode : public dynode_info_t return nTimeToCheckAt - lastPing.sigTime < nSeconds; } - bool IsEnabled() { return nActiveState == DYNODE_ENABLED; } - bool IsPreEnabled() { return nActiveState == DYNODE_PRE_ENABLED; } - bool IsPoSeBanned() { return nActiveState == DYNODE_POSE_BAN; } + bool IsEnabled() const { return nActiveState == DYNODE_ENABLED; } + bool IsPreEnabled() const { return nActiveState == DYNODE_PRE_ENABLED; } + bool IsPoSeBanned() const { return nActiveState == DYNODE_POSE_BAN; } // NOTE: this one relies on nPoSeBanScore, not on nActiveState as everything else here - bool IsPoSeVerified() { return nPoSeBanScore <= -DYNODE_POSE_BAN_MAX_SCORE; } - bool IsExpired() { return nActiveState == DYNODE_EXPIRED; } - bool IsOutpointSpent() { return nActiveState == DYNODE_OUTPOINT_SPENT; } - bool IsUpdateRequired() { return nActiveState == DYNODE_UPDATE_REQUIRED; } - bool IsSentinelPingExpired() { return nActiveState == DYNODE_SENTINEL_PING_EXPIRED; } - bool IsNewStartRequired() { return nActiveState == DYNODE_NEW_START_REQUIRED; } + bool IsPoSeVerified() const { return nPoSeBanScore <= -DYNODE_POSE_BAN_MAX_SCORE; } + bool IsExpired() const { return nActiveState == DYNODE_EXPIRED; } + bool IsOutpointSpent() const { return nActiveState == DYNODE_OUTPOINT_SPENT; } + bool IsUpdateRequired() const { return nActiveState == DYNODE_UPDATE_REQUIRED; } + bool IsSentinelPingExpired() const { return nActiveState == DYNODE_SENTINEL_PING_EXPIRED; } + bool IsNewStartRequired() const { return nActiveState == DYNODE_NEW_START_REQUIRED; } static bool IsValidStateForAutoStart(int nActiveStateIn) { @@ -236,7 +278,7 @@ class CDynode : public dynode_info_t nActiveStateIn == DYNODE_SENTINEL_PING_EXPIRED; } - bool IsValidForPayment() + bool IsValidForPayment() const { if(nActiveState == DYNODE_ENABLED) { return true; @@ -256,7 +298,7 @@ class CDynode : public dynode_info_t void DecreasePoSeBanScore() { if(nPoSeBanScore > -DYNODE_POSE_BAN_MAX_SCORE) nPoSeBanScore--; } void PoSeBan() { nPoSeBanScore = DYNODE_POSE_BAN_MAX_SCORE; } - dynode_info_t GetInfo(); + dynode_info_t GetInfo() const; static std::string StateToString(int nStateIn); std::string GetStateString() const; @@ -264,8 +306,8 @@ class CDynode : public dynode_info_t int GetCollateralAge(); - int GetLastPaidTime() { return nTimeLastPaid; } - int GetLastPaidBlock() { return nBlockLastPaid; } + int GetLastPaidTime() const { return nTimeLastPaid; } + int GetLastPaidBlock() const { return nBlockLastPaid; } void UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack); // KEEP TRACK OF EACH GOVERNANCE ITEM INCASE THIS NODE GOES OFFLINE, SO WE CAN RECALC THEIR STATUS @@ -293,11 +335,11 @@ class CDynode : public dynode_info_t inline bool operator==(const CDynode& a, const CDynode& b) { - return a.vin == b.vin; + return a.outpoint == b.outpoint; } inline bool operator!=(const CDynode& a, const CDynode& b) { - return !(a.vin == b.vin); + return !(a.outpoint == b.outpoint); } // @@ -318,45 +360,55 @@ class CDynodeBroadcast : public CDynode template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(vin); + int nVersion = s.GetVersion(); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn txin{}; + if (ser_action.ForRead()) { + READWRITE(txin); + outpoint = txin.prevout; + } else { + txin = CTxIn(outpoint); + READWRITE(txin); + } + } else { + // using new format directly + READWRITE(outpoint); + } READWRITE(addr); READWRITE(pubKeyCollateralAddress); READWRITE(pubKeyDynode); - READWRITE(vchSig); + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(vchSig); + } READWRITE(sigTime); READWRITE(nProtocolVersion); - READWRITE(lastPing); + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(lastPing); + } } - uint256 GetHash() const - { - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << vin; - ss << pubKeyCollateralAddress; - ss << sigTime; - return ss.GetHash(); - } + uint256 GetHash() const; + uint256 GetSignatureHash() const; /// Create Dynode broadcast, needs to be relayed manually after that static bool Create(const COutPoint& outpoint, const CService& service, const CKey& keyCollateralAddressNew, const CPubKey& pubKeyCollateralAddressNew, const CKey& keyDynodeNew, const CPubKey& pubKeyDynodeNew, std::string &strErrorRet, CDynodeBroadcast &dnbRet); - static bool Create(std::string strService, std::string strKey, std::string strTxHash, std::string strOutputIndex, std::string& strErrorRet, CDynodeBroadcast &dnbRet, bool fOffline = false); + static bool Create(const std::string strService, const std::string strKey, const std::string strTxHash, const std::string strOutputIndex, std::string& strErrorRet, CDynodeBroadcast &dnbRet, bool fOffline = false); bool SimpleCheck(int& nDos); bool Update(CDynode* pdn, int& nDos, CConnman& connman); bool CheckOutpoint(int& nDos); - /// Is the input associated with this public key? (and there is 1000 DYN - checking if valid Dynode) - bool IsVinAssociatedWithPubkey(const CTxIn& vin, const CPubKey& pubkey); bool Sign(const CKey& keyCollateralAddress); - bool CheckSignature(int& nDos); - void Relay(CConnman& connman); + bool CheckSignature(int& nDos) const; + void Relay(CConnman& connman) const; }; class CDynodeVerification { public: - CTxIn vin1{}; - CTxIn vin2{}; + COutPoint dynodeOutpoint1{}; + COutPoint dynodeOutpoint2{}; CService addr{}; int nonce{}; int nBlockHeight{}; @@ -375,8 +427,27 @@ class CDynodeVerification template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(vin1); - READWRITE(vin2); + int nVersion = s.GetVersion(); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn txin1{}; + CTxIn txin2{}; + if (ser_action.ForRead()) { + READWRITE(txin1); + READWRITE(txin2); + dynodeOutpoint1 = txin1.prevout; + dynodeOutpoint2 = txin2.prevout; + } else { + txin1 = CTxIn(dynodeOutpoint1); + txin2 = CTxIn(dynodeOutpoint2); + READWRITE(txin1); + READWRITE(txin2); + } + } else { + // using new format directly + READWRITE(dynodeOutpoint1); + READWRITE(dynodeOutpoint2); + } READWRITE(addr); READWRITE(nonce); READWRITE(nBlockHeight); @@ -386,15 +457,42 @@ class CDynodeVerification uint256 GetHash() const { + // Note: doesn't match serialization + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << vin1; - ss << vin2; + // adding dummy values here to match old hashing format + ss << dynodeOutpoint1 << uint8_t{} << 0xffffffff; + ss << dynodeOutpoint2 << uint8_t{} << 0xffffffff; ss << addr; ss << nonce; ss << nBlockHeight; return ss.GetHash(); } + uint256 GetSignatureHash1(const uint256& blockHash) const + { + // Note: doesn't match serialization + + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << addr; + ss << nonce; + ss << blockHash; + return ss.GetHash(); + } + + uint256 GetSignatureHash2(const uint256& blockHash) const + { + // Note: doesn't match serialization + + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << dynodeOutpoint1; + ss << dynodeOutpoint2; + ss << addr; + ss << nonce; + ss << blockHash; + return ss.GetHash(); + } + void Relay() const { CInv inv(MSG_DYNODE_VERIFY, GetHash()); diff --git a/src/dynodeconfig.cpp b/src/dynodeconfig.cpp index 52cdb5a8cb..5d12089434 100644 --- a/src/dynodeconfig.cpp +++ b/src/dynodeconfig.cpp @@ -10,7 +10,7 @@ CDynodeConfig dynodeConfig; -void CDynodeConfig::add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex) { +void CDynodeConfig::add(const std::string& alias, const std::string& ip, const std::string& privKey, const std::string& txHash, const std::string& outputIndex) { CDynodeEntry cme(alias, ip, privKey, txHash, outputIndex); entries.push_back(cme); } diff --git a/src/dynodeconfig.h b/src/dynodeconfig.h index 21ff04307a..8c6e607e32 100644 --- a/src/dynodeconfig.h +++ b/src/dynodeconfig.h @@ -28,7 +28,7 @@ class CDynodeConfig std::string outputIndex; public: - CDynodeEntry(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex) { + CDynodeEntry(const std::string& alias, const std::string& ip, const std::string& privKey, const std::string& txHash, const std::string& outputIndex) { this->alias = alias; this->ip = ip; this->privKey = privKey; @@ -83,7 +83,7 @@ class CDynodeConfig void clear(); bool read(std::string& strErr); - void add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex); + void add(const std::string& alias, const std::string& ip, const std::string& privKey, const std::string& txHash, const std::string& outputIndex); std::vector& getEntries() { return entries; diff --git a/src/dynodeman.cpp b/src/dynodeman.cpp index 9860a420fe..a65cd8d3c8 100644 --- a/src/dynodeman.cpp +++ b/src/dynodeman.cpp @@ -7,37 +7,44 @@ #include "activedynode.h" #include "addrman.h" -#include "governance.h" +#include "alert.h" +#include "clientversion.h" #include "dynode-payments.h" #include "dynode-sync.h" +#include "governance.h" +#include "init.h" #include "messagesigner.h" #include "netfulfilledman.h" +#include "netmessagemaker.h" #ifdef ENABLE_WALLET #include "privatesend-client.h" #endif // ENABLE_WALLET #include "script/standard.h" +#include "ui_interface.h" #include "util.h" +#include "warnings.h" /** Dynode manager */ CDynodeMan dnodeman; const std::string CDynodeMan::SERIALIZATION_VERSION_STRING = "CDynodeMan-Version-3"; +const int CDynodeMan::LAST_PAID_SCAN_BLOCKS = 100; struct CompareLastPaidBlock { - bool operator()(const std::pair& t1, - const std::pair& t2) const + bool operator()(const std::pair& t1, + const std::pair& t2) const { - return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->vin < t2.second->vin); + return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->outpoint < t2.second->outpoint); } }; struct CompareScoreDN { - bool operator()(const std::pair& t1, - const std::pair& t2) const + bool operator()(const std::pair& t1, + const std::pair& t2) const { - return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->vin < t2.second->vin); + return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->outpoint < t2.second->outpoint); } }; @@ -74,10 +81,10 @@ bool CDynodeMan::Add(CDynode &dn) { LOCK(cs); - if (Has(dn.vin.prevout)) return false; + if (Has(dn.outpoint)) return false; - LogPrint("dynode", "CDynodeMan::Add -- Adding new Dynode: addr=%s, %i now\n", dn.addr.ToString(), size() + 1); - mapDynodes[dn.vin.prevout] = dn; + LogPrint("Dynode", "CDynodeMan::Add -- Adding new Dynode: addr=%s, %i now\n", dn.addr.ToString(), size() + 1); + mapDynodes[dn.outpoint] = dn; fDynodesAdded = true; return true; } @@ -86,29 +93,35 @@ void CDynodeMan::AskForDN(CNode* pnode, const COutPoint& outpoint, CConnman& con { if(!pnode) return; - LOCK(cs); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + LOCK(cs); - std::map >::iterator it1 = mWeAskedForDynodeListEntry.find(outpoint); + CService addrSquashed = Params().AllowMultiplePorts() ? (CService)pnode->addr : CService(pnode->addr, 0); + auto it1 = mWeAskedForDynodeListEntry.find(outpoint); if (it1 != mWeAskedForDynodeListEntry.end()) { - std::map::iterator it2 = it1->second.find(pnode->addr); + auto it2 = it1->second.find(addrSquashed); if (it2 != it1->second.end()) { if (GetTime() < it2->second) { // we've asked recently, should not repeat too often or we could get banned return; } // we asked this node for this outpoint but it's ok to ask again already - LogPrintf("CDynodeMan::AskForDN -- Asking same peer %s for missing Dynode entry again: %s\n", pnode->addr.ToString(), outpoint.ToStringShort()); + LogPrintf("CDynodeMan::AskForDN -- Asking same peer %s for missing Dynode entry again: %s\n", addrSquashed.ToString(), outpoint.ToStringShort()); } else { // we already asked for this outpoint but not this node - LogPrintf("CDynodeMan::AskForDN -- Asking new peer %s for missing Dynode entry: %s\n", pnode->addr.ToString(), outpoint.ToStringShort()); + LogPrintf("CDynodeMan::AskForDN -- Asking new peer %s for missing Dynode entry: %s\n", addrSquashed.ToString(), outpoint.ToStringShort()); } } else { // we never asked any node for this outpoint - LogPrintf("CDynodeMan::AskForDN -- Asking peer %s for missing Dynode entry for the first time: %s\n", pnode->addr.ToString(), outpoint.ToStringShort()); + LogPrintf("CDynodeMan::AskForDN -- Asking peer %s for missing Dynode entry for the first time: %s\n", addrSquashed.ToString(), outpoint.ToStringShort()); } - mWeAskedForDynodeListEntry[outpoint][pnode->addr] = GetTime() + PSEG_UPDATE_SECONDS; + mWeAskedForDynodeListEntry[outpoint][addrSquashed] = GetTime() + PSEG_UPDATE_SECONDS; - connman.PushMessage(pnode, NetMsgType::PSEG, CTxIn(outpoint)); + if (pnode->GetSendVersion() == 70900) { + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSEG, CTxIn(outpoint))); + } else { + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSEG, outpoint)); + } } bool CDynodeMan::AllowMixing(const COutPoint &outpoint) @@ -151,15 +164,16 @@ bool CDynodeMan::PoSeBan(const COutPoint &outpoint) void CDynodeMan::Check() { - LOCK(cs); - - LogPrint("Dynode", "CDynodeMan::Check -- nLastSentinelPingTime=%d, IsSentinelPingActive()=%d\n", nLastSentinelPingTime, IsSentinelPingActive()); + LOCK2(cs_main, cs); for (auto& dnpair : mapDynodes) { + // NOTE: internally it checks only every DYNODE_CHECK_SECONDS seconds + // since the last time, so expect some DNs to skip this dnpair.second.Check(); } } + void CDynodeMan::CheckAndRemove(CConnman& connman) { if(!dynodeSync.IsDynodeListSynced()) return; @@ -175,7 +189,7 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) // Remove spent Dynodes, prepare structures and make requests to reasure the state of inactive ones rank_pair_vec_t vecDynodeRanks; - // ask for up to DNB_RECOVERY_MAX_ASK_ENTRIES dynode entries at a time + // ask for up to DNB_RECOVERY_MAX_ASK_ENTRIES Dynode entries at a time int nAskForDnbRecovery = DNB_RECOVERY_MAX_ASK_ENTRIES; std::map::iterator it = mapDynodes.begin(); while (it != mapDynodes.end()) { @@ -183,7 +197,7 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) uint256 hash = dnb.GetHash(); // If collateral was spent ... if (it->second.IsOutpointSpent()) { - LogPrint("dynode", "CDynodeMan::CheckAndRemove -- Removing Dynode: %s addr=%s %i now\n", it->second.GetStateString(), it->second.addr.ToString(), size() - 1); + LogPrint("Dynode", "CDynodeMan::CheckAndRemove -- Removing Dynode: %s addr=%s %i now\n", it->second.GetStateString(), it->second.addr.ToString(), size() - 1); // erase all of the broadcasts we've seen from this txin, ... mapSeenDynodeBroadcast.erase(hash); mWeAskedForDynodeListEntry.erase(it->first); @@ -195,17 +209,18 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) bool fAsk = (nAskForDnbRecovery > 0) && dynodeSync.IsSynced() && it->second.IsNewStartRequired() && - !IsDnbRecoveryRequested(hash); + !IsDnbRecoveryRequested(hash) && + !IsArgSet("-connect"); if(fAsk) { // this DN is in a non-recoverable state and we haven't asked other nodes yet - std::set setRequested; + std::set setRequested; // calulate only once and only when it's needed if(vecDynodeRanks.empty()) { int nRandomBlockHeight = GetRandInt(nCachedBlockHeight); GetDynodeRanks(vecDynodeRanks, nRandomBlockHeight); } bool fAskedForDnbRecovery = false; - // ask first DNB_RECOVERY_QUORUM_TOTAL dynodes we can connect to and we haven't asked recently + // ask first DNB_RECOVERY_QUORUM_TOTAL Dynodes we can connect to and we haven't asked recently for(int i = 0; setRequested.size() < DNB_RECOVERY_QUORUM_TOTAL && i < (int)vecDynodeRanks.size(); i++) { // avoid banning if(mWeAskedForDynodeListEntry.count(it->first) && mWeAskedForDynodeListEntry[it->first].count(vecDynodeRanks[i].second.addr)) continue; @@ -216,7 +231,7 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) fAskedForDnbRecovery = true; } if(fAskedForDnbRecovery) { - LogPrint("dynode", "CDynodeMan::CheckAndRemove -- Recovery initiated, dynode=%s\n", it->first.ToStringShort()); + LogPrint("Dynode", "CDynodeMan::CheckAndRemove -- Recovery initiated, dynode=%s\n", it->first.ToStringShort()); nAskForDnbRecovery--; } // wait for dnb recovery replies for DNB_RECOVERY_WAIT_SECONDS seconds @@ -233,13 +248,13 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) // all nodes we asked should have replied now if(itDnbReplies->second.size() >= DNB_RECOVERY_QUORUM_REQUIRED) { // majority of nodes we asked agrees that this DN doesn't require new dnb, reprocess one of new dnbs - LogPrint("Dynode", "CDynodeMan::CheckAndRemove -- reprocessing dnb, Dynode=%s\n", itDnbReplies->second[0].vin.prevout.ToStringShort()); + LogPrint("Dynode", "CDynodeMan::CheckAndRemove -- reprocessing dnb, Dynode=%s\n", itDnbReplies->second[0].outpoint.ToStringShort()); // mapSeenDynodeBroadcast.erase(itDnbReplies->first); int nDos; itDnbReplies->second[0].fRecovery = true; - CheckDnbAndUpdateDynodeList(NULL, itDnbReplies->second[0], nDos, connman); + CheckDnbAndUpdateDynodeList(nullptr, itDnbReplies->second[0], nDos, connman); } - LogPrint("Dynode", "CDynodeMan::CheckAndRemove -- removing dnb recovery reply, Dynode=%s, size=%d\n", itDnbReplies->second[0].vin.prevout.ToStringShort(), (int)itDnbReplies->second.size()); + LogPrint("Dynode", "CDynodeMan::CheckAndRemove -- removing dnb recovery reply, Dynode=%s, size=%d\n", itDnbReplies->second[0].outpoint.ToStringShort(), (int)itDnbReplies->second.size()); mDnbRecoveryGoodReplies.erase(itDnbReplies++); } else { ++itDnbReplies; @@ -250,7 +265,7 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) // no need for cm_main below LOCK(cs); - std::map > >::iterator itDnbRequest = mDnbRecoveryRequests.begin(); + auto itDnbRequest = mDnbRecoveryRequests.begin(); while(itDnbRequest != mDnbRecoveryRequests.end()){ // Allow this dnb to be re-verified again after DNB_RECOVERY_RETRY_SECONDS seconds // if DN is still in DYNODE_NEW_START_REQUIRED state. @@ -262,7 +277,7 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) } // check who's asked for the Dynode list - std::map::iterator it1 = mAskedUsForDynodeList.begin(); + auto it1 = mAskedUsForDynodeList.begin(); while(it1 != mAskedUsForDynodeList.end()){ if((*it1).second < GetTime()) { mAskedUsForDynodeList.erase(it1++); @@ -282,9 +297,9 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) } // check which Dynodes we've asked for - std::map >::iterator it2 = mWeAskedForDynodeListEntry.begin(); + auto it2 = mWeAskedForDynodeListEntry.begin(); while(it2 != mWeAskedForDynodeListEntry.end()){ - std::map::iterator it3 = it2->second.begin(); + auto it3 = it2->second.begin(); while(it3 != it2->second.end()){ if(it3->second < GetTime()){ it2->second.erase(it3++); @@ -299,7 +314,7 @@ void CDynodeMan::CheckAndRemove(CConnman& connman) } } - std::map::iterator it3 = mWeAskedForVerification.begin(); + auto it3 = mWeAskedForVerification.begin(); while(it3 != mWeAskedForVerification.end()){ if(it3->second.nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS) { mWeAskedForVerification.erase(it3++); @@ -401,19 +416,25 @@ int CDynodeMan::CountByIP(int nNetworkType) void CDynodeMan::PsegUpdate(CNode* pnode, CConnman& connman) { + CNetMsgMaker msgMaker(pnode->GetSendVersion()); LOCK(cs); - if(Params().NetworkIDString() == CBaseChainParams::MAIN) { + CService addrSquashed = Params().AllowMultiplePorts() ? (CService)pnode->addr : CService(pnode->addr, 0); + if(Params().NetworkIDString() == CBaseChainParams::MAIN) { if(!(pnode->addr.IsRFC1918() || pnode->addr.IsLocal())) { - std::map::iterator it = mWeAskedForDynodeList.find(pnode->addr); + auto it = mWeAskedForDynodeList.find(addrSquashed); if(it != mWeAskedForDynodeList.end() && GetTime() < (*it).second) { - LogPrintf("CDynodeMan::PsegUpdate -- we already asked %s for the list; skipping...\n", pnode->addr.ToString()); + LogPrintf("CDynodeMan::PsegUpdate -- we already asked %s for the list; skipping...\n", addrSquashed.ToString()); return; } } - } + } - connman.PushMessage(pnode, NetMsgType::PSEG, CTxIn()); + if (pnode->GetSendVersion() == 70900) { + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSEG, CTxIn())); + } else { + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSEG, COutPoint())); + } int64_t askAgain = GetTime() + PSEG_UPDATE_SECONDS; mWeAskedForDynodeList[pnode->addr] = askAgain; @@ -424,7 +445,7 @@ CDynode* CDynodeMan::Find(const COutPoint &outpoint) { LOCK(cs); auto it = mapDynodes.find(outpoint); - return it == mapDynodes.end() ? NULL : &(it->second); + return it == mapDynodes.end() ? nullptr : &(it->second); } bool CDynodeMan::Get(const COutPoint& outpoint, CDynode& dynodeRet) @@ -463,6 +484,19 @@ bool CDynodeMan::GetDynodeInfo(const CPubKey& pubKeyDynode, dynode_info_t& dnInf return false; } +bool CDynodeMan::GetDynodeInfo(const CScript& payee, dynode_info_t& dnInfoRet) +{ + LOCK(cs); + for (const auto& dnpair : mapDynodes) { + CScript scriptCollateralAddress = GetScriptForDestination(dnpair.second.pubKeyCollateralAddress.GetID()); + if (scriptCollateralAddress == payee) { + dnInfoRet = dnpair.second.GetInfo(); + return true; + } + } + return false; +} + bool CDynodeMan::Has(const COutPoint& outpoint) { LOCK(cs); @@ -482,11 +516,6 @@ bool CDynodeMan::GetNextDynodeInQueueForPayment(int nBlockHeight, bool fFilterSi dnInfoRet = dynode_info_t(); nCountRet = 0; - int nCheckBlockHeight = nBlockHeight - 101; - if (nCheckBlockHeight < 1) { - return false; - } - if (!dynodeSync.IsWinnersListSynced()) { // without winner list we can't reliably find the next winner anyway return false; @@ -495,7 +524,7 @@ bool CDynodeMan::GetNextDynodeInQueueForPayment(int nBlockHeight, bool fFilterSi // Need LOCK2 here to ensure consistent locking order because the GetBlockHash call below locks cs_main LOCK2(cs_main,cs); - std::vector > vecDynodeLastPaid; + std::vector > vecDynodeLastPaid; /* Make a vector with all of the last paid times @@ -503,7 +532,7 @@ bool CDynodeMan::GetNextDynodeInQueueForPayment(int nBlockHeight, bool fFilterSi int nDnCount = CountDynodes(); - for (auto& dnpair : mapDynodes) { + for (const auto& dnpair : mapDynodes) { if(!dnpair.second.IsValidForPayment()) continue; // //check protocol version @@ -531,8 +560,8 @@ bool CDynodeMan::GetNextDynodeInQueueForPayment(int nBlockHeight, bool fFilterSi sort(vecDynodeLastPaid.begin(), vecDynodeLastPaid.end(), CompareLastPaidBlock()); uint256 blockHash; - if(!GetBlockHash(blockHash, nCheckBlockHeight)) { - LogPrintf("CDynode::GetNextDynodeInQueueForPayment -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", nCheckBlockHeight); + if(!GetBlockHash(blockHash, nBlockHeight - 101)) { + LogPrintf("CDynode::GetNextDynodeInQueueForPayment -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", nBlockHeight - 101); return false; } // Look at 1/10 of the oldest nodes (by last payment), calculate their scores and pay the best one @@ -542,8 +571,8 @@ bool CDynodeMan::GetNextDynodeInQueueForPayment(int nBlockHeight, bool fFilterSi int nTenthNetwork = nDnCount/10; int nCountTenth = 0; arith_uint256 nHighest = 0; - CDynode *pBestDynode = NULL; - BOOST_FOREACH (PAIRTYPE(int, CDynode*)& s, vecDynodeLastPaid){ + const CDynode *pBestDynode = nullptr; + for (const auto& s : vecDynodeLastPaid) { arith_uint256 nScore = s.second->CalculateScore(blockHash); if(nScore > nHighest){ nHighest = nScore; @@ -571,30 +600,29 @@ dynode_info_t CDynodeMan::FindRandomNotInVec(const std::vector &vecTo if(nCountNotExcluded < 1) return dynode_info_t(); // fill a vector of pointers - std::vector vpDynodesShuffled; - for (auto& dnpair : mapDynodes) { + std::vector vpDynodesShuffled; + for (const auto& dnpair : mapDynodes) { vpDynodesShuffled.push_back(&dnpair.second); } FastRandomContext insecure_rand; - // shuffle pointers std::random_shuffle(vpDynodesShuffled.begin(), vpDynodesShuffled.end(), insecure_rand); bool fExclude; // loop through - BOOST_FOREACH(CDynode* pdn, vpDynodesShuffled) { + for (const auto& pdn : vpDynodesShuffled) { if(pdn->nProtocolVersion < nProtocolVersion || !pdn->IsEnabled()) continue; fExclude = false; - BOOST_FOREACH(const COutPoint &outpointToExclude, vecToExclude) { - if(pdn->vin.prevout == outpointToExclude) { + for (const auto& outpointToExclude : vecToExclude) { + if(pdn->outpoint == outpointToExclude) { fExclude = true; break; } } if(fExclude) continue; // found the one not in vecToExclude - LogPrint("Dynode", "CDynodeMan::FindRandomNotInVec -- found, Dynode=%s\n", pdn->vin.prevout.ToStringShort()); + LogPrint("Dynode", "CDynodeMan::FindRandomNotInVec -- found, Dynode=%s\n", pdn->outpoint.ToStringShort()); return pdn->GetInfo(); } @@ -609,14 +637,13 @@ bool CDynodeMan::GetDynodeScores(const uint256& nBlockHash, CDynodeMan::score_pa if (!dynodeSync.IsDynodeListSynced()) return false; - AssertLockHeld(cs); if (mapDynodes.empty()) return false; // calculate scores - for (auto& dnpair : mapDynodes) { + for (const auto& dnpair : mapDynodes) { if (dnpair.second.nProtocolVersion >= nMinProtocol) { vecDynodeScoresRet.push_back(std::make_pair(dnpair.second.CalculateScore(nBlockHash), &dnpair.second)); } @@ -630,9 +657,6 @@ bool CDynodeMan::GetDynodeRank(const COutPoint& outpoint, int& nRankRet, int nBl { nRankRet = -1; - if (nBlockHeight < 1) - return false; - if (!dynodeSync.IsDynodeListSynced()) return false; @@ -650,9 +674,9 @@ bool CDynodeMan::GetDynodeRank(const COutPoint& outpoint, int& nRankRet, int nBl return false; int nRank = 0; - for (auto& scorePair : vecDynodeScores) { + for (const auto& scorePair : vecDynodeScores) { nRank++; - if(scorePair.second->vin.prevout == outpoint) { + if(scorePair.second->outpoint == outpoint) { nRankRet = nRank; return true; } @@ -664,9 +688,6 @@ bool CDynodeMan::GetDynodeRank(const COutPoint& outpoint, int& nRankRet, int nBl bool CDynodeMan::GetDynodeRanks(CDynodeMan::rank_pair_vec_t& vecDynodeRanksRet, int nBlockHeight, int nMinProtocol) { vecDynodeRanksRet.clear(); - - if (nBlockHeight < 1) - return false; if (!dynodeSync.IsDynodeListSynced()) return false; @@ -685,7 +706,7 @@ bool CDynodeMan::GetDynodeRanks(CDynodeMan::rank_pair_vec_t& vecDynodeRanksRet, return false; int nRank = 0; - for (auto& scorePair : vecDynodeScores) { + for (const auto& scorePair : vecDynodeScores) { nRank++; vecDynodeRanksRet.push_back(std::make_pair(nRank, *scorePair.second)); } @@ -737,7 +758,46 @@ std::pair > CDynodeMan::PopScheduledDnbRequestConnec return std::make_pair(pairFront.first, setResult); } -void CDynodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman) +void CDynodeMan::ProcessPendingDnbRequests(CConnman& connman) +{ + std::pair > p = PopScheduledDnbRequestConnection(); + if (!(p.first == CService() || p.second.empty())) { + if (connman.IsDynodeOrDisconnectRequested(p.first)) return; + mapPendingDNB.insert(std::make_pair(p.first, std::make_pair(GetTime(), p.second))); + connman.AddPendingDynode(p.first); + } + + std::map > >::iterator itPendingDNB = mapPendingDNB.begin(); + while (itPendingDNB != mapPendingDNB.end()) { + bool fDone = connman.ForNode(itPendingDNB->first, [&](CNode* pnode) { + // compile request vector + std::vector vToFetch; + for (auto& nHash : itPendingDNB->second.second) { + if(nHash != uint256()) { + vToFetch.push_back(CInv(MSG_DYNODE_ANNOUNCE, nHash)); + LogPrint("dynode", "-- asking for dnb %s from addr=%s\n", nHash.ToString(), pnode->addr.ToString()); + } + } + + // ask for data + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETDATA, vToFetch)); + return true; + }); + + int64_t nTimeAdded = itPendingDNB->second.first; + if (fDone || (GetTime() - nTimeAdded > 15)) { + if (!fDone) { + LogPrint("dynode", "CDynodeMan::%s -- failed to connect to %s\n", __func__, itPendingDNB->first.ToString()); + } + mapPendingDNB.erase(itPendingDNB++); + } else { + ++itPendingDNB; + } + } +} + +void CDynodeMan::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) { if(fLiteMode) return; // disable all Dynamic specific functionality @@ -750,7 +810,7 @@ void CDynodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStre if(!dynodeSync.IsBlockchainSynced()) return; - LogPrint("Dynode", "DNANNOUNCE -- Dynode announce, Dynode=%s\n", dnb.vin.prevout.ToStringShort()); + LogPrint("Dynode", "DNANNOUNCE -- Dynode announce, Dynode=%s\n", dnb.outpoint.ToStringShort()); int nDos = 0; @@ -758,8 +818,10 @@ void CDynodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStre // use announced Dynode as a peer connman.AddNewAddress(CAddress(dnb.addr, NODE_NETWORK), pfrom->addr, 2*60*60); } else if(nDos > 0) { + LOCK(cs_main); Misbehaving(pfrom->GetId(), nDos); } + if(fDynodesAdded) { NotifyDynodeUpdates(connman); } @@ -774,7 +836,7 @@ void CDynodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStre if(!dynodeSync.IsBlockchainSynced()) return; - LogPrint("Dynode", "DNPING -- Dynode ping, Dynode=%s\n", dnp.vin.prevout.ToStringShort()); + LogPrint("Dynode", "DNPING -- Dynode ping, Dynode=%s\n", dnp.dynodeOutpoint.ToStringShort()); // Need LOCK2 here to ensure consistent locking order because the CheckAndUpdate call below locks cs_main LOCK2(cs_main, cs); @@ -782,10 +844,10 @@ void CDynodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStre if(mapSeenDynodePing.count(nHash)) return; //seen mapSeenDynodePing.insert(std::make_pair(nHash, dnp)); - LogPrint("Dynode", "DNPING -- Dynode ping, Dynode=%s new\n", dnp.vin.prevout.ToStringShort()); + LogPrint("Dynode", "DNPING -- Dynode ping, Dynode=%s new\n", dnp.dynodeOutpoint.ToStringShort()); // see if we have this Dynode - CDynode* pdn = Find(dnp.vin.prevout); + CDynode* pdn = Find(dnp.dynodeOutpoint); if(pdn && dnp.fSentinelIsCurrent) UpdateLastSentinelPingTime(); @@ -806,7 +868,7 @@ void CDynodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStre // something significant is broken or dn is unknown, // we might have to ask for a Dynode entry once - AskForDN(pfrom, dnp.vin.prevout, connman); + AskForDN(pfrom, dnp.dynodeOutpoint, connman); } else if (strCommand == NetMsgType::PSEG) { //Get Dynode list or specific entry // Ignore such requests until we are fully synced. @@ -814,62 +876,23 @@ void CDynodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStre // but this is a heavy one so it's better to finish sync first. if (!dynodeSync.IsSynced()) return; - CTxIn vin; - vRecv >> vin; - - LogPrint("Dynode", "PSEG -- Dynode list, Dynode=%s\n", vin.prevout.ToStringShort()); - - LOCK(cs); - - if(vin == CTxIn()) { //only should ask for this once - //local network - bool isLocal = (pfrom->addr.IsRFC1918() || pfrom->addr.IsLocal()); - int nDnCount = dnodeman.CountDynodes(); - // This is to prevent unnecessary banning of Dynodes whilst the network is in its infancy - if(!isLocal && Params().NetworkIDString() == CBaseChainParams::MAIN && nDnCount > 200) { - std::map::iterator it = mAskedUsForDynodeList.find(pfrom->addr); - if (it != mAskedUsForDynodeList.end() && it->second > GetTime()) { - Misbehaving(pfrom->GetId(), 34); - LogPrintf("PSEG -- peer already asked me for the list, peer=%d\n", pfrom->id); - return; - } - int64_t askAgain = GetTime() + PSEG_UPDATE_SECONDS; - mAskedUsForDynodeList[pfrom->addr] = askAgain; - } - } //else, asking for a specific node which is ok - - int nInvCount = 0; + COutPoint dynodeOutpoint; - for (auto& dnpair : mapDynodes) { - if (vin != CTxIn() && vin != dnpair.second.vin) continue; // asked for specific vin but we are not there yet - if (dnpair.second.addr.IsRFC1918() || dnpair.second.addr.IsLocal()) continue; // do not send local network dynode - if (dnpair.second.IsUpdateRequired()) continue; // do not send outdated dynodes - - LogPrint("dynode", "PSEG -- Sending Dynode entry: dynode=%s addr=%s\n", dnpair.first.ToStringShort(), dnpair.second.addr.ToString()); - CDynodeBroadcast dnb = CDynodeBroadcast(dnpair.second); - CDynodePing dnp = dnpair.second.lastPing; - uint256 hashDNB = dnb.GetHash(); - uint256 hashDNP = dnp.GetHash(); - pfrom->PushInventory(CInv(MSG_DYNODE_ANNOUNCE, hashDNB)); - pfrom->PushInventory(CInv(MSG_DYNODE_PING, hashDNP)); - nInvCount++; - - mapSeenDynodeBroadcast.insert(std::make_pair(hashDNB, std::make_pair(GetTime(), dnb))); - mapSeenDynodePing.insert(std::make_pair(hashDNP, dnp)); - - if (vin.prevout == dnpair.first) { - LogPrintf("PSEG -- Sent 1 Dynode inv to peer %d\n", pfrom->id); - return; - } + if (pfrom->nVersion == 70900) { + CTxIn vin; + vRecv >> vin; + dynodeOutpoint = vin.prevout; + } else { + vRecv >> dynodeOutpoint; } - if(vin == CTxIn()) { - connman.PushMessage(pfrom, NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_LIST, nInvCount); - LogPrintf("PSEG -- Sent %d Dynode invs to peer %d\n", nInvCount, pfrom->id); - return; + LogPrint("Dynode", "PSEG -- Dynode list, Dynode=%s\n", dynodeOutpoint.ToStringShort()); + + if(dynodeOutpoint.IsNull()) { + SyncAll(pfrom, connman); + } else { + SyncSingle(pfrom, dynodeOutpoint, connman); } - // smth weird happen - someone asked us for vin we have no idea about? - LogPrint("Dynode", "PSEG -- No invs sent to peer %d\n", pfrom->id); } else if (strCommand == NetMsgType::DNVERIFY) { // Dynode Verify @@ -896,6 +919,78 @@ void CDynodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStre } } +void CDynodeMan::SyncSingle(CNode* pnode, const COutPoint& outpoint, CConnman& connman) +{ + // do not provide any data until our node is synced + if (!dynodeSync.IsSynced()) return; + + LOCK(cs); + + auto it = mapDynodes.find(outpoint); + + if(it != mapDynodes.end()) { + if (it->second.addr.IsRFC1918() || it->second.addr.IsLocal()) return; // do not send local network Dynode + // NOTE: send Dynode regardless of its current state, the other node will need it to verify old votes. + LogPrint("Dynode", "CDynodeMan::%s -- Sending Dynode entry: Dynode=%s addr=%s\n", __func__, outpoint.ToStringShort(), it->second.addr.ToString()); + PushPsegInvs(pnode, it->second); + LogPrintf("CDynodeMan::%s -- Sent 1 Dynode inv to peer=%d\n", __func__, pnode->id); + } +} + +void CDynodeMan::SyncAll(CNode* pnode, CConnman& connman) +{ + // do not provide any data until our node is synced + if (!dynodeSync.IsSynced()) return; + + // local network + bool isLocal = (pnode->addr.IsRFC1918() || pnode->addr.IsLocal()); + + CService addrSquashed = Params().AllowMultiplePorts() ? (CService)pnode->addr : CService(pnode->addr, 0); + // should only ask for this once + if(!isLocal && Params().NetworkIDString() == CBaseChainParams::MAIN) { + LOCK2(cs_main, cs); + auto it = mAskedUsForDynodeList.find(addrSquashed); + if (it != mAskedUsForDynodeList.end() && it->second > GetTime()) { + Misbehaving(pnode->GetId(), 34); + LogPrintf("CDynodeMan::%s -- peer already asked me for the list, peer=%d\n", __func__, pnode->id); + return; + } + int64_t askAgain = GetTime() + PSEG_UPDATE_SECONDS; + mAskedUsForDynodeList[addrSquashed] = askAgain; + } + + int nInvCount = 0; + + LOCK(cs); + + for (const auto& dnpair : mapDynodes) { + if (Params().RequireRoutableExternalIP() && + (dnpair.second.addr.IsRFC1918() || dnpair.second.addr.IsLocal())) + continue; // do not send local network Dynode + // NOTE: send Dynode regardless of its current state, the other node will need it to verify old votes. + LogPrint("Dynode", "CDynodeMan::%s -- Sending Dynode entry: Dynode=%s addr=%s\n", __func__, dnpair.first.ToStringShort(), dnpair.second.addr.ToString()); + PushPsegInvs(pnode, dnpair.second); + nInvCount++; + } + + connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_LIST, nInvCount)); + LogPrintf("CDynodeMan::%s -- Sent %d Dynode invs to peer=%d\n", __func__, nInvCount, pnode->id); +} + +void CDynodeMan::PushPsegInvs(CNode* pnode, const CDynode& dn) +{ + AssertLockHeld(cs); + + CDynodeBroadcast dnb(dn); + CDynodePing dnp = dnb.lastPing; + uint256 hashDNB = dnb.GetHash(); + uint256 hashDNP = dnp.GetHash(); + pnode->PushInventory(CInv(MSG_DYNODE_ANNOUNCE, hashDNB)); + pnode->PushInventory(CInv(MSG_DYNODE_PING, hashDNP)); + mapSeenDynodeBroadcast.insert(std::make_pair(hashDNB, std::make_pair(GetTime(), dnb))); + mapSeenDynodePing.insert(std::make_pair(hashDNP, dnp)); +} + // Verification of Dynode via unique direct requests. void CDynodeMan::DoFullVerificationStep(CConnman& connman) @@ -904,12 +999,9 @@ void CDynodeMan::DoFullVerificationStep(CConnman& connman) if(!dynodeSync.IsSynced()) return; rank_pair_vec_t vecDynodeRanks; - GetDynodeRanks(vecDynodeRanks, nCachedBlockHeight - 1, MIN_POSE_PROTO_VERSION); - // Need LOCK2 here to ensure consistent locking order because the SendVerifyRequest call below locks cs_main - // through GetHeight() signal in ConnectNode - LOCK2(cs_main, cs); + LOCK(cs); int nCount = 0; @@ -917,20 +1009,18 @@ void CDynodeMan::DoFullVerificationStep(CConnman& connman) int nRanksTotal = (int)vecDynodeRanks.size(); // send verify requests only if we are in top MAX_POSE_RANK - std::vector >::iterator it = vecDynodeRanks.begin(); - while(it != vecDynodeRanks.end()) { - if(it->first > MAX_POSE_RANK) { + for (auto& rankPair : vecDynodeRanks) { + if(rankPair.first > MAX_POSE_RANK) { LogPrint("Dynode", "CDynodeMan::DoFullVerificationStep -- Must be in top %d to send verify request\n", (int)MAX_POSE_RANK); return; } - if(it->second.vin.prevout == activeDynode.outpoint) { - nMyRank = it->first; + if(rankPair.second.outpoint == activeDynode.outpoint) { + nMyRank = rankPair.first; LogPrint("Dynode", "CDynodeMan::DoFullVerificationStep -- Found self at rank %d/%d, verifying up to %d Dynodes\n", nMyRank, nRanksTotal, (int)MAX_POSE_CONNECTIONS); break; } - ++it; } // edge case: list is too short and this Dynode is not enabled @@ -941,28 +1031,28 @@ void CDynodeMan::DoFullVerificationStep(CConnman& connman) int nOffset = MAX_POSE_RANK + nMyRank - 1; if(nOffset >= (int)vecDynodeRanks.size()) return; - std::vector vSortedByAddr; - for (auto& dnpair : mapDynodes) { + std::vector vSortedByAddr; + for (const auto& dnpair : mapDynodes) { vSortedByAddr.push_back(&dnpair.second); } sort(vSortedByAddr.begin(), vSortedByAddr.end(), CompareByAddr()); - it = vecDynodeRanks.begin() + nOffset; + auto it = vecDynodeRanks.begin() + nOffset; while(it != vecDynodeRanks.end()) { if(it->second.IsPoSeVerified() || it->second.IsPoSeBanned()) { LogPrint("Dynode", "CDynodeMan::DoFullVerificationStep -- Already %s%s%s Dynode %s address %s, skipping...\n", it->second.IsPoSeVerified() ? "verified" : "", it->second.IsPoSeVerified() && it->second.IsPoSeBanned() ? " and " : "", it->second.IsPoSeBanned() ? "banned" : "", - it->second.vin.prevout.ToStringShort(), it->second.addr.ToString()); + it->second.outpoint.ToStringShort(), it->second.addr.ToString()); nOffset += MAX_POSE_CONNECTIONS; if(nOffset >= (int)vecDynodeRanks.size()) break; it += MAX_POSE_CONNECTIONS; continue; } LogPrint("Dynode", "CDynodeMan::DoFullVerificationStep -- Verifying Dynode %s rank %d/%d address %s\n", - it->second.vin.prevout.ToStringShort(), it->first, nRanksTotal, it->second.addr.ToString()); + it->second.outpoint.ToStringShort(), it->first, nRanksTotal, it->second.addr.ToString()); if(SendVerifyRequest(CAddress(it->second.addr, NODE_NETWORK), vSortedByAddr, connman)) { nCount++; if(nCount >= MAX_POSE_CONNECTIONS) break; @@ -990,8 +1080,8 @@ void CDynodeMan::CheckSameAddr() { LOCK(cs); - CDynode* pprevDynode = NULL; - CDynode* pverifiedDynode = NULL; + CDynode* pprevDynode = nullptr; + CDynode* pverifiedDynode = nullptr; for (auto& dnpair : mapDynodes) { vSortedByAddr.push_back(&dnpair.second); @@ -999,13 +1089,13 @@ void CDynodeMan::CheckSameAddr() sort(vSortedByAddr.begin(), vSortedByAddr.end(), CompareByAddr()); - BOOST_FOREACH(CDynode* pdn, vSortedByAddr) { + for (const auto& pdn : vSortedByAddr) { // check only (pre)enabled Dynodes if(!pdn->IsEnabled() && !pdn->IsPreEnabled()) continue; // initial step if(!pprevDynode) { pprevDynode = pdn; - pverifiedDynode = pdn->IsPoSeVerified() ? pdn : NULL; + pverifiedDynode = pdn->IsPoSeVerified() ? pdn : nullptr; continue; } // second+ step @@ -1020,20 +1110,20 @@ void CDynodeMan::CheckSameAddr() pverifiedDynode = pdn; } } else { - pverifiedDynode = pdn->IsPoSeVerified() ? pdn : NULL; + pverifiedDynode = pdn->IsPoSeVerified() ? pdn : nullptr; } pprevDynode = pdn; } } // ban duplicates - BOOST_FOREACH(CDynode* pdn, vBan) { - LogPrintf("CDynodeMan::CheckSameAddr -- increasing PoSe ban score for Dynode %s\n", pdn->vin.prevout.ToStringShort()); + for (auto& pdn : vBan) { + LogPrintf("CDynodeMan::CheckSameAddr -- increasing PoSe ban score for Dynode %s\n", pdn->outpoint.ToStringShort()); pdn->IncreasePoSeBanScore(); } } -bool CDynodeMan::SendVerifyRequest(const CAddress& addr, const std::vector& vSortedByAddr, CConnman& connman) +bool CDynodeMan::SendVerifyRequest(const CAddress& addr, const std::vector& vSortedByAddr, CConnman& connman) { if(netfulfilledman.HasFulfilledRequest(addr, strprintf("%s", NetMsgType::DNVERIFY)+"-request")) { // we already asked for verification, not a good idea to do this too often, skip it @@ -1041,22 +1131,46 @@ bool CDynodeMan::SendVerifyRequest(const CAddress& addr, const std::vector >::iterator itPendingDNV = mapPendingDNV.begin(); + + while (itPendingDNV != mapPendingDNV.end()) { + bool fDone = connman.ForNode(itPendingDNV->first, [&](CNode* pnode) { + netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::DNVERIFY)+"-request"); + // use random nonce, store it and require node to reply with correct one later + mWeAskedForVerification[pnode->addr] = itPendingDNV->second.second; + LogPrint("Dynode", "-- verifying node using nonce %d addr=%s\n", itPendingDNV->second.second.nonce, pnode->addr.ToString()); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); // TODO this gives a warning about version not being set (we should wait for VERSION exchange) + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DNVERIFY, itPendingDNV->second.second)); + return true; + }); + + int64_t nTimeAdded = itPendingDNV->second.first; + if (fDone || (GetTime() - nTimeAdded > 15)) { + if (!fDone) { + LogPrint("Dynode", "CDynodeMan::%s -- failed to connect to %s\n", __func__, itPendingDNV->first.ToString()); + } + mapPendingDNV.erase(itPendingDNV++); + } else { + ++itPendingDNV; + } + } +} + void CDynodeMan::SendVerifyReply(CNode* pnode, CDynodeVerification& dnv, CConnman& connman) { AssertLockHeld(cs_main); @@ -1070,32 +1184,47 @@ void CDynodeMan::SendVerifyReply(CNode* pnode, CDynodeVerification& dnv, CConnma if(netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::DNVERIFY)+"-reply")) { // peer should not ask us that often - LogPrintf("DynodeMan::SendVerifyReply -- ERROR: peer already asked me recently, peer=%d\n", pnode->id); + LogPrintf("CDynodeMan::SendVerifyReply -- ERROR: peer already asked me recently, peer=%d\n", pnode->id); Misbehaving(pnode->id, 20); return; } uint256 blockHash; if(!GetBlockHash(blockHash, dnv.nBlockHeight)) { - LogPrintf("DynodeMan::SendVerifyReply -- can't get block hash for unknown block height %d, peer=%d\n", dnv.nBlockHeight, pnode->id); + LogPrintf("CDynodeMan::SendVerifyReply -- can't get block hash for unknown block height %d, peer=%d\n", dnv.nBlockHeight, pnode->id); return; } - std::string strMessage = strprintf("%s%d%s", activeDynode.service.ToString(false), dnv.nonce, blockHash.ToString()); + std::string strError; - if(!CMessageSigner::SignMessage(strMessage, dnv.vchSig1, activeDynode.keyDynode)) { - LogPrintf("DynodeMan::SendVerifyReply -- SignMessage() failed\n"); - return; - } + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = dnv.GetSignatureHash1(blockHash); - std::string strError; + if(!CHashSigner::SignHash(hash, activeDynode.keyDynode, dnv.vchSig1)) { + LogPrintf("CDynodeMan::SendVerifyReply -- SignHash() failed\n"); + return; + } - if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, dnv.vchSig1, strMessage, strError)) { - LogPrintf("DynodeMan::SendVerifyReply -- VerifyMessage() failed, error: %s\n", strError); - return; + if (!CHashSigner::VerifyHash(hash, activeDynode.pubKeyDynode, dnv.vchSig1, strError)) { + LogPrintf("CDynodeMan::SendVerifyReply -- VerifyHash() failed, error: %s\n", strError); + return; + } + } else { + std::string strMessage = strprintf("%s%d%s", activeDynode.service.ToString(false), dnv.nonce, blockHash.ToString()); + + if(!CMessageSigner::SignMessage(strMessage, dnv.vchSig1, activeDynode.keyDynode)) { + LogPrintf("CDynodeMan::SendVerifyReply -- SignMessage() failed\n"); + return; + } + + if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, dnv.vchSig1, strMessage, strError)) { + LogPrintf("CDynodeMan::SendVerifyReply -- VerifyMessage() failed, error: %s\n", strError); + return; + } } - connman.PushMessage(pnode, NetMsgType::DNVERIFY, dnv); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DNVERIFY, dnv)); netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::DNVERIFY)+"-reply"); } @@ -1105,8 +1234,6 @@ void CDynodeMan::ProcessVerifyReply(CNode* pnode, CDynodeVerification& dnv) std::string strError; - int nDnCount = dnodeman.CountDynodes(); - // did we even ask for it? if that's the case we should have matching fulfilled request if(!netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::DNVERIFY)+"-request")) { LogPrintf("CDynodeMan::ProcessVerifyReply -- ERROR: we didn't ask for verification of %s, peer=%d\n", pnode->addr.ToString(), pnode->id); @@ -1137,24 +1264,32 @@ void CDynodeMan::ProcessVerifyReply(CNode* pnode, CDynodeVerification& dnv) return; } - if (nDnCount > 200) { - // we already verified this address, why node is spamming? - if(netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::DNVERIFY)+"-done")) { - LogPrintf("CDynodeMan::ProcessVerifyReply -- ERROR: already verified %s recently\n", pnode->addr.ToString()); - Misbehaving(pnode->id, 20); - return; - } + // we already verified this address, why node is spamming? + if(netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::DNVERIFY)+"-done")) { + LogPrintf("CDynodeMan::ProcessVerifyReply -- ERROR: already verified %s recently\n", pnode->addr.ToString()); + Misbehaving(pnode->id, 20); + return; } { LOCK(cs); - CDynode* prealDynode = NULL; + CDynode* prealDynode = nullptr; std::vector vpDynodesToBan; + + uint256 hash1 = dnv.GetSignatureHash1(blockHash); std::string strMessage1 = strprintf("%s%d%s", pnode->addr.ToString(false), dnv.nonce, blockHash.ToString()); + for (auto& dnpair : mapDynodes) { if(CAddress(dnpair.second.addr, NODE_NETWORK) == pnode->addr) { - if(CMessageSigner::VerifyMessage(dnpair.second.pubKeyDynode, dnv.vchSig1, strMessage1, strError)) { + bool fFound = false; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + fFound = CHashSigner::VerifyHash(hash1, dnpair.second.pubKeyDynode, dnv.vchSig1, strError); + // we don't care about dnv with signature in old format + } else { + fFound = CMessageSigner::VerifyMessage(dnpair.second.pubKeyDynode, dnv.vchSig1, strMessage1, strError); + } + if (fFound) { // found it! prealDynode = &dnpair.second; if(!dnpair.second.IsPoSeVerified()) { @@ -1162,25 +1297,40 @@ void CDynodeMan::ProcessVerifyReply(CNode* pnode, CDynodeVerification& dnv) } netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::DNVERIFY)+"-done"); - // we can only broadcast it if we are an activated Dynode - if(activeDynode.outpoint == COutPoint()) continue; + // we can only broadcast it if we are an activated dynode + if(activeDynode.outpoint.IsNull()) continue; // update ... dnv.addr = dnpair.second.addr; - dnv.vin1 = dnpair.second.vin; - dnv.vin2 = CTxIn(activeDynode.outpoint); - std::string strMessage2 = strprintf("%s%d%s%s%s", dnv.addr.ToString(false), dnv.nonce, blockHash.ToString(), - dnv.vin1.prevout.ToStringShort(), dnv.vin2.prevout.ToStringShort()); + dnv.dynodeOutpoint1 = dnpair.second.outpoint; + dnv.dynodeOutpoint2 = activeDynode.outpoint; // ... and sign it - if(!CMessageSigner::SignMessage(strMessage2, dnv.vchSig2, activeDynode.keyDynode)) { - LogPrintf("DynodeMan::ProcessVerifyReply -- SignMessage() failed\n"); - return; - } - std::string strError; - if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, dnv.vchSig2, strMessage2, strError)) { - LogPrintf("DynodeMan::ProcessVerifyReply -- VerifyMessage() failed, error: %s\n", strError); - return; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash2 = dnv.GetSignatureHash2(blockHash); + + if(!CHashSigner::SignHash(hash2, activeDynode.keyDynode, dnv.vchSig2)) { + LogPrintf("DynodeMan::ProcessVerifyReply -- SignHash() failed\n"); + return; + } + + if(!CHashSigner::VerifyHash(hash2, activeDynode.pubKeyDynode, dnv.vchSig2, strError)) { + LogPrintf("DynodeMan::ProcessVerifyReply -- VerifyHash() failed, error: %s\n", strError); + return; + } + } else { + std::string strMessage2 = strprintf("%s%d%s%s%s", dnv.addr.ToString(false), dnv.nonce, blockHash.ToString(), + dnv.dynodeOutpoint1.ToStringShort(), dnv.dynodeOutpoint2.ToStringShort()); + + if(!CMessageSigner::SignMessage(strMessage2, dnv.vchSig2, activeDynode.keyDynode)) { + LogPrintf("DynodeMan::ProcessVerifyReply -- SignMessage() failed\n"); + return; + } + + if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, dnv.vchSig2, strMessage2, strError)) { + LogPrintf("DynodeMan::ProcessVerifyReply -- VerifyMessage() failed, error: %s\n", strError); + return; + } } mWeAskedForVerification[pnode->addr] = dnv; @@ -1201,15 +1351,15 @@ void CDynodeMan::ProcessVerifyReply(CNode* pnode, CDynodeVerification& dnv) return; } LogPrintf("CDynodeMan::ProcessVerifyReply -- verified real Dynode %s for addr %s\n", - prealDynode->vin.prevout.ToStringShort(), pnode->addr.ToString()); + prealDynode->outpoint.ToStringShort(), pnode->addr.ToString()); // increase ban score for everyone else - BOOST_FOREACH(CDynode* pdn, vpDynodesToBan) { + for (const auto& pdn : vpDynodesToBan) { pdn->IncreasePoSeBanScore(); - LogPrint("dynode", "CDynodeMan::ProcessVerifyReply -- increased PoSe ban score for %s addr %s, new score %d\n", - prealDynode->vin.prevout.ToStringShort(), pnode->addr.ToString(), pdn->nPoSeBanScore); + LogPrint("Dynode", "CDynodeMan::ProcessVerifyReply -- increased PoSe ban score for %s addr %s, new score %d\n", + prealDynode->outpoint.ToStringShort(), pnode->addr.ToString(), pdn->nPoSeBanScore); } if(!vpDynodesToBan.empty()) - LogPrintf("CDynodeMan::ProcessVerifyReply -- PoSe score increased for %d fake dynodes, addr %s\n", + LogPrintf("CDynodeMan::ProcessVerifyReply -- PoSe score increased for %d fake Dynodes, addr %s\n", (int)vpDynodesToBan.size(), pnode->addr.ToString()); } } @@ -1228,14 +1378,14 @@ void CDynodeMan::ProcessVerifyBroadcast(CNode* pnode, const CDynodeVerification& // we don't care about history if(dnv.nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS) { - LogPrint("dynode", "CDynodeMan::ProcessVerifyBroadcast -- Outdated: current block %d, verification block %d, peer=%d\n", + LogPrint("Dynode", "CDynodeMan::ProcessVerifyBroadcast -- Outdated: current block %d, verification block %d, peer=%d\n", nCachedBlockHeight, dnv.nBlockHeight, pnode->id); return; } - if(dnv.vin1.prevout == dnv.vin2.prevout) { - LogPrint("dynode", "CDynodeMan::ProcessVerifyBroadcast -- ERROR: same vins %s, peer=%d\n", - dnv.vin1.prevout.ToStringShort(), pnode->id); + if(dnv.dynodeOutpoint1 == dnv.dynodeOutpoint2) { + LogPrint("Dynode", "CDynodeMan::ProcessVerifyBroadcast -- ERROR: same outpoints %s, peer=%d\n", + dnv.dynodeOutpoint1.ToStringShort(), pnode->id); // that was NOT a good idea to cheat and verify itself, // ban the node we received such message from Misbehaving(pnode->id, 100); @@ -1251,34 +1401,30 @@ void CDynodeMan::ProcessVerifyBroadcast(CNode* pnode, const CDynodeVerification& int nRank; - if (!GetDynodeRank(dnv.vin2.prevout, nRank, dnv.nBlockHeight, MIN_POSE_PROTO_VERSION)) { - LogPrint("dynode", "CDynodeMan::ProcessVerifyBroadcast -- Can't calculate rank for dynode %s\n", - dnv.vin2.prevout.ToStringShort()); + if (!GetDynodeRank(dnv.dynodeOutpoint2, nRank, dnv.nBlockHeight, MIN_POSE_PROTO_VERSION)) { + LogPrint("Dynode", "CDynodeMan::ProcessVerifyBroadcast -- Can't calculate rank for Dynode %s\n", + dnv.dynodeOutpoint2.ToStringShort()); return; } if(nRank > MAX_POSE_RANK) { - LogPrint("dynode", "CDynodeMan::ProcessVerifyBroadcast -- Dynode %s is not in top %d, current rank %d, peer=%d\n", - dnv.vin2.prevout.ToStringShort(), (int)MAX_POSE_RANK, nRank, pnode->id); + LogPrint("Dynode", "CDynodeMan::ProcessVerifyBroadcast -- Dynode %s is not in top %d, current rank %d, peer=%d\n", + dnv.dynodeOutpoint2.ToStringShort(), (int)MAX_POSE_RANK, nRank, pnode->id); return; } { LOCK(cs); - std::string strMessage1 = strprintf("%s%d%s", dnv.addr.ToString(false), dnv.nonce, blockHash.ToString()); - std::string strMessage2 = strprintf("%s%d%s%s%s", dnv.addr.ToString(false), dnv.nonce, blockHash.ToString(), - dnv.vin1.prevout.ToStringShort(), dnv.vin2.prevout.ToStringShort()); - - CDynode* pdn1 = Find(dnv.vin1.prevout); + CDynode* pdn1 = Find(dnv.dynodeOutpoint1); if(!pdn1) { - LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- can't find Dynode1 %s\n", dnv.vin1.prevout.ToStringShort()); + LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- can't find Dynode1 %s\n", dnv.dynodeOutpoint1.ToStringShort()); return; } - CDynode* pdn2 = Find(dnv.vin2.prevout); + CDynode* pdn2 = Find(dnv.dynodeOutpoint2); if(!pdn2) { - LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- can't find Dynode %s\n", dnv.vin2.prevout.ToStringShort()); + LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- can't find Dynode %s\n", dnv.dynodeOutpoint2.ToStringShort()); return; } @@ -1287,14 +1433,33 @@ void CDynodeMan::ProcessVerifyBroadcast(CNode* pnode, const CDynodeVerification& return; } - if(CMessageSigner::VerifyMessage(pdn1->pubKeyDynode, dnv.vchSig1, strMessage1, strError)) { - LogPrintf("DynodeMan::ProcessVerifyBroadcast -- VerifyMessage() for Dynode1 failed, error: %s\n", strError); - return; - } + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash1 = dnv.GetSignatureHash1(blockHash); + uint256 hash2 = dnv.GetSignatureHash2(blockHash); - if(CMessageSigner::VerifyMessage(pdn2->pubKeyDynode, dnv.vchSig2, strMessage2, strError)) { - LogPrintf("DynodeMan::ProcessVerifyBroadcast -- VerifyMessage() for Dynode2 failed, error: %s\n", strError); - return; + if(!CHashSigner::VerifyHash(hash1, pdn1->pubKeyDynode, dnv.vchSig1, strError)) { + LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- VerifyHash() failed, error: %s\n", strError); + return; + } + + if(!CHashSigner::VerifyHash(hash2, pdn2->pubKeyDynode, dnv.vchSig2, strError)) { + LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- VerifyHash() failed, error: %s\n", strError); + return; + } + } else { + std::string strMessage1 = strprintf("%s%d%s", dnv.addr.ToString(false), dnv.nonce, blockHash.ToString()); + std::string strMessage2 = strprintf("%s%d%s%s%s", dnv.addr.ToString(false), dnv.nonce, blockHash.ToString(), + dnv.dynodeOutpoint1.ToStringShort(), dnv.dynodeOutpoint2.ToStringShort()); + + if(!CMessageSigner::VerifyMessage(pdn1->pubKeyDynode, dnv.vchSig1, strMessage1, strError)) { + LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- VerifyMessage() for dynode1 failed, error: %s\n", strError); + return; + } + + if(!CMessageSigner::VerifyMessage(pdn2->pubKeyDynode, dnv.vchSig2, strMessage2, strError)) { + LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- VerifyMessage() for dynode2 failed, error: %s\n", strError); + return; + } } if(!pdn1->IsPoSeVerified()) { @@ -1303,19 +1468,19 @@ void CDynodeMan::ProcessVerifyBroadcast(CNode* pnode, const CDynodeVerification& dnv.Relay(); LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- verified Dynode %s for addr %s\n", - pdn1->vin.prevout.ToStringShort(), pdn1->addr.ToString()); + pdn1->outpoint.ToStringShort(), pdn1->addr.ToString()); // increase ban score for everyone else with the same addr int nCount = 0; for (auto& dnpair : mapDynodes) { - if(dnpair.second.addr != dnv.addr || dnpair.first == dnv.vin1.prevout) continue; + if(dnpair.second.addr != dnv.addr || dnpair.first == dnv.dynodeOutpoint1) continue; dnpair.second.IncreasePoSeBanScore(); nCount++; LogPrint("Dynode", "CDynodeMan::ProcessVerifyBroadcast -- increased PoSe ban score for %s addr %s, new score %d\n", dnpair.first.ToStringShort(), dnpair.second.addr.ToString(), dnpair.second.nPoSeBanScore); } if(nCount) - LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- PoSe score increased for %d fake dynodes, addr %s\n", + LogPrintf("CDynodeMan::ProcessVerifyBroadcast -- PoSe score increased for %d fake Dynodes, addr %s\n", nCount, pdn1->addr.ToString()); } } @@ -1333,28 +1498,6 @@ std::string CDynodeMan::ToString() const return info.str(); } -void CDynodeMan::UpdateDynodeList(CDynodeBroadcast dnb, CConnman& connman) -{ - LOCK2(cs_main, cs); - mapSeenDynodePing.insert(std::make_pair(dnb.lastPing.GetHash(), dnb.lastPing)); - mapSeenDynodeBroadcast.insert(std::make_pair(dnb.GetHash(), std::make_pair(GetTime(), dnb))); - - LogPrintf("CDynodeMan::UpdateDynodeList -- Dynode=%s addr=%s\n", dnb.vin.prevout.ToStringShort(), dnb.addr.ToString()); - - CDynode* pdn = Find(dnb.vin.prevout); - if(pdn == NULL) { - if(Add(dnb)) { - dynodeSync.BumpAssetLastTime("CDynodeMan::UpdateDynodeList - new"); - } - } else { - CDynodeBroadcast dnbOld = mapSeenDynodeBroadcast[CDynodeBroadcast(*pdn).GetHash()].second; - if(pdn->UpdateFromNewBroadcast(dnb, connman)) { - dynodeSync.BumpAssetLastTime("CDynodeMan::UpdateDynodeList - seen"); - mapSeenDynodeBroadcast.erase(dnbOld.GetHash()); - } - } -} - bool CDynodeMan::CheckDnbAndUpdateDynodeList(CNode* pfrom, CDynodeBroadcast dnb, int& nDos, CConnman& connman) { // Need to lock cs_main here to ensure consistent locking order because the SimpleCheck call below locks cs_main @@ -1363,14 +1506,14 @@ bool CDynodeMan::CheckDnbAndUpdateDynodeList(CNode* pfrom, CDynodeBroadcast dnb, { LOCK(cs); nDos = 0; - LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s\n", dnb.vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s\n", dnb.outpoint.ToStringShort()); uint256 hash = dnb.GetHash(); if(mapSeenDynodeBroadcast.count(hash) && !dnb.fRecovery) { //seen - LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s seen\n", dnb.vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s seen\n", dnb.outpoint.ToStringShort()); // less then 2 pings left before this DN goes into non-recoverable state, bump sync timeout if(GetTime() - mapSeenDynodeBroadcast[hash].first > DYNODE_NEW_START_REQUIRED_SECONDS - DYNODE_MIN_DNP_SECONDS * 2) { - LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s seen update\n", dnb.vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s seen update\n", dnb.outpoint.ToStringShort()); mapSeenDynodeBroadcast[hash].first = GetTime(); dynodeSync.BumpAssetLastTime("CDynodeMan::CheckDnbAndUpdateDynodeList - seen"); } @@ -1389,29 +1532,29 @@ bool CDynodeMan::CheckDnbAndUpdateDynodeList(CNode* pfrom, CDynodeBroadcast dnb, LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dnb=%s seen request, addr=%s, better lastPing: %d min ago, projected dn state: %s\n", hash.ToString(), pfrom->addr.ToString(), (GetAdjustedTime() - dnb.lastPing.sigTime)/60, dnTemp.GetStateString()); if(dnTemp.IsValidStateForAutoStart(dnTemp.nActiveState)) { // this node thinks it's a good one - LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s seen good\n", dnb.vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s seen good\n", dnb.outpoint.ToStringShort()); mDnbRecoveryGoodReplies[hash].push_back(dnb); - + } } } } + return true; } - return true; - } mapSeenDynodeBroadcast.insert(std::make_pair(hash, std::make_pair(GetTime(), dnb))); - LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s new\n", dnb.vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- dynode=%s new\n", dnb.outpoint.ToStringShort()); if(!dnb.SimpleCheck(nDos)) { - LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- SimpleCheck() failed, dynode=%s\n", dnb.vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- SimpleCheck() failed, dynode=%s\n", dnb.outpoint.ToStringShort()); return false; } + // search Dynode list - CDynode* pdn = Find(dnb.vin.prevout); + CDynode* pdn = Find(dnb.outpoint); if(pdn) { CDynodeBroadcast dnbOld = mapSeenDynodeBroadcast[CDynodeBroadcast(*pdn).GetHash()].second; if(!dnb.Update(pdn, nDos, connman)) { - LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- Update() failed, dynode=%s\n", dnb.vin.prevout.ToStringShort()); + LogPrint("dynode", "CDynodeMan::CheckDnbAndUpdateDynodeList -- Update() failed, dynode=%s\n", dnb.outpoint.ToStringShort()); return false; } if(hash != dnbOld.GetHash()) { @@ -1430,7 +1573,7 @@ bool CDynodeMan::CheckDnbAndUpdateDynodeList(CNode* pfrom, CDynodeBroadcast dnb, if(dnb.nProtocolVersion == PROTOCOL_VERSION) { // ... and PROTOCOL_VERSION, then we've been remotely activated ... LogPrintf("CDynodeMan::CheckDnbAndUpdateDynodeList -- Got NEW Dynode entry: dynode=%s sigTime=%lld addr=%s\n", - dnb.vin.prevout.ToStringShort(), dnb.sigTime, dnb.addr.ToString()); + dnb.outpoint.ToStringShort(), dnb.sigTime, dnb.addr.ToString()); activeDynode.ManageState(connman); } else { // ... otherwise we need to reactivate our node, do not add it to the list and do not relay @@ -1441,7 +1584,7 @@ bool CDynodeMan::CheckDnbAndUpdateDynodeList(CNode* pfrom, CDynodeBroadcast dnb, } dnb.Relay(connman); } else { - LogPrintf("CDynodeMan::CheckDnbAndUpdateDynodeList -- Rejected Dynode entry: %s addr=%s\n", dnb.vin.prevout.ToStringShort(), dnb.addr.ToString()); + LogPrintf("CDynodeMan::CheckDnbAndUpdateDynodeList -- Rejected Dynode entry: %s addr=%s\n", dnb.outpoint.ToStringShort(), dnb.addr.ToString()); return false; } @@ -1454,18 +1597,19 @@ void CDynodeMan::UpdateLastPaid(const CBlockIndex* pindex) if(fLiteMode || !dynodeSync.IsWinnersListSynced() || mapDynodes.empty()) return; - static bool IsFirstRun = true; - // Do full scan on first run or if we are not a Dynode - // (DNs should update this info on every block, so limited scan should be enough for them) - int nMaxBlocksToScanBack = (IsFirstRun || !fDynodeMode) ? dnpayments.GetStorageLimit() : LAST_PAID_SCAN_BLOCKS; + static int nLastRunBlockHeight = 0; + // Scan at least LAST_PAID_SCAN_BLOCKS but no more than dnpayments.GetStorageLimit() + int nMaxBlocksToScanBack = std::max(LAST_PAID_SCAN_BLOCKS, nCachedBlockHeight - nLastRunBlockHeight); + nMaxBlocksToScanBack = std::min(nMaxBlocksToScanBack, dnpayments.GetStorageLimit()); - // nCachedBlockHeight, nMaxBlocksToScanBack, IsFirstRun ? "true" : "false"); + LogPrint("dynode", "CDynodeMan::UpdateLastPaid -- nCachedBlockHeight=%d, nLastRunBlockHeight=%d, nMaxBlocksToScanBack=%d\n", + nCachedBlockHeight, nLastRunBlockHeight, nMaxBlocksToScanBack); - for (auto& dnpair: mapDynodes) { + for (auto& dnpair : mapDynodes) { dnpair.second.UpdateLastPaid(pindex, nMaxBlocksToScanBack); } - IsFirstRun = false; + nLastRunBlockHeight = nCachedBlockHeight; } void CDynodeMan::UpdateLastSentinelPingTime() @@ -1541,7 +1685,7 @@ void CDynodeMan::SetDynodeLastPing(const COutPoint& outpoint, const CDynodePing& void CDynodeMan::UpdatedBlockTip(const CBlockIndex *pindex) { nCachedBlockHeight = pindex->nHeight; - LogPrint("dynode", "CDynodeMan::UpdatedBlockTip -- nCachedBlockHeight=%d\n", nCachedBlockHeight); + LogPrint("Dynode", "CDynodeMan::UpdatedBlockTip -- nCachedBlockHeight=%d\n", nCachedBlockHeight); CheckSameAddr(); @@ -1551,6 +1695,47 @@ void CDynodeMan::UpdatedBlockTip(const CBlockIndex *pindex) } } +void CDynodeMan::WarnDynodeDaemonUpdates() +{ + LOCK(cs); + + static bool fWarned = false; + + if (fWarned || !size() || !dynodeSync.IsDynodeListSynced()) + return; + + int nUpdatedDynodes{0}; + + for (const auto& dnpair : mapDynodes) { + if (dnpair.second.lastPing.nDaemonVersion > CLIENT_VERSION) { + ++nUpdatedDynodes; + } + } + + // Warn only when at least half of known dynodes already updated + if (nUpdatedDynodes < size() / 2) + return; + + std::string strWarning; + if (nUpdatedDynodes != size()) { + strWarning = strprintf(_("Warning: At least %d of %d dynodes are running on a newer software version. Please check latest releases, you might need to update too."), + nUpdatedDynodes, size()); + } else { + // someone was postponing this update for way too long probably + strWarning = strprintf(_("Warning: Every dynode (out of %d known ones) is running on a newer software version. Please check latest releases, it's very likely that you missed a major/critical update."), + size()); + } + + // notify GetWarnings(), called by Qt and the JSON-RPC code to warn the user + SetMiscWarning(strWarning); + // trigger GUI update + uiInterface.NotifyAlertChanged(SerializeHash(strWarning), CT_NEW); + // trigger cmd-line notification + CAlert::Notify(strWarning); + + fWarned = true; +} + void CDynodeMan::NotifyDynodeUpdates(CConnman& connman) { // Avoid double locking @@ -1574,3 +1759,31 @@ void CDynodeMan::NotifyDynodeUpdates(CConnman& connman) fDynodesAdded = false; fDynodesRemoved = false; } + +void CDynodeMan::DoMaintenance(CConnman& connman) +{ + if(fLiteMode) return; // disable all Dynamic specific functionality + + if(!dynodeSync.IsBlockchainSynced() || ShutdownRequested()) + return; + + static unsigned int nTick = 0; + + nTick++; + + // make sure to check all dynodes first + dnodeman.Check(); + + dnodeman.ProcessPendingDnbRequests(connman); + dnodeman.ProcessPendingDnvRequests(connman); + + if(nTick % 60 == 0) { + dnodeman.ProcessDynodeConnections(connman); + dnodeman.CheckAndRemove(connman); + dnodeman.WarnDynodeDaemonUpdates(); + } + + if(fDynodeMode && (nTick % (60 * 5) == 0)) { + dnodeman.DoFullVerificationStep(connman); + } +} diff --git a/src/dynodeman.h b/src/dynodeman.h index 7540b53bb8..7d677b99ac 100644 --- a/src/dynodeman.h +++ b/src/dynodeman.h @@ -10,15 +10,16 @@ #include "sync.h" class CDynodeMan; +class CConnman; extern CDynodeMan dnodeman; class CDynodeMan { public: - typedef std::pair score_pair_t; + typedef std::pair score_pair_t; typedef std::vector score_pair_vec_t; - typedef std::pair rank_pair_t; + typedef std::pair rank_pair_t; typedef std::vector rank_pair_vec_t; private: @@ -26,7 +27,7 @@ class CDynodeMan static const int PSEG_UPDATE_SECONDS = 3 * 60 * 60; - static const int LAST_PAID_SCAN_BLOCKS = 100; + static const int LAST_PAID_SCAN_BLOCKS; static const int MIN_POSE_PROTO_VERSION = 70900; static const int MAX_POSE_CONNECTIONS = 10; @@ -48,18 +49,22 @@ class CDynodeMan // map to hold all DNs std::map mapDynodes; // who's asked for the Dynode list and the last time - std::map mAskedUsForDynodeList; + std::map mAskedUsForDynodeList; // who we asked for the Dynode list and the last time - std::map mWeAskedForDynodeList; + std::map mWeAskedForDynodeList; // which Dynodes we've asked for - std::map > mWeAskedForDynodeListEntry; - // who we asked for the Dynode verification - std::map mWeAskedForVerification; + std::map > mWeAskedForDynodeListEntry; + + // who we asked for the dynode verification + std::map mWeAskedForVerification; // these maps are used for Dynode recovery from DYNODE_NEW_START_REQUIRED state - std::map > > mDnbRecoveryRequests; + std::map > > mDnbRecoveryRequests; std::map > mDnbRecoveryGoodReplies; std::list< std::pair > listScheduledDnbRequestConnections; + std::map > > mapPendingDNB; + std::map > mapPendingDNV; + CCriticalSection cs_mapPendingDNV; /// Set when Dynodes are added, cleared when CGovernanceManager is notified bool fDynodesAdded; @@ -77,6 +82,11 @@ class CDynodeMan bool GetDynodeScores(const uint256& nBlockHash, score_pair_vec_t& vecDynodeScoresRet, int nMinProtocol = 0); + void SyncSingle(CNode* pnode, const COutPoint& outpoint, CConnman& connman); + void SyncAll(CNode* pnode, CConnman& connman); + + void PushPsegInvs(CNode* pnode, const CDynode& dn); + public: // Keep track of all broadcasts I've seen std::map > mapSeenDynodeBroadcast; @@ -159,8 +169,8 @@ class CDynodeMan bool Has(const COutPoint& outpoint); bool GetDynodeInfo(const COutPoint& outpoint, dynode_info_t& dnInfoRet); - bool GetDynodeInfo(const CPubKey& pubKeyDynode, dynode_info_t& dnInfoRet); + bool GetDynodeInfo(const CScript& payee, dynode_info_t& dnInfoRet); /// Find an entry in the Dynode list that is next to be paid bool GetNextDynodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCountRet, dynode_info_t& dnInfoRet); @@ -177,12 +187,14 @@ class CDynodeMan void ProcessDynodeConnections(CConnman& connman); std::pair > PopScheduledDnbRequestConnection(); + void ProcessPendingDnbRequests(CConnman& connman); - void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman); + void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void DoFullVerificationStep(CConnman& connman); void CheckSameAddr(); - bool SendVerifyRequest(const CAddress& addr, const std::vector& vSortedByAddr, CConnman& connman); + bool SendVerifyRequest(const CAddress& addr, const std::vector& vSortedByAddr, CConnman& connman); + void ProcessPendingDnvRequests(CConnman& connman); void SendVerifyReply(CNode* pnode, CDynodeVerification& dnv, CConnman& connman); void ProcessVerifyReply(CNode* pnode, CDynodeVerification& dnv); void ProcessVerifyBroadcast(CNode* pnode, const CDynodeVerification& dnv); @@ -192,14 +204,11 @@ class CDynodeMan std::string ToString() const; - /// Update Dynode list and maps using provided CDynodeBroadcast - void UpdateDynodeList(CDynodeBroadcast dnb, CConnman& connman); /// Perform complete check and only then update list and maps bool CheckDnbAndUpdateDynodeList(CNode* pfrom, CDynodeBroadcast dnb, int& nDos, CConnman& connman); bool IsDnbRecoveryRequested(const uint256& hash) { return mDnbRecoveryRequests.count(hash); } void UpdateLastPaid(const CBlockIndex* pindex); - bool UpdateLastPsq(const CTxIn& vin); void AddDirtyGovernanceObjectHash(const uint256& nHash) { @@ -227,12 +236,15 @@ class CDynodeMan void UpdatedBlockTip(const CBlockIndex *pindex); + void WarnDynodeDaemonUpdates(); + /** * Called to notify CGovernanceManager that the Dynode index has been updated. * Must be called while not holding the CDynodeMan::cs mutex */ void NotifyDynodeUpdates(CConnman& connman); + void DoMaintenance(CConnman &connman); }; #endif // DYNAMIC_DYNODEMAN_H diff --git a/src/fluid/fluid.cpp b/src/fluid/fluid.cpp index bb15b7460a..db350aa087 100644 --- a/src/fluid/fluid.cpp +++ b/src/fluid/fluid.cpp @@ -460,8 +460,8 @@ bool CFluid::GetMintingInstructions(const CBlockIndex* pblockindex, CDynamicAddr CBlock block; if (GetFluidBlock(pblockindex, block)) { - for (const CTransaction& tx : block.vtx) { - for (const CTxOut& txout : tx.vout) { + for (const CTransactionRef& tx : block.vtx) { + for (const CTxOut& txout : tx->vout) { if (txout.scriptPubKey.IsProtocolInstruction(MINT_TX)) { std::string message; if (CheckIfQuorumExists(ScriptToAsmStr(txout.scriptPubKey), message)) @@ -477,8 +477,8 @@ bool CFluid::GetProofOverrideRequest(const CBlockIndex* pblockindex, CAmount& co CBlock block; if (GetFluidBlock(pblockindex, block)) { - for (const CTransaction& tx : block.vtx) { - for (const CTxOut& txout : tx.vout) { + for (const CTransactionRef& tx : block.vtx) { + for (const CTxOut& txout : tx->vout) { if (txout.scriptPubKey.IsProtocolInstruction(MINING_MODIFY_TX)) { std::string message; if (CheckIfQuorumExists(ScriptToAsmStr(txout.scriptPubKey), message)) @@ -494,8 +494,8 @@ bool CFluid::GetDynodeOverrideRequest(const CBlockIndex* pblockindex, CAmount& c CBlock block; if (GetFluidBlock(pblockindex, block)) { - for (const CTransaction& tx : block.vtx) { - for (const CTxOut& txout : tx.vout) { + for (const CTransactionRef& tx : block.vtx) { + for (const CTxOut& txout : tx->vout) { if (txout.scriptPubKey.IsProtocolInstruction(DYNODE_MODFIY_TX)) { std::string message; if (CheckIfQuorumExists(ScriptToAsmStr(txout.scriptPubKey), message)) @@ -511,8 +511,8 @@ void CFluid::AddFluidTransactionsToRecord(const CBlockIndex* pblockindex, std::v CBlock block; if (GetFluidBlock(pblockindex, block)) { - for (const CTransaction& tx : block.vtx) { - for (const CTxOut& txout : tx.vout) { + for (const CTransactionRef& tx : block.vtx) { + for (const CTxOut& txout : tx->vout) { if (IsTransactionFluid(txout.scriptPubKey)) { if (!InsertTransactionToRecord(txout.scriptPubKey, transactionRecord)) { LogPrintf("AddFluidTransactionsToRecord(): Script Database Entry: %s , FAILED!\n", ScriptToAsmStr(txout.scriptPubKey)); diff --git a/src/fluid/rpcfluid.cpp b/src/fluid/rpcfluid.cpp index 9b0a510068..16ab94cb41 100644 --- a/src/fluid/rpcfluid.cpp +++ b/src/fluid/rpcfluid.cpp @@ -568,19 +568,20 @@ UniValue getfluidsovereigns(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ -------------------- #ifdef ENABLE_WALLET /* Fluid Protocol */ - { "fluid", "sendfluidtransaction", &sendfluidtransaction, true }, - { "fluid", "signtoken", &signtoken, true }, - { "fluid", "consenttoken", &consenttoken, true }, - { "fluid", "getrawpubkey", &getrawpubkey, true }, - { "fluid", "verifyquorum", &verifyquorum, true }, - { "fluid", "maketoken", &maketoken, true }, - { "fluid", "getfluidhistory", &getfluidhistory, true }, - { "fluid", "getfluidhistoryraw", &getfluidhistoryraw, true }, - { "fluid", "getfluidsovereigns", &getfluidsovereigns, true }, - { "fluid", "gettime", &gettime, true }, + { "fluid", "sendfluidtransaction", &sendfluidtransaction, true, {"opcode","hexstring"} }, + { "fluid", "signtoken", &signtoken, true, {"address","tokenkey"} }, + { "fluid", "consenttoken", &consenttoken, true, {"address","tokenkey"} }, + { "fluid", "getrawpubkey", &getrawpubkey, true, {"address"} }, + { "fluid", "verifyquorum", &verifyquorum, true, {"tokenkey"} }, + { "fluid", "maketoken", &maketoken, true, {"string"} }, + { "fluid", "getfluidhistory", &getfluidhistory, true, {} }, + { "fluid", "getfluidhistoryraw", &getfluidhistoryraw, true, {} }, + { "fluid", "getfluidsovereigns", &getfluidsovereigns, true, {} }, + { "fluid", "gettime", &gettime, true, {} }, #endif //ENABLE_WALLET }; diff --git a/src/governance-classes.cpp b/src/governance-classes.cpp index aceeb4032b..c4a90df8b3 100644 --- a/src/governance-classes.cpp +++ b/src/governance-classes.cpp @@ -14,16 +14,14 @@ #include -#include #include - // DECLARE GLOBAL VARIABLES FOR GOVERNANCE CLASSES CGovernanceTriggerManager triggerman; // SPLIT UP STRING BY DELIMITER // http://www.boost.org/doc/libs/1_58_0/doc/html/boost/algorithm/split_idp202406848.html -std::vector SplitBy(std::string strCommand, std::string strDelimit) +std::vector SplitBy(const std::string& strCommand, const std::string& strDelimit) { std::vector vParts; boost::split(vParts, strCommand, boost::is_any_of(strDelimit)); @@ -40,7 +38,7 @@ std::vector SplitBy(std::string strCommand, std::string strDelimit) CAmount ParsePaymentAmount(const std::string& strAmount) { - DBG( cout << "ParsePaymentAmount Start: strAmount = " << strAmount << endl; ); + DBG( std::cout << "ParsePaymentAmount Start: strAmount = " << strAmount << std::endl; ); CAmount nAmount = 0; if (strAmount.empty()) { @@ -95,7 +93,7 @@ CAmount ParsePaymentAmount(const std::string& strAmount) throw std::runtime_error(ostr.str()); } - DBG( cout << "ParsePaymentAmount Returning true nAmount = " << nAmount << endl; ); + DBG( std::cout << "ParsePaymentAmount Returning true nAmount = " << nAmount << std::endl; ); return nAmount; } @@ -106,17 +104,17 @@ CAmount ParsePaymentAmount(const std::string& strAmount) bool CGovernanceTriggerManager::AddNewTrigger(uint256 nHash) { - DBG( cout << "CGovernanceTriggerManager::AddNewTrigger: Start" << endl; ); + DBG( std::cout << "CGovernanceTriggerManager::AddNewTrigger: Start" << std::endl; ); AssertLockHeld(governance.cs); // IF WE ALREADY HAVE THIS HASH, RETURN if(mapTrigger.count(nHash)) { DBG( - cout << "CGovernanceTriggerManager::AddNewTrigger: Already have hash" + std::cout << "CGovernanceTriggerManager::AddNewTrigger: Already have hash" << ", nHash = " << nHash.GetHex() << ", count = " << mapTrigger.count(nHash) << ", mapTrigger.size() = " << mapTrigger.size() - << endl; ); + << std::endl; ); return false; } @@ -125,25 +123,25 @@ bool CGovernanceTriggerManager::AddNewTrigger(uint256 nHash) CSuperblock_sptr pSuperblockTmp(new CSuperblock(nHash)); pSuperblock = pSuperblockTmp; } - catch(const std::exception& e) { - DBG( cout << "CGovernanceTriggerManager::AddNewTrigger Error creating superblock" + catch(std::exception& e) { + DBG( std::cout << "CGovernanceTriggerManager::AddNewTrigger Error creating superblock" << ", e.what() = " << e.what() - << endl; ); + << std::endl; ); LogPrintf("CGovernanceTriggerManager::AddNewTrigger -- Error creating superblock: %s\n", e.what()); return false; } catch(...) { LogPrintf("CGovernanceTriggerManager::AddNewTrigger: Unknown Error creating superblock\n"); - DBG( cout << "CGovernanceTriggerManager::AddNewTrigger Error creating superblock catchall" << endl; ); + DBG( std::cout << "CGovernanceTriggerManager::AddNewTrigger Error creating superblock catchall" << std::endl; ); return false; } pSuperblock->SetStatus(SEEN_OBJECT_IS_VALID); - DBG( cout << "CGovernanceTriggerManager::AddNewTrigger: Inserting trigger" << endl; ); + DBG( std::cout << "CGovernanceTriggerManager::AddNewTrigger: Inserting trigger" << std::endl; ); mapTrigger.insert(std::make_pair(nHash, pSuperblock)); - DBG( cout << "CGovernanceTriggerManager::AddNewTrigger: End" << endl; ); + DBG( std::cout << "CGovernanceTriggerManager::AddNewTrigger: End" << std::endl; ); return true; } @@ -157,39 +155,31 @@ bool CGovernanceTriggerManager::AddNewTrigger(uint256 nHash) void CGovernanceTriggerManager::CleanAndRemove() { LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- Start\n"); - DBG( cout << "CGovernanceTriggerManager::CleanAndRemove: Start" << endl; ); + DBG( std::cout << "CGovernanceTriggerManager::CleanAndRemove: Start" << std::endl; ); AssertLockHeld(governance.cs); - // LOOK AT THESE OBJECTS AND COMPILE A VALID LIST OF TRIGGERS - for(trigger_m_it it = mapTrigger.begin(); it != mapTrigger.end(); ++it) { - //int nNewStatus = -1; - CGovernanceObject* pObj = governance.FindGovernanceObject((*it).first); - if(!pObj) { - continue; - } - CSuperblock_sptr& pSuperblock = it->second; - if(!pSuperblock) { - continue; - } - // IF THIS ISN'T A TRIGGER, WHY ARE WE HERE? - if(pObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) { - pSuperblock->SetStatus(SEEN_OBJECT_ERROR_INVALID); - } - } - - // Remove triggers that are invalid or already executed - DBG( cout << "CGovernanceTriggerManager::CleanAndRemove: mapTrigger.size() = " << mapTrigger.size() << endl; ); + // Remove triggers that are invalid or expired + DBG( std::cout << "CGovernanceTriggerManager::CleanAndRemove: mapTrigger.size() = " << mapTrigger.size() << std::endl; ); LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- mapTrigger.size() = %d\n", mapTrigger.size()); + trigger_m_it it = mapTrigger.begin(); while(it != mapTrigger.end()) { bool remove = false; + CGovernanceObject* pObj = nullptr; CSuperblock_sptr& pSuperblock = it->second; if(!pSuperblock) { - DBG( cout << "CGovernanceTriggerManager::CleanAndRemove: NULL superblock marked for removal " << endl; ); + DBG( std::cout << "CGovernanceTriggerManager::CleanAndRemove: NULL superblock marked for removal" << std::endl; ); LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- NULL superblock marked for removal\n"); remove = true; } else { - DBG( cout << "CGovernanceTriggerManager::CleanAndRemove: superblock status = " << pSuperblock->GetStatus() << endl; ); + pObj = governance.FindGovernanceObject(it->first); + if(!pObj || pObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) { + DBG( std::cout << "CGovernanceTriggerManager::CleanAndRemove: Unknown or non-trigger superblock" << std::endl; ); + LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- Unknown or non-trigger superblock\n"); + pSuperblock->SetStatus(SEEN_OBJECT_ERROR_INVALID); + } + + DBG( std::cout << "CGovernanceTriggerManager::CleanAndRemove: superblock status = " << pSuperblock->GetStatus() << std::endl; ); LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- superblock status = %d\n", pSuperblock->GetStatus()); switch(pSuperblock->GetStatus()) { case SEEN_OBJECT_ERROR_INVALID: @@ -199,40 +189,33 @@ void CGovernanceTriggerManager::CleanAndRemove() break; case SEEN_OBJECT_IS_VALID: case SEEN_OBJECT_EXECUTED: - { - int nTriggerBlock = Params().GetConsensus().nSuperblockCycle; - // Rough approximation: a cycle of superblock ++ - int nExpirationBlock = nTriggerBlock + GOVERNANCE_TRIGGER_EXPIRATION_BLOCKS; - LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- nTriggerBlock = %d, nExpirationBlock = %d\n", nTriggerBlock, nExpirationBlock); - if(governance.GetCachedBlockHeight() > nExpirationBlock) { - LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- Outdated trigger found\n"); - remove = true; - CGovernanceObject* pgovobj = pSuperblock->GetGovernanceObject(); - if(pgovobj) { - LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- Expiring outdated object: %s\n", pgovobj->GetHash().ToString()); - pgovobj->fExpired = true; - pgovobj->nDeletionTime = GetAdjustedTime(); - } - } - } + remove = pSuperblock->IsExpired(); break; default: break; } } + LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- %smarked for removal\n", remove ? "" : "NOT "); if(remove) { DBG( - string strdata = "NULL"; - CGovernanceObject* pgovobj = pSuperblock->GetGovernanceObject(); - if(pgovobj) { - strdata = pgovobj->GetDataAsString(); + std::string strDataAsPlainString = "NULL"; + if(pObj) { + strDataAsPlainString = pObj->GetDataAsPlainString(); } - cout << "CGovernanceTriggerManager::CleanAndRemove: Removing object: " - << strdata - << endl; + std::cout << "CGovernanceTriggerManager::CleanAndRemove: Removing object: " + << strDataAsPlainString + << std::endl; ); LogPrint("gobject", "CGovernanceTriggerManager::CleanAndRemove -- Removing trigger object\n"); + // mark corresponding object for deletion + if (pObj) { + pObj->fCachedDelete = true; + if (pObj->nDeletionTime == 0) { + pObj->nDeletionTime = GetAdjustedTime(); + } + } + // delete the trigger mapTrigger.erase(it++); } else { @@ -240,7 +223,7 @@ void CGovernanceTriggerManager::CleanAndRemove() } } - DBG( cout << "CGovernanceTriggerManager::CleanAndRemove: End" << endl; ); + DBG( std::cout << "CGovernanceTriggerManager::CleanAndRemove: End" << std::endl; ); } /** @@ -255,22 +238,18 @@ std::vector CGovernanceTriggerManager::GetActiveTriggers() AssertLockHeld(governance.cs); std::vector vecResults; - DBG( cout << "GetActiveTriggers: mapTrigger.size() = " << mapTrigger.size() << endl; ); + DBG( std::cout << "GetActiveTriggers: mapTrigger.size() = " << mapTrigger.size() << std::endl; ); // LOOK AT THESE OBJECTS AND COMPILE A VALID LIST OF TRIGGERS - trigger_m_it it = mapTrigger.begin(); - while(it != mapTrigger.end()) { - - CGovernanceObject* pObj = governance.FindGovernanceObject((*it).first); - + for (const auto& pair : mapTrigger) { + CGovernanceObject* pObj = governance.FindGovernanceObject(pair.first); if(pObj) { - DBG( cout << "GetActiveTriggers: pObj->GetDataAsString() = " << pObj->GetDataAsString() << endl; ); - vecResults.push_back(it->second); + DBG( std::cout << "GetActiveTriggers: pObj->GetDataAsPlainString() = " << pObj->GetDataAsPlainString() << std::endl; ); + vecResults.push_back(pair.second); } - ++it; } - DBG( cout << "GetActiveTriggers: vecResults.size() = " << vecResults.size() << endl; ); + DBG( std::cout << "GetActiveTriggers: vecResults.size() = " << vecResults.size() << std::endl; ); return vecResults; } @@ -294,34 +273,36 @@ bool CSuperblockManager::IsSuperblockTriggered(int nBlockHeight) LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- vecTriggers.size() = %d\n", vecTriggers.size()); - DBG( cout << "IsSuperblockTriggered Number triggers = " << vecTriggers.size() << endl; ); + DBG( std::cout << "IsSuperblockTriggered Number triggers = " << vecTriggers.size() << std::endl; ); - BOOST_FOREACH(CSuperblock_sptr pSuperblock, vecTriggers) + for (const auto& pSuperblock : vecTriggers) { if(!pSuperblock) { LogPrintf("CSuperblockManager::IsSuperblockTriggered -- Non-superblock found, continuing\n"); - DBG( cout << "IsSuperblockTriggered Not a superblock, continuing " << endl; ); + DBG( std::cout << "IsSuperblockTriggered Not a superblock, continuing " << std::endl; ); continue; } CGovernanceObject* pObj = pSuperblock->GetGovernanceObject(); if(!pObj) { - LogPrintf("CSuperblockManager::IsSuperblockTriggered -- pObj == NULL, continuing\n"); - DBG( cout << "IsSuperblockTriggered pObj is NULL, continuing" << endl; ); + LogPrintf("CSuperblockManager::IsSuperblockTriggered -- pObj == nullptr, continuing\n"); + DBG( std::cout << "IsSuperblockTriggered pObj is NULL, continuing" << std::endl; ); continue; } - LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- data = %s\n", pObj->GetDataAsString()); + LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- data = %s\n", pObj->GetDataAsPlainString()); - if(nBlockHeight != Params().GetConsensus().nSuperblockCycle) { + // note : 12.1 - is epoch calculation correct? + + if(nBlockHeight != pSuperblock->GetBlockHeight()) { LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- block height doesn't match nBlockHeight = %d, blockStart = %d, continuing\n", nBlockHeight, - Params().GetConsensus().nSuperblockCycle); - DBG( cout << "IsSuperblockTriggered Not the target block, continuing" + pSuperblock->GetBlockHeight()); + DBG( std::cout << "IsSuperblockTriggered Not the target block, continuing" << ", nBlockHeight = " << nBlockHeight - << ", superblock->GetBlockStart() = " << pSuperblock->GetBlockStart() - << endl; ); + << ", superblock->GetBlockHeight() = " << pSuperblock->GetBlockHeight() + << std::endl; ); continue; } @@ -331,12 +312,12 @@ bool CSuperblockManager::IsSuperblockTriggered(int nBlockHeight) if(pObj->IsSetCachedFunding()) { LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- fCacheFunding = true, returning true\n"); - DBG( cout << "IsSuperblockTriggered returning true" << endl; ); + DBG( std::cout << "IsSuperblockTriggered returning true" << std::endl; ); return true; } else { LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- fCacheFunding = false, continuing\n"); - DBG( cout << "IsSuperblockTriggered No fCachedFunding, continuing" << endl; ); + DBG( std::cout << "IsSuperblockTriggered No fCachedFunding, continuing" << std::endl; ); } } @@ -354,32 +335,32 @@ bool CSuperblockManager::GetBestSuperblock(CSuperblock_sptr& pSuperblockRet, int std::vector vecTriggers = triggerman.GetActiveTriggers(); int nYesCount = 0; - BOOST_FOREACH(CSuperblock_sptr pSuperblock, vecTriggers) { + for (const auto& pSuperblock : vecTriggers) { if(!pSuperblock) { - DBG( cout << "GetBestSuperblock Not a superblock, continuing" << endl; ); + DBG( std::cout << "GetBestSuperblock Not a superblock, continuing" << std::endl; ); continue; } CGovernanceObject* pObj = pSuperblock->GetGovernanceObject(); if(!pObj) { - DBG( cout << "GetBestSuperblock pObj is NULL, continuing" << endl; ); + DBG( std::cout << "GetBestSuperblock pObj is NULL, continuing" << std::endl; ); continue; } - if(nBlockHeight != Params().GetConsensus().nSuperblockCycle) { - DBG( cout << "GetBestSuperblock Not the target block, continuing" << endl; ); + if(nBlockHeight != pSuperblock->GetBlockHeight()) { + DBG( std::cout << "GetBestSuperblock Not the target block, continuing" << std::endl; ); continue; } // DO WE HAVE A NEW WINNER? int nTempYesCount = pObj->GetAbsoluteYesCount(VOTE_SIGNAL_FUNDING); - DBG( cout << "GetBestSuperblock nTempYesCount = " << nTempYesCount << endl; ); + DBG( std::cout << "GetBestSuperblock nTempYesCount = " << nTempYesCount << std::endl; ); if(nTempYesCount > nYesCount) { nYesCount = nTempYesCount; pSuperblockRet = pSuperblock; - DBG( cout << "GetBestSuperblock Valid superblock found, pSuperblock set" << endl; ); + DBG( std::cout << "GetBestSuperblock Valid superblock found, pSuperblock set" << std::endl; ); } } @@ -394,7 +375,7 @@ bool CSuperblockManager::GetBestSuperblock(CSuperblock_sptr& pSuperblockRet, int void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNewRet, int nBlockHeight, std::vector& voutSuperblockRet) { - DBG( cout << "CSuperblockManager::CreateSuperblock Start" << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock Start" << std::endl; ); LOCK(governance.cs); @@ -403,7 +384,7 @@ void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNewRet, int nBl CSuperblock_sptr pSuperblock; if(!CSuperblockManager::GetBestSuperblock(pSuperblock, nBlockHeight)) { LogPrint("gobject", "CSuperblockManager::CreateSuperblock -- Can't find superblock for height %d\n", nBlockHeight); - DBG( cout << "CSuperblockManager::CreateSuperblock Failed to get superblock for height, returning" << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock Failed to get superblock for height, returning" << std::endl; ); return; } @@ -413,7 +394,7 @@ void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNewRet, int nBl // CONFIGURE SUPERBLOCK OUTPUTS // Superblock payments are appended to the end of the coinbase vout vector - DBG( cout << "CSuperblockManager::CreateSuperblock Number payments: " << pSuperblock->CountPayments() << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock Number payments: " << pSuperblock->CountPayments() << std::endl; ); // TODO: How many payments can we add before things blow up? // Consider at least following limits: @@ -421,9 +402,9 @@ void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNewRet, int nBl // - max "budget" available for(int i = 0; i < pSuperblock->CountPayments(); i++) { CGovernancePayment payment; - DBG( cout << "CSuperblockManager::CreateSuperblock i = " << i << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock i = " << i << std::endl; ); if(pSuperblock->GetPayment(i, payment)) { - DBG( cout << "CSuperblockManager::CreateSuperblock Payment found " << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock Payment found " << std::endl; ); // SET COINBASE OUTPUT TO SUPERBLOCK SETTING CTxOut txout = CTxOut(payment.nAmount, payment.script); @@ -438,15 +419,15 @@ void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNewRet, int nBl // TODO: PRINT NICE N.N DYNAMIC OUTPUT - DBG( cout << "CSuperblockManager::CreateSuperblock Before LogPrintf call, nAmount = " << payment.nAmount << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock Before LogPrintf call, nAmount = " << payment.nAmount << std::endl; ); LogPrintf("NEW Superblock : output %d (addr %s, amount %d)\n", i, address2.ToString(), payment.nAmount); - DBG( cout << "CSuperblockManager::CreateSuperblock After LogPrintf call " << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock After LogPrintf call " << std::endl; ); } else { - DBG( cout << "CSuperblockManager::CreateSuperblock Payment not found " << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock Payment not found " << std::endl; ); } } - DBG( cout << "CSuperblockManager::CreateSuperblock End" << endl; ); + DBG( std::cout << "CSuperblockManager::CreateSuperblock End" << std::endl; ); } bool CSuperblockManager::IsValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward) @@ -462,10 +443,22 @@ bool CSuperblockManager::IsValid(const CTransaction& txNew, int nBlockHeight, CA return false; } +void CSuperblockManager::ExecuteBestSuperblock(int nBlockHeight) +{ + LOCK(governance.cs); + + CSuperblock_sptr pSuperblock; + if(GetBestSuperblock(pSuperblock, nBlockHeight)) { + // All checks are done in CSuperblock::IsValid via IsBlockValueValid and IsBlockPayeeValid, + // tip wouldn't be updated if anything was wrong. Mark this trigger as executed. + pSuperblock->SetExecuted(); + } +} + CSuperblock:: CSuperblock() : nGovObjHash(), - nEpochStart(0), + nBlockHeight(0), nStatus(SEEN_OBJECT_UNKNOWN), vecPayments() {} @@ -473,43 +466,43 @@ CSuperblock() CSuperblock:: CSuperblock(uint256& nHash) : nGovObjHash(nHash), - nEpochStart(0), + nBlockHeight(0), nStatus(SEEN_OBJECT_UNKNOWN), vecPayments() { - DBG( cout << "CSuperblock Constructor Start" << endl; ); + DBG( std::cout << "CSuperblock Constructor Start" << std::endl; ); CGovernanceObject* pGovObj = GetGovernanceObject(); if(!pGovObj) { - DBG( cout << "CSuperblock Constructor pGovObjIn is NULL, returning" << endl; ); + DBG( std::cout << "CSuperblock Constructor pGovObjIn is NULL, returning" << std::endl; ); throw std::runtime_error("CSuperblock: Failed to find Governance Object"); } - DBG( cout << "CSuperblock Constructor pGovObj : " - << pGovObj->GetDataAsString() + DBG( std::cout << "CSuperblock Constructor pGovObj : " + << pGovObj->GetDataAsPlainString() << ", nObjectType = " << pGovObj->GetObjectType() - << endl; ); + << std::endl; ); if (pGovObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) { - DBG( cout << "CSuperblock Constructor pHoObj not a trigger, returning" << endl; ); + DBG( std::cout << "CSuperblock Constructor pGovObj not a trigger, returning" << std::endl; ); throw std::runtime_error("CSuperblock: Governance Object not a trigger"); } UniValue obj = pGovObj->GetJSONObject(); - // FIRST WE GET THE START EPOCH, THE DATE WHICH THE PAYMENT SHALL OCCUR - nEpochStart = obj["event_block_height"].get_int(); + // FIRST WE GET THE START HEIGHT, THE BLOCK HEIGHT AT WHICH THE PAYMENT SHALL OCCUR + nBlockHeight = obj["event_block_height"].get_int(); // NEXT WE GET THE PAYMENT INFORMATION AND RECONSTRUCT THE PAYMENT VECTOR std::string strAddresses = obj["payment_addresses"].get_str(); std::string strAmounts = obj["payment_amounts"].get_str(); ParsePaymentSchedule(strAddresses, strAmounts); - LogPrint("gobject", "CSuperblock -- nEpochStart = %d, strAddresses = %s, strAmounts = %s, vecPayments.size() = %d\n", - nEpochStart, strAddresses, strAmounts, vecPayments.size()); + LogPrint("gobject", "CSuperblock -- nBlockHeight = %d, strAddresses = %s, strAmounts = %s, vecPayments.size() = %d\n", + nBlockHeight, strAddresses, strAmounts, vecPayments.size()); - DBG( cout << "CSuperblock Constructor End" << endl; ); + DBG( std::cout << "CSuperblock Constructor End" << std::endl; ); } /** @@ -525,6 +518,25 @@ bool CSuperblock::IsValidBlockHeight(int nBlockHeight) ((nBlockHeight % Params().GetConsensus().nSuperblockCycle) == 0); } +void CSuperblock::GetNearestSuperblocksHeights(int nBlockHeight, int& nLastSuperblockRet, int& nNextSuperblockRet) +{ + const Consensus::Params& consensusParams = Params().GetConsensus(); + int nSuperblockStartBlock = consensusParams.nSuperblockStartBlock; + int nSuperblockCycle = consensusParams.nSuperblockCycle; + + // Get first superblock + int nFirstSuperblockOffset = (nSuperblockCycle - nSuperblockStartBlock % nSuperblockCycle) % nSuperblockCycle; + int nFirstSuperblock = nSuperblockStartBlock + nFirstSuperblockOffset; + + if(nBlockHeight < nFirstSuperblock) { + nLastSuperblockRet = 0; + nNextSuperblockRet = nFirstSuperblock; + } else { + nLastSuperblockRet = nBlockHeight - nBlockHeight % nSuperblockCycle; + nNextSuperblockRet = nLastSuperblockRet + nSuperblockCycle; + } +} + CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight) { @@ -542,7 +554,8 @@ CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight) return nPaymentsLimit; } -void CSuperblock::ParsePaymentSchedule(std::string& strPaymentAddresses, std::string& strPaymentAmounts) + +void CSuperblock::ParsePaymentSchedule(const std::string& strPaymentAddresses, const std::string& strPaymentAmounts) { // SPLIT UP ADDR/AMOUNT STRINGS AND PUT IN VECTORS @@ -573,7 +586,7 @@ void CSuperblock::ParsePaymentSchedule(std::string& strPaymentAddresses, std::st AMOUNTS = [AMOUNT1|2|3|4|5|6] */ - DBG( cout << "CSuperblock::ParsePaymentSchedule vecParsed1.size() = " << vecParsed1.size() << endl; ); + DBG( std::cout << "CSuperblock::ParsePaymentSchedule vecParsed1.size() = " << vecParsed1.size() << std::endl; ); for (int i = 0; i < (int)vecParsed1.size(); i++) { CDynamicAddress address(vecParsed1[i]); @@ -583,17 +596,29 @@ void CSuperblock::ParsePaymentSchedule(std::string& strPaymentAddresses, std::st LogPrintf("%s\n", ostr.str()); throw std::runtime_error(ostr.str()); } + /* + TODO - DBG( cout << "CSuperblock::ParsePaymentSchedule i = " << i + - There might be an issue with multisig in the coinbase on mainnet, we will add support for it in a future release. + - Post 12.3+ (test multisig coinbase transaction) + */ + if(address.IsScript()) { + std::ostringstream ostr; + ostr << "CSuperblock::ParsePaymentSchedule -- Script addresses are not supported yet : " << vecParsed1[i]; + LogPrintf("%s\n", ostr.str()); + throw std::runtime_error(ostr.str()); + } + + DBG( std::cout << "CSuperblock::ParsePaymentSchedule i = " << i << ", vecParsed2[i] = " << vecParsed2[i] - << endl; ); + << std::endl; ); CAmount nAmount = ParsePaymentAmount(vecParsed2[i]); - DBG( cout << "CSuperblock::ParsePaymentSchedule: " + DBG( std::cout << "CSuperblock::ParsePaymentSchedule: " << "amount string = " << vecParsed2[i] << ", nAmount = " << nAmount - << endl; ); + << std::endl; ); CGovernancePayment payment(address, nAmount); if(payment.IsValid()) { @@ -632,7 +657,6 @@ CAmount CSuperblock::GetPaymentsTotalAmount() return nPaymentsTotalAmount; } - /** * Is Transaction Valid * @@ -659,8 +683,8 @@ bool CSuperblock::IsValid(const CTransaction& txNew, int nBlockHeight, CAmount b int nPayments = CountPayments(); int nMinerPayments = nOutputs - nPayments; - LogPrint("gobject", "CSuperblock::IsValid nOutputs = %d, nPayments = %d, strData = %s\n", - nOutputs, nPayments, GetGovernanceObject()->GetDataAsHex()); + LogPrint("gobject", "CSuperblock::IsValid nOutputs = %d, nPayments = %d, GetDataAsHexString = %s\n", + nOutputs, nPayments, GetGovernanceObject()->GetDataAsHexString()); // We require an exact match (including order) between the expected // superblock payments and the payments actually in the block. @@ -725,6 +749,42 @@ bool CSuperblock::IsValid(const CTransaction& txNew, int nBlockHeight, CAmount b return true; } +bool CSuperblock::IsExpired() +{ + bool fExpired{false}; + int nExpirationBlocks{0}; + // Executed triggers are kept for another superblock cycle (approximately 1 month), + // other valid triggers are kept for ~1 day only, everything else is pruned after ~1h. + switch (nStatus) { + case SEEN_OBJECT_EXECUTED: + nExpirationBlocks = Params().GetConsensus().nSuperblockCycle; + break; + case SEEN_OBJECT_IS_VALID: + nExpirationBlocks = 576; + break; + default: + nExpirationBlocks = 24; + break; + } + + int nExpirationBlock = nBlockHeight + nExpirationBlocks; + + LogPrint("gobject", "CSuperblock::IsExpired -- nBlockHeight = %d, nExpirationBlock = %d\n", nBlockHeight, nExpirationBlock); + + if(governance.GetCachedBlockHeight() > nExpirationBlock) { + LogPrint("gobject", "CSuperblock::IsExpired -- Outdated trigger found\n"); + fExpired = true; + CGovernanceObject* pgovobj = GetGovernanceObject(); + if(pgovobj) { + LogPrint("gobject", "CSuperblock::IsExpired -- Expiring outdated object: %s\n", pgovobj->GetHash().ToString()); + pgovobj->fExpired = true; + pgovobj->nDeletionTime = GetAdjustedTime(); + } + } + + return fExpired; +} + /** * Get Required Payment String * diff --git a/src/governance-classes.h b/src/governance-classes.h index 3868f91c14..28acc6a14b 100644 --- a/src/governance-classes.h +++ b/src/governance-classes.h @@ -17,23 +17,20 @@ #include +class CSuperblock; class CGovernanceTrigger; class CGovernanceTriggerManager; -class CSuperblock; class CSuperblockManager; static const int TRIGGER_UNKNOWN = -1; static const int TRIGGER_SUPERBLOCK = 1000; static const CAmount STATIC_SUPERBLOCK_AMOUNT = 0; //Budget amount fixed at 0DYN -typedef boost::shared_ptr CSuperblock_sptr; +typedef std::shared_ptr CSuperblock_sptr; // DECLARE GLOBAL VARIABLES FOR GOVERNANCE CLASSES extern CGovernanceTriggerManager triggerman; -// SPLIT A STRING UP - USED FOR SUPERBLOCK PAYMENTS -std::vector SplitBy(std::string strCommand, std::string strDelimit); - /** * Trigger Mananger * @@ -77,6 +74,7 @@ class CSuperblockManager static bool IsSuperblockTriggered(int nBlockHeight); static void CreateSuperblock(CMutableTransaction& txNewRet, int nBlockHeight, std::vector& voutSuperblockRet); + static void ExecuteBestSuperblock(int nBlockHeight); static std::string GetRequiredPaymentsString(int nBlockHeight); static bool IsValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward); @@ -114,7 +112,7 @@ class CGovernancePayment nAmount = nAmountIn; fValid = true; } - catch(const std::exception& e) + catch(std::exception& e) { LogPrintf("CGovernancePayment Payment not valid: addrIn = %s, nAmountIn = %d, what = %s\n", addrIn.ToString(), nAmountIn, e.what()); @@ -152,11 +150,11 @@ class CSuperblock : public CGovernanceObject private: uint256 nGovObjHash; - int nEpochStart; + int nBlockHeight; int nStatus; std::vector vecPayments; - void ParsePaymentSchedule(std::string& strPaymentAddresses, std::string& strPaymentAmounts); + void ParsePaymentSchedule(const std::string& strPaymentAddresses, const std::string& strPaymentAmounts); public: @@ -164,6 +162,7 @@ class CSuperblock : public CGovernanceObject CSuperblock(uint256& nHash); static bool IsValidBlockHeight(int nBlockHeight); + static void GetNearestSuperblocksHeights(int nBlockHeight, int& nLastSuperblockRet, int& nNextSuperblockRet); static CAmount GetPaymentsLimit(int nBlockHeight); int GetStatus() { return nStatus; } @@ -181,11 +180,17 @@ class CSuperblock : public CGovernanceObject return pObj; } + int GetBlockHeight() + { + return nBlockHeight; + } + int CountPayments() { return (int)vecPayments.size(); } bool GetPayment(int nPaymentIndex, CGovernancePayment& paymentRet); CAmount GetPaymentsTotalAmount(); bool IsValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward); + bool IsExpired(); }; -#endif // DYNAMIC_GOVERNANCE_CLASSES_H +#endif diff --git a/src/governance-misc.h b/src/governance-misc.h deleted file mode 100644 index 45c7aa58d4..0000000000 --- a/src/governance-misc.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers -// Copyright (c) 2014-2017 The Dash Core Developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef DYNAMIC_GOVERNANCE_MISC_H -#define DYNAMIC_GOVERNANCE_MISC_H - -#include "governance.h" -#include "init.h" -#include "validation.h" - -class CGovernanceVote; - -/** -* Triggers and Settings - 12.2 -* ----------------------------------- -* -* This allows the network fine grained control of the p2p side, including but not limited to: -* - Which blocks are valid -* - What it costs to do various things on the network -* -*/ - - -// class CGovernanceTrigger -// { -// static &T IsBlockBanned(int n) -// { - -// } -// }; - -// /* - - -// */ - -// class CGovernanceSettings -// { -// template -// // strName=trigger, strParamater=ban-block ... obj= tigger.ban-block(args) -// static &T GetSetting(std::string strName, &T networkDefault) -// { -// /* -// - get setting from Dynode network -// */ - -// return networkDefault; -// } -// }; - -#endif // DYNAMIC_GOVERNANCE_MISC_H diff --git a/src/governance-object.cpp b/src/governance-object.cpp index ea150bc1dc..0b46b6b39d 100644 --- a/src/governance-object.cpp +++ b/src/governance-object.cpp @@ -3,97 +3,101 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "governance-object.h" + #include "core_io.h" +#include "dynode-sync.h" #include "dynodeman.h" #include "governance.h" #include "governance-classes.h" -#include "governance-object.h" #include "governance-vote.h" +#include "governance-validators.h" #include "instantsend.h" #include "messagesigner.h" #include "util.h" #include - -CGovernanceObject::CGovernanceObject() -: cs(), - nObjectType(GOVERNANCE_OBJECT_UNKNOWN), - nHashParent(), - nRevision(0), - nTime(0), - nDeletionTime(0), - nCollateralHash(), - strData(), - vinDynode(), - vchSig(), - fCachedLocalValidity(false), - strLocalValidityError(), - fCachedFunding(false), - fCachedValid(true), - fCachedDelete(false), - fCachedEndorsed(false), - fDirtyCache(true), - fExpired(false), - fUnparsable(false), - mapCurrentDNVotes(), - mapOrphanVotes(), - fileVotes() +#include + +CGovernanceObject::CGovernanceObject(): + cs(), + nObjectType(GOVERNANCE_OBJECT_UNKNOWN), + nHashParent(), + nRevision(0), + nTime(0), + nDeletionTime(0), + nCollateralHash(), + vchData(), + dynodeOutpoint(), + vchSig(), + fCachedLocalValidity(false), + strLocalValidityError(), + fCachedFunding(false), + fCachedValid(true), + fCachedDelete(false), + fCachedEndorsed(false), + fDirtyCache(true), + fExpired(false), + fUnparsable(false), + mapCurrentDNVotes(), + cmmapOrphanVotes(), + fileVotes() { - // PARSE JSON DATA STORAGE (STRDATA) + // PARSE JSON DATA STORAGE (VCHDATA) LoadData(); } -CGovernanceObject::CGovernanceObject(uint256 nHashParentIn, int nRevisionIn, int64_t nTimeIn, uint256 nCollateralHashIn, std::string strDataIn) -: cs(), - nObjectType(GOVERNANCE_OBJECT_UNKNOWN), - nHashParent(nHashParentIn), - nRevision(nRevisionIn), - nTime(nTimeIn), - nDeletionTime(0), - nCollateralHash(nCollateralHashIn), - strData(strDataIn), - vinDynode(), - vchSig(), - fCachedLocalValidity(false), - strLocalValidityError(), - fCachedFunding(false), - fCachedValid(true), - fCachedDelete(false), - fCachedEndorsed(false), - fDirtyCache(true), - fExpired(false), - fUnparsable(false), - mapCurrentDNVotes(), - mapOrphanVotes(), - fileVotes() +CGovernanceObject::CGovernanceObject(const uint256& nHashParentIn, int nRevisionIn, int64_t nTimeIn, const uint256& nCollateralHashIn, const std::string& strDataHexIn): + cs(), + nObjectType(GOVERNANCE_OBJECT_UNKNOWN), + nHashParent(nHashParentIn), + nRevision(nRevisionIn), + nTime(nTimeIn), + nDeletionTime(0), + nCollateralHash(nCollateralHashIn), + vchData(ParseHex(strDataHexIn)), + dynodeOutpoint(), + vchSig(), + fCachedLocalValidity(false), + strLocalValidityError(), + fCachedFunding(false), + fCachedValid(true), + fCachedDelete(false), + fCachedEndorsed(false), + fDirtyCache(true), + fExpired(false), + fUnparsable(false), + mapCurrentDNVotes(), + cmmapOrphanVotes(), + fileVotes() { - // PARSE JSON DATA STORAGE (STRDATA) + // PARSE JSON DATA STORAGE (VCHDATA) LoadData(); } -CGovernanceObject::CGovernanceObject(const CGovernanceObject& other) -: cs(), - nObjectType(other.nObjectType), - nHashParent(other.nHashParent), - nRevision(other.nRevision), - nTime(other.nTime), - nDeletionTime(other.nDeletionTime), - nCollateralHash(other.nCollateralHash), - strData(other.strData), - vinDynode(other.vinDynode), - vchSig(other.vchSig), - fCachedLocalValidity(other.fCachedLocalValidity), - strLocalValidityError(other.strLocalValidityError), - fCachedFunding(other.fCachedFunding), - fCachedValid(other.fCachedValid), - fCachedDelete(other.fCachedDelete), - fCachedEndorsed(other.fCachedEndorsed), - fDirtyCache(other.fDirtyCache), - fExpired(other.fExpired), - fUnparsable(other.fUnparsable), - mapCurrentDNVotes(other.mapCurrentDNVotes), - mapOrphanVotes(other.mapOrphanVotes), - fileVotes(other.fileVotes) +CGovernanceObject::CGovernanceObject(const CGovernanceObject& other): + cs(), + nObjectType(other.nObjectType), + nHashParent(other.nHashParent), + nRevision(other.nRevision), + nTime(other.nTime), + nDeletionTime(other.nDeletionTime), + nCollateralHash(other.nCollateralHash), + vchData(other.vchData), + dynodeOutpoint(other.dynodeOutpoint), + vchSig(other.vchSig), + fCachedLocalValidity(other.fCachedLocalValidity), + strLocalValidityError(other.strLocalValidityError), + fCachedFunding(other.fCachedFunding), + fCachedValid(other.fCachedValid), + fCachedDelete(other.fCachedDelete), + fCachedEndorsed(other.fCachedEndorsed), + fDirtyCache(other.fDirtyCache), + fExpired(other.fExpired), + fUnparsable(other.fUnparsable), + mapCurrentDNVotes(other.mapCurrentDNVotes), + cmmapOrphanVotes(other.cmmapOrphanVotes), + fileVotes(other.fileVotes) {} bool CGovernanceObject::ProcessVote(CNode* pfrom, @@ -101,11 +105,23 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom, CGovernanceException& exception, CConnman& connman) { + LOCK(cs); + + // do not process already known valid votes twice + if (fileVotes.HasVote(vote.GetHash())) { + // nothing to do here, not an error + std::ostringstream ostr; + ostr << "CGovernanceObject::ProcessVote -- Already known valid vote"; + LogPrint("gobject", "%s\n", ostr.str()); + exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_NONE); + return false; + } + if(!dnodeman.Has(vote.GetDynodeOutpoint())) { std::ostringstream ostr; - ostr << "CGovernanceObject::ProcessVote -- Dynode index not found"; + ostr << "CGovernanceObject::ProcessVote -- Dynode " << vote.GetDynodeOutpoint().ToStringShort() << " not found"; exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_WARNING); - if(mapOrphanVotes.Insert(vote.GetDynodeOutpoint(), vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME))) { + if(cmmapOrphanVotes.Insert(vote.GetDynodeOutpoint(), vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME))) { if(pfrom) { dnodeman.AskForDN(pfrom, vote.GetDynodeOutpoint(), connman); } @@ -117,11 +133,8 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom, return false; } - vote_m_it it = mapCurrentDNVotes.find(vote.GetDynodeOutpoint()); - if(it == mapCurrentDNVotes.end()) { - it = mapCurrentDNVotes.insert(vote_m_t::value_type(vote.GetDynodeOutpoint(), vote_rec_t())).first; - } - vote_rec_t& recVote = it->second; + vote_m_it it = mapCurrentDNVotes.emplace(vote_m_t::value_type(vote.GetDynodeOutpoint(), vote_rec_t())).first; + vote_rec_t& voteRecordRef = it->second; vote_signal_enum_t eSignal = vote.GetSignal(); if(eSignal == VOTE_SIGNAL_NONE) { std::ostringstream ostr; @@ -137,14 +150,11 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom, exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20); return false; } - vote_instance_m_it it2 = recVote.mapInstances.find(int(eSignal)); - if(it2 == recVote.mapInstances.end()) { - it2 = recVote.mapInstances.insert(vote_instance_m_t::value_type(int(eSignal), vote_instance_t())).first; - } - vote_instance_t& voteInstance = it2->second; + vote_instance_m_it it2 = voteRecordRef.mapInstances.emplace(vote_instance_m_t::value_type(int(eSignal), vote_instance_t())).first; + vote_instance_t& voteInstanceRef = it2->second; // Reject obsolete votes - if(vote.GetTimestamp() < voteInstance.nCreationTime) { + if(vote.GetTimestamp() < voteInstanceRef.nCreationTime) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Obsolete vote"; LogPrint("gobject", "%s\n", ostr.str()); @@ -153,9 +163,9 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom, } int64_t nNow = GetAdjustedTime(); - int64_t nVoteTimeUpdate = voteInstance.nTime; + int64_t nVoteTimeUpdate = voteInstanceRef.nTime; if(governance.AreRateChecksEnabled()) { - int64_t nTimeDelta = nNow - voteInstance.nTime; + int64_t nTimeDelta = nNow - voteInstanceRef.nTime; if(nTimeDelta < GOVERNANCE_UPDATE_MIN) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Dynode voting too often" @@ -168,6 +178,7 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom, return false; } } + // Finally check that the vote is actually valid (done last because of cost of signature verification) if(!vote.IsValid(true)) { std::ostringstream ostr; @@ -180,6 +191,7 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom, governance.AddInvalidVote(vote); return false; } + if(!dnodeman.AddGovernanceVote(vote.GetDynodeOutpoint(), vote.GetParentHash())) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Unable to add governance vote" @@ -189,16 +201,17 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom, exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_PERMANENT_ERROR); return false; } - voteInstance = vote_instance_t(vote.GetOutcome(), nVoteTimeUpdate, vote.GetTimestamp()); - if(!fileVotes.HasVote(vote.GetHash())) { - fileVotes.AddVote(vote); - } + + voteInstanceRef = vote_instance_t(vote.GetOutcome(), nVoteTimeUpdate, vote.GetTimestamp()); + fileVotes.AddVote(vote); fDirtyCache = true; return true; } void CGovernanceObject::ClearDynodeVotes() { + LOCK(cs); + vote_m_it it = mapCurrentDNVotes.begin(); while(it != mapCurrentDNVotes.end()) { if(!dnodeman.Has(it->first)) { @@ -215,105 +228,131 @@ std::string CGovernanceObject::GetSignatureMessage() const { LOCK(cs); std::string strMessage = nHashParent.ToString() + "|" + - boost::lexical_cast(nRevision) + "|" + - boost::lexical_cast(nTime) + "|" + - strData + "|" + - vinDynode.prevout.ToStringShort() + "|" + + std::to_string(nRevision) + "|" + + std::to_string(nTime) + "|" + + GetDataAsHexString() + "|" + + dynodeOutpoint.ToStringShort() + "|" + nCollateralHash.ToString(); return strMessage; } -void CGovernanceObject::SetDynodeVin(const COutPoint& outpoint) -{ - vinDynode = CTxIn(outpoint); -} - -bool CGovernanceObject::Sign(CKey& keyDynode, CPubKey& pubKeyDynode) +uint256 CGovernanceObject::GetHash() const { - std::string strError; - std::string strMessage = GetSignatureMessage(); + // Note: doesn't match serialization - LOCK(cs); + // CREATE HASH OF ALL IMPORTANT PIECES OF DATA - if(!CMessageSigner::SignMessage(strMessage, vchSig, keyDynode)) { - LogPrintf("CGovernanceObject::Sign -- SignMessage() failed\n"); - return false; - } + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << nHashParent; + ss << nRevision; + ss << nTime; + ss << GetDataAsHexString(); + ss << dynodeOutpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing + ss << vchSig; + // fee_tx is left out on purpose - if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CGovernanceObject::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; - } + DBG( printf("CGovernanceObject::GetHash %i %li %s\n", nRevision, nTime, GetDataAsHexString().c_str()); ); - LogPrint("gobject", "CGovernanceObject::Sign -- pubkey id = %s, vin = %s\n", - pubKeyDynode.GetID().ToString(), vinDynode.prevout.ToStringShort()); + return ss.GetHash(); +} +uint256 CGovernanceObject::GetSignatureHash() const +{ + return SerializeHash(*this); +} - return true; +void CGovernanceObject::SetDynodeOutpoint(const COutPoint& outpoint) +{ + dynodeOutpoint = outpoint; } -bool CGovernanceObject::CheckSignature(CPubKey& pubKeyDynode) +bool CGovernanceObject::Sign(const CKey& keyDynode, const CPubKey& pubKeyDynode) { std::string strError; - std::string strMessage = GetSignatureMessage(); + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); - LOCK(cs); - if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CGovernance::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); - return false; + if (!CHashSigner::SignHash(hash, keyDynode, vchSig)) { + LogPrintf("CGovernanceObject::Sign -- SignHash() failed\n"); + return false; + } + + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + LogPrintf("CGovernanceObject::Sign -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = GetSignatureMessage(); + if (!CMessageSigner::SignMessage(strMessage, vchSig, keyDynode)) { + LogPrintf("CGovernanceObject::Sign -- SignMessage() failed\n"); + return false; + } + + if (!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CGovernanceObject::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } + LogPrint("gobject", "CGovernanceObject::Sign -- pubkey id = %s, dynode = %s\n", + pubKeyDynode.GetID().ToString(), dynodeOutpoint.ToStringShort()); + return true; } -int CGovernanceObject::GetObjectSubtype() +bool CGovernanceObject::CheckSignature(const CPubKey& pubKeyDynode) const { - // todo - 12.1 - // - detect subtype from strData json, obj["subtype"] + std::string strError; - if(nObjectType == GOVERNANCE_OBJECT_TRIGGER) return TRIGGER_SUPERBLOCK; - return -1; -} + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); -uint256 CGovernanceObject::GetHash() const -{ - // CREATE HASH OF ALL IMPORTANT PIECES OF DATA + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + // could be an old object + std::string strMessage = GetSignatureMessage(); - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << nHashParent; - ss << nRevision; - ss << nTime; - ss << strData; - ss << vinDynode; - ss << vchSig; - // fee_tx is left out on purpose - uint256 h1 = ss.GetHash(); + if (!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + // nope, not in old format either + LogPrintf("CGovernance::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); + return false; + } + } + } else { + std::string strMessage = GetSignatureMessage(); - DBG( printf("CGovernanceObject::GetHash %i %li %s\n", nRevision, nTime, strData.c_str()); ); + if (!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CGovernance::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); + return false; + } + } - return h1; + return true; } /** - Return the actual object from the strData JSON structure. + Return the actual object from the vchData JSON structure. Returns an empty object on error. */ UniValue CGovernanceObject::GetJSONObject() { UniValue obj(UniValue::VOBJ); - if(strData.empty()) { + if(vchData.empty()) { return obj; } UniValue objResult(UniValue::VOBJ); GetData(objResult); - std::vector arr1 = objResult.getValues(); - std::vector arr2 = arr1.at( 0 ).getValues(); - obj = arr2.at( 1 ); + if (objResult.isObject()) { + obj = objResult; + } else { + std::vector arr1 = objResult.getValues(); + std::vector arr2 = arr1.at( 0 ).getValues(); + obj = arr2.at( 1 ); + } return obj; } @@ -322,7 +361,7 @@ UniValue CGovernanceObject::GetJSONObject() * LoadData * -------------------------------------------------------- * -* Attempt to load data from strData +* Attempt to load data from vchData * */ @@ -331,18 +370,18 @@ void CGovernanceObject::LoadData() // todo : 12.1 - resolved //return; - if(strData.empty()) { + if(vchData.empty()) { return; } try { - // ATTEMPT TO LOAD JSON STRING FROM STRDATA + // ATTEMPT TO LOAD JSON STRING FROM VCHDATA UniValue objResult(UniValue::VOBJ); GetData(objResult); - DBG( cout << "CGovernanceObject::LoadData strData = " - << GetDataAsString() - << endl; ); + DBG( std::cout << "CGovernanceObject::LoadData GetDataAsPlainString = " + << GetDataAsPlainString() + << std::endl; ); UniValue obj = GetJSONObject(); nObjectType = obj["type"].get_int(); @@ -352,7 +391,7 @@ void CGovernanceObject::LoadData() std::ostringstream ostr; ostr << "CGovernanceObject::LoadData Error parsing JSON" << ", e.what() = " << e.what(); - DBG( cout << ostr.str() << endl; ); + DBG( std::cout << ostr.str() << std::endl; ); LogPrintf("%s\n", ostr.str()); return; } @@ -360,7 +399,7 @@ void CGovernanceObject::LoadData() fUnparsable = true; std::ostringstream ostr; ostr << "CGovernanceObject::LoadData Unknown Error parsing JSON"; - DBG( cout << ostr.str() << endl; ); + DBG( std::cout << ostr.str() << std::endl; ); LogPrintf("%s\n", ostr.str()); return; } @@ -377,7 +416,7 @@ void CGovernanceObject::LoadData() void CGovernanceObject::GetData(UniValue& objResult) { UniValue o(UniValue::VOBJ); - std::string s = GetDataAsString(); + std::string s = GetDataAsPlainString(); o.read(s); objResult = o; } @@ -388,17 +427,14 @@ void CGovernanceObject::GetData(UniValue& objResult) * */ -std::string CGovernanceObject::GetDataAsHex() +std::string CGovernanceObject::GetDataAsHexString() const { - return strData; + return HexStr(vchData); } -std::string CGovernanceObject::GetDataAsString() +std::string CGovernanceObject::GetDataAsPlainString() const { - std::vector v = ParseHex(strData); - std::string s(v.begin(), v.end()); - - return s; + return std::string(vchData.begin(), vchData.end()); } void CGovernanceObject::UpdateLocalValidity() @@ -409,7 +445,7 @@ void CGovernanceObject::UpdateLocalValidity() }; -bool CGovernanceObject::IsValidLocally(std::string& strError, bool fCheckCollateral) +bool CGovernanceObject::IsValidLocally(std::string& strError, bool fCheckCollateral) const { bool fMissingDynode = false; bool fMissingConfirmations = false; @@ -417,41 +453,50 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool fCheckCollate return IsValidLocally(strError, fMissingDynode, fMissingConfirmations, fCheckCollateral); } -bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingDynode, bool& fMissingConfirmations, bool fCheckCollateral) +bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingDynode, bool& fMissingConfirmations, bool fCheckCollateral) const { fMissingDynode = false; fMissingConfirmations = false; - if(fUnparsable) { + if (fUnparsable) { strError = "Object data unparseable"; return false; } switch(nObjectType) { - case GOVERNANCE_OBJECT_PROPOSAL: - case GOVERNANCE_OBJECT_TRIGGER: - case GOVERNANCE_OBJECT_WATCHDOG: - break; - default: - strError = strprintf("Invalid object type %d", nObjectType); + case GOVERNANCE_OBJECT_WATCHDOG: { + // watchdogs are deprecated return false; - } - - // IF ABSOLUTE NO COUNT (NO-YES VALID VOTES) IS MORE THAN 10% OF THE NETWORK DYNODES, OBJ IS INVALID - - // CHECK COLLATERAL IF REQUIRED (HIGH CPU USAGE) + } + case GOVERNANCE_OBJECT_PROPOSAL: { + CProposalValidator validator(GetDataAsHexString()); + // Note: It's ok to have expired proposals + // they are going to be cleared by CGovernanceManager::UpdateCachesAndClean() + // TODO: should they be tagged as "expired" to skip vote downloading? + if (!validator.Validate(false)) { + strError = strprintf("Invalid proposal data, error messages: %s", validator.GetErrorMessages()); + return false; + } + if (fCheckCollateral && !IsCollateralValid(strError, fMissingConfirmations)) { + strError = "Invalid proposal collateral"; + return false; + } + return true; + } + case GOVERNANCE_OBJECT_TRIGGER: { + if (!fCheckCollateral) + // nothing else we can check here (yet?) + return true; - if(fCheckCollateral) { - if((nObjectType == GOVERNANCE_OBJECT_TRIGGER) || (nObjectType == GOVERNANCE_OBJECT_WATCHDOG)) { - std::string strOutpoint = vinDynode.prevout.ToStringShort(); + std::string strOutpoint = dynodeOutpoint.ToStringShort(); dynode_info_t infoDn; - if(!dnodeman.GetDynodeInfo(vinDynode.prevout, infoDn)) { + if (!dnodeman.GetDynodeInfo(dynodeOutpoint, infoDn)) { - CDynode::CollateralStatus err = CDynode::CheckCollateral(vinDynode.prevout, CPubKey()); + CDynode::CollateralStatus err = CDynode::CheckCollateral(dynodeOutpoint, CPubKey()); if (err == CDynode::COLLATERAL_UTXO_NOT_FOUND) { strError = "Failed to find Dynode UTXO, missing dynode=" + strOutpoint + "\n"; } else if (err == CDynode::COLLATERAL_INVALID_AMOUNT) { - strError = "Dynode UTXO should have 1000 DYN, missing dynode=" + strOutpoint + "\n"; + strError = "Dynode UTXO should have 1000 DASH, missing dynode=" + strOutpoint + "\n"; } else if (err == CDynode::COLLATERAL_INVALID_PUBKEY) { fMissingDynode = true; strError = "Dynode not found: " + strOutpoint; @@ -464,35 +509,22 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingDyno } // Check that we have a valid DN signature - if(!CheckSignature(infoDn.pubKeyDynode)) { + if (!CheckSignature(infoDn.pubKeyDynode)) { strError = "Invalid dynode signature for: " + strOutpoint + ", pubkey id = " + infoDn.pubKeyDynode.GetID().ToString(); return false; } return true; } - - if (!IsCollateralValid(strError, fMissingConfirmations)) + default: { + strError = strprintf("Invalid object type %d", nObjectType); return false; + } } - /* - TODO - - - There might be an issue with multisig in the coinbase on mainnet, we will add support for it in a future release. - - Post 12.2+ (test multisig coinbase transaction) - */ - - // 12.1 - todo - compile error - // if(address.IsPayToScriptHash()) { - // strError = "Governance system - multisig is not currently supported"; - // return false; - // } - - return true; } -CAmount CGovernanceObject::GetMinCollateralFee() +CAmount CGovernanceObject::GetMinCollateralFee() const { // Only 1 type has a fee for the moment but switch statement allows for future object types switch(nObjectType) { @@ -503,32 +535,32 @@ CAmount CGovernanceObject::GetMinCollateralFee() } } -bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingConfirmations) +bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingConfirmations) const { strError = ""; fMissingConfirmations = false; CAmount nMinFee = GetMinCollateralFee(); uint256 nExpectedHash = GetHash(); - CTransaction txCollateral; + CTransactionRef txCollateral; uint256 nBlockHash; // RETRIEVE TRANSACTION IN QUESTION if(!GetTransaction(nCollateralHash, txCollateral, Params().GetConsensus(), nBlockHash, true)){ - strError = strprintf("Can't find collateral tx %s", txCollateral.ToString()); + strError = strprintf("Can't find collateral tx %s", nCollateralHash.ToString()); LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } if(nBlockHash == uint256()) { - strError = strprintf("Collateral tx %s is not mined yet", txCollateral.ToString()); + strError = strprintf("Collateral tx %s is not mined yet", txCollateral->ToString()); LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } - if(txCollateral.vout.size() < 1) { - strError = strprintf("tx vout size less than 1 | %d", txCollateral.vout.size()); + if(txCollateral->vout.size() < 1) { + strError = strprintf("tx vout size less than 1 | %d", txCollateral->vout.size()); LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } @@ -538,36 +570,36 @@ bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingC CScript findScript; findScript << OP_RETURN << ToByteVector(nExpectedHash); - DBG( cout << "IsCollateralValid: txCollateral.vout.size() = " << txCollateral.vout.size() << endl; ); + DBG( std::cout << "IsCollateralValid: txCollateral->vout.size() = " << txCollateral->vout.size() << std::endl; ); - DBG( cout << "IsCollateralValid: findScript = " << ScriptToAsmStr( findScript, false ) << endl; ); + DBG( std::cout << "IsCollateralValid: findScript = " << ScriptToAsmStr( findScript, false ) << std::endl; ); - DBG( cout << "IsCollateralValid: nMinFee = " << nMinFee << endl; ); + DBG( std::cout << "IsCollateralValid: nMinFee = " << nMinFee << std::endl; ); bool foundOpReturn = false; - BOOST_FOREACH(const CTxOut o, txCollateral.vout) { - DBG( cout << "IsCollateralValid txout : " << o.ToString() - << ", o.nValue = " << o.nValue - << ", o.scriptPubKey = " << ScriptToAsmStr( o.scriptPubKey, false ) - << endl; ); - if(!o.scriptPubKey.IsPayToPublicKeyHash() && !o.scriptPubKey.IsUnspendable()) { - strError = strprintf("Invalid Script %s", txCollateral.ToString()); + for (const auto& output : txCollateral->vout) { + DBG( std::cout << "IsCollateralValid txout : " << output.ToString() + << ", output.nValue = " << output.nValue + << ", output.scriptPubKey = " << ScriptToAsmStr( output.scriptPubKey, false ) + << std::endl; ); + if(!output.scriptPubKey.IsPayToPublicKeyHash() && !output.scriptPubKey.IsUnspendable()) { + strError = strprintf("Invalid Script %s", txCollateral->ToString()); LogPrintf ("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } - if(o.scriptPubKey == findScript && o.nValue >= nMinFee) { - DBG( cout << "IsCollateralValid foundOpReturn = true" << endl; ); + if(output.scriptPubKey == findScript && output.nValue >= nMinFee) { + DBG( std::cout << "IsCollateralValid foundOpReturn = true" << std::endl; ); foundOpReturn = true; } else { - DBG( cout << "IsCollateralValid No match, continuing" << endl; ); + DBG( std::cout << "IsCollateralValid No match, continuing" << std::endl; ); } } if(!foundOpReturn){ - strError = strprintf("Couldn't find opReturn %s in %s", nExpectedHash.ToString(), txCollateral.ToString()); + strError = strprintf("Couldn't find opReturn %s in %s", nExpectedHash.ToString(), txCollateral->ToString()); LogPrintf ("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } @@ -605,15 +637,13 @@ bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingC int CGovernanceObject::CountMatchingVotes(vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn) const { + LOCK(cs); + int nCount = 0; - for(vote_m_cit it = mapCurrentDNVotes.begin(); it != mapCurrentDNVotes.end(); ++it) { - const vote_rec_t& recVote = it->second; + for (const auto& votepair : mapCurrentDNVotes) { + const vote_rec_t& recVote = votepair.second; vote_instance_m_cit it2 = recVote.mapInstances.find(eVoteSignalIn); - if(it2 == recVote.mapInstances.end()) { - continue; - } - const vote_instance_t& voteInstance = it2->second; - if(voteInstance.eOutcome == eVoteOutcomeIn) { + if(it2 != recVote.mapInstances.end() && it2->second.eOutcome == eVoteOutcomeIn) { ++nCount; } } @@ -649,9 +679,11 @@ int CGovernanceObject::GetAbstainCount(vote_signal_enum_t eVoteSignalIn) const return CountMatchingVotes(eVoteSignalIn, VOTE_OUTCOME_ABSTAIN); } -bool CGovernanceObject::GetCurrentDNVotes(const COutPoint& dnCollateralOutpoint, vote_rec_t& voteRecord) +bool CGovernanceObject::GetCurrentDNVotes(const COutPoint& dnCollateralOutpoint, vote_rec_t& voteRecord) const { - vote_m_it it = mapCurrentDNVotes.find(dnCollateralOutpoint); + LOCK(cs); + + vote_m_cit it = mapCurrentDNVotes.find(dnCollateralOutpoint); if (it == mapCurrentDNVotes.end()) { return false; } @@ -661,6 +693,12 @@ bool CGovernanceObject::GetCurrentDNVotes(const COutPoint& dnCollateralOutpoint, void CGovernanceObject::Relay(CConnman& connman) { + // Do not relay until fully synced + if(!dynodeSync.IsSynced()) { + LogPrint("gobject", "CGovernanceObject::Relay -- won't relay until fully synced\n"); + return; + } + CInv inv(MSG_GOVERNANCE_OBJECT, GetHash()); connman.RelayInv(inv, MIN_GOVERNANCE_PEER_PROTO_VERSION); } @@ -674,11 +712,8 @@ void CGovernanceObject::UpdateSentinelVariables() // CALCULATE THE MINUMUM VOTE COUNT REQUIRED FOR FULL SIGNAL - // todo - 12.1 - should be set to `10` after governance vote compression is implemented int nAbsVoteReq = std::max(Params().GetConsensus().nGovernanceMinQuorum, nDnCount / 10); int nAbsDeleteReq = std::max(Params().GetConsensus().nGovernanceMinQuorum, (2 * nDnCount) / 3); - // todo - 12.1 - Temporarily set to 1 for testing - reverted - //nAbsVoteReq = 1; // SET SENTINEL FLAGS TO FALSE @@ -714,7 +749,7 @@ void CGovernanceObject::swap(CGovernanceObject& first, CGovernanceObject& second swap(first.nTime, second.nTime); swap(first.nDeletionTime, second.nDeletionTime); swap(first.nCollateralHash, second.nCollateralHash); - swap(first.strData, second.strData); + swap(first.vchData, second.vchData); swap(first.nObjectType, second.nObjectType); // swap all cached valid flags @@ -729,8 +764,8 @@ void CGovernanceObject::swap(CGovernanceObject& first, CGovernanceObject& second void CGovernanceObject::CheckOrphanVotes(CConnman& connman) { int64_t nNow = GetAdjustedTime(); - const vote_mcache_t::list_t& listVotes = mapOrphanVotes.GetItemList(); - vote_mcache_t::list_cit it = listVotes.begin(); + const vote_cmm_t::list_t& listVotes = cmmapOrphanVotes.GetItemList(); + vote_cmm_t::list_cit it = listVotes.begin(); while(it != listVotes.end()) { bool fRemove = false; const COutPoint& key = it->key; @@ -744,7 +779,7 @@ void CGovernanceObject::CheckOrphanVotes(CConnman& connman) continue; } CGovernanceException exception; - if(!ProcessVote(NULL, vote, exception, connman)) { + if(!ProcessVote(nullptr, vote, exception, connman)) { LogPrintf("CGovernanceObject::CheckOrphanVotes -- Failed to add orphan vote: %s\n", exception.what()); } else { @@ -753,7 +788,7 @@ void CGovernanceObject::CheckOrphanVotes(CConnman& connman) } ++it; if(fRemove) { - mapOrphanVotes.Erase(key, pairVote); + cmmapOrphanVotes.Erase(key, pairVote); } } } diff --git a/src/governance-object.h b/src/governance-object.h index 5f410abd9b..64ca9fb3da 100644 --- a/src/governance-object.h +++ b/src/governance-object.h @@ -16,6 +16,7 @@ #include "net.h" #include "sync.h" #include "util.h" +#include "utilstrencodings.h" #include @@ -42,9 +43,6 @@ static const int64_t GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS = 1; static const int64_t GOVERNANCE_UPDATE_MIN = 60*60; static const int64_t GOVERNANCE_DELETION_DELAY = 10*60; static const int64_t GOVERNANCE_ORPHAN_EXPIRATION_TIME = 10*60; -static const int64_t GOVERNANCE_WATCHDOG_EXPIRATION_TIME = 2*60*60; - -static const int GOVERNANCE_TRIGGER_EXPIRATION_BLOCKS = 675; // FOR SEEN MAP ARRAYS - GOVERNANCE OBJECTS AND VOTES static const int SEEN_OBJECT_IS_VALID = 0; @@ -113,8 +111,8 @@ struct vote_rec_t { class CGovernanceObject { friend class CGovernanceManager; - friend class CGovernanceTriggerManager; + friend class CSuperblock; public: // Types typedef std::map vote_m_t; @@ -123,7 +121,7 @@ class CGovernanceObject typedef vote_m_t::const_iterator vote_m_cit; - typedef CacheMultiMap vote_mcache_t; + typedef CacheMultiMap vote_cmm_t; private: /// critical section to protect the inner data structures @@ -148,10 +146,10 @@ class CGovernanceObject uint256 nCollateralHash; /// Data field - can be used for anything - std::string strData; + std::vector vchData; /// Dynode info for signed objects - CTxIn vinDynode; + COutPoint dynodeOutpoint; std::vector vchSig; /// is valid by blockchain @@ -163,7 +161,7 @@ class CGovernanceObject /// true == minimum network support has been reached for this object to be funded (doesn't mean it will for sure though) bool fCachedFunding; - /// true == minimum network has been reached flagging this object as a valid and understood goverance object (e.g, the serialized data is correct format, etc) + /// true == minimum network has been reached flagging this object as a valid and understood governance object (e.g, the serialized data is correct format, etc) bool fCachedValid; /// true == minimum network support has been reached saying this object should be deleted from the system entirely @@ -186,14 +184,14 @@ class CGovernanceObject vote_m_t mapCurrentDNVotes; /// Limited map of votes orphaned by DN - vote_mcache_t mapOrphanVotes; + vote_cmm_t cmmapOrphanVotes; CGovernanceObjectVoteFile fileVotes; public: CGovernanceObject(); - CGovernanceObject(uint256 nHashParentIn, int nRevisionIn, int64_t nTime, uint256 nCollateralHashIn, std::string strDataIn); + CGovernanceObject(const uint256& nHashParentIn, int nRevisionIn, int64_t nTime, const uint256& nCollateralHashIn, const std::string& strDataHexIn); CGovernanceObject(const CGovernanceObject& other); @@ -217,8 +215,8 @@ class CGovernanceObject return nCollateralHash; } - const CTxIn& GetDynodeVin() const { - return vinDynode; + const COutPoint& GetDynodeOutpoint() const { + return dynodeOutpoint; } bool IsSetCachedFunding() const { @@ -249,34 +247,33 @@ class CGovernanceObject fDirtyCache = true; } - CGovernanceObjectVoteFile& GetVoteFile() { + const CGovernanceObjectVoteFile& GetVoteFile() const { return fileVotes; } // Signature related functions - void SetDynodeVin(const COutPoint& outpoint); - bool Sign(CKey& keyDynode, CPubKey& pubKeyDynode); - bool CheckSignature(CPubKey& pubKeyDynode); + void SetDynodeOutpoint(const COutPoint& outpoint); + bool Sign(const CKey& keyDynode, const CPubKey& pubKeyDynode); + bool CheckSignature(const CPubKey& pubKeyDynode) const; std::string GetSignatureMessage() const; + uint256 GetSignatureHash() const; // CORE OBJECT FUNCTIONS - bool IsValidLocally(std::string& strError, bool fCheckCollateral); + bool IsValidLocally(std::string& strError, bool fCheckCollateral) const; - bool IsValidLocally(std::string& strError, bool& fMissingDynode, bool& fMissingConfirmations, bool fCheckCollateral); + bool IsValidLocally(std::string& strError, bool& fMissingDynode, bool& fMissingConfirmations, bool fCheckCollateral) const; /// Check the collateral transaction for the budget proposal/finalized budget - bool IsCollateralValid(std::string& strError, bool &fMissingConfirmations); + bool IsCollateralValid(std::string& strError, bool& fMissingConfirmations) const; void UpdateLocalValidity(); void UpdateSentinelVariables(); - int GetObjectSubtype(); - - CAmount GetMinCollateralFee(); + CAmount GetMinCollateralFee() const; UniValue GetJSONObject(); @@ -294,12 +291,12 @@ class CGovernanceObject int GetNoCount(vote_signal_enum_t eVoteSignalIn) const; int GetAbstainCount(vote_signal_enum_t eVoteSignalIn) const; - bool GetCurrentDNVotes(const COutPoint& dnCollateralOutpoint, vote_rec_t& voteRecord); + bool GetCurrentDNVotes(const COutPoint& dnCollateralOutpoint, vote_rec_t& voteRecord) const; // FUNCTIONS FOR DEALING WITH DATA STRING - std::string GetDataAsHex(); - std::string GetDataAsString(); + std::string GetDataAsHexString() const; + std::string GetDataAsPlainString() const; // SERIALIZER @@ -309,15 +306,43 @@ class CGovernanceObject inline void SerializationOp(Stream& s, Operation ser_action) { // SERIALIZE DATA FOR SAVING/LOADING OR NETWORK FUNCTIONS - + int nVersion = s.GetVersion(); READWRITE(nHashParent); READWRITE(nRevision); READWRITE(nTime); READWRITE(nCollateralHash); - READWRITE(LIMITED_STRING(strData, MAX_GOVERNANCE_OBJECT_DATA_SIZE)); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + std::string strDataHex; + if (ser_action.ForRead()) { + READWRITE(LIMITED_STRING(strDataHex, MAX_GOVERNANCE_OBJECT_DATA_SIZE)); + vchData = ParseHex(strDataHex); + } else { + strDataHex = HexStr(vchData); + READWRITE(LIMITED_STRING(strDataHex, MAX_GOVERNANCE_OBJECT_DATA_SIZE)); + } + } else { + // using new format directly + READWRITE(vchData); + } READWRITE(nObjectType); - READWRITE(vinDynode); - READWRITE(vchSig); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn txin; + if (ser_action.ForRead()) { + READWRITE(txin); + dynodeOutpoint = txin.prevout; + } else { + txin = CTxIn(dynodeOutpoint); + READWRITE(txin); + } + } else { + // using new format directly + READWRITE(dynodeOutpoint); + } + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(vchSig); + } if(s.GetType() & SER_DISK) { // Only include these for the disk file format LogPrint("gobject", "CGovernanceObject::SerializationOp Reading/writing votes from/to disk\n"); @@ -355,4 +380,5 @@ class CGovernanceObject }; -#endif \ No newline at end of file +#endif + diff --git a/src/governance-validators.cpp b/src/governance-validators.cpp index 2532403676..ef5353f08c 100644 --- a/src/governance-validators.cpp +++ b/src/governance-validators.cpp @@ -6,39 +6,38 @@ #include "governance-validators.h" #include "base58.h" +#include "timedata.h" +#include "tinyformat.h" #include "utilstrencodings.h" #include -CProposalValidator::CProposalValidator(const std::string& strDataHexIn) - : strData(), - objJSON(UniValue::VOBJ), - fJSONValid(false), - strErrorMessages() -{ - if(!strDataHexIn.empty()) { - SetHexData(strDataHexIn); - } -} +const size_t MAX_DATA_SIZE = 512; +const size_t MAX_NAME_SIZE = 40; -void CProposalValidator::Clear() +CProposalValidator::CProposalValidator(const std::string& strHexData) : + objJSON(UniValue::VOBJ), + fJSONValid(false), + strErrorMessages() { - strData = std::string(); - objJSON = UniValue(UniValue::VOBJ); - fJSONValid = false; - strErrorMessages = std::string(); + if(!strHexData.empty()) { + ParseStrHexData(strHexData); + } } -void CProposalValidator::SetHexData(const std::string& strDataHexIn) +void CProposalValidator::ParseStrHexData(const std::string& strHexData) { - std::vector v = ParseHex(strDataHexIn); - strData = std::string(v.begin(), v.end()); - ParseJSONData(); + std::vector v = ParseHex(strHexData); + if (v.size() > MAX_DATA_SIZE) { + strErrorMessages = strprintf("data exceeds %lu characters;", MAX_DATA_SIZE); + return; + } + ParseJSONData(std::string(v.begin(), v.end())); } -bool CProposalValidator::Validate() +bool CProposalValidator::Validate(bool fCheckExpiration) { - if(!ValidateJSON()) { + if(!fJSONValid) { strErrorMessages += "JSON parsing error;"; return false; } @@ -46,7 +45,7 @@ bool CProposalValidator::Validate() strErrorMessages += "Invalid name;"; return false; } - if(!ValidateStartEndEpoch()) { + if(!ValidateStartEndEpoch(fCheckExpiration)) { strErrorMessages += "Invalid start:end range;"; return false; } @@ -65,11 +64,6 @@ bool CProposalValidator::Validate() return true; } -bool CProposalValidator::ValidateJSON() -{ - return fJSONValid; -} - bool CProposalValidator::ValidateName() { std::string strName; @@ -78,15 +72,8 @@ bool CProposalValidator::ValidateName() return false; } - if(strName.size() > 40) { - strErrorMessages += "name exceeds 40 characters;"; - return false; - } - - std::string strNameStripped = StripWhitespace(strName); - - if(strNameStripped.empty()) { - strErrorMessages += "name is empty;"; + if(strName.size() > MAX_NAME_SIZE) { + strErrorMessages += strprintf("name exceeds %lu characters;", MAX_NAME_SIZE); return false; } @@ -102,7 +89,7 @@ bool CProposalValidator::ValidateName() return true; } -bool CProposalValidator::ValidateStartEndEpoch() +bool CProposalValidator::ValidateStartEndEpoch(bool fCheckExpiration) { int64_t nStartEpoch = 0; int64_t nEndEpoch = 0; @@ -122,6 +109,11 @@ bool CProposalValidator::ValidateStartEndEpoch() return false; } + if(fCheckExpiration && nEndEpoch <= GetAdjustedTime()) { + strErrorMessages += "expired;"; + return false; + } + return true; } @@ -155,17 +147,8 @@ bool CProposalValidator::ValidatePaymentAddress() return false; } - static const std::string base58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - - size_t nLength = strPaymentAddress.size(); - - if((nLength < 26) || (nLength > 35)) { - strErrorMessages += "incorrect payment_address length;"; - return false; - } - - if(strPaymentAddress.find_first_not_of(base58chars) != std::string::npos) { - strErrorMessages += "payment_address contains invalid characters;"; + if(std::find_if(strPaymentAddress.begin(), strPaymentAddress.end(), ::isspace) != strPaymentAddress.end()) { + strErrorMessages += "payment_address can't have whitespaces;"; return false; } @@ -175,6 +158,11 @@ bool CProposalValidator::ValidatePaymentAddress() return false; } + if(address.IsScript()) { + strErrorMessages += "script addresses are not supported;"; + return false; + } + return true; } @@ -186,9 +174,12 @@ bool CProposalValidator::ValidateURL() return false; } - std::string strURLStripped = StripWhitespace(strURL); + if(std::find_if(strURL.begin(), strURL.end(), ::isspace) != strURL.end()) { + strErrorMessages += "url can't have whitespaces;"; + return false; + } - if(strURLStripped.size() < 4U) { + if(strURL.size() < 4U) { strErrorMessages += "url too short;"; return false; } @@ -201,20 +192,27 @@ bool CProposalValidator::ValidateURL() return true; } -void CProposalValidator::ParseJSONData() +void CProposalValidator::ParseJSONData(const std::string& strJSONData) { fJSONValid = false; - if(strData.empty()) { + if(strJSONData.empty()) { return; } try { UniValue obj(UniValue::VOBJ); - obj.read(strData); - std::vector arr1 = obj.getValues(); - std::vector arr2 = arr1.at(0).getValues(); - objJSON = arr2.at(1); + + obj.read(strJSONData); + + if (obj.isObject()) { + objJSON = obj; + } else { + std::vector arr1 = obj.getValues(); + std::vector arr2 = arr1.at(0).getValues(); + objJSON = arr2.at(1); + } + fJSONValid = true; } catch(std::exception& e) { @@ -225,11 +223,11 @@ void CProposalValidator::ParseJSONData() } } -bool CProposalValidator::GetDataValue(const std::string& strKey, std::string& strValue) +bool CProposalValidator::GetDataValue(const std::string& strKey, std::string& strValueRet) { bool fOK = false; try { - strValue = objJSON[strKey].get_str(); + strValueRet = objJSON[strKey].get_str(); fOK = true; } catch(std::exception& e) { @@ -241,14 +239,14 @@ bool CProposalValidator::GetDataValue(const std::string& strKey, std::string& st return fOK; } -bool CProposalValidator::GetDataValue(const std::string& strKey, int64_t& nValue) +bool CProposalValidator::GetDataValue(const std::string& strKey, int64_t& nValueRet) { bool fOK = false; try { const UniValue uValue = objJSON[strKey]; switch(uValue.getType()) { case UniValue::VNUM: - nValue = uValue.get_int64(); + nValueRet = uValue.get_int64(); fOK = true; break; default: @@ -264,14 +262,14 @@ bool CProposalValidator::GetDataValue(const std::string& strKey, int64_t& nValue return fOK; } -bool CProposalValidator::GetDataValue(const std::string& strKey, double& dValue) +bool CProposalValidator::GetDataValue(const std::string& strKey, double& dValueRet) { bool fOK = false; try { const UniValue uValue = objJSON[strKey]; switch(uValue.getType()) { case UniValue::VNUM: - dValue = uValue.get_real(); + dValueRet = uValue.get_real(); fOK = true; break; default: @@ -287,20 +285,6 @@ bool CProposalValidator::GetDataValue(const std::string& strKey, double& dValue) return fOK; } -std::string CProposalValidator::StripWhitespace(const std::string& strIn) -{ - static const std::string strWhitespace = " \f\n\r\t\v"; - - std::string::size_type nStart = strIn.find_first_not_of(strWhitespace); - std::string::size_type nEnd = strIn.find_last_not_of(strWhitespace); - - if((nStart == std::string::npos) || (nEnd == std::string::npos)) { - return std::string(); - } - - return strIn.substr(nStart, nEnd - nStart + 1); -} - /* The purpose of this function is to replicate the behavior of the Python urlparse function used by sentinel (urlparse.py). This function diff --git a/src/governance-validators.h b/src/governance-validators.h index e53fc14502..e87de5a136 100644 --- a/src/governance-validators.h +++ b/src/governance-validators.h @@ -10,27 +10,17 @@ #include -class CProposalValidator { +class CProposalValidator +{ +private: + UniValue objJSON; + bool fJSONValid; + std::string strErrorMessages; + public: CProposalValidator(const std::string& strDataHexIn = std::string()); - void Clear(); - - void SetHexData(const std::string& strDataHexIn); - - bool Validate(); - - bool ValidateJSON(); - - bool ValidateName(); - - bool ValidateStartEndEpoch(); - - bool ValidatePaymentAmount(); - - bool ValidatePaymentAddress(); - - bool ValidateURL(); + bool Validate(bool fCheckExpiration = true); const std::string& GetErrorMessages() { @@ -38,27 +28,20 @@ class CProposalValidator { } private: - void ParseJSONData(); - - bool GetDataValue(const std::string& strKey, std::string& strValue); - - bool GetDataValue(const std::string& strKey, int64_t& nValue); - - bool GetDataValue(const std::string& strKey, double& dValue); - - static std::string StripWhitespace(const std::string& strIn); - - static bool CheckURL(const std::string& strURLIn); - -private: - std::string strData; + void ParseStrHexData(const std::string& strHexData); + void ParseJSONData(const std::string& strJSONData); - UniValue objJSON; - - bool fJSONValid; + bool GetDataValue(const std::string& strKey, std::string& strValueRet); + bool GetDataValue(const std::string& strKey, int64_t& nValueRet); + bool GetDataValue(const std::string& strKey, double& dValueRet); - std::string strErrorMessages; + bool ValidateName(); + bool ValidateStartEndEpoch(bool fCheckExpiration = true); + bool ValidatePaymentAmount(); + bool ValidatePaymentAddress(); + bool ValidateURL(); + bool CheckURL(const std::string& strURLIn); }; -#endif \ No newline at end of file +#endif diff --git a/src/governance-vote.cpp b/src/governance-vote.cpp index 74bc9350f9..ffe47b9586 100644 --- a/src/governance-vote.cpp +++ b/src/governance-vote.cpp @@ -5,12 +5,11 @@ #include "governance-vote.h" #include "governance-object.h" +#include "dynode-sync.h" #include "dynodeman.h" #include "messagesigner.h" #include "util.h" -#include - std::string CGovernanceVoting::ConvertOutcomeToString(vote_outcome_enum_t nOutcome) { switch(nOutcome) @@ -47,106 +46,13 @@ std::string CGovernanceVoting::ConvertSignalToString(vote_signal_enum_t nSignal) case VOTE_SIGNAL_ENDORSED: strReturn = "ENDORSED"; break; - case VOTE_SIGNAL_NOOP1: - strReturn = "NOOP1"; - break; - case VOTE_SIGNAL_NOOP2: - strReturn = "NOOP2"; - break; - case VOTE_SIGNAL_NOOP3: - strReturn = "NOOP3"; - break; - case VOTE_SIGNAL_NOOP4: - strReturn = "NOOP4"; - break; - case VOTE_SIGNAL_NOOP5: - strReturn = "NOOP5"; - break; - case VOTE_SIGNAL_NOOP6: - strReturn = "NOOP6"; - break; - case VOTE_SIGNAL_NOOP7: - strReturn = "NOOP7"; - break; - case VOTE_SIGNAL_NOOP8: - strReturn = "NOOP8"; - break; - case VOTE_SIGNAL_NOOP9: - strReturn = "NOOP9"; - break; - case VOTE_SIGNAL_NOOP10: - strReturn = "NOOP10"; - break; - case VOTE_SIGNAL_NOOP11: - strReturn = "NOOP11"; - break; - case VOTE_SIGNAL_CUSTOM1: - strReturn = "CUSTOM1"; - break; - case VOTE_SIGNAL_CUSTOM2: - strReturn = "CUSTOM2"; - break; - case VOTE_SIGNAL_CUSTOM3: - strReturn = "CUSTOM3"; - break; - case VOTE_SIGNAL_CUSTOM4: - strReturn = "CUSTOM4"; - break; - case VOTE_SIGNAL_CUSTOM5: - strReturn = "CUSTOM5"; - break; - case VOTE_SIGNAL_CUSTOM6: - strReturn = "CUSTOM6"; - break; - case VOTE_SIGNAL_CUSTOM7: - strReturn = "CUSTOM7"; - break; - case VOTE_SIGNAL_CUSTOM8: - strReturn = "CUSTOM8"; - break; - case VOTE_SIGNAL_CUSTOM9: - strReturn = "CUSTOM9"; - break; - case VOTE_SIGNAL_CUSTOM10: - strReturn = "CUSTOM10"; - break; - case VOTE_SIGNAL_CUSTOM11: - strReturn = "CUSTOM11"; - break; - case VOTE_SIGNAL_CUSTOM12: - strReturn = "CUSTOM12"; - break; - case VOTE_SIGNAL_CUSTOM13: - strReturn = "CUSTOM13"; - break; - case VOTE_SIGNAL_CUSTOM14: - strReturn = "CUSTOM14"; - break; - case VOTE_SIGNAL_CUSTOM15: - strReturn = "CUSTOM15"; - break; - case VOTE_SIGNAL_CUSTOM16: - strReturn = "CUSTOM16"; - break; - case VOTE_SIGNAL_CUSTOM17: - strReturn = "CUSTOM17"; - break; - case VOTE_SIGNAL_CUSTOM18: - strReturn = "CUSTOM18"; - break; - case VOTE_SIGNAL_CUSTOM19: - strReturn = "CUSTOM19"; - break; - case VOTE_SIGNAL_CUSTOM20: - strReturn = "CUSTOM20"; - break; } return strReturn; } -vote_outcome_enum_t CGovernanceVoting::ConvertVoteOutcome(std::string strVoteOutcome) +vote_outcome_enum_t CGovernanceVoting::ConvertVoteOutcome(const std::string& strVoteOutcome) { vote_outcome_enum_t eVote = VOTE_OUTCOME_NONE; if(strVoteOutcome == "yes") { @@ -161,94 +67,157 @@ vote_outcome_enum_t CGovernanceVoting::ConvertVoteOutcome(std::string strVoteOut return eVote; } -vote_signal_enum_t CGovernanceVoting::ConvertVoteSignal(std::string strVoteSignal) +vote_signal_enum_t CGovernanceVoting::ConvertVoteSignal(const std::string& strVoteSignal) { - vote_signal_enum_t eSignal = VOTE_SIGNAL_NONE; - if(strVoteSignal == "funding") { - eSignal = VOTE_SIGNAL_FUNDING; - } - else if(strVoteSignal == "valid") { - eSignal = VOTE_SIGNAL_VALID; - } - if(strVoteSignal == "delete") { - eSignal = VOTE_SIGNAL_DELETE; - } - if(strVoteSignal == "endorsed") { - eSignal = VOTE_SIGNAL_ENDORSED; - } - - if(eSignal != VOTE_SIGNAL_NONE) { - return eSignal; - } - - // ID FIVE THROUGH CUSTOM_START ARE TO BE USED BY GOVERNANCE ENGINE / TRIGGER SYSTEM - - // convert custom sentinel outcomes to integer and store - try { - int i = boost::lexical_cast(strVoteSignal); - if(i < VOTE_SIGNAL_CUSTOM1 || i > VOTE_SIGNAL_CUSTOM20) { - eSignal = VOTE_SIGNAL_NONE; - } - else { - eSignal = vote_signal_enum_t(i); - } - } - catch(std::exception const & e) - { - std::ostringstream ostr; - ostr << "CGovernanceVote::ConvertVoteSignal: error : " << e.what() << std::endl; - LogPrintf(ostr.str().c_str()); + static const std::map mapStrVoteSignals = { + {"funding", VOTE_SIGNAL_FUNDING}, + {"valid", VOTE_SIGNAL_VALID}, + {"delete", VOTE_SIGNAL_DELETE}, + {"endorsed", VOTE_SIGNAL_ENDORSED} + }; + + const auto& it = mapStrVoteSignals.find(strVoteSignal); + if (it == mapStrVoteSignals.end()) { + LogPrintf("CGovernanceVoting::%s -- ERROR: Unknown signal %s\n", __func__, strVoteSignal); + return VOTE_SIGNAL_NONE; } - - return eSignal; + return it->second; } CGovernanceVote::CGovernanceVote() : fValid(true), fSynced(false), nVoteSignal(int(VOTE_SIGNAL_NONE)), - vinDynode(), + dynodeOutpoint(), nParentHash(), nVoteOutcome(int(VOTE_OUTCOME_NONE)), nTime(0), vchSig() {} -CGovernanceVote::CGovernanceVote(COutPoint outpointDynodeIn, uint256 nParentHashIn, vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn) +CGovernanceVote::CGovernanceVote(const COutPoint& outpointDynodeIn, const uint256& nParentHashIn, vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn) : fValid(true), fSynced(false), nVoteSignal(eVoteSignalIn), - vinDynode(outpointDynodeIn), + dynodeOutpoint(outpointDynodeIn), nParentHash(nParentHashIn), nVoteOutcome(eVoteOutcomeIn), nTime(GetAdjustedTime()), vchSig() -{} +{ + UpdateHash(); +} + +std::string CGovernanceVote::ToString() const +{ + std::ostringstream ostr; + ostr << dynodeOutpoint.ToStringShort() << ":" + << nTime << ":" + << CGovernanceVoting::ConvertOutcomeToString(GetOutcome()) << ":" + << CGovernanceVoting::ConvertSignalToString(GetSignal()); + return ostr.str(); +} void CGovernanceVote::Relay(CConnman& connman) const { + // Do not relay until fully synced + if(!dynodeSync.IsSynced()) { + LogPrint("gobject", "CGovernanceVote::Relay -- won't relay until fully synced\n"); + return; + } + CInv inv(MSG_GOVERNANCE_OBJECT_VOTE, GetHash()); connman.RelayInv(inv, MIN_GOVERNANCE_PEER_PROTO_VERSION); } -bool CGovernanceVote::Sign(CKey& keyDynode, CPubKey& pubKeyDynode) +void CGovernanceVote::UpdateHash() const +{ + // Note: doesn't match serialization + + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << dynodeOutpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing format + ss << nParentHash; + ss << nVoteSignal; + ss << nVoteOutcome; + ss << nTime; + *const_cast(&hash) = ss.GetHash(); +} + +uint256 CGovernanceVote::GetHash() const +{ + return hash; +} + +uint256 CGovernanceVote::GetSignatureHash() const { - // Choose coins to use - CPubKey pubKeyCollateralAddress; - CKey keyCollateralAddress; + return SerializeHash(*this); +} +bool CGovernanceVote::Sign(const CKey& keyDynode, const CPubKey& pubKeyDynode) +{ std::string strError; - std::string strMessage = vinDynode.prevout.ToStringShort() + "|" + nParentHash.ToString() + "|" + - boost::lexical_cast(nVoteSignal) + "|" + boost::lexical_cast(nVoteOutcome) + "|" + boost::lexical_cast(nTime); - if(!CMessageSigner::SignMessage(strMessage, vchSig, keyDynode)) { - LogPrintf("CGovernanceVote::Sign -- SignMessage() failed\n"); - return false; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if(!CHashSigner::SignHash(hash, keyDynode, vchSig)) { + LogPrintf("CGovernanceVote::Sign -- SignHash() failed\n"); + return false; + } + + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + LogPrintf("CGovernanceVote::Sign -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + + std::string strMessage = dynodeOutpoint.ToStringShort() + "|" + nParentHash.ToString() + "|" + + std::to_string(nVoteSignal) + "|" + std::to_string(nVoteOutcome) + "|" + std::to_string(nTime); + + if(!CMessageSigner::SignMessage(strMessage, vchSig, keyDynode)) { + LogPrintf("CGovernanceVote::Sign -- SignMessage() failed\n"); + return false; + } + + if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CGovernanceVote::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } - if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CGovernanceVote::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; + return true; +} + +bool CGovernanceVote::CheckSignature(const CPubKey& pubKeyDynode) const +{ + std::string strError; + + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + // could be a signature in old format + std::string strMessage = dynodeOutpoint.ToStringShort() + "|" + nParentHash.ToString() + "|" + + std::to_string(nVoteSignal) + "|" + + std::to_string(nVoteOutcome) + "|" + + std::to_string(nTime); + + if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + // nope, not in old format either + LogPrint("gobject", "CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s\n", strError); + return false; + } + } + } else { + std::string strMessage = dynodeOutpoint.ToStringShort() + "|" + nParentHash.ToString() + "|" + + std::to_string(nVoteSignal) + "|" + + std::to_string(nVoteOutcome) + "|" + + std::to_string(nTime); + + if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrint("gobject", "CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } return true; @@ -261,7 +230,7 @@ bool CGovernanceVote::IsValid(bool fSignatureCheck) const return false; } - // support up to 50 actions (implemented in sentinel) + // support up to MAX_SUPPORTED_VOTE_SIGNAL, can be extended if(nVoteSignal > MAX_SUPPORTED_VOTE_SIGNAL) { LogPrint("gobject", "CGovernanceVote::IsValid -- Client attempted to vote on invalid signal(%d) - %s\n", nVoteSignal, GetHash().ToString()); @@ -276,28 +245,19 @@ bool CGovernanceVote::IsValid(bool fSignatureCheck) const } dynode_info_t infoDn; - if(!dnodeman.GetDynodeInfo(vinDynode.prevout, infoDn)) { - LogPrint("gobject", "CGovernanceVote::IsValid -- Unknown Dynode - %s\n", vinDynode.prevout.ToStringShort()); + if(!dnodeman.GetDynodeInfo(dynodeOutpoint, infoDn)) { + LogPrint("gobject", "CGovernanceVote::IsValid -- Unknown Dynode - %s\n", dynodeOutpoint.ToStringShort()); return false; } if(!fSignatureCheck) return true; - std::string strError; - std::string strMessage = vinDynode.prevout.ToStringShort() + "|" + nParentHash.ToString() + "|" + - boost::lexical_cast(nVoteSignal) + "|" + boost::lexical_cast(nVoteOutcome) + "|" + boost::lexical_cast(nTime); - - if(!CMessageSigner::VerifyMessage(infoDn.pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s\n", strError); - return false; - } - - return true; + return CheckSignature(infoDn.pubKeyDynode); } bool operator==(const CGovernanceVote& vote1, const CGovernanceVote& vote2) { - bool fResult = ((vote1.vinDynode == vote2.vinDynode) && + bool fResult = ((vote1.dynodeOutpoint == vote2.dynodeOutpoint) && (vote1.nParentHash == vote2.nParentHash) && (vote1.nVoteOutcome == vote2.nVoteOutcome) && (vote1.nVoteSignal == vote2.nVoteSignal) && @@ -307,11 +267,11 @@ bool operator==(const CGovernanceVote& vote1, const CGovernanceVote& vote2) bool operator<(const CGovernanceVote& vote1, const CGovernanceVote& vote2) { - bool fResult = (vote1.vinDynode < vote2.vinDynode); + bool fResult = (vote1.dynodeOutpoint < vote2.dynodeOutpoint); if(!fResult) { return false; } - fResult = (vote1.vinDynode == vote2.vinDynode); + fResult = (vote1.dynodeOutpoint == vote2.dynodeOutpoint); fResult = fResult && (vote1.nParentHash < vote2.nParentHash); if(!fResult) { diff --git a/src/governance-vote.h b/src/governance-vote.h index 9a9689c61b..5eeab21beb 100644 --- a/src/governance-vote.h +++ b/src/governance-vote.h @@ -30,37 +30,6 @@ enum vote_signal_enum_t { VOTE_SIGNAL_VALID = 2, // -- this object checks out in sentinel engine VOTE_SIGNAL_DELETE = 3, // -- this object should be deleted from memory entirely VOTE_SIGNAL_ENDORSED = 4, // -- officially endorsed by the network somehow (delegation) - VOTE_SIGNAL_NOOP1 = 5, // FOR FURTHER EXPANSION - VOTE_SIGNAL_NOOP2 = 6, - VOTE_SIGNAL_NOOP3 = 7, - VOTE_SIGNAL_NOOP4 = 8, - VOTE_SIGNAL_NOOP5 = 9, - VOTE_SIGNAL_NOOP6 = 10, - VOTE_SIGNAL_NOOP7 = 11, - VOTE_SIGNAL_NOOP8 = 12, - VOTE_SIGNAL_NOOP9 = 13, - VOTE_SIGNAL_NOOP10 = 14, - VOTE_SIGNAL_NOOP11 = 15, - VOTE_SIGNAL_CUSTOM1 = 16, // SENTINEL CUSTOM ACTIONS - VOTE_SIGNAL_CUSTOM2 = 17, // 16-35 - VOTE_SIGNAL_CUSTOM3 = 18, - VOTE_SIGNAL_CUSTOM4 = 19, - VOTE_SIGNAL_CUSTOM5 = 20, - VOTE_SIGNAL_CUSTOM6 = 21, - VOTE_SIGNAL_CUSTOM7 = 22, - VOTE_SIGNAL_CUSTOM8 = 23, - VOTE_SIGNAL_CUSTOM9 = 24, - VOTE_SIGNAL_CUSTOM10 = 25, - VOTE_SIGNAL_CUSTOM11 = 26, - VOTE_SIGNAL_CUSTOM12 = 27, - VOTE_SIGNAL_CUSTOM13 = 28, - VOTE_SIGNAL_CUSTOM14 = 29, - VOTE_SIGNAL_CUSTOM15 = 30, - VOTE_SIGNAL_CUSTOM16 = 31, - VOTE_SIGNAL_CUSTOM17 = 32, - VOTE_SIGNAL_CUSTOM18 = 33, - VOTE_SIGNAL_CUSTOM19 = 34, - VOTE_SIGNAL_CUSTOM20 = 35 }; static const int MAX_SUPPORTED_VOTE_SIGNAL = VOTE_SIGNAL_ENDORSED; @@ -74,14 +43,14 @@ static const int MAX_SUPPORTED_VOTE_SIGNAL = VOTE_SIGNAL_ENDORSED; class CGovernanceVoting { public: - static vote_outcome_enum_t ConvertVoteOutcome(std::string strVoteOutcome); - static vote_signal_enum_t ConvertVoteSignal(std::string strVoteSignal); + static vote_outcome_enum_t ConvertVoteOutcome(const std::string& strVoteOutcome); + static vote_signal_enum_t ConvertVoteSignal(const std::string& strVoteSignal); static std::string ConvertOutcomeToString(vote_outcome_enum_t nOutcome); static std::string ConvertSignalToString(vote_signal_enum_t nSignal); }; // -// CGovernanceVote - Allow a Dynode to vote and broadcast throughout the network +// CGovernanceVote - Allow a dynode node to vote and broadcast throughout the network // class CGovernanceVote @@ -94,15 +63,19 @@ class CGovernanceVote bool fValid; //if the vote is currently valid / counted bool fSynced; //if we've sent this to our peers int nVoteSignal; // see VOTE_ACTIONS above - CTxIn vinDynode; + COutPoint dynodeOutpoint; uint256 nParentHash; int nVoteOutcome; // see VOTE_OUTCOMES above int64_t nTime; std::vector vchSig; + /** Memory only. */ + const uint256 hash; + void UpdateHash() const; + public: CGovernanceVote(); - CGovernanceVote(COutPoint outpointDynodeIn, uint256 nParentHashIn, vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn); + CGovernanceVote(const COutPoint& outpointDynodeIn, const uint256& nParentHashIn, vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn); bool IsValid() const { return fValid; } @@ -116,11 +89,12 @@ class CGovernanceVote const uint256& GetParentHash() const { return nParentHash; } - void SetTime(int64_t nTimeIn) { nTime = nTimeIn; } + void SetTime(int64_t nTimeIn) { nTime = nTimeIn; UpdateHash(); } void SetSignature(const std::vector& vchSigIn) { vchSig = vchSigIn; } - bool Sign(CKey& keyDynode, CPubKey& pubKeyDynode); + bool Sign(const CKey& keyDynode, const CPubKey& pubKeyDynode); + bool CheckSignature(const CPubKey& pubKeyDynode) const; bool IsValid(bool fSignatureCheck) const; void Relay(CConnman& connman) const; @@ -128,7 +102,7 @@ class CGovernanceVote return CGovernanceVoting::ConvertOutcomeToString(GetOutcome()); } - const COutPoint& GetDynodeOutpoint() const { return vinDynode.prevout; } + const COutPoint& GetDynodeOutpoint() const { return dynodeOutpoint; } /** * GetHash() @@ -136,86 +110,41 @@ class CGovernanceVote * GET UNIQUE HASH WITH DETERMINISTIC VALUE OF THIS SPECIFIC VOTE */ - uint256 GetHash() const - { - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << vinDynode; - ss << nParentHash; - ss << nVoteSignal; - ss << nVoteOutcome; - ss << nTime; - return ss.GetHash(); - } + uint256 GetHash() const; + uint256 GetSignatureHash() const; - std::string ToString() const - { - std::ostringstream ostr; - ostr << vinDynode.ToString() << ":" - << nTime << ":" - << CGovernanceVoting::ConvertOutcomeToString(GetOutcome()) << ":" - << CGovernanceVoting::ConvertSignalToString(GetSignal()); - return ostr.str(); - } - - /** - * GetTypeHash() - * - * GET HASH WITH DETERMINISTIC VALUE OF DYNODE-VIN/PARENT-HASH/VOTE-SIGNAL - * - * This hash collides with previous Dynode votes when they update their votes on governance objects. - * With 12.1 there's various types of votes (funding, valid, delete, etc), so this is the deterministic hash - * that will collide with the previous vote and allow the system to update. - * - * -- - * - * We do not include an outcome, because that can change when a Dynode updates their vote from yes to no - * on funding a specific project for example. - * We do not include a time because it will be updated each time the vote is updated, changing the hash - */ - uint256 GetTypeHash() const - { - // CALCULATE HOW TO STORE VOTE IN governance.mapVotes - - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << vinDynode; - ss << nParentHash; - ss << nVoteSignal; - // -- no outcome - // -- timeless - return ss.GetHash(); - } + std::string ToString() const; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(vinDynode); + int nVersion = s.GetVersion(); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn txin{}; + if (ser_action.ForRead()) { + READWRITE(txin); + dynodeOutpoint = txin.prevout; + } else { + txin = CTxIn(dynodeOutpoint); + READWRITE(txin); + } + } else { + // using new format directly + READWRITE(dynodeOutpoint); + } READWRITE(nParentHash); READWRITE(nVoteOutcome); READWRITE(nVoteSignal); READWRITE(nTime); - READWRITE(vchSig); + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(vchSig); + } + if (ser_action.ForRead()) + UpdateHash(); } }; - - -/** -* 12.1.1 - CGovernanceVoteManager -* ------------------------------- -* - - GetVote(name, yes_no): - - caching function - - mark last accessed votes - - load serialized files from filesystem if needed - - calc answer - - return result - - CacheUnused(): - - Cache votes if lastused > 12h/24/48/etc - -*/ - #endif \ No newline at end of file diff --git a/src/governance-votedb.cpp b/src/governance-votedb.cpp index 0aa42bbf34..3493b3b102 100644 --- a/src/governance-votedb.cpp +++ b/src/governance-votedb.cpp @@ -21,27 +21,27 @@ CGovernanceObjectVoteFile::CGovernanceObjectVoteFile(const CGovernanceObjectVote void CGovernanceObjectVoteFile::AddVote(const CGovernanceVote& vote) { + uint256 nHash = vote.GetHash(); + // make sure to never add/update already known votes + if (HasVote(nHash)) + return; listVotes.push_front(vote); - mapVoteIndex[vote.GetHash()] = listVotes.begin(); + mapVoteIndex.emplace(nHash, listVotes.begin()); ++nMemoryVotes; } bool CGovernanceObjectVoteFile::HasVote(const uint256& nHash) const { - vote_m_cit it = mapVoteIndex.find(nHash); - if(it == mapVoteIndex.end()) { - return false; - } - return true; + return mapVoteIndex.find(nHash) != mapVoteIndex.end(); } -bool CGovernanceObjectVoteFile::GetVote(const uint256& nHash, CGovernanceVote& vote) const +bool CGovernanceObjectVoteFile::SerializeVoteToStream(const uint256& nHash, CDataStream& ss) const { vote_m_cit it = mapVoteIndex.find(nHash); if(it == mapVoteIndex.end()) { return false; } - vote = *(it->second); + ss << *(it->second); return true; } @@ -69,14 +69,6 @@ void CGovernanceObjectVoteFile::RemoveVotesFromDynode(const COutPoint& outpointD } } -CGovernanceObjectVoteFile& CGovernanceObjectVoteFile::operator=(const CGovernanceObjectVoteFile& other) -{ - nMemoryVotes = other.nMemoryVotes; - listVotes = other.listVotes; - RebuildIndex(); - return *this; -} - void CGovernanceObjectVoteFile::RebuildIndex() { mapVoteIndex.clear(); diff --git a/src/governance-votedb.h b/src/governance-votedb.h index 2310b941be..bb3580588a 100644 --- a/src/governance-votedb.h +++ b/src/governance-votedb.h @@ -11,6 +11,7 @@ #include "governance-vote.h" #include "serialize.h" +#include "streams.h" #include "uint256.h" /** @@ -63,7 +64,7 @@ class CGovernanceObjectVoteFile /** * Retrieve a vote cached in memory */ - bool GetVote(const uint256& nHash, CGovernanceVote& vote) const; + bool SerializeVoteToStream(const uint256& nHash, CDataStream& ss) const; int GetVoteCount() { return nMemoryVotes; @@ -71,8 +72,6 @@ class CGovernanceObjectVoteFile std::vector GetVotes() const; - CGovernanceObjectVoteFile& operator=(const CGovernanceObjectVoteFile& other); - void RemoveVotesFromDynode(const COutPoint& outpointDynode); ADD_SERIALIZE_METHODS; @@ -91,4 +90,4 @@ class CGovernanceObjectVoteFile }; -#endif \ No newline at end of file +#endif diff --git a/src/governance.cpp b/src/governance.cpp index c611900a54..6d6f225a1a 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -5,16 +5,20 @@ #include "governance.h" +#include "consensus/validation.h" #include "dynode.h" #include "dynode-sync.h" #include "dynodeman.h" #include "governance-object.h" +#include "governance-validators.h" #include "governance-vote.h" #include "governance-classes.h" #include "net_processing.h" +#include "netmessagemaker.h" #include "messagesigner.h" #include "netfulfilledman.h" #include "util.h" +#include "validationinterface.h" CGovernanceManager governance; @@ -30,12 +34,9 @@ CGovernanceManager::CGovernanceManager() mapObjects(), mapErasedGovernanceObjects(), mapDynodeOrphanObjects(), - mapWatchdogObjects(), - nHashWatchdogCurrent(), - nTimeWatchdogCurrent(0), - mapVoteToObject(MAX_CACHE_SIZE), - mapInvalidVotes(MAX_CACHE_SIZE), - mapOrphanVotes(MAX_CACHE_SIZE), + cmapVoteToObject(MAX_CACHE_SIZE), + cmapInvalidVotes(MAX_CACHE_SIZE), + cmmapOrphanVotes(MAX_CACHE_SIZE), mapLastDynodeObject(), setRequestedObjects(), fRateChecksEnabled(true), @@ -43,15 +44,16 @@ CGovernanceManager::CGovernanceManager() {} // Accessors for thread-safe access to maps -bool CGovernanceManager::HaveObjectForHash(uint256 nHash) { +bool CGovernanceManager::HaveObjectForHash(const uint256& nHash) const +{ LOCK(cs); return (mapObjects.count(nHash) == 1 || mapPostponedObjects.count(nHash) == 1); } -bool CGovernanceManager::SerializeObjectForHash(uint256 nHash, CDataStream& ss) +bool CGovernanceManager::SerializeObjectForHash(const uint256& nHash, CDataStream& ss) const { LOCK(cs); - object_m_it it = mapObjects.find(nHash); + object_m_cit it = mapObjects.find(nHash); if (it == mapObjects.end()) { it = mapPostponedObjects.find(nHash); if (it == mapPostponedObjects.end()) @@ -61,59 +63,47 @@ bool CGovernanceManager::SerializeObjectForHash(uint256 nHash, CDataStream& ss) return true; } -bool CGovernanceManager::HaveVoteForHash(uint256 nHash) +bool CGovernanceManager::HaveVoteForHash(const uint256& nHash) const { LOCK(cs); - CGovernanceObject* pGovobj = NULL; - if(!mapVoteToObject.Get(nHash,pGovobj)) { - return false; - } - - if(!pGovobj->GetVoteFile().HasVote(nHash)) { - return false; - } - return true; + CGovernanceObject* pGovobj = nullptr; + return cmapVoteToObject.Get(nHash, pGovobj) && pGovobj->GetVoteFile().HasVote(nHash); } int CGovernanceManager::GetVoteCount() const { LOCK(cs); - return (int)mapVoteToObject.GetSize(); + return (int)cmapVoteToObject.GetSize(); } -bool CGovernanceManager::SerializeVoteForHash(uint256 nHash, CDataStream& ss) +bool CGovernanceManager::SerializeVoteForHash(const uint256& nHash, CDataStream& ss) const { LOCK(cs); - CGovernanceObject* pGovobj = NULL; - if(!mapVoteToObject.Get(nHash,pGovobj)) { - return false; - } - - CGovernanceVote vote; - if(!pGovobj->GetVoteFile().GetVote(nHash, vote)) { - return false; - } - - ss << vote; - return true; + CGovernanceObject* pGovobj = nullptr; + return cmapVoteToObject.Get(nHash,pGovobj) && pGovobj->GetVoteFile().SerializeVoteToStream(nHash, ss); } -void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman) +void CGovernanceManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) { // lite mode is not supported if(fLiteMode) return; if(!dynodeSync.IsBlockchainSynced()) return; - if(pfrom->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) return; - // ANOTHER USER IS ASKING US TO HELP THEM SYNC GOVERNANCE OBJECT DATA if (strCommand == NetMsgType::DNGOVERNANCESYNC) { + if(pfrom->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) { + LogPrint("gobject", "DNGOVERNANCESYNC -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_GOVERNANCE_PEER_PROTO_VERSION))); + return; + } + // Ignore such requests until we are fully synced. - // We could start processing this after Dynode list is synced + // We could start processing this after dynode list is synced // but this is a heavy one so it's better to finish sync first. if (!dynodeSync.IsSynced()) return; @@ -131,18 +121,11 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C } if(nProp == uint256()) { - if(netfulfilledman.HasFulfilledRequest(pfrom->addr, NetMsgType::DNGOVERNANCESYNC)) { - // Asking for the whole list multiple times in a short period of time is no good - LogPrint("gobject", "DNGOVERNANCESYNC -- peer already asked me for the list\n"); - Misbehaving(pfrom->GetId(), 20); - return; - } - netfulfilledman.AddFulfilledRequest(pfrom->addr, NetMsgType::DNGOVERNANCESYNC); + SyncAll(pfrom, connman); + } else { + SyncSingleObjAndItsVotes(pfrom, nProp, filter, connman); } - - Sync(pfrom, nProp, filter, connman); LogPrint("gobject", "DNGOVERNANCESYNC -- syncing governance objects to our peer at %s\n", pfrom->addr.ToString()); - } // A NEW GOVERNANCE OBJECT HAS ARRIVED @@ -157,6 +140,13 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C pfrom->setAskFor.erase(nHash); + if(pfrom->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) { + LogPrint("gobject", "DNGOVERNANCEOBJECT -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_GOVERNANCE_PEER_PROTO_VERSION))); + return; + } + if(!dynodeSync.IsDynodeListSynced()) { LogPrint("gobject", "DNGOVERNANCEOBJECT -- dynode list not synced\n"); return; @@ -203,9 +193,9 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C if(!fIsValid) { if(fDynodeMissing) { - int& count = mapDynodeOrphanCounter[govobj.GetDynodeVin().prevout]; + int& count = mapDynodeOrphanCounter[govobj.GetDynodeOutpoint()]; if (count >= 10) { - LogPrint("gobject", "DNGOVERNANCEOBJECT -- Too many orphan objects, missing dynode=%s\n", govobj.GetDynodeVin().prevout.ToStringShort()); + LogPrint("gobject", "DNGOVERNANCEOBJECT -- Too many orphan objects, missing dynode=%s\n", govobj.GetDynodeOutpoint().ToStringShort()); // ask for this object again in 2 minutes CInv inv(MSG_GOVERNANCE_OBJECT, govobj.GetHash()); pfrom->AskFor(inv); @@ -240,6 +230,13 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C uint256 nHash = vote.GetHash(); pfrom->setAskFor.erase(nHash); + + if(pfrom->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) { + LogPrint("gobject", "DNGOVERNANCEOBJECTVOTE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_GOVERNANCE_PEER_PROTO_VERSION))); + } + // Ignore such messages until dynode list is synced if(!dynodeSync.IsDynodeListSynced()) { LogPrint("gobject", "DNGOVERNANCEOBJECTVOTE -- dynode list not synced\n"); @@ -265,11 +262,13 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C else { LogPrint("gobject", "DNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s\n", exception.what()); if((exception.GetNodePenalty() != 0) && dynodeSync.IsSynced()) { + LOCK(cs_main); Misbehaving(pfrom->GetId(), exception.GetNodePenalty()); } return; } - + // SEND NOTIFICATION TO SCRIPT/ZMQ + GetMainSignals().NotifyGovernanceVote(vote); } } @@ -277,7 +276,7 @@ void CGovernanceManager::CheckOrphanVotes(CGovernanceObject& govobj, CGovernance { uint256 nHash = govobj.GetHash(); std::vector vecVotePairs; - mapOrphanVotes.GetAll(nHash, vecVotePairs); + cmmapOrphanVotes.GetAll(nHash, vecVotePairs); ScopedLockBool guard(cs, fRateChecksEnabled, false); @@ -290,19 +289,19 @@ void CGovernanceManager::CheckOrphanVotes(CGovernanceObject& govobj, CGovernance if(pairVote.second < nNow) { fRemove = true; } - else if(govobj.ProcessVote(NULL, vote, exception, connman)) { + else if(govobj.ProcessVote(nullptr, vote, exception, connman)) { vote.Relay(connman); fRemove = true; } if(fRemove) { - mapOrphanVotes.Erase(nHash, pairVote); + cmmapOrphanVotes.Erase(nHash, pairVote); } } } void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, CConnman& connman, CNode* pfrom) { - DBG( cout << "CGovernanceManager::AddGovernanceObject START" << endl; ); + DBG( std::cout << "CGovernanceManager::AddGovernanceObject START" << std::endl; ); uint256 nHash = govobj.GetHash(); std::string strHash = nHash.ToString(); @@ -321,60 +320,39 @@ void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, CConnman return; } + LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Adding object: hash = %s, type = %d\n", nHash.ToString(), govobj.GetObjectType()); + + // INSERT INTO OUR GOVERNANCE OBJECT MEMORY // IF WE HAVE THIS OBJECT ALREADY, WE DON'T WANT ANOTHER COPY + auto objpair = mapObjects.emplace(nHash, govobj); - if(mapObjects.count(nHash)) { + if(!objpair.second) { LogPrintf("CGovernanceManager::AddGovernanceObject -- already have governance object %s\n", nHash.ToString()); return; } - LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Adding object: hash = %s, type = %d\n", nHash.ToString(), govobj.GetObjectType()); - - if(govobj.nObjectType == GOVERNANCE_OBJECT_WATCHDOG) { - // If it's a watchdog, make sure it fits required time bounds - if((govobj.GetCreationTime() < GetAdjustedTime() - GOVERNANCE_WATCHDOG_EXPIRATION_TIME || - govobj.GetCreationTime() > GetAdjustedTime() + GOVERNANCE_WATCHDOG_EXPIRATION_TIME) - ) { - // drop it - LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- CreationTime is out of bounds: hash = %s\n", nHash.ToString()); - return; - } + // SHOULD WE ADD THIS OBJECT TO ANY OTHER MANANGERS? - if(!UpdateCurrentWatchdog(govobj)) { - // Allow wd's which are not current to be reprocessed - if(pfrom && (nHashWatchdogCurrent != uint256())) { - pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, nHashWatchdogCurrent)); + DBG( std::cout << "CGovernanceManager::AddGovernanceObject Before trigger block, GetDataAsPlainString = " + << govobj.GetDataAsPlainString() + << ", nObjectType = " << govobj.nObjectType + << std::endl; ); + + if (govobj.nObjectType == GOVERNANCE_OBJECT_TRIGGER) { + DBG( std::cout << "CGovernanceManager::AddGovernanceObject Before AddNewTrigger" << std::endl; ); + if (!triggerman.AddNewTrigger(nHash)) { + LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- undo adding invalid trigger object: hash = %s\n", nHash.ToString()); + CGovernanceObject& objref = objpair.first->second; + objref.fCachedDelete = true; + if (objref.nDeletionTime == 0) { + objref.nDeletionTime = GetAdjustedTime(); } - LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Watchdog not better than current: hash = %s\n", nHash.ToString()); return; } + DBG( std::cout << "CGovernanceManager::AddGovernanceObject After AddNewTrigger" << std::endl; ); } - // INSERT INTO OUR GOVERNANCE OBJECT MEMORY - mapObjects.insert(std::make_pair(nHash, govobj)); - - // SHOULD WE ADD THIS OBJECT TO ANY OTHER MANANGERS? - - DBG( cout << "CGovernanceManager::AddGovernanceObject Before trigger block, strData = " - << govobj.GetDataAsString() - << ", nObjectType = " << govobj.nObjectType - << endl; ); - - switch(govobj.nObjectType) { - case GOVERNANCE_OBJECT_TRIGGER: - DBG( cout << "CGovernanceManager::AddGovernanceObject Before AddNewTrigger" << endl; ); - triggerman.AddNewTrigger(nHash); - DBG( cout << "CGovernanceManager::AddGovernanceObject After AddNewTrigger" << endl; ); - break; - case GOVERNANCE_OBJECT_WATCHDOG: - mapWatchdogObjects[nHash] = govobj.GetCreationTime() + GOVERNANCE_WATCHDOG_EXPIRATION_TIME; - LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Added watchdog to map: hash = %s\n", nHash.ToString()); - break; - default: - break; - } - - LogPrintf("AddGovernanceObject -- %s new, received form %s\n", strHash, pfrom? pfrom->addrName : "NULL"); + LogPrintf("CGovernanceManager::AddGovernanceObject -- %s new, received from %s\n", strHash, pfrom ? pfrom->GetAddrName() : "nullptr"); govobj.Relay(connman); // Update the rate buffer @@ -387,41 +365,11 @@ void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, CConnman CGovernanceException exception; CheckOrphanVotes(govobj, exception, connman); - DBG( cout << "CGovernanceManager::AddGovernanceObject END" << endl; ); -} + // SEND NOTIFICATION TO SCRIPT/ZMQ + GetMainSignals().NotifyGovernanceObject(govobj); -bool CGovernanceManager::UpdateCurrentWatchdog(CGovernanceObject& watchdogNew) -{ - bool fAccept = false; - - arith_uint256 nHashNew = UintToArith256(watchdogNew.GetHash()); - arith_uint256 nHashCurrent = UintToArith256(nHashWatchdogCurrent); - - int64_t nExpirationDelay = GOVERNANCE_WATCHDOG_EXPIRATION_TIME / 2; - int64_t nNow = GetAdjustedTime(); - if(nHashWatchdogCurrent == uint256() || // no known current OR - ((nNow - watchdogNew.GetCreationTime() < nExpirationDelay) && // (new one is NOT expired AND - ((nNow - nTimeWatchdogCurrent > nExpirationDelay) || (nHashNew > nHashCurrent)))// (current is expired OR - // its hash is lower)) - ) { - LOCK(cs); - object_m_it it = mapObjects.find(nHashWatchdogCurrent); - if(it != mapObjects.end()) { - LogPrint("gobject", "CGovernanceManager::UpdateCurrentWatchdog -- Expiring previous current watchdog, hash = %s\n", nHashWatchdogCurrent.ToString()); - it->second.fExpired = true; - if(it->second.nDeletionTime == 0) { - it->second.nDeletionTime = nNow; - } - } - nHashWatchdogCurrent = watchdogNew.GetHash(); - nTimeWatchdogCurrent = watchdogNew.GetCreationTime(); - fAccept = true; - LogPrint("gobject", "CGovernanceManager::UpdateCurrentWatchdog -- Current watchdog updated to: hash = %s\n", - ArithToUint256(nHashNew).ToString()); - } - - return fAccept; + DBG( std::cout << "CGovernanceManager::AddGovernanceObject END" << std::endl; ); } void CGovernanceManager::UpdateCachesAndClean() @@ -432,34 +380,6 @@ void CGovernanceManager::UpdateCachesAndClean() LOCK2(cs_main, cs); - // Flag expired watchdogs for removal - int64_t nNow = GetAdjustedTime(); - LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Number watchdogs in map: %d, current time = %d\n", mapWatchdogObjects.size(), nNow); - if(mapWatchdogObjects.size() > 1) { - hash_time_m_it it = mapWatchdogObjects.begin(); - while(it != mapWatchdogObjects.end()) { - LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Checking watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second); - if(it->second < nNow) { - LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Attempting to expire watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second); - object_m_it it2 = mapObjects.find(it->first); - if(it2 != mapObjects.end()) { - LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Expiring watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second); - it2->second.fExpired = true; - if(it2->second.nDeletionTime == 0) { - it2->second.nDeletionTime = nNow; - } - } - if(it->first == nHashWatchdogCurrent) { - nHashWatchdogCurrent = uint256(); - } - mapWatchdogObjects.erase(it++); - } - else { - ++it; - } - } - } - for(size_t i = 0; i < vecDirtyHashes.size(); ++i) { object_m_it it = mapObjects.find(vecDirtyHashes[i]); if(it == mapObjects.end()) { @@ -471,13 +391,12 @@ void CGovernanceManager::UpdateCachesAndClean() ScopedLockBool guard(cs, fRateChecksEnabled, false); - // UPDATE CACHE FOR EACH OBJECT THAT IS FLAGGED DIRTYCACHE=TRUE - - object_m_it it = mapObjects.begin(); - // Clean up any expired or invalid triggers triggerman.CleanAndRemove(); + object_m_it it = mapObjects.begin(); + int64_t nNow = GetAdjustedTime(); + while(it != mapObjects.end()) { CGovernanceObject* pObj = &((*it).second); @@ -499,13 +418,9 @@ void CGovernanceManager::UpdateCachesAndClean() pObj->UpdateSentinelVariables(); } - if(pObj->IsSetCachedDelete() && (nHash == nHashWatchdogCurrent)) { - nHashWatchdogCurrent = uint256(); - } - // IF DELETE=TRUE, THEN CLEAN THE MESS UP! - int64_t nTimeSinceDeletion = GetAdjustedTime() - pObj->GetDeletionTime(); + int64_t nTimeSinceDeletion = nNow - pObj->GetDeletionTime(); LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Checking object for deletion: %s, deletion time = %d, time since deletion = %d, delete flag = %d, expired flag = %d\n", strHash, pObj->GetDeletionTime(), nTimeSinceDeletion, pObj->IsSetCachedDelete(), pObj->IsSetExpired()); @@ -516,32 +431,43 @@ void CGovernanceManager::UpdateCachesAndClean() dnodeman.RemoveGovernanceObject(pObj->GetHash()); // Remove vote references - const object_ref_cache_t::list_t& listItems = mapVoteToObject.GetItemList(); - object_ref_cache_t::list_cit lit = listItems.begin(); + const object_ref_cm_t::list_t& listItems = cmapVoteToObject.GetItemList(); + object_ref_cm_t::list_cit lit = listItems.begin(); while(lit != listItems.end()) { if(lit->value == pObj) { uint256 nKey = lit->key; ++lit; - mapVoteToObject.Erase(nKey); + cmapVoteToObject.Erase(nKey); } else { ++lit; } } - int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing; - int64_t nTimeExpired = pObj->GetCreationTime() + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY; + int64_t nTimeExpired{0}; - if(pObj->GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG) { - mapWatchdogObjects.erase(nHash); - } else if(pObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) { + if(pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { // keep hashes of deleted proposals forever nTimeExpired = std::numeric_limits::max(); + } else { + int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing; + nTimeExpired = pObj->GetCreationTime() + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY; } mapErasedGovernanceObjects.insert(std::make_pair(nHash, nTimeExpired)); mapObjects.erase(it++); } else { + // NOTE: triggers are handled via triggerman + if (pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { + CProposalValidator validator(pObj->GetDataAsHexString()); + if (!validator.Validate()) { + LogPrintf("CGovernanceManager::UpdateCachesAndClean -- set for deletion expired obj %s\n", (*it).first.ToString()); + pObj->fCachedDelete = true; + if (pObj->nDeletionTime == 0) { + pObj->nDeletionTime = nNow; + } + } + } ++it; } } @@ -558,59 +484,58 @@ void CGovernanceManager::UpdateCachesAndClean() LogPrintf("CGovernanceManager::UpdateCachesAndClean -- %s\n", ToString()); } -CGovernanceObject *CGovernanceManager::FindGovernanceObject(const uint256& nHash) +CGovernanceObject* CGovernanceManager::FindGovernanceObject(const uint256& nHash) { LOCK(cs); if(mapObjects.count(nHash)) return &mapObjects[nHash]; - return NULL; + return nullptr; } -std::vector CGovernanceManager::GetMatchingVotes(const uint256& nParentHash) +std::vector CGovernanceManager::GetMatchingVotes(const uint256& nParentHash) const { LOCK(cs); std::vector vecResult; - object_m_it it = mapObjects.find(nParentHash); + object_m_cit it = mapObjects.find(nParentHash); if(it == mapObjects.end()) { return vecResult; } - CGovernanceObject& govobj = it->second; - return govobj.GetVoteFile().GetVotes(); + return it->second.GetVoteFile().GetVotes(); } -std::vector CGovernanceManager::GetCurrentVotes(const uint256& nParentHash, const COutPoint& dnCollateralOutpointFilter) +std::vector CGovernanceManager::GetCurrentVotes(const uint256& nParentHash, const COutPoint& dnCollateralOutpointFilter) const { LOCK(cs); std::vector vecResult; // Find the governance object or short-circuit. - object_m_it it = mapObjects.find(nParentHash); + object_m_cit it = mapObjects.find(nParentHash); if(it == mapObjects.end()) return vecResult; - CGovernanceObject& govobj = it->second; + const CGovernanceObject& govobj = it->second; CDynode dn; std::map mapDynodes; - if(dnCollateralOutpointFilter == COutPoint()) { + if(dnCollateralOutpointFilter.IsNull()) { mapDynodes = dnodeman.GetFullDynodeMap(); } else if (dnodeman.Get(dnCollateralOutpointFilter, dn)) { mapDynodes[dnCollateralOutpointFilter] = dn; } // Loop thru each DN collateral outpoint and get the votes for the `nParentHash` governance object - for (auto& dnpair : mapDynodes) + for (const auto& dnpair : mapDynodes) { // get a vote_rec_t from the govobj vote_rec_t voteRecord; if (!govobj.GetCurrentDNVotes(dnpair.first, voteRecord)) continue; - for (vote_instance_m_it it3 = voteRecord.mapInstances.begin(); it3 != voteRecord.mapInstances.end(); ++it3) { - int signal = (it3->first); - int outcome = ((it3->second).eOutcome); - int64_t nCreationTime = ((it3->second).nCreationTime); + for (const auto& voteInstancePair : voteRecord.mapInstances) { + int signal = voteInstancePair.first; + int outcome = voteInstancePair.second.eOutcome; + int64_t nCreationTime = voteInstancePair.second.nCreationTime; CGovernanceVote vote = CGovernanceVote(dnpair.first, nParentHash, (vote_signal_enum_t)signal, (vote_outcome_enum_t)outcome); vote.SetTime(nCreationTime); @@ -622,30 +547,21 @@ std::vector CGovernanceManager::GetCurrentVotes(const uint256& return vecResult; } -std::vector CGovernanceManager::GetAllNewerThan(int64_t nMoreThanTime) +std::vector CGovernanceManager::GetAllNewerThan(int64_t nMoreThanTime) const { LOCK(cs); - std::vector vGovObjs; + std::vector vGovObjs; - object_m_it it = mapObjects.begin(); - while(it != mapObjects.end()) - { + for (const auto& objPair : mapObjects) { // IF THIS OBJECT IS OLDER THAN TIME, CONTINUE - - if((*it).second.GetCreationTime() < nMoreThanTime) { - ++it; + if(objPair.second.GetCreationTime() < nMoreThanTime) { continue; } // ADD GOVERNANCE OBJECT TO LIST - - CGovernanceObject* pGovObj = &((*it).second); + const CGovernanceObject* pGovObj = &(objPair.second); vGovObjs.push_back(pGovObj); - - // NEXT - - ++it; } return vGovObjs; @@ -698,7 +614,7 @@ bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) break; case MSG_GOVERNANCE_OBJECT_VOTE: { - if(mapVoteToObject.HasKey(inv.hash)) { + if(cmapVoteToObject.HasKey(inv.hash)) { LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest already have governance vote, returning false\n"); return false; } @@ -710,7 +626,7 @@ bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) } - hash_s_t* setHash = NULL; + hash_s_t* setHash = nullptr; switch(inv.type) { case MSG_GOVERNANCE_OBJECT: setHash = &setRequestedObjects; @@ -732,106 +648,119 @@ bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) return true; } -void CGovernanceManager::Sync(CNode* pfrom, const uint256& nProp, const CBloomFilter& filter, CConnman& connman) +void CGovernanceManager::SyncSingleObjAndItsVotes(CNode* pnode, const uint256& nProp, const CBloomFilter& filter, CConnman& connman) { - - /* - This code checks each of the hash maps for all known budget proposals and finalized budget proposals, then checks them against the - budget object to see if they're OK. If all checks pass, we'll send it to the peer. - */ - // do not provide any data until our node is synced - if(fDynodeMode && !dynodeSync.IsSynced()) return; + if(!dynodeSync.IsSynced()) return; - int nObjCount = 0; int nVoteCount = 0; // SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT - LogPrint("gobject", "CGovernanceManager::Sync -- syncing to peer=%d, nProp = %s\n", pfrom->id, nProp.ToString()); + LogPrint("gobject", "CGovernanceManager::%s -- syncing single object to peer=%d, nProp = %s\n", __func__, pnode->id, nProp.ToString()); - { - LOCK2(cs_main, cs); + LOCK2(cs_main, cs); - if(nProp == uint256()) { - // all valid objects, no votes - for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) { - CGovernanceObject& govobj = it->second; - std::string strHash = it->first.ToString(); + // single valid object and its valid votes + object_m_it it = mapObjects.find(nProp); + if(it == mapObjects.end()) { + LogPrint("gobject", "CGovernanceManager::%s -- no matching object for hash %s, peer=%d\n", __func__, nProp.ToString(), pnode->id); + return; + } + CGovernanceObject& govobj = it->second; + std::string strHash = it->first.ToString(); - LogPrint("gobject", "CGovernanceManager::Sync -- attempting to sync govobj: %s, peer=%d\n", strHash, pfrom->id); + LogPrint("gobject", "CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d\n", __func__, strHash, pnode->id); - if(govobj.IsSetCachedDelete() || govobj.IsSetExpired()) { - LogPrintf("CGovernanceManager::Sync -- not syncing deleted/expired govobj: %s, peer=%d\n", - strHash, pfrom->id); - continue; - } + if(govobj.IsSetCachedDelete() || govobj.IsSetExpired()) { + LogPrintf("CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d\n", __func__, + strHash, pnode->id); + return; + } - // Push the inventory budget proposal message over to the other client - LogPrint("gobject", "CGovernanceManager::Sync -- syncing govobj: %s, peer=%d\n", strHash, pfrom->id); - pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, it->first)); - ++nObjCount; - } - } else { - // single valid object and its valid votes - object_m_it it = mapObjects.find(nProp); - if(it == mapObjects.end()) { - LogPrint("gobject", "CGovernanceManager::Sync -- no matching object for hash %s, peer=%d\n", nProp.ToString(), pfrom->id); - return; - } - CGovernanceObject& govobj = it->second; - std::string strHash = it->first.ToString(); + // Push the govobj inventory message over to the other client + LogPrint("gobject", "CGovernanceManager::%s -- syncing govobj: %s, peer=%d\n", __func__, strHash, pnode->id); + pnode->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, it->first)); - LogPrint("gobject", "CGovernanceManager::Sync -- attempting to sync govobj: %s, peer=%d\n", strHash, pfrom->id); + auto fileVotes = govobj.GetVoteFile(); - if(govobj.IsSetCachedDelete() || govobj.IsSetExpired()) { - LogPrintf("CGovernanceManager::Sync -- not syncing deleted/expired govobj: %s, peer=%d\n", - strHash, pfrom->id); - return; - } + for (const auto& vote : fileVotes.GetVotes()) { + uint256 nVoteHash = vote.GetHash(); + if(filter.contains(nVoteHash) || !vote.IsValid(true)) { + continue; + } + pnode->PushInventory(CInv(MSG_GOVERNANCE_OBJECT_VOTE, nVoteHash)); + ++nVoteCount; + } - // Push the inventory budget proposal message over to the other client - LogPrint("gobject", "CGovernanceManager::Sync -- syncing govobj: %s, peer=%d\n", strHash, pfrom->id); - pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, it->first)); - ++nObjCount; + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_GOVOBJ, 1)); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_GOVOBJ_VOTE, nVoteCount)); + LogPrintf("CGovernanceManager::%s -- sent 1 object and %d votes to peer=%d\n", __func__, nVoteCount, pnode->id); +} - std::vector vecVotes = govobj.GetVoteFile().GetVotes(); - for(size_t i = 0; i < vecVotes.size(); ++i) { - if(filter.contains(vecVotes[i].GetHash())) { - continue; - } - if(!vecVotes[i].IsValid(true)) { - continue; - } - pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT_VOTE, vecVotes[i].GetHash())); - ++nVoteCount; - } +void CGovernanceManager::SyncAll(CNode* pnode, CConnman& connman) const +{ + // do not provide any data until our node is synced + if(!dynodeSync.IsSynced()) return; + + if(netfulfilledman.HasFulfilledRequest(pnode->addr, NetMsgType::DNGOVERNANCESYNC)) { + LOCK(cs_main); + // Asking for the whole list multiple times in a short period of time is no good + LogPrint("gobject", "CGovernanceManager::%s -- peer already asked me for the list\n", __func__); + Misbehaving(pnode->GetId(), 20); + return; + } + netfulfilledman.AddFulfilledRequest(pnode->addr, NetMsgType::DNGOVERNANCESYNC); + + int nObjCount = 0; + int nVoteCount = 0; + + // SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT + + LogPrint("gobject", "CGovernanceManager::%s -- syncing all objects to peer=%d\n", __func__, pnode->id); + + LOCK2(cs_main, cs); + + // all valid objects, no votes + for (const auto& objPair : mapObjects) { + uint256 nHash = objPair.first; + const CGovernanceObject& govobj = objPair.second; + std::string strHash = nHash.ToString(); + + LogPrint("gobject", "CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d\n", __func__, strHash, pnode->id); + + if(govobj.IsSetCachedDelete() || govobj.IsSetExpired()) { + LogPrintf("CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d\n", __func__, + strHash, pnode->id); + continue; } + + // Push the inventory budget proposal message over to the other client + LogPrint("gobject", "CGovernanceManager::%s -- syncing govobj: %s, peer=%d\n", __func__, strHash, pnode->id); + pnode->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, nHash)); + ++nObjCount; } - connman.PushMessage(pfrom, NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_GOVOBJ, nObjCount); - connman.PushMessage(pfrom, NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_GOVOBJ_VOTE, nVoteCount); - LogPrintf("CGovernanceManager::Sync -- sent %d objects and %d votes to peer=%d\n", nObjCount, nVoteCount, pfrom->id); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_GOVOBJ, nObjCount)); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, DYNODE_SYNC_GOVOBJ_VOTE, nVoteCount)); + LogPrintf("CGovernanceManager::%s -- sent %d objects and %d votes to peer=%d\n", __func__, nObjCount, nVoteCount, pnode->id); } - void CGovernanceManager::DynodeRateUpdate(const CGovernanceObject& govobj) { - int nObjectType = govobj.GetObjectType(); - if((nObjectType != GOVERNANCE_OBJECT_TRIGGER) && (nObjectType != GOVERNANCE_OBJECT_WATCHDOG)) + if(govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) return; - const CTxIn& vin = govobj.GetDynodeVin(); - txout_m_it it = mapLastDynodeObject.find(vin.prevout); + const COutPoint& dynodeOutpoint = govobj.GetDynodeOutpoint(); + txout_m_it it = mapLastDynodeObject.find(dynodeOutpoint); if(it == mapLastDynodeObject.end()) - it = mapLastDynodeObject.insert(txout_m_t::value_type(vin.prevout, last_object_rec(true))).first; + it = mapLastDynodeObject.insert(txout_m_t::value_type(dynodeOutpoint, last_object_rec(true))).first; int64_t nTimestamp = govobj.GetCreationTime(); - if (GOVERNANCE_OBJECT_TRIGGER == nObjectType) - it->second.triggerBuffer.AddTimestamp(nTimestamp); - else if (GOVERNANCE_OBJECT_WATCHDOG == nObjectType) - it->second.watchdogBuffer.AddTimestamp(nTimestamp); + it->second.triggerBuffer.AddTimestamp(nTimestamp); if (nTimestamp > GetTime() + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME) { // schedule additional relay for the object @@ -861,12 +790,11 @@ bool CGovernanceManager::DynodeRateCheck(const CGovernanceObject& govobj, bool f return true; } - int nObjectType = govobj.GetObjectType(); - if((nObjectType != GOVERNANCE_OBJECT_TRIGGER) && (nObjectType != GOVERNANCE_OBJECT_WATCHDOG)) { + if(govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) { return true; } - const CTxIn& vin = govobj.GetDynodeVin(); + const COutPoint& dynodeOutpoint = govobj.GetDynodeOutpoint(); int64_t nTimestamp = govobj.GetCreationTime(); int64_t nNow = GetAdjustedTime(); int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing; @@ -874,18 +802,18 @@ bool CGovernanceManager::DynodeRateCheck(const CGovernanceObject& govobj, bool f std::string strHash = govobj.GetHash().ToString(); if(nTimestamp < nNow - 2 * nSuperblockCycleSeconds) { - LogPrintf("CGovernanceManager::DynodeRateCheck -- object %s rejected due to too old timestamp, dynode vin = %s, timestamp = %d, current time = %d\n", - strHash, vin.prevout.ToStringShort(), nTimestamp, nNow); + LogPrintf("CGovernanceManager::DynodeRateCheck -- object %s rejected due to too old timestamp, dynode = %s, timestamp = %d, current time = %d\n", + strHash, dynodeOutpoint.ToStringShort(), nTimestamp, nNow); return false; } if(nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION) { - LogPrintf("CGovernanceManager::DynodeRateCheck -- object %s rejected due to too new (future) timestamp, dynode vin = %s, timestamp = %d, current time = %d\n", - strHash, vin.prevout.ToStringShort(), nTimestamp, nNow); + LogPrintf("CGovernanceManager::DynodeRateCheck -- object %s rejected due to too new (future) timestamp, dynode = %s, timestamp = %d, current time = %d\n", + strHash, dynodeOutpoint.ToStringShort(), nTimestamp, nNow); return false; } - txout_m_it it = mapLastDynodeObject.find(vin.prevout); + txout_m_it it = mapLastDynodeObject.find(dynodeOutpoint); if(it == mapLastDynodeObject.end()) return true; @@ -894,64 +822,58 @@ bool CGovernanceManager::DynodeRateCheck(const CGovernanceObject& govobj, bool f return true; } - double dMaxRate = 1.1 / nSuperblockCycleSeconds; - double dRate = 0.0; - CRateCheckBuffer buffer; - switch(nObjectType) { - case GOVERNANCE_OBJECT_TRIGGER: - // Allow 1 trigger per dn per cycle, with a small fudge factor - buffer = it->second.triggerBuffer; - dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds); - break; - case GOVERNANCE_OBJECT_WATCHDOG: - buffer = it->second.watchdogBuffer; - dMaxRate = 2 * 1.1 / 3600.; - break; - default: - break; - } + // Allow 1 trigger per dn per cycle, with a small fudge factor + double dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds); + + // Temporary copy to check rate after new timestamp is added + CRateCheckBuffer buffer = it->second.triggerBuffer; buffer.AddTimestamp(nTimestamp); - dRate = buffer.GetRate(); + double dRate = buffer.GetRate(); - bool fRateOK = ( dRate < dMaxRate ); + if(dRate < dMaxRate) { + return true; + } - if(!fRateOK) - { - LogPrintf("CGovernanceManager::DynodeRateCheck -- Rate too high: object hash = %s, dynode vin = %s, object timestamp = %d, rate = %f, max rate = %f\n", - strHash, vin.prevout.ToStringShort(), nTimestamp, dRate, dMaxRate); + LogPrintf("CGovernanceManager::DynodeRateCheck -- Rate too high: object hash = %s, dynode = %s, object timestamp = %d, rate = %f, max rate = %f\n", + strHash, dynodeOutpoint.ToStringShort(), nTimestamp, dRate, dMaxRate); - if (fUpdateFailStatus) - it->second.fStatusOK = false; - } + if (fUpdateFailStatus) + it->second.fStatusOK = false; - return fRateOK; + return false; } bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) { ENTER_CRITICAL_SECTION(cs); uint256 nHashVote = vote.GetHash(); - if(mapInvalidVotes.HasKey(nHashVote)) { + uint256 nHashGovobj = vote.GetParentHash(); + + if(cmapVoteToObject.HasKey(nHashVote)) { + LogPrint("gobject", "CGovernanceObject::ProcessVote -- skipping known valid vote %s for object %s\n", nHashVote.ToString(), nHashGovobj.ToString()); + LEAVE_CRITICAL_SECTION(cs); + return false; + } + + if(cmapInvalidVotes.HasKey(nHashVote)) { std::ostringstream ostr; ostr << "CGovernanceManager::ProcessVote -- Old invalid vote " << ", DN outpoint = " << vote.GetDynodeOutpoint().ToStringShort() - << ", governance object hash = " << vote.GetParentHash().ToString(); + << ", governance object hash = " << nHashGovobj.ToString(); LogPrintf("%s\n", ostr.str()); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20); LEAVE_CRITICAL_SECTION(cs); return false; } - uint256 nHashGovobj = vote.GetParentHash(); object_m_it it = mapObjects.find(nHashGovobj); if(it == mapObjects.end()) { std::ostringstream ostr; - ostr << "CGovernanceManager::ProcessVote -- Unknown parent object " - << ", DN outpoint = " << vote.GetDynodeOutpoint().ToStringShort() - << ", governance object hash = " << vote.GetParentHash().ToString(); + ostr << "CGovernanceManager::ProcessVote -- Unknown parent object " << nHashGovobj.ToString() + << ", DN outpoint = " << vote.GetDynodeOutpoint().ToStringShort(); exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_WARNING); - if(mapOrphanVotes.Insert(nHashGovobj, vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME))) { + if(cmmapOrphanVotes.Insert(nHashGovobj, vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME))) { LEAVE_CRITICAL_SECTION(cs); RequestGovernanceObject(pfrom, nHashGovobj, connman); LogPrintf("%s\n", ostr.str()); @@ -971,7 +893,7 @@ bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, return false; } - bool fOk = govobj.ProcessVote(pfrom, vote, exception, connman); + bool fOk = govobj.ProcessVote(pfrom, vote, exception, connman) && cmapVoteToObject.Insert(nHashVote, &govobj); LEAVE_CRITICAL_SECTION(cs); return fOk; } @@ -982,8 +904,8 @@ void CGovernanceManager::CheckDynodeOrphanVotes(CConnman& connman) ScopedLockBool guard(cs, fRateChecksEnabled, false); - for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) { - it->second.CheckOrphanVotes(connman); + for (auto& objPair : mapObjects) { + objPair.second.CheckOrphanVotes(connman); } } @@ -1014,7 +936,7 @@ void CGovernanceManager::CheckDynodeOrphanObjects(CConnman& connman) Misbehaving(pair.second.idFrom, 20); } - auto it_count = mapDynodeOrphanCounter.find(govobj.GetDynodeVin().prevout); + auto it_count = mapDynodeOrphanCounter.find(govobj.GetDynodeOutpoint()); if(--it_count->second == 0) mapDynodeOrphanCounter.erase(it_count); @@ -1034,8 +956,7 @@ void CGovernanceManager::CheckPostponedObjects(CConnman& connman) const uint256& nHash = it->first; CGovernanceObject& govobj = it->second; - assert(govobj.GetObjectType() != GOVERNANCE_OBJECT_WATCHDOG && - govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER); + assert(govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER); std::string strError; bool fMissingConfirmations; @@ -1057,7 +978,7 @@ void CGovernanceManager::CheckPostponedObjects(CConnman& connman) } - // Perform additional relays for triggers/watchdogs + // Perform additional relays for triggers int64_t nNow = GetAdjustedTime(); int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing; @@ -1099,8 +1020,10 @@ void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nH LogPrint("gobject", "CGovernanceObject::RequestGovernanceObject -- hash = %s (peer=%d)\n", nHash.ToString(), pfrom->GetId()); + CNetMsgMaker msgMaker(pfrom->GetSendVersion()); + if(pfrom->nVersion < GOVERNANCE_FILTER_PROTO_VERSION) { - connman.PushMessage(pfrom, NetMsgType::DNGOVERNANCESYNC, nHash); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DNGOVERNANCESYNC, nHash)); return; } @@ -1123,7 +1046,7 @@ void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nH } LogPrint("gobject", "CGovernanceManager::RequestGovernanceObject -- nHash %s nVoteCount %d peer=%d\n", nHash.ToString(), nVoteCount, pfrom->id); - connman.PushMessage(pfrom, NetMsgType::DNGOVERNANCESYNC, nHash, filter); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DNGOVERNANCESYNC, nHash, filter)); } int CGovernanceManager::RequestGovernanceObjectVotes(CNode* pnode, CConnman& connman) @@ -1163,22 +1086,25 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& if(mapObjects.empty()) return -2; - for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) { - if(mapAskedRecently.count(it->first)) { - std::map::iterator it1 = mapAskedRecently[it->first].begin(); - while(it1 != mapAskedRecently[it->first].end()) { - if(it1->second < nNow) { - mapAskedRecently[it->first].erase(it1++); + for (const auto& objPair : mapObjects) { + uint256 nHash = objPair.first; + if(mapAskedRecently.count(nHash)) { + auto it = mapAskedRecently[nHash].begin(); + while(it != mapAskedRecently[nHash].end()) { + if(it->second < nNow) { + mapAskedRecently[nHash].erase(it++); } else { - ++it1; + ++it; } } - if(mapAskedRecently[it->first].size() >= nPeersPerHashMax) continue; + if(mapAskedRecently[nHash].size() >= nPeersPerHashMax) continue; } - if(it->second.nObjectType == GOVERNANCE_OBJECT_TRIGGER) { - vpGovObjsTriggersTmp.push_back(&(it->second)); + + auto govObj = objPair.second; + if(govObj.nObjectType == GOVERNANCE_OBJECT_TRIGGER) { + vpGovObjsTriggersTmp.push_back(&govObj); } else { - vpGovObjsTmp.push_back(&(it->second)); + vpGovObjsTmp.push_back(&govObj); } } } @@ -1202,7 +1128,7 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& nHashGovobj = vpGovObjsTmp.back()->GetHash(); } bool fAsked = false; - BOOST_FOREACH(CNode* pnode, vNodesCopy) { + for (const auto& pnode : vNodesCopy) { // Only use regular peers, don't try to ask from outbound "dynode" connections - // they stay connected for a short period of time and it's possible that we won't get everything we should. // Only use outbound connections - inbound connection could be a "dynode" connection @@ -1262,12 +1188,14 @@ bool CGovernanceManager::AcceptMessage(const uint256& nHash, hash_s_t& setHash) void CGovernanceManager::RebuildIndexes() { - mapVoteToObject.Clear(); - for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) { - CGovernanceObject& govobj = it->second; + LOCK(cs); + + cmapVoteToObject.Clear(); + for (auto& objPair : mapObjects) { + CGovernanceObject& govobj = objPair.second; std::vector vecVotes = govobj.GetVoteFile().GetVotes(); for(size_t i = 0; i < vecVotes.size(); ++i) { - mapVoteToObject.Insert(vecVotes[i].GetHash(), &govobj); + cmapVoteToObject.Insert(vecVotes[i].GetHash(), &govobj); } } } @@ -1276,14 +1204,19 @@ void CGovernanceManager::AddCachedTriggers() { LOCK(cs); - for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) { - CGovernanceObject& govobj = it->second; + for (auto& objpair : mapObjects) { + CGovernanceObject& govobj = objpair.second; if(govobj.nObjectType != GOVERNANCE_OBJECT_TRIGGER) { continue; } - triggerman.AddNewTrigger(govobj.GetHash()); + if (!triggerman.AddNewTrigger(govobj.GetHash())) { + govobj.fCachedDelete = true; + if (govobj.nDeletionTime == 0) { + govobj.nDeletionTime = GetAdjustedTime(); + } + } } } @@ -1304,33 +1237,58 @@ std::string CGovernanceManager::ToString() const int nProposalCount = 0; int nTriggerCount = 0; - int nWatchdogCount = 0; int nOtherCount = 0; - object_m_cit it = mapObjects.begin(); - - while(it != mapObjects.end()) { - switch(it->second.GetObjectType()) { + for (const auto& objPair : mapObjects) { + switch(objPair.second.GetObjectType()) { case GOVERNANCE_OBJECT_PROPOSAL: nProposalCount++; break; case GOVERNANCE_OBJECT_TRIGGER: nTriggerCount++; break; - case GOVERNANCE_OBJECT_WATCHDOG: - nWatchdogCount++; - break; default: nOtherCount++; break; } - ++it; } - return strprintf("Governance Objects: %d (Proposals: %d, Triggers: %d, Watchdogs: %d/%d, Other: %d; Erased: %d), Votes: %d", + return strprintf("Governance Objects: %d (Proposals: %d, Triggers: %d, Other: %d; Erased: %d), Votes: %d", (int)mapObjects.size(), - nProposalCount, nTriggerCount, nWatchdogCount, mapWatchdogObjects.size(), nOtherCount, (int)mapErasedGovernanceObjects.size(), - (int)mapVoteToObject.GetSize()); + nProposalCount, nTriggerCount, nOtherCount, (int)mapErasedGovernanceObjects.size(), + (int)cmapVoteToObject.GetSize()); +} + +UniValue CGovernanceManager::ToJson() const +{ + LOCK(cs); + + int nProposalCount = 0; + int nTriggerCount = 0; + int nOtherCount = 0; + + for (const auto& objpair : mapObjects) { + switch(objpair.second.GetObjectType()) { + case GOVERNANCE_OBJECT_PROPOSAL: + nProposalCount++; + break; + case GOVERNANCE_OBJECT_TRIGGER: + nTriggerCount++; + break; + default: + nOtherCount++; + break; + } + } + + UniValue jsonObj(UniValue::VOBJ); + jsonObj.push_back(Pair("objects_total", (int)mapObjects.size())); + jsonObj.push_back(Pair("proposals", nProposalCount)); + jsonObj.push_back(Pair("triggers", nTriggerCount)); + jsonObj.push_back(Pair("other", nOtherCount)); + jsonObj.push_back(Pair("erased", (int)mapErasedGovernanceObjects.size())); + jsonObj.push_back(Pair("votes", (int)cmapVoteToObject.GetSize())); + return jsonObj; } void CGovernanceManager::UpdatedBlockTip(const CBlockIndex *pindex, CConnman& connman) @@ -1348,17 +1306,19 @@ void CGovernanceManager::UpdatedBlockTip(const CBlockIndex *pindex, CConnman& co LogPrint("gobject", "CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight); CheckPostponedObjects(connman); + + CSuperblockManager::ExecuteBestSuperblock(pindex->nHeight); } void CGovernanceManager::RequestOrphanObjects(CConnman& connman) { - std::vector vNodesCopy = connman.CopyNodeVector(); + std::vector vNodesCopy = connman.CopyNodeVector(CConnman::FullyConnectedOnly); std::vector vecHashesFiltered; { std::vector vecHashes; LOCK(cs); - mapOrphanVotes.GetKeys(vecHashes); + cmmapOrphanVotes.GetKeys(vecHashes); for(size_t i = 0; i < vecHashes.size(); ++i) { const uint256& nHash = vecHashes[i]; if(mapObjects.find(nHash) == mapObjects.end()) { @@ -1385,17 +1345,17 @@ void CGovernanceManager::RequestOrphanObjects(CConnman& connman) void CGovernanceManager::CleanOrphanObjects() { LOCK(cs); - const vote_mcache_t::list_t& items = mapOrphanVotes.GetItemList(); + const vote_cmm_t::list_t& items = cmmapOrphanVotes.GetItemList(); int64_t nNow = GetAdjustedTime(); - vote_mcache_t::list_cit it = items.begin(); + vote_cmm_t::list_cit it = items.begin(); while(it != items.end()) { - vote_mcache_t::list_cit prevIt = it; + vote_cmm_t::list_cit prevIt = it; ++it; const vote_time_pair_t& pairVote = prevIt->value; if(pairVote.second < nNow) { - mapOrphanVotes.Erase(prevIt->key, prevIt->value); + cmmapOrphanVotes.Erase(prevIt->key, prevIt->value); } } } \ No newline at end of file diff --git a/src/governance.h b/src/governance.h index 474459f971..9a747f3a1e 100644 --- a/src/governance.h +++ b/src/governance.h @@ -20,6 +20,8 @@ #include "timedata.h" #include "util.h" +#include + class CGovernanceManager; class CGovernanceTriggerManager; class CGovernanceObject; @@ -38,7 +40,8 @@ typedef std::pair object_info_pair_t; static const int RATE_BUFFER_SIZE = 5; -class CRateCheckBuffer { +class CRateCheckBuffer +{ private: std::vector vecTimestamps; @@ -153,7 +156,6 @@ class CGovernanceManager struct last_object_rec { last_object_rec(bool fStatusOKIn = true) : triggerBuffer(), - watchdogBuffer(), fStatusOK(fStatusOKIn) {} @@ -163,12 +165,10 @@ class CGovernanceManager inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(triggerBuffer); - READWRITE(watchdogBuffer); READWRITE(fStatusOK); } CRateCheckBuffer triggerBuffer; - CRateCheckBuffer watchdogBuffer; bool fStatusOK; }; @@ -179,7 +179,7 @@ class CGovernanceManager typedef object_m_t::const_iterator object_m_cit; - typedef CacheMap object_ref_cache_t; + typedef CacheMap object_ref_cm_t; typedef std::map vote_m_t; @@ -187,9 +187,9 @@ class CGovernanceManager typedef vote_m_t::const_iterator vote_m_cit; - typedef CacheMap vote_cache_t; + typedef CacheMap vote_cm_t; - typedef CacheMultiMap vote_mcache_t; + typedef CacheMultiMap vote_cmm_t; typedef object_m_t::size_type size_type; @@ -246,17 +246,11 @@ class CGovernanceManager object_m_t mapPostponedObjects; hash_s_t setAdditionalRelayObjects; - hash_time_m_t mapWatchdogObjects; - - uint256 nHashWatchdogCurrent; - - int64_t nTimeWatchdogCurrent; + object_ref_cm_t cmapVoteToObject; - object_ref_cache_t mapVoteToObject; + vote_cm_t cmapInvalidVotes; - vote_cache_t mapInvalidVotes; - - vote_mcache_t mapOrphanVotes; + vote_cmm_t cmmapOrphanVotes; txout_m_t mapLastDynodeObject; @@ -294,28 +288,27 @@ class CGovernanceManager virtual ~CGovernanceManager() {} /** - * This is called by AlreadyHave in main.cpp as part of the inventory + * This is called by AlreadyHave in net_processing.cpp as part of the inventory * retrieval process. Returns true if we want to retrieve the object, otherwise * false. (Note logic is inverted in AlreadyHave). */ bool ConfirmInventoryRequest(const CInv& inv); - void Sync(CNode* node, const uint256& nProp, const CBloomFilter& filter, CConnman& connman); + void SyncSingleObjAndItsVotes(CNode* pnode, const uint256& nProp, const CBloomFilter& filter, CConnman& connman); + void SyncAll(CNode* pnode, CConnman& connman) const; - void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman); + void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void DoMaintenance(CConnman& connman); - CGovernanceObject *FindGovernanceObject(const uint256& nHash); - - std::vector GetMatchingVotes(const uint256& nParentHash); - std::vector GetCurrentVotes(const uint256& nParentHash, const COutPoint& dnCollateralOutpointFilter); - std::vector GetAllNewerThan(int64_t nMoreThanTime); + CGovernanceObject* FindGovernanceObject(const uint256& nHash); - bool IsBudgetPaymentBlock(int nBlockHeight); - void AddGovernanceObject(CGovernanceObject& govobj, CConnman& connman, CNode* pfrom = NULL); + // These commands are only used in RPC + std::vector GetMatchingVotes(const uint256& nParentHash) const; + std::vector GetCurrentVotes(const uint256& nParentHash, const COutPoint& dnCollateralOutpointFilter) const; + std::vector GetAllNewerThan(int64_t nMoreThanTime) const; - std::string GetRequiredPaymentsString(int nBlockHeight); + void AddGovernanceObject(CGovernanceObject& govobj, CConnman& connman, CNode* pfrom = nullptr); void UpdateCachesAndClean(); @@ -328,16 +321,14 @@ class CGovernanceManager LogPrint("gobject", "Governance object manager was cleared\n"); mapObjects.clear(); mapErasedGovernanceObjects.clear(); - mapWatchdogObjects.clear(); - nHashWatchdogCurrent = uint256(); - nTimeWatchdogCurrent = 0; - mapVoteToObject.Clear(); - mapInvalidVotes.Clear(); - mapOrphanVotes.Clear(); + cmapVoteToObject.Clear(); + cmapInvalidVotes.Clear(); + cmmapOrphanVotes.Clear(); mapLastDynodeObject.clear(); } std::string ToString() const; + UniValue ToJson() const; ADD_SERIALIZE_METHODS; @@ -354,12 +345,9 @@ class CGovernanceManager } READWRITE(mapErasedGovernanceObjects); - READWRITE(mapInvalidVotes); - READWRITE(mapOrphanVotes); + READWRITE(cmapInvalidVotes); + READWRITE(cmmapOrphanVotes); READWRITE(mapObjects); - READWRITE(mapWatchdogObjects); - READWRITE(nHashWatchdogCurrent); - READWRITE(nTimeWatchdogCurrent); READWRITE(mapLastDynodeObject); if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) { Clear(); @@ -368,21 +356,21 @@ class CGovernanceManager } void UpdatedBlockTip(const CBlockIndex *pindex, CConnman& connman); - int64_t GetLastDiffTime() { return nTimeLastDiff; } + int64_t GetLastDiffTime() const { return nTimeLastDiff; } void UpdateLastDiffTime(int64_t nTimeIn) { nTimeLastDiff = nTimeIn; } - int GetCachedBlockHeight() { return nCachedBlockHeight; } + int GetCachedBlockHeight() const { return nCachedBlockHeight; } // Accessors for thread-safe access to maps - bool HaveObjectForHash(uint256 nHash); + bool HaveObjectForHash(const uint256& nHash) const; - bool HaveVoteForHash(uint256 nHash); + bool HaveVoteForHash(const uint256& nHash) const; int GetVoteCount() const; - bool SerializeObjectForHash(uint256 nHash, CDataStream& ss); + bool SerializeObjectForHash(const uint256& nHash, CDataStream& ss) const; - bool SerializeVoteForHash(uint256 nHash, CDataStream& ss); + bool SerializeVoteForHash(const uint256& nHash, CDataStream& ss) const; void AddPostponedObject(const CGovernanceObject& govobj) { @@ -390,9 +378,9 @@ class CGovernanceManager mapPostponedObjects.insert(std::make_pair(govobj.GetHash(), govobj)); } - void AddSeenGovernanceObject(uint256 nHash, int status); + void AddSeenGovernanceObject(const uint256& nHash, int status); - void AddSeenVote(uint256 nHash, int status); + void AddSeenVote(const uint256& nHash, int status); void DynodeRateUpdate(const CGovernanceObject& govobj); @@ -401,7 +389,7 @@ class CGovernanceManager bool DynodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus, bool fForce, bool& fRateCheckBypassed); bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) { - bool fOK = ProcessVote(NULL, vote, exception, connman); + bool fOK = ProcessVote(nullptr, vote, exception, connman); if(fOK) { vote.Relay(connman); } @@ -429,12 +417,12 @@ class CGovernanceManager void AddInvalidVote(const CGovernanceVote& vote) { - mapInvalidVotes.Insert(vote.GetHash(), vote); + cmapInvalidVotes.Insert(vote.GetHash(), vote); } void AddOrphanVote(const CGovernanceVote& vote) { - mapOrphanVotes.Insert(vote.GetHash(), vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME)); + cmmapOrphanVotes.Insert(vote.GetHash(), vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME)); } bool ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman); @@ -453,8 +441,6 @@ class CGovernanceManager void AddCachedTriggers(); - bool UpdateCurrentWatchdog(CGovernanceObject& watchdogNew); - void RequestOrphanObjects(CConnman& connman); void CleanOrphanObjects(); diff --git a/src/init.cpp b/src/init.cpp index dd819a7380..aefd759a4e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -245,15 +245,28 @@ void PrepareShutdown() peerLogic.reset(); g_connman.reset(); - // STORE DATA CACHES INTO SERIALIZED DAT FILES - CFlatDB flatdb1("dncache.dat", "magicDynodeCache"); - flatdb1.Dump(dnodeman); - CFlatDB flatdb2("dnpayments.dat", "magicDynodePaymentsCache"); - flatdb2.Dump(dnpayments); - CFlatDB flatdb3("governance.dat", "magicGovernanceCache"); - flatdb3.Dump(governance); - CFlatDB flatdb4("netfulfilled.dat", "magicFulfilledCache"); - flatdb4.Dump(netfulfilledman); + if (!fLiteMode) { +#ifdef ENABLE_WALLET + // Stop PrivateSend, release keys + privateSendClient.fEnablePrivateSend = false; + privateSendClient.ResetPool(); +#endif + + // STORE DATA CACHES INTO SERIALIZED DAT FILES + CFlatDB flatdb1("dncache.dat", "magicDynodeCache"); + flatdb1.Dump(dnodeman); + CFlatDB flatdb2("dnpayments.dat", "magicDynodePaymentsCache"); + flatdb2.Dump(dnpayments); + CFlatDB flatdb3("governance.dat", "magicGovernanceCache"); + flatdb3.Dump(governance); + CFlatDB flatdb4("netfulfilled.dat", "magicFulfilledCache"); + flatdb4.Dump(netfulfilledman); + if(fEnableInstantSend) + { + CFlatDB flatdb5("instantsend.dat", "magicInstantSendCache"); + flatdb5.Dump(instantsend); + } + } UnregisterNodeSignals(GetNodeSignals()); if (fDumpMempoolLater) @@ -364,8 +377,15 @@ bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) { return true; } +void OnRPCStarted() +{ + uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange); +} + void OnRPCStopped() { + uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange); + RPCNotifyBlockChange(false, nullptr); cvBlockChange.notify_all(); LogPrint("rpc", "RPC stopped.\n"); } @@ -414,9 +434,9 @@ std::string HelpMessage(HelpMessageMode mode) #ifndef WIN32 strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), DYNAMIC_PID_FILENAME)); #endif - strUsage += HelpMessageOpt("-prune=", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. " + strUsage += HelpMessageOpt("-prune=", strprintf(_("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " - "(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); + "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); strUsage += HelpMessageOpt("-reindex-chainstate", _("Rebuild chain state from the currently indexed blocks")); strUsage += HelpMessageOpt("-reindex", _("Rebuild chain state and block index from the blk*.dat files on disk")); #ifndef WIN32 @@ -430,6 +450,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Connection options:")); strUsage += HelpMessageOpt("-addnode=", _("Add a node to connect to and attempt to keep the connection open")); + strUsage += HelpMessageOpt("-allowprivatenet", strprintf(_("Allow RFC1918 addresses to be relayed and connected to (default: %u)"), DEFAULT_ALLOWPRIVATENET)); strUsage += HelpMessageOpt("-banscore=", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD)); strUsage += HelpMessageOpt("-bantime=", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME)); strUsage += HelpMessageOpt("-bind=", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6")); @@ -443,13 +464,13 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION)); strUsage += HelpMessageOpt("-maxconnections=", strprintf(_("Maintain at most connections to peers (temporary service connections excluded) (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); strUsage += HelpMessageOpt("-maxreceivebuffer=", strprintf(_("Maximum per-connection receive buffer, *1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER)); - strUsage += HelpMessageOpt("-maxsenFdbuffer=", strprintf(_("Maximum per-connection send buffer, *1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER)); + strUsage += HelpMessageOpt("-maxsendbuffer=", strprintf(_("Maximum per-connection send buffer, *1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER)); strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(_("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)"), DEFAULT_MAX_TIME_ADJUSTMENT)); strUsage += HelpMessageOpt("-onion=", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); strUsage += HelpMessageOpt("-onlynet=", _("Only connect to nodes in network (ipv4, ipv6 or onion)")); strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG)); strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS)); - strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), DEFAULT_P2P_PORT, DEFAULT_P2P_PORT + 100)); + strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); strUsage += HelpMessageOpt("-seednode=", _("Connect to a node to retrieve peer addresses, and disconnect")); @@ -481,6 +502,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-zmqpubhashblock=
", _("Enable publish hash block in
")); strUsage += HelpMessageOpt("-zmqpubhashtx=
", _("Enable publish hash transaction in
")); strUsage += HelpMessageOpt("-zmqpubhashtxlock=
", _("Enable publish hash transaction (locked via InstantSend) in
")); + strUsage += HelpMessageOpt("-zmqpubhashgovernancevote=
", _("Enable publish hash of governance votes in
")); + strUsage += HelpMessageOpt("-zmqpubhashgovernanceobject=
", _("Enable publish hash of governance objects (like proposals) in
")); strUsage += HelpMessageOpt("-zmqpubrawblock=
", _("Enable publish raw block in
")); strUsage += HelpMessageOpt("-zmqpubrawtx=
", _("Enable publish raw transaction in
")); strUsage += HelpMessageOpt("-zmqpubrawtxlock=
", _("Enable publish raw transaction (locked via InstantSend) in
")); @@ -490,6 +513,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-uacomment=", _("Append comment to the user agent string")); if (showDebug) { + strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); + strUsage += HelpMessageOpt("-checklevel=", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL)); strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); strUsage += HelpMessageOpt("-checkmempool=", strprintf("Run checks every transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED)); @@ -503,27 +528,17 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitdescendantcount=", strprintf("Do not accept transactions if any ancestor would have or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT)); strUsage += HelpMessageOpt("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); } - std::string debugCategories1 = "addrman, alert, bench, coindb, db, http, leveldb, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq, Dynamic "; // Don't translate these and qt below - std::string debugCategories2 = "gobject, instantsend, keepass, dynode, dnpayments, dnsync, privatesend, spork"; // Don't translate these and qt below - std::string debugCategories3 = ""; // Don't translate these and qt below - - if (mode == HMM_DYNAMIC_QT) - { - debugCategories3 = ", qt"; // Don't translate this - strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional). If is not supplied or if = 1, output all debugging information. can be: %u (or specifically: %u)%u."), 0, debugCategories1, debugCategories2, debugCategories3)); - } + std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, leveldb, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq, " + "dynamic (or specifically: gobject, instantsend, keepass, dynode, dnpayments, dnsync, privatesend, spork)"; // Don't translate these and qt below + if (mode == HMM_DYNAMIC_QT) + debugCategories += ", qt"; + strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + + _("If is not supplied or if = 1, output all debugging information.") + _(" can be:") + " " + debugCategories + "."); if (showDebug) - { strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0"); - strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), DEFAULT_GENERATE)); - strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS_CPU)); -#if ENABLE_GPU - strUsage += HelpMessageOpt("-genproclimit-gpu=", strprintf(_("Set the number of threads per GPU for coin generation if enabled (default: %d)"), DEFAULT_GENERATE_THREADS_GPU)); -#endif strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)")); strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), DEFAULT_LOGIPS)); strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), DEFAULT_LOGTIMESTAMPS)); - } if (showDebug) { strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS)); @@ -532,6 +547,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitfreerelay=", strprintf("Continuously rate-limit free transactions to *1000 bytes per minute (default: %u)", DEFAULT_LIMITFREERELAY)); strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", DEFAULT_RELAYPRIORITY)); strUsage += HelpMessageOpt("-maxsigcachesize=", strprintf("Limit size of signature cache to MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE)); + strUsage += HelpMessageOpt("-maxtipage=", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); } strUsage += HelpMessageOpt("-minrelaytxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE))); @@ -546,6 +562,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)")); AppendParamsHelpMessages(strUsage, showDebug); strUsage += HelpMessageOpt("-litemode=", strprintf(_("Disable all Dynamic specific functionality (Dynodes, PrivateSend, InstantSend, Governance) (0-1, default: %u)"), 0)); + strUsage += HelpMessageOpt("-sporkaddr=", strprintf(_("Override spork address. Only useful for regtest and devnet. Using this on mainnet or testnet will ban you."))); strUsage += HelpMessageGroup(_("Dynode options:")); strUsage += HelpMessageOpt("-dynode=", strprintf(_("Enable the client to act as a Dynode (0-1, default: %u)"), 0)); @@ -559,7 +576,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-privatesendmultisession=", strprintf(_("Enable multiple PrivateSend mixing sessions per block, experimental (0-1, default: %u)"), DEFAULT_PRIVATESEND_MULTISESSION)); strUsage += HelpMessageOpt("-privatesendrounds=", strprintf(_("Use N separate Dynodes for each denominated input to mix funds (2-16, default: %u)"), DEFAULT_PRIVATESEND_ROUNDS)); strUsage += HelpMessageOpt("-privatesendamount=", strprintf(_("Keep N DYN anonymized (default: %u)"), DEFAULT_PRIVATESEND_AMOUNT)); - strUsage += HelpMessageOpt("-liquidityprovider=", strprintf(_("Provide liquidity to PrivateSend by infrequently mixing coins on a continual basis (0-100, default: %u, 1=very frequent, high fees, 100=very infrequent, low fees)"), DEFAULT_PRIVATESEND_LIQUIDITY)); + strUsage += HelpMessageOpt("-liquidityprovider=", strprintf(_("Provide liquidity to PrivateSend by infrequently mixing coins on a continual basis (%u-%u, default: %u, 1=very frequent, high fees, %u=very infrequent, low fees)"), + MIN_PRIVATESEND_LIQUIDITY, MAX_PRIVATESEND_LIQUIDITY, DEFAULT_PRIVATESEND_LIQUIDITY, MAX_PRIVATESEND_LIQUIDITY)); #endif // ENABLE_WALLET strUsage += HelpMessageGroup(_("InstantSend options:")); @@ -569,17 +587,20 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Node relay options:")); - if (showDebug) + if (showDebug) { strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard())); + strUsage += HelpMessageOpt("-incrementalrelayfee=", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE))); + strUsage += HelpMessageOpt("-dustrelayfee=", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE))); + } strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(_("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT)); strUsage += HelpMessageGroup(_("Block creation options:")); - strUsage += HelpMessageOpt("-blockminsize=", strprintf(_("Set minimum block size in bytes (default: %u)"), DEFAULT_BLOCK_MIN_SIZE)); strUsage += HelpMessageOpt("-blockmaxsize=", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); strUsage += HelpMessageOpt("-blockprioritysize=", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE)); + strUsage += HelpMessageOpt("-blockmintxfee=", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE))); if (showDebug) strUsage += HelpMessageOpt("-blockversion=", "Override block version to test forking scenarios"); @@ -590,7 +611,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-rpccookiefile=", _("Location of the auth cookie (default: data dir)")); strUsage += HelpMessageOpt("-rpcuser=", _("Username for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcpassword=", _("Password for JSON-RPC connections")); - strUsage += HelpMessageOpt("-rpcauth=", _("Username and hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcuser. This option can be specified multiple times")); + strUsage += HelpMessageOpt("-rpcauth=", _("Username and hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=/rpcpassword= pair of arguments. This option can be specified multiple times")); strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Listen for JSON-RPC connections on (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); strUsage += HelpMessageOpt("-rpcallowip=", _("Allow JSON-RPC connections from specified source. Valid for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times")); strUsage += HelpMessageOpt("-rpcthreads=", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS)); @@ -666,15 +687,14 @@ struct CImportingNow // works correctly. void CleanupBlockRevFiles() { - using namespace boost::filesystem; - std::map mapBlockFiles; + std::map mapBlockFiles; // Glob all blk?????.dat and rev?????.dat files from the blocks directory. // Remove the rev files immediately and insert the blk file paths into an // ordered map keyed by block file index. LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n"); - path blocksdir = GetDataDir() / "blocks"; - for (directory_iterator it(blocksdir); it != directory_iterator(); it++) { + boost::filesystem::path blocksdir = GetDataDir() / "blocks"; + for (boost::filesystem::directory_iterator it(blocksdir); it != boost::filesystem::directory_iterator(); it++) { if (is_regular_file(*it) && it->path().filename().string().length() == 12 && it->path().filename().string().substr(8,4) == ".dat") @@ -691,7 +711,7 @@ void CleanupBlockRevFiles() // keeping a separate counter. Once we hit a gap (or if 0 doesn't exist) // start removing block files. int nContigCounter = 0; - BOOST_FOREACH(const PAIRTYPE(std::string, path)& item, mapBlockFiles) { + BOOST_FOREACH(const PAIRTYPE(std::string, boost::filesystem::path)& item, mapBlockFiles) { if (atoi(item.first) == nContigCounter) { nContigCounter++; continue; @@ -788,6 +808,7 @@ bool InitSanityCheck(void) bool AppInitServers(boost::thread_group& threadGroup) { + RPCServer::OnStarted(&OnRPCStarted); RPCServer::OnStopped(&OnRPCStopped); RPCServer::OnPreCommand(&OnRPCPreCommand); if (!InitHTTPServer()) @@ -865,6 +886,12 @@ void InitParameterInteraction() LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__); } + // disable whitelistrelay in blocksonly mode + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { + if (SoftSetBoolArg("-whitelistrelay", false)) + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__); + } + // disable whitelistrelay in blocksonly mode if (GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { if (SoftSetBoolArg("-whitelistrelay", true)) @@ -895,6 +922,7 @@ void InitParameterInteraction() LogPrintf("%s: parameter interaction: can't use -hdseed and -mnemonic/-mnemonicpassphrase together, will prefer -seed\n", __func__); } #endif // ENABLE_WALLET + // Make sure additional indexes are recalculated correctly in VerifyDB // (we must reconnect blocks whenever we disconnect them for these indexes to work) bool fAdditionalIndexes = @@ -1019,6 +1047,8 @@ bool AppInitParameterInteraction() return InitError(_("Prune mode is incompatible with -txindex.")); } + fAllowPrivateNet = GetBoolArg("-allowprivatenet", DEFAULT_ALLOWPRIVATENET); + // Make sure enough file descriptors are available int nBind = std::max( (mapMultiArgs.count("-bind") ? mapMultiArgs.at("-bind").size() : 0) + @@ -1027,11 +1057,11 @@ bool AppInitParameterInteraction() nMaxConnections = std::max(nUserMaxConnections, 0); // Trim requested connection counts, to fit into system limitations - nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); - nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); + nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS)), 0); + nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS); if (nFD < MIN_CORE_FILEDESCRIPTORS) return InitError(_("Not enough file descriptors available.")); - nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections); + nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections); if (nMaxConnections < nUserMaxConnections) InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); @@ -1062,6 +1092,9 @@ bool AppInitParameterInteraction() if (GetBoolArg("-whitelistalwaysrelay", false)) InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.")); + if (IsArgSet("-blockminsize")) + InitWarning("Unsupported argument -blockminsize ignored."); + // Checkmempool and checkblockindex default to true in regtest mode int ratio = std::min(std::max(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); if (ratio != 0) { @@ -1070,11 +1103,26 @@ bool AppInitParameterInteraction() fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); + hashAssumeValid = uint256S(GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex())); + if (!hashAssumeValid.IsNull()) + LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex()); + else + LogPrintf("Validating signatures for all blocks.\n"); + // mempool limits int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0))); + // incremental relay fee sets the minimimum feerate increase necessary for BIP 125 replacement in the mempool + // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting. + if (IsArgSet("-incrementalrelayfee")) + { + CAmount n = 0; + if (!ParseMoney(GetArg("-incrementalrelayfee", ""), n)) + return InitError(AmountErrMsg("incrementalrelayfee", GetArg("-incrementalrelayfee", ""))); + incrementalRelayFee = CFeeRate(n); + } // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); @@ -1126,10 +1174,33 @@ bool AppInitParameterInteraction() return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", ""))); // High fee check is done afterward in CWallet::ParameterInteraction() ::minRelayTxFee = CFeeRate(n); + } else if (incrementalRelayFee > ::minRelayTxFee) { + // Allow only setting incrementalRelayFee to control both + ::minRelayTxFee = incrementalRelayFee; + LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString()); + } + + // Sanity check argument for min fee for including tx in block + // TODO: Harmonize which arguments need sanity checking and where that happens + if (IsArgSet("-blockmintxfee")) + { + CAmount n = 0; + if (!ParseMoney(GetArg("-blockmintxfee", ""), n)) + return InitError(AmountErrMsg("blockmintxfee", GetArg("-blockmintxfee", ""))); + } + + // Feerate used to define dust. Shouldn't be changed lightly as old + // implementations may inadvertently create non-standard transactions + if (IsArgSet("-dustrelayfee")) + { + CAmount n = 0; + if (!ParseMoney(GetArg("-dustrelayfee", ""), n) || 0 == n) + return InitError(AmountErrMsg("dustrelayfee", GetArg("-dustrelayfee", ""))); + dustRelayFee = CFeeRate(n); } - fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard()); - if (Params().RequireStandard() && !fRequireStandard) + fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard()); + if (chainparams.RequireStandard() && !fRequireStandard) return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString())); nBytesPerSigOp = GetArg("-bytespersigop", nBytesPerSigOp); @@ -1140,8 +1211,7 @@ bool AppInitParameterInteraction() fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); - ForceSetArg("-datacarriersize", nMaxDatacarrierBytes); - //LogPrintf("nMaxDatacarrierBytes=%u \n", nMaxDatacarrierBytes); + nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); @@ -1151,6 +1221,8 @@ bool AppInitParameterInteraction() if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT); if ((!fEnableReplacement) && IsArgSet("-mempoolreplacement")) { // Minimal effort at forwards compatibility @@ -1160,6 +1232,32 @@ bool AppInitParameterInteraction() fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end()); } + if (mapMultiArgs.count("-bip9params")) { + // Allow overriding BIP9 parameters for testing + if (!chainparams.MineBlocksOnDemand()) { + return InitError("BIP9 parameters may only be overridden on regtest."); + } + const std::vector& deployments = mapMultiArgs.at("-bip9params"); + for (auto i : deployments) { + std::vector vDeploymentParams; + boost::split(vDeploymentParams, i, boost::is_any_of(":")); + if (vDeploymentParams.size() != 3) { + return InitError("BIP9 parameters malformed, expecting deployment:start:end"); + } + int64_t nStartTime, nTimeout; + if (!ParseInt64(vDeploymentParams[1], &nStartTime)) { + return InitError(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1])); + } + if (!ParseInt64(vDeploymentParams[2], &nTimeout)) { + return InitError(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2])); + } + bool found = false; + if (!found) { + return InitError(strprintf("Invalid deployment (%s)", vDeploymentParams[0])); + } + } + } + return true; } @@ -1216,8 +1314,11 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); #endif - if (GetBoolArg("-shrinkdebugfile", !fDebug)) + if (GetBoolArg("-shrinkdebugfile", !fDebug)) { + // Do this first since it both loads a bunch of debug.log into memory, + // and because this needs to happen before any other debug.log printing ShrinkDebugFile(); + } if (fPrintToDebugLog) OpenDebugLog(); @@ -1233,11 +1334,17 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); std::ostringstream strErrors; + InitSignatureCache(); + LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads); if (nScriptCheckThreads) { for (int i=0; i uacomments; + if (mapMultiArgs.count("-uacomment")) { BOOST_FOREACH(std::string cmt, mapMultiArgs.at("-uacomment")) { @@ -1682,22 +1790,33 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) fDynodeMode = GetBoolArg("-dynode", false); // TODO: dynode should have no wallet - if((fDynodeMode || dynodeConfig.getCount() > -1) && fTxIndex == false) { - return InitError("Enabling Dynode support requires turning on transaction indexing." - "Please add txindex=1 to your configuration and start with -reindex"); + //lite mode disables all Dynamic-specific functionality + fLiteMode = GetBoolArg("-litemode", false); + + if(fLiteMode) { + InitWarning(_("You are starting in lite mode, all Dynamic-specific functionality is disabled.")); + } + + if((!fLiteMode && fTxIndex == false) + && chainparams.NetworkIDString() != CBaseChainParams::REGTEST) { + return InitError(_("Transaction index can't be disabled in full mode. Either start with -litemode command line switch or enable transaction index.")); + } + + if(fLiteMode && fDynodeMode) { + return InitError(_("You can not start a dynode in lite mode.")); } if(fDynodeMode) { LogPrintf("DYNODE:\n"); - std::string strdynodepairingkey = GetArg("-dynodepairingkey", ""); - if(!strdynodepairingkey.empty()) { - if(!CMessageSigner::GetKeysFromSecret(strdynodepairingkey, activeDynode.keyDynode, activeDynode.pubKeyDynode)) - return InitError(_("Invalid dynodepairingkey. Please see documenation.")); + std::string strDyNodePrivKey = GetArg("-dynodeprivkey", ""); + if(!strDyNodePrivKey.empty()) { + if(!CMessageSigner::GetKeysFromSecret(strDyNodePrivKey, activeDynode.keyDynode, activeDynode.pubKeyDynode)) + return InitError(_("Invalid dynodeprivkey. Please see documenation.")); LogPrintf(" pubKeyDynode: %s\n", CDynamicAddress(activeDynode.pubKeyDynode.GetID()).ToString()); } else { - return InitError(_("You must specify a dynodepairingkey in the configuration. Please see documentation for help.")); + return InitError(_("You must specify a dynodeprivkey in the configuration. Please see documentation for help.")); } } @@ -1709,9 +1828,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("Locking Dynodes:\n"); uint256 dnTxHash; int outputIndex; - BOOST_FOREACH(CDynodeConfig::CDynodeEntry dne, dynodeConfig.getEntries()) { + for (const auto& dne : dynodeConfig.getEntries()) { dnTxHash.SetHex(dne.getTxHash()); - outputIndex = boost::lexical_cast(dne.getOutputIndex()); + outputIndex = (uint32_t)atoi(dne.getOutputIndex()); COutPoint outpoint = COutPoint(dnTxHash, outputIndex); // don't lock non-spendable outpoint (i.e. it's already spent or it's not from this wallet at all) if(pwalletMain->IsMine(CTxIn(outpoint)) != ISMINE_SPENDABLE) { @@ -1725,32 +1844,29 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) privateSendClient.nLiquidityProvider = std::min(std::max((int)GetArg("-liquidityprovider", DEFAULT_PRIVATESEND_LIQUIDITY), 0), 100); + int nMaxRounds = MAX_PRIVATESEND_ROUNDS; if(privateSendClient.nLiquidityProvider) { // special case for liquidity providers only, normal clients should use default value privateSendClient.SetMinBlocksToWait(privateSendClient.nLiquidityProvider * 15); + nMaxRounds = std::numeric_limits::max(); } privateSendClient.fEnablePrivateSend = GetBoolArg("-enableprivatesend", false); privateSendClient.fPrivateSendMultiSession = GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION); - privateSendClient.nPrivateSendRounds = std::min(std::max((int)GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS), 2), 16); - privateSendClient.nPrivateSendAmount = std::min(std::max((int)GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT), 2), 999999); + privateSendClient.nPrivateSendRounds = std::min(std::max((int)GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS), MIN_PRIVATESEND_ROUNDS), nMaxRounds); + privateSendClient.nPrivateSendAmount = std::min(std::max((int)GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT), MIN_PRIVATESEND_AMOUNT), MAX_PRIVATESEND_AMOUNT); #endif // ENABLE_WALLET fEnableInstantSend = GetBoolArg("-enableinstantsend", 1); nInstantSendDepth = GetArg("-instantsenddepth", DEFAULT_INSTANTSEND_DEPTH); nInstantSendDepth = std::min(std::max(nInstantSendDepth, 0), 60); - //lite mode disables all Dynode and PrivateSend related functionality - fLiteMode = GetBoolArg("-litemode", false); - if(fDynodeMode && fLiteMode){ - return InitError("You can not start a Dynode in litemode"); - } - LogPrintf("fLiteMode %d\n", fLiteMode); LogPrintf("nInstantSendDepth %d\n", nInstantSendDepth); #ifdef ENABLE_WALLET - LogPrintf("PrivateSend rounds %d\n", privateSendClient.nPrivateSendRounds); - LogPrintf("PrivateSend amount %d\n", privateSendClient.nPrivateSendAmount); + LogPrintf("PrivateSend liquidityprovider: %d\n", privateSendClient.nLiquidityProvider); + LogPrintf("PrivateSend rounds: %d\n", privateSendClient.nPrivateSendRounds); + LogPrintf("PrivateSend amount: %d\n", privateSendClient.nPrivateSendAmount); #endif // ENABLE_WALLET CPrivateSend::InitStandardDenominations(); @@ -1759,8 +1875,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // LOAD SERIALIZED DAT FILES INTO DATA CACHES FOR INTERNAL USE - boost::filesystem::path pathDB = GetDataDir(); - std::string strDBName; + if (!fLiteMode) { + boost::filesystem::path pathDB = GetDataDir(); + std::string strDBName; strDBName = "dncache.dat"; uiInterface.InitMessage(_("Loading Dynode cache...")); @@ -1796,6 +1913,17 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(_("Failed to load fulfilled requests cache from") + "\n" + (pathDB / strDBName).string()); } + if(fEnableInstantSend) + { + strDBName = "instantsend.dat"; + uiInterface.InitMessage(_("Loading InstantSend data cache...")); + CFlatDB flatdb5(strDBName, "magicInstantSendCache"); + if(!flatdb5.Load(instantsend)) { + return InitError(_("Failed to load InstantSend data cache from") + "\n" + (pathDB / strDBName).string()); + } + } + } + // ********************************************************* Step 11c: update block tip in Dynamic modules // force UpdatedBlockTip to initialize nCachedBlockHeight for PS, DN payments and budgets @@ -1805,13 +1933,24 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 11d: start dynamic-ps- threads - threadGroup.create_thread(boost::bind(&ThreadCheckPrivateSend, boost::ref(*g_connman))); - if (fDynodeMode) - threadGroup.create_thread(boost::bind(&ThreadCheckPrivateSendServer, boost::ref(*g_connman))); + if (!fLiteMode) { + scheduler.scheduleEvery(boost::bind(&CNetFulfilledRequestManager::DoMaintenance, boost::ref(netfulfilledman)), 60); + scheduler.scheduleEvery(boost::bind(&CDynodeSync::DoMaintenance, boost::ref(dynodeSync), boost::ref(*g_connman)), DYNODE_SYNC_TICK_SECONDS); + scheduler.scheduleEvery(boost::bind(&CDynodeMan::DoMaintenance, boost::ref(dnodeman), boost::ref(*g_connman)), 1); + scheduler.scheduleEvery(boost::bind(&CActiveDynode::DoMaintenance, boost::ref(activeDynode), boost::ref(*g_connman)), 1); + + scheduler.scheduleEvery(boost::bind(&CDynodePayments::DoMaintenance, boost::ref(dnpayments)), 60); + scheduler.scheduleEvery(boost::bind(&CGovernanceManager::DoMaintenance, boost::ref(governance), boost::ref(*g_connman)), 60 * 5); + + scheduler.scheduleEvery(boost::bind(&CInstantSend::DoMaintenance, boost::ref(instantsend)), 60); + + if (fDynodeMode) + scheduler.scheduleEvery(boost::bind(&CPrivateSendServer::DoMaintenance, boost::ref(privateSendServer), boost::ref(*g_connman)), 1); #ifdef ENABLE_WALLET - else - threadGroup.create_thread(boost::bind(&ThreadCheckPrivateSendClient, boost::ref(*g_connman))); + else + scheduler.scheduleEvery(boost::bind(&CPrivateSendClient::DoMaintenance, boost::ref(privateSendClient), boost::ref(*g_connman)), 1); #endif // ENABLE_WALLET + } // ********************************************************* Step 12: start node @@ -1824,7 +1963,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) //// debug print LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("chainActive.Height() = %d\n", chainActive.Height()); - if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(threadGroup, scheduler); @@ -1839,6 +1977,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nRelevantServices = nRelevantServices; connOptions.nMaxConnections = nMaxConnections; connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections); + connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS; connOptions.nMaxFeeler = 1; connOptions.nBestHeight = chainActive.Height(); connOptions.uiInterface = &uiInterface; diff --git a/src/init.h b/src/init.h index df74161dce..b8dd2550ae 100644 --- a/src/init.h +++ b/src/init.h @@ -11,9 +11,7 @@ #include class CScheduler; -#ifdef ENABLE_WALLET class CWallet; -#endif //ENABLE_WALLET namespace boost { diff --git a/src/instantsend.cpp b/src/instantsend.cpp index 0406269b5d..3f9f1d55af 100644 --- a/src/instantsend.cpp +++ b/src/instantsend.cpp @@ -13,6 +13,7 @@ #include "dynodeman.h" #include "messagesigner.h" #include "net.h" +#include "netmessagemaker.h" #include "protocol.h" #include "spork.h" #include "sync.h" @@ -20,6 +21,7 @@ #include "util.h" #include "consensus/validation.h" #include "validationinterface.h" +#include "warnings.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" #endif // ENABLE_WALLET @@ -37,6 +39,7 @@ int nInstantSendDepth = DEFAULT_INSTANTSEND_DEPTH; int nCompleteTXLocks; CInstantSend instantsend; +const std::string CInstantSend::SERIALIZATION_VERSION_STRING = "CInstantSend-Version-1"; // Transaction Locks // @@ -49,20 +52,26 @@ CInstantSend instantsend; // CInstantSend // -void CInstantSend::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman) +void CInstantSend::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) { if(fLiteMode) return; // disable all Dynamic specific functionality if(!sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED)) return; - // NOTE: NetMsgType::TXLOCKREQUEST is handled via ProcessMessage() in main.cpp + // NOTE: NetMsgType::TXLOCKREQUEST is handled via ProcessMessage() in net_processing.cpp if (strCommand == NetMsgType::TXLOCKVOTE) // InstantSend Transaction Lock Consensus Votes { - if(pfrom->nVersion < MIN_INSTANTSEND_PROTO_VERSION) return; + if(pfrom->nVersion < MIN_INSTANTSEND_PROTO_VERSION) { + LogPrint("instantsend", "TXLOCKVOTE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_INSTANTSEND_PROTO_VERSION))); + return; + } CTxLockVote vote; vRecv >> vote; + uint256 nVoteHash = vote.GetHash(); pfrom->setAskFor.erase(nVoteHash); @@ -70,17 +79,13 @@ void CInstantSend::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataSt // Ignore any InstantSend messages until dynode list is synced if(!dynodeSync.IsDynodeListSynced()) return; - LOCK(cs_main); -#ifdef ENABLE_WALLET - if (pwalletMain) - LOCK(pwalletMain->cs_wallet); -#endif - LOCK(cs_instantsend); - - if(mapTxLockVotes.count(nVoteHash)) return; - mapTxLockVotes.insert(std::make_pair(nVoteHash, vote)); + { + LOCK(cs_instantsend); + auto ret = mapTxLockVotes.emplace(nVoteHash, vote); + if (!ret.second) return; + } - ProcessTxLockVote(pfrom, vote, connman); + ProcessNewTxLockVote(pfrom, vote, connman); return; } @@ -88,12 +93,16 @@ void CInstantSend::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataSt bool CInstantSend::ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman) { - LOCK2(cs_main, cs_instantsend); + LOCK(cs_main); +#ifdef ENABLE_WALLET + LOCK(pwalletMain ? &pwalletMain->cs_wallet : NULL); +#endif + LOCK2(mempool.cs, cs_instantsend); uint256 txHash = txLockRequest.GetHash(); // Check to see if we conflict with existing completed lock - BOOST_FOREACH(const CTxIn& txin, txLockRequest.vin) { + for (const auto& txin : txLockRequest.tx->vin) { std::map::iterator it = mapLockedOutpoints.find(txin.prevout); if(it != mapLockedOutpoints.end() && it->second != txLockRequest.GetHash()) { // Conflicting with complete lock, proceed to see if we should cancel them both @@ -104,10 +113,10 @@ bool CInstantSend::ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CCo // Check to see if there are votes for conflicting request, // if so - do not fail, just warn user - BOOST_FOREACH(const CTxIn& txin, txLockRequest.vin) { + for (const auto& txin : txLockRequest.tx->vin) { std::map >::iterator it = mapVotedOutpoints.find(txin.prevout); if(it != mapVotedOutpoints.end()) { - BOOST_FOREACH(const uint256& hash, it->second) { + for (const auto& hash : it->second) { if(hash != txLockRequest.GetHash()) { LogPrint("instantsend", "CInstantSend::ProcessTxLockRequest -- Double spend attempt! %s\n", txin.prevout.ToStringShort()); // do not fail here, let it go and see which one will get the votes to be locked @@ -125,8 +134,9 @@ bool CInstantSend::ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CCo LogPrintf("CInstantSend::ProcessTxLockRequest -- accepted, txid=%s\n", txHash.ToString()); // Dynodes will sometimes propagate votes before the transaction is known to the client. - // If this just happened - lock inputs, resolve conflicting locks, update transaction status - // forcing external script notification. + // If this just happened - process orphan votes, lock inputs, resolve conflicting locks, + // update transaction status forcing external script/zmq notifications. + ProcessOrphanTxLockVotes(); std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); TryToFinalizeLockCandidate(itLockCandidate->second); @@ -147,7 +157,7 @@ bool CInstantSend::CreateTxLockCandidate(const CTxLockRequest& txLockRequest) CTxLockCandidate txLockCandidate(txLockRequest); // all inputs should already be checked by txLockRequest.IsValid() above, just use them now - for(const auto& txin : txLockRequest.vin) { + for(const auto& txin : txLockRequest.tx->vin) { txLockCandidate.AddOutPointLock(txin.prevout); } mapTxLockCandidates.insert(std::make_pair(txHash, txLockCandidate)); @@ -161,7 +171,7 @@ bool CInstantSend::CreateTxLockCandidate(const CTxLockRequest& txLockRequest) LogPrintf("CInstantSend::CreateTxLockCandidate -- update empty, txid=%s\n", txHash.ToString()); // all inputs should already be checked by txLockRequest.IsValid() above, just use them now - for(const auto& txin : txLockRequest.vin) { + for(const auto& txin : txLockRequest.tx->vin) { itLockCandidate->second.AddOutPointLock(txin.prevout); } } else { @@ -183,13 +193,23 @@ void CInstantSend::CreateEmptyTxLockCandidate(const uint256& txHash) void CInstantSend::Vote(const uint256& txHash, CConnman& connman) { AssertLockHeld(cs_main); - LOCK(cs_instantsend); +#ifdef ENABLE_WALLET + LOCK(pwalletMain ? &pwalletMain->cs_wallet : NULL); +#endif + + CTxLockRequest dummyRequest; + CTxLockCandidate txLockCandidate(dummyRequest); + { + LOCK(cs_instantsend); + auto itLockCandidate = mapTxLockCandidates.find(txHash); + if (itLockCandidate == mapTxLockCandidates.end()) return; + txLockCandidate = itLockCandidate->second; + Vote(txLockCandidate, connman); + } - std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); - if (itLockCandidate == mapTxLockCandidates.end()) return; - Vote(itLockCandidate->second, connman); // Let's see if our vote changed smth - TryToFinalizeLockCandidate(itLockCandidate->second); + LOCK2(mempool.cs, cs_instantsend); + TryToFinalizeLockCandidate(txLockCandidate); } void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman) @@ -197,68 +217,62 @@ void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman) if(!fDynodeMode) return; if(!sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED)) return; - LOCK2(cs_main, cs_instantsend); + AssertLockHeld(cs_main); + AssertLockHeld(cs_instantsend); uint256 txHash = txLockCandidate.GetHash(); - // We should never vote on a Transaction Lock Request that was not (yet) accepted by the mempool if(mapLockRequestAccepted.find(txHash) == mapLockRequestAccepted.end()) return; - // check if we need to vote on this candidate's outpoints, // it's possible that we need to vote for several of them - std::map::iterator itOutpointLock = txLockCandidate.mapOutPointLocks.begin(); - while(itOutpointLock != txLockCandidate.mapOutPointLocks.end()) { - - int nPrevoutHeight = GetUTXOHeight(itOutpointLock->first); + for (auto& outpointLockPair : txLockCandidate.mapOutPointLocks) { + int nPrevoutHeight = GetUTXOHeight(outpointLockPair.first); if(nPrevoutHeight == -1) { - LogPrint("instantsend", "CInstantSend::Vote -- Failed to find UTXO %s\n", itOutpointLock->first.ToStringShort()); + LogPrint("instantsend", "CInstantSend::Vote -- Failed to find UTXO %s\n", outpointLockPair.first.ToStringShort()); return; } - int nLockInputHeight = nPrevoutHeight + 4; + int nLockInputHeight = nPrevoutHeight + Params().GetConsensus().nInstantSendConfirmationsRequired - 2; int nRank; int nMinRequiredProtocol = std::max(MIN_INSTANTSEND_PROTO_VERSION, dnpayments.GetMinDynodePaymentsProto()); if(!dnodeman.GetDynodeRank(activeDynode.outpoint, nRank, nLockInputHeight, nMinRequiredProtocol)) { LogPrint("instantsend", "CInstantSend::Vote -- Can't calculate rank for dynode %s\n", activeDynode.outpoint.ToStringShort()); - ++itOutpointLock; continue; } int nSignaturesTotal = COutPointLock::SIGNATURES_TOTAL; if(nRank > nSignaturesTotal) { LogPrint("instantsend", "CInstantSend::Vote -- Dynode not in the top %d (%d)\n", nSignaturesTotal, nRank); - ++itOutpointLock; continue; } LogPrint("instantsend", "CInstantSend::Vote -- In the top %d (%d)\n", nSignaturesTotal, nRank); - std::map >::iterator itVoted = mapVotedOutpoints.find(itOutpointLock->first); + std::map >::iterator itVoted = mapVotedOutpoints.find(outpointLockPair.first); // Check to see if we already voted for this outpoint, // refuse to vote twice or to include the same outpoint in another tx bool fAlreadyVoted = false; if(itVoted != mapVotedOutpoints.end()) { - BOOST_FOREACH(const uint256& hash, itVoted->second) { + for (const auto& hash : itVoted->second) { std::map::iterator it2 = mapTxLockCandidates.find(hash); - if(it2->second.HasDynodeVoted(itOutpointLock->first, activeDynode.outpoint)) { + if(it2->second.HasDynodeVoted(outpointLockPair.first, activeDynode.outpoint)) { // we already voted for this outpoint to be included either in the same tx or in a competing one, // skip it anyway fAlreadyVoted = true; LogPrintf("CInstantSend::Vote -- WARNING: We already voted for this outpoint, skipping: txHash=%s, outpoint=%s\n", - txHash.ToString(), itOutpointLock->first.ToStringShort()); + txHash.ToString(), outpointLockPair.first.ToStringShort()); break; } } } if(fAlreadyVoted) { - ++itOutpointLock; continue; // skip to the next outpoint } // we haven't voted for this outpoint yet, let's try to do this now - CTxLockVote vote(txHash, itOutpointLock->first, activeDynode.outpoint); + CTxLockVote vote(txHash, outpointLockPair.first, activeDynode.outpoint); if(!vote.Sign()) { LogPrintf("CInstantSend::Vote -- Failed to sign consensus vote\n"); @@ -272,117 +286,160 @@ void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman) // vote constructed sucessfully, let's store and relay it uint256 nVoteHash = vote.GetHash(); mapTxLockVotes.insert(std::make_pair(nVoteHash, vote)); - if(itOutpointLock->second.AddVote(vote)) { + if(outpointLockPair.second.AddVote(vote)) { LogPrintf("CInstantSend::Vote -- Vote created successfully, relaying: txHash=%s, outpoint=%s, vote=%s\n", - txHash.ToString(), itOutpointLock->first.ToStringShort(), nVoteHash.ToString()); + txHash.ToString(), outpointLockPair.first.ToStringShort(), nVoteHash.ToString()); if(itVoted == mapVotedOutpoints.end()) { std::set setHashes; setHashes.insert(txHash); - mapVotedOutpoints.insert(std::make_pair(itOutpointLock->first, setHashes)); + mapVotedOutpoints.insert(std::make_pair(outpointLockPair.first, setHashes)); } else { - mapVotedOutpoints[itOutpointLock->first].insert(txHash); - if(mapVotedOutpoints[itOutpointLock->first].size() > 1) { + mapVotedOutpoints[outpointLockPair.first].insert(txHash); + if(mapVotedOutpoints[outpointLockPair.first].size() > 1) { // it's ok to continue, just warn user LogPrintf("CInstantSend::Vote -- WARNING: Vote conflicts with some existing votes: txHash=%s, outpoint=%s, vote=%s\n", - txHash.ToString(), itOutpointLock->first.ToStringShort(), nVoteHash.ToString()); + txHash.ToString(), outpointLockPair.first.ToStringShort(), nVoteHash.ToString()); } } vote.Relay(connman); } - - ++itOutpointLock; } } -//received a consensus vote -bool CInstantSend::ProcessTxLockVote(CNode* pfrom, CTxLockVote& vote, CConnman& connman) +bool CInstantSend::ProcessNewTxLockVote(CNode* pfrom, const CTxLockVote& vote, CConnman& connman) { - // cs_main, cs_wallet and cs_instantsend should be already locked - AssertLockHeld(cs_main); -#ifdef ENABLE_WALLET - if (pwalletMain) - AssertLockHeld(pwalletMain->cs_wallet); -#endif - AssertLockHeld(cs_instantsend); - uint256 txHash = vote.GetTxHash(); + uint256 nVoteHash = vote.GetHash(); if(!vote.IsValid(pfrom, connman)) { // could be because of missing DN - LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Vote is invalid, txid=%s\n", txHash.ToString()); + LogPrint("instantsend", "CInstantSend::%s -- Vote is invalid, txid=%s\n", __func__, txHash.ToString()); return false; } // relay valid vote asap vote.Relay(connman); + LOCK(cs_main); +#ifdef ENABLE_WALLET + LOCK(pwalletMain ? &pwalletMain->cs_wallet : NULL); +#endif + LOCK2(mempool.cs, cs_instantsend); + // Dynodes will sometimes propagate votes before the transaction is known to the client, // will actually process only after the lock request itself has arrived std::map::iterator it = mapTxLockCandidates.find(txHash); if(it == mapTxLockCandidates.end() || !it->second.txLockRequest) { - if(!mapTxLockVotesOrphan.count(vote.GetHash())) { + // no or empty tx lock candidate + if(it == mapTxLockCandidates.end()) { // start timeout countdown after the very first vote CreateEmptyTxLockCandidate(txHash); - mapTxLockVotesOrphan[vote.GetHash()] = vote; - LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Orphan vote: txid=%s dynode=%s new\n", - txHash.ToString(), vote.GetDynodeOutpoint().ToStringShort()); - bool fReprocess = true; - std::map::iterator itLockRequest = mapLockRequestAccepted.find(txHash); - if(itLockRequest == mapLockRequestAccepted.end()) { - itLockRequest = mapLockRequestRejected.find(txHash); - if(itLockRequest == mapLockRequestRejected.end()) { - // still too early, wait for tx lock request - fReprocess = false; - } - } - if(fReprocess && IsEnoughOrphanVotesForTx(itLockRequest->second)) { - // We have enough votes for corresponding lock to complete, - // tx lock request should already be received at this stage. - LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Found enough orphan votes, reprocessing Transaction Lock Request: txid=%s\n", txHash.ToString()); - ProcessTxLockRequest(itLockRequest->second, connman); - return true; - } - } else { - LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Orphan vote: txid=%s dynode=%s seen\n", - txHash.ToString(), vote.GetDynodeOutpoint().ToStringShort()); } + bool fInserted = mapTxLockVotesOrphan.emplace(nVoteHash, vote).second; + LogPrint("instantsend", "CInstantSend::%s -- Orphan vote: txid=%s dynode=%s %s\n", + __func__, txHash.ToString(), vote.GetDynodeOutpoint().ToStringShort(), fInserted ? "new" : "seen"); // This tracks those messages and allows only the same rate as of the rest of the network // TODO: make sure this works good enough for multi-quorum int nDynodeOrphanExpireTime = GetTime() + 60*10; // keep time data for 10 minutes - if(!mapDynodeOrphanVotes.count(vote.GetDynodeOutpoint())) { - mapDynodeOrphanVotes[vote.GetDynodeOutpoint()] = nDynodeOrphanExpireTime; + auto itDnOV = mapDynodeOrphanVotes.find(vote.GetDynodeOutpoint()); + if(itDnOV == mapDynodeOrphanVotes.end()) { + mapDynodeOrphanVotes.emplace(vote.GetDynodeOutpoint(), nDynodeOrphanExpireTime); } else { - int64_t nPrevOrphanVote = mapDynodeOrphanVotes[vote.GetDynodeOutpoint()]; - if(nPrevOrphanVote > GetTime() && nPrevOrphanVote > GetAverageDynodeOrphanVoteTime()) { - LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- dynode is spamming orphan Transaction Lock Votes: txid=%s dynode=%s\n", - txHash.ToString(), vote.GetDynodeOutpoint().ToStringShort()); + if(itDnOV->second > GetTime() && itDnOV->second > GetAverageDynodeOrphanVoteTime()) { + LogPrint("instantsend", "CInstantSend::%s -- dynode is spamming orphan Transaction Lock Votes: txid=%s dynode=%s\n", + __func__, txHash.ToString(), vote.GetDynodeOutpoint().ToStringShort()); // Misbehaving(pfrom->id, 1); return false; } // not spamming, refresh - mapDynodeOrphanVotes[vote.GetDynodeOutpoint()] = nDynodeOrphanExpireTime; + itDnOV->second = nDynodeOrphanExpireTime; } return true; } + // We have a valid (non-empty) tx lock candidate CTxLockCandidate& txLockCandidate = it->second; if (txLockCandidate.IsTimedOut()) { - LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- too late, Transaction Lock timed out, txid=%s\n", txHash.ToString()); + LogPrint("instantsend", "CInstantSend::%s -- too late, Transaction Lock timed out, txid=%s\n", __func__, txHash.ToString()); return false; } - LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Transaction Lock Vote, txid=%s\n", txHash.ToString()); + LogPrint("instantsend", "CInstantSend::%s -- Transaction Lock Vote, txid=%s\n", __func__, txHash.ToString()); + + UpdateVotedOutpoints(vote, txLockCandidate); + + if(!txLockCandidate.AddVote(vote)) { + // this should never happen + return false; + } + + int nSignatures = txLockCandidate.CountVotes(); + int nSignaturesMax = txLockCandidate.txLockRequest.GetMaxSignatures(); + LogPrint("instantsend", "CInstantSend::%s -- Transaction Lock signatures count: %d/%d, vote hash=%s\n", __func__, + nSignatures, nSignaturesMax, nVoteHash.ToString()); + + TryToFinalizeLockCandidate(txLockCandidate); + + return true; +} + +bool CInstantSend::ProcessOrphanTxLockVote(const CTxLockVote& vote) +{ + // cs_main, cs_wallet and cs_instantsend should be already locked + AssertLockHeld(cs_main); +#ifdef ENABLE_WALLET + if (pwalletMain) + AssertLockHeld(pwalletMain->cs_wallet); +#endif + AssertLockHeld(cs_instantsend); + + uint256 txHash = vote.GetTxHash(); + + // We shouldn't process orphan votes without a valid tx lock candidate + std::map::iterator it = mapTxLockCandidates.find(txHash); + if(it == mapTxLockCandidates.end() || !it->second.txLockRequest) + return false; // this shouldn never happen + + CTxLockCandidate& txLockCandidate = it->second; + + if (txLockCandidate.IsTimedOut()) { + LogPrint("instantsend", "CInstantSend::%s -- too late, Transaction Lock timed out, txid=%s\n", __func__, txHash.ToString()); + return false; + } + + LogPrint("instantsend", "CInstantSend::%s -- Transaction Lock Vote, txid=%s\n", __func__, txHash.ToString()); + + UpdateVotedOutpoints(vote, txLockCandidate); + + if(!txLockCandidate.AddVote(vote)) { + // this should never happen + return false; + } + + int nSignatures = txLockCandidate.CountVotes(); + int nSignaturesMax = txLockCandidate.txLockRequest.GetMaxSignatures(); + LogPrint("instantsend", "CInstantSend::%s -- Transaction Lock signatures count: %d/%d, vote hash=%s\n", + __func__, nSignatures, nSignaturesMax, vote.GetHash().ToString()); + + return true; +} + +void CInstantSend::UpdateVotedOutpoints(const CTxLockVote& vote, CTxLockCandidate& txLockCandidate) +{ + AssertLockHeld(cs_instantsend); + + uint256 txHash = vote.GetTxHash(); std::map >::iterator it1 = mapVotedOutpoints.find(vote.GetOutpoint()); if(it1 != mapVotedOutpoints.end()) { - BOOST_FOREACH(const uint256& hash, it1->second) { + for (const auto& hash : it1->second) { if(hash != txHash) { // same outpoint was already voted to be locked by another tx lock request, // let's see if it was the same dynode who voted on this outpoint @@ -390,7 +447,7 @@ bool CInstantSend::ProcessTxLockVote(CNode* pfrom, CTxLockVote& vote, CConnman& std::map::iterator it2 = mapTxLockCandidates.find(hash); if(it2 !=mapTxLockCandidates.end() && it2->second.HasDynodeVoted(vote.GetOutpoint(), vote.GetDynodeOutpoint())) { // yes, it was the same dynode - LogPrintf("CInstantSend::ProcessTxLockVote -- dynode sent conflicting votes! %s\n", vote.GetDynodeOutpoint().ToStringShort()); + LogPrintf("CInstantSend::%s -- dynode sent conflicting votes! %s\n", __func__, vote.GetDynodeOutpoint().ToStringShort()); // mark both Lock Candidates as attacked, none of them should complete, // or at least the new (current) one shouldn't even // if the second one was already completed earlier @@ -407,38 +464,18 @@ bool CInstantSend::ProcessTxLockVote(CNode* pfrom, CTxLockVote& vote, CConnman& // store all votes, regardless of them being sent by malicious dynode or not it1->second.insert(txHash); } else { - std::set setHashes; - setHashes.insert(txHash); - mapVotedOutpoints.insert(std::make_pair(vote.GetOutpoint(), setHashes)); + mapVotedOutpoints.emplace(vote.GetOutpoint(), std::set({txHash})); } - - if(!txLockCandidate.AddVote(vote)) { - // this should never happen - return false; - } - - int nSignatures = txLockCandidate.CountVotes(); - int nSignaturesMax = txLockCandidate.txLockRequest.GetMaxSignatures(); - LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Transaction Lock signatures count: %d/%d, vote hash=%s\n", - nSignatures, nSignaturesMax, vote.GetHash().ToString()); - - TryToFinalizeLockCandidate(txLockCandidate); - - return true; } -void CInstantSend::ProcessOrphanTxLockVotes(CConnman& connman) +void CInstantSend::ProcessOrphanTxLockVotes() { - LOCK(cs_main); -#ifdef ENABLE_WALLET - if (pwalletMain) - LOCK(pwalletMain->cs_wallet); -#endif - LOCK(cs_instantsend); + AssertLockHeld(cs_main); + AssertLockHeld(cs_instantsend); std::map::iterator it = mapTxLockVotesOrphan.begin(); while(it != mapTxLockVotesOrphan.end()) { - if(ProcessTxLockVote(NULL, it->second, connman)) { + if(ProcessOrphanTxLockVote(it->second)) { mapTxLockVotesOrphan.erase(it++); } else { ++it; @@ -446,49 +483,14 @@ void CInstantSend::ProcessOrphanTxLockVotes(CConnman& connman) } } -bool CInstantSend::IsEnoughOrphanVotesForTx(const CTxLockRequest& txLockRequest) -{ - // There could be a situation when we already have quite a lot of votes - // but tx lock request still wasn't received. Let's scan through - // orphan votes to check if this is the case. - BOOST_FOREACH(const CTxIn& txin, txLockRequest.vin) { - if(!IsEnoughOrphanVotesForTxAndOutPoint(txLockRequest.GetHash(), txin.prevout)) { - return false; - } - } - return true; -} - -bool CInstantSend::IsEnoughOrphanVotesForTxAndOutPoint(const uint256& txHash, const COutPoint& outpoint) -{ - // Scan orphan votes to check if this outpoint has enough orphan votes to be locked in some tx. - LOCK2(cs_main, cs_instantsend); - int nCountVotes = 0; - std::map::iterator it = mapTxLockVotesOrphan.begin(); - while(it != mapTxLockVotesOrphan.end()) { - if(it->second.GetTxHash() == txHash && it->second.GetOutpoint() == outpoint) { - nCountVotes++; - if(nCountVotes >= COutPointLock::SIGNATURES_REQUIRED) { - return true; - } - } - ++it; - } - return false; -} - void CInstantSend::TryToFinalizeLockCandidate(const CTxLockCandidate& txLockCandidate) { if(!sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED)) return; - LOCK(cs_main); -#ifdef ENABLE_WALLET - if (pwalletMain) - LOCK(pwalletMain->cs_wallet); -#endif - LOCK(cs_instantsend); + AssertLockHeld(cs_main); + AssertLockHeld(cs_instantsend); - uint256 txHash = txLockCandidate.txLockRequest.GetHash(); + uint256 txHash = txLockCandidate.txLockRequest.tx->GetHash(); if(txLockCandidate.IsAllOutPointsReady() && !IsLockedInstantSendTransaction(txHash)) { // we have enough votes now LogPrint("instantsend", "CInstantSend::TryToFinalizeLockCandidate -- Transaction Lock is ready to complete, txid=%s\n", txHash.ToString()); @@ -501,7 +503,8 @@ void CInstantSend::TryToFinalizeLockCandidate(const CTxLockCandidate& txLockCand void CInstantSend::UpdateLockedTransaction(const CTxLockCandidate& txLockCandidate) { - // cs_wallet and cs_instantsend should be already locked + // cs_main, cs_wallet and cs_instantsend should be already locked + AssertLockHeld(cs_main); #ifdef ENABLE_WALLET if (pwalletMain) AssertLockHeld(pwalletMain->cs_wallet); @@ -525,7 +528,7 @@ void CInstantSend::UpdateLockedTransaction(const CTxLockCandidate& txLockCandida } #endif - GetMainSignals().NotifyTransactionLock(txLockCandidate.txLockRequest); + GetMainSignals().NotifyTransactionLock(*txLockCandidate.txLockRequest.tx); LogPrint("instantsend", "CInstantSend::UpdateLockedTransaction -- done, txid=%s\n", txHash.ToString()); } @@ -540,11 +543,8 @@ void CInstantSend::LockTransactionInputs(const CTxLockCandidate& txLockCandidate if(!txLockCandidate.IsAllOutPointsReady()) return; - std::map::const_iterator it = txLockCandidate.mapOutPointLocks.begin(); - - while(it != txLockCandidate.mapOutPointLocks.end()) { - mapLockedOutpoints.insert(std::make_pair(it->first, txHash)); - ++it; + for (const auto& pair : txLockCandidate.mapOutPointLocks) { + mapLockedOutpoints.insert(std::make_pair(pair.first, txHash)); } LogPrint("instantsend", "CInstantSend::LockTransactionInputs -- done, txid=%s\n", txHash.ToString()); } @@ -560,16 +560,17 @@ bool CInstantSend::GetLockedOutPointTxHash(const COutPoint& outpoint, uint256& h bool CInstantSend::ResolveConflicts(const CTxLockCandidate& txLockCandidate) { - LOCK2(cs_main, cs_instantsend); + AssertLockHeld(cs_main); + AssertLockHeld(cs_instantsend); uint256 txHash = txLockCandidate.GetHash(); // make sure the lock is ready if(!txLockCandidate.IsAllOutPointsReady()) return false; - LOCK(mempool.cs); // protect mempool.mapNextTx + AssertLockHeld(mempool.cs); // protect mempool.mapNextTx - BOOST_FOREACH(const CTxIn& txin, txLockCandidate.txLockRequest.vin) { + for (const auto& txin : txLockCandidate.txLockRequest.tx->vin) { uint256 hashConflicting; if(GetLockedOutPointTxHash(txin.prevout, hashConflicting) && txHash != hashConflicting) { // completed lock which conflicts with another completed one? @@ -613,14 +614,14 @@ bool CInstantSend::ResolveConflicts(const CTxLockCandidate& txLockCandidate) } } // FOREACH // No conflicts were found so far, check to see if it was already included in block - CTransaction txTmp; + CTransactionRef txTmp; uint256 hashBlock; if(GetTransaction(txHash, txTmp, Params().GetConsensus(), hashBlock, true) && hashBlock != uint256()) { LogPrint("instantsend", "CInstantSend::ResolveConflicts -- Done, %s is included in block %s\n", txHash.ToString(), hashBlock.ToString()); return true; } // Not in block yet, make sure all its inputs are still unspent - BOOST_FOREACH(const CTxIn& txin, txLockCandidate.txLockRequest.vin) { + for (const auto& txin : txLockCandidate.txLockRequest.tx->vin) { Coin coin; if(!GetUTXOCoin(txin.prevout, coin)) { // Not in UTXO anymore? A conflicting tx was mined while we were waiting for votes. @@ -639,12 +640,9 @@ int64_t CInstantSend::GetAverageDynodeOrphanVoteTime() // NOTE: should never actually call this function when mapDynodeOrphanVotes is empty if(mapDynodeOrphanVotes.empty()) return 0; - std::map::iterator it = mapDynodeOrphanVotes.begin(); int64_t total = 0; - - while(it != mapDynodeOrphanVotes.end()) { - total+= it->second; - ++it; + for (const auto& pair : mapDynodeOrphanVotes) { + total += pair.second; } return total / mapDynodeOrphanVotes.size(); @@ -664,11 +662,10 @@ void CInstantSend::CheckAndRemove() uint256 txHash = txLockCandidate.GetHash(); if(txLockCandidate.IsExpired(nCachedBlockHeight)) { LogPrintf("CInstantSend::CheckAndRemove -- Removing expired Transaction Lock Candidate: txid=%s\n", txHash.ToString()); - std::map::iterator itOutpointLock = txLockCandidate.mapOutPointLocks.begin(); - while(itOutpointLock != txLockCandidate.mapOutPointLocks.end()) { - mapLockedOutpoints.erase(itOutpointLock->first); - mapVotedOutpoints.erase(itOutpointLock->first); - ++itOutpointLock; + + for (const auto& pair : txLockCandidate.mapOutPointLocks) { + mapLockedOutpoints.erase(pair.first); + mapVotedOutpoints.erase(pair.first); } mapLockRequestAccepted.erase(txHash); mapLockRequestRejected.erase(txHash); @@ -760,7 +757,7 @@ bool CInstantSend::GetTxLockRequest(const uint256& txHash, CTxLockRequest& txLoc LOCK(cs_instantsend); std::map::iterator it = mapTxLockCandidates.find(txHash); - if(it == mapTxLockCandidates.end()) return false; + if(it == mapTxLockCandidates.end() || !it->second.txLockRequest) return false; txLockRequestRet = it->second.txLockRequest; return true; @@ -779,7 +776,7 @@ bool CInstantSend::GetTxLockVote(const uint256& hash, CTxLockVote& txLockVoteRet bool CInstantSend::IsInstantSendReadyToLock(const uint256& txHash) { - if(!fEnableInstantSend || fLargeWorkForkFound || fLargeWorkInvalidChainFound || + if(!fEnableInstantSend || GetfLargeWorkForkFound() || GetfLargeWorkInvalidChainFound() || !sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED)) return false; LOCK(cs_instantsend); @@ -789,9 +786,24 @@ bool CInstantSend::IsInstantSendReadyToLock(const uint256& txHash) return it != mapTxLockCandidates.end() && it->second.IsAllOutPointsReady(); } +void CInstantSend::Clear() +{ + LOCK(cs_instantsend); + + mapLockRequestAccepted.clear(); + mapLockRequestRejected.clear(); + mapTxLockVotes.clear(); + mapTxLockVotesOrphan.clear(); + mapTxLockCandidates.clear(); + mapVotedOutpoints.clear(); + mapLockedOutpoints.clear(); + mapDynodeOrphanVotes.clear(); + nCachedBlockHeight = 0; +} + bool CInstantSend::IsLockedInstantSendTransaction(const uint256& txHash) { - if(!fEnableInstantSend || fLargeWorkForkFound || fLargeWorkInvalidChainFound || + if(!fEnableInstantSend || GetfLargeWorkForkFound() || GetfLargeWorkInvalidChainFound() || !sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) return false; LOCK(cs_instantsend); @@ -804,11 +816,9 @@ bool CInstantSend::IsLockedInstantSendTransaction(const uint256& txHash) if(itLockCandidate->second.mapOutPointLocks.empty()) return false; // and all of these outputs must be included in mapLockedOutpoints with correct hash - std::map::iterator itOutpointLock = itLockCandidate->second.mapOutPointLocks.begin(); - while(itOutpointLock != itLockCandidate->second.mapOutPointLocks.end()) { + for (const auto& pair : itLockCandidate->second.mapOutPointLocks) { uint256 hashLocked; - if(!GetLockedOutPointTxHash(itOutpointLock->first, hashLocked) || hashLocked != txHash) return false; - ++itOutpointLock; + if(!GetLockedOutPointTxHash(pair.first, hashLocked) || hashLocked != txHash) return false; } return true; @@ -817,7 +827,7 @@ bool CInstantSend::IsLockedInstantSendTransaction(const uint256& txHash) int CInstantSend::GetTransactionLockSignatures(const uint256& txHash) { if(!fEnableInstantSend) return -1; - if(fLargeWorkForkFound || fLargeWorkInvalidChainFound) return -2; + if(GetfLargeWorkForkFound() || GetfLargeWorkInvalidChainFound()) return -2; if(!sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED)) return -3; LOCK(cs_instantsend); @@ -865,7 +875,7 @@ void CInstantSend::UpdatedBlockTip(const CBlockIndex *pindex) nCachedBlockHeight = pindex->nHeight; } -void CInstantSend::SyncTransaction(const CTransaction& tx, const CBlock* pblock) +void CInstantSend::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock) { // Update lock candidates and votes if corresponding tx confirmed // or went from confirmed to 0-confirmed or conflicted. @@ -876,19 +886,8 @@ void CInstantSend::SyncTransaction(const CTransaction& tx, const CBlock* pblock) uint256 txHash = tx.GetHash(); - // When tx is 0-confirmed or conflicted, pblock is NULL and nHeightNew should be set to -1 - CBlockIndex* pblockindex = NULL; - if(pblock) { - uint256 blockHash = pblock->GetHash(); - BlockMap::iterator mi = mapBlockIndex.find(blockHash); - if(mi == mapBlockIndex.end() || !mi->second) { - // shouldn't happen - LogPrint("instantsend", "CTxLockRequest::SyncTransaction -- Failed to find block %s\n", blockHash.ToString()); - return; - } - pblockindex = mi->second; - } - int nHeightNew = pblockindex ? pblockindex->nHeight : -1; + // When tx is 0-confirmed or conflicted, posInBlock is SYNC_TRANSACTION_NOT_IN_BLOCK and nHeightNew should be set to -1 + int nHeightNew = posInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK ? -1 : pindex->nHeight; LogPrint("instantsend", "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d\n", txHash.ToString(), nHeightNew); @@ -899,39 +898,32 @@ void CInstantSend::SyncTransaction(const CTransaction& tx, const CBlock* pblock) txHash.ToString(), nHeightNew); itLockCandidate->second.SetConfirmedHeight(nHeightNew); // Loop through outpoint locks - std::map::iterator itOutpointLock = itLockCandidate->second.mapOutPointLocks.begin(); - while(itOutpointLock != itLockCandidate->second.mapOutPointLocks.end()) { + for (const auto& pair : itLockCandidate->second.mapOutPointLocks) { + // Check corresponding lock votes - std::vector vVotes = itOutpointLock->second.GetVotes(); - std::vector::iterator itVote = vVotes.begin(); - std::map::iterator it; - while(itVote != vVotes.end()) { - uint256 nVoteHash = itVote->GetHash(); + for (const auto& vote : pair.second.GetVotes()) { + uint256 nVoteHash = vote.GetHash(); LogPrint("instantsend", "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d vote %s updated\n", txHash.ToString(), nHeightNew, nVoteHash.ToString()); - it = mapTxLockVotes.find(nVoteHash); + const auto& it = mapTxLockVotes.find(nVoteHash); if(it != mapTxLockVotes.end()) { it->second.SetConfirmedHeight(nHeightNew); } - ++itVote; } - ++itOutpointLock; } } // check orphan votes - std::map::iterator itOrphanVote = mapTxLockVotesOrphan.begin(); - while(itOrphanVote != mapTxLockVotesOrphan.end()) { - if(itOrphanVote->second.GetTxHash() == txHash) { + for (const auto& pair : mapTxLockVotesOrphan) { + if(pair.second.GetTxHash() == txHash) { LogPrint("instantsend", "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d vote %s updated\n", - txHash.ToString(), nHeightNew, itOrphanVote->first.ToString()); - mapTxLockVotes[itOrphanVote->first].SetConfirmedHeight(nHeightNew); + txHash.ToString(), nHeightNew, pair.first.ToString()); + mapTxLockVotes[pair.first].SetConfirmedHeight(nHeightNew); } - ++itOrphanVote; } } -std::string CInstantSend::ToString() +std::string CInstantSend::ToString() const { LOCK(cs_instantsend); return strprintf("Lock Candidates: %llu, Votes %llu", mapTxLockCandidates.size(), mapTxLockVotes.size()); @@ -943,21 +935,23 @@ std::string CInstantSend::ToString() bool CTxLockRequest::IsValid() const { - if(vout.size() < 1) return false; + if(tx->vout.size() < 1) return false; - if(vin.size() > WARN_MANY_INPUTS) { + if(tx->vin.size() > WARN_MANY_INPUTS) { LogPrint("instantsend", "CTxLockRequest::IsValid -- WARNING: Too many inputs: tx=%s", ToString()); } - LOCK(cs_main); - if(!CheckFinalTx(*this)) { + AssertLockHeld(cs_main); + if(!CheckFinalTx(*tx)) { LogPrint("instantsend", "CTxLockRequest::IsValid -- Transaction is not final: tx=%s", ToString()); return false; } CAmount nValueIn = 0; - BOOST_FOREACH(const CTxIn& txin, vin) { + int nInstantSendConfirmationsRequired = Params().GetConsensus().nInstantSendConfirmationsRequired; + + for (const auto& txin : tx->vin) { Coin coin; @@ -968,7 +962,7 @@ bool CTxLockRequest::IsValid() const int nTxAge = chainActive.Height() - coin.nHeight + 1; // 1 less than the "send IX" gui requires, in case of a block propagating the network at the time - int nConfirmationsRequired = INSTANTSEND_CONFIRMATIONS_REQUIRED - 1; + int nConfirmationsRequired = nInstantSendConfirmationsRequired - 1; if(nTxAge < nConfirmationsRequired) { LogPrint("instantsend", "CTxLockRequest::IsValid -- outpoint %s too new: nTxAge=%d, nConfirmationsRequired=%d, txid=%s\n", @@ -983,8 +977,8 @@ bool CTxLockRequest::IsValid() const LogPrint("instantsend", "CTxLockRequest::IsValid -- Transaction value too high: nValueIn=%d, tx=%s", nValueIn, ToString()); return false; } - - CAmount nValueOut = GetValueOut(); + + CAmount nValueOut = tx->GetValueOut(); if(nValueIn - nValueOut < GetMinFee()) { LogPrint("instantsend", "CTxLockRequest::IsValid -- did not include enough fees in transaction: fees=%d, tx=%s", nValueOut - nValueIn, ToString()); @@ -997,12 +991,12 @@ bool CTxLockRequest::IsValid() const CAmount CTxLockRequest::GetMinFee() const { CAmount nMinFee = MIN_FEE; - return std::max(nMinFee, CAmount(vin.size() * nMinFee)); + return std::max(nMinFee, CAmount(tx->vin.size() * nMinFee)); } int CTxLockRequest::GetMaxSignatures() const { - return vin.size() * COutPointLock::SIGNATURES_TOTAL; + return tx->vin.size() * COutPointLock::SIGNATURES_TOTAL; } // @@ -1023,7 +1017,7 @@ bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const return false; } - int nLockInputHeight = coin.nHeight + 4; + int nLockInputHeight = coin.nHeight + Params().GetConsensus().nInstantSendConfirmationsRequired - 2; int nRank; int nMinRequiredProtocol = std::max(MIN_INSTANTSEND_PROTO_VERSION, dnpayments.GetMinDynodePaymentsProto()); @@ -1051,17 +1045,17 @@ bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const uint256 CTxLockVote::GetHash() const { - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << txHash; - ss << outpoint; - ss << outpointDynode; - return ss.GetHash(); + return SerializeHash(*this); +} + +uint256 CTxLockVote::GetSignatureHash() const +{ + return GetHash(); } bool CTxLockVote::CheckSignature() const { std::string strError; - std::string strMessage = txHash.ToString() + outpoint.ToStringShort(); dynode_info_t infoDn; @@ -1070,9 +1064,24 @@ bool CTxLockVote::CheckSignature() const return false; } - if(!CMessageSigner::VerifyMessage(infoDn.pubKeyDynode, vchDynodeSignature, strMessage, strError)) { - LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); - return false; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if (!CHashSigner::VerifyHash(hash, infoDn.pubKeyDynode, vchDynodeSignature, strError)) { + // could be a signature in old format + std::string strMessage = txHash.ToString() + outpoint.ToStringShort(); + if(!CMessageSigner::VerifyMessage(infoDn.pubKeyDynode, vchDynodeSignature, strMessage, strError)) { + // nope, not in old format either + LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); + return false; + } + } + } else { + std::string strMessage = txHash.ToString() + outpoint.ToStringShort(); + if(!CMessageSigner::VerifyMessage(infoDn.pubKeyDynode, vchDynodeSignature, strMessage, strError)) { + LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } return true; @@ -1081,16 +1090,31 @@ bool CTxLockVote::CheckSignature() const bool CTxLockVote::Sign() { std::string strError; - std::string strMessage = txHash.ToString() + outpoint.ToStringShort(); - if(!CMessageSigner::SignMessage(strMessage, vchDynodeSignature, activeDynode.keyDynode)) { - LogPrintf("CTxLockVote::Sign -- SignMessage() failed\n"); - return false; - } + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); - if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, vchDynodeSignature, strMessage, strError)) { - LogPrintf("CTxLockVote::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; + if(!CHashSigner::SignHash(hash, activeDynode.keyDynode, vchDynodeSignature)) { + LogPrintf("CTxLockVote::Sign -- SignHash() failed\n"); + return false; + } + + if (!CHashSigner::VerifyHash(hash, activeDynode.pubKeyDynode, vchDynodeSignature, strError)) { + LogPrintf("CTxLockVote::Sign -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = txHash.ToString() + outpoint.ToStringShort(); + + if(!CMessageSigner::SignMessage(strMessage, vchDynodeSignature, activeDynode.keyDynode)) { + LogPrintf("CTxLockVote::Sign -- SignMessage() failed\n"); + return false; + } + + if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, vchDynodeSignature, strMessage, strError)) { + LogPrintf("CTxLockVote::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } return true; @@ -1099,7 +1123,11 @@ bool CTxLockVote::Sign() void CTxLockVote::Relay(CConnman& connman) const { CInv inv(MSG_TXLOCK_VOTE, GetHash()); - connman.RelayInv(inv); + CTxLockRequest request; + if(instantsend.GetTxLockRequest(txHash, request)) + connman.RelayInvFiltered(inv, *request.tx); + else + connman.RelayInv(inv); } bool CTxLockVote::IsExpired(int nHeight) const @@ -1116,7 +1144,7 @@ bool CTxLockVote::IsTimedOut() const bool CTxLockVote::IsFailed() const { return (GetTime() - nTimeCreated > INSTANTSEND_FAILED_TIMEOUT_SECONDS) && !instantsend.IsLockedInstantSendTransaction(GetTxHash()); -} +} // // COutPointLock @@ -1124,19 +1152,14 @@ bool CTxLockVote::IsFailed() const bool COutPointLock::AddVote(const CTxLockVote& vote) { - if(mapDynodeVotes.count(vote.GetDynodeOutpoint())) - return false; - mapDynodeVotes.insert(std::make_pair(vote.GetDynodeOutpoint(), vote)); - return true; + return mapDynodeVotes.emplace(vote.GetDynodeOutpoint(), vote).second; } std::vector COutPointLock::GetVotes() const { std::vector vRet; - std::map::const_iterator itVote = mapDynodeVotes.begin(); - while(itVote != mapDynodeVotes.end()) { - vRet.push_back(itVote->second); - ++itVote; + for (const auto& pair : mapDynodeVotes) { + vRet.push_back(pair.second); } return vRet; } @@ -1148,10 +1171,8 @@ bool COutPointLock::HasDynodeVoted(const COutPoint& outpointDynodeIn) const void COutPointLock::Relay(CConnman& connman) const { - std::map::const_iterator itVote = mapDynodeVotes.begin(); - while(itVote != mapDynodeVotes.end()) { - itVote->second.Relay(connman); - ++itVote; + for (const auto& pair : mapDynodeVotes) { + pair.second.Relay(connman); } } @@ -1182,10 +1203,8 @@ bool CTxLockCandidate::IsAllOutPointsReady() const { if(mapOutPointLocks.empty()) return false; - std::map::const_iterator it = mapOutPointLocks.begin(); - while(it != mapOutPointLocks.end()) { - if(!it->second.IsReady()) return false; - ++it; + for (const auto& pair : mapOutPointLocks) { + if(!pair.second.IsReady()) return false; } return true; } @@ -1200,10 +1219,8 @@ int CTxLockCandidate::CountVotes() const { // Note: do NOT use vote count to figure out if tx is locked, use IsAllOutPointsReady() instead int nCountVotes = 0; - std::map::const_iterator it = mapOutPointLocks.begin(); - while(it != mapOutPointLocks.end()) { - nCountVotes += it->second.CountVotes(); - ++it; + for (const auto& pair : mapOutPointLocks) { + nCountVotes += pair.second.CountVotes(); } return nCountVotes; } @@ -1221,10 +1238,8 @@ bool CTxLockCandidate::IsTimedOut() const void CTxLockCandidate::Relay(CConnman& connman) const { - connman.RelayTransaction(txLockRequest); - std::map::const_iterator itOutpointLock = mapOutPointLocks.begin(); - while(itOutpointLock != mapOutPointLocks.end()) { - itOutpointLock->second.Relay(connman); - ++itOutpointLock; + connman.RelayTransaction(*txLockRequest.tx); + for (const auto& pair : mapOutPointLocks) { + pair.second.Relay(connman); } } diff --git a/src/instantsend.h b/src/instantsend.h index 7988f0debf..9e55d78c15 100644 --- a/src/instantsend.h +++ b/src/instantsend.h @@ -20,14 +20,20 @@ extern CInstantSend instantsend; /* At 15 signatures, 1/2 of the dynode network can be owned by - one party without comprimising the security of InstantSend + one party without compromising the security of InstantSend (1000/2150.0)**10 = 0.00047382219560689856 (1000/2900.0)**10 = 2.3769498616783657e-05 ### getting 5 of 10 signatures w/ 1000 nodes of 2900 (1000/2900.0)**5 = 0.004875397277841433 */ -static const int INSTANTSEND_CONFIRMATIONS_REQUIRED = 11; + +// The INSTANTSEND_DEPTH is the "pseudo block depth" level assigned to locked +// txs to indicate the degree of confidence in their eventual confirmation and +// inability to be double-spent (adjustable via command line argument) +static const int MIN_INSTANTSEND_DEPTH = 0; +static const int MAX_INSTANTSEND_DEPTH = 60; +/// Default number of "pseudo-confirmations" for an InstantSend tx static const int DEFAULT_INSTANTSEND_DEPTH = 10; static const int MIN_INSTANTSEND_PROTO_VERSION = 70900; @@ -46,6 +52,8 @@ extern int nCompleteTXLocks; class CInstantSend { private: + static const std::string SERIALIZATION_VERSION_STRING; + // Keep track of current block height int nCachedBlockHeight; @@ -67,25 +75,56 @@ class CInstantSend void CreateEmptyTxLockCandidate(const uint256& txHash); void Vote(CTxLockCandidate& txLockCandidate, CConnman& connman); - //process consensus vote message - bool ProcessTxLockVote(CNode* pfrom, CTxLockVote& vote, CConnman& connman); - void ProcessOrphanTxLockVotes(CConnman& connman); - bool IsEnoughOrphanVotesForTx(const CTxLockRequest& txLockRequest); - bool IsEnoughOrphanVotesForTxAndOutPoint(const uint256& txHash, const COutPoint& outpoint); + /// Process consensus vote message + bool ProcessNewTxLockVote(CNode* pfrom, const CTxLockVote& vote, CConnman& connman); + + void UpdateVotedOutpoints(const CTxLockVote& vote, CTxLockCandidate& txLockCandidate); + bool ProcessOrphanTxLockVote(const CTxLockVote& vote); + void ProcessOrphanTxLockVotes(); int64_t GetAverageDynodeOrphanVoteTime(); void TryToFinalizeLockCandidate(const CTxLockCandidate& txLockCandidate); void LockTransactionInputs(const CTxLockCandidate& txLockCandidate); - //update UI and notify external script if any + /// Update UI and notify external script if any void UpdateLockedTransaction(const CTxLockCandidate& txLockCandidate); bool ResolveConflicts(const CTxLockCandidate& txLockCandidate); bool IsInstantSendReadyToLock(const uint256 &txHash); public: - CCriticalSection cs_instantsend; + mutable CCriticalSection cs_instantsend; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + std::string strVersion; + if(ser_action.ForRead()) { + READWRITE(strVersion); + } + else { + strVersion = SERIALIZATION_VERSION_STRING; + READWRITE(strVersion); + } + + READWRITE(mapLockRequestAccepted); + READWRITE(mapLockRequestRejected); + READWRITE(mapTxLockVotes); + READWRITE(mapTxLockVotesOrphan); + READWRITE(mapTxLockCandidates); + READWRITE(mapVotedOutpoints); + READWRITE(mapLockedOutpoints); + READWRITE(mapDynodeOrphanVotes); + READWRITE(nCachedBlockHeight); + + if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) { + Clear(); + } + } - void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman); + void Clear(); + + void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); bool ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman); void Vote(const uint256& txHash, CConnman& connman); @@ -101,47 +140,88 @@ class CInstantSend bool GetLockedOutPointTxHash(const COutPoint& outpoint, uint256& hashRet); - // verify if transaction is currently locked + /// Verify if transaction is currently locked bool IsLockedInstantSendTransaction(const uint256& txHash); - // get the actual number of accepted lock signatures + /// Get the actual number of accepted lock signatures int GetTransactionLockSignatures(const uint256& txHash); - // get instantsend confirmations (only) + /// Get instantsend confirmations (only) int GetConfirmations(const uint256 &nTXHash); - // remove expired entries from maps + /// Remove expired entries from maps void CheckAndRemove(); - // verify if transaction lock timed out + /// Verify if transaction lock timed out bool IsTxLockCandidateTimedOut(const uint256& txHash); void Relay(const uint256& txHash, CConnman& connman); void UpdatedBlockTip(const CBlockIndex *pindex); - void SyncTransaction(const CTransaction& tx, const CBlock* pblock); + void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock); + + std::string ToString() const; - std::string ToString(); + void DoMaintenance() { CheckAndRemove(); } }; -class CTxLockRequest : public CTransaction +/** + * An InstantSend transaction lock request. + */ +class CTxLockRequest { private: - static const CAmount MIN_FEE = 0.001 * COIN; + static const CAmount MIN_FEE = 0.0001 * COIN; public: + /// Warn for a large number of inputs to an IS tx - fees could be substantial + /// and the number txlvote responses requested large (10 * # of inputs) static const int WARN_MANY_INPUTS = 100; - CTxLockRequest() = default; - CTxLockRequest(const CTransaction& tx) : CTransaction(tx) {}; + CTransactionRef tx; + + CTxLockRequest() : tx(MakeTransactionRef()) {} + CTxLockRequest(const CTransaction& _tx) : tx(MakeTransactionRef(_tx)) {}; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(tx); + } bool IsValid() const; CAmount GetMinFee() const; int GetMaxSignatures() const; + const uint256 &GetHash() const { + return tx->GetHash(); + } + + std::string ToString() const { + return tx->ToString(); + } + + friend bool operator==(const CTxLockRequest& a, const CTxLockRequest& b) + { + return *a.tx == *b.tx; + } + + friend bool operator!=(const CTxLockRequest& a, const CTxLockRequest& b) + { + return *a.tx != *b.tx; + } + explicit operator bool() const { return *this != CTxLockRequest(); } }; +/** + * An InstantSend transaction lock vote. Sent by a dynode in response to a + * transaction lock request (ix message) to indicate the transaction input can + * be locked. Contains the proposed transaction's hash and the outpoint being + * locked along with the dynodes outpoint and signature. + * @see CTxLockRequest + */ class CTxLockVote { private: @@ -150,7 +230,7 @@ class CTxLockVote COutPoint outpointDynode; std::vector vchDynodeSignature; // local memory only - int nConfirmedHeight; // when corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1 + int nConfirmedHeight; ///< When corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1 int64_t nTimeCreated; public: @@ -179,10 +259,13 @@ class CTxLockVote READWRITE(txHash); READWRITE(outpoint); READWRITE(outpointDynode); - READWRITE(vchDynodeSignature); + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(vchDynodeSignature); + } } uint256 GetHash() const; + uint256 GetSignatureHash() const; uint256 GetTxHash() const { return txHash; } COutPoint GetOutpoint() const { return outpoint; } @@ -200,16 +283,21 @@ class CTxLockVote void Relay(CConnman& connman) const; }; +/** + * An InstantSend OutpointLock. + */ class COutPointLock { private: - COutPoint outpoint; // utxo - std::map mapDynodeVotes; // dynode outpoint - vote + COutPoint outpoint; ///< UTXO + std::map mapDynodeVotes; ///< Dynode outpoint - vote bool fAttacked = false; public: - static const int SIGNATURES_REQUIRED = 11; - static const int SIGNATURES_TOTAL = 20; + static const int SIGNATURES_REQUIRED = 6; + static const int SIGNATURES_TOTAL = 10; + + COutPointLock() {} COutPointLock(const COutPoint& outpointIn) : outpoint(outpointIn), @@ -218,6 +306,15 @@ class COutPointLock COutPoint GetOutpoint() const { return outpoint; } + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(outpoint); + READWRITE(mapDynodeVotes); + READWRITE(fAttacked); + } + bool AddVote(const CTxLockVote& vote); std::vector GetVotes() const; bool HasDynodeVoted(const COutPoint& outpointDynodeIn) const; @@ -228,13 +325,21 @@ class COutPointLock void Relay(CConnman& connman) const; }; +/** + * An InstantSend transaction lock candidate. + */ class CTxLockCandidate { private: - int nConfirmedHeight; // when corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1 + int nConfirmedHeight; /// mapOutPointLocks; + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(txLockRequest); + READWRITE(mapOutPointLocks); + READWRITE(nTimeCreated); + READWRITE(nConfirmedHeight); + } + uint256 GetHash() const { return txLockRequest.GetHash(); } void AddOutPointLock(const COutPoint& outpoint); diff --git a/src/keystore.h b/src/keystore.h index af32779af1..ccf39fe9f4 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -66,9 +66,9 @@ class CBasicKeyStore : public CKeyStore CHDChain hdChain; public: - bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); - bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; - bool HaveKey(const CKeyID &address) const + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override; + bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; + bool HaveKey(const CKeyID &address) const override { bool result; { @@ -77,7 +77,7 @@ class CBasicKeyStore : public CKeyStore } return result; } - void GetKeys(std::set &setAddress) const + void GetKeys(std::set &setAddress) const override { setAddress.clear(); { @@ -90,7 +90,7 @@ class CBasicKeyStore : public CKeyStore } } } - bool GetKey(const CKeyID &address, CKey &keyOut) const + bool GetKey(const CKeyID &address, CKey &keyOut) const override { { LOCK(cs_KeyStore); @@ -103,16 +103,16 @@ class CBasicKeyStore : public CKeyStore } return false; } - virtual bool AddCScript(const CScript& redeemScript); - virtual bool HaveCScript(const CScriptID &hash) const; - virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const; + virtual bool AddCScript(const CScript& redeemScript) override; + virtual bool HaveCScript(const CScriptID &hash) const override; + virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override; - virtual bool AddWatchOnly(const CScript &dest); - virtual bool RemoveWatchOnly(const CScript &dest); - virtual bool HaveWatchOnly(const CScript &dest) const; - virtual bool HaveWatchOnly() const; + virtual bool AddWatchOnly(const CScript &dest) override; + virtual bool RemoveWatchOnly(const CScript &dest) override; + virtual bool HaveWatchOnly(const CScript &dest) const override; + virtual bool HaveWatchOnly() const override; - bool GetHDChain(CHDChain& hdChainRet) const; + virtual bool GetHDChain(CHDChain& hdChainRet) const; }; typedef std::vector > CKeyingMaterial; diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index cfbb6af644..d15212e469 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -23,8 +23,8 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter) for (unsigned int i = 0; i < block.vtx.size(); i++) { - const uint256& hash = block.vtx[i].GetHash(); - if (filter.IsRelevantAndUpdate(block.vtx[i])) + const uint256& hash = block.vtx[i]->GetHash(); + if (filter.IsRelevantAndUpdate(*block.vtx[i])) { vMatch.push_back(true); vMatchedTxn.push_back(std::make_pair(i, hash)); @@ -49,7 +49,7 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, const std::set& txids) for (unsigned int i = 0; i < block.vtx.size(); i++) { - const uint256& hash = block.vtx[i].GetHash(); + const uint256& hash = block.vtx[i]->GetHash(); if (txids.count(hash)) vMatch.push_back(true); else diff --git a/src/messagesigner.cpp b/src/messagesigner.cpp index e73f691f24..36e175a0b5 100644 --- a/src/messagesigner.cpp +++ b/src/messagesigner.cpp @@ -12,7 +12,7 @@ #include "tinyformat.h" #include "utilstrencodings.h" -bool CMessageSigner::GetKeysFromSecret(const std::string strSecret, CKey& keyRet, CPubKey& pubkeyRet) +bool CMessageSigner::GetKeysFromSecret(const std::string& strSecret, CKey& keyRet, CPubKey& pubkeyRet) { CDynamicSecret vchSecret; @@ -24,7 +24,7 @@ bool CMessageSigner::GetKeysFromSecret(const std::string strSecret, CKey& keyRet return true; } -bool CMessageSigner::SignMessage(const std::string strMessage, std::vector& vchSigRet, const CKey key) +bool CMessageSigner::SignMessage(const std::string& strMessage, std::vector& vchSigRet, const CKey& key) { CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; @@ -33,21 +33,31 @@ bool CMessageSigner::SignMessage(const std::string strMessage, std::vector& vchSig, const std::string strMessage, std::string& strErrorRet) +bool CMessageSigner::VerifyMessage(const CPubKey& pubkey, const std::vector& vchSig, const std::string& strMessage, std::string& strErrorRet) +{ + return VerifyMessage(pubkey.GetID(), vchSig, strMessage, strErrorRet); +} + +bool CMessageSigner::VerifyMessage(const CKeyID& keyID, const std::vector& vchSig, const std::string& strMessage, std::string& strErrorRet) { CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; ss << strMessage; - return CHashSigner::VerifyHash(ss.GetHash(), pubkey, vchSig, strErrorRet); + return CHashSigner::VerifyHash(ss.GetHash(), keyID, vchSig, strErrorRet); } -bool CHashSigner::SignHash(const uint256& hash, const CKey key, std::vector& vchSigRet) +bool CHashSigner::SignHash(const uint256& hash, const CKey& key, std::vector& vchSigRet) { return key.SignCompact(hash, vchSigRet); } -bool CHashSigner::VerifyHash(const uint256& hash, const CPubKey pubkey, const std::vector& vchSig, std::string& strErrorRet) +bool CHashSigner::VerifyHash(const uint256& hash, const CPubKey& pubkey, const std::vector& vchSig, std::string& strErrorRet) +{ + return VerifyHash(hash, pubkey.GetID(), vchSig, strErrorRet); +} + +bool CHashSigner::VerifyHash(const uint256& hash, const CKeyID& keyID, const std::vector& vchSig, std::string& strErrorRet) { CPubKey pubkeyFromSig; if(!pubkeyFromSig.RecoverCompact(hash, vchSig)) { @@ -55,9 +65,9 @@ bool CHashSigner::VerifyHash(const uint256& hash, const CPubKey pubkey, const st return false; } - if(pubkeyFromSig.GetID() != pubkey.GetID()) { + if(pubkeyFromSig.GetID() != keyID) { strErrorRet = strprintf("Keys don't match: pubkey=%s, pubkeyFromSig=%s, hash=%s, vchSig=%s", - pubkey.GetID().ToString(), pubkeyFromSig.GetID().ToString(), hash.ToString(), + keyID.ToString(), pubkeyFromSig.GetID().ToString(), hash.ToString(), EncodeBase64(&vchSig[0], vchSig.size())); return false; } diff --git a/src/messagesigner.h b/src/messagesigner.h index 9ecd891f66..38b24ef0ee 100644 --- a/src/messagesigner.h +++ b/src/messagesigner.h @@ -16,11 +16,13 @@ class CMessageSigner { public: /// Set the private/public key values, returns true if successful - static bool GetKeysFromSecret(const std::string strSecret, CKey& keyRet, CPubKey& pubkeyRet); + static bool GetKeysFromSecret(const std::string& strSecret, CKey& keyRet, CPubKey& pubkeyRet); /// Sign the message, returns true if successful - static bool SignMessage(const std::string strMessage, std::vector& vchSigRet, const CKey key); + static bool SignMessage(const std::string& strMessage, std::vector& vchSigRet, const CKey& key); /// Verify the message signature, returns true if succcessful - static bool VerifyMessage(const CPubKey pubkey, const std::vector& vchSig, const std::string strMessage, std::string& strErrorRet); + static bool VerifyMessage(const CPubKey& pubkey, const std::vector& vchSig, const std::string& strMessage, std::string& strErrorRet); + /// Verify the message signature, returns true if succcessful + static bool VerifyMessage(const CKeyID& keyID, const std::vector& vchSig, const std::string& strMessage, std::string& strErrorRet); }; /** Helper class for signing hashes and checking their signatures @@ -29,9 +31,11 @@ class CHashSigner { public: /// Sign the hash, returns true if successful - static bool SignHash(const uint256& hash, const CKey key, std::vector& vchSigRet); + static bool SignHash(const uint256& hash, const CKey& key, std::vector& vchSigRet); + /// Verify the hash signature, returns true if succcessful + static bool VerifyHash(const uint256& hash, const CPubKey& pubkey, const std::vector& vchSig, std::string& strErrorRet); /// Verify the hash signature, returns true if succcessful - static bool VerifyHash(const uint256& hash, const CPubKey pubkey, const std::vector& vchSig, std::string& strErrorRet); + static bool VerifyHash(const uint256& hash, const CKeyID& keyID, const std::vector& vchSig, std::string& strErrorRet); }; #endif \ No newline at end of file diff --git a/src/miner.cpp b/src/miner.cpp index 9c3f047301..33a7c268f3 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -110,7 +110,8 @@ bool CheckWork(const CChainParams& chainparams, const CBlock* pblock, CWallet& w // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(chainparams, pblock, true, NULL, NULL)) + std::shared_ptr shared_pblock = std::make_shared(*pblock); + if (!ProcessNewBlock(chainparams, shared_pblock, true, NULL)) return error("ProcessBlock, block not accepted"); } @@ -134,18 +135,13 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity: - nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE - 1000), nBlockMaxSize)); - + nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); + // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); - // Minimum block size you want to create; block will be filled with free transactions - // until there are no more or the block reaches this size: - unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); - nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); - // Collect memory pool transactions into the block CTxMemPool::setEntries inBlock; CTxMemPool::setEntries waitSet; @@ -174,7 +170,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); // Add our coinbase tx as first transaction - pblock->vtx.push_back(txNew); + pblock->vtx.emplace_back(); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); @@ -239,15 +235,13 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, } unsigned int nTxSize = iter->GetTxSize(); - if (fPriorityBlock && - (nBlockSize + nTxSize >= nBlockPrioritySize || !AllowFree(actualPriority))) { - fPriorityBlock = false; - waitPriMap.clear(); - } - if (!priorityTx && - (iter->GetModifiedFee() < ::minRelayTxFee.GetFee(nTxSize) && nBlockSize >= nBlockMinSize)) { + + // If now that this txs is added we've surpassed our desired priority size + // or have dropped below the AllowFreeThreshold, then we're done adding priority txs + if (nBlockSize >= nBlockPrioritySize || !AllowFree(actualPriority)) { break; } + if (nBlockSize + nTxSize >= nBlockMaxSize) { if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) { break; @@ -271,15 +265,16 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, continue; } - CAmount nTxFees = iter->GetFee(); - pblock->vtx.push_back(tx); - - pblocktemplate->vTxFees.push_back(nTxFees); - pblocktemplate->vTxSigOps.push_back(nTxSigOps); - nBlockSize += nTxSize; + // Add dummy coinbase tx as first transaction + pblock->vtx.emplace_back(); + pblocktemplate->vTxFees.push_back(-1); // updated at end + pblocktemplate->vTxSigOps.push_back(-1); // updated at end + + nBlockSize += iter->GetTxSize(); ++nBlockTx; - nBlockSigOps += nTxSigOps; - nFees += nTxFees; + nBlockSigOps += iter->GetSigOpCount(); + nFees += iter->GetFee(); + inBlock.insert(iter); if (fPrintPriority) { double dPriority = iter->GetPriority(nHeight); @@ -315,24 +310,28 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, CFluidMint fluidMint; bool areWeMinting = GetMintingInstructions(nHeight, fluidMint); - // Compute regular coinbase transaction. - txNew.vout[0].scriptPubKey = scriptPubKeyIn; + // Create coinbase transaction. + CMutableTransaction coinbaseTx; + coinbaseTx.vin.resize(1); + coinbaseTx.vin[0].prevout.SetNull(); + coinbaseTx.vout.resize(1); + coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn; if (areWeMinting) { mintAddress = fluidMint.GetDestinationAddress(); fluidIssuance = fluidMint.MintAmount; - txNew.vout[0].nValue = blockReward + fluidIssuance; + coinbaseTx.vout[0].nValue = blockReward + fluidIssuance; } else { - txNew.vout[0].nValue = blockReward; + coinbaseTx.vout[0].nValue = blockReward; } - txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; + coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; CScript script; if (areWeMinting) { // Pick out the amount of issuance - txNew.vout[0].nValue -= fluidIssuance; + coinbaseTx.vout[0].nValue -= fluidIssuance; assert(mintAddress.IsValid()); if (!mintAddress.IsScript()) { @@ -341,13 +340,13 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, CScriptID fluidScriptID = boost::get(mintAddress.Get()); script = CScript() << OP_HASH160 << ToByteVector(fluidScriptID) << OP_EQUAL; } - txNew.vout.push_back(CTxOut(fluidIssuance, script)); + coinbaseTx.vout.push_back(CTxOut(fluidIssuance, script)); LogPrintf("CreateNewBlock(): Generated Fluid Issuance Transaction:\n%s\n", txNew.ToString()); } // Update coinbase transaction with additional info about dynode and governance payments, // get some info back to pass to getblocktemplate - FillBlockPayments(txNew, nHeight, pblock->txoutDynode, pblock->voutSuperblock); + FillBlockPayments(coinbaseTx, nHeight, blockReward, pblock->txoutDynode, pblock->voutSuperblock); // LogPrintf("CreateNewBlock -- nBlockHeight %d blockReward %lld txoutDynode %s txNew %s", // nHeight, blockReward, pblock->txoutDynode.ToString(), txNew.ToString()); @@ -359,7 +358,7 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, LogPrintf("CreateNewBlock(): Computed Miner Block Reward is %ld DYN\n", FormatMoney(blockAmount)); // Update block coinbase - pblock->vtx[0] = txNew; + pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); pblocktemplate->vTxFees[0] = -nFees; // Fill in header @@ -367,7 +366,8 @@ std::unique_ptr CreateNewBlock(const CChainParams& chainparams, UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; - pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); + pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]); + CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { LogPrintf("CreateNewBlock(): Generated Transaction:\n%s\n", txNew.ToString()); @@ -388,11 +388,11 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned } ++nExtraNonce; unsigned int nHeight = pindexPrev->nHeight + 1; // Height first in coinbase required for block.version=2 - CMutableTransaction txCoinbase(pblock->vtx[0]); + CMutableTransaction txCoinbase(*pblock->vtx[0]); txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; assert(txCoinbase.vin[0].scriptSig.size() <= 100); - pblock->vtx[0] = txCoinbase; + pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); } @@ -460,7 +460,7 @@ int64_t GetGPUHashRate() static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams, CConnman* connman) { LogPrintf("%s\n", pblock->ToString()); - LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); + LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0]->vout[0].nValue)); // Found a solution { @@ -474,7 +474,8 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(chainparams, pblock, true, NULL, NULL)) + std::shared_ptr shared_pblock = std::make_shared(*pblock); + if (!ProcessNewBlock(chainparams, shared_pblock, true, NULL)) return error("ProcessBlockFound -- ProcessNewBlock() failed, block not accepted"); return true; diff --git a/src/net.cpp b/src/net.cpp index 564e297e63..bf0f092dcd 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -20,6 +20,7 @@ #include "hash.h" #include "primitives/transaction.h" #include "netbase.h" +#include "netmessagemaker.h" #include "scheduler.h" #include "ui_interface.h" #include "utilstrencodings.h" @@ -83,7 +84,6 @@ bool fRelayTxes = true; CCriticalSection cs_mapLocalHost; std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; -static CNode* pnodeLocalHost = NULL; std::string strSubVersion; boost::array vnThreadsRunning; @@ -177,8 +177,9 @@ int GetnScore(const CService& addr) // Is our peer's addrLocal potentially useful as an external IP source? bool IsPeerAddrLocalGood(CNode *pnode) { - return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() && - !IsLimited(pnode->addrLocal.GetNetwork()); + CService addrLocal = pnode->GetAddrLocal(); + return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() && + !IsLimited(addrLocal.GetNetwork()); } // pushes our own address to a peer @@ -193,7 +194,7 @@ void AdvertiseLocal(CNode *pnode) if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() || GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0)) { - addrLocal.SetIP(pnode->addrLocal); + addrLocal.SetIP(pnode->GetAddrLocal()); } if (addrLocal.IsRoutable()) { @@ -345,31 +346,20 @@ bool CConnman::CheckIncomingNonce(uint64_t nonce) return true; } -CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool fConnectToDynode) +CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { - // TODO: This is different from what we have in Bitcoin which only calls ConnectNode from OpenNetworkConnection - // If we ever switch to using OpenNetworkConnection for DNs as well, this can be removed - if (!fNetworkActive) { - return NULL; - } - if (pszDest == NULL) { - // we clean dynode connections in CDynodeMan::ProcessDynodeConnections() - // so should be safe to skip this and connect to local Hot DN on CActiveDynode::ManageState() - if (IsLocal(addrConnect) && !fConnectToDynode) + bool fAllowLocal = Params().AllowMultiplePorts() && addrConnect.GetPort() != GetListenPort(); + if (!fAllowLocal && IsLocal(addrConnect)) { return NULL; + } // Look for an existing connection CNode* pnode = FindNode((CService)addrConnect); if (pnode) { - // we have existing connection to this node but it was not a connection to dynode, - // change flag and add reference so that we can correctly clear it later - if(fConnectToDynode && !pnode->fDynode) { - pnode->AddRef(); - pnode->fDynode = true; - } - return pnode; + LogPrintf("Failed to open new connection, already connected\n"); + return NULL; } } @@ -399,17 +389,10 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo CNode* pnode = FindNode((CService)addrConnect); if (pnode) { - // we have existing connection to this node but it was not a connection to dynode, - // change flag and add reference so that we can correctly clear it later - if(fConnectToDynode && !pnode->fDynode) { - pnode->AddRef(); - pnode->fDynode = true; - } - if (pnode->addrName.empty()) { - pnode->addrName = std::string(pszDest); - } + pnode->MaybeSetAddrName(std::string(pszDest)); CloseSocket(hSocket); - return pnode; + LogPrintf("Failed to open new connection, already connected\n"); + return NULL; } } @@ -418,18 +401,11 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo // Add node NodeId id = GetNewNodeId(); uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); - CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false, true); + CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false); pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); - pnode->nTimeConnected = GetSystemTimeInSeconds(); - if(fConnectToDynode) { - pnode->AddRef(); - pnode->fDynode = true; - } + pnode->AddRef(); - GetNodeSignals().InitializeNode(pnode, *this); - LOCK(cs_vNodes); - vNodes.push_back(pnode); return pnode; } else if (!proxyConnectionFailed) { @@ -618,7 +594,6 @@ void CConnman::SetBannedSetDirty(bool dirty) setBannedIsDirty = dirty; } - bool CConnman::IsWhitelistedRange(const CNetAddr &addr) { LOCK(cs_vWhitelistedRange); BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) { @@ -633,6 +608,33 @@ void CConnman::AddWhitelistedRange(const CSubNet &subnet) { vWhitelistedRange.push_back(subnet); } + +std::string CNode::GetAddrName() const { + LOCK(cs_addrName); + return addrName; +} + +void CNode::MaybeSetAddrName(const std::string& addrNameIn) { + LOCK(cs_addrName); + if (addrName.empty()) { + addrName = addrNameIn; + } +} + +CService CNode::GetAddrLocal() const { + LOCK(cs_addrLocal); + return addrLocal; +} + +void CNode::SetAddrLocal(const CService& addrLocalIn) { + LOCK(cs_addrLocal); + if (addrLocal.IsValid()) { + error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString()); + } else { + addrLocal = addrLocalIn; + } +} + #undef X #define X(name) stats.name = name void CNode::copyStats(CNodeStats &stats) @@ -640,22 +642,36 @@ void CNode::copyStats(CNodeStats &stats) stats.nodeid = this->GetId(); X(nServices); X(addr); - X(fRelayTxes); + { + LOCK(cs_filter); + X(fRelayTxes); + } X(nLastSend); X(nLastRecv); X(nTimeConnected); X(nTimeOffset); - X(addrName); + stats.addrName = GetAddrName(); X(nVersion); - X(cleanSubVer); + { + LOCK(cs_SubVer); + X(cleanSubVer); + } X(fInbound); + X(fAddnode); X(nStartingHeight); - X(nSendBytes); - X(mapSendBytesPerMsgCmd); - X(nRecvBytes); - X(mapRecvBytesPerMsgCmd); + { + LOCK(cs_vSend); + X(mapSendBytesPerMsgCmd); + X(nSendBytes); + } + { + LOCK(cs_vRecv); + X(mapRecvBytesPerMsgCmd); + X(nRecvBytes); + } X(fWhitelisted); + // It is common for nodes with good ping times to suddenly become lagged, // due to a new block arriving or other large transfer. // Merely reporting pingtime might fool the caller into thinking the node was still responsive, @@ -673,7 +689,8 @@ void CNode::copyStats(CNodeStats &stats) stats.dPingWait = (((double)nPingUsecWait) / 1e6); // Leave string empty if addrLocal invalid (not filled in yet) - stats.addrLocal = addrLocal.IsValid() ? addrLocal.ToString() : ""; + CService addrLocalUnlocked = GetAddrLocal(); + stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : ""; } #undef X @@ -681,6 +698,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete { complete = false; int64_t nTimeMicros = GetTimeMicros(); + LOCK(cs_vRecv); nLastRecv = nTimeMicros / 1000000; nRecvBytes += nBytes; while (nBytes > 0) { @@ -812,13 +830,13 @@ const uint256& CNetMessage::GetMessageHash() const } // requires LOCK(cs_vSend) -size_t CConnman::SocketSendData(CNode *pnode) +size_t CConnman::SocketSendData(CNode *pnode) const { - std::deque::iterator it = pnode->vSendMsg.begin(); + auto it = pnode->vSendMsg.begin(); size_t nSentSize = 0; while (it != pnode->vSendMsg.end()) { - const CSerializeData &data = *it; + const auto &data = *it; assert(data.size() > pnode->nSendOffset); int nBytes = 0; { @@ -1114,8 +1132,8 @@ void CConnman::ThreadSocketHandler() { if (pnode->fDisconnect) { - LogPrintf("ThreadSocketHandler -- removing node: peer=%d addr=%s nRefCount=%d fNetworkNode=%d fInbound=%d fDynode=%d\n", - pnode->id, pnode->addr.ToString(), pnode->GetRefCount(), pnode->fNetworkNode, pnode->fInbound, pnode->fDynode); + LogPrintf("ThreadSocketHandler -- removing node: peer=%d addr=%s nRefCount=%d fInbound=%d fDynode=%d\n", + pnode->id, pnode->addr.ToString(), pnode->GetRefCount(), pnode->fInbound, pnode->fDynode); // remove from vNodes vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); @@ -1128,10 +1146,7 @@ void CConnman::ThreadSocketHandler() pnode->CloseSocketDisconnect(); // hold in disconnected pool until all refs are released - if (pnode->fNetworkNode || pnode->fInbound) - pnode->Release(); - if (pnode->fDynode) - pnode->Release(); + pnode->Release(); vNodesDisconnected.push_back(pnode); } } @@ -1154,8 +1169,7 @@ void CConnman::ThreadSocketHandler() fDelete = true; } } - if (fDelete) - { + if (fDelete) { vNodesDisconnected.remove(pnode); DeleteNode(pnode); } @@ -1542,13 +1556,20 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe void CConnman::ThreadDNSAddressSeed() { // goal: only query DNS seeds if address need is acute + // Avoiding DNS seeds when we don't need them improves user privacy by + // creating fewer identifying DNS requests, reduces trust by giving seeds + // less influence on the network topology, and reduces traffic to the seeds. if ((addrman.size() > 0) && (!GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) { if (!interruptNet.sleep_for(std::chrono::seconds(11))) return; LOCK(cs_vNodes); - if (vNodes.size() >= 2) { + int nRelevant = 0; + for (auto pnode : vNodes) { + nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices); + } + if (nRelevant >= 2) { LogPrintf("P2P peers available. Skipped DNS seeding.\n"); return; } @@ -1560,6 +1581,9 @@ void CConnman::ThreadDNSAddressSeed() LogPrintf("Loading addresses from DNS seeds (could take a while)\n"); BOOST_FOREACH(const CDNSSeedData &seed, vSeeds) { + if (interruptNet) { + return; + } if (HaveNameProxy()) { AddOneShot(seed.host); } else { @@ -1577,6 +1601,9 @@ void CConnman::ThreadDNSAddressSeed() found++; } } + if (interruptNet) { + return; + } // TODO: The seed name resolve may fail, yielding an IP of [::], which results in // addrman assigning the same source to results from different seeds. // This should switch to a hard-coded stable dummy IP for each seed name, so that the @@ -1698,11 +1725,22 @@ void CConnman::ThreadOpenConnections() // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. // This is only done for mainnet and testnet int nOutbound = 0; + int nOutboundRelevant = 0; std::set > setConnected; if (!Params().AllowMultipleAddressesFromGroup()) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - if (!pnode->fInbound && !pnode->fDynode) { + if (!pnode->fInbound && !pnode->fAddnode && !pnode->fDynode) { + + // Count the peers that have all relevant services + if (pnode->fSuccessfullyConnected && !pnode->fFeeler && ((pnode->nServices & nRelevantServices) == nRelevantServices)) { + nOutboundRelevant++; + } + // Netgroups for inbound and addnode peers are not excluded because our goal here + // is to not use multiple of our limited outbound slots on a single netgroup + // but inbound and addnode peers do not use our outbound slots. Inbound peers + // also have the added issue that they're attacker controlled and could be used + // to prevent us from connecting to particular hosts if we used them here. setConnected.insert(pnode->addr.GetGroup()); nOutbound++; } @@ -1739,7 +1777,12 @@ void CConnman::ThreadOpenConnections() CAddrInfo addr = addrman.Select(fFeeler); // if we selected an invalid address, restart - if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) + if (!addr.IsValid() || setConnected.count(addr.GetGroup())) + break; + + // if we selected a local address, restart (local addresses are allowed in regtest and devnet) + bool fAllowLocal = Params().AllowMultiplePorts() && addrConnect.GetPort() != GetListenPort(); + if (!fAllowLocal && IsLocal(addrConnect)) break; // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman, @@ -1760,11 +1803,28 @@ void CConnman::ThreadOpenConnections() if (nANow - addr.nLastTry < 600 && nTries < 30) continue; + // only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up. + ServiceFlags nRequiredServices = nRelevantServices; + if (nTries >= 40 && nOutbound < (nMaxOutbound >> 1)) { + nRequiredServices = REQUIRED_SERVICES; + } + + if ((addr.nServices & nRequiredServices) != nRequiredServices) { + continue; + } + // do not allow non-default ports, unless after 50 invalid addresses selected already - if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50) + if (addr.GetPort() != Params().GetDefaultPort() && addr.GetPort() != GetListenPort() && nTries < 50) continue; addrConnect = addr; + + // regardless of the services assumed to be available, only require the minimum if half or more outbound have relevant services + if (nOutboundRelevant >= (nMaxOutbound >> 1)) { + addrConnect.nServices = REQUIRED_SERVICES; + } else { + addrConnect.nServices = nRequiredServices; + } break; } @@ -1805,6 +1865,7 @@ std::vector CConnman::GetAddedNodeInfo() if (pnode->addr.IsValid()) { mapConnected[pnode->addr] = pnode->fInbound; } + std::string addrName = pnode->GetAddrName(); if (!pnode->addrName.empty()) { mapConnectedByName[pnode->addrName] = std::make_pair(pnode->fInbound, static_cast(pnode->addr)); } @@ -1843,26 +1904,34 @@ void CConnman::ThreadOpenAddedConnections() vAddedNodes = mapMultiArgs.at("-addnode"); } - for (unsigned int i = 0; true; i++) + while (true) { + CSemaphoreGrant grant(*semAddnode); std::vector vInfo = GetAddedNodeInfo(); + bool tried = false; for (const AddedNodeInfo& info : vInfo) { if (!info.fConnected) { - CSemaphoreGrant grant(*semOutbound); + if (!grant.TryAcquire()) { + // If we've used up our semaphore and need a new one, lets not wait here since while we are waiting + // the addednodeinfo state might change. + break; + } // If strAddedNode is an IP/port, decode it immediately, so // OpenNetworkConnection can detect existing connections to that IP/port. + tried = true; CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort())); - OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false); + OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true); if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) return; } } - if (!interruptNet.sleep_for(std::chrono::minutes(2))) + // Retry every 60 seconds if a connection was attempted, otherwise two seconds + if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2))) return; } } -void CConnman::ThreadDnbRequestConnections() +void CConnman::ThreadOpenDynodeConnections() { // Connecting to specific addresses, no dynode connections available if (IsArgSet("-connect") && mapMultiArgs.at("-connect").size() > 0) @@ -1877,36 +1946,35 @@ void CConnman::ThreadDnbRequestConnections() if (interruptNet) return; - std::pair > p = dnodeman.PopScheduledDnbRequestConnection(); - if(p.first == CService() || p.second.empty()) continue; - - ConnectNode(CAddress(p.first, NODE_NETWORK), NULL, false, true); + // NOTE: Process only one pending dynode at a time - LOCK(cs_vNodes); - - CNode *pnode = FindNode(p.first); - if(!pnode || pnode->fDisconnect) continue; - - grant.MoveTo(pnode->grantDynodeOutbound); + LOCK(cs_vPendingDynodes); + if (vPendingDynodes.empty()) { + // nothing to do, keep waiting + continue; + } - // compile request vector - std::vector vToFetch; - std::set::iterator it = p.second.begin(); - while(it != p.second.end()) { - if(*it != uint256()) { - vToFetch.push_back(CInv(MSG_DYNODE_ANNOUNCE, *it)); - LogPrint("dynode", "ThreadDnbRequestConnections -- asking for dnb %s from addr=%s\n", it->ToString(), p.first.ToString()); - } - ++it; + const CService addr = vPendingDynodes.front(); + vPendingDynodes.erase(vPendingDynodes.begin()); + if (IsDynodeOrDisconnectRequested(addr)) { + // nothing to do, try the next one + continue; } - // ask for data - PushMessage(pnode, NetMsgType::GETDATA, vToFetch); + OpenDynodeConnection(CAddress(addr, NODE_NETWORK)); + // should be in the list now if connection was opened + ForNode(addr, CConnman::AllNodes, [&](CNode* pnode) { + if (pnode->fDisconnect) { + return false; + } + grant.MoveTo(pnode->grantDynodeOutbound); + return true; + }); } } // if successful, this moves the passed grant to the constructed node -bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler) +bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode, bool fConnectToDynode) { // // Initiate outbound network connection @@ -1918,9 +1986,16 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai return false; } if (!pszDest) { - if (IsLocal(addrConnect) || - FindNode((CNetAddr)addrConnect) || IsBanned(addrConnect) || - FindNode(addrConnect.ToStringIPPort())) + // banned or exact match? + if (IsBanned(addrConnect) || FindNode(addrConnect.ToStringIPPort())) + return false; + // local and not a connection to itself? + bool fAllowLocal = Params().AllowMultiplePorts() && addrConnect.GetPort() != GetListenPort(); + if (!fAllowLocal && IsLocal(addrConnect)) + return false; + // if multiple ports for same IP are allowed, search for IP:PORT match, otherwise search for IP-only match + if ((!Params().AllowMultiplePorts() && FindNode((CNetAddr)addrConnect)) || + (Params().AllowMultiplePorts() && FindNode((CService)addrConnect))) return false; } else if (FindNode(std::string(pszDest))) return false; @@ -1935,10 +2010,24 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai pnode->fOneShot = true; if (fFeeler) pnode->fFeeler = true; + if (fAddnode) + pnode->fAddnode = true; + if (fConnectToDynode) + pnode->fDynode = true; + + GetNodeSignals().InitializeNode(pnode, *this); + { + LOCK(cs_vNodes); + vNodes.push_back(pnode); + } return true; } +bool CConnman::OpenDynodeConnection(const CAddress &addrConnect) { + return OpenNetworkConnection(addrConnect, false, NULL, NULL, false, false, false, true); +} + void CConnman::ThreadMessageHandler() { while (!flagInterruptMsgProc) @@ -1960,9 +2049,8 @@ void CConnman::ThreadMessageHandler() // Send messages { - TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend) - GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); + LOCK(pnode->cs_sendProcessing); + GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); } if (flagInterruptMsgProc) return; @@ -2151,7 +2239,9 @@ void CConnman::SetNetworkActive(bool active) } } -CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In) +CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : + addrman(Params().AllowMultiplePorts()), + nSeed0(nSeed0In), nSeed1(nSeed1In) { fNetworkActive = true; setBannedIsDirty = false; @@ -2160,9 +2250,11 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe nSendBufferMaxSize = 0; nReceiveFloodSize = 0; semOutbound = NULL; + semAddnode = NULL; semDynodeOutbound = NULL; nMaxConnections = 0; nMaxOutbound = 0; + nMaxAddnode = 0; nBestHeight = 0; clientInterface = NULL; flagInterruptMsgProc = false; @@ -2184,6 +2276,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c nLocalServices = connOptions.nLocalServices; nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); + nMaxAddnode = connOptions.nMaxAddnode; nMaxFeeler = connOptions.nMaxFeeler; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; @@ -2228,29 +2321,24 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c DumpBanlist(); } + uiInterface.InitMessage(_("Starting network threads...")); + fAddressesInitialized = true; if (semOutbound == NULL) { // initialize semaphore semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); } + if (semAddnode == NULL) { + // initialize semaphore + semAddnode = new CSemaphore(nMaxAddnode); + } if (semDynodeOutbound == NULL) { // initialize semaphore semDynodeOutbound = new CSemaphore(MAX_OUTBOUND_DYNODE_CONNECTIONS); } - if (pnodeLocalHost == NULL) { - CNetAddr local; - LookupHost("127.0.0.1", local, false); - - NodeId id = GetNewNodeId(); - uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); - - pnodeLocalHost = new CNode(id, nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0, nonce); - GetNodeSignals().InitializeNode(pnodeLocalHost, *this); - } - // // Start threads // @@ -2279,7 +2367,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c threadOpenConnections = std::thread(&TraceThread >, "opencon", std::function(std::bind(&CConnman::ThreadOpenConnections, this))); // Initiate dynode connections - threadDnbRequestConnections = std::thread(&TraceThread >, "dnbcon", std::function(std::bind(&CConnman::ThreadDnbRequestConnections, this))); + threadOpenDynodeConnections = std::thread(&TraceThread >, "dncon", std::function(std::bind(&CConnman::ThreadOpenDynodeConnections, this))); // Process messages threadMessageHandler = std::thread(&TraceThread >, "msghand", std::function(std::bind(&CConnman::ThreadMessageHandler, this))); @@ -2324,17 +2412,31 @@ void CConnman::Interrupt() interruptNet(); InterruptSocks5(true); - if (semOutbound) - for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) + if (semOutbound) { + for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) { semOutbound->post(); + } + } + + if (semAddnode) { + for (int i=0; ipost(); + } + } + + if (semDynodeOutbound) { + for (int i=0; ipost(); + } + } } void CConnman::Stop() { if (threadMessageHandler.joinable()) threadMessageHandler.join(); - if (threadDnbRequestConnections.joinable()) - threadDnbRequestConnections.join(); + if (threadOpenDynodeConnections.joinable()) + threadOpenDynodeConnections.join(); if (threadOpenConnections.joinable()) threadOpenConnections.join(); if (threadOpenAddedConnections.joinable()) @@ -2344,10 +2446,6 @@ void CConnman::Stop() if (threadSocketHandler.joinable()) threadSocketHandler.join(); - if (semDynodeOutbound) - for (int i=0; ipost(); - if (fAddressesInitialized) { DumpData(); @@ -2374,11 +2472,10 @@ void CConnman::Stop() vhListenSocket.clear(); delete semOutbound; semOutbound = NULL; + delete semAddnode; + semAddnode = NULL; delete semDynodeOutbound; semDynodeOutbound = NULL; - if(pnodeLocalHost) - DeleteNode(pnodeLocalHost); - pnodeLocalHost = NULL; } void CConnman::DeleteNode(CNode* pnode) @@ -2451,6 +2548,18 @@ bool CConnman::RemoveAddedNode(const std::string& strNode) return false; } +bool CConnman::AddPendingDynode(const CService& service) +{ + LOCK(cs_vPendingDynodes); + for(std::vector::const_iterator it = vPendingDynodes.begin(); it != vPendingDynodes.end(); ++it) { + if (service == *it) + return false; + } + + vPendingDynodes.push_back(service); + return true; +} + size_t CConnman::GetNodeCount(NumConnections flags) { LOCK(cs_vNodes); @@ -2472,9 +2581,8 @@ void CConnman::GetNodeStats(std::vector& vstats) vstats.reserve(vNodes.size()); for(std::vector::iterator it = vNodes.begin(); it != vNodes.end(); ++it) { CNode* pnode = *it; - CNodeStats stats; - pnode->copyStats(stats); - vstats.push_back(stats); + vstats.emplace_back(); + pnode->copyStats(vstats.back()); } } @@ -2514,11 +2622,26 @@ void CConnman::RelayTransaction(const CTransaction& tx) void CConnman::RelayInv(CInv &inv, const int minProtoVersion) { LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) + for (const auto& pnode : vNodes) if(pnode->nVersion >= minProtoVersion) pnode->PushInventory(inv); } +void CConnman::RelayInvFiltered(CInv &inv, const CTransaction& relatedTx, const int minProtoVersion) +{ + LOCK(cs_vNodes); + for (const auto& pnode : vNodes) { + if(pnode->nVersion < minProtoVersion) + continue; + { + LOCK(pnode->cs_filter); + if(pnode->pfilter && !pnode->pfilter->IsRelevantAndUpdate(relatedTx)) + continue; + } + pnode->PushInventory(inv); + } +} + void CConnman::RecordBytesRecv(uint64_t bytes) { LOCK(cs_totalBytesRecv); @@ -2645,7 +2768,8 @@ int CConnman::GetBestHeight() const unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string& addrNameIn, bool fInboundIn, bool fNetworkNodeIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string& addrNameIn, bool fInboundIn) : + nTimeConnected(GetSystemTimeInSeconds()), addr(addrIn), fInbound(fInboundIn), id(idIn), @@ -2665,7 +2789,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nLastRecv = 0; nSendBytes = 0; nRecvBytes = 0; - nTimeConnected = GetSystemTimeInSeconds(); nTimeOffset = 0; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; @@ -2676,7 +2799,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn fOneShot = false; fClient = false; // set by version message fFeeler = false; - fNetworkNode = fNetworkNodeIn; fSuccessfullyConnected = false; fDisconnect = false; nRefCount = 0; @@ -2702,9 +2824,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn fPingQueued = false; fDynode = false; nMinPingUsecTime = std::numeric_limits::max(); - minFeeFilter = 0; - lastSentFeeFilter = 0; - nextSendTimeFeeFilter = 0; fPauseRecv = false; fPauseSend = false; nProcessQueueSize = 0; @@ -2713,9 +2832,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; - if(fNetworkNode || fInbound) - AddRef(); - if (fLogIPs) LogPrint("net", "Added connection to %s peer=%d\n", addrName, id); else @@ -2781,43 +2897,34 @@ bool CConnman::NodeFullyConnected(const CNode* pnode) return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect; } -CDataStream CConnman::BeginMessage(CNode* pnode, int nVersion, int flags, const std::string& sCommand) -{ - return {SER_NETWORK, (nVersion ? nVersion : pnode->GetSendVersion()) | flags, CMessageHeader(Params().MessageStart(), sCommand.c_str(), 0) }; -} - -void CConnman::EndMessage(CDataStream& strm) +void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) { - // Set the size - assert(strm.size () >= CMessageHeader::HEADER_SIZE); - unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE; - WriteLE32((uint8_t*)&strm[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); - // Set the checksum - uint256 hash = Hash(strm.begin() + CMessageHeader::HEADER_SIZE, strm.end()); - memcpy((char*)&strm[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE); + size_t nMessageSize = msg.data.size(); + size_t nTotalSize = nMessageSize + CMessageHeader::HEADER_SIZE; + LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.command.c_str()), nMessageSize, pnode->id); -} - -void CConnman::PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand) -{ - if(strm.empty()) - return; + std::vector serializedHeader; + serializedHeader.reserve(CMessageHeader::HEADER_SIZE); + uint256 hash = Hash(msg.data.data(), msg.data.data() + nMessageSize); + CMessageHeader hdr(Params().MessageStart(), msg.command.c_str(), nMessageSize); + memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE); - unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE; - LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(sCommand.c_str()), nSize, pnode->id); + CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, serializedHeader, 0, hdr}; size_t nBytesSent = 0; { LOCK(pnode->cs_vSend); bool optimisticSend(pnode->vSendMsg.empty()); - pnode->vSendMsg.emplace_back(strm.begin(), strm.end()); //log total amount of bytes per command - pnode->mapSendBytesPerMsgCmd[sCommand] += strm.size(); - pnode->nSendSize += strm.size(); + pnode->mapSendBytesPerMsgCmd[msg.command] += nTotalSize; + pnode->nSendSize += nTotalSize; if (pnode->nSendSize > nSendBufferMaxSize) pnode->fPauseSend = true; + pnode->vSendMsg.push_back(std::move(serializedHeader)); + if (nMessageSize) + pnode->vSendMsg.push_back(std::move(msg.data)); // If write queue empty, attempt "optimistic write" if (optimisticSend == true) @@ -2853,22 +2960,35 @@ bool CConnman::ForNode(NodeId id, std::function cond, return found != nullptr && cond(found) && func(found); } +bool CConnman::IsDynodeOrDisconnectRequested(const CService& addr) { + return ForNode(addr, AllNodes, [](CNode* pnode){ + return pnode->fDynode || pnode->fDisconnect; + }); +} + int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -std::vector CConnman::CopyNodeVector() +std::vector CConnman::CopyNodeVector(std::function cond) { std::vector vecNodesCopy; LOCK(cs_vNodes); for(size_t i = 0; i < vNodes.size(); ++i) { CNode* pnode = vNodes[i]; + if (!cond(pnode)) + continue; pnode->AddRef(); vecNodesCopy.push_back(pnode); } return vecNodesCopy; } +std::vector CConnman::CopyNodeVector() +{ + return CopyNodeVector(AllNodes); +} + void CConnman::ReleaseNodeVector(const std::vector& vecNodes) { LOCK(cs_vNodes); @@ -2878,12 +2998,12 @@ void CConnman::ReleaseNodeVector(const std::vector& vecNodes) } } -CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) +CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const { return CSipHasher(nSeed0, nSeed1).Write(id); } -uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) +uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const { std::vector vchNetGroup(ad.GetGroup()); diff --git a/src/net.h b/src/net.h index c489afb3ed..1810d172a5 100644 --- a/src/net.h +++ b/src/net.h @@ -66,6 +66,8 @@ static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024; static const unsigned int MAX_SUBVERSION_LENGTH = 256; /** Maximum number of outgoing nodes */ static const int MAX_OUTBOUND_CONNECTIONS = 16; +/** Maximum number of addnode outgoing nodes */ +static const int MAX_ADDNODE_CONNECTIONS = 16; /** Maximum number if outgoing dynodes */ static const int MAX_OUTBOUND_DYNODE_CONNECTIONS = 21; /** -listen default */ @@ -95,15 +97,15 @@ static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000; static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK; +// NOTE: When adjusting this, update rpcnet:setban's help ("24h") +static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban + // This seems like a bit too much adjusting enum threadId { THREAD_NTP, THREAD_MAX }; -// NOTE: When adjusting this, update rpcnet:setban's help ("24h") -static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban - typedef int NodeId; struct AddedNodeInfo @@ -118,6 +120,19 @@ class CTransaction; class CNodeStats; class CClientUIInterface; +struct CSerializedNetMsg +{ + CSerializedNetMsg() = default; + CSerializedNetMsg(CSerializedNetMsg&&) = default; + CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default; + // No copying, only moves. + CSerializedNetMsg(const CSerializedNetMsg& msg) = delete; + CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete; + + std::vector data; + std::string command; +}; + class CConnman { public: @@ -135,6 +150,7 @@ class CConnman ServiceFlags nRelevantServices = NODE_NONE; int nMaxConnections = 0; int nMaxOutbound = 0; + int nMaxAddnode = 0; int nMaxFeeler = 0; int nBestHeight = 0; CClientUIInterface* uiInterface = nullptr; @@ -151,15 +167,10 @@ class CConnman bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool GetNetworkActive() const { return fNetworkActive; }; void SetNetworkActive(bool active); - bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); + bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false, bool fConnectToDynode = false); + bool OpenDynodeConnection(const CAddress& addrConnect); bool CheckIncomingNonce(uint64_t nonce); - // fConnectToDynode should be 'true' only if you want this node to allow to connect to itself - // and/or you want it to be disconnected on CDynodeMan::ProcessDynodeConnections() - // Unfortunately, can't make this method private like in Bitcoin, - // because it's used in many Dynamic-specific places (dynode, privatesend). - CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL, bool fCountFailure = false, bool fConnectToDynode = false); - struct CFullyConnectedOnly { bool operator() (const CNode* pnode) const { return NodeFullyConnected(pnode); @@ -189,32 +200,16 @@ class CConnman return ForNode(id, FullyConnectedOnly, func); } - template - void PushMessageWithVersionAndFlag(CNode* pnode, int nVersion, int flag, const std::string& sCommand, Args&&... args) + bool IsConnected(const CService& addr, std::function cond) { - auto msg(BeginMessage(pnode, nVersion, flag, sCommand)); - ::SerializeMany(msg, std::forward(args)...); - EndMessage(msg); - PushMessage(pnode, msg, sCommand); + return ForNode(addr, cond, [](CNode* pnode){ + return true; + }); } - template - void PushMessageWithFlag(CNode* pnode, int flag, const std::string& sCommand, Args&&... args) - { - PushMessageWithVersionAndFlag(pnode, 0, flag, sCommand, std::forward(args)...); - } + bool IsDynodeOrDisconnectRequested(const CService& addr); - template - void PushMessageWithVersion(CNode* pnode, int nVersion, const std::string& sCommand, Args&&... args) - { - PushMessageWithVersionAndFlag(pnode, nVersion, 0, sCommand, std::forward(args)...); - } - - template - void PushMessage(CNode* pnode, const std::string& sCommand, Args&&... args) - { - PushMessageWithVersionAndFlag(pnode, 0, 0, sCommand, std::forward(args)...); - } + void PushMessage(CNode* pnode, CSerializedNetMsg&& msg); template bool ForEachNodeContinueIf(const Condition& cond, Callable&& func) @@ -316,12 +311,14 @@ class CConnman ForEachNodeThen(FullyConnectedOnly, pre, post); } + std::vector CopyNodeVector(std::function cond); std::vector CopyNodeVector(); void ReleaseNodeVector(const std::vector& vecNodes); void RelayTransaction(const CTransaction& tx); void RelayTransaction(const CTransaction& tx, const CDataStream& ss); void RelayInv(CInv &inv, const int minProtoVersion = MIN_PEER_PROTO_VERSION); + void RelayInvFiltered(CInv &inv, const CTransaction &relatedTx, const int minProtoVersion = MIN_PEER_PROTO_VERSION); // Addrman functions size_t GetAddressCount() const; @@ -360,6 +357,7 @@ class CConnman bool AddNode(const std::string& node); bool RemoveAddedNode(const std::string& node); + bool AddPendingDynode(const CService& addr); std::vector GetAddedNodeInfo(); size_t GetNodeCount(NumConnections num); @@ -401,9 +399,11 @@ class CConnman int GetBestHeight() const; /** Get a unique deterministic randomizer. */ - CSipHasher GetDeterministicRandomizer(uint64_t id); + CSipHasher GetDeterministicRandomizer(uint64_t id) const; unsigned int GetReceiveFloodSize() const; + + void WakeMessageHandler(); private: struct ListenSocket { SOCKET socket; @@ -419,11 +419,9 @@ class CConnman void AcceptConnection(const ListenSocket& hListenSocket); void ThreadSocketHandler(); void ThreadDNSAddressSeed(); - void ThreadDnbRequestConnections(); - - uint64_t CalculateKeyedNetGroup(const CAddress& ad); + void ThreadOpenDynodeConnections(); - void WakeMessageHandler(); + uint64_t CalculateKeyedNetGroup(const CAddress& ad) const; CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); @@ -431,13 +429,14 @@ class CConnman CNode* FindNode(const CService& addr); bool AttemptToEvictConnection(); + CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL, bool fCountFailure = false); bool IsWhitelistedRange(const CNetAddr &addr); void DeleteNode(CNode* pnode); NodeId GetNewNodeId(); - size_t SocketSendData(CNode *pnode); + size_t SocketSendData(CNode *pnode) const; //!check is the banlist has unwritten changes bool BannedSetIsDirty(); //!set the "dirty" flag for the banlist @@ -448,10 +447,6 @@ class CConnman void DumpData(); void DumpBanlist(); - CDataStream BeginMessage(CNode* node, int nVersion, int flags, const std::string& sCommand); - void PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand); - void EndMessage(CDataStream& strm); - // Network stats void RecordBytesRecv(uint64_t bytes); void RecordBytesSent(uint64_t bytes); @@ -490,6 +485,8 @@ class CConnman CCriticalSection cs_vOneShots; std::vector vAddedNodes; CCriticalSection cs_vAddedNodes; + std::vector vPendingDynodes; + CCriticalSection cs_vPendingDynodes; std::vector vNodes; std::list vNodesDisconnected; mutable CCriticalSection cs_vNodes; @@ -502,9 +499,11 @@ class CConnman ServiceFlags nRelevantServices; CSemaphore *semOutbound; + CSemaphore *semAddnode; CSemaphore *semDynodeOutbound; int nMaxConnections; int nMaxOutbound; + int nMaxAddnode; int nMaxFeeler; std::atomic nBestHeight; CClientUIInterface* clientInterface; @@ -525,7 +524,7 @@ class CConnman std::thread threadSocketHandler; std::thread threadOpenAddedConnections; std::thread threadOpenConnections; - std::thread threadDnbRequestConnections; + std::thread threadOpenDynodeConnections; std::thread threadMessageHandler; }; extern std::unique_ptr g_connman; @@ -622,6 +621,7 @@ class CNodeStats int nVersion; std::string cleanSubVer; bool fInbound; + bool fAddnode; int nStartingHeight; uint64_t nSendBytes; mapMsgCmdSize mapSendBytesPerMsgCmd; @@ -688,47 +688,49 @@ class CNode friend class CConnman; public: // socket - ServiceFlags nServices; + std::atomic nServices; ServiceFlags nServicesExpected; SOCKET hSocket; size_t nSendSize; // total size of all vSendMsg entries size_t nSendOffset; // offset inside the first vSendMsg already sent uint64_t nSendBytes; - std::deque vSendMsg; + std::deque> vSendMsg; CCriticalSection cs_vSend; CCriticalSection cs_hSocket; + CCriticalSection cs_vRecv; CCriticalSection cs_vProcessMsg; std::list vProcessMsg; size_t nProcessQueueSize; + CCriticalSection cs_sendProcessing; + std::deque vRecvGetData; uint64_t nRecvBytes; std::atomic nRecvVersion; - int64_t nLastSend; - int64_t nLastRecv; - int64_t nTimeConnected; - int64_t nTimeOffset; - int64_t nLastWarningTime; + std::atomic nLastSend; + std::atomic nLastRecv; + const int64_t nTimeConnected; + std::atomic nTimeOffset; + std::atomic nLastWarningTime; const CAddress addr; - std::string addrName; - CService addrLocal; - int nNumWarningsSkipped; + std::atomic nNumWarningsSkipped; std::atomic nVersion; // strSubVer is whatever byte array we read from the wire. However, this field is intended // to be printed out, displayed to humans in various forms and so on. So we sanitize it and // store the sanitized version in cleanSubVer. The original should be used when dealing with // the network or wire types and the cleaned string used when displayed or logged. std::string strSubVer, cleanSubVer; + CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer bool fWhitelisted; // This peer can bypass DoS banning. bool fFeeler; // If true this node is being used as a short lived feeler. bool fOneShot; + bool fAddnode; bool fClient; const bool fInbound; - bool fNetworkNode; std::atomic_bool fSuccessfullyConnected; - bool fDisconnect; + std::atomic_bool fDisconnect; // We use fRelayTxes for two purposes - // a) it allows us to not relay tx invs before receiving the peer's version message // b) the peer may tell us in its version message that we should not relay tx invs @@ -755,8 +757,8 @@ class CNode public: uint256 hashContinue; - int nStartingHeight; - + std::atomic nStartingHeight; + // flood relay std::vector vAddrToSend; CRollingBloomFilter addrKnown; @@ -783,9 +785,6 @@ class CNode // Used for headers announcements - unfiltered blocks to relay // Also protected by cs_inventory std::vector vBlockHashesToAnnounce; - // Blocks received by INV while headers chain was too far behind. These are used to delay GETHEADERS messages - // Also protected by cs_inventory - std::vector vBlockHashesFromINV; // Used for BIP35 mempool sending, also protected by cs_inventory bool fSendMempool; @@ -797,22 +796,17 @@ class CNode std::atomic timeLastMempoolReq; // Ping time measurement: // The pong reply we're expecting, or 0 if no pong expected. - uint64_t nPingNonceSent; + std::atomic nPingNonceSent; // Time (in usec) the last ping was sent, or 0 if no ping was ever sent. - int64_t nPingUsecStart; + std::atomic nPingUsecStart; // Last measured round-trip time. - int64_t nPingUsecTime; + std::atomic nPingUsecTime; // Best measured round-trip time. - int64_t nMinPingUsecTime; + std::atomic nMinPingUsecTime; // Whether a ping is requested. - bool fPingQueued; - // Minimum fee rate with which to filter inv's to this node - CAmount minFeeFilter; - CCriticalSection cs_feeFilter; - CAmount lastSentFeeFilter; - int64_t nextSendTimeFeeFilter; - - CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string &addrNameIn = "", bool fInboundIn = false, bool fNetworkNodeIn = false); + std::atomic fPingQueued; + + CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); private: @@ -820,10 +814,17 @@ class CNode void operator=(const CNode&); const uint64_t nLocalHostNonce; + // Services offered to this peer const ServiceFlags nLocalServices; const int nMyStartingHeight; int nSendVersion; std::list vRecvMsg; // Used only by SocketHandler thread + + mutable CCriticalSection cs_addrName; + std::string addrName; + + CService addrLocal; + mutable CCriticalSection cs_addrLocal; public: NodeId GetId() const { @@ -857,6 +858,10 @@ class CNode void SetSendVersion(int nVersionIn); int GetSendVersion() const; + CService GetAddrLocal() const; + //! May not be called more than once + void SetAddrLocal(const CService& addrLocalIn); + CNode* AddRef() { nRefCount++; @@ -868,8 +873,6 @@ class CNode nRefCount--; } - - void AddAddressKnown(const CAddress& addr) { addrKnown.insert(addr.GetKey()); @@ -923,12 +926,6 @@ class CNode vBlockHashesToAnnounce.push_back(hash); } - void PushBlockHashFromINV(const uint256 &hash) - { - LOCK(cs_inventory); - vBlockHashesFromINV.push_back(hash); - } - void AskFor(const CInv& inv); void CloseSocketDisconnect(); @@ -939,6 +936,10 @@ class CNode { return nLocalServices; } + + std::string GetAddrName() const; + //! Sets the addrName only if it was not previously set + void MaybeSetAddrName(const std::string& addrNameIn); }; class CExplicitNetCleanup diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f3d9ebc43a..cf20893e99 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -10,6 +10,7 @@ #include "alert.h" #include "addrman.h" #include "arith_uint256.h" +#include "blockencodings.h" #include "chainparams.h" #include "consensus/validation.h" #include "hash.h" @@ -18,6 +19,7 @@ #include "merkleblock.h" #include "net.h" #include "netbase.h" +#include "netmessagemaker.h" #include "policy/fees.h" #include "policy/policy.h" #include "primitives/block.h" @@ -50,9 +52,7 @@ using namespace std; # error "Dynamic cannot be compiled without assertions." #endif -int64_t nTimeBestReceived = 0; // Used only to inform the wallet of when we last received a block - -extern FeeFilterRounder filterRounder; +std::atomic nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block struct IteratorComparator { @@ -64,7 +64,7 @@ struct IteratorComparator }; struct COrphanTx { - CTransaction tx; + CTransactionRef tx; NodeId fromPeer; int64_t nTimeExpire; }; @@ -72,6 +72,9 @@ map mapOrphanTransactions GUARDED_BY(cs_main); map::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(cs_main); void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +static size_t vExtraTxnForCompactIt = 0; +static std::vector> vExtraTxnForCompact GUARDED_BY(cs_main); + static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256("main address relay")[0:8] // Internal stuff @@ -84,7 +87,7 @@ namespace { * messages or ban them when processing happens afterwards. Protected by * cs_main. */ - map mapBlockSource; + std::map> mapBlockSource; /** * Filter for transactions that were recently rejected by @@ -106,16 +109,20 @@ namespace { * * Memory used: 1.3MB */ - boost::scoped_ptr recentRejects; + std::unique_ptr recentRejects; uint256 hashRecentRejectsChainTip; /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ struct QueuedBlock { uint256 hash; - const CBlockIndex* pindex; //!< Optional. - bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request. + const CBlockIndex* pindex; //!< Optional. + bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request. + std::unique_ptr partialBlock; //!< Optional, used for CMPCTBLOCK downloads }; - map::iterator> > mapBlocksInFlight; + std::map::iterator> > mapBlocksInFlight; + + /** Stack of nodes which we have set to announce using compact blocks */ + std::list lNodesAnnouncingHeaderAndIDs; /** Number of preferable block download peers. */ int nPreferredDownload = 0; @@ -124,7 +131,7 @@ namespace { int nPeersWithValidatedDownloads = 0; /** Relay map, protected by cs_main. */ - typedef std::map> MapRelay; + typedef std::map MapRelay; MapRelay mapRelay; /** Expiration-time ordered list of (expire time, relay map entry) pairs, protected by cs_main). */ std::deque> vRelayExpiration; @@ -178,7 +185,7 @@ struct CNodeState { int64_t nHeadersSyncTimeout; //! Since when we're stalling block download progress (in microseconds), or 0. int64_t nStallingSince; - list vBlocksInFlight; + std::list vBlocksInFlight; //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty. int64_t nDownloadingSince; int nBlocksInFlight; @@ -187,6 +194,15 @@ struct CNodeState { bool fPreferredDownload; //! Whether this peer wants invs or headers (when possible) for block announcements. bool fPreferHeaders; + //! Whether this peer wants invs or cmpctblocks (when possible) for block announcements. + bool fPreferHeaderAndIDs; + //! Whether this peer will send us cmpctblocks if we request them + bool fProvidesHeaderAndIDs; + /** + * If we've announced last version to this peer: whether the peer sends last version in cmpctblocks/blocktxns, + * otherwise: whether this peer sends non-last version in cmpctblocks/blocktxns. + */ + bool fSupportsDesiredCmpctVersion; CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) { fCurrentlyConnected = false; @@ -205,6 +221,9 @@ struct CNodeState { nBlocksInFlightValidHeaders = 0; fPreferredDownload = false; fPreferHeaders = false; + fPreferHeaderAndIDs = false; + fProvidesHeaderAndIDs = false; + fSupportsDesiredCmpctVersion = false; } }; @@ -240,8 +259,8 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = CAddress(CService(), nLocalNodeServices); - connman.PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, - nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes); + connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, + nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes)); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid); @@ -251,7 +270,7 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) void InitializeNode(CNode *pnode, CConnman& connman) { CAddress addr = pnode->addr; - std::string addrName = pnode->addrName; + std::string addrName = pnode->GetAddrName(); NodeId nodeid = pnode->GetId(); { LOCK(cs_main); @@ -293,8 +312,9 @@ void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { // Requires cs_main. // Returns a bool indicating whether we requested this block. +// Also used if a block was /not/ received and timed out or started with another peer bool MarkBlockAsReceived(const uint256& hash) { - map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); + std::map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); if (itInFlight != mapBlocksInFlight.end()) { CNodeState *state = State(itInFlight->second.first); state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; @@ -316,17 +336,26 @@ bool MarkBlockAsReceived(const uint256& hash) { } // Requires cs_main. -void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, const CBlockIndex *pindex = NULL) { +// returns false, still setting pit, if the block was already in flight from the same peer +// pit will only be valid as long as the same cs_main lock is being held +bool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, const CBlockIndex *pindex = NULL, std::list::iterator **pit = NULL) { CNodeState *state = State(nodeid); assert(state != NULL); + // Short-circuit most stuff in case its from the same node + std::map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); + if (itInFlight != mapBlocksInFlight.end() && itInFlight->second.first == nodeid) { + *pit = &itInFlight->second.second; + return false; + } + // Make sure it's not listed somewhere already. MarkBlockAsReceived(hash); - QueuedBlock newentry = {hash, pindex, pindex != NULL}; - list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); + std::list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), + {hash, pindex, pindex != NULL, std::unique_ptr(pit ? new PartiallyDownloadedBlock(&mempool) : NULL)}); state->nBlocksInFlight++; - state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders; + state->nBlocksInFlightValidHeaders += it->fValidatedHeaders; if (state->nBlocksInFlight == 1) { // We're starting a block download (batch) from this peer. state->nDownloadingSince = GetTimeMicros(); @@ -334,7 +363,10 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL) { nPeersWithValidatedDownloads++; } - mapBlocksInFlight[hash] = std::make_pair(nodeid, it); + itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it))).first; + if (pit) + *pit = &itInFlight->second.second; + return true; } /** Check whether the last unknown block a peer advertised is not yet known. */ @@ -370,6 +402,41 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { } } +void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) { + AssertLockHeld(cs_main); + CNodeState* nodestate = State(nodeid); + if (!nodestate || !nodestate->fSupportsDesiredCmpctVersion) { + // Never ask from peers who can't provide desired version. + return; + } + if (nodestate->fProvidesHeaderAndIDs) { + for (std::list::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) { + if (*it == nodeid) { + lNodesAnnouncingHeaderAndIDs.erase(it); + lNodesAnnouncingHeaderAndIDs.push_back(nodeid); + return; + } + } + connman.ForNode(nodeid, [&connman](CNode* pfrom){ + bool fAnnounceUsingCMPCTBLOCK = false; + uint64_t nCMPCTBLOCKVersion = 1; + if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { + // As per BIP152, we only get 3 of our peers to announce + // blocks using compact encodings. + connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){ + connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + return true; + }); + lNodesAnnouncingHeaderAndIDs.pop_front(); + } + fAnnounceUsingCMPCTBLOCK = true; + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); + return true; + }); + } +} + // Requires cs_main bool CanDirectFetch(const Consensus::Params &consensusParams) { @@ -418,7 +485,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorpindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) { + if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < UintToArith256(consensusParams.nMinimumChainWork)) { // This peer has nothing interesting. return; } @@ -527,24 +594,20 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) // mapOrphanTransactions // -// TODO This is a temporary solution while backporting Bitcoin 0.13 changes into Dynamic -// See caller of this method -void LoopMapOrphanTransactionsByPrev(const CTransaction &tx, std::vector &vOrphanErase) +void AddToCompactExtraTransactions(const CTransactionRef& tx) { - for (size_t j = 0; j < tx.vin.size(); j++) { - auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout); - if (itByPrev == mapOrphanTransactionsByPrev.end()) continue; - for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) { - const CTransaction& orphanTx = (*mi)->second.tx; - const uint256& orphanHash = orphanTx.GetHash(); - vOrphanErase.push_back(orphanHash); - } - } + size_t max_extra_txn = GetArg("-blockreconstructionextratxn", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN); + if (max_extra_txn <= 0) + return; + if (!vExtraTxnForCompact.size()) + vExtraTxnForCompact.resize(max_extra_txn); + vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetHash(), tx); + vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % max_extra_txn; } -bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - uint256 hash = tx.GetHash(); + const uint256& hash = tx->GetHash(); if (mapOrphanTransactions.count(hash)) return false; @@ -555,7 +618,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c // have been mined or received. // 100 orphans, each of which is at most 99,999 bytes big is // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case): - unsigned int sz = GetSerializeSize(tx, SER_NETWORK, CTransaction::CURRENT_VERSION); + unsigned int sz = GetSerializeSize(*tx, SER_NETWORK, CTransaction::CURRENT_VERSION); if (sz > MAX_STANDARD_TX_SIZE) { LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); @@ -564,21 +627,23 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME}); assert(ret.second); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + BOOST_FOREACH(const CTxIn& txin, tx->vin) { mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first); } + AddToCompactExtraTransactions(tx); + LogPrint("mempool", "stored orphan tx %s (mapsz %u outsz %u)\n", hash.ToString(), mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size()); return true; } -int EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +int static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - map::iterator it = mapOrphanTransactions.find(hash); + std::map::iterator it = mapOrphanTransactions.find(hash); if (it == mapOrphanTransactions.end()) return 0; - BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) + BOOST_FOREACH(const CTxIn& txin, it->second.tx->vin) { auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout); if (itPrev == mapOrphanTransactionsByPrev.end()) @@ -594,19 +659,20 @@ int EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) void EraseOrphansFor(NodeId peer) { int nErased = 0; - map::iterator iter = mapOrphanTransactions.begin(); + std::map::iterator iter = mapOrphanTransactions.begin(); while (iter != mapOrphanTransactions.end()) { - map::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid + std::map::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid if (maybeErase->second.fromPeer == peer) { - nErased += EraseOrphanTx(maybeErase->second.tx.GetHash()); + nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); } } - if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer); + if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer=%d\n", nErased, peer); } + unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { unsigned int nEvicted = 0; @@ -616,12 +682,12 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE // Sweep out expired orphan pool entries: int nErased = 0; int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL; - map::iterator iter = mapOrphanTransactions.begin(); + std::map::iterator iter = mapOrphanTransactions.begin(); while (iter != mapOrphanTransactions.end()) { - map::iterator maybeErase = iter++; + std::map::iterator maybeErase = iter++; if (maybeErase->second.nTimeExpire <= nNow) { - nErased += EraseOrphanTx(maybeErase->second.tx.GetHash()); + nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); } else { nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); } @@ -634,7 +700,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE { // Evict a random orphan: uint256 randomhash = GetRandHash(); - map::iterator it = mapOrphanTransactions.lower_bound(randomhash); + std::map::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); EraseOrphanTx(it->first); @@ -680,6 +746,78 @@ PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanI recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); } +void PeerLogicValidation::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock) { + if (nPosInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK) + return; + + LOCK(cs_main); + + std::vector vOrphanErase; + // Which orphan pool entries must we evict? + for (size_t j = 0; j < tx.vin.size(); j++) { + auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout); + if (itByPrev == mapOrphanTransactionsByPrev.end()) continue; + for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) { + const CTransaction& orphanTx = *(*mi)->second.tx; + const uint256& orphanHash = orphanTx.GetHash(); + vOrphanErase.push_back(orphanHash); + } + } + + // Erase orphan transactions include or precluded by this block + if (vOrphanErase.size()) { + int nErased = 0; + BOOST_FOREACH(uint256 &orphanHash, vOrphanErase) { + nErased += EraseOrphanTx(orphanHash); + } + LogPrint("mempool", "Erased %d orphan tx included or conflicted by block\n", nErased); + } +} + +static CCriticalSection cs_most_recent_block; +static std::shared_ptr most_recent_block; +static std::shared_ptr most_recent_compact_block; +static uint256 most_recent_block_hash; + +void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr& pblock) { + std::shared_ptr pcmpctblock = std::make_shared (*pblock); + const CNetMsgMaker msgMaker(PROTOCOL_VERSION); + + LOCK(cs_main); + + static int nHighestFastAnnounce = 0; + if (pindex->nHeight <= nHighestFastAnnounce) + return; + nHighestFastAnnounce = pindex->nHeight; + + uint256 hashBlock(pblock->GetHash()); + + { + LOCK(cs_most_recent_block); + most_recent_block_hash = hashBlock; + most_recent_block = pblock; + most_recent_compact_block = pcmpctblock; + } + + connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, &hashBlock](CNode* pnode) { + // TODO: Avoid the repeated-serialization here + if (pnode->fDisconnect) + return; + ProcessBlockAvailability(pnode->GetId()); + CNodeState &state = *State(pnode->GetId()); + // If the peer has, or we announced to them the previous block already, + // but we don't think they have this one, go ahead and announce it + if (state.fPreferHeaderAndIDs && + !PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) { + + LogPrint("net", "%s sending header-and-ids %s to peer=%d\n", "PeerLogicValidation::NewPoWValidBlock", + hashBlock.ToString(), pnode->id); + connman->PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock)); + state.pindexBestHeaderSent = pindex; + } + }); +} + void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) { const int nNewHeight = pindexNew->nHeight; connman->SetBestHeight(nNewHeight); @@ -714,16 +852,29 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta LOCK(cs_main); const uint256 hash(block.GetHash()); - std::map::iterator it = mapBlockSource.find(hash); + std::map >::iterator it = mapBlockSource.find(hash); int nDoS = 0; if (state.IsInvalid(nDoS)) { - if (it != mapBlockSource.end() && State(it->second)) { + if (it != mapBlockSource.end() && State(it->second.first)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash}; - State(it->second)->rejects.push_back(reject); - if (nDoS > 0) - Misbehaving(it->second, nDoS); + State(it->second.first)->rejects.push_back(reject); + if (nDoS > 0 && it->second.second) + Misbehaving(it->second.first, nDoS); + } + } + // Check that: + // 1. The block is valid + // 2. We're not in initial block download + // 3. This is currently the best block we're aware of. We haven't updated + // the tip yet so we have no way to check this directly here. Instead we + // just check that there are currently no other blocks in flight. + else if (state.IsValid() && + !IsInitialBlockDownload() && + mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) { + if (it != mapBlockSource.end()) { + MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, *connman); } } if (it != mapBlockSource.end()) @@ -848,11 +999,11 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); } -void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman, std::atomic& interruptMsgProc) +void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman, const std::atomic& interruptMsgProc) { std::deque::iterator it = pfrom->vRecvGetData.begin(); - vector vNotFound; - + std::vector vNotFound; + const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); LOCK(cs_main); while (it != pfrom->vRecvGetData.end()) { @@ -868,12 +1019,27 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam it++; - if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK) { bool send = false; BlockMap::iterator mi = mapBlockIndex.find(inv.hash); if (mi != mapBlockIndex.end()) { + if (mi->second->nChainTx && !mi->second->IsValid(BLOCK_VALID_SCRIPTS) && + mi->second->IsValid(BLOCK_VALID_TREE)) { + // If we have the block and all of its parents, but have not yet validated it, + // we might be in the middle of connecting it (ie in the unlock of cs_main + // before ActivateBestChain but after AcceptBlock). + // In this case, we need to run ActivateBestChain prior to checking the relay + // conditions below. + std::shared_ptr a_recent_block; + { + LOCK(cs_most_recent_block); + a_recent_block = most_recent_block; + } + CValidationState dummy; + ActivateBestChain(dummy, Params(), a_recent_block); + } if (chainActive.Contains(mi->second)) { send = true; } else { @@ -908,20 +1074,20 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (!ReadBlockFromDisk(block, (*mi).second, consensusParams)) assert(!"cannot load block from disk"); if (inv.type == MSG_BLOCK) - connman.PushMessage(pfrom, NetMsgType::BLOCK, block); - else // MSG_FILTERED_BLOCK) + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, block)); + else if (inv.type == MSG_FILTERED_BLOCK) { - bool send = false; + bool sendMerkleBlock = false; CMerkleBlock merkleBlock; { LOCK(pfrom->cs_filter); if (pfrom->pfilter) { - send = true; + sendMerkleBlock = true; merkleBlock = CMerkleBlock(block, *pfrom->pfilter); } } - if (send) { - connman.PushMessage(pfrom, NetMsgType::MERKLEBLOCK, merkleBlock); + if (sendMerkleBlock) { + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see // This avoids hurting performance by pointlessly requiring a round-trip // Note that there is currently no way for a node to request any single transactions we didn't send here - @@ -930,11 +1096,23 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // however we MUST always provide at least what the remote peer needs typedef std::pair PairType; BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) - connman.PushMessage(pfrom, NetMsgType::TX, block.vtx[pair.first]); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::TX, *block.vtx[pair.first])); } // else // no response } + else if (inv.type == MSG_CMPCT_BLOCK) + { + // If a peer is asking for old blocks, we're almost guaranteed + // they won't have a useful mempool to match against a compact block, + // and we don't feel like constructing the object for them, so + // instead we respond with the full, non-compact block. + if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { + CBlockHeaderAndShortTxIDs cmpctblock(block); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::CMPCTBLOCK, cmpctblock)); + } else + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, block)); + } // Trigger the peer node to send a getblocks request for the next batch of inventory if (inv.hash == pfrom->hashContinue) @@ -942,14 +1120,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // Bypass PushInventory, this must send even if redundant, // and we want it right after the last block so they don't // wait for other stuff first. - vector vInv; + std::vector vInv; vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); - connman.PushMessage(pfrom, NetMsgType::INV, vInv); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); pfrom->hashContinue.SetNull(); } } } - else if (inv.IsKnownType()) + else if (inv.IsKnownType()) { // Send stream from relay memory bool push = false; @@ -958,14 +1136,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (inv.type == MSG_TX) { auto mi = mapRelay.find(inv.hash); if (mi != mapRelay.end()) { - connman.PushMessage(pfrom, NetMsgType::TX, *mi->second); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::TX, *mi->second)); push = true; } else if (pfrom->timeLastMempoolReq) { auto txinfo = mempool.info(inv.hash); // To protect privacy, do not answer getdata using the mempool when // that TX couldn't have been INVed in reply to a MEMPOOL request. if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) { - connman.PushMessage(pfrom, NetMsgType::TX, *txinfo.tx); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::TX, *txinfo.tx)); push = true; } } @@ -974,7 +1152,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (!push && inv.type == MSG_TXLOCK_REQUEST) { CTxLockRequest txLockRequest; if(instantsend.GetTxLockRequest(inv.hash, txLockRequest)) { - connman.PushMessage(pfrom, NetMsgType::TXLOCKREQUEST, txLockRequest); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::TXLOCKREQUEST, txLockRequest)); push = true; } } @@ -982,21 +1160,21 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (!push && inv.type == MSG_TXLOCK_VOTE) { CTxLockVote vote; if(instantsend.GetTxLockVote(inv.hash, vote)) { - connman.PushMessage(pfrom, NetMsgType::TXLOCKVOTE, vote); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::TXLOCKVOTE, vote)); push = true; } } if (!push && inv.type == MSG_SPORK) { if(mapSporks.count(inv.hash)) { - connman.PushMessage(pfrom, NetMsgType::SPORK, mapSporks[inv.hash]); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SPORK, mapSporks[inv.hash])); push = true; } } if (!push && inv.type == MSG_DYNODE_PAYMENT_VOTE) { if(dnpayments.HasVerifiedPaymentVote(inv.hash)) { - connman.PushMessage(pfrom, NetMsgType::DYNODEPAYMENTVOTE, dnpayments.mapDynodePaymentVotes[inv.hash]); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DYNODEPAYMENTVOTE, dnpayments.mapDynodePaymentVotes[inv.hash])); push = true; } } @@ -1009,7 +1187,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam std::vector vecVoteHashes = payee.GetVoteHashes(); BOOST_FOREACH(uint256& hash, vecVoteHashes) { if(dnpayments.HasVerifiedPaymentVote(hash)) { - connman.PushMessage(pfrom, NetMsgType::DYNODEPAYMENTVOTE, dnpayments.mapDynodePaymentVotes[hash]); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DYNODEPAYMENTVOTE, dnpayments.mapDynodePaymentVotes[hash])); } } } @@ -1019,14 +1197,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (!push && inv.type == MSG_DYNODE_ANNOUNCE) { if(dnodeman.mapSeenDynodeBroadcast.count(inv.hash)){ - connman.PushMessage(pfrom, NetMsgType::DNANNOUNCE, dnodeman.mapSeenDynodeBroadcast[inv.hash].second); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DNANNOUNCE, dnodeman.mapSeenDynodeBroadcast[inv.hash].second)); push = true; } } if (!push && inv.type == MSG_DYNODE_PING) { if(dnodeman.mapSeenDynodePing.count(inv.hash)) { - connman.PushMessage(pfrom, NetMsgType::DNPING, dnodeman.mapSeenDynodePing[inv.hash]); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DNPING, dnodeman.mapSeenDynodePing[inv.hash])); push = true; } } @@ -1034,7 +1212,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (!push && inv.type == MSG_PSTX) { CPrivateSendBroadcastTx pstx = CPrivateSend::GetPSTX(inv.hash); if(pstx) { - connman.PushMessage(pfrom, NetMsgType::PSTX, pstx); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::PSTX, pstx)); push = true; } } @@ -1053,7 +1231,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } LogPrint("net", "ProcessGetData -- MSG_GOVERNANCE_OBJECT: topush = %d, inv = %s\n", topush, inv.ToString()); if(topush) { - connman.PushMessage(pfrom, NetMsgType::DNGOVERNANCEOBJECT, ss); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DNGOVERNANCEOBJECT, ss)); push = true; } } @@ -1071,14 +1249,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } if(topush) { LogPrint("net", "ProcessGetData -- pushing: inv = %s\n", inv.ToString()); - connman.PushMessage(pfrom, NetMsgType::DNGOVERNANCEOBJECTVOTE, ss); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DNGOVERNANCEOBJECTVOTE, ss)); push = true; } } if (!push && inv.type == MSG_DYNODE_VERIFY) { if(dnodeman.mapSeenDynodeVerification.count(inv.hash)) { - connman.PushMessage(pfrom, NetMsgType::DNVERIFY, dnodeman.mapSeenDynodeVerification[inv.hash]); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::DNVERIFY, dnodeman.mapSeenDynodeVerification[inv.hash])); push = true; } } @@ -1090,7 +1268,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // Track requests for our stuff. GetMainSignals().Inventory(inv.hash); - if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK) break; } } @@ -1105,11 +1283,27 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // do that because they want to know about (and store and rebroadcast and // risk analyze) the dependencies of transactions relevant to them, without // having to download the entire memory pool. - connman.PushMessage(pfrom, NetMsgType::NOTFOUND, vNotFound); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); + } +} + +inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman& connman) { + BlockTransactions resp(req); + for (size_t i = 0; i < req.indexes.size(); i++) { + if (req.indexes[i] >= block.vtx.size()) { + LOCK(cs_main); + Misbehaving(pfrom->GetId(), 100); + LogPrintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom->id); + return; + } + resp.txn[i] = block.vtx[req.indexes[i]]; } + LOCK(cs_main); + CNetMsgMaker msgMaker(pfrom->GetSendVersion()); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCKTXN, resp)); } -bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, std::atomic& interruptMsgProc) +bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, const std::atomic& interruptMsgProc) { LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); @@ -1133,19 +1327,36 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - - if (strCommand == NetMsgType::VERSION) + if (strCommand == NetMsgType::REJECT) { - // Feeler connections exist only to verify if address is online. - if (pfrom->fFeeler) { - assert(pfrom->fInbound == false); - pfrom->fDisconnect = true; + if (fDebug) { + try { + std::string strMsg; unsigned char ccode; std::string strReason; + vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH); + + std::ostringstream ss; + ss << strMsg << " code " << itostr(ccode) << ": " << strReason; + + if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX) + { + uint256 hash; + vRecv >> hash; + ss << ": hash " << hash.ToString(); + } + LogPrint("net", "Reject %s\n", SanitizeString(ss.str())); + } catch (const std::ios_base::failure&) { + // Avoid feedback loops by preventing reject messages from triggering a new reject message. + LogPrint("net", "Unparseable reject message received\n"); + } } + } + else if (strCommand == NetMsgType::VERSION) + { // Each connection can only send one version message if (pfrom->nVersion != 0) { - connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")); + connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message"))); LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); return false; @@ -1160,6 +1371,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int nVersion; int nSendVersion; std::string strSubVer; + std::string cleanSubVer; int nStartingHeight = -1; bool fRelay = true; @@ -1173,8 +1385,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pfrom->nServicesExpected & ~nServices) { LogPrint("net", "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->id, nServices, pfrom->nServicesExpected); - connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, - strprintf("Expected to offer services %08x", pfrom->nServicesExpected)); + connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, + strprintf("Expected to offer services %08x", pfrom->nServicesExpected))); pfrom->fDisconnect = true; return false; } @@ -1183,8 +1395,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { // disconnect from peers older than this proto version LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, nVersion); - connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)); + connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION))); pfrom->fDisconnect = true; return false; } @@ -1195,6 +1407,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> addrFrom >> nNonce; if (!vRecv.empty()) { vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH); + cleanSubVer = SanitizeString(strSubVer); } if (!vRecv.empty()) { vRecv >> nStartingHeight; @@ -1218,12 +1431,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pfrom->fInbound) PushNodeVersion(pfrom, connman, GetAdjustedTime()); - connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::VERACK); + connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK)); pfrom->nServices = nServices; - pfrom->addrLocal = addrMe; - pfrom->strSubVer = strSubVer; - pfrom->cleanSubVer = SanitizeString(strSubVer); + pfrom->SetAddrLocal(addrMe); + { + LOCK(pfrom->cs_SubVer); + pfrom->strSubVer = strSubVer; + pfrom->cleanSubVer = cleanSubVer; + } pfrom->nStartingHeight = nStartingHeight; pfrom->fClient = !(nServices & NODE_NETWORK); { @@ -1253,7 +1469,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString()); pfrom->PushAddress(addr, insecure_rand); } else if (IsPeerAddrLocalGood(pfrom)) { - addr.SetIP(pfrom->addrLocal); + addr.SetIP(addrMe); LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString()); pfrom->PushAddress(addr, insecure_rand); } @@ -1262,7 +1478,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Get recent addresses if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000) { - connman.PushMessage(pfrom, NetMsgType::GETADDR); + connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR)); pfrom->fGetAddr = true; } connman.MarkAddressGood(pfrom->addr); @@ -1280,13 +1496,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n", - pfrom->cleanSubVer, pfrom->nVersion, + cleanSubVer, pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString(), pfrom->id, remoteAddr); int64_t nTimeOffset = nTime - GetTime(); pfrom->nTimeOffset = nTimeOffset; AddTimeData(pfrom->addr, nTimeOffset); + + // Feeler connections exist only to verify if address is online. + if (pfrom->fFeeler) { + assert(pfrom->fInbound == false); + pfrom->fDisconnect = true; + } + return true; } @@ -1298,13 +1521,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return false; } + // At this point, the outgoing message serialization version can't change. + const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); - else if (strCommand == NetMsgType::VERACK) + if (strCommand == NetMsgType::VERACK) { pfrom->SetRecvVersion(std::min(pfrom->nVersion.load(), PROTOCOL_VERSION)); - // Mark this node as currently connected, so we update its timestamp later. - if (pfrom->fNetworkNode) { + if (!pfrom->fInbound) { + // Mark this node as currently connected, so we update its timestamp later. LOCK(cs_main); State(pfrom->GetId())->fCurrentlyConnected = true; } @@ -1314,11 +1539,30 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // We send this to non-NODE NETWORK peers as well, because even // non-NODE NETWORK peers can announce blocks (such as pruning // nodes) - connman.PushMessage(pfrom, NetMsgType::SENDHEADERS); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); + } + + if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) { + // Tell our peer we are willing to provide version-1 cmpctblocks + // However, we do not request new block announcements using + // cmpctblock messages. + // We send this to non-NODE NETWORK peers as well, because + // they may wish to request compact blocks from us + bool fAnnounceUsingCMPCTBLOCK = false; + uint64_t nCMPCTBLOCKVersion = 1; + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); } + pfrom->fSuccessfullyConnected = true; } + else if (!pfrom->fSuccessfullyConnected) + { + // Must have a verack message before anything else + LOCK(cs_main); + Misbehaving(pfrom->GetId(), 1); + return false; + } else if (strCommand == NetMsgType::ADDR) { @@ -1372,6 +1616,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, State(pfrom->GetId())->fPreferHeaders = true; } + else if (strCommand == NetMsgType::SENDCMPCT) + { + bool fAnnounceUsingCMPCTBLOCK = false; + uint64_t nCMPCTBLOCKVersion = 1; + vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; + if (nCMPCTBLOCKVersion == 1) { + LOCK(cs_main); + State(pfrom->GetId())->fProvidesHeaderAndIDs = true; + State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK; + State(pfrom->GetId())->fSupportsDesiredCmpctVersion = true; + } + } else if (strCommand == NetMsgType::INV) { @@ -1392,9 +1648,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LOCK(cs_main); - std::vector vToFetch; - - for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { const CInv &inv = vInv[nInv]; @@ -1425,7 +1678,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Download if this is a nice peer, or we have no nice peers and this one might do. bool fFetch = state->fPreferredDownload || (nPreferredDownload == 0 && !pfrom->fOneShot); // Only actively request headers from a single peer, unless we're close to end of initial download. - if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 64) { + if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - nMaxTipAge) { // Make sure to mark this peer as the one we are currently syncing with etc. state->fSyncStarted = true; state->nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(chainparams.GetConsensus().nPowTargetSpacing); @@ -1435,7 +1688,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // fell back to inv we probably have a reorg which we should get the headers for first, // we now only provide a getheaders response here. When we receive the headers, we will // then ask for the blocks we need. - connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash)); LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); } } @@ -1451,9 +1704,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Track requests for our stuff GetMainSignals().Inventory(inv.hash); } - - if (!vToFetch.empty()) - connman.PushMessage(pfrom, NetMsgType::GETDATA, vToFetch); } @@ -1485,6 +1735,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uint256 hashStop; vRecv >> locator >> hashStop; + // We might have announced the currently-being-connected tip using a + // compact block, which resulted in the peer sending a getblocks + // request, which we would otherwise respond to without the new block. + // To avoid this situation we simply verify that we are on our best + // known chain now. This is super overkill, but we handle it better + // for getheaders requests, and there are no known nodes which support + // compact blocks but still use getblocks to request blocks. + { + std::shared_ptr a_recent_block; + { + LOCK(cs_most_recent_block); + a_recent_block = most_recent_block; + } + CValidationState dummy; + ActivateBestChain(dummy, Params(), a_recent_block); + } + LOCK(cs_main); // Find the last block the caller has in the main chain @@ -1522,6 +1789,54 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } + else if (strCommand == NetMsgType::GETBLOCKTXN) + { + BlockTransactionsRequest req; + vRecv >> req; + + std::shared_ptr recent_block; + { + LOCK(cs_most_recent_block); + if (most_recent_block_hash == req.blockhash) + recent_block = most_recent_block; + // Unlock cs_most_recent_block to avoid cs_main lock inversion + } + if (recent_block) { + SendBlockTransactions(*recent_block, req, pfrom, connman); + return true; + } + + LOCK(cs_main); + + BlockMap::iterator it = mapBlockIndex.find(req.blockhash); + if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) { + LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->id); + return true; + } + + if (it->second->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) { + // If an older block is requested (should never happen in practice, + // but can happen in tests) send a block response instead of a + // blocktxn response. Sending a full block response instead of a + // small blocktxn response is preferable in the case where a peer + // might maliciously send lots of getblocktxn requests to trigger + // expensive disk reads, because it will require the peer to + // actually receive all the data read from disk over the network. + LogPrint("net", "Peer %d sent us a getblocktxn for a block > %i deep", pfrom->id, MAX_BLOCKTXN_DEPTH); + CInv inv; + inv.type = MSG_BLOCK; + inv.hash = req.blockhash; + pfrom->vRecvGetData.push_back(inv); + ProcessGetData(pfrom, chainparams.GetConsensus(), connman, interruptMsgProc); + return true; + } + + CBlock block; + bool ret = ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()); + assert(ret); + + SendBlockTransactions(block, req, pfrom, connman); + } else if (strCommand == NetMsgType::GETHEADERS) { @@ -1567,11 +1882,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // if our peer has chainActive.Tip() (and thus we are sending an empty // headers message). In both cases it's safe to update // pindexBestHeaderSent to be our tip. + // + // It is important that we simply reset the BestHeaderSent value here, + // and not max(BestHeaderSent, newHeaderSent). We might have announced + // the currently-being-connected tip using a compact block, which + // resulted in the peer sending a headers request, which we respond to + // without the new block. By resetting the BestHeaderSent, we ensure we + // will re-announce the new block via headers (or compact blocks again) + // in the SendMessages logic. nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); - connman.PushMessage(pfrom, NetMsgType::HEADERS, vHeaders); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); } + else if (strCommand == NetMsgType::TX || strCommand == NetMsgType::PSTX || strCommand == NetMsgType::TXLOCKREQUEST) { // Stop processing the transaction early if @@ -1584,23 +1908,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, deque vWorkQueue; vector vEraseQueue; - CTransaction tx; + CTransactionRef ptx; CTxLockRequest txLockRequest; CPrivateSendBroadcastTx pstx; int nInvType = MSG_TX; // Read data and assign inv type if(strCommand == NetMsgType::TX) { - vRecv >> tx; + vRecv >> ptx; } else if(strCommand == NetMsgType::TXLOCKREQUEST) { vRecv >> txLockRequest; - tx = txLockRequest; + ptx = txLockRequest.tx; nInvType = MSG_TXLOCK_REQUEST; } else if (strCommand == NetMsgType::PSTX) { vRecv >> pstx; - tx = pstx.tx; + ptx = pstx.tx; nInvType = MSG_PSTX; } + const CTransaction& tx = *ptx; CInv inv(nInvType, tx.GetHash()); pfrom->AddInventoryKnown(inv); @@ -1621,13 +1946,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CDynode dn; - if(!dnodeman.Get(pstx.vin.prevout, dn)) { - LogPrint("privatesend", "PSTX -- Can't find dynode %s to verify %s\n", pstx.vin.prevout.ToStringShort(), hashTx.ToString()); + if(!dnodeman.Get(pstx.dynodeOutpoint, dn)) { + LogPrint("privatesend", "PSTX -- Can't find dynode %s to verify %s\n", pstx.dynodeOutpoint.ToStringShort(), hashTx.ToString()); return false; } if(!dn.fAllowMixingTx) { - LogPrint("privatesend", "PSTX -- Dynode %s is sending too many transactions %s\n", pstx.vin.prevout.ToStringShort(), hashTx.ToString()); + LogPrint("privatesend", "PSTX -- Dynode %s is sending too many transactions %s\n", pstx.dynodeOutpoint.ToStringShort(), hashTx.ToString()); return true; // TODO: Not an error? Could it be that someone is relaying old PSTXes // we have no idea about (e.g we were offline)? How to handle them? @@ -1640,7 +1965,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrintf("PSTX -- Got Dynode transaction %s\n", hashTx.ToString()); mempool.PrioritiseTransaction(hashTx, hashTx.ToString(), 1000, 0.1*COIN); - dnodeman.DisallowMixing(pstx.vin.prevout); + dnodeman.DisallowMixing(pstx.dynodeOutpoint); } LOCK(cs_main); @@ -1650,7 +1975,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mapAlreadyAskedFor.erase(inv.hash); - if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { + std::list lRemovedTxn; + + if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, ptx, true, &fMissingInputs, &lRemovedTxn)) { // Process custom txes, this changes AlreadyHave to "true" if (strCommand == NetMsgType::PSTX) { LogPrintf("PSTX -- Dynode transaction accepted, txid=%s, peer=%d\n", @@ -1687,7 +2014,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mi != itByPrev->second.end(); ++mi) { - const CTransaction& orphanTx = (*mi)->second.tx; + const CTransactionRef& porphanTx = (*mi)->second.tx; + const CTransaction& orphanTx = *porphanTx; const uint256& orphanHash = orphanTx.GetHash(); NodeId fromPeer = (*mi)->second.fromPeer; bool fMissingInputs2 = false; @@ -1699,8 +2027,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (setMisbehaving.count(fromPeer)) continue; - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) - { + if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, true, &fMissingInputs2, &lRemovedTxn)) { LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); connman.RelayTransaction(orphanTx); for (unsigned int i = 0; i < orphanTx.vout.size(); i++) { @@ -1722,8 +2049,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Probably non-standard or insufficient fee/priority LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); vEraseQueue.push_back(orphanHash); - assert(recentRejects); - recentRejects->insert(orphanHash); + if (!stateDummy.CorruptionPossible()) { + assert(recentRejects); + recentRejects->insert(orphanHash); + } } mempool.check(pcoinsTip); } @@ -1747,7 +2076,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->AddInventoryKnown(inv); if (!AlreadyHave(inv)) pfrom->AskFor(inv); } - AddOrphanTx(tx, pfrom->GetId()); + AddOrphanTx(ptx, pfrom->GetId()); // DoS prevention: do not allow mapOrphanTransactions to grow unbounded unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); @@ -1756,10 +2085,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted); } else { LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString()); + // We will continue to reject this tx since it has rejected + // parents so avoid re-requesting it from other peers. + recentRejects->insert(tx.GetHash()); } } else { - assert(recentRejects); - recentRejects->insert(tx.GetHash()); + if (!state.CorruptionPossible()) { + assert(recentRejects); + recentRejects->insert(tx.GetHash()); + if (RecursiveDynamicUsage(*ptx) < 100000) { + AddToCompactExtraTransactions(ptx); + } + } if (strCommand == NetMsgType::TXLOCKREQUEST && !AlreadyHave(inv)) { // i.e. AcceptToMemoryPool failed, probably because it's conflicting @@ -1793,6 +2130,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } + for (const CTransactionRef& removedTx : lRemovedTxn) + AddToCompactExtraTransactions(removedTx); + int nDoS = 0; if (state.IsInvalid(nDoS)) { @@ -1800,14 +2140,272 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->id, FormatStateMessage(state)); if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P - connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), - state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); - if (nDoS > 0) + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), + state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash)); + if (nDoS > 0) { Misbehaving(pfrom->GetId(), nDoS); + } } } + else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing + { + CBlockHeaderAndShortTxIDs cmpctblock; + vRecv >> cmpctblock; + + { + LOCK(cs_main); + if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) { + // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers + if (!IsInitialBlockDownload()) + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); + return true; + } + } + + const CBlockIndex *pindex = NULL; + CValidationState state; + if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) { + int nDoS; + if (state.IsInvalid(nDoS)) { + if (nDoS > 0) { + LOCK(cs_main); + Misbehaving(pfrom->GetId(), nDoS); + } + LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->id); + return true; + } + } + + // When we succeed in decoding a block's txids from a cmpctblock + // message we typically jump to the BLOCKTXN handling code, with a + // dummy (empty) BLOCKTXN message, to re-use the logic there in + // completing processing of the putative block (without cs_main). + bool fProcessBLOCKTXN = false; + CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION); + + // If we end up treating this as a plain headers message, call that as well + // without cs_main. + bool fRevertToHeaderProcessing = false; + CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION); + + // Keep a CBlock for "optimistic" compactblock reconstructions (see + // below) + std::shared_ptr pblock = std::make_shared(); + bool fBlockReconstructed = false; + + { + LOCK(cs_main); + // If AcceptBlockHeader returned true, it set pindex + assert(pindex); + UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash()); + + std::map::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash()); + bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end(); + + if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here + return true; + + if (pindex->nChainWork <= chainActive.Tip()->nChainWork || // We know something better + pindex->nTx != 0) { // We had this block at some point, but pruned it + if (fAlreadyInFlight) { + // We requested this block for some reason, but our mempool will probably be useless + // so we just grab the block via normal getdata + std::vector vInv(1); + vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + } + return true; + } + + // If we're not close to tip yet, give up and let parallel block fetch work its magic + if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus())) + return true; + + CNodeState *nodestate = State(pfrom->GetId()); + + // We want to be a bit conservative just to be extra careful about DoS + // possibilities in compact block processing... + if (pindex->nHeight <= chainActive.Height() + 2) { + if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) || + (fAlreadyInFlight && blockInFlightIt->second.first == pfrom->GetId())) { + std::list::iterator *queuedBlockIt = NULL; + if (!MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), chainparams.GetConsensus(), pindex, &queuedBlockIt)) { + if (!(*queuedBlockIt)->partialBlock) + (*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&mempool)); + else { + // The block was already in flight using compact blocks from the same peer + LogPrint("net", "Peer sent us compact block we were already syncing!\n"); + return true; + } + } + + PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock; + ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact); + if (status == READ_STATUS_INVALID) { + MarkBlockAsReceived(pindex->GetBlockHash()); // Reset in-flight state in case of whitelist + Misbehaving(pfrom->GetId(), 100); + LogPrintf("Peer %d sent us invalid compact block\n", pfrom->id); + return true; + } else if (status == READ_STATUS_FAILED) { + // Duplicate txindexes, the block is now in-flight, so just request it + std::vector vInv(1); + vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + return true; + } + + BlockTransactionsRequest req; + for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++) { + if (!partialBlock.IsTxAvailable(i)) + req.indexes.push_back(i); + } + if (req.indexes.empty()) { + // Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions) + BlockTransactions txn; + txn.blockhash = cmpctblock.header.GetHash(); + blockTxnMsg << txn; + fProcessBLOCKTXN = true; + } else { + req.blockhash = pindex->GetBlockHash(); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); + } + } else { + // This block is either already in flight from a different + // peer, or this peer has too many blocks outstanding to + // download from. + // Optimistically try to reconstruct anyway since we might be + // able to without any round trips. + PartiallyDownloadedBlock tempBlock(&mempool); + ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact); + if (status != READ_STATUS_OK) { + // TODO: don't ignore failures + return true; + } + std::vector dummy; + status = tempBlock.FillBlock(*pblock, dummy); + if (status == READ_STATUS_OK) { + fBlockReconstructed = true; + } + } + } else { + if (fAlreadyInFlight) { + // We requested this block, but its far into the future, so our + // mempool will probably be useless - request the block normally + std::vector vInv(1); + vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + return true; + } else { + // If this was an announce-cmpctblock, we want the same treatment as a header message + // Dirty hack to process as if it were just a headers message (TODO: move message handling into their own functions) + std::vector headers; + headers.push_back(cmpctblock.header); + vHeadersMsg << headers; + fRevertToHeaderProcessing = true; + } + } + } // cs_main + + if (fProcessBLOCKTXN) + return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc); + + if (fRevertToHeaderProcessing) + return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman, interruptMsgProc); + + if (fBlockReconstructed) { + // If we got here, we were able to optimistically reconstruct a + // block that is in flight from some other peer. + { + LOCK(cs_main); + mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom->GetId(), false)); + } + bool fNewBlock = false; + ProcessNewBlock(chainparams, pblock, true, &fNewBlock); + if (fNewBlock) + pfrom->nLastBlockTime = GetTime(); + + LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid() + if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) { + // Clear download state for this block, which is in + // process from some other peer. We do this after calling + // ProcessNewBlock so that a malleated cmpctblock announcement + // can't be used to interfere with block relay. + MarkBlockAsReceived(pblock->GetHash()); + } + } + + } + + else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing + { + BlockTransactions resp; + vRecv >> resp; + + std::shared_ptr pblock = std::make_shared(); + bool fBlockRead = false; + { + LOCK(cs_main); + + std::map::iterator> >::iterator it = mapBlocksInFlight.find(resp.blockhash); + if (it == mapBlocksInFlight.end() || !it->second.second->partialBlock || + it->second.first != pfrom->GetId()) { + LogPrint("net", "Peer %d sent us block transactions for block we weren't expecting\n", pfrom->id); + return true; + } + + PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock; + ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn); + if (status == READ_STATUS_INVALID) { + MarkBlockAsReceived(resp.blockhash); // Reset in-flight state in case of whitelist + Misbehaving(pfrom->GetId(), 100); + LogPrintf("Peer %d sent us invalid compact block/non-matching block transactions\n", pfrom->id); + return true; + } else if (status == READ_STATUS_FAILED) { + // Might have collided, fall back to getdata now :( + std::vector invs; + invs.push_back(CInv(MSG_BLOCK, resp.blockhash)); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs)); + } else { + // Block is either okay, or possibly we received + // READ_STATUS_CHECKBLOCK_FAILED. + // Note that CheckBlock can only fail for one of a few reasons: + // 1. bad-proof-of-work (impossible here, because we've already + // accepted the header) + // 2. merkleroot doesn't match the transactions given (already + // caught in FillBlock with READ_STATUS_FAILED, so + // impossible here) + // 3. the block is otherwise invalid (eg invalid coinbase, + // block is too big, too many legacy sigops, etc). + // So if CheckBlock failed, #3 is the only possibility. + // Under BIP 152, we don't DoS-ban unless proof of work is + // invalid (we don't require all the stateless checks to have + // been run). This is handled below, so just treat this as + // though the block was successfully read, and rely on the + // handling in ProcessNewBlock to ensure the block index is + // updated, reject messages go out, etc. + MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer + fBlockRead = true; + // mapBlockSource is only used for sending reject messages and DoS scores, + // so the race between here and cs_main in ProcessNewBlock is fine. + // BIP 152 permits peers to relay compact blocks after validating + // the header only; we should not punish peers if the block turns + // out to be invalid. + mapBlockSource.emplace(resp.blockhash, std::make_pair(pfrom->GetId(), false)); + } + } // Don't hold cs_main when we call into ProcessNewBlock + if (fBlockRead) { + bool fNewBlock = false; + // Since we requested this block (it was in mapBlocksInFlight), force it to be processed, + // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc) + ProcessNewBlock(chainparams, pblock, true, &fNewBlock); + if (fNewBlock) + pfrom->nLastBlockTime = GetTime(); + } + } + + else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing { std::vector headers; @@ -1825,6 +2423,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, ReadCompactSize(vRecv); // ignore tx count; assume it is 0. } + if (nCount == 0) { + // Nothing interesting. Stop asking this peers for more headers. + return true; + } + const CBlockIndex *pindexLast = NULL; { LOCK(cs_main); @@ -1840,7 +2443,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // nUnconnectingHeaders gets reset back to 0. if (nCount > 0 && mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) { nodestate->nUnconnectingHeaders++; - connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); LogPrint("net", "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", headers[0].GetHash().ToString(), headers[0].hashPrevBlock.ToString(), @@ -1895,7 +2498,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue // from there instead. LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); - connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256())); } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); @@ -1922,7 +2525,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); } else { - vector vGetData; + std::vector vGetData; // Download as much as possible, from earliest to latest. BOOST_REVERSE_FOREACH(const CBlockIndex *pindex, vToFetch) { if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { @@ -1939,7 +2542,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); } if (vGetData.size() > 0) { - connman.PushMessage(pfrom, NetMsgType::GETDATA, vGetData); + if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) { + // In any case, we want to download using a compact block, not a regular one + vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); + } + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); } } } @@ -1948,17 +2555,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing { - CBlock block; - vRecv >> block; + std::shared_ptr pblock = std::make_shared(); + vRecv >> *pblock; - LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id); + LogPrint("net", "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom->id); // Process all blocks from whitelisted peers, even if not requested, // unless we're still syncing with the network. // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - const uint256 hash(block.GetHash()); + const uint256 hash(pblock->GetHash()); { LOCK(cs_main); // Also always process if we requested the block explicitly, as we may @@ -1966,10 +2573,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, forceProcessing |= MarkBlockAsReceived(hash); // mapBlockSource is only used for sending reject messages and DoS scores, // so the race between here and cs_main in ProcessNewBlock is fine. - mapBlockSource.emplace(hash, pfrom->GetId()); + mapBlockSource.emplace(hash, std::make_pair(pfrom->GetId(), true)); } bool fNewBlock = false; - ProcessNewBlock(chainparams, &block, forceProcessing, NULL, &fNewBlock); + ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock); if (fNewBlock) pfrom->nLastBlockTime = GetTime(); } @@ -2012,6 +2619,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } + if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted) + { + LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); + pfrom->fDisconnect = true; + return true; + } + LOCK(pfrom->cs_inventory); pfrom->fSendMempool = true; } @@ -2034,7 +2648,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // it, if the remote node sends a ping once per second and this node takes 5 // seconds to respond to each, the 5th ping the remote sends would appear to // return very quickly. - connman.PushMessage(pfrom, NetMsgType::PONG, nonce); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); } } @@ -2059,7 +2673,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pingUsecTime > 0) { // Successful ping time measurement, replace previous pfrom->nPingUsecTime = pingUsecTime; - pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime); + pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime); } else { // This should never happen sProblem = "Timing mishap"; @@ -2184,41 +2798,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->fRelayTxes = true; } - - else if (strCommand == NetMsgType::REJECT) - { - if (fDebug) { - try { - string strMsg; unsigned char ccode; string strReason; - vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH); - - ostringstream ss; - ss << strMsg << " code " << itostr(ccode) << ": " << strReason; - - if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX) - { - uint256 hash; - vRecv >> hash; - ss << ": hash " << hash.ToString(); - } - LogPrint("net", "Reject %s\n", SanitizeString(ss.str())); - } catch (const std::ios_base::failure&) { - // Avoid feedback loops by preventing reject messages from triggering a new reject message. - LogPrint("net", "Unparseable reject message received\n"); - } - } - } - - else if (strCommand == NetMsgType::FEEFILTER) { - CAmount newFeeFilter = 0; - vRecv >> newFeeFilter; - if (MoneyRange(newFeeFilter)) { - { - LOCK(pfrom->cs_feeFilter); - pfrom->minFeeFilter = newFeeFilter; - } - LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id); - } + else if (strCommand == NetMsgType::NOTFOUND) { + // We do not care about the NOTFOUND message, but logging an Unknown Command + // message would be undesirable as we transmit it ourselves. } else { @@ -2255,7 +2837,37 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } -bool ProcessMessages(CNode* pfrom, CConnman& connman, std::atomic& interruptMsgProc) +static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman) +{ + AssertLockHeld(cs_main); + CNodeState &state = *State(pnode->GetId()); + + BOOST_FOREACH(const CBlockReject& reject, state.rejects) { + connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock)); + } + state.rejects.clear(); + + if (state.fShouldBan) { + state.fShouldBan = false; + if (pnode->fWhitelisted) + LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString()); + else if (pnode->fAddnode) + LogPrintf("Warning: not punishing addnoded peer %s!\n", pnode->addr.ToString()); + else { + pnode->fDisconnect = true; + if (pnode->addr.IsLocal()) + LogPrintf("Warning: not banning local peer %s!\n", pnode->addr.ToString()); + else + { + connman.Ban(pnode->addr, BanReasonNodeMisbehaving); + } + } + return true; + } + return false; +} + +bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic& interruptMsgProc) { const CChainParams& chainparams = Params(); // @@ -2338,7 +2950,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, std::atomic& interru } catch (const std::ios_base::failure& e) { - connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")); + connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message"))); if (strstr(e.what(), "end of data")) { // Allow exceptions from under-length message on vRecv @@ -2368,6 +2980,9 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, std::atomic& interru if (!fRet) LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id); + LOCK(cs_main); + SendRejectsAndCheckIfBanned(pfrom, connman); + return fMoreWork; } @@ -2388,7 +3003,7 @@ class CompareInvMempoolOrder } }; -bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsgProc) +bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interruptMsgProc) { const Consensus::Params& consensusParams = Params().GetConsensus(); { @@ -2396,6 +3011,9 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg if (!pto->fSuccessfullyConnected || pto->fDisconnect) return true; + // If we get here, the outgoing message serialization version is set and can't change. + const CNetMsgMaker msgMaker(pto->GetSendVersion()); + // // Message: ping // @@ -2417,11 +3035,11 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg pto->nPingUsecStart = GetTimeMicros(); if (pto->nVersion > BIP0031_VERSION) { pto->nPingNonceSent = nonce; - connman.PushMessage(pto, NetMsgType::PING, nonce); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce)); } else { // Peer is too old to support ping command with nonce, pong will never arrive. pto->nPingNonceSent = 0; - connman.PushMessage(pto, NetMsgType::PING); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING)); } } @@ -2429,6 +3047,10 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg if (!lockMain) return true; + if (SendRejectsAndCheckIfBanned(pto, connman)) + return true; + CNodeState &state = *State(pto->GetId()); + // Address refresh broadcast int64_t nNow = GetTimeMicros(); if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) { @@ -2452,46 +3074,26 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg // receiver rejects addr messages larger than 1000 if (vAddr.size() >= 1000) { - connman.PushMessage(pto, NetMsgType::ADDR, vAddr); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); vAddr.clear(); } } } pto->vAddrToSend.clear(); if (!vAddr.empty()) - connman.PushMessage(pto, NetMsgType::ADDR, vAddr); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); // we only send the big addr message once if (pto->vAddrToSend.capacity() > 40) pto->vAddrToSend.shrink_to_fit(); } - CNodeState &state = *State(pto->GetId()); - if (state.fShouldBan) { - if (pto->fWhitelisted) - LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString()); - else { - pto->fDisconnect = true; - if (pto->addr.IsLocal()) - LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); - else - { - connman.Ban(pto->addr, BanReasonNodeMisbehaving); - } - } - state.fShouldBan = false; - } - - BOOST_FOREACH(const CBlockReject& reject, state.rejects) - connman.PushMessage(pto, NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock); - state.rejects.clear(); - // Start block sync if (pindexBestHeader == NULL) pindexBestHeader = chainActive.Tip(); bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. if (!state.fSyncStarted && !pto->fClient && !pto->fDisconnect && !fImporting && !fReindex) { // Only actively request headers from a single peer, unless we're close to end of initial download. - if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 64) { + if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - nMaxTipAge) { state.fSyncStarted = true; state.nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(consensusParams.nPowTargetSpacing); nSyncStarted++; @@ -2506,7 +3108,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg if (pindexStart->pprev) pindexStart = pindexStart->pprev; LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight); - connman.PushMessage(pto, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256())); } } @@ -2530,8 +3132,10 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg // blocks, or if the peer doesn't want headers, just // add all to the inv queue. LOCK(pto->cs_inventory); - vector vHeaders; - bool fRevertToInv = (!state.fPreferHeaders || pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE); + std::vector vHeaders; + bool fRevertToInv = ((!state.fPreferHeaders && + (!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) || + pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE); const CBlockIndex *pBestIndex = NULL; // last header queued for delivery ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date @@ -2583,6 +3187,45 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg } } } + if (!fRevertToInv && !vHeaders.empty()) { + if (vHeaders.size() == 1 && state.fPreferHeaderAndIDs) { + // We only send up to 1 block as header-and-ids, as otherwise + // probably means we're doing an initial-ish-sync or they're slow + LogPrint("net", "%s sending header-and-ids %s to peer=%d\n", __func__, + vHeaders.front().GetHash().ToString(), pto->id); + + bool fGotBlockFromCache = false; + { + LOCK(cs_most_recent_block); + if (most_recent_block_hash == pBestIndex->GetBlockHash()) { + CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::CMPCTBLOCK, cmpctblock)); + fGotBlockFromCache = true; + } + } + if (!fGotBlockFromCache) { + CBlock block; + bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams); + assert(ret); + CBlockHeaderAndShortTxIDs cmpctblock(block); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::CMPCTBLOCK, cmpctblock)); + } + state.pindexBestHeaderSent = pBestIndex; + } else if (state.fPreferHeaders) { + if (vHeaders.size() > 1) { + LogPrint("net", "%s: %u headers, range (%s, %s), to peer=%d\n", __func__, + vHeaders.size(), + vHeaders.front().GetHash().ToString(), + vHeaders.back().GetHash().ToString(), pto->id); + } else { + LogPrint("net", "%s: sending header %s to peer=%d\n", __func__, + vHeaders.front().GetHash().ToString(), pto->id); + } + connman.PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); + state.pindexBestHeaderSent = pBestIndex; + } else + fRevertToInv = true; + } if (fRevertToInv) { // If falling back to using an inv, just try to inv the tip. // The last entry in vBlockHashesToAnnounce was our tip at some point @@ -2608,18 +3251,6 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg pto->id, hashToAnnounce.ToString()); } } - } else if (!vHeaders.empty()) { - if (vHeaders.size() > 1) { - LogPrint("net", "%s: %u headers, range (%s, %s), to peer=%d\n", __func__, - vHeaders.size(), - vHeaders.front().GetHash().ToString(), - vHeaders.back().GetHash().ToString(), pto->id); - } else { - LogPrint("net", "%s: sending header %s to peer=%d\n", __func__, - vHeaders.front().GetHash().ToString(), pto->id); - } - connman.PushMessage(pto, NetMsgType::HEADERS, vHeaders); - state.pindexBestHeaderSent = pBestIndex; } pto->vBlockHashesToAnnounce.clear(); } @@ -2627,7 +3258,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg // // Message: inventory // - vector vInv; + std::vector vInv; { LOCK(pto->cs_inventory); vInv.reserve(std::max(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX)); @@ -2636,7 +3267,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg BOOST_FOREACH(const uint256& hash, pto->vInventoryBlockToSend) { vInv.push_back(CInv(MSG_BLOCK, hash)); if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, NetMsgType::INV, vInv); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } } @@ -2660,11 +3291,6 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg if (fSendTrickle && pto->fSendMempool) { auto vtxinfo = mempool.infoAll(); pto->fSendMempool = false; - CAmount filterrate = 0; - { - LOCK(pto->cs_feeFilter); - filterrate = pto->minFeeFilter; - } LOCK(pto->cs_filter); @@ -2672,10 +3298,6 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg const uint256& hash = txinfo.tx->GetHash(); CInv inv(MSG_TX, hash); pto->setInventoryTxToSend.erase(hash); - if (filterrate) { - if (txinfo.feeRate.GetFeePerK() < filterrate) - continue; - } if (pto->pfilter) { if (!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue; } @@ -2685,10 +3307,11 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { LogPrint("net", "SendMessages -- pushing inv's: count=%d peer=%d\n", vInv.size(), pto->id); - connman.PushMessage(pto, NetMsgType::INV, vInv); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } } + pto->timeLastMempoolReq = GetTime(); } // Determine transactions to relay @@ -2699,11 +3322,6 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg for (std::set::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++) { vInvTx.push_back(it); } - CAmount filterrate = 0; - { - LOCK(pto->cs_feeFilter); - filterrate = pto->minFeeFilter; - } // Topologically and fee-rate sort the inventory we send for privacy and priority reasons. // A heap is used so that not all items need sorting if only a few are being sent. CompareInvMempoolOrder compareInvMempoolOrder(&mempool); @@ -2729,9 +3347,6 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg if (!txinfo.tx) { continue; } - if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) { - continue; - } if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue; // Send vInv.push_back(CInv(MSG_TX, hash)); @@ -2750,7 +3365,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg } } if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, NetMsgType::INV, vInv); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } pto->filterInventoryKnown.insert(hash); @@ -2761,41 +3376,43 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg for (const auto& inv : pto->vInventoryOtherToSend) { vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { - connman.PushMessage(pto, NetMsgType::INV, vInv); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } } pto->vInventoryOtherToSend.clear(); } if (!vInv.empty()) - connman.PushMessage(pto, NetMsgType::INV, vInv); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); // Detect whether we're stalling nNow = GetTimeMicros(); - if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { + if (state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { // Stalling only triggers when the block download window cannot move. During normal steady state, // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection // should only happen during initial block download. LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id); pto->fDisconnect = true; + return true; } // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout. // We compensate for other peers to prevent killing off peers due to our own downstream link // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes // to unreasonably increase our timeout. - if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { + if (state.vBlocksInFlight.size() > 0) { QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0); if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); pto->fDisconnect = true; + return true; } } // Check for headers sync timeouts if (state.fSyncStarted && state.nHeadersSyncTimeout < std::numeric_limits::max()) { // Detect whether this is a stalling initial-headers-sync peer - if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 64) { + if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - nMaxTipAge) { if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) { // Disconnect a (non-whitelisted) peer if it is our only sync peer, // and we have others we could be using instead. @@ -2829,7 +3446,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg // // Message: getdata (blocks) // - vector vGetData; + std::vector vGetData; if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vector vToDownload; NodeId staller = -1; @@ -2860,7 +3477,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg vGetData.push_back(inv); if (vGetData.size() >= 1000) { - connman.PushMessage(pto, NetMsgType::GETDATA, vGetData); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); LogPrint("net", "SendMessages -- GETDATA -- pushed size = %lu peer=%d\n", vGetData.size(), pto->id); vGetData.clear(); } @@ -2872,33 +3489,10 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg pto->mapAskFor.erase(pto->mapAskFor.begin()); } if (!vGetData.empty()) { - connman.PushMessage(pto, NetMsgType::GETDATA, vGetData); + connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); LogPrint("net", "SendMessages -- GETDATA -- pushed size = %lu peer=%d\n", vGetData.size(), pto->id); } - // - // Message: feefilter - // - // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay - if (!pto->fDisconnect && pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && - !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) { - CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); - int64_t timeNow = GetTimeMicros(); - if (timeNow > pto->nextSendTimeFeeFilter) { - CAmount filterToSend = filterRounder.round(currentFilter); - if (filterToSend != pto->lastSentFeeFilter) { - connman.PushMessage(pto, NetMsgType::FEEFILTER, filterToSend); - pto->lastSentFeeFilter = filterToSend; - } - pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); - } - // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY - // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. - else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter && - (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) { - pto->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000; - } - } } return true; } diff --git a/src/net_processing.h b/src/net_processing.h index e99d194bf9..f4eff60cad 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -23,6 +23,9 @@ static const int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header +/** Default number of orphan+recently-replaced txn to keep around for block reconstruction */ +static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100; + /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); /** Unregister a network node */ @@ -35,8 +38,10 @@ class PeerLogicValidation : public CValidationInterface { public: PeerLogicValidation(CConnman* connmanIn); - virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload); - virtual void BlockChecked(const CBlock& block, const CValidationState& state); + virtual void SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock) override; + virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; + virtual void BlockChecked(const CBlock& block, const CValidationState& state) override; + virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr& pblock) override; }; struct CNodeStateStats { @@ -52,7 +57,7 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); void Misbehaving(NodeId nodeid, int howmuch); /** Process protocol messages received from a given node */ -bool ProcessMessages(CNode* pfrom, CConnman& connman, std::atomic& interrupt); +bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic& interruptMsgProc); /** * Send queued protocol messages to be sent to a give node. * @@ -61,6 +66,6 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, std::atomic& interru * @param[in] interrupt Interrupt condition for processing threads * @return True if there is more work to be done */ -bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interrupt); +bool SendMessages(CNode* pto, CConnman& connman, const std::atomic& interrupt); #endif // DYNAMIC_NET_PROCESSING_H diff --git a/src/netbase.cpp b/src/netbase.cpp index 8de7e9dec3..ead2a6658d 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -290,7 +290,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials vSocks5Init.push_back(0x01); // # METHODS vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED } - ssize_t ret = send(hSocket, (const char*)begin_ptr(vSocks5Init), vSocks5Init.size(), MSG_NOSIGNAL); + ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL); if (ret != (ssize_t)vSocks5Init.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); @@ -315,7 +315,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); vAuth.push_back(auth->password.size()); vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); - ret = send(hSocket, (const char*)begin_ptr(vAuth), vAuth.size(), MSG_NOSIGNAL); + ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL); if (ret != (ssize_t)vAuth.size()) { CloseSocket(hSocket); return error("Error sending authentication to proxy"); @@ -345,7 +345,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end()); vSocks5.push_back((port >> 8) & 0xFF); vSocks5.push_back((port >> 0) & 0xFF); - ret = send(hSocket, (const char*)begin_ptr(vSocks5), vSocks5.size(), MSG_NOSIGNAL); + ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL); if (ret != (ssize_t)vSocks5.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); diff --git a/src/netfulfilledman.cpp b/src/netfulfilledman.cpp index aa997fd8aa..5a2a75defb 100644 --- a/src/netfulfilledman.cpp +++ b/src/netfulfilledman.cpp @@ -12,26 +12,29 @@ CNetFulfilledRequestManager netfulfilledman; -void CNetFulfilledRequestManager::AddFulfilledRequest(CAddress addr, std::string strRequest) +void CNetFulfilledRequestManager::AddFulfilledRequest(const CService& addr, const std::string& strRequest) { LOCK(cs_mapFulfilledRequests); - mapFulfilledRequests[addr][strRequest] = GetTime() + Params().FulfilledRequestExpireTime(); + CService addrSquashed = Params().AllowMultiplePorts() ? addr : CService(addr, 0); + mapFulfilledRequests[addrSquashed][strRequest] = GetTime() + Params().FulfilledRequestExpireTime(); } -bool CNetFulfilledRequestManager::HasFulfilledRequest(CAddress addr, std::string strRequest) +bool CNetFulfilledRequestManager::HasFulfilledRequest(const CService& addr, const std::string& strRequest) { LOCK(cs_mapFulfilledRequests); - fulfilledreqmap_t::iterator it = mapFulfilledRequests.find(addr); + CService addrSquashed = Params().AllowMultiplePorts() ? addr : CService(addr, 0); + fulfilledreqmap_t::iterator it = mapFulfilledRequests.find(addrSquashed); return it != mapFulfilledRequests.end() && it->second.find(strRequest) != it->second.end() && it->second[strRequest] > GetTime(); } -void CNetFulfilledRequestManager::RemoveFulfilledRequest(CAddress addr, std::string strRequest) +void CNetFulfilledRequestManager::RemoveFulfilledRequest(const CService& addr, const std::string& strRequest) { LOCK(cs_mapFulfilledRequests); - fulfilledreqmap_t::iterator it = mapFulfilledRequests.find(addr); + CService addrSquashed = Params().AllowMultiplePorts() ? addr : CService(addr, 0); + fulfilledreqmap_t::iterator it = mapFulfilledRequests.find(addrSquashed); if (it != mapFulfilledRequests.end()) { it->second.erase(strRequest); diff --git a/src/netfulfilledman.h b/src/netfulfilledman.h index 86a1cca51e..ad9f1a04d7 100644 --- a/src/netfulfilledman.h +++ b/src/netfulfilledman.h @@ -8,8 +8,7 @@ #ifndef DYNAMIC_NETFULFILLEDMAN_H #define DYNAMIC_NETFULFILLEDMAN_H -#include "netbase.h" -#include "protocol.h" +#include "netaddress.h" #include "serialize.h" #include "sync.h" @@ -22,12 +21,14 @@ class CNetFulfilledRequestManager { private: typedef std::map fulfilledreqmapentry_t; - typedef std::map fulfilledreqmap_t; + typedef std::map fulfilledreqmap_t; //keep track of what node has/was asked for and when fulfilledreqmap_t mapFulfilledRequests; CCriticalSection cs_mapFulfilledRequests; + void RemoveFulfilledRequest(const CService& addr, const std::string& strRequest); + public: CNetFulfilledRequestManager() {} @@ -39,14 +40,15 @@ class CNetFulfilledRequestManager READWRITE(mapFulfilledRequests); } - void AddFulfilledRequest(CAddress addr, std::string strRequest); // expire after 1 hour by default - bool HasFulfilledRequest(CAddress addr, std::string strRequest); - void RemoveFulfilledRequest(CAddress addr, std::string strRequest); + void AddFulfilledRequest(const CService& addr, const std::string& strRequest); + bool HasFulfilledRequest(const CService& addr, const std::string& strRequest); void CheckAndRemove(); void Clear(); std::string ToString() const; + + void DoMaintenance() { CheckAndRemove(); } }; #endif // DYNAMIC_NETFULFILLEDMAN_H diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h new file mode 100644 index 0000000000..689b3cfb0e --- /dev/null +++ b/src/netmessagemaker.h @@ -0,0 +1,37 @@ +// Copyright (c) 2016-2018 Duality Blockchain Solutions Developers +// Copyright (c) 2009-2018 The Bitcoin Developers +// Copyright (c) 2009-2018 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DYNAMIC_NETMESSAGEMAKER_H +#define DYNAMIC_NETMESSAGEMAKER_H + +#include "net.h" +#include "serialize.h" + +class CNetMsgMaker +{ +public: + CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){} + + template + CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args) const + { + CSerializedNetMsg msg; + msg.command = std::move(sCommand); + CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward(args)... }; + return msg; + } + + template + CSerializedNetMsg Make(std::string sCommand, Args&&... args) const + { + return Make(0, std::move(sCommand), std::forward(args)...); + } + +private: + const int nVersion; +}; + +#endif // DYNAMIC_NETMESSAGEMAKER_H diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index dd6b41a7e6..c0ae2ef7ed 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -281,6 +281,11 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe } } +// This function is called from CTxMemPool::removeUnchecked to ensure +// txs removed from the mempool for any reason are no longer +// tracked. Txs that were part of a block have already been removed in +// processBlockTx to ensure they are never double tracked, but it is +// of no harm to try to remove them again. bool CBlockPolicyEstimator::removeTx(uint256 hash) { std::map::iterator pos = mapMemPoolTxs.find(hash); @@ -294,7 +299,7 @@ bool CBlockPolicyEstimator::removeTx(uint256 hash) } CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee) - : nBestSeenHeight(0) + : nBestSeenHeight(0), trackedTxs(0), untrackedTxs(0) { static_assert(MIN_FEERATE > 0, "Min feerate must be nonzero"); minTrackedFee = _minRelayFee < CFeeRate(MIN_FEERATE) ? CFeeRate(MIN_FEERATE) : _minRelayFee; @@ -306,7 +311,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee) feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY); } -void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate) +void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate) { unsigned int txHeight = entry.GetHeight(); uint256 hash = entry.GetTx().GetHash(); @@ -315,59 +320,57 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo return; } - if (txHeight < nBestSeenHeight) { + if (txHeight != nBestSeenHeight) { // Ignore side chains and re-orgs; assuming they are random they don't // affect the estimate. We'll potentially double count transactions in 1-block reorgs. + // Ignore txs if BlockPolicyEstimator is not in sync with chainActive.Tip(). + // It will be synced next time a block is processed. return; } // Only want to be updating estimates when our blockchain is synced, // otherwise we'll miscalculate how many blocks its taking to get included. - if (!fCurrentEstimate) - return; - - if (!entry.WasClearAtEntry()) { - // This transaction depends on other transactions in the mempool to - // be included in a block before it will be able to be included, so - // we shouldn't include it in our calculations + if (!validFeeEstimate) { + untrackedTxs++; return; } + trackedTxs++; - // Feerates are stored and reported as DYN-per-kb: + // Feerates are stored and reported as BTC-per-kb: CFeeRate feeRate(entry.GetFee(), entry.GetTxSize()); mapMemPoolTxs[hash].blockHeight = txHeight; mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK()); } -void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry) + +bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry) { - if (!entry.WasClearAtEntry()) { - // This transaction depended on other transactions in the mempool to - // be included in a block before it was able to be included, so - // we shouldn't include it in our calculations - return; + if (!removeTx(entry->GetTx().GetHash())) { + // This transaction wasn't being tracked for fee estimation + return false; } // How many blocks did it take for miners to include this transaction? // blocksToConfirm is 1-based, so a transaction included in the earliest // possible block has confirmation count of 1 - int blocksToConfirm = nBlockHeight - entry.GetHeight(); + int blocksToConfirm = nBlockHeight - entry->GetHeight(); if (blocksToConfirm <= 0) { // This can't happen because we don't process transactions from a block with a height // lower than our greatest seen height LogPrint("estimatefee", "Blockpolicy error Transaction had negative blocksToConfirm\n"); - return; + return false; } - // Feerates are stored and reported as DYN-per-kb: - CFeeRate feeRate(entry.GetFee(), entry.GetTxSize()); + // Feerates are stored and reported as BTC-per-kb: + CFeeRate feeRate(entry->GetFee(), entry->GetTxSize()); feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK()); + return true; } void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight, - std::vector& entries, bool fCurrentEstimate) + std::vector& entries) { if (nBlockHeight <= nBestSeenHeight) { // Ignore side chains and re-orgs; assuming they are random @@ -377,25 +380,30 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight, // transaction fees." return; } - nBestSeenHeight = nBlockHeight; - // Only want to be updating estimates when our blockchain is synced, - // otherwise we'll miscalculate how many blocks its taking to get included. - if (!fCurrentEstimate) - return; + // Must update nBestSeenHeight in sync with ClearCurrent so that + // calls to removeTx (via processBlockTx) correctly calculate age + // of unconfirmed txs to remove from tracking. + nBestSeenHeight = nBlockHeight; - // Clear the current block state + // Clear the current block state and update unconfirmed circular buffer feeStats.ClearCurrent(nBlockHeight); + unsigned int countedTxs = 0; // Repopulate the current block states - for (unsigned int i = 0; i < entries.size(); i++) - processBlockTx(nBlockHeight, entries[i]); + for (unsigned int i = 0; i < entries.size(); i++) { + if (processBlockTx(nBlockHeight, entries[i])) + countedTxs++; + } // Update all exponential averages with the current block state feeStats.UpdateMovingAverages(); - LogPrint("estimatefee", "Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n", - entries.size(), mapMemPoolTxs.size()); + LogPrint("estimatefee", "Blockpolicy after updating estimates for %u of %u txs in block, since last block %u of %u tracked, new mempool map size %u\n", + countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size()); + + trackedTxs = 0; + untrackedTxs = 0; } CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) @@ -426,10 +434,6 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun if (confTarget == 1) confTarget = 2; - // It's not possible to get reasonable estimates for confTarget of 1 - if (confTarget == 1) - confTarget = 2; - double median = -1; while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) { median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); @@ -485,20 +489,3 @@ void CBlockPolicyEstimator::Read(CAutoFile& filein, int nFileVersion) } } -FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee) -{ - CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2); - feeset.insert(0); - for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) { - feeset.insert(bucketBoundary); - } -} - -CAmount FeeFilterRounder::round(CAmount currentMinFee) -{ - std::set::iterator it = feeset.lower_bound(currentMinFee); - if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) { - it--; - } - return *it; -} diff --git a/src/policy/fees.h b/src/policy/fees.h index 6b210892be..187e5930cb 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -203,10 +203,10 @@ class CBlockPolicyEstimator /** Process all the transactions that have been included in a block */ void processBlock(unsigned int nBlockHeight, - std::vector& entries, bool fCurrentEstimate); + std::vector& entries); /** Process a transaction confirmed in a block*/ - void processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry); + bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry); /** Process a transaction accepted to the mempool*/ void processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate); @@ -253,26 +253,13 @@ class CBlockPolicyEstimator TxStatsInfo() : blockHeight(0), bucketIndex(0) {} }; - FastRandomContext insecure_rand; - // map of txids to information about that transaction std::map mapMemPoolTxs; /** Classes to track historical data on transaction confirmations */ TxConfirmStats feeStats; -}; -class FeeFilterRounder -{ -public: - /** Create new FeeFilterRounder */ - FeeFilterRounder(const CFeeRate& minIncrementalFee); - - /** Quantize a minimum fee for privacy purpose before broadcast **/ - CAmount round(CAmount currentMinFee); - -private: - std::set feeset; - FastRandomContext insecure_rand; + unsigned int trackedTxs; + unsigned int untrackedTxs; }; #endif /*DYNAMIC_POLICYESTIMATOR_H */ diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 512edbfdd5..105c10b550 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -156,3 +156,6 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) return true; } + +CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE); +CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE); diff --git a/src/policy/policy.h b/src/policy/policy.h index 78c0a70a35..c984494157 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -19,6 +19,8 @@ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 3145728; // 3MB (75% of MAX_B static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; /** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 200000; +/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ +static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000; /** The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = 400000; // 4MB /** Maximum number of signature check operations in an IsStandard() P2SH script */ @@ -27,6 +29,14 @@ static const unsigned int MAX_P2SH_SIGOPS = 15; static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; /** Default for -maxmempool, maximum megabytes of mempool memory usage */ static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 1200; // 1200MB +/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP 125 replacement **/ +static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000; +/** Min feerate for defining dust. Historically this has been the same as the + * minRelayTxFee, however changing the dust limit changes which transactions are + * standard and should be done with care and ideally rarely. It makes sense to + * only increase the dust limit after prior releases were already not creating + * outputs below the new threshold */ +static const unsigned int DUST_RELAY_TX_FEE = 1000; /** * Standard script verification flags that standard transactions will comply * with. However scripts violating these flags may still be present in valid @@ -65,4 +75,6 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason); */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); +extern CFeeRate incrementalRelayFee; +extern CFeeRate dustRelayFee; #endif // DYNAMIC_POLICY_POLICY_H diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 858671cd7a..ac846aff9e 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -11,6 +11,11 @@ #include "tinyformat.h" #include "utilstrencodings.h" +uint256 CBlockHeader::GetHash() const +{ + return hash_Argon2d(BEGIN(nVersion), END(nNonce), 1); +} + std::string CBlock::ToString() const { std::stringstream s; @@ -23,7 +28,7 @@ std::string CBlock::ToString() const vtx.size()); for (unsigned int i = 0; i < vtx.size(); i++) { - s << " " << vtx[i].ToString() << "\n"; + s << " " << vtx[i]->ToString() << "\n"; } return s.str(); } diff --git a/src/primitives/block.h b/src/primitives/block.h index 91bbdcb32f..a9e481487e 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -62,10 +62,7 @@ class CBlockHeader return (nBits == 0); } - uint256 GetHash() const - { - return hash_Argon2d(BEGIN(nVersion), END(nNonce), 1); - } + uint256 GetHash() const; int64_t GetBlockTime() const { @@ -78,7 +75,7 @@ class CBlock : public CBlockHeader { public: // network and disk - std::vector vtx; + std::vector vtx; // memory only mutable CTxOut txoutDynode; // Dynode payment diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 471992dcc0..0fd7044835 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -87,25 +87,16 @@ std::string CMutableTransaction::ToString() const return str; } -void CTransaction::UpdateHash() const +uint256 CTransaction::ComputeHash() const { - *const_cast(&hash) = SerializeHash(*this); + return SerializeHash(*this); } -CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { } - -CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) { - UpdateHash(); -} +/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */ +CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), hash() {} +CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), hash(ComputeHash()) {} +CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), hash(ComputeHash()) {} -CTransaction& CTransaction::operator=(const CTransaction &tx) { - *const_cast(&nVersion) = tx.nVersion; - *const_cast*>(&vin) = tx.vin; - *const_cast*>(&vout) = tx.vout; - *const_cast(&nLockTime) = tx.nLockTime; - *const_cast(&hash) = tx.hash; - return *this; -} CAmount CTransaction::GetValueOut() const { @@ -114,7 +105,7 @@ CAmount CTransaction::GetValueOut() const { nValueOut += it->nValue; if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut)) - throw std::runtime_error("CTransaction::GetValueOut(): value out of range"); + throw std::runtime_error(std::string(__func__) + ": value out of range"); } return nValueOut; } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 61a30452c2..1cfdd5a73f 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -204,17 +204,12 @@ class CTxOut }; struct CMutableTransaction; -struct CDiskTxPos; + /** The basic transaction that is broadcasted on the network and contained in * blocks. A transaction can contain multiple inputs and outputs. */ class CTransaction { -private: - /** Memory only. */ - const uint256 hash; - void UpdateHash() const; - public: // Default transaction version. static const int32_t CURRENT_VERSION=1; @@ -223,7 +218,7 @@ class CTransaction // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and // MAX_STANDARD_VERSION will be equal. - static const int32_t MAX_STANDARD_VERSION=1; + static const int32_t MAX_STANDARD_VERSION=2; // The local variables are made const to prevent unintended modification // without updating the cached hash value. However, CTransaction is not @@ -235,26 +230,33 @@ class CTransaction const std::vector vout; const uint32_t nLockTime; +private: + /** Memory only. */ + const uint256 hash; + + uint256 ComputeHash() const; + +public: /** Construct a CTransaction that qualifies as IsNull() */ CTransaction(); /** Convert a CMutableTransaction into a CTransaction. */ CTransaction(const CMutableTransaction &tx); - - CTransaction& operator=(const CTransaction& tx); - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(*const_cast(&this->nVersion)); - READWRITE(*const_cast*>(&vin)); - READWRITE(*const_cast*>(&vout)); - READWRITE(*const_cast(&nLockTime)); - if (ser_action.ForRead()) - UpdateHash(); + CTransaction(CMutableTransaction &&tx); + + template + inline void Serialize(Stream& s) const { + s << this->nVersion; + s << vin; + s << vout; + s << nLockTime; } + /** This deserializing constructor is provided instead of an Unserialize method. + * Unserialize is not possible, since it would require overwriting const fields. */ + template + CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {} + bool IsNull() const { return vin.empty() && vout.empty(); } @@ -273,7 +275,7 @@ class CTransaction // Compute modified tx size for priority calculation (optionally given tx size) unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; - + /** * Get the total transaction size in bytes, including witness data. * "Total Size" defined in BIP141 and BIP144. @@ -281,9 +283,6 @@ class CTransaction */ unsigned int GetTotalSize() const; - // Used for DDNS - bool ReadFromDisk(const CDiskTxPos& postx); - bool IsCoinBase() const { return (vin.size() == 1 && vin[0].prevout.IsNull()); @@ -323,6 +322,11 @@ struct CMutableTransaction READWRITE(nLockTime); } + template + CMutableTransaction(deserialize_type, Stream& s) { + Unserialize(s); + } + /** Compute the hash of this CMutableTransaction. This is computed on the * fly, as opposed to GetHash() in CTransaction, which uses a cached result. */ @@ -342,6 +346,10 @@ struct CMutableTransaction }; +typedef std::shared_ptr CTransactionRef; +static inline CTransactionRef MakeTransactionRef() { return std::make_shared(); } +template static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared(std::forward(txIn)); } + /** Implementation of BIP69 * https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki */ diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 76fb450333..13cf9f8223 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -9,8 +9,10 @@ #include "consensus/validation.h" #include "core_io.h" #include "init.h" +#include "dynode-payments.h" #include "dynode-sync.h" #include "dynodeman.h" +#include "netmessagemaker.h" #include "script/sign.h" #include "txmempool.h" #include "util.h" @@ -20,7 +22,7 @@ CPrivateSendClient privateSendClient; -void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman) +void CPrivateSendClient::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) { if(fDynodeMode) return; if(fLiteMode) return; // ignore all Dynamic related functionality @@ -31,7 +33,9 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C if(!lockRecv) return; if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { - LogPrint("privatesend", "PSQUEUE -- incompatible version! nVersion: %d\n", pfrom->nVersion); + LogPrint("privatesend", "PSQUEUE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION))); return; } @@ -39,7 +43,7 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C vRecv >> psq; // process every psq only once - BOOST_FOREACH(CPrivateSendQueue q, vecPrivateSendQueue) { + for (const auto& q : vecPrivateSendQueue) { if(q == psq) { // LogPrint("privatesend", "PSQUEUE -- %s seen\n", psq.ToString()); return; @@ -49,13 +53,14 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C LogPrint("privatesend", "PSQUEUE -- %s new\n", psq.ToString()); if(psq.IsExpired()) return; + if(psq.nInputCount < 0 || psq.nInputCount > PRIVATESEND_ENTRY_MAX_SIZE) return; dynode_info_t infoDn; - if(!dnodeman.GetDynodeInfo(psq.vin.prevout, infoDn)) return; + if(!dnodeman.GetDynodeInfo(psq.dynodeOutpoint, infoDn)) return; if(!psq.CheckSignature(infoDn.pubKeyDynode)) { // we probably have outdated info - dnodeman.AskForDN(pfrom, psq.vin.prevout, connman); + dnodeman.AskForDN(pfrom, psq.dynodeOutpoint, connman); return; } @@ -72,8 +77,8 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C SubmitDenominate(connman); } } else { - BOOST_FOREACH(CPrivateSendQueue q, vecPrivateSendQueue) { - if(q.vin == psq.vin) { + for (const auto& q : vecPrivateSendQueue) { + if(q.dynodeOutpoint == psq.dynodeOutpoint) { // no way same dn can send another "not yet ready" psq this soon LogPrint("privatesend", "PSQUEUE -- Dynode %s is sending WAY too many psq messages\n", infoDn.addr.ToString()); return; @@ -88,10 +93,10 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C return; } - if(!dnodeman.AllowMixing(psq.vin.prevout)) return; + if(!dnodeman.AllowMixing(psq.dynodeOutpoint)) return; LogPrint("privatesend", "PSQUEUE -- new PrivateSend queue (%s) from dynode %s\n", psq.ToString(), infoDn.addr.ToString()); - if(infoMixingDynode.fInfoValid && infoMixingDynode.vin.prevout == psq.vin.prevout) { + if(infoMixingDynode.fInfoValid && infoMixingDynode.outpoint == psq.dynodeOutpoint) { psq.fTried = true; } vecPrivateSendQueue.push_back(psq); @@ -101,7 +106,9 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C } else if(strCommand == NetMsgType::PSSTATUSUPDATE) { if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { - LogPrintf("PSSTATUSUPDATE -- incompatible version! nVersion: %d\n", pfrom->nVersion); + LogPrint("privatesend", "PSSTATUSUPDATE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION))); return; } @@ -118,9 +125,6 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C int nMsgMessageID; vRecv >> nMsgSessionID >> nMsgState >> nMsgEntriesCount >> nMsgStatusUpdate >> nMsgMessageID; - LogPrint("privatesend", "PSSTATUSUPDATE -- nMsgSessionID %d nMsgState: %d nEntriesCount: %d nMsgStatusUpdate: %d nMsgMessageID %d\n", - nMsgSessionID, nMsgState, nEntriesCount, nMsgStatusUpdate, nMsgMessageID); - if(nMsgState < POOL_STATE_MIN || nMsgState > POOL_STATE_MAX) { LogPrint("privatesend", "PSSTATUSUPDATE -- nMsgState is out of bounds: %d\n", nMsgState); return; @@ -136,7 +140,8 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C return; } - LogPrint("privatesend", "PSSTATUSUPDATE -- GetMessageByID: %s\n", CPrivateSend::GetMessageByID(PoolMessage(nMsgMessageID))); + LogPrint("privatesend", "PSSTATUSUPDATE -- nMsgSessionID %d nMsgState: %d nEntriesCount: %d nMsgStatusUpdate: %d nMsgMessageID %d (%s)\n", + nMsgSessionID, nMsgState, nEntriesCount, nMsgStatusUpdate, nMsgMessageID, CPrivateSend::GetMessageByID(PoolMessage(nMsgMessageID))); if(!CheckPoolStateUpdate(PoolState(nMsgState), nMsgEntriesCount, PoolStatusUpdate(nMsgStatusUpdate), PoolMessage(nMsgMessageID), nMsgSessionID)) { LogPrint("privatesend", "PSSTATUSUPDATE -- CheckPoolStateUpdate failed\n"); @@ -145,19 +150,21 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C } else if(strCommand == NetMsgType::PSFINALTX) { if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { - LogPrintf("PSFINALTX -- incompatible version! nVersion: %d\n", pfrom->nVersion); + LogPrint("privatesend", "PSFINALTX -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION))); return; } if(!infoMixingDynode.fInfoValid) return; - if((CNetAddr)infoMixingDynode.addr != (CNetAddr)pfrom->addr) { + if(infoMixingDynode.addr != pfrom->addr) { //LogPrintf("PSFINALTX -- message doesn't match current Dynode: infoMixingDynode %s addr %s\n", infoMixingDynode.addr.ToString(), pfrom->addr.ToString()); return; } int nMsgSessionID; - CTransaction txNew; - vRecv >> nMsgSessionID >> txNew; + vRecv >> nMsgSessionID; + CTransaction txNew(deserialize, vRecv); if(nSessionID != nMsgSessionID) { LogPrint("privatesend", "PSFINALTX -- message doesn't match current PrivateSend session: nSessionID: %d nMsgSessionID: %d\n", nSessionID, nMsgSessionID); @@ -172,7 +179,9 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C } else if(strCommand == NetMsgType::PSCOMPLETE) { if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { - LogPrintf("PSCOMPLETE -- incompatible version! nVersion: %d\n", pfrom->nVersion); + LogPrint("privatesend", "PSCOMPLETE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION))); return; } @@ -218,6 +227,7 @@ void CPrivateSendClient::SetNull() nEntriesCount = 0; fLastEntryAccepted = false; infoMixingDynode = dynode_info_t(); + pendingPsaRequest = CPendingPsaRequest(); CPrivateSendBase::SetNull(); } @@ -230,7 +240,7 @@ void CPrivateSendClient::UnlockCoins() while(true) { TRY_LOCK(pwalletMain->cs_wallet, lockWallet); if(!lockWallet) {MilliSleep(50); continue;} - BOOST_FOREACH(COutPoint outpoint, vecOutPointLocked) + for (const auto& outpoint : vecOutPointLocked) pwalletMain->UnlockCoin(outpoint); break; } @@ -304,7 +314,7 @@ bool CPrivateSendClient::IsMixingDynode(const CNode* pnode) void CPrivateSendClient::CheckPool() { // reset if we're here for 10 seconds - if((nState == POOL_STATE_ERROR || nState == POOL_STATE_SUCCESS) && GetTimeMillis() - nTimeLastSuccessfulStep >= 10000) { + if((nState == POOL_STATE_ERROR || nState == POOL_STATE_SUCCESS) && GetTime() - nTimeLastSuccessfulStep >= 10) { LogPrint("privatesend", "CPrivateSendClient::CheckPool -- timeout, RESETTING\n"); UnlockCoins(); if (nState == POOL_STATE_ERROR) { @@ -321,32 +331,32 @@ void CPrivateSendClient::CheckPool() // void CPrivateSendClient::CheckTimeout() { + if(fDynodeMode) return; + CheckQueue(); - if(!fEnablePrivateSend && !fDynodeMode) return; + if(!fEnablePrivateSend) return; // catching hanging sessions - if(!fDynodeMode) { - switch(nState) { - case POOL_STATE_ERROR: - LogPrint("privatesend", "CPrivateSendClient::CheckTimeout -- Pool error -- Running CheckPool\n"); - CheckPool(); - break; - case POOL_STATE_SUCCESS: - LogPrint("privatesend", "CPrivateSendClient::CheckTimeout -- Pool success -- Running CheckPool\n"); - CheckPool(); - break; - default: - break; - } + switch(nState) { + case POOL_STATE_ERROR: + LogPrint("privatesend", "CPrivateSendClient::CheckTimeout -- Pool error -- Running CheckPool\n"); + CheckPool(); + break; + case POOL_STATE_SUCCESS: + LogPrint("privatesend", "CPrivateSendClient::CheckTimeout -- Pool success -- Running CheckPool\n"); + CheckPool(); + break; + default: + break; } - int nLagTime = fDynodeMode ? 0 : 10000; // if we're the client, give the server a few extra seconds before resetting. + int nLagTime = 10; // give the server a few extra seconds before resetting. int nTimeout = (nState == POOL_STATE_SIGNING) ? PRIVATESEND_SIGNING_TIMEOUT : PRIVATESEND_QUEUE_TIMEOUT; - bool fTimeout = GetTimeMillis() - nTimeLastSuccessfulStep >= nTimeout*1000 + nLagTime; + bool fTimeout = GetTime() - nTimeLastSuccessfulStep >= nTimeout + nLagTime; if(nState != POOL_STATE_IDLE && fTimeout) { - LogPrint("privatesend", "CPrivateSendClient::CheckTimeout -- %s timed out (%ds) -- restting\n", + LogPrint("privatesend", "CPrivateSendClient::CheckTimeout -- %s timed out (%ds) -- resetting\n", (nState == POOL_STATE_SIGNING) ? "Signing" : "Session", nTimeout); UnlockCoins(); keyHolderStorage.ReturnAll(); @@ -373,11 +383,11 @@ bool CPrivateSendClient::SendDenominate(const std::vector& vecTxPSIn, c } // lock the funds we're going to use - BOOST_FOREACH(CTxIn txin, txMyCollateral.vin) + for (const auto& txin : txMyCollateral.vin) vecOutPointLocked.push_back(txin.prevout); - for (const auto& txpsin : vecTxPSIn) - vecOutPointLocked.push_back(txpsin.prevout); + for (const auto& txdsin : vecTxPSIn) + vecOutPointLocked.push_back(txdsin.prevout); // we should already be connected to a Dynode if(!nSessionID) { @@ -402,39 +412,29 @@ bool CPrivateSendClient::SendDenominate(const std::vector& vecTxPSIn, c LogPrintf("CPrivateSendClient::SendDenominate -- Added transaction to pool.\n"); - //check it against the memory pool to make sure it's valid { - CValidationState validationState; + // construct a pseudo tx, for debugging purpuses only + CMutableTransaction tx; - for (const auto& txpsin : vecTxPSIn) { - LogPrint("privatesend", "CPrivateSendClient::SendDenominate -- txpsin=%s\n", txpsin.ToString()); - tx.vin.push_back(txpsin); + for (const auto& txdsin : vecTxPSIn) { + LogPrint("privatesend", "CPrivateSendClient::SendDenominate -- txdsin=%s\n", txdsin.ToString()); + tx.vin.push_back(txdsin); } - BOOST_FOREACH(const CTxOut& txout, vecTxOut) { + for (const CTxOut& txout : vecTxOut) { LogPrint("privatesend", "CPrivateSendClient::SendDenominate -- txout=%s\n", txout.ToString()); tx.vout.push_back(txout); } LogPrintf("CPrivateSendClient::SendDenominate -- Submitting partial tx %s", tx.ToString()); - - mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), 1000, 0.1*COIN); - TRY_LOCK(cs_main, lockMain); - if(!lockMain || !AcceptToMemoryPool(mempool, validationState, CTransaction(tx), false, NULL, false, maxTxFee, true)) { - LogPrintf("CPrivateSendClient::SendDenominate -- AcceptToMemoryPool() failed! tx=%s", tx.ToString()); - UnlockCoins(); - keyHolderStorage.ReturnAll(); - SetNull(); - return false; - } } // store our entry for later use CPrivateSendEntry entry(vecTxPSIn, vecTxOut, txMyCollateral); vecEntries.push_back(entry); RelayIn(entry, connman); - nTimeLastSuccessfulStep = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTime(); return true; } @@ -464,13 +464,13 @@ bool CPrivateSendClient::CheckPoolStateUpdate(PoolState nStateNew, int nEntriesC if(nStateNew == POOL_STATE_QUEUE && nSessionID == 0 && nSessionIDNew != 0) { // new session id should be set only in POOL_STATE_QUEUE state nSessionID = nSessionIDNew; - nTimeLastSuccessfulStep = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTime(); LogPrintf("CPrivateSendClient::CheckPoolStateUpdate -- set nSessionID to %d\n", nSessionID); return true; } else if(nStateNew == POOL_STATE_ACCEPTING_ENTRIES && nEntriesCount != nEntriesCountNew) { nEntriesCount = nEntriesCountNew; - nTimeLastSuccessfulStep = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTime(); fLastEntryAccepted = true; LogPrintf("CPrivateSendClient::CheckPoolStateUpdate -- new entry accepted!\n"); return true; @@ -488,26 +488,38 @@ bool CPrivateSendClient::CheckPoolStateUpdate(PoolState nStateNew, int nEntriesC // bool CPrivateSendClient::SignFinalTransaction(const CTransaction& finalTransactionNew, CNode* pnode, CConnman& connman) { - if(fDynodeMode || pnode == NULL) return false; + if(fDynodeMode || pnode == nullptr) return false; finalMutableTransaction = finalTransactionNew; LogPrintf("CPrivateSendClient::SignFinalTransaction -- finalMutableTransaction=%s", finalMutableTransaction.ToString()); + // Make sure it's BIP69 compliant + sort(finalMutableTransaction.vin.begin(), finalMutableTransaction.vin.end(), CompareInputBIP69()); + sort(finalMutableTransaction.vout.begin(), finalMutableTransaction.vout.end(), CompareOutputBIP69()); + + if(finalMutableTransaction.GetHash() != finalTransactionNew.GetHash()) { + LogPrintf("CPrivateSendClient::SignFinalTransaction -- WARNING! Dynode %s is not BIP69 compliant!\n", infoMixingDynode.outpoint.ToStringShort()); + UnlockCoins(); + keyHolderStorage.ReturnAll(); + SetNull(); + return false; + } + std::vector sigs; //make sure my inputs/outputs are present, otherwise refuse to sign - BOOST_FOREACH(const CPrivateSendEntry entry, vecEntries) { - BOOST_FOREACH(const CTxPSIn txpsin, entry.vecTxPSIn) { + for (const auto& entry : vecEntries) { + for (const auto& txdsin : entry.vecTxPSIn) { /* Sign my transaction and all outputs */ int nMyInputIndex = -1; CScript prevPubKey = CScript(); CTxIn txin = CTxIn(); for(unsigned int i = 0; i < finalMutableTransaction.vin.size(); i++) { - if(finalMutableTransaction.vin[i] == txpsin) { + if(finalMutableTransaction.vin[i] == txdsin) { nMyInputIndex = i; - prevPubKey = txpsin.prevPubKey; - txin = txpsin; + prevPubKey = txdsin.prevPubKey; + txin = txdsin; } } @@ -565,9 +577,10 @@ bool CPrivateSendClient::SignFinalTransaction(const CTransaction& finalTransacti // push all of our signatures to the Dynode LogPrintf("CPrivateSendClient::SignFinalTransaction -- pushing sigs to the dynode, finalMutableTransaction=%s", finalMutableTransaction.ToString()); - connman.PushMessage(pnode, NetMsgType::PSSIGNFINALTX, sigs); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSSIGNFINALTX, sigs)); SetState(POOL_STATE_SIGNING); - nTimeLastSuccessfulStep = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTime(); return true; } @@ -590,6 +603,11 @@ void CPrivateSendClient::CompletedTransaction(PoolMessage nMessageID) strLastMessage = CPrivateSend::GetMessageByID(nMessageID); } +bool CPrivateSendClient::IsDenomSkipped(CAmount nDenomValue) +{ + return std::find(vecDenominationsSkipped.begin(), vecDenominationsSkipped.end(), nDenomValue) != vecDenominationsSkipped.end(); +} + bool CPrivateSendClient::WaitForAnotherBlock() { if(!dynodeSync.IsDynodeListSynced()) @@ -613,14 +631,14 @@ bool CPrivateSendClient::CheckAutomaticBackup() case -1: // Automatic backup failed, nothing else we can do until user fixes the issue manually. // There is no way to bring user attention in daemon mode so we just update status and - // keep spaming if debug is on. + // keep spamming if debug is on. LogPrint("privatesend", "CPrivateSendClient::CheckAutomaticBackup -- ERROR! Failed to create automatic backup.\n"); strAutoDenomResult = _("ERROR! Failed to create automatic backup") + ", " + _("see debug.log for details."); return false; case -2: // We were able to create automatic backup but keypool was not replenished because wallet is locked. // There is no way to bring user attention in daemon mode so we just update status and - // keep spaming if debug is on. + // keep spamming if debug is on. LogPrint("privatesend", "CPrivateSendClient::CheckAutomaticBackup -- WARNING! Failed to create replenish keypool, please unlock your wallet to do so.\n"); strAutoDenomResult = _("WARNING! Failed to replenish keypool, please unlock your wallet to do so.") + ", " + _("see debug.log for details."); return false; @@ -689,8 +707,8 @@ bool CPrivateSendClient::DoAutomaticDenominating(CConnman& connman, bool fDryRun return false; } - TRY_LOCK(cs_privatesend, lockPS); - if(!lockPS) { + TRY_LOCK(cs_privatesend, lockDS); + if(!lockDS) { strAutoDenomResult = _("Lock is already in place."); return false; } @@ -714,7 +732,7 @@ bool CPrivateSendClient::DoAutomaticDenominating(CConnman& connman, bool fDryRun CAmount nValueMin = CPrivateSend::GetSmallestDenomination(); - // if there are no confirmed PS collateral inputs yet + // if there are no confirmed DS collateral inputs yet if(!pwalletMain->HasCollateralInputs()) { // should have some additional amount for them nValueMin += CPrivateSend::GetMaxCollateralAmount(); @@ -823,7 +841,7 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CCon { std::vector vecStandardDenoms = CPrivateSend::GetStandardDenominations(); // Look through the queues and see if anything matches - BOOST_FOREACH(CPrivateSendQueue& psq, vecPrivateSendQueue) { + for (auto& psq : vecPrivateSendQueue) { // only try each queue once if(psq.fTried) continue; psq.fTried = true; @@ -832,13 +850,19 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CCon dynode_info_t infoDn; - if(!dnodeman.GetDynodeInfo(psq.vin.prevout, infoDn)) { - LogPrintf("CPrivateSendClient::JoinExistingQueue -- psq dynode is not in dynode list, dynode=%s\n", psq.vin.prevout.ToStringShort()); + if(!dnodeman.GetDynodeInfo(psq.dynodeOutpoint, infoDn)) { + LogPrintf("CPrivateSendClient::JoinExistingQueue -- psq dynode is not in dynode list, dynode=%s\n", psq.dynodeOutpoint.ToStringShort()); continue; } if(infoDn.nProtocolVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) continue; + // skip next dn payments winners + if (dnpayments.IsScheduled(infoDn, 0)) { + LogPrintf("CPrivateSendClient::JoinExistingQueue -- skipping winner, dynode=%s\n", infoDn.outpoint.ToStringShort()); + continue; + } + std::vector vecBits; if(!CPrivateSend::GetDenominationsBits(psq.nDenom, vecBits)) { // incompatible denom @@ -854,45 +878,42 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CCon CAmount nValueInTmp = 0; std::vector vecTxPSInTmp; std::vector vCoinsTmp; - - // Try to match their denominations if possible, select at least 1 denominations - if(!pwalletMain->SelectCoinsByDenominations(psq.nDenom, vecStandardDenoms[vecBits.front()], nBalanceNeedsAnonymized, vecTxPSInTmp, vCoinsTmp, nValueInTmp, 0, nPrivateSendRounds + (bool)nLiquidityProvider)) { - LogPrintf("CPrivateSendClient::JoinExistingQueue -- Couldn't match denominations %d %d (%s)\n", vecBits.front(), psq.nDenom, CPrivateSend::GetDenominationsToString(psq.nDenom)); + CAmount nMinAmount = vecStandardDenoms[vecBits.front()]; + CAmount nMaxAmount = nBalanceNeedsAnonymized; + // nInputCount is not covered by legacy signature, require SPORK_6_NEW_SIGS to activate to use new algo + // (to make sure nInputCount wasn't modified by some intermediary node) + bool fNewAlgo = infoDn.nProtocolVersion > 70900 && sporkManager.IsSporkActive(SPORK_6_NEW_SIGS); + + if (fNewAlgo && psq.nInputCount != 0) { + nMinAmount = nMaxAmount = psq.nInputCount * vecStandardDenoms[vecBits.front()]; + } + // Try to match their denominations if possible, select exact number of denominations + if(!pwalletMain->SelectCoinsByDenominations(psq.nDenom, nMinAmount, nMaxAmount, vecTxPSInTmp, vCoinsTmp, nValueInTmp, 0, nPrivateSendRounds)) { + LogPrintf("CPrivateSendClient::JoinExistingQueue -- Couldn't match %d denominations %d %d (%s)\n", psq.nInputCount, vecBits.front(), psq.nDenom, CPrivateSend::GetDenominationsToString(psq.nDenom)); continue; } - vecDynodesUsed.push_back(psq.vin.prevout); + vecDynodesUsed.push_back(psq.dynodeOutpoint); - bool fSkip = false; - connman.ForNode(infoDn.addr, CConnman::AllNodes, [&fSkip](CNode* pnode) { - fSkip = pnode->fDisconnect || pnode->fDynode; - return true; - }); - if (fSkip) { + if (connman.IsDynodeOrDisconnectRequested(infoDn.addr)) { LogPrintf("CPrivateSendClient::JoinExistingQueue -- skipping dynode connection, addr=%s\n", infoDn.addr.ToString()); continue; } - LogPrintf("CPrivateSendClient::JoinExistingQueue -- attempt to connect to dynode from queue, addr=%s\n", infoDn.addr.ToString()); - // connect to Dynode and submit the queue request - CNode* pnode = connman.ConnectNode(CAddress(infoDn.addr, NODE_NETWORK), NULL, false, true); - if(pnode) { - infoMixingDynode = infoDn; - nSessionDenom = psq.nDenom; - - connman.PushMessage(pnode, NetMsgType::PSACCEPT, nSessionDenom, txMyCollateral); - LogPrintf("CPrivateSendClient::JoinExistingQueue -- connected (from queue), sending PSACCEPT: nSessionDenom: %d (%s), addr=%s\n", - nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), pnode->addr.ToString()); - strAutoDenomResult = _("Mixing in progress..."); - SetState(POOL_STATE_QUEUE); - nTimeLastSuccessfulStep = GetTimeMillis(); - return true; - } else { - LogPrintf("CPrivateSendClient::JoinExistingQueue -- can't connect, addr=%s\n", infoDn.addr.ToString()); - strAutoDenomResult = _("Error connecting to Dynode."); - continue; - } + nSessionDenom = psq.nDenom; + nSessionInputCount = fNewAlgo ? psq.nInputCount : 0; + infoMixingDynode = infoDn; + pendingPsaRequest = CPendingPsaRequest(infoDn.addr, CPrivateSendAccept(nSessionDenom, nSessionInputCount, txMyCollateral)); + connman.AddPendingDynode(infoDn.addr); + // TODO: add new state POOL_STATE_CONNECTING and bump MIN_PRIVATESEND_PEER_PROTO_VERSION + SetState(POOL_STATE_QUEUE); + nTimeLastSuccessfulStep = GetTime(); + LogPrintf("CPrivateSendClient::JoinExistingQueue -- pending connection (from queue): nSessionDenom: %d (%s), nSessionInputCount: %d, addr=%s\n", + nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), nSessionInputCount, infoDn.addr.ToString()); + strAutoDenomResult = _("Trying to connect..."); + return true; } + strAutoDenomResult = _("Failed to find mixing queue to join"); return false; } @@ -914,62 +935,107 @@ bool CPrivateSendClient::StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsA // otherwise, try one randomly while(nTries < 10) { dynode_info_t infoDn = dnodeman.FindRandomNotInVec(vecDynodesUsed, MIN_PRIVATESEND_PEER_PROTO_VERSION); + if(!infoDn.fInfoValid) { LogPrintf("CPrivateSendClient::StartNewQueue -- Can't find random dynode!\n"); strAutoDenomResult = _("Can't find random Dynode."); return false; } - vecDynodesUsed.push_back(infoDn.vin.prevout); + + // skip next dn payments winners + if (dnpayments.IsScheduled(infoDn, 0)) { + LogPrintf("CPrivateSendClient::StartNewQueue -- skipping winner, dynode=%s\n", infoDn.outpoint.ToStringShort()); + nTries++; + continue; + } + + vecDynodesUsed.push_back(infoDn.outpoint); if(infoDn.nLastPsq != 0 && infoDn.nLastPsq + nDnCountEnabled/5 > dnodeman.nPsqCount) { LogPrintf("CPrivateSendClient::StartNewQueue -- Too early to mix on this dynode!" " dynode=%s addr=%s nLastPsq=%d CountEnabled/5=%d nPsqCount=%d\n", - infoDn.vin.prevout.ToStringShort(), infoDn.addr.ToString(), infoDn.nLastPsq, + infoDn.outpoint.ToStringShort(), infoDn.addr.ToString(), infoDn.nLastPsq, nDnCountEnabled/5, dnodeman.nPsqCount); nTries++; continue; } - bool fSkip = false; - connman.ForNode(infoDn.addr, CConnman::AllNodes, [&fSkip](CNode* pnode) { - fSkip = pnode->fDisconnect || pnode->fDynode; - return true; - }); - if (fSkip) { + if (connman.IsDynodeOrDisconnectRequested(infoDn.addr)) { LogPrintf("CPrivateSendClient::StartNewQueue -- skipping dynode connection, addr=%s\n", infoDn.addr.ToString()); nTries++; continue; } LogPrintf("CPrivateSendClient::StartNewQueue -- attempt %d connection to Dynode %s\n", nTries, infoDn.addr.ToString()); - CNode* pnode = connman.ConnectNode(CAddress(infoDn.addr, NODE_NETWORK), NULL, false, true); - if(pnode) { - LogPrintf("CPrivateSendClient::StartNewQueue -- connected, addr=%s\n", infoDn.addr.ToString()); - infoMixingDynode = infoDn; - - std::vector vecAmounts; - pwalletMain->ConvertList(vecTxIn, vecAmounts); - // try to get a single random denom out of vecAmounts - while(nSessionDenom == 0) { - nSessionDenom = CPrivateSend::GetDenominationsByAmounts(vecAmounts); - } - connman.PushMessage(pnode, NetMsgType::PSACCEPT, nSessionDenom, txMyCollateral); - LogPrintf("CPrivateSendClient::StartNewQueue -- connected, sending PSACCEPT, nSessionDenom: %d (%s)\n", - nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); - strAutoDenomResult = _("Mixing in progress..."); - SetState(POOL_STATE_QUEUE); - nTimeLastSuccessfulStep = GetTimeMillis(); - return true; - } else { - LogPrintf("CPrivateSendClient::StartNewQueue -- can't connect, addr=%s\n", infoDn.addr.ToString()); - nTries++; - continue; + std::vector vecAmounts; + pwalletMain->ConvertList(vecTxIn, vecAmounts); + // try to get a single random denom out of vecAmounts + while(nSessionDenom == 0) { + nSessionDenom = CPrivateSend::GetDenominationsByAmounts(vecAmounts); } + + // Count available denominations. + // Should never really fail after this point, since we just selected compatible inputs ourselves. + std::vector vecBits; + if (!CPrivateSend::GetDenominationsBits(nSessionDenom, vecBits)) { + return false; + } + + CAmount nValueInTmp = 0; + std::vector vecTxPSInTmp; + std::vector vCoinsTmp; + std::vector vecStandardDenoms = CPrivateSend::GetStandardDenominations(); + + bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], vecStandardDenoms[vecBits.front()] * PRIVATESEND_ENTRY_MAX_SIZE, vecTxPSInTmp, vCoinsTmp, nValueInTmp, 0, nPrivateSendRounds); + if (!fSelected) { + return false; + } + + // nInputCount is not covered by legacy signature, require SPORK_6_NEW_SIGS to activate to use new algo + // (to make sure nInputCount wasn't modified by some intermediary node) + bool fNewAlgo = infoDn.nProtocolVersion > 70900 && sporkManager.IsSporkActive(SPORK_6_NEW_SIGS); + nSessionInputCount = fNewAlgo + ? std::min(vecTxPSInTmp.size(), size_t(5 + GetRand(PRIVATESEND_ENTRY_MAX_SIZE - 5 + 1))) + : 0; + infoMixingDynode = infoDn; + connman.AddPendingDynode(infoDn.addr); + pendingPsaRequest = CPendingPsaRequest(infoDn.addr, CPrivateSendAccept(nSessionDenom, nSessionInputCount, txMyCollateral)); + // TODO: add new state POOL_STATE_CONNECTING and bump MIN_PRIVATESEND_PEER_PROTO_VERSION + SetState(POOL_STATE_QUEUE); + nTimeLastSuccessfulStep = GetTime(); + LogPrintf("CPrivateSendClient::StartNewQueue -- pending connection, nSessionDenom: %d (%s), nSessionInputCount: %d, addr=%s\n", + nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), nSessionInputCount, infoDn.addr.ToString()); + strAutoDenomResult = _("Trying to connect..."); + return true; } + strAutoDenomResult = _("Failed to start a new mixing queue"); return false; } +void CPrivateSendClient::ProcessPendingPsaRequest(CConnman& connman) +{ + if (!pendingPsaRequest) return; + + bool fDone = connman.ForNode(pendingPsaRequest.GetAddr(), [&](CNode* pnode) { + LogPrint("privatesend", "-- processing psa queue for addr=%s\n", pnode->addr.ToString()); + nTimeLastSuccessfulStep = GetTime(); + // TODO: this vvvv should be here after new state POOL_STATE_CONNECTING is added and MIN_PRIVATESEND_PEER_PROTO_VERSION is bumped + // SetState(POOL_STATE_QUEUE); + strAutoDenomResult = _("Mixing in progress..."); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSACCEPT, pendingPsaRequest.GetPSA())); + return true; + }); + + if (fDone) { + pendingPsaRequest = CPendingPsaRequest(); + } else if (pendingPsaRequest.IsExpired()) { + LogPrint("privatesend", "CPrivateSendClient::%s -- failed to connect to %s\n", __func__, pendingPsaRequest.GetAddr().ToString()); + SetNull(); + } +} + bool CPrivateSendClient::SubmitDenominate(CConnman& connman) { std::string strError; @@ -977,17 +1043,28 @@ bool CPrivateSendClient::SubmitDenominate(CConnman& connman) std::vector vecTxOutRet; // Submit transaction to the pool if we get here - // Try to use only inputs with the same number of rounds starting from the highest number of rounds possible - for(int i = nPrivateSendRounds + (bool)nLiquidityProvider; i > 0; i--) { - if(PrepareDenominate(i - 1, i, strError, vecTxPSInRet, vecTxOutRet)) { - LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i); - return SendDenominate(vecTxPSInRet, vecTxOutRet, connman); + if (nLiquidityProvider) { + // Try to use only inputs with the same number of rounds starting from the lowest number of rounds possible + for(int i = 0; i< nPrivateSendRounds; i++) { + if(PrepareDenominate(i, i + 1, strError, vecTxPSInRet, vecTxOutRet)) { + LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i); + return SendDenominate(vecTxPSInRet, vecTxOutRet, connman); + } + LogPrint("privatesend", "CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError); + } + } else { + // Try to use only inputs with the same number of rounds starting from the highest number of rounds possible + for(int i = nPrivateSendRounds; i > 0; i--) { + if(PrepareDenominate(i - 1, i, strError, vecTxPSInRet, vecTxOutRet)) { + LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i); + return SendDenominate(vecTxPSInRet, vecTxOutRet, connman); + } + LogPrint("privatesend", "CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError); } - LogPrint("privatesend", "CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError); } // We failed? That's strange but let's just make final attempt and try to mix everything - if(PrepareDenominate(0, nPrivateSendRounds + (bool)nLiquidityProvider, strError, vecTxPSInRet, vecTxOutRet)) { + if(PrepareDenominate(0, nPrivateSendRounds, strError, vecTxPSInRet, vecTxOutRet)) { LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for all rounds, success\n"); return SendDenominate(vecTxPSInRet, vecTxOutRet, connman); } @@ -1035,7 +1112,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std:: return false; } std::vector vecStandardDenoms = CPrivateSend::GetStandardDenominations(); - bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], CPrivateSend::GetMaxPoolAmount(), vecTxPSIn, vCoins, nValueIn, nMinRounds, nMaxRounds); + bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], vecStandardDenoms[vecBits.front()] * PRIVATESEND_ENTRY_MAX_SIZE, vecTxPSIn, vCoins, nValueIn, nMinRounds, nMaxRounds); if (nMinRounds >= 0 && !fSelected) { strErrorRet = "Can't select current denominated inputs"; return false; @@ -1045,7 +1122,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std:: { LOCK(pwalletMain->cs_wallet); - for (auto& txin : vecTxPSIn) { + for (const auto& txin : vecTxPSIn) { pwalletMain->LockCoin(txin.prevout); } } @@ -1056,10 +1133,10 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std:: // NOTE: No need to randomize order of inputs because they were // initially shuffled in CWallet::SelectCoinsByDenominations already. int nStep = 0; - int nStepsMax = 5 + GetRandInt(PRIVATESEND_ENTRY_MAX_SIZE-5+1); + int nStepsMax = nSessionInputCount != 0 ? nSessionInputCount : (5 + GetRandInt(PRIVATESEND_ENTRY_MAX_SIZE - 5 + 1)); while (nStep < nStepsMax) { - BOOST_FOREACH(int nBit, vecBits) { + for (const auto& nBit : vecBits) { CAmount nValueDenom = vecStandardDenoms[nBit]; if (nValueLeft - nValueDenom < 0) continue; @@ -1068,14 +1145,14 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std:: std::vector::iterator it2 = vCoins.begin(); while (it2 != vCoins.end()) { // we have matching inputs - if ((*it2).tx->vout[(*it2).i].nValue == nValueDenom) { + if ((*it2).tx->tx->vout[(*it2).i].nValue == nValueDenom) { // add new input in resulting vector vecTxPSInRet.push_back(*it); - // remove corresponting items from initial vectors + // remove corresponding items from initial vectors vecTxPSIn.erase(it); vCoins.erase(it2); - CScript scriptDenom = keyHolderStorage.AddKey(pwalletMain).GetScriptForDestination(); + CScript scriptDenom = keyHolderStorage.AddKey(pwalletMain); // add new output CTxOut txout(nValueDenom, scriptDenom); @@ -1098,16 +1175,18 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std:: { // unlock unused coins LOCK(pwalletMain->cs_wallet); - for (auto& txin : vecTxPSIn) { + for (const auto& txin : vecTxPSIn) { pwalletMain->UnlockCoin(txin.prevout); } } - if (CPrivateSend::GetDenominations(vecTxOutRet) != nSessionDenom) { - // unlock used coins on failure - LOCK(pwalletMain->cs_wallet); - for (auto& txin : vecTxPSInRet) { - pwalletMain->UnlockCoin(txin.prevout); + if (CPrivateSend::GetDenominations(vecTxOutRet) != nSessionDenom || (nSessionInputCount != 0 && vecTxOutRet.size() != nSessionInputCount)) { + { + // unlock used coins on failure + LOCK(pwalletMain->cs_wallet); + for (const auto& txin : vecTxPSInRet) { + pwalletMain->UnlockCoin(txin.prevout); + } } keyHolderStorage.ReturnAll(); strErrorRet = "Can't make current denominated outputs"; @@ -1128,13 +1207,13 @@ bool CPrivateSendClient::MakeCollateralAmounts(CConnman& connman) } // First try to use only non-denominated funds - BOOST_FOREACH(CompactTallyItem& item, vecTally) { + for (const auto& item : vecTally) { if(!MakeCollateralAmounts(item, false, connman)) continue; return true; } // There should be at least some denominated funds we should be able to break in pieces to continue mixing - BOOST_FOREACH(CompactTallyItem& item, vecTally) { + for (const auto& item : vecTally) { if(!MakeCollateralAmounts(item, true, connman)) continue; return true; } @@ -1147,11 +1226,10 @@ bool CPrivateSendClient::MakeCollateralAmounts(CConnman& connman) // Split up large inputs or create fee sized inputs bool CPrivateSendClient::MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated, CConnman& connman) { - LOCK2(cs_main, pwalletMain->cs_wallet); // denominated input is always a single one, so we can check its amount directly and return early - if(!fTryDenominated && tallyItem.vecTxIn.size() == 1 && CPrivateSend::IsDenominatedAmount(tallyItem.nAmount)) + if(!fTryDenominated && tallyItem.vecOutPoints.size() == 1 && CPrivateSend::IsDenominatedAmount(tallyItem.nAmount)) return false; CWalletTx wtx; @@ -1178,17 +1256,16 @@ bool CPrivateSendClient::MakeCollateralAmounts(const CompactTallyItem& tallyItem coinControl.fAllowWatchOnly = false; // send change to the same address so that we were able create more denoms out of it later coinControl.destChange = tallyItem.txdest; - BOOST_FOREACH(const CTxIn& txin, tallyItem.vecTxIn) - coinControl.Select(txin.prevout); + for (const auto& outpoint : tallyItem.vecOutPoints) + coinControl.Select(outpoint); bool fSuccess = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, nFeeRet, nChangePosRet, strFail, &coinControl, true, ONLY_NONDENOMINATED); if(!fSuccess) { - LogPrintf("CPrivateSendClient::MakeCollateralAmounts -- ONLY_NONDENOMINATED Error: %s\n", strFail); - // If we failed then most likeky there are not enough funds on this address. + LogPrintf("CPrivateSendClient::MakeCollateralAmounts -- ONLY_NONDENOMINATED: %s\n", strFail); + // If we failed then most likely there are not enough funds on this address. if(fTryDenominated) { // Try to also use denominated coins (we can't mix denominated without collaterals anyway). - // DN-like funds should not be touched in any case. if(!pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, nFeeRet, nChangePosRet, strFail, &coinControl, true, ALL_COINS)) { LogPrintf("CPrivateSendClient::MakeCollateralAmounts -- ALL_COINS Error: %s\n", strFail); @@ -1206,7 +1283,7 @@ bool CPrivateSendClient::MakeCollateralAmounts(const CompactTallyItem& tallyItem LogPrintf("CPrivateSendClient::MakeCollateralAmounts -- txid=%s\n", wtx.GetHash().GetHex()); - // use the same nCachedLastSuccessBlock as for PS mixing to prevent race + // use the same nCachedLastSuccessBlock as for DS mixing to prevent race CValidationState state; if(!pwalletMain->CommitTransaction(wtx, reservekeyChange, &connman, state)) { LogPrintf("CPrivateSendClient::MakeCollateralAmounts -- CommitTransaction failed! Reason given: %s\n", state.GetRejectReason()); @@ -1231,7 +1308,7 @@ bool CPrivateSendClient::CreateDenominated(CConnman& connman) bool fCreateMixingCollaterals = !pwalletMain->HasCollateralInputs(); - BOOST_FOREACH(CompactTallyItem& item, vecTally) { + for (const auto& item : vecTally) { if(!CreateDenominated(item, fCreateMixingCollaterals, connman)) continue; return true; } @@ -1249,12 +1326,12 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo CAmount nValueLeft = tallyItem.nAmount; nValueLeft -= CPrivateSend::GetCollateralAmount(); // leave some room for fees - LogPrintf("CreateDenominated0 nValueLeft: %f\n", (float)nValueLeft/COIN); + LogPrintf("CreateDenominated0: %s nValueLeft: %f\n", CDynamicAddress(tallyItem.txdest).ToString(), (float)nValueLeft/COIN); // ****** Add an output for mixing collaterals ************ / if(fCreateMixingCollaterals) { - CScript scriptCollateral = keyHolderStorageDenom.AddKey(pwalletMain).GetScriptForDestination(); + CScript scriptCollateral = keyHolderStorageDenom.AddKey(pwalletMain); vecSend.push_back((CRecipient){ scriptCollateral, CPrivateSend::GetMaxCollateralAmount(), false }); nValueLeft -= CPrivateSend::GetMaxCollateralAmount(); } @@ -1262,13 +1339,13 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo // ****** Add outputs for denoms ************ / // try few times - skipping smallest denoms first if there are too many of them already, if failed - use them too - int nOutputsTotal = 0; bool fSkip = true; do { std::vector vecStandardDenoms = CPrivateSend::GetStandardDenominations(); - BOOST_REVERSE_FOREACH(CAmount nDenomValue, vecStandardDenoms) { + for (auto it = vecStandardDenoms.rbegin(); it != vecStandardDenoms.rend(); ++it) { + CAmount nDenomValue = *it; if(fSkip) { // Note: denoms are skipped if there are already DENOMS_COUNT_MAX of them @@ -1290,7 +1367,7 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo // add each output up to 11 times until it can't be added again while(nValueLeft - nDenomValue >= 0 && nOutputs <= 10) { - CScript scriptDenom = keyHolderStorageDenom.AddKey(pwalletMain).GetScriptForDestination(); + CScript scriptDenom = keyHolderStorageDenom.AddKey(pwalletMain); vecSend.push_back((CRecipient){ scriptDenom, nDenomValue, false }); @@ -1316,8 +1393,8 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo coinControl.fAllowWatchOnly = false; // send change to the same address so that we were able create more denoms out of it later coinControl.destChange = tallyItem.txdest; - BOOST_FOREACH(const CTxIn& txin, tallyItem.vecTxIn) - coinControl.Select(txin.prevout); + for (const auto& outpoint : tallyItem.vecOutPoints) + coinControl.Select(outpoint); CWalletTx wtx; CAmount nFeeRet = 0; @@ -1342,7 +1419,7 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo return false; } - // use the same nCachedLastSuccessBlock as for PS mixing to prevent race + // use the same nCachedLastSuccessBlock as for DS mixing to prevent race nCachedLastSuccessBlock = nCachedBlockHeight; LogPrintf("CPrivateSendClient::CreateDenominated -- txid=%s\n", wtx.GetHash().GetHex()); @@ -1355,7 +1432,8 @@ void CPrivateSendClient::RelayIn(const CPrivateSendEntry& entry, CConnman& connm connman.ForNode(infoMixingDynode.addr, [&entry, &connman](CNode* pnode) { LogPrintf("CPrivateSendClient::RelayIn -- found master, relaying message to %s\n", pnode->addr.ToString()); - connman.PushMessage(pnode, NetMsgType::PSVIN, entry); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSVIN, entry)); return true; }); } @@ -1370,35 +1448,25 @@ void CPrivateSendClient::UpdatedBlockTip(const CBlockIndex *pindex) { nCachedBlockHeight = pindex->nHeight; LogPrint("privatesend", "CPrivateSendClient::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight); + } -//TODO: Rename/move to core -void ThreadCheckPrivateSendClient(CConnman& connman) +void CPrivateSendClient::DoMaintenance(CConnman& connman) { if(fLiteMode) return; // disable all Dynamic specific functionality if(fDynodeMode) return; // no client-side mixing on dynodes - static bool fOneThread; - if(fOneThread) return; - fOneThread = true; - - // Make this thread recognisable as the PrivateSend thread - RenameThread("dynamic-ps-client"); + if(!dynodeSync.IsBlockchainSynced() || ShutdownRequested()) + return; - unsigned int nTick = 0; - unsigned int nDoAutoNextRun = nTick + PRIVATESEND_AUTO_TIMEOUT_MIN; + static unsigned int nTick = 0; + static unsigned int nDoAutoNextRun = nTick + PRIVATESEND_AUTO_TIMEOUT_MIN; - while (true) - { - MilliSleep(1000); - - if(dynodeSync.IsBlockchainSynced() && !ShutdownRequested()) { - nTick++; - privateSendClient.CheckTimeout(); - if(nDoAutoNextRun == nTick) { - privateSendClient.DoAutomaticDenominating(connman); - nDoAutoNextRun = nTick + PRIVATESEND_AUTO_TIMEOUT_MIN + GetRandInt(PRIVATESEND_AUTO_TIMEOUT_MAX - PRIVATESEND_AUTO_TIMEOUT_MIN); - } - } + nTick++; + privateSendClient.CheckTimeout(); + privateSendClient.ProcessPendingPsaRequest(connman); + if(nDoAutoNextRun == nTick) { + privateSendClient.DoAutomaticDenominating(connman); + nDoAutoNextRun = nTick + PRIVATESEND_AUTO_TIMEOUT_MIN + GetRandInt(PRIVATESEND_AUTO_TIMEOUT_MAX - PRIVATESEND_AUTO_TIMEOUT_MIN); } } diff --git a/src/privatesend-client.h b/src/privatesend-client.h index f6ac40e453..78a87e8a3e 100644 --- a/src/privatesend-client.h +++ b/src/privatesend-client.h @@ -20,9 +20,9 @@ static const int MIN_PRIVATESEND_ROUNDS = 2; static const int MIN_PRIVATESEND_AMOUNT = 2; static const int MIN_PRIVATESEND_LIQUIDITY = 0; static const int MAX_PRIVATESEND_ROUNDS = 16; -static const int MAX_PRIVATESEND_AMOUNT = 100000; +static const int MAX_PRIVATESEND_AMOUNT = MAX_MONEY / COIN; static const int MAX_PRIVATESEND_LIQUIDITY = 100; -static const int DEFAULT_PRIVATESEND_ROUNDS = 2; +static const int DEFAULT_PRIVATESEND_ROUNDS = 4; static const int DEFAULT_PRIVATESEND_AMOUNT = 1000; static const int DEFAULT_PRIVATESEND_LIQUIDITY = 0; @@ -37,6 +37,45 @@ static const int PRIVATESEND_KEYS_THRESHOLD_STOP = 50; // The main object for accessing mixing extern CPrivateSendClient privateSendClient; +class CPendingPsaRequest +{ +private: + static const int TIMEOUT = 15; + + CService addr; + CPrivateSendAccept psa; + int64_t nTimeCreated; + +public: + CPendingPsaRequest(): + addr(CService()), + psa(CPrivateSendAccept()), + nTimeCreated(0) + {}; + + CPendingPsaRequest(const CService& addr_, const CPrivateSendAccept& psa_): + addr(addr_), + psa(psa_) + { nTimeCreated = GetTime(); } + + CService GetAddr() { return addr; } + CPrivateSendAccept GetPSA() { return psa; } + bool IsExpired() { return GetTime() - nTimeCreated > TIMEOUT; } + + friend bool operator==(const CPendingPsaRequest& a, const CPendingPsaRequest& b) + { + return a.addr == b.addr && a.psa == b.psa; + } + friend bool operator!=(const CPendingPsaRequest& a, const CPendingPsaRequest& b) + { + return !(a == b); + } + explicit operator bool() const + { + return *this != CPendingPsaRequest(); + } +}; + /** Used to keep track of current status of mixing pool */ class CPrivateSendClient : public CPrivateSendBase @@ -62,6 +101,7 @@ class CPrivateSendClient : public CPrivateSendBase dynode_info_t infoMixingDynode; CMutableTransaction txMyCollateral; // client side collateral + CPendingPsaRequest pendingPsaRequest; CKeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate @@ -69,9 +109,7 @@ class CPrivateSendClient : public CPrivateSendBase void CheckPool(); void CompletedTransaction(PoolMessage nMessageID); - bool IsDenomSkipped(CAmount nDenomValue) { - return std::find(vecDenominationsSkipped.begin(), vecDenominationsSkipped.end(), nDenomValue) != vecDenominationsSkipped.end(); - } + bool IsDenomSkipped(CAmount nDenomValue); bool WaitForAnotherBlock(); @@ -129,7 +167,7 @@ class CPrivateSendClient : public CPrivateSendBase nCachedNumBlocks(std::numeric_limits::max()), fCreateAutoBackups(true) { SetNull(); } - void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman); + void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void ClearSkippedDenominations() { vecDenominationsSkipped.clear(); } @@ -147,11 +185,13 @@ class CPrivateSendClient : public CPrivateSendBase /// Passively run mixing in the background according to the configuration in settings bool DoAutomaticDenominating(CConnman& connman, bool fDryRun=false); + void ProcessPendingPsaRequest(CConnman& connman); + void CheckTimeout(); void UpdatedBlockTip(const CBlockIndex *pindex); -}; -void ThreadCheckPrivateSendClient(CConnman& connman); + void DoMaintenance(CConnman& connman); +}; #endif \ No newline at end of file diff --git a/src/privatesend-server.cpp b/src/privatesend-server.cpp index 77e965b80d..0b6b26aaaa 100644 --- a/src/privatesend-server.cpp +++ b/src/privatesend-server.cpp @@ -11,6 +11,7 @@ #include "init.h" #include "dynode-sync.h" #include "dynodeman.h" +#include "netmessagemaker.h" #include "script/interpreter.h" #include "txmempool.h" #include "util.h" @@ -18,7 +19,7 @@ CPrivateSendServer privateSendServer; -void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman) +void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) { if(!fDynodeMode) return; if(fLiteMode) return; // ignore all Dynamic related functionality @@ -27,7 +28,9 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C if(strCommand == NetMsgType::PSACCEPT) { if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { - LogPrintf("PSACCEPT -- incompatible version! nVersion: %d\n", pfrom->nVersion); + LogPrint("privatesend", "PSACCEPT -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION))); PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman); return; } @@ -39,11 +42,12 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C return; } - int nDenom; - CTransaction txCollateral; - vRecv >> nDenom >> txCollateral; + CPrivateSendAccept psa; + vRecv >> psa; - LogPrint("privatesend", "PSACCEPT -- nDenom %d (%s) txCollateral %s", nDenom, CPrivateSend::GetDenominationsToString(nDenom), txCollateral.ToString()); + LogPrint("privatesend", "PSACCEPT -- nDenom %d (%s) txCollateral %s", psa.nDenom, CPrivateSend::GetDenominationsToString(psa.nDenom), psa.txCollateral.ToString()); + + if(psa.nInputCount < 0 || psa.nInputCount > PRIVATESEND_ENTRY_MAX_SIZE) return; dynode_info_t dnInfo; if(!dnodeman.GetDynodeInfo(activeDynode.outpoint, dnInfo)) { @@ -61,8 +65,8 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C PoolMessage nMessageID = MSG_NOERR; - bool fResult = nSessionID == 0 ? CreateNewSession(nDenom, txCollateral, nMessageID, connman) - : AddUserToExistingSession(nDenom, txCollateral, nMessageID); + bool fResult = nSessionID == 0 ? CreateNewSession(psa, nMessageID, connman) + : AddUserToExistingSession(psa, nMessageID); if(fResult) { LogPrintf("PSACCEPT -- is compatible, please submit!\n"); PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman); @@ -78,7 +82,9 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C if(!lockRecv) return; if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { - LogPrint("privatesend", "PSQUEUE -- incompatible version! nVersion: %d\n", pfrom->nVersion); + LogPrint("privatesend", "PSQUEUE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION))); return; } @@ -86,7 +92,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C vRecv >> psq; // process every psq only once - BOOST_FOREACH(CPrivateSendQueue q, vecPrivateSendQueue) { + for (const auto& q : vecPrivateSendQueue) { if(q == psq) { // LogPrint("privatesend", "PSQUEUE -- %s seen\n", psq.ToString()); return; @@ -96,19 +102,20 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C LogPrint("privatesend", "PSQUEUE -- %s new\n", psq.ToString()); if(psq.IsExpired()) return; + if(psq.nInputCount < 0 || psq.nInputCount > PRIVATESEND_ENTRY_MAX_SIZE) return; dynode_info_t dnInfo; - if(!dnodeman.GetDynodeInfo(psq.vin.prevout, dnInfo)) return; + if(!dnodeman.GetDynodeInfo(psq.dynodeOutpoint, dnInfo)) return; if(!psq.CheckSignature(dnInfo.pubKeyDynode)) { // we probably have outdated info - dnodeman.AskForDN(pfrom, psq.vin.prevout, connman); + dnodeman.AskForDN(pfrom, psq.dynodeOutpoint, connman); return; } if(!psq.fReady) { - BOOST_FOREACH(CPrivateSendQueue q, vecPrivateSendQueue) { - if(q.vin == psq.vin) { + for (const auto& q : vecPrivateSendQueue) { + if(q.dynodeOutpoint == psq.dynodeOutpoint) { // no way same dn can send another "not yet ready" psq this soon LogPrint("privatesend", "PSQUEUE -- Dynode %s is sending WAY too many psq messages\n", dnInfo.addr.ToString()); return; @@ -122,7 +129,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C LogPrint("privatesend", "PSQUEUE -- Dynode %s is sending too many psq messages\n", dnInfo.addr.ToString()); return; } - dnodeman.AllowMixing(psq.vin.prevout); + dnodeman.AllowMixing(psq.dynodeOutpoint); LogPrint("privatesend", "PSQUEUE -- new PrivateSend queue (%s) from dynode %s\n", psq.ToString(), dnInfo.addr.ToString()); vecPrivateSendQueue.push_back(psq); @@ -132,7 +139,9 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C } else if(strCommand == NetMsgType::PSVIN) { if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { - LogPrintf("PSVIN -- incompatible version! nVersion: %d\n", pfrom->nVersion); + LogPrint("privatesend", "PSVIN -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION))); PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman); return; } @@ -147,7 +156,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C CPrivateSendEntry entry; vRecv >> entry; - LogPrint("privatesend", "PSVIN -- txCollateral %s", entry.txCollateral.ToString()); + LogPrint("privatesend", "PSVIN -- txCollateral %s", entry.txCollateral->ToString()); if(entry.vecTxPSIn.size() > PRIVATESEND_ENTRY_MAX_SIZE) { LogPrintf("PSVIN -- ERROR: too many inputs! %d/%d\n", entry.vecTxPSIn.size(), PRIVATESEND_ENTRY_MAX_SIZE); @@ -161,6 +170,18 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C return; } + if(nSessionInputCount != 0 && entry.vecTxPSIn.size() != nSessionInputCount) { + LogPrintf("PSVIN -- ERROR: incorrect number of inputs! %d/%d\n", entry.vecTxPSIn.size(), nSessionInputCount); + PushStatus(pfrom, STATUS_REJECTED, ERR_INVALID_INPUT_COUNT, connman); + return; + } + + if(nSessionInputCount != 0 && entry.vecTxOut.size() != nSessionInputCount) { + LogPrintf("PSVIN -- ERROR: incorrect number of outputs! %d/%d\n", entry.vecTxOut.size(), nSessionInputCount); + PushStatus(pfrom, STATUS_REJECTED, ERR_INVALID_INPUT_COUNT, connman); + return; + } + //do we have the same denominations as the current session? if(!IsOutputsCompatibleWithSessionDenom(entry.vecTxOut)) { LogPrintf("PSVIN -- not compatible with existing transactions!\n"); @@ -191,7 +212,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C } } - BOOST_FOREACH(const CTxIn txin, entry.vecTxPSIn) { + for (const auto& txin : entry.vecTxPSIn) { tx.vin.push_back(txin); LogPrint("privatesend", "PSVIN -- txin=%s\n", txin.ToString()); @@ -200,7 +221,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C if(GetUTXOCoin(txin.prevout, coin)) { nValueIn += coin.out.nValue; } else { - LogPrintf("PSVIN -- missing input! tx=%s", tx.ToString()); + LogPrintf("PSVIN -- missing input! txin=%s\n", txin.ToString()); PushStatus(pfrom, STATUS_REJECTED, ERR_MISSING_TX, connman); return; } @@ -213,17 +234,6 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C PushStatus(pfrom, STATUS_REJECTED, ERR_FEES, connman); return; } - - { - LOCK(cs_main); - CValidationState validationState; - mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), 1000, 0.1*COIN); - if(!AcceptToMemoryPool(mempool, validationState, CTransaction(tx), false, NULL, false, maxTxFee, true)) { - LogPrintf("PSVIN -- transaction not valid! tx=%s", tx.ToString()); - PushStatus(pfrom, STATUS_REJECTED, ERR_INVALID_TX, connman); - return; - } - } } PoolMessage nMessageID = MSG_NOERR; @@ -241,7 +251,9 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C } else if(strCommand == NetMsgType::PSSIGNFINALTX) { if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { - LogPrintf("PSSIGNFINALTX -- incompatible version! nVersion: %d\n", pfrom->nVersion); + LogPrint("privatesend", "PSSIGNFINALTX -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion); + connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION))); return; } @@ -253,7 +265,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C int nTxInIndex = 0; int nTxInsCount = (int)vecTxIn.size(); - BOOST_FOREACH(const CTxIn txin, vecTxIn) { + for (const auto& txin : vecTxIn) { nTxInIndex++; if(!AddScriptSig(txin)) { LogPrint("privatesend", "PSSIGNFINALTX -- AddScriptSig() failed at %d/%d, session: %d\n", nTxInIndex, nTxInsCount, nSessionID); @@ -280,28 +292,22 @@ void CPrivateSendServer::SetNull() // void CPrivateSendServer::CheckPool(CConnman& connman) { - if(fDynodeMode) { - LogPrint("privatesend", "CPrivateSendServer::CheckPool -- entries count %lu\n", GetEntriesCount()); + if (!fDynodeMode) return; - // If entries are full, create finalized transaction - if(nState == POOL_STATE_ACCEPTING_ENTRIES && GetEntriesCount() >= CPrivateSend::GetMaxPoolTransactions()) { - LogPrint("privatesend", "CPrivateSendServer::CheckPool -- FINALIZE TRANSACTIONS\n"); - CreateFinalTransaction(connman); - return; - } + LogPrint("privatesend", "CPrivateSendServer::CheckPool -- entries count %lu\n", GetEntriesCount()); - // If we have all of the signatures, try to compile the transaction - if(nState == POOL_STATE_SIGNING && IsSignaturesComplete()) { - LogPrint("privatesend", "CPrivateSendServer::CheckPool -- SIGNING\n"); - CommitFinalTransaction(connman); - return; - } + // If entries are full, create finalized transaction + if (nState == POOL_STATE_ACCEPTING_ENTRIES && GetEntriesCount() >= CPrivateSend::GetMaxPoolTransactions()) { + LogPrint("privatesend", "CPrivateSendServer::CheckPool -- FINALIZE TRANSACTIONS\n"); + CreateFinalTransaction(connman); + return; } - // reset if we're here for 10 seconds - if((nState == POOL_STATE_ERROR || nState == POOL_STATE_SUCCESS) && GetTimeMillis() - nTimeLastSuccessfulStep >= 10000) { - LogPrint("privatesend", "CPrivateSendServer::CheckPool -- timeout, RESETTING\n"); - SetNull(); + // If we have all of the signatures, try to compile the transaction + if (nState == POOL_STATE_SIGNING && IsSignaturesComplete()) { + LogPrint("privatesend", "CPrivateSendServer::CheckPool -- SIGNING\n"); + CommitFinalTransaction(connman); + return; } } @@ -316,8 +322,8 @@ void CPrivateSendServer::CreateFinalTransaction(CConnman& connman) for (const auto& txout : vecEntries[i].vecTxOut) txNew.vout.push_back(txout); - BOOST_FOREACH(const CTxPSIn& txpsin, vecEntries[i].vecTxPSIn) - txNew.vin.push_back(txpsin); + for (const auto& txdsin : vecEntries[i].vecTxPSIn) + txNew.vin.push_back(txdsin); } sort(txNew.vin.begin(), txNew.vin.end(), CompareInputBIP69()); @@ -335,17 +341,17 @@ void CPrivateSendServer::CommitFinalTransaction(CConnman& connman) { if(!fDynodeMode) return; // check and relay final tx only on dynode - CTransaction finalTransaction = CTransaction(finalMutableTransaction); - uint256 hashTx = finalTransaction.GetHash(); + CTransactionRef finalTransaction = MakeTransactionRef(finalMutableTransaction); + uint256 hashTx = finalTransaction->GetHash(); - LogPrint("privatesend", "CPrivateSendServer::CommitFinalTransaction -- finalTransaction=%s", finalTransaction.ToString()); + LogPrint("privatesend", "CPrivateSendServer::CommitFinalTransaction -- finalTransaction=%s", finalTransaction->ToString()); { // See if the transaction is valid TRY_LOCK(cs_main, lockMain); CValidationState validationState; mempool.PrioritiseTransaction(hashTx, hashTx.ToString(), 1000, 0.1*COIN); - if(!lockMain || !AcceptToMemoryPool(mempool, validationState, finalTransaction, false, NULL, false, maxTxFee, true)) + if(!lockMain || !AcceptToMemoryPool(mempool, validationState, finalTransaction, false, NULL, NULL, false, maxTxFee, true)) { LogPrintf("CPrivateSendServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n"); SetNull(); @@ -355,16 +361,16 @@ void CPrivateSendServer::CommitFinalTransaction(CConnman& connman) } } - LogPrintf("CPrivateSendServer::CommitFinalTransaction -- CREATING PSTX\n"); + LogPrintf("CPrivateSendServer::CommitFinalTransaction -- CREATING DSTX\n"); - // create and sign dynode pstx transaction + // create and sign dynode dstx transaction if(!CPrivateSend::GetPSTX(hashTx)) { - CPrivateSendBroadcastTx pstxNew(finalTransaction, activeDynode.outpoint, GetAdjustedTime()); - pstxNew.Sign(); - CPrivateSend::AddPSTX(pstxNew); + CPrivateSendBroadcastTx dstxNew(finalTransaction, activeDynode.outpoint, GetAdjustedTime()); + dstxNew.Sign(); + CPrivateSend::AddPSTX(dstxNew); } - LogPrintf("CPrivateSendServer::CommitFinalTransaction -- TRANSMITTING PSTX\n"); + LogPrintf("CPrivateSendServer::CommitFinalTransaction -- TRANSMITTING DSTX\n"); CInv inv(MSG_PSTX, hashTx); connman.RelayInv(inv); @@ -386,7 +392,7 @@ void CPrivateSendServer::CommitFinalTransaction(CConnman& connman) // Why bother? PrivateSend uses collateral to ensure abuse to the process is kept to a minimum. // The submission and signing stages are completely separate. In the cases where // a client submits a transaction then refused to sign, there must be a cost. Otherwise they -// would be able to do this over and over again and bring the mixing to a hault. +// would be able to do this over and over again and bring the mixing to a halt. // // How does this work? Messages to Dynodes come in via NetMsgType::PSVIN, these require a valid collateral // transaction for the client to be able to enter the pool. This transaction is kept by the Dynode @@ -399,13 +405,13 @@ void CPrivateSendServer::ChargeFees(CConnman& connman) //we don't need to charge collateral for every offence. if(GetRandInt(100) > 33) return; - std::vector vecOffendersCollaterals; + std::vector vecOffendersCollaterals; if(nState == POOL_STATE_ACCEPTING_ENTRIES) { - BOOST_FOREACH(const CTransaction& txCollateral, vecSessionCollaterals) { + for (const auto& txCollateral : vecSessionCollaterals) { bool fFound = false; - BOOST_FOREACH(const CPrivateSendEntry& entry, vecEntries) - if(entry.txCollateral == txCollateral) + for (const auto& entry : vecEntries) + if(*entry.txCollateral == *txCollateral) fFound = true; // This queue entry didn't send us the promised transaction @@ -418,9 +424,9 @@ void CPrivateSendServer::ChargeFees(CConnman& connman) if(nState == POOL_STATE_SIGNING) { // who didn't sign? - BOOST_FOREACH(const CPrivateSendEntry entry, vecEntries) { - BOOST_FOREACH(const CTxPSIn txpsin, entry.vecTxPSIn) { - if(!txpsin.fHasSig) { + for (const auto& entry : vecEntries) { + for (const auto& txdsin : entry.vecTxPSIn) { + if(!txdsin.fHasSig) { LogPrintf("CPrivateSendServer::ChargeFees -- found uncooperative node (didn't sign), found offence\n"); vecOffendersCollaterals.push_back(entry.txCollateral); } @@ -442,17 +448,16 @@ void CPrivateSendServer::ChargeFees(CConnman& connman) if(nState == POOL_STATE_ACCEPTING_ENTRIES || nState == POOL_STATE_SIGNING) { LogPrintf("CPrivateSendServer::ChargeFees -- found uncooperative node (didn't %s transaction), charging fees: %s\n", - (nState == POOL_STATE_SIGNING) ? "sign" : "send", vecOffendersCollaterals[0].ToString()); + (nState == POOL_STATE_SIGNING) ? "sign" : "send", vecOffendersCollaterals[0]->ToString()); LOCK(cs_main); CValidationState state; - bool fMissingInputs; - if(!AcceptToMemoryPool(mempool, state, vecOffendersCollaterals[0], false, &fMissingInputs, false, maxTxFee)) { + if(!AcceptToMemoryPool(mempool, state, vecOffendersCollaterals[0], false, NULL, NULL, false, maxTxFee)) { // should never really happen LogPrintf("CPrivateSendServer::ChargeFees -- ERROR: AcceptToMemoryPool failed!\n"); } else { - connman.RelayTransaction(vecOffendersCollaterals[0]); + connman.RelayTransaction(*vecOffendersCollaterals[0]); } } } @@ -475,19 +480,16 @@ void CPrivateSendServer::ChargeRandomFees(CConnman& connman) LOCK(cs_main); - BOOST_FOREACH(const CTransaction& txCollateral, vecSessionCollaterals) { - + for (const auto& txCollateral : vecSessionCollaterals) { if(GetRandInt(100) > 10) return; - - LogPrintf("CPrivateSendServer::ChargeRandomFees -- charging random fees, txCollateral=%s", txCollateral.ToString()); + LogPrintf("CPrivateSendServer::ChargeRandomFees -- charging random fees, txCollateral=%s", txCollateral->ToString()); CValidationState state; - bool fMissingInputs; - if(!AcceptToMemoryPool(mempool, state, txCollateral, false, &fMissingInputs, false, maxTxFee)) { + if(!AcceptToMemoryPool(mempool, state, txCollateral, false, NULL, NULL, false, maxTxFee)) { // should never really happen LogPrintf("CPrivateSendServer::ChargeRandomFees -- ERROR: AcceptToMemoryPool failed!\n"); } else { - connman.RelayTransaction(txCollateral); + connman.RelayTransaction(*txCollateral); } } } @@ -497,20 +499,18 @@ void CPrivateSendServer::ChargeRandomFees(CConnman& connman) // void CPrivateSendServer::CheckTimeout(CConnman& connman) { - CheckQueue(); - if(!fDynodeMode) return; - int nLagTime = fDynodeMode ? 0 : 10000; // if we're the client, give the server a few extra seconds before resetting. + CheckQueue(); + int nTimeout = (nState == POOL_STATE_SIGNING) ? PRIVATESEND_SIGNING_TIMEOUT : PRIVATESEND_QUEUE_TIMEOUT; - bool fTimeout = GetTimeMillis() - nTimeLastSuccessfulStep >= nTimeout*1000 + nLagTime; + bool fTimeout = GetTime() - nTimeLastSuccessfulStep >= nTimeout; if(nState != POOL_STATE_IDLE && fTimeout) { - LogPrint("privatesend", "CPrivateSendServer::CheckTimeout -- %s timed out (%ds) -- restting\n", + LogPrint("privatesend", "CPrivateSendServer::CheckTimeout -- %s timed out (%ds) -- resetting\n", (nState == POOL_STATE_SIGNING) ? "Signing" : "Session", nTimeout); ChargeFees(connman); SetNull(); - SetState(POOL_STATE_ERROR); } } @@ -526,7 +526,7 @@ void CPrivateSendServer::CheckForCompleteQueue(CConnman& connman) if(nState == POOL_STATE_QUEUE && IsSessionReady()) { SetState(POOL_STATE_ACCEPTING_ENTRIES); - CPrivateSendQueue psq(nSessionDenom, activeDynode.outpoint, GetAdjustedTime(), true); + CPrivateSendQueue psq(nSessionDenom, nSessionInputCount, activeDynode.outpoint, GetAdjustedTime(), true); LogPrint("privatesend", "CPrivateSendServer::CheckForCompleteQueue -- queue is ready, signing and relaying (%s)\n", psq.ToString()); psq.Sign(); psq.Relay(connman); @@ -544,17 +544,17 @@ bool CPrivateSendServer::IsInputScriptSigValid(const CTxIn& txin) int nTxInIndex = -1; CScript sigPubKey = CScript(); - BOOST_FOREACH(CPrivateSendEntry& entry, vecEntries) { + for (const auto& entry : vecEntries) { for (const auto& txout : entry.vecTxOut) txNew.vout.push_back(txout); - BOOST_FOREACH(const CTxPSIn& txpsin, entry.vecTxPSIn) { - txNew.vin.push_back(txpsin); + for (const auto& txdsin : entry.vecTxPSIn) { + txNew.vin.push_back(txdsin); - if(txpsin.prevout == txin.prevout) { + if(txdsin.prevout == txin.prevout) { nTxInIndex = i; - sigPubKey = txpsin.prevPubKey; + sigPubKey = txdsin.prevPubKey; } i++; } @@ -583,7 +583,7 @@ bool CPrivateSendServer::AddEntry(const CPrivateSendEntry& entryNew, PoolMessage { if(!fDynodeMode) return false; - BOOST_FOREACH(CTxIn txin, entryNew.vecTxPSIn) { + for (const auto& txin : entryNew.vecTxPSIn) { if(txin.prevout.IsNull()) { LogPrint("privatesend", "CPrivateSendServer::AddEntry -- input not valid!\n"); nMessageIDRet = ERR_INVALID_INPUT; @@ -591,7 +591,7 @@ bool CPrivateSendServer::AddEntry(const CPrivateSendEntry& entryNew, PoolMessage } } - if(!CPrivateSend::IsCollateralValid(entryNew.txCollateral)) { + if(!CPrivateSend::IsCollateralValid(*entryNew.txCollateral)) { LogPrint("privatesend", "CPrivateSendServer::AddEntry -- collateral not valid!\n"); nMessageIDRet = ERR_INVALID_COLLATERAL; return false; @@ -603,11 +603,11 @@ bool CPrivateSendServer::AddEntry(const CPrivateSendEntry& entryNew, PoolMessage return false; } - BOOST_FOREACH(CTxIn txin, entryNew.vecTxPSIn) { + for (const auto& txin : entryNew.vecTxPSIn) { LogPrint("privatesend", "looking for txin -- %s\n", txin.ToString()); - BOOST_FOREACH(const CPrivateSendEntry& entry, vecEntries) { - BOOST_FOREACH(const CTxPSIn& txpsin, entry.vecTxPSIn) { - if(txpsin.prevout == txin.prevout) { + for (const auto& entry : vecEntries) { + for (const auto& txdsin : entry.vecTxPSIn) { + if(txdsin.prevout == txin.prevout) { LogPrint("privatesend", "CPrivateSendServer::AddEntry -- found in txin\n"); nMessageIDRet = ERR_ALREADY_HAVE; return false; @@ -620,7 +620,7 @@ bool CPrivateSendServer::AddEntry(const CPrivateSendEntry& entryNew, PoolMessage LogPrint("privatesend", "CPrivateSendServer::AddEntry -- adding entry\n"); nMessageIDRet = MSG_ENTRIES_ADDED; - nTimeLastSuccessfulStep = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTime(); return true; } @@ -629,9 +629,9 @@ bool CPrivateSendServer::AddScriptSig(const CTxIn& txinNew) { LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24)); - BOOST_FOREACH(const CPrivateSendEntry& entry, vecEntries) { - BOOST_FOREACH(const CTxPSIn& txpsin, entry.vecTxPSIn) { - if(txpsin.scriptSig == txinNew.scriptSig) { + for (const auto& entry : vecEntries) { + for (const auto& txdsin : entry.vecTxPSIn) { + if(txdsin.scriptSig == txinNew.scriptSig) { LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- already exists\n"); return false; } @@ -645,8 +645,8 @@ bool CPrivateSendServer::AddScriptSig(const CTxIn& txinNew) LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- scriptSig=%s new\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24)); - BOOST_FOREACH(CTxIn& txin, finalMutableTransaction.vin) { - if(txinNew.prevout == txin.prevout && txin.nSequence == txinNew.nSequence) { + for (auto& txin : finalMutableTransaction.vin) { + if(txin.prevout == txinNew.prevout && txin.nSequence == txinNew.nSequence) { txin.scriptSig = txinNew.scriptSig; LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- adding to finalMutableTransaction, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24)); } @@ -665,9 +665,9 @@ bool CPrivateSendServer::AddScriptSig(const CTxIn& txinNew) // Check to make sure everything is signed bool CPrivateSendServer::IsSignaturesComplete() { - BOOST_FOREACH(const CPrivateSendEntry& entry, vecEntries) - BOOST_FOREACH(const CTxPSIn& txpsin, entry.vecTxPSIn) - if(!txpsin.fHasSig) return false; + for (const auto& entry : vecEntries) + for (const auto& txdsin : entry.vecTxPSIn) + if(!txdsin.fHasSig) return false; return true; } @@ -676,7 +676,7 @@ bool CPrivateSendServer::IsOutputsCompatibleWithSessionDenom(const std::vector vecBits; - if(!CPrivateSend::GetDenominationsBits(nDenom, vecBits)) { - LogPrint("privatesend", "CPrivateSendServer::IsAcceptableDenomAndCollateral -- denom not valid!\n"); + if(!CPrivateSend::GetDenominationsBits(psa.nDenom, vecBits)) { + LogPrint("privatesend", "CPrivateSendServer::%s -- denom not valid!\n", __func__); nMessageIDRet = ERR_DENOM; return false; } // check collateral - if(!fUnitTest && !CPrivateSend::IsCollateralValid(txCollateral)) { - LogPrint("privatesend", "CPrivateSendServer::IsAcceptableDenomAndCollateral -- collateral not valid!\n"); + if(!fUnitTest && !CPrivateSend::IsCollateralValid(psa.txCollateral)) { + LogPrint("privatesend", "CPrivateSendServer::%s -- collateral not valid!\n", __func__); nMessageIDRet = ERR_INVALID_COLLATERAL; return false; } + if(psa.nInputCount < 0 || psa.nInputCount > PRIVATESEND_ENTRY_MAX_SIZE) { + LogPrint("privatesend", "CPrivateSendServer::%s -- requested count is not valid!\n", __func__); + nMessageIDRet = ERR_INVALID_INPUT_COUNT; + return false; + } + return true; } -bool CPrivateSendServer::CreateNewSession(int nDenom, CTransaction txCollateral, PoolMessage& nMessageIDRet, CConnman& connman) +bool CPrivateSendServer::CreateNewSession(const CPrivateSendAccept& psa, PoolMessage& nMessageIDRet, CConnman& connman) { if(!fDynodeMode || nSessionID != 0) return false; @@ -718,39 +724,42 @@ bool CPrivateSendServer::CreateNewSession(int nDenom, CTransaction txCollateral, return false; } - if(!IsAcceptableDenomAndCollateral(nDenom, txCollateral, nMessageIDRet)) { + if(!IsAcceptablePSA(psa, nMessageIDRet)) { return false; } // start new session nMessageIDRet = MSG_NOERR; nSessionID = GetRandInt(999999)+1; - nSessionDenom = nDenom; + nSessionDenom = psa.nDenom; + // nInputCount is not covered by legacy signature, require SPORK_6_NEW_SIGS to activate to use new algo + // (to make sure nInputCount wasn't modified by some intermediary node) + nSessionInputCount = sporkManager.IsSporkActive(SPORK_6_NEW_SIGS) ? psa.nInputCount : 0; SetState(POOL_STATE_QUEUE); - nTimeLastSuccessfulStep = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTime(); if(!fUnitTest) { //broadcast that I'm accepting entries, only if it's the first entry through - CPrivateSendQueue psq(nDenom, activeDynode.outpoint, GetAdjustedTime(), false); + CPrivateSendQueue psq(psa.nDenom, psa.nInputCount, activeDynode.outpoint, GetAdjustedTime(), false); LogPrint("privatesend", "CPrivateSendServer::CreateNewSession -- signing and relaying new queue: %s\n", psq.ToString()); psq.Sign(); psq.Relay(connman); vecPrivateSendQueue.push_back(psq); } - vecSessionCollaterals.push_back(txCollateral); + vecSessionCollaterals.push_back(MakeTransactionRef(psa.txCollateral)); LogPrintf("CPrivateSendServer::CreateNewSession -- new session created, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d\n", nSessionID, nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), vecSessionCollaterals.size()); return true; } -bool CPrivateSendServer::AddUserToExistingSession(int nDenom, CTransaction txCollateral, PoolMessage& nMessageIDRet) +bool CPrivateSendServer::AddUserToExistingSession(const CPrivateSendAccept& psa, PoolMessage& nMessageIDRet) { if(!fDynodeMode || nSessionID == 0 || IsSessionReady()) return false; - if(!IsAcceptableDenomAndCollateral(nDenom, txCollateral, nMessageIDRet)) { + if(!IsAcceptablePSA(psa, nMessageIDRet)) { return false; } @@ -761,21 +770,28 @@ bool CPrivateSendServer::AddUserToExistingSession(int nDenom, CTransaction txCol return false; } - if(nDenom != nSessionDenom) { + if(psa.nDenom != nSessionDenom) { LogPrintf("CPrivateSendServer::AddUserToExistingSession -- incompatible denom %d (%s) != nSessionDenom %d (%s)\n", - nDenom, CPrivateSend::GetDenominationsToString(nDenom), nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); + psa.nDenom, CPrivateSend::GetDenominationsToString(psa.nDenom), nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); nMessageIDRet = ERR_DENOM; return false; } + if(psa.nInputCount != nSessionInputCount) { + LogPrintf("CPrivateSendServer::AddUserToExistingSession -- incompatible count %d != nSessionInputCount %d\n", + psa.nInputCount, nSessionInputCount); + nMessageIDRet = ERR_INVALID_INPUT_COUNT; + return false; + } + // count new user as accepted to an existing session nMessageIDRet = MSG_NOERR; - nTimeLastSuccessfulStep = GetTimeMillis(); - vecSessionCollaterals.push_back(txCollateral); + nTimeLastSuccessfulStep = GetTime(); + vecSessionCollaterals.push_back(MakeTransactionRef(psa.txCollateral)); - LogPrintf("CPrivateSendServer::AddUserToExistingSession -- new user accepted, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d\n", - nSessionID, nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), vecSessionCollaterals.size()); + LogPrintf("CPrivateSendServer::AddUserToExistingSession -- new user accepted, nSessionID: %d nSessionDenom: %d (%s) nSessionInputCount: %d vecSessionCollaterals.size(): %d\n", + nSessionID, nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), nSessionInputCount, vecSessionCollaterals.size()); return true; } @@ -788,7 +804,8 @@ void CPrivateSendServer::RelayFinalTransaction(const CTransaction& txFinal, CCon // final mixing tx with empty signatures should be relayed to mixing participants only for (const auto entry : vecEntries) { bool fOk = connman.ForNode(entry.addr, [&txFinal, &connman, this](CNode* pnode) { - connman.PushMessage(pnode, NetMsgType::PSFINALTX, nSessionID, txFinal); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSFINALTX, nSessionID, txFinal)); return true; }); if(!fOk) { @@ -802,7 +819,8 @@ void CPrivateSendServer::RelayFinalTransaction(const CTransaction& txFinal, CCon void CPrivateSendServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman& connman) { if(!pnode) return; - connman.PushMessage(pnode, NetMsgType::PSSTATUSUPDATE, nSessionID, (int)nState, (int)vecEntries.size(), (int)nStatusUpdate, (int)nMessageID); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSSTATUSUPDATE, nSessionID, (int)nState, (int)vecEntries.size(), (int)nStatusUpdate, (int)nMessageID)); } void CPrivateSendServer::RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& connman, PoolMessage nMessageID) @@ -827,7 +845,7 @@ void CPrivateSendServer::RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& c __func__, nDisconnected, nSessionID, nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); // notify everyone else that this session should be terminated - for (const auto entry : vecEntries) { + for (const auto& entry : vecEntries) { connman.ForNode(entry.addr, [&connman, this](CNode* pnode) { PushStatus(pnode, STATUS_REJECTED, MSG_NOERR, connman); return true; @@ -847,9 +865,10 @@ void CPrivateSendServer::RelayCompletedTransaction(PoolMessage nMessageID, CConn __func__, nSessionID, nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); // final mixing tx with empty signatures should be relayed to mixing participants only - for (const auto entry : vecEntries) { + for (const auto& entry : vecEntries) { bool fOk = connman.ForNode(entry.addr, [&nMessageID, &connman, this](CNode* pnode) { - connman.PushMessage(pnode, NetMsgType::PSCOMPLETE, nSessionID, (int)nMessageID); + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSCOMPLETE, nSessionID, (int)nMessageID)); return true; }); if(!fOk) { @@ -862,7 +881,9 @@ void CPrivateSendServer::RelayCompletedTransaction(PoolMessage nMessageID, CConn void CPrivateSendServer::SetState(PoolState nStateNew) { - if(fDynodeMode && (nStateNew == POOL_STATE_ERROR || nStateNew == POOL_STATE_SUCCESS)) { + if(!fDynodeMode) return; + + if(nStateNew == POOL_STATE_ERROR || nStateNew == POOL_STATE_SUCCESS) { LogPrint("privatesend", "CPrivateSendServer::SetState -- Can't set state to ERROR or SUCCESS as a Dynode. \n"); return; } @@ -871,28 +892,14 @@ void CPrivateSendServer::SetState(PoolState nStateNew) nState = nStateNew; } -//TODO: Rename/move to core -void ThreadCheckPrivateSendServer(CConnman& connman) +void CPrivateSendServer::DoMaintenance(CConnman& connman) { if(fLiteMode) return; // disable all Dynamic specific functionality + if(!fDynodeMode) return; // only run on dynodes - static bool fOneThread; - if(fOneThread) return; - fOneThread = true; - - // Make this thread recognisable as the PrivateSend thread - RenameThread("dynamic-ps-server"); - - unsigned int nTick = 0; - - while (true) - { - MilliSleep(1000); + if(!dynodeSync.IsBlockchainSynced() || ShutdownRequested()) + return; - if(dynodeSync.IsBlockchainSynced() && !ShutdownRequested()) { - nTick++; - privateSendServer.CheckTimeout(connman); - privateSendServer.CheckForCompleteQueue(connman); - } - } + privateSendServer.CheckTimeout(connman); + privateSendServer.CheckForCompleteQueue(connman); } diff --git a/src/privatesend-server.h b/src/privatesend-server.h index 62b4bcc301..b11cb190de 100644 --- a/src/privatesend-server.h +++ b/src/privatesend-server.h @@ -21,7 +21,7 @@ class CPrivateSendServer : public CPrivateSendBase private: // Mixing uses collateral transactions to trust parties entering the pool // to behave honestly. If they don't it takes their money. - std::vector vecSessionCollaterals; + std::vector vecSessionCollaterals; bool fUnitTest; @@ -42,9 +42,9 @@ class CPrivateSendServer : public CPrivateSendBase void CommitFinalTransaction(CConnman& connman); /// Is this nDenom and txCollateral acceptable? - bool IsAcceptableDenomAndCollateral(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet); - bool CreateNewSession(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet, CConnman& connman); - bool AddUserToExistingSession(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet); + bool IsAcceptablePSA(const CPrivateSendAccept& psa, PoolMessage &nMessageIDRet); + bool CreateNewSession(const CPrivateSendAccept& psa, PoolMessage &nMessageIDRet, CConnman& connman); + bool AddUserToExistingSession(const CPrivateSendAccept& psa, PoolMessage &nMessageIDRet); /// Do we have enough users to take entries? bool IsSessionReady() { return (int)vecSessionCollaterals.size() >= CPrivateSend::GetMaxPoolTransactions(); } @@ -70,12 +70,12 @@ class CPrivateSendServer : public CPrivateSendBase CPrivateSendServer() : fUnitTest(false) { SetNull(); } - void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman); + void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void CheckTimeout(CConnman& connman); void CheckForCompleteQueue(CConnman& connman); -}; -void ThreadCheckPrivateSendServer(CConnman& connman); + void DoMaintenance(CConnman& connman); +}; #endif \ No newline at end of file diff --git a/src/privatesend-util.cpp b/src/privatesend-util.cpp index afe0924084..4703b3cc73 100644 --- a/src/privatesend-util.cpp +++ b/src/privatesend-util.cpp @@ -27,33 +27,48 @@ CScript CKeyHolder::GetScriptForDestination() const } -const CKeyHolder& CKeyHolderStorage::AddKey(CWallet* pwallet) +CScript CKeyHolderStorage::AddKey(CWallet* pwallet) { + auto keyHolder = std::unique_ptr(new CKeyHolder(pwallet)); + auto script = keyHolder->GetScriptForDestination(); + LOCK(cs_storage); - storage.emplace_back(std::unique_ptr(new CKeyHolder(pwallet))); + storage.emplace_back(std::move(keyHolder)); LogPrintf("CKeyHolderStorage::%s -- storage size %lld\n", __func__, storage.size()); - return *storage.back(); + return script; } -void CKeyHolderStorage::KeepAll(){ - LOCK(cs_storage); - if (storage.size() > 0) { - for (auto &key : storage) { + +void CKeyHolderStorage::KeepAll() +{ + std::vector> tmp; + { + // don't hold cs_storage while calling KeepKey(), which might lock cs_wallet + LOCK(cs_storage); + std::swap(storage, tmp); + } + + if (tmp.size() > 0) { + for (auto &key : tmp) { key->KeepKey(); } - LogPrintf("CKeyHolderStorage::%s -- %lld keys kept\n", __func__, storage.size()); - storage.clear(); + LogPrintf("CKeyHolderStorage::%s -- %lld keys kept\n", __func__, tmp.size()); } } void CKeyHolderStorage::ReturnAll() { - LOCK(cs_storage); - if (storage.size() > 0) { - for (auto &key : storage) { + std::vector> tmp; + { + // don't hold cs_storage while calling ReturnKey(), which might lock cs_wallet + LOCK(cs_storage); + std::swap(storage, tmp); + } + + if (tmp.size() > 0) { + for (auto &key : tmp) { key->ReturnKey(); } - LogPrintf("CKeyHolderStorage::%s -- %lld keys returned\n", __func__, storage.size()); - storage.clear(); + LogPrintf("CKeyHolderStorage::%s -- %lld keys returned\n", __func__, tmp.size()); } } \ No newline at end of file diff --git a/src/privatesend-util.h b/src/privatesend-util.h index e9e55caa00..e7c112630f 100644 --- a/src/privatesend-util.h +++ b/src/privatesend-util.h @@ -31,7 +31,7 @@ class CKeyHolderStorage mutable CCriticalSection cs_storage; public: - const CKeyHolder& AddKey(CWallet* pwalletIn); + CScript AddKey(CWallet* pwalletIn); void KeepAll(); void ReturnAll(); diff --git a/src/privatesend.cpp b/src/privatesend.cpp index 70cf2de9bf..99c0ee8e68 100644 --- a/src/privatesend.cpp +++ b/src/privatesend.cpp @@ -14,12 +14,13 @@ #include "dynode-sync.h" #include "dynodeman.h" #include "messagesigner.h" +#include "netmessagemaker.h" #include "script/sign.h" #include "txmempool.h" #include "util.h" #include "utilmoneystr.h" -#include +#include bool CPrivateSendEntry::AddScriptSig(const CTxIn& txin) { @@ -37,28 +38,71 @@ bool CPrivateSendEntry::AddScriptSig(const CTxIn& txin) return false; } +uint256 CPrivateSendQueue::GetSignatureHash() const +{ + return SerializeHash(*this); +} + bool CPrivateSendQueue::Sign() { if(!fDynodeMode) return false; - std::string strMessage = vin.ToString() + boost::lexical_cast(nDenom) + boost::lexical_cast(nTime) + boost::lexical_cast(fReady); + std::string strError = ""; - if(!CMessageSigner::SignMessage(strMessage, vchSig, activeDynode.keyDynode)) { - LogPrintf("CPrivateSendQueue::Sign -- SignMessage() failed, %s\n", ToString()); - return false; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if (!CHashSigner::SignHash(hash, activeDynode.keyDynode, vchSig)) { + LogPrintf("CPrivateSendQueue::Sign -- SignHash() failed\n"); + return false; + } + + if (!CHashSigner::VerifyHash(hash, activeDynode.pubKeyDynode, vchSig, strError)) { + LogPrintf("CPrivateSendQueue::Sign -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = CTxIn(dynodeOutpoint).ToString() + + std::to_string(nDenom) + + std::to_string(nTime) + + std::to_string(fReady); + + if(!CMessageSigner::SignMessage(strMessage, vchSig, activeDynode.keyDynode)) { + LogPrintf("CPrivateSendQueue::Sign -- SignMessage() failed, %s\n", ToString()); + return false; + } + + if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CPrivateSendQueue::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } - return CheckSignature(activeDynode.pubKeyDynode); + return true; } -bool CPrivateSendQueue::CheckSignature(const CPubKey& pubKeyDynode) +bool CPrivateSendQueue::CheckSignature(const CPubKey& pubKeyDynode) const { - std::string strMessage = vin.ToString() + boost::lexical_cast(nDenom) + boost::lexical_cast(nTime) + boost::lexical_cast(fReady); std::string strError = ""; - if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CPrivateSendQueue::CheckSignature -- Got bad Dynode queue signature: %s; error: %s\n", ToString(), strError); - return false; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + // we don't care about queues with old signature format + LogPrintf("CPrivateSendQueue::CheckSignature -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = CTxIn(dynodeOutpoint).ToString() + + std::to_string(nDenom) + + std::to_string(nTime) + + std::to_string(fReady); + + if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CPrivateSendQueue::CheckSignature -- Got bad Dynode queue signature: %s; error: %s\n", ToString(), strError); + return false; + } } return true; @@ -66,37 +110,73 @@ bool CPrivateSendQueue::CheckSignature(const CPubKey& pubKeyDynode) bool CPrivateSendQueue::Relay(CConnman& connman) { - std::vector vNodesCopy = connman.CopyNodeVector(); - BOOST_FOREACH(CNode* pnode, vNodesCopy) - if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION) - connman.PushMessage(pnode, NetMsgType::PSQUEUE, (*this)); - - connman.ReleaseNodeVector(vNodesCopy); + connman.ForEachNode([&connman, this](CNode* pnode) { + CNetMsgMaker msgMaker(pnode->GetSendVersion()); + if (pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION) + connman.PushMessage(pnode, msgMaker.Make(NetMsgType::PSQUEUE, (*this))); + }); return true; } +uint256 CPrivateSendBroadcastTx::GetSignatureHash() const +{ + return SerializeHash(*this); +} + bool CPrivateSendBroadcastTx::Sign() { if(!fDynodeMode) return false; - std::string strMessage = tx.GetHash().ToString() + boost::lexical_cast(sigTime); + std::string strError = ""; - if(!CMessageSigner::SignMessage(strMessage, vchSig, activeDynode.keyDynode)) { - LogPrintf("CPrivateSendBroadcastTx::Sign -- SignMessage() failed\n"); - return false; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if (!CHashSigner::SignHash(hash, activeDynode.keyDynode, vchSig)) { + LogPrintf("CPrivateSendBroadcastTx::Sign -- SignHash() failed\n"); + return false; + } + + if (!CHashSigner::VerifyHash(hash, activeDynode.pubKeyDynode, vchSig, strError)) { + LogPrintf("CPrivateSendBroadcastTx::Sign -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = tx->GetHash().ToString() + std::to_string(sigTime); + + if(!CMessageSigner::SignMessage(strMessage, vchSig, activeDynode.keyDynode)) { + LogPrintf("CPrivateSendBroadcastTx::Sign -- SignMessage() failed\n"); + return false; + } + + if(!CMessageSigner::VerifyMessage(activeDynode.pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CPrivateSendBroadcastTx::Sign -- VerifyMessage() failed, error: %s\n", strError); + return false; + } } - return CheckSignature(activeDynode.pubKeyDynode); + return true; } -bool CPrivateSendBroadcastTx::CheckSignature(const CPubKey& pubKeyDynode) +bool CPrivateSendBroadcastTx::CheckSignature(const CPubKey& pubKeyDynode) const { - std::string strMessage = tx.GetHash().ToString() + boost::lexical_cast(sigTime); std::string strError = ""; - if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { - LogPrintf("CPrivateSendBroadcastTx::CheckSignature -- Got bad pstx signature, error: %s\n", strError); - return false; + if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { + uint256 hash = GetSignatureHash(); + + if (!CHashSigner::VerifyHash(hash, pubKeyDynode, vchSig, strError)) { + // we don't care about pstxes with old signature format + LogPrintf("CPrivateSendBroadcastTx::CheckSignature -- VerifyHash() failed, error: %s\n", strError); + return false; + } + } else { + std::string strMessage = tx->GetHash().ToString() + std::to_string(sigTime); + + if(!CMessageSigner::VerifyMessage(pubKeyDynode, vchSig, strMessage, strError)) { + LogPrintf("CPrivateSendBroadcastTx::CheckSignature -- Got bad pstx signature, error: %s\n", strError); + return false; + } } return true; @@ -114,10 +194,11 @@ void CPrivateSendBase::SetNull() nState = POOL_STATE_IDLE; nSessionID = 0; nSessionDenom = 0; + nSessionInputCount = 0; vecEntries.clear(); finalMutableTransaction.vin.clear(); finalMutableTransaction.vout.clear(); - nTimeLastSuccessfulStep = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTime(); } void CPrivateSendBase::CheckQueue() @@ -186,16 +267,17 @@ bool CPrivateSend::IsCollateralValid(const CTransaction& txCollateral) CAmount nValueIn = 0; CAmount nValueOut = 0; - BOOST_FOREACH(const CTxOut txout, txCollateral.vout) { + for (const auto& txout : txCollateral.vout) { nValueOut += txout.nValue; - if(!txout.scriptPubKey.IsPayToPublicKeyHash()) { + bool fAllowData = dnpayments.GetMinDynodePaymentsProto() > 70900; + if(!txout.scriptPubKey.IsPayToPublicKeyHash() && !(fAllowData && txout.scriptPubKey.IsUnspendable())) { LogPrintf ("CPrivateSend::IsCollateralValid -- Invalid Script, txCollateral=%s", txCollateral.ToString()); return false; } } - BOOST_FOREACH(const CTxIn txin, txCollateral.vin) { + for (const auto& txin : txCollateral.vin) { Coin coin; if(!GetUTXOCoin(txin.prevout, coin)) { LogPrint("privatesend", "CPrivateSend::IsCollateralValid -- Unknown inputs in collateral transaction, txCollateral=%s", txCollateral.ToString()); @@ -215,7 +297,7 @@ bool CPrivateSend::IsCollateralValid(const CTransaction& txCollateral) { LOCK(cs_main); CValidationState validationState; - if(!AcceptToMemoryPool(mempool, validationState, txCollateral, false, NULL, false, maxTxFee, true)) { + if(!AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(txCollateral), false, NULL, NULL, false, maxTxFee, true)) { LogPrint("privatesend", "CPrivateSend::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n"); return false; } @@ -226,10 +308,13 @@ bool CPrivateSend::IsCollateralValid(const CTransaction& txCollateral) bool CPrivateSend::IsCollateralAmount(CAmount nInputAmount) { - // collateral inputs should always be a 2x..4x of mixing collateral - return nInputAmount > GetCollateralAmount() && - nInputAmount <= GetMaxCollateralAmount() && - nInputAmount % GetCollateralAmount() == 0; + if (dnpayments.GetMinDynodePaymentsProto() > 70900) { + // collateral input can be anything between 1x and "max" (including both) + return (nInputAmount >= GetCollateralAmount() && nInputAmount <= GetMaxCollateralAmount()); + } else { // <= 70208 + // collateral input can be anything between 2x and "max" (including both) + return (nInputAmount >= GetCollateralAmount() * 2 && nInputAmount <= GetMaxCollateralAmount()); + } } /* Create a nice string to show the denominations @@ -278,13 +363,13 @@ int CPrivateSend::GetDenominations(const std::vector& vecTxOut, bool fSi std::vector > vecDenomUsed; // make a list of denominations, with zero uses - BOOST_FOREACH(CAmount nDenomValue, vecStandardDenominations) + for (const auto& nDenomValue : vecStandardDenominations) vecDenomUsed.push_back(std::make_pair(nDenomValue, 0)); // look for denominations and update uses to 1 - BOOST_FOREACH(CTxOut txout, vecTxOut) { + for (const auto& txout : vecTxOut) { bool found = false; - BOOST_FOREACH (PAIRTYPE(CAmount, int)& s, vecDenomUsed) { + for (auto& s : vecDenomUsed) { if(txout.nValue == s.first) { s.second = 1; found = true; @@ -296,7 +381,7 @@ int CPrivateSend::GetDenominations(const std::vector& vecTxOut, bool fSi int nDenom = 0; int c = 0; // if the denomination is used, shift the bit on - BOOST_FOREACH (PAIRTYPE(CAmount, int)& s, vecDenomUsed) { + for (const auto& s : vecDenomUsed) { int bit = (fSingleRandomDenom ? GetRandInt(2) : 1) & s.second; nDenom |= bit << c++; if(fSingleRandomDenom && bit) break; // use just one random denomination @@ -374,6 +459,7 @@ std::string CPrivateSend::GetMessageByID(PoolMessage nMessageID) case MSG_NOERR: return _("No errors detected."); case MSG_SUCCESS: return _("Transaction created successfully."); case MSG_ENTRIES_ADDED: return _("Your entries added successfully."); + case ERR_INVALID_INPUT_COUNT: return _("Invalid input count."); default: return _("Unknown response."); } } @@ -381,7 +467,7 @@ std::string CPrivateSend::GetMessageByID(PoolMessage nMessageID) void CPrivateSend::AddPSTX(const CPrivateSendBroadcastTx& pstx) { LOCK(cs_mappstx); - mapPSTX.insert(std::make_pair(pstx.tx.GetHash(), pstx)); + mapPSTX.insert(std::make_pair(pstx.tx->GetHash(), pstx)); } CPrivateSendBroadcastTx CPrivateSend::GetPSTX(const uint256& hash) @@ -412,7 +498,7 @@ void CPrivateSend::UpdatedBlockTip(const CBlockIndex *pindex) } } -void CPrivateSend::SyncTransaction(const CTransaction& tx, const CBlock* pblock) +void CPrivateSend::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock) { if (tx.IsCoinBase()) return; @@ -421,68 +507,7 @@ void CPrivateSend::SyncTransaction(const CTransaction& tx, const CBlock* pblock) uint256 txHash = tx.GetHash(); if (!mapPSTX.count(txHash)) return; - // When tx is 0-confirmed or conflicted, pblock is NULL and nConfirmedHeight should be set to -1 - CBlockIndex* pblockindex = NULL; - if(pblock) { - uint256 blockHash = pblock->GetHash(); - BlockMap::iterator mi = mapBlockIndex.find(blockHash); - if(mi == mapBlockIndex.end() || !mi->second) { - // shouldn't happen - LogPrint("privatesend", "CPrivateSendClient::SyncTransaction -- Failed to find block %s\n", blockHash.ToString()); - return; - } - pblockindex = mi->second; - } - mapPSTX[txHash].SetConfirmedHeight(pblockindex ? pblockindex->nHeight : -1); + // When tx is 0-confirmed or conflicted, posInBlock is SYNC_TRANSACTION_NOT_IN_BLOCK and nConfirmedHeight should be set to -1 + mapPSTX[txHash].SetConfirmedHeight(posInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK ? -1 : pindex->nHeight); LogPrint("privatesend", "CPrivateSendClient::SyncTransaction -- txid=%s\n", txHash.ToString()); } - -//TODO: Rename/move to core -void ThreadCheckPrivateSend(CConnman& connman) -{ - if(fLiteMode) return; // disable all Dynamic specific functionality - - static bool fOneThread; - if(fOneThread) return; - fOneThread = true; - - // Make this thread recognisable as the PrivateSend thread - RenameThread("dynamic-ps"); - - unsigned int nTick = 0; - - while (true) - { - MilliSleep(1000); - - // try to sync from all available nodes, one step at a time - dynodeSync.ProcessTick(connman); - - if(dynodeSync.IsBlockchainSynced() && !ShutdownRequested()) { - - nTick++; - - // make sure to check all dynodes first - dnodeman.Check(); - - // check if we should activate or ping every few minutes, - // slightly postpone first run to give net thread a chance to connect to some peers - if(nTick % DYNODE_MIN_DNP_SECONDS == 15) - activeDynode.ManageState(connman); - - if(nTick % 60 == 0) { - dnodeman.ProcessDynodeConnections(connman); - dnodeman.CheckAndRemove(connman); - dnpayments.CheckAndRemove(); - instantsend.CheckAndRemove(); - } - if(fDynodeMode && (nTick % (60 * 5) == 0)) { - dnodeman.DoFullVerificationStep(connman); - } - - if(nTick % (60 * 5) == 0) { - governance.DoMaintenance(connman); - } - } - } -} \ No newline at end of file diff --git a/src/privatesend.h b/src/privatesend.h index 1959ede0ec..1e5b0856b1 100644 --- a/src/privatesend.h +++ b/src/privatesend.h @@ -52,6 +52,7 @@ enum PoolMessage { MSG_NOERR, MSG_SUCCESS, MSG_ENTRIES_ADDED, + ERR_INVALID_INPUT_COUNT, MSG_POOL_MIN = ERR_ALREADY_HAVE, MSG_POOL_MAX = MSG_ENTRIES_ADDED }; @@ -82,44 +83,80 @@ class CTxPSIn : public CTxIn // memory only CScript prevPubKey; bool fHasSig; // flag to indicate if signed - int nSentTimes; //times we've sent this anonymously CTxPSIn(const CTxIn& txin, const CScript& script) : CTxIn(txin), prevPubKey(script), - fHasSig(false), - nSentTimes(0) + fHasSig(false) {} CTxPSIn() : CTxIn(), prevPubKey(), - fHasSig(false), - nSentTimes(0) + fHasSig(false) {} }; +class CPrivateSendAccept +{ +public: + int nDenom; + int nInputCount; + CMutableTransaction txCollateral; + + CPrivateSendAccept() : + nDenom(0), + nInputCount(0), + txCollateral(CMutableTransaction()) + {}; + + CPrivateSendAccept(int nDenom, int nInputCount, const CMutableTransaction& txCollateral) : + nDenom(nDenom), + nInputCount(nInputCount), + txCollateral(txCollateral) + {}; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(nDenom); + int nVersion = s.GetVersion(); + if (nVersion > 70900) { + READWRITE(nInputCount); + } else if (ser_action.ForRead()) { + nInputCount = 0; + } + READWRITE(txCollateral); + } + + friend bool operator==(const CPrivateSendAccept& a, const CPrivateSendAccept& b) + { + return a.nDenom == b.nDenom && a.txCollateral == b.txCollateral; + } +}; + // A clients transaction in the mixing pool class CPrivateSendEntry { public: std::vector vecTxPSIn; std::vector vecTxOut; - CTransaction txCollateral; + CTransactionRef txCollateral; // memory only CService addr; CPrivateSendEntry() : vecTxPSIn(std::vector()), vecTxOut(std::vector()), - txCollateral(CTransaction()), + txCollateral(MakeTransactionRef()), addr(CService()) {} CPrivateSendEntry(const std::vector& vecTxPSIn, const std::vector& vecTxOut, const CTransaction& txCollateral) : vecTxPSIn(vecTxPSIn), vecTxOut(vecTxOut), - txCollateral(txCollateral), + txCollateral(MakeTransactionRef(txCollateral)), addr(CService()) {} @@ -143,7 +180,8 @@ class CPrivateSendQueue { public: int nDenom; - CTxIn vin; + int nInputCount; + COutPoint dynodeOutpoint; int64_t nTime; bool fReady; //ready for submit std::vector vchSig; @@ -152,16 +190,18 @@ class CPrivateSendQueue CPrivateSendQueue() : nDenom(0), - vin(CTxIn()), + nInputCount(0), + dynodeOutpoint(COutPoint()), nTime(0), fReady(false), vchSig(std::vector()), fTried(false) {} - CPrivateSendQueue(int nDenom, COutPoint outpoint, int64_t nTime, bool fReady) : + CPrivateSendQueue(int nDenom, int nInputCount, COutPoint outpoint, int64_t nTime, bool fReady) : nDenom(nDenom), - vin(CTxIn(outpoint)), + nInputCount(nInputCount), + dynodeOutpoint(outpoint), nTime(nTime), fReady(fReady), vchSig(std::vector()), @@ -173,12 +213,34 @@ class CPrivateSendQueue template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nDenom); - READWRITE(vin); + int nVersion = s.GetVersion(); + if (nVersion > 70900) { + READWRITE(nInputCount); + } else if (ser_action.ForRead()) { + nInputCount = 0; + } + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn txin{}; + if (ser_action.ForRead()) { + READWRITE(txin); + dynodeOutpoint = txin.prevout; + } else { + txin = CTxIn(dynodeOutpoint); + READWRITE(txin); + } + } else { + // using new format directly + READWRITE(dynodeOutpoint); + } READWRITE(nTime); READWRITE(fReady); - READWRITE(vchSig); + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(vchSig); + } } + uint256 GetSignatureHash() const; /** Sign this mixing transaction * \return true if all conditions are met: * 1) we have an active Dynode, @@ -188,22 +250,22 @@ class CPrivateSendQueue */ bool Sign(); /// Check if we have a valid Dynode address - bool CheckSignature(const CPubKey& pubKeyDynode); + bool CheckSignature(const CPubKey& pubKeyDynode) const; bool Relay(CConnman& connman); /// Is this queue expired? bool IsExpired() { return GetAdjustedTime() - nTime > PRIVATESEND_QUEUE_TIMEOUT; } - std::string ToString() + std::string ToString() const { - return strprintf("nDenom=%d, nTime=%lld, fReady=%s, fTried=%s, dynode=%s", - nDenom, nTime, fReady ? "true" : "false", fTried ? "true" : "false", vin.prevout.ToStringShort()); + return strprintf("nDenom=%d, nInputCount=%d, nTime=%lld, fReady=%s, fTried=%s, dynode=%s", + nDenom, nInputCount, nTime, fReady ? "true" : "false", fTried ? "true" : "false", dynodeOutpoint.ToStringShort()); } friend bool operator==(const CPrivateSendQueue& a, const CPrivateSendQueue& b) { - return a.nDenom == b.nDenom && a.vin.prevout == b.vin.prevout && a.nTime == b.nTime && a.fReady == b.fReady; + return a.nDenom == b.nDenom && a.nInputCount == b.nInputCount && a.dynodeOutpoint == b.dynodeOutpoint && a.nTime == b.nTime && a.fReady == b.fReady; } }; @@ -217,25 +279,25 @@ class CPrivateSendBroadcastTx int nConfirmedHeight; public: - CTransaction tx; - CTxIn vin; + CTransactionRef tx; + COutPoint dynodeOutpoint; std::vector vchSig; int64_t sigTime; CPrivateSendBroadcastTx() : nConfirmedHeight(-1), - tx(), - vin(), + tx(MakeTransactionRef()), + dynodeOutpoint(), vchSig(), sigTime(0) {} - CPrivateSendBroadcastTx(CTransaction tx, COutPoint outpoint, int64_t sigTime) : + CPrivateSendBroadcastTx(const CTransactionRef& _tx, COutPoint _outpoint, int64_t _sigTime) : nConfirmedHeight(-1), - tx(tx), - vin(CTxIn(outpoint)), + tx(_tx), + dynodeOutpoint(_outpoint), vchSig(), - sigTime(sigTime) + sigTime(_sigTime) {} ADD_SERIALIZE_METHODS; @@ -243,14 +305,30 @@ class CPrivateSendBroadcastTx template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(tx); - READWRITE(vin); - READWRITE(vchSig); + int nVersion = s.GetVersion(); + if (nVersion == 70900 && (s.GetType() & SER_NETWORK)) { + // converting from/to old format + CTxIn txin{}; + if (ser_action.ForRead()) { + READWRITE(txin); + dynodeOutpoint = txin.prevout; + } else { + txin = CTxIn(dynodeOutpoint); + READWRITE(txin); + } + } else { + // using new format directly + READWRITE(dynodeOutpoint); + } + if (!(s.GetType() & SER_GETHASH)) { + READWRITE(vchSig); + } READWRITE(sigTime); } friend bool operator==(const CPrivateSendBroadcastTx& a, const CPrivateSendBroadcastTx& b) { - return a.tx == b.tx; + return *a.tx == *b.tx; } friend bool operator!=(const CPrivateSendBroadcastTx& a, const CPrivateSendBroadcastTx& b) { @@ -261,8 +339,10 @@ class CPrivateSendBroadcastTx return *this != CPrivateSendBroadcastTx(); } + uint256 GetSignatureHash() const; + bool Sign(); - bool CheckSignature(const CPubKey& pubKeyDynode); + bool CheckSignature(const CPubKey& pubKeyDynode) const; void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; } bool IsExpired(int nHeight); @@ -291,6 +371,7 @@ class CPrivateSendBase public: int nSessionDenom; //Users must submit an denom matching this + int nSessionInputCount; //Users must submit a count matching this CPrivateSendBase() { SetNull(); } @@ -354,10 +435,7 @@ class CPrivateSend static CPrivateSendBroadcastTx GetPSTX(const uint256& hash); static void UpdatedBlockTip(const CBlockIndex *pindex); - - static void SyncTransaction(const CTransaction& tx, const CBlock* pblock); + static void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock); }; -void ThreadCheckPrivateSend(CConnman& connman); - #endif \ No newline at end of file diff --git a/src/protocol.cpp b/src/protocol.cpp index 8aa300a0be..53f9b29677 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -37,7 +37,10 @@ const char *FILTERADD="filteradd"; const char *FILTERCLEAR="filterclear"; const char *REJECT="reject"; const char *SENDHEADERS="sendheaders"; -const char *FEEFILTER="feefilter"; +const char *SENDCMPCT="sendcmpct"; +const char *CMPCTBLOCK="cmpctblock"; +const char *GETBLOCKTXN="getblocktxn"; +const char *BLOCKTXN="blocktxn"; // Dynamic message types const char *TXLOCKREQUEST="is"; const char *TXLOCKVOTE="txlvote"; @@ -113,7 +116,10 @@ const static std::string allNetMessageTypes[] = { NetMsgType::FILTERCLEAR, NetMsgType::REJECT, NetMsgType::SENDHEADERS, - NetMsgType::FEEFILTER, + NetMsgType::SENDCMPCT, + NetMsgType::CMPCTBLOCK, + NetMsgType::GETBLOCKTXN, + NetMsgType::BLOCKTXN, // Dynamic message types // NOTE: do NOT include non-implmented here, we want them to be "Unknown command" in ProcessMessage() NetMsgType::TXLOCKREQUEST, diff --git a/src/protocol.h b/src/protocol.h index 13a1439192..377569a8d5 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -218,11 +218,31 @@ extern const char *REJECT; */ extern const char *SENDHEADERS; /** - * The feefilter message tells the receiving peer not to inv us any txs - * which do not meet the specified min fee rate. - * @since protocol version 70600 as described by BIP133 + * Contains a 1-byte bool and 8-byte LE version number. + * Indicates that a node is willing to provide blocks via "cmpctblock" messages. + * May indicate that a node prefers to receive new block announcements via a + * "cmpctblock" message rather than an "inv", depending on message contents. + * @since protocol version 71000 as described by BIP 152 */ -extern const char *FEEFILTER; +extern const char *SENDCMPCT; +/** + * Contains a CBlockHeaderAndShortTxIDs object - providing a header and + * list of "short txids". + * @since protocol version 71000 as described by BIP 152 + */ +extern const char *CMPCTBLOCK; +/** + * Contains a BlockTransactionsRequest + * Peer should respond with "blocktxn" message. + * @since protocol version 71000 as described by BIP 152 + */ +extern const char *GETBLOCKTXN; +/** + * Contains a BlockTransactions. + * Sent in response to a "getblocktxn" message. + * @since protocol version 71000 as described by BIP 152 + */ +extern const char *BLOCKTXN; // Dynamic message types // NOTE: do NOT declare non-implmented here, we don't want them to be exposed to the outside // TODO: add description @@ -267,12 +287,17 @@ enum ServiceFlags : uint64_t { // NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections. // Dynamic nodes used to support this by default, without advertising this bit. NODE_BLOOM = (1 << 2), + // NODE_XTHIN means the node supports Xtreme Thinblocks + // If this is turned off then the node will not service nor make xthin requests + NODE_XTHIN = (1 << 4), - // Remember that service bits are just unauthenticated - // advertisements, so your code must be robust against - // collisions and other cases where nodes may be advertising - // a service they do not actually support. Other service - // bits should be allocated via the BIP process. + // 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 + // unauthenticated advertisements, so your code must be robust against + // collisions and other cases where nodes may be advertising a service they + // do not actually support. Other service bits should be allocated via the + // BIP process. }; /** A CService with information about it as peer */ @@ -335,6 +360,9 @@ enum GetDataMsg { MSG_GOVERNANCE_OBJECT = 13, MSG_GOVERNANCE_OBJECT_VOTE = 14, MSG_DYNODE_VERIFY = 15, + // Nodes may always request a MSG_CMPCT_BLOCK in a getdata, however, + // MSG_CMPCT_BLOCK should not appear in any invs except as a part of getdata. + MSG_CMPCT_BLOCK = 20, //!< Defined in BIP152 }; /** inv message data */ diff --git a/src/psnotificationinterface.cpp b/src/psnotificationinterface.cpp index 06b8c2f28c..d9e93a45a6 100644 --- a/src/psnotificationinterface.cpp +++ b/src/psnotificationinterface.cpp @@ -42,6 +42,9 @@ void CPSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con if (fInitialDownload) return; + if (fLiteMode) + return; + dnodeman.UpdatedBlockTip(pindexNew); CPrivateSend::UpdatedBlockTip(pindexNew); #ifdef ENABLE_WALLET @@ -52,8 +55,8 @@ void CPSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con governance.UpdatedBlockTip(pindexNew, connman); } -void CPSNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) +void CPSNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) { - instantsend.SyncTransaction(tx, pblock); - CPrivateSend::SyncTransaction(tx, pblock); + instantsend.SyncTransaction(tx, pindex, posInBlock); + CPrivateSend::SyncTransaction(tx, pindex, posInBlock); } diff --git a/src/psnotificationinterface.h b/src/psnotificationinterface.h index fd235fb905..11d8b38963 100644 --- a/src/psnotificationinterface.h +++ b/src/psnotificationinterface.h @@ -22,7 +22,7 @@ class CPSNotificationInterface : public CValidationInterface void AcceptedBlockHeader(const CBlockIndex *pindexNew) override; void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) override; void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; - void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) override; + void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) override; private: CConnman& connman; diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 4e56c1ff5d..a74fdffe91 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -22,7 +22,7 @@ secp256k1_context* secp256k1_context_verify = NULL; * * Supported violations include negative integers, excessive padding, garbage * at the end, and overly long length descriptors. This is safe to use in - * Bitcoin because since the activation of BIP66, signatures are verified to be + * Dynamic because since the activation of BIP66, signatures are verified to be * strict DER before being passed to this module, and we know it supports all * violations present in the blockchain before that point. */ diff --git a/src/pubkey.h b/src/pubkey.h index bffd952b99..bfd4c44e1c 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -15,7 +15,7 @@ #include #include -/** +/** * secp256k1: * const unsigned int PRIVATE_KEY_SIZE = 279; * const unsigned int PUBLIC_KEY_SIZE = 65; @@ -154,7 +154,7 @@ class CPubKey /* * Check syntactic correctness. - * + * * Note that this is consensus critical as CheckSig() calls it! */ bool IsValid() const @@ -201,8 +201,11 @@ struct CExtPubKey { friend bool operator==(const CExtPubKey &a, const CExtPubKey &b) { - return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild && - a.chaincode == b.chaincode && a.pubkey == b.pubkey; + return a.nDepth == b.nDepth && + memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && + a.nChild == b.nChild && + a.chaincode == b.chaincode && + a.pubkey == b.pubkey; } void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index cdaaceaee3..bfa68d64f6 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -168,7 +168,7 @@ double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const LOCK(cs_main); tip = chainActive.Tip(); } - return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), tip); + return GuessVerificationProgress(Params().TxData(), tip); } void ClientModel::updateTimer() diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index ec2a9ed602..e1bbc66586 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -527,14 +527,14 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nQuantity++; // Amount - nAmount += out.tx->vout[out.i].nValue; + nAmount += out.tx->tx->vout[out.i].nValue; // Priority - dPriorityInputs += (double)out.tx->vout[out.i].nValue * (out.nDepth+1); + dPriorityInputs += (double)out.tx->tx->vout[out.i].nValue * (out.nDepth+1); // Bytes CTxDestination address; - if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) { CPubKey pubkey; CKeyID *keyid = boost::get(&address); @@ -731,7 +731,7 @@ void CoinControlDialog::updateView() CAmount nSum = 0; int nChildren = 0; BOOST_FOREACH(const COutput& out, coins.second) { - nSum += out.tx->vout[out.i].nValue; + nSum += out.tx->tx->vout[out.i].nValue; nChildren++; CCoinControlWidgetItem *itemOutput; @@ -743,7 +743,7 @@ void CoinControlDialog::updateView() // address CTxDestination outputAddress; QString sAddress = ""; - if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, outputAddress)) + if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress)) { sAddress = QString::fromStdString(CDynamicAddress(outputAddress).ToString()); @@ -770,9 +770,9 @@ void CoinControlDialog::updateView() } // amount - itemOutput->setText(COLUMN_AMOUNT, DynamicUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue)); - itemOutput->setToolTip(COLUMN_AMOUNT, DynamicUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue)); - itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly + itemOutput->setText(COLUMN_AMOUNT, DynamicUnits::format(nDisplayUnit, out.tx->tx->vout[out.i].nValue)); + itemOutput->setToolTip(COLUMN_AMOUNT, DynamicUnits::format(nDisplayUnit, out.tx->tx->vout[out.i].nValue)); + itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->tx->vout[out.i].nValue)); // padding so that sorting works correctly // date itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); @@ -781,7 +781,7 @@ void CoinControlDialog::updateView() // PrivateSend rounds - COutPoint outpoint = COutPoint(out.tx->GetHash(), out.i); + COutPoint outpoint = COutPoint(out.tx->tx->GetHash(), out.i); int nRounds = pwalletMain->GetOutpointPrivateSendRounds(outpoint); if (nRounds >= 0 || fDebug) itemOutput->setText(COLUMN_PRIVATESEND_ROUNDS, QString::number(nRounds)); diff --git a/src/qt/coincontroltreewidget.h b/src/qt/coincontroltreewidget.h index 3a335b1c99..a540d204a7 100644 --- a/src/qt/coincontroltreewidget.h +++ b/src/qt/coincontroltreewidget.h @@ -19,7 +19,7 @@ class CoinControlTreeWidget : public QTreeWidget explicit CoinControlTreeWidget(QWidget *parent = 0); protected: - virtual void keyPressEvent(QKeyEvent *event); + virtual void keyPressEvent(QKeyEvent *event) override; }; #endif // DYNAMIC_QT_COINCONTROLTREEDIALOG_H diff --git a/src/qt/dynamicgui.cpp b/src/qt/dynamicgui.cpp index 08d5b79aa2..6fb13e395d 100644 --- a/src/qt/dynamicgui.cpp +++ b/src/qt/dynamicgui.cpp @@ -842,9 +842,9 @@ void DynamicGUI::showConfEditor() GUIUtil::openConfigfile(); } -void DynamicGUI::showSNConfEditor() +void DynamicGUI::showDNConfEditor() { - GUIUtil::openSNConfigfile(); + GUIUtil::openDNConfigfile(); } void DynamicGUI::showBackups() diff --git a/src/qt/dynamicgui.h b/src/qt/dynamicgui.h index 6edf5d0f89..66a33d9ba2 100644 --- a/src/qt/dynamicgui.h +++ b/src/qt/dynamicgui.h @@ -271,7 +271,7 @@ private Q_SLOTS: /** Open external (default) editor with dynamic.conf */ void showConfEditor(); /** Open external (default) editor with dynode.conf */ - void showSNConfEditor(); + void showDNConfEditor(); /** Show folder with wallet backups in default file browser */ void showBackups(); diff --git a/src/qt/dynodelist.cpp b/src/qt/dynodelist.cpp index 17d5721a24..e548047bc8 100644 --- a/src/qt/dynodelist.cpp +++ b/src/qt/dynodelist.cpp @@ -119,10 +119,14 @@ void DynodeList::StartAlias(std::string strAlias) bool fSuccess = CDynodeBroadcast::Create(dne.getIp(), dne.getPrivKey(), dne.getTxHash(), dne.getOutputIndex(), strError, dnb); + int nDoS; + if (fSuccess && !dnodeman.CheckDnbAndUpdateDynodeList(NULL, dnb, nDoS, *g_connman)) { + strError = "Failed to verify DNB"; + fSuccess = false; + } + if(fSuccess) { strStatusHtml += "
Successfully started Dynode."; - dnodeman.UpdateDynodeList(dnb, *g_connman); - dnb.Relay(*g_connman); dnodeman.NotifyDynodeUpdates(*g_connman); } else { strStatusHtml += "
Failed to start Dynode.
Error: " + strError; @@ -160,10 +164,14 @@ void DynodeList::StartAll(std::string strCommand) bool fSuccess = CDynodeBroadcast::Create(dne.getIp(), dne.getPrivKey(), dne.getTxHash(), dne.getOutputIndex(), strError, dnb); + int nDoS; + if (fSuccess && !dnodeman.CheckDnbAndUpdateDynodeList(NULL, dnb, nDoS, *g_connman)) { + strError = "Failed to verify DNB"; + fSuccess = false; + } + if(fSuccess) { nCountSuccessful++; - dnodeman.UpdateDynodeList(dnb, *g_connman); - dnb.Relay(*g_connman); dnodeman.NotifyDynodeUpdates(*g_connman); } else { nCountFailed++; @@ -229,7 +237,6 @@ void DynodeList::updateMyNodeList(bool fForce) if(!fLockAcquired) { return; } - static int64_t nTimeMyListUpdated = 0; // automatically update my Dynode list only once in MY_DYNODELIST_UPDATE_SECONDS seconds, @@ -240,6 +247,11 @@ void DynodeList::updateMyNodeList(bool fForce) if(nSecondsTillUpdate > 0 && !fForce) return; nTimeMyListUpdated = GetTime(); + // Find selected row + QItemSelectionModel* selectionModel = ui->tableWidgetMyDynodes->selectionModel(); + QModelIndexList selected = selectionModel->selectedRows(); + int nSelectedRow = selected.count() ? selected.at(0).row() : 0; + ui->tableWidgetDynodes->setSortingEnabled(false); for (const auto& dne : dynodeConfig.getEntries()) { int32_t nOutputIndex = 0; @@ -249,6 +261,7 @@ void DynodeList::updateMyNodeList(bool fForce) updateMyDynodeInfo(QString::fromStdString(dne.getAlias()), QString::fromStdString(dne.getIp()), COutPoint(uint256S(dne.getTxHash()), nOutputIndex)); } + ui->tableWidgetMyDynodes->selectRow(nSelectedRow); ui->tableWidgetDynodes->setSortingEnabled(true); // reset "timer" @@ -284,7 +297,7 @@ void DynodeList::updateNodeList() std::map mapDynodes = dnodeman.GetFullDynodeMap(); int offsetFromUtc = GetOffsetFromUtc(); - for(auto& dnpair : mapDynodes) + for(const auto& dnpair : mapDynodes) { CDynode dn = dnpair.second; // populate list diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 464474f93f..fa94e714d2 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -123,6 +123,23 @@ QFont fixedPitchFont() #endif } +// Just some dummy data to generate an convincing random-looking (but consistent) address +static const uint8_t dummydata[] = {0xeb,0x15,0x23,0x1d,0xfc,0xeb,0x60,0x92,0x58,0x86,0xb6,0x7d,0x06,0x52,0x99,0x92,0x59,0x15,0xae,0xb1,0x72,0xc0,0x66,0x47}; + +// Generate a dummy address with invalid CRC, starting with the network prefix. +static std::string DummyAddress(const CChainParams ¶ms) +{ + std::vector sourcedata = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); + sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata)); + for(int i=0; i<256; ++i) { // Try every trailing byte + std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size()); + if (!CDynamicAddress(s).IsValid()) + return s; + sourcedata[sourcedata.size()-1] += 1; + } + return ""; +} + void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent) { parent->setFocusProxy(widget); @@ -131,7 +148,8 @@ void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent) #if QT_VERSION >= 0x040700 // We don't want translators to use own addresses in translations // and this is the only place, where this address is supplied. - widget->setPlaceholderText(QObject::tr("Enter a Dynamic address (e.g. %1)").arg("D5nRy9Tf7Zsef8gMGL2fhWA9ZslrP4K5tf")); + widget->setPlaceholderText(QObject::tr("Enter a Dynamic address (e.g. %1)").arg( + QString::fromStdString(DummyAddress(Params())))); #endif widget->setValidator(new DynamicAddressEntryValidator(parent)); widget->setCheckValidator(new DynamicAddressCheckValidator(parent)); @@ -443,7 +461,7 @@ void openConfigfile() QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); } -void openSNConfigfile() +void openDNConfigfile() { boost::filesystem::path pathConfig = GetDynodeConfigFile(); @@ -847,45 +865,31 @@ LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef CFRelease(currentItemURL); } } - - CFRelease(listSnapshot); - return nullptr; + return NULL; } bool GetStartOnSystemStartup() { CFURLRef dynamicAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - if (dynamicAppUrl == nullptr) { - return false; - } - - LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr); + LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, dynamicAppUrl); - - CFRelease(dynamicAppUrl); return !!foundItem; // return boolified object } bool SetStartOnSystemStartup(bool fAutoStart) { CFURLRef dynamicAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - if (dynamicAppUrl == nullptr) { - return false; - } - - LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr); + LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, dynamicAppUrl); if(fAutoStart && !foundItem) { - // add dynamic app to startup item list - LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, nullptr, nullptr, dynamicAppUrl, nullptr, nullptr); + // add Dynamic Core app to startup item list + LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, dynamicAppUrl, NULL, NULL); } else if(!fAutoStart && foundItem) { // remove item LSSharedFileListItemRemove(loginItems, foundItem); } - - CFRelease(dynamicAppUrl); return true; } #pragma GCC diagnostic pop @@ -896,6 +900,17 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; } #endif +void migrateQtSettings() +{ + QSettings settings; + if(!settings.value("fMigrationDone121", false).toBool()) { + settings.remove("theme"); + settings.remove("nWindowPos"); + settings.remove("nWindowSize"); + settings.setValue("fMigrationDone121", true); + } +} + void saveWindowGeometry(const QString& strSetting, QWidget *parent) { QSettings settings; @@ -909,14 +924,17 @@ void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize, QPoint pos = settings.value(strSetting + "Pos").toPoint(); QSize size = settings.value(strSetting + "Size", defaultSize).toSize(); - if (!pos.x() && !pos.y()) { - QRect screen = QApplication::desktop()->screenGeometry(); - pos.setX((screen.width() - size.width()) / 2); - pos.setY((screen.height() - size.height()) / 2); - } - parent->resize(size); parent->move(pos); + + if ((!pos.x() && !pos.y()) || (QApplication::desktop()->screenNumber(parent) == -1)) + { + QRect screen = QApplication::desktop()->screenGeometry(); + QPoint defaultPos = screen.center() - + QPoint(defaultSize.width() / 2, defaultSize.height() / 2); + parent->resize(defaultSize); + parent->move(defaultPos); + } } // Return name of current UI-theme or default theme if no theme was found @@ -1019,6 +1037,9 @@ QString formatServicesStr(quint64 mask) case NODE_BLOOM: strList.append("BLOOM"); break; + case NODE_XTHIN: + strList.append("XTHIN"); + break; default: strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check)); } diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index f7929e03c1..06970e4df4 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -124,7 +124,7 @@ namespace GUIUtil void openConfigfile(); // Open dynode.conf - void openSNConfigfile(); + void openDNConfigfile(); // Browse backup folder void showBackups(); @@ -192,6 +192,9 @@ namespace GUIUtil bool GetStartOnSystemStartup(); bool SetStartOnSystemStartup(bool fAutoStart); + /** Modify Qt network specific settings on migration */ + void migrateQtSettings(); + /** Save window size and position */ void saveWindowGeometry(const QString& strSetting, QWidget *parent); /** Restore window size and position */ diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index 9d705c8e73..169426e07b 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -51,11 +51,11 @@ class ReceiveCoinsDialog : public QDialog public Q_SLOTS: void clear(); - void reject(); - void accept(); + void reject() override; + void accept() override; protected: - virtual void keyPressEvent(QKeyEvent *event); + virtual void keyPressEvent(QKeyEvent *event) override; private: Ui::ReceiveCoinsDialog *ui; @@ -66,7 +66,7 @@ public Q_SLOTS: QModelIndex selectedRow(); void copyColumnToClipboard(int column); - virtual void resizeEvent(QResizeEvent *event); + virtual void resizeEvent(QResizeEvent *event) override; private Q_SLOTS: void on_receiveButton_clicked(); diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 9593a4b0ad..1e669187ad 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -41,8 +41,8 @@ public Q_SLOTS: void copyImage(); protected: - virtual void mousePressEvent(QMouseEvent *event); - virtual void contextMenuEvent(QContextMenuEvent *event); + virtual void mousePressEvent(QMouseEvent *event) override; + virtual void contextMenuEvent(QContextMenuEvent *event) override; private: QMenu *contextMenu; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index ef41979973..6526dbe3e3 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -30,10 +30,10 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) AssertLockHeld(cs_main); if (!CheckFinalTx(wtx)) { - if (wtx.nLockTime < LOCKTIME_THRESHOLD) - return tr("Open for %n more block(s)", "", wtx.nLockTime - chainActive.Height()); + if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD) + return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height()); else - return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime)); + return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime)); } else { @@ -157,7 +157,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // Coinbase // CAmount nUnmatured = 0; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) + BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) nUnmatured += wallet->GetCredit(txout, ISMINE_ALL); strHTML += "" + tr("Credit") + ": "; if (wtx.IsInMainChain()) @@ -176,14 +176,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco else { isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { isminetype mine = wallet->IsMine(txin); if(fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) + BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) { isminetype mine = wallet->IsMine(txout); if(fAllToMe > mine) fAllToMe = mine; @@ -197,7 +197,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Debit // - BOOST_FOREACH(const CTxOut& txout, wtx.vout) + BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) { // Ignore change isminetype toSelf = wallet->IsMine(txout); @@ -236,7 +236,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "" + tr("Total credit") + ": " + DynamicUnits::formatHtmlWithUnit(unit, nValue) + "
"; } - CAmount nTxFee = nDebit - wtx.GetValueOut(); + CAmount nTxFee = nDebit - wtx.tx->GetValueOut(); if (nTxFee > 0) strHTML += "" + tr("Transaction fee") + ": " + DynamicUnits::formatHtmlWithUnit(unit, -nTxFee) + "
"; } @@ -245,10 +245,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Mixed debit transaction // - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) if (wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + DynamicUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) + BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) if (wallet->IsMine(txout)) strHTML += "" + tr("Credit") + ": " + DynamicUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
"; } @@ -266,7 +266,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "" + tr("Transaction ID") + ": " + rec->getTxID() + "
"; strHTML += "" + tr("Output index") + ": " + QString::number(rec->getOutputIndex()) + "
"; - strHTML += "" + tr("Transaction total size") + ": " + QString::number(wtx.GetTotalSize()) + " bytes
"; + strHTML += "" + tr("Transaction total size") + ": " + QString::number(wtx.tx->GetTotalSize()) + " bytes
"; // Message from normal dynamic:URI (dynamic:XyZ...?message=example) Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm) @@ -300,20 +300,20 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (fDebug) { strHTML += "

" + tr("Debug information") + "

"; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) if(wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + DynamicUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) + BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) if(wallet->IsMine(txout)) strHTML += "" + tr("Credit") + ": " + DynamicUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
"; strHTML += "
" + tr("Transaction") + ":
"; - strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true); + strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true); strHTML += "
" + tr("Inputs") + ":"; strHTML += "
    "; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { COutPoint prevout = txin.prevout; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 7133fa4bed..906c08caaf 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -55,14 +55,15 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // // Credit // - BOOST_FOREACH(const CTxOut& txout, wtx.vout) + for(unsigned int i = 0; i < wtx.tx->vout.size(); i++) { + const CTxOut& txout = wtx.tx->vout[i]; isminetype mine = wallet->IsMine(txout); if(mine) { TransactionRecord sub(hash, nTime); CTxDestination address; - sub.idx = parts.size(); // sequence number + sub.idx = i; // vout index sub.credit = txout.nValue; sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) @@ -98,7 +99,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * int nFromMe = 0; bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { if(wallet->IsMine(txin)) { fAllFromMeDenom = fAllFromMeDenom && wallet->IsDenominated(txin.prevout); @@ -112,7 +113,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * isminetype fAllToMe = ISMINE_SPENDABLE; bool fAllToMeDenom = true; int nToMe = 0; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) { + BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) { if(wallet->IsMine(txout)) { fAllToMeDenom = fAllToMeDenom && CPrivateSend::IsDenominatedAmount(txout.nValue); nToMe++; @@ -136,11 +137,12 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // Payment to self by default sub.type = TransactionRecord::SendToSelf; sub.address = ""; + if(mapValue["PS"] == "1") { sub.type = TransactionRecord::PrivateSend; CTxDestination address; - if (ExtractDestination(wtx.vout[0].scriptPubKey, address)) + if (ExtractDestination(wtx.tx->vout[0].scriptPubKey, address)) { // Sent to Dynamic Address sub.address = CDynamicAddress(address).ToString(); @@ -153,14 +155,15 @@ QList TransactionRecord::decomposeTransaction(const CWallet * } else { - for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) + for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { - const CTxOut& txout = wtx.vout[nOut]; + const CTxOut& txout = wtx.tx->vout[nOut]; sub.idx = parts.size(); + if(IsTransactionFluid(txout.scriptPubKey)) sub.type = TransactionRecord::Fluid; if(CPrivateSend::IsCollateralAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendMakeCollaterals; if(CPrivateSend::IsDenominatedAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendCreateDenominations; - if(nDebit - wtx.GetValueOut() == CPrivateSend::GetCollateralAmount()) sub.type = TransactionRecord::PrivateSendCollateralPayment; + if(nDebit - wtx.tx->GetValueOut() == CPrivateSend::GetCollateralAmount()) sub.type = TransactionRecord::PrivateSendCollateralPayment; } } @@ -176,12 +179,12 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // // Debit // - CAmount nTxFee = nDebit - wtx.GetValueOut(); + CAmount nTxFee = nDebit - wtx.tx->GetValueOut(); CDomainEntry entry; std::string strOpType; - for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) + for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { - const CTxOut& txout = wtx.vout[nOut]; + const CTxOut& txout = wtx.tx->vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); sub.involvesWatchAddress = involvesWatchAddress; @@ -300,15 +303,15 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) if (!CheckFinalTx(wtx)) { - if (wtx.nLockTime < LOCKTIME_THRESHOLD) + if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD) { status.status = TransactionStatus::OpenUntilBlock; - status.open_for = wtx.nLockTime - chainActive.Height(); + status.open_for = wtx.tx->nLockTime - chainActive.Height(); } else { status.status = TransactionStatus::OpenUntilDate; - status.open_for = wtx.nLockTime; + status.open_for = wtx.tx->nLockTime; } } // For generated transactions, determine maturity diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 7212291157..b901164534 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -84,9 +84,9 @@ class TransactionView : public QWidget GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer; - virtual void resizeEvent(QResizeEvent* event); + virtual void resizeEvent(QResizeEvent* event) override; - bool eventFilter(QObject *obj, QEvent *event); + bool eventFilter(QObject *obj, QEvent *event) override; private Q_SLOTS: void contextualMenu(const QPoint &); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index b4038342ea..6fa8aa7abd 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -81,7 +81,7 @@ CAmount WalletModel::getBalance(const CCoinControl *coinControl) const wallet->AvailableCoins(vCoins, true, coinControl); BOOST_FOREACH(const COutput& out, vCoins) if(out.fSpendable) - nBalance += out.tx->vout[out.i].nValue; + nBalance += out.tx->tx->vout[out.i].nValue; return nBalance; } @@ -321,12 +321,12 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact transaction.reassignAmounts(nChangePosRet); if(recipients[0].fUseInstantSend) { - if(newTx->GetValueOut() > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { + if(newTx->tx->GetValueOut() > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DYN.").arg(sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } - if(newTx->vin.size() > CTxLockRequest::WARN_MANY_INPUTS) { + if(newTx->tx->vin.size() > CTxLockRequest::WARN_MANY_INPUTS) { Q_EMIT message(tr("Send Coins"), tr("Used way too many inputs (>%1) for this InstantSend transaction, fees could be huge.").arg(CTxLockRequest::WARN_MANY_INPUTS), CClientUIInterface::MSG_WARNING); } @@ -684,7 +684,7 @@ void WalletModel::listCoins(std::map >& mapCoins) int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true); - if (outpoint.n < out.tx->vout.size() && wallet->IsMine(out.tx->vout[outpoint.n]) == ISMINE_SPENDABLE) + if (outpoint.n < out.tx->tx->vout.size() && wallet->IsMine(out.tx->tx->vout[outpoint.n]) == ISMINE_SPENDABLE) vCoins.push_back(out); } @@ -692,14 +692,14 @@ void WalletModel::listCoins(std::map >& mapCoins) { COutput cout = out; - while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0])) + while (wallet->IsChange(cout.tx->tx->vout[cout.i]) && cout.tx->tx->vin.size() > 0 && wallet->IsMine(cout.tx->tx->vin[0])) { - if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break; - cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0, true, true); + if (!wallet->mapWallet.count(cout.tx->tx->vin[0].prevout.hash)) break; + cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], cout.tx->tx->vin[0].prevout.n, 0, true, true); } CTxDestination address; - if(!out.fSpendable || !ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) + if(!out.fSpendable || !ExtractDestination(cout.tx->tx->vout[cout.i].scriptPubKey, address)) continue; mapCoins[QString::fromStdString(CDynamicAddress(address).ToString())].push_back(out); } diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 9d949e8ef3..6114ee9ac9 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -66,7 +66,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet) if (out.amount() <= 0) continue; if (i == nChangePosRet) i++; - subtotal += walletTransaction->vout[i].nValue; + subtotal += walletTransaction->tx->vout[i].nValue; i++; } rcp.amount = subtotal; @@ -75,7 +75,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet) { if (i == nChangePosRet) i++; - rcp.amount = walletTransaction->vout[i].nValue; + rcp.amount = walletTransaction->tx->vout[i].nValue; i++; } } diff --git a/src/rest.cpp b/src/rest.cpp index 877c0369e0..afc0cea371 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -366,7 +366,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) if (!ParseHashStr(hashStr, hash)) return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); - CTransaction tx; + CTransactionRef tx; uint256 hashBlock = uint256(); if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); @@ -391,7 +391,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) case RF_JSON: { UniValue objTx(UniValue::VOBJ); - TxToJSON(tx, hashBlock, objTx); + TxToJSON(*tx, hashBlock, objTx); std::string strJSON = objTx.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 771929487d..aef17cf438 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -11,6 +11,7 @@ #include "checkpoints.h" #include "coins.h" #include "hash.h" +#include "instantsend.h" #include "policy/policy.h" #include "rpcserver.h" #include "streams.h" @@ -29,6 +30,19 @@ #include // boost::thread::interrupt +#include +#include + +struct CUpdatedBlock +{ + uint256 hash; + int height; +}; + +static std::mutex cs_blockchange; +static std::condition_variable cond_blockchange; +static CUpdatedBlock latestblock; + extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); @@ -104,16 +118,16 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); UniValue txs(UniValue::VARR); - BOOST_FOREACH(const CTransaction&tx, block.vtx) + for(const auto& tx : block.vtx) { if(txDetails) { UniValue objTx(UniValue::VOBJ); - TxToJSON(tx, uint256(), objTx); + TxToJSON(*tx, uint256(), objTx); txs.push_back(objTx); } else - txs.push_back(tx.GetHash().GetHex()); + txs.push_back(tx->GetHash().GetHex()); } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); @@ -165,6 +179,138 @@ UniValue getbestblockhash(const JSONRPCRequest& request) return chainActive.Tip()->GetBlockHash().GetHex(); } +void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex) +{ + if(pindex) { + std::lock_guard lock(cs_blockchange); + latestblock.hash = pindex->GetBlockHash(); + latestblock.height = pindex->nHeight; + } + cond_blockchange.notify_all(); +} + +UniValue waitfornewblock(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() > 1) + throw std::runtime_error( + "waitfornewblock (timeout)\n" + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" + "\nResult:\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("waitfornewblock", "1000") + + HelpExampleRpc("waitfornewblock", "1000") + ); + int timeout = 0; + if (request.params.size() > 0) + timeout = request.params[0].get_int(); + + CUpdatedBlock block; + { + std::unique_lock lock(cs_blockchange); + block = latestblock; + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); + else + cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); + block = latestblock; + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + +UniValue waitforblock(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) + throw std::runtime_error( + "waitforblock (timeout)\n" + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. \"blockhash\" (required, string) Block hash to wait for.\n" + "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" + "\nResult:\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + ); + int timeout = 0; + + uint256 hash = uint256S(request.params[0].get_str()); + + if (request.params.size() > 1) + timeout = request.params[1].get_int(); + + CUpdatedBlock block; + { + std::unique_lock lock(cs_blockchange); + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();}); + else + cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); }); + block = latestblock; + } + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + +UniValue waitforblockheight(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) + throw std::runtime_error( + "waitforblockheight (timeout)\n" + "\nWaits for (at least) block height and returns the height and hash\n" + "of the current tip.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. height (required, int) Block height to wait for (int)\n" + "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" + "\nResult:\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("waitforblockheight", "\"100\", 1000") + + HelpExampleRpc("waitforblockheight", "\"100\", 1000") + ); + int timeout = 0; + + int height = request.params[0].get_int(); + + if (request.params.size() > 1) + timeout = request.params[1].get_int(); + + CUpdatedBlock block; + { + std::unique_lock lock(cs_blockchange); + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();}); + else + cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); }); + block = latestblock; + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + UniValue getdifficulty(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) @@ -236,8 +382,11 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) } info.push_back(Pair("depends", depends)); + info.push_back(Pair("instantsend", instantsend.HasTxLockRequest(tx.GetHash()))); + info.push_back(Pair("instantlock", instantsend.IsLockedInstantSendTransaction(tx.GetHash()))); } + UniValue mempoolToJSON(bool fVerbose = false) { if (fVerbose) @@ -801,6 +950,55 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats) return true; } +UniValue pruneblockchain(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) + throw std::runtime_error( + "pruneblockchain\n" + "\nArguments:\n" + "1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp\n" + " to prune blocks whose block time is at least 2 hours older than the provided timestamp.\n" + "\nResult:\n" + "n (numeric) Height of the last block pruned.\n" + "\nExamples:\n" + + HelpExampleCli("pruneblockchain", "1000") + + HelpExampleRpc("pruneblockchain", "1000")); + + if (!fPruneMode) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Cannot prune blocks because node is not in prune mode."); + + LOCK(cs_main); + + int heightParam = request.params[0].get_int(); + if (heightParam < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height."); + + // Height value more than a billion is too high to be a block height, and + // too low to be a block time (corresponds to timestamp from Sep 2001). + if (heightParam > 1000000000) { + // Add a 2 hour buffer to include blocks which might have had old timestamps + CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - 7200); + if (!pindex) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp."); + } + heightParam = pindex->nHeight; + } + + unsigned int height = (unsigned int) heightParam; + unsigned int chainHeight = (unsigned int) chainActive.Height(); + if (chainHeight < Params().PruneAfterHeight()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Blockchain is too short for pruning."); + else if (height > chainHeight) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height."); + else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { + LogPrint("rpc", "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks."); + height = chainHeight - MIN_BLOCKS_TO_KEEP; + } + + PruneBlockFilesManual(height); + return uint64_t(height); +} + UniValue gettxoutsetinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) @@ -1045,7 +1243,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast())); - obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); + obj.push_back(Pair("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); @@ -1138,6 +1336,7 @@ UniValue getchaintips(const JSONRPCRequest& request) std::set setTips; std::set setOrphans; std::set setPrevs; + BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex) { if (!chainActive.Contains(item.second)) { @@ -1248,12 +1447,12 @@ UniValue preciousblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "preciousblock \"hash\"\n" + "preciousblock \"blockhash\"\n" "\nTreats a block as if it were received before others with the same work.\n" "\nA later preciousblock call can override the effect of an earlier one.\n" "\nThe effects of preciousblock are not retained across restarts.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to mark as precious\n" + "1. \"blockhash\" (string, required) the hash of the block to mark as precious\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("preciousblock", "\"blockhash\"") @@ -1286,10 +1485,10 @@ UniValue invalidateblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "invalidateblock \"hash\"\n" + "invalidateblock \"blockhash\"\n" "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to mark as invalid\n" + "1. \"blockhash\" (string, required) the hash of the block to mark as invalid\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("invalidateblock", "\"blockhash\"") @@ -1306,11 +1505,11 @@ UniValue invalidateblock(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlockIndex* pblockindex = mapBlockIndex[hash]; - InvalidateBlock(state, Params().GetConsensus(), pblockindex); + InvalidateBlock(state, Params(), pblockindex); } if (state.IsValid()) { - ActivateBestChain(state, Params(), NULL); + ActivateBestChain(state, Params()); } if (!state.IsValid()) { @@ -1324,11 +1523,11 @@ UniValue reconsiderblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "reconsiderblock \"hash\"\n" + "reconsiderblock \"blockhash\"\n" "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n" "This can be used to undo the effects of invalidateblock.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to reconsider\n" + "1. \"blockhash\" (string, required) the hash of the block to reconsider\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("reconsiderblock", "\"blockhash\"") @@ -1337,7 +1536,6 @@ UniValue reconsiderblock(const JSONRPCRequest& request) std::string strHash = request.params[0].get_str(); uint256 hash(uint256S(strHash)); - CValidationState state; { LOCK(cs_main); @@ -1345,12 +1543,11 @@ UniValue reconsiderblock(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlockIndex* pblockindex = mapBlockIndex[hash]; - ReconsiderBlock(state, pblockindex); + ResetBlockFailureFlags(pblockindex); } - if (state.IsValid()) { - ActivateBestChain(state, Params(), NULL); - } + CValidationState state; + ActivateBestChain(state, Params()); if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); @@ -1360,35 +1557,41 @@ UniValue reconsiderblock(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode - // --------------------- ------------------------ ----------------------- ---------- - { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, - { "blockchain", "getbestblockhash", &getbestblockhash, true }, - { "blockchain", "getblockcount", &getblockcount, true }, - { "blockchain", "getblock", &getblock, true }, - { "blockchain", "getblockhashes", &getblockhashes, true }, - { "blockchain", "getblockhash", &getblockhash, true }, - { "blockchain", "getblockheader", &getblockheader, true }, - { "blockchain", "getblockheaders", &getblockheaders, true }, - { "blockchain", "getchaintips", &getchaintips, true }, - { "blockchain", "getdifficulty", &getdifficulty, true }, - { "blockchain", "getmempoolancestors", &getmempoolancestors, true }, - { "blockchain", "getmempooldescendants", &getmempooldescendants, true }, - { "blockchain", "getmempoolentry", &getmempoolentry, true }, - { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, - { "blockchain", "getrawmempool", &getrawmempool, true }, - { "blockchain", "gettxout", &gettxout, true }, - { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true }, - { "blockchain", "verifychain", &verifychain, true }, - { "blockchain", "preciousblock", &preciousblock, true }, +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ --- + { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} }, + { "blockchain", "getbestblockhash", &getbestblockhash, true, {} }, + { "blockchain", "getblockcount", &getblockcount, true, {} }, + { "blockchain", "getblock", &getblock, true, {"blockhash","verbose"} }, + { "blockchain", "getblockhashes", &getblockhashes, true, {"high","low"} }, + { "blockchain", "getblockhash", &getblockhash, true, {"height"} }, + { "blockchain", "getblockheader", &getblockheader, true, {"blockhash","verbose"} }, + { "blockchain", "getblockheaders", &getblockheaders, true, {"blockhash","count","verbose"} }, + { "blockchain", "getchaintips", &getchaintips, true, {"count","branchlen"} }, + { "blockchain", "getdifficulty", &getdifficulty, true, {} }, + { "blockchain", "getmempoolancestors", &getmempoolancestors, true, {"txid","verbose"} }, + { "blockchain", "getmempooldescendants", &getmempooldescendants, true, {"txid","verbose"} }, + { "blockchain", "getmempoolentry", &getmempoolentry, true, {"txid"} }, + { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} }, + { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} }, + { "blockchain", "gettxout", &gettxout, true, {"txid","n","includemempool"} }, + { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} }, + { "blockchain", "pruneblockchain", &pruneblockchain, true, {"height"} }, + { "blockchain", "verifychain", &verifychain, true, {"checklevel","nblocks"} }, + + { "blockchain", "preciousblock", &preciousblock, true, {"blockhash"} }, /* Not shown in help */ - { "hidden", "invalidateblock", &invalidateblock, true }, - { "hidden", "reconsiderblock", &reconsiderblock, true }, + { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} }, + { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} }, + { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} }, + { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} }, + { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} }, }; -void RegisterBlockchainRPCCommands(CRPCTable &tableRPC) + +void RegisterBlockchainRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 7627c52f32..c4c3fab40d 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -22,132 +22,137 @@ class CRPCConvertParam public: std::string methodName; //! method whose params want conversion int paramIdx; //! 0-based idx of param to convert + std::string paramName; //!< parameter name }; static const CRPCConvertParam vRPCConvertParams[] = { - { "stop", 0 }, - { "setmocktime", 0 }, - { "setgenerate", 0 }, - { "setgenerate", 1 }, - { "setgenerate", 2 }, - { "generate", 0 }, - { "generate", 1 }, - { "generatetoaddress", 0 }, - { "generatetoaddress", 2 }, - { "getnetworkhashps", 0 }, - { "getnetworkhashps", 1 }, - { "sendtoaddress", 1 }, - { "sendtoaddress", 4 }, - { "sendtoaddress", 5 }, - { "sendtoaddress", 6 }, - { "instantsendtoaddress", 1 }, - { "instantsendtoaddress", 4 }, - { "settxfee", 0 }, - { "getreceivedbyaddress", 1 }, - { "getreceivedbyaddress", 2 }, - { "getreceivedbyaccount", 1 }, - { "getreceivedbyaccount", 2 }, - { "listreceivedbyaddress", 0 }, - { "listreceivedbyaddress", 1 }, - { "listreceivedbyaddress", 2 }, - { "listreceivedbyaddress", 3 }, - { "listreceivedbyaccount", 0 }, - { "listreceivedbyaccount", 1 }, - { "listreceivedbyaccount", 2 }, - { "listreceivedbyaccount", 3 }, - { "getbalance", 1 }, - { "getbalance", 2 }, - { "getbalance", 3 }, - { "getchaintips", 0 }, - { "getchaintips", 1 }, - { "getblockhash", 0 }, - { "getsuperblockbudget", 0 }, - { "move", 2 }, - { "move", 3 }, - { "sendfrom", 2 }, - { "sendfrom", 3 }, - { "sendfrom", 4 }, - { "listtransactions", 1 }, - { "listtransactions", 2 }, - { "listtransactions", 3 }, - { "listaccounts", 0 }, - { "listaccounts", 1 }, - { "listaccounts", 2 }, - { "walletpassphrase", 1 }, - { "walletpassphrase", 2 }, - { "getblocktemplate", 0 }, - { "listsinceblock", 1 }, - { "listsinceblock", 2 }, - { "sendmany", 1 }, - { "sendmany", 2 }, - { "sendmany", 3 }, - { "sendmany", 4 }, - { "sendmany", 5 }, - { "sendmany", 6 }, - { "sendmany", 7 }, - { "addmultisigaddress", 0 }, - { "addmultisigaddress", 1 }, - { "createmultisig", 0 }, - { "createmultisig", 1 }, - { "listunspent", 0 }, - { "listunspent", 1 }, - { "listunspent", 2 }, - { "getblock", 1 }, - { "getblockheader", 1 }, - { "getblockheaders", 1 }, - { "getblockheaders", 2 }, - { "gettransaction", 1 }, - { "getrawtransaction", 1 }, - { "createrawtransaction", 0 }, - { "createrawtransaction", 1 }, - { "createrawtransaction", 2 }, - { "signrawtransaction", 1 }, - { "signrawtransaction", 2 }, - { "sendrawtransaction", 1 }, - { "fundrawtransaction", 1 }, - { "gettxout", 1 }, - { "gettxout", 2 }, - { "gettxoutproof", 0 }, - { "lockunspent", 0 }, - { "lockunspent", 1 }, - { "importprivkey", 2 }, - { "importaddress", 2 }, - { "importaddress", 3 }, - { "importpubkey", 2 }, - { "importmulti", 0 }, - { "importmulti", 1 }, - { "verifychain", 0 }, - { "verifychain", 1 }, - { "keypoolrefill", 0 }, - { "getrawmempool", 0 }, - { "estimatefee", 0 }, - { "estimatepriority", 0 }, - { "estimatesmartfee", 0 }, - { "estimatesmartpriority", 0 }, - { "prioritisetransaction", 1 }, - { "prioritisetransaction", 2 }, - { "setban", 2 }, - { "setban", 3 }, - { "getmempoolancestors", 1 }, - { "getmempooldescendants", 1 }, - { "setnetworkactive", 0 }, - { "spork", 1 }, - { "voteraw", 1 }, - { "voteraw", 5 }, - { "getblockhashes", 0 }, - { "getblockhashes", 1 }, - { "getspentinfo", 0}, - { "getaddresstxids", 0}, - { "getaddressbalance", 0}, - { "getaddressdeltas", 0}, - { "getaddressutxos", 0}, - { "getaddressmempool", 0}, + { "setmocktime", 0, "timestamp" }, + { "setgenerate", 0, "generate" }, + { "setgenerate", 1, "genproclimit" }, + { "setgenerate", 2, "genproclimit-gpu" }, + { "generate", 0, "nblocks" }, + { "generate", 1, "maxtries" }, + { "generatetoaddress", 0, "nblocks" }, + { "generatetoaddress", 2, "maxtries" }, + { "getnetworkhashps", 0, "nblocks" }, + { "getnetworkhashps", 1, "height" }, + { "sendtoaddress", 1, "amount" }, + { "sendtoaddress", 4, "subtractfeefromamount" }, + { "sendtoaddress", 5, "use_is" }, + { "sendtoaddress", 6, "use_ps" }, + { "instantsendtoaddress", 1, "address" }, + { "instantsendtoaddress", 4, "comment_to" }, + { "settxfee", 0, "amount" }, + { "getreceivedbyaddress", 1, "minconf" }, + { "getreceivedbyaddress", 2, "addlockconf" }, + { "getreceivedbyaccount", 1, "minconf" }, + { "getreceivedbyaccount", 2, "addlockconf" }, + { "listreceivedbyaddress", 0, "minconf" }, + { "listreceivedbyaddress", 1, "addlockconf" }, + { "listreceivedbyaddress", 2, "include_empty" }, + { "listreceivedbyaddress", 3, "include_watchonly" }, + { "listreceivedbyaccount", 0, "minconf" }, + { "listreceivedbyaccount", 1, "addlockconf" }, + { "listreceivedbyaccount", 2, "include_empty" }, + { "listreceivedbyaccount", 3, "include_watchonly" }, + { "getbalance", 1, "minconf" }, + { "getbalance", 2, "addlockconf" }, + { "getbalance", 3, "include_watchonly" }, + { "getchaintips", 0, "count" }, + { "getchaintips", 1, "branchlen" }, + { "getblockhash", 0, "height" }, + { "getsuperblockbudget", 0, "index" }, + { "move", 2, "amount" }, + { "move", 3, "minconf" }, + { "sendfrom", 2, "amount" }, + { "sendfrom", 3, "minconf" }, + { "sendfrom", 4, "addlockconf" }, + { "listtransactions", 1, "count" }, + { "listtransactions", 2, "skip" }, + { "listtransactions", 3, "include_watchonly" }, + { "listaccounts", 0, "minconf" }, + { "listaccounts", 1, "addlockconf" }, + { "listaccounts", 2, "include_watchonly" }, + { "walletpassphrase", 1, "timeout" }, + { "walletpassphrase", 2, "mixingonly" }, + { "getblocktemplate", 0, "template_request" }, + { "listsinceblock", 1, "target_confirmations" }, + { "listsinceblock", 2, "include_watchonly" }, + { "sendmany", 1, "amounts" }, + { "sendmany", 2, "minconf" }, + { "sendmany", 3, "addlockconf" }, + { "sendmany", 5, "subtractfeefromamount" }, + { "sendmany", 6, "use_is" }, + { "sendmany", 7, "use_ps" }, + { "addmultisigaddress", 0, "nrequired" }, + { "addmultisigaddress", 1, "keys" }, + { "createmultisig", 0, "nrequired" }, + { "createmultisig", 1, "keys" }, + { "listunspent", 0, "minconf" }, + { "listunspent", 1, "maxconf" }, + { "listunspent", 2, "addresses" }, + { "listunspent", 3, "include_unsafe" }, + { "getblock", 1, "verbose" }, + { "getblockheader", 1, "verbose" }, + { "getblockheaders", 1, "count" }, + { "getblockheaders", 2, "verbose" }, + { "gettransaction", 1, "include_watchonly" }, + { "getrawtransaction", 1, "verbose" }, + { "createrawtransaction", 0, "inputs" }, + { "createrawtransaction", 1, "outputs" }, + { "createrawtransaction", 2, "locktime" }, + { "signrawtransaction", 1, "prevtxs" }, + { "signrawtransaction", 2, "privkeys" }, + { "sendrawtransaction", 1, "allowhighfees" }, + { "sendrawtransaction", 2, "instantsend" }, + { "sendrawtransaction", 3, "bypasslimits" }, + { "fundrawtransaction", 1, "options" }, + { "gettxout", 1, "n" }, + { "gettxout", 2, "include_mempool" }, + { "gettxoutproof", 0, "txids" }, + { "lockunspent", 0, "unlock" }, + { "lockunspent", 1, "transactions" }, + { "importprivkey", 2, "rescan" }, + { "importelectrumwallet", 1, "index" }, + { "importaddress", 2, "rescan" }, + { "importaddress", 3, "p2sh" }, + { "importpubkey", 2, "rescan" }, + { "importmulti", 0, "requests" }, + { "importmulti", 1, "options" }, + { "verifychain", 0, "checklevel" }, + { "verifychain", 1, "nblocks" }, + { "pruneblockchain", 0, "height" }, + { "keypoolrefill", 0, "newsize" }, + { "getrawmempool", 0, "verbose" }, + { "estimatefee", 0, "nblocks" }, + { "estimatepriority", 0, "nblocks" }, + { "estimatesmartfee", 0, "nblocks" }, + { "estimatesmartpriority", 0, "nblocks" }, + { "prioritisetransaction", 1, "priority_delta" }, + { "prioritisetransaction", 2, "fee_delta" }, + { "setban", 2, "bantime" }, + { "setban", 3, "absolute" }, + { "getmempoolancestors", 1, "verbose" }, + { "getmempooldescendants", 1, "verbose" }, + { "setnetworkactive", 0, "state" }, + { "spork", 1, "value" }, + { "voteraw", 1, "tx_index" }, + { "voteraw", 5, "time" }, + { "getblockhashes", 0, "high"}, + { "getblockhashes", 1, "low" }, + { "getspentinfo", 0, "json" }, + { "getaddresstxids", 0, "addresses" }, + { "getaddressbalance", 0, "addresses" }, + { "getaddressdeltas", 0, "addresses" }, + { "getaddressutxos", 0, "addresses" }, + { "getaddressmempool", 0, "addresses" }, }; class CRPCConvertTable { private: - std::set > members; + std::set> members; + std::set> membersByName; public: CRPCConvertTable(); @@ -155,6 +160,9 @@ class CRPCConvertTable bool convert(const std::string& method, int idx) { return (members.count(std::make_pair(method, idx)) > 0); } + bool convert(const std::string& method, const std::string& name) { + return (membersByName.count(std::make_pair(method, name)) > 0); + } }; CRPCConvertTable::CRPCConvertTable() @@ -165,6 +173,8 @@ CRPCConvertTable::CRPCConvertTable() for (unsigned int i = 0; i < n_elem; i++) { members.insert(std::make_pair(vRPCConvertParams[i].methodName, vRPCConvertParams[i].paramIdx)); + membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName, + vRPCConvertParams[i].paramName)); } } @@ -202,3 +212,27 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) +{ + UniValue params(UniValue::VOBJ); + + for (const std::string &s: strParams) { + size_t pos = s.find("="); + if (pos == std::string::npos) { + throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)")); + } + + std::string name = s.substr(0, pos); + std::string value = s.substr(pos+1); + + if (!rpcCvtTable.convert(strMethod, name)) { + // insert string value directly + params.pushKV(name, value); + } else { + // parse string as JSON, insert bool/number/object/etc. value + params.pushKV(name, ParseNonRFCJSONValue(value)); + } + } + + return params; +} diff --git a/src/rpcclient.h b/src/rpcclient.h index 324fe9ecfc..eb3aa19254 100644 --- a/src/rpcclient.h +++ b/src/rpcclient.h @@ -11,6 +11,13 @@ #include UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) + * as well as objects and arrays. + */ + +/** Convert named arguments to command-specific RPC representation */ +UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector& strParams); + /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) * as well as objects and arrays. */ diff --git a/src/rpcdynode.cpp b/src/rpcdynode.cpp index 65e24e924f..be06e941df 100644 --- a/src/rpcdynode.cpp +++ b/src/rpcdynode.cpp @@ -27,11 +27,16 @@ UniValue dynodelist(const JSONRPCRequest& request); +bool EnsureWalletIsAvailable(bool avoidException); + #ifdef ENABLE_WALLET void EnsureWalletIsUnlocked(); UniValue privatesend(const JSONRPCRequest& request) { + if (!EnsureWalletIsAvailable(request.fHelp)) + return NullUniValue; + if (request.fHelp || request.params.size() != 1) throw std::runtime_error( "privatesend \"command\"\n" @@ -43,6 +48,9 @@ UniValue privatesend(const JSONRPCRequest& request) " reset - Reset mixing\n" ); + if(fDynodeMode) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on dynodes"); + if(request.params[0].get_str() == "start") { { LOCK(pwalletMain->cs_wallet); @@ -50,9 +58,6 @@ UniValue privatesend(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first."); } - if(fDynodeMode) - return "Mixing is not supported from Dynodes"; - privateSendClient.fEnablePrivateSend = true; bool result = privateSendClient.DoAutomaticDenominating(*g_connman); return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClient.GetStatus() + ", will retry")); @@ -91,7 +96,7 @@ UniValue getpoolinfo(const JSONRPCRequest& request) dynode_info_t dnInfo; if (privateSendClient.GetMixingDynodeInfo(dnInfo)) { - obj.push_back(Pair("outpoint", dnInfo.vin.prevout.ToStringShort())); + obj.push_back(Pair("outpoint", dnInfo.outpoint.ToStringShort())); obj.push_back(Pair("addr", dnInfo.addr.ToString())); } @@ -177,8 +182,8 @@ UniValue dynode(const JSONRPCRequest& request) throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Incorrect dynode address %s", strAddress)); // TODO: Pass CConnman instance somehow and don't use global variable. - CNode *pnode = g_connman->ConnectNode(CAddress(addr, NODE_NETWORK), NULL); - if(!pnode) + g_connman->OpenDynodeConnection(CAddress(addr, NODE_NETWORK)); + if (!g_connman->IsConnected(CAddress(addr, NODE_NETWORK), CConnman::AllNodes)) throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Couldn't connect to dynode %s", strAddress)); return "successfully connected"; @@ -234,7 +239,7 @@ UniValue dynode(const JSONRPCRequest& request) obj.push_back(Pair("height", nHeight)); obj.push_back(Pair("IP:port", dnInfo.addr.ToString())); obj.push_back(Pair("protocol", (int64_t)dnInfo.nProtocolVersion)); - obj.push_back(Pair("outpoint", dnInfo.vin.prevout.ToStringShort())); + obj.push_back(Pair("outpoint", dnInfo.outpoint.ToStringShort())); obj.push_back(Pair("payee", CDynamicAddress(dnInfo.pubKeyCollateralAddress.GetID()).ToString())); obj.push_back(Pair("lastseen", dnInfo.nTimeLastPing)); obj.push_back(Pair("activeseconds", dnInfo.nTimeLastPing - dnInfo.sigTime)); @@ -257,6 +262,9 @@ UniValue dynode(const JSONRPCRequest& request) if (strCommand == "start-alias") { + if (!EnsureWalletIsAvailable(request.fHelp)) + return NullUniValue; + if (request.params.size() < 2) throw JSONRPCError(RPC_INVALID_PARAMETER, "Please specify an alias"); @@ -272,7 +280,7 @@ UniValue dynode(const JSONRPCRequest& request) UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", strAlias)); - BOOST_FOREACH(CDynodeConfig::CDynodeEntry dne, dynodeConfig.getEntries()) { + for (const auto& dne : dynodeConfig.getEntries()) { if(dne.getAlias() == strAlias) { fFound = true; std::string strError; @@ -280,13 +288,16 @@ UniValue dynode(const JSONRPCRequest& request) bool fResult = CDynodeBroadcast::Create(dne.getIp(), dne.getPrivKey(), dne.getTxHash(), dne.getOutputIndex(), strError, dnb); + int nDoS; + if (fResult && !dnodeman.CheckDnbAndUpdateDynodeList(NULL, dnb, nDoS, *g_connman)) { + strError = "Failed to verify DNB"; + fResult = false; + } + statusObj.push_back(Pair("result", fResult ? "successful" : "failed")); if(fResult) { - dnodeman.UpdateDynodeList(dnb, *g_connman); - dnb.Relay(*g_connman); - } else { statusObj.push_back(Pair("errorMessage", strError)); - } + } dnodeman.NotifyDynodeUpdates(*g_connman); break; } @@ -303,6 +314,9 @@ UniValue dynode(const JSONRPCRequest& request) if (strCommand == "start-all" || strCommand == "start-missing" || strCommand == "start-disabled") { + if (!EnsureWalletIsAvailable(request.fHelp)) + return NullUniValue; + { LOCK(pwalletMain->cs_wallet); EnsureWalletIsUnlocked(); @@ -317,7 +331,7 @@ UniValue dynode(const JSONRPCRequest& request) UniValue resultsObj(UniValue::VOBJ); - BOOST_FOREACH(CDynodeConfig::CDynodeEntry dne, dynodeConfig.getEntries()) { + for (const auto& dne : dynodeConfig.getEntries()) { std::string strError; COutPoint outpoint = COutPoint(uint256S(dne.getTxHash()), uint32_t(atoi(dne.getOutputIndex().c_str()))); @@ -330,14 +344,18 @@ UniValue dynode(const JSONRPCRequest& request) bool fResult = CDynodeBroadcast::Create(dne.getIp(), dne.getPrivKey(), dne.getTxHash(), dne.getOutputIndex(), strError, dnb); + int nDoS; + if (fResult && !dnodeman.CheckDnbAndUpdateDynodeList(NULL, dnb, nDoS, *g_connman)) { + strError = "Failed to verify DNB"; + fResult = false; + } + UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", dne.getAlias())); statusObj.push_back(Pair("result", fResult ? "successful" : "failed")); if (fResult) { nSuccessful++; - dnodeman.UpdateDynodeList(dnb, *g_connman); - dnb.Relay(*g_connman); } else { nFailed++; statusObj.push_back(Pair("errorMessage", strError)); @@ -367,7 +385,7 @@ UniValue dynode(const JSONRPCRequest& request) { UniValue resultObj(UniValue::VOBJ); - BOOST_FOREACH(CDynodeConfig::CDynodeEntry dne, dynodeConfig.getEntries()) { + for (const auto& dne : dynodeConfig.getEntries()) { COutPoint outpoint = COutPoint(uint256S(dne.getTxHash()), uint32_t(atoi(dne.getOutputIndex().c_str()))); CDynode dn; bool fFound = dnodeman.Get(outpoint, dn); @@ -389,12 +407,15 @@ UniValue dynode(const JSONRPCRequest& request) #ifdef ENABLE_WALLET if (strCommand == "outputs") { + if (!EnsureWalletIsAvailable(request.fHelp)) + return NullUniValue; + // Find possible candidates std::vector vPossibleCoins; pwalletMain->AvailableCoins(vPossibleCoins, true, NULL, false, ONLY_1000); UniValue obj(UniValue::VOBJ); - BOOST_FOREACH(COutput& out, vPossibleCoins) { + for (const auto& out : vPossibleCoins) { obj.push_back(Pair(out.tx->GetHash().ToString(), strprintf("%d", out.i))); } @@ -515,10 +536,10 @@ UniValue dynodelist(const JSONRPCRequest& request) if (strMode == "rank") { CDynodeMan::rank_pair_vec_t vDynodeRanks; dnodeman.GetDynodeRanks(vDynodeRanks); - BOOST_FOREACH(PAIRTYPE(int, CDynode)& s, vDynodeRanks) { - std::string strOutpoint = s.second.vin.prevout.ToStringShort(); + for (const auto& rankpair : vDynodeRanks) { + std::string strOutpoint = rankpair.second.outpoint.ToStringShort(); if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, s.first)); + obj.push_back(Pair(strOutpoint, rankpair.first)); } } else { std::map mapDynodes = dnodeman.GetFullDynodeMap(); @@ -642,6 +663,9 @@ UniValue dynodebroadcast(const JSONRPCRequest& request) #ifdef ENABLE_WALLET if (strCommand == "create-alias") { + if (!EnsureWalletIsAvailable(request.fHelp)) + return NullUniValue; + // wait for reindex and/or import to finish if (fImporting || fReindex) throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish"); @@ -662,7 +686,7 @@ UniValue dynodebroadcast(const JSONRPCRequest& request) statusObj.push_back(Pair("alias", strAlias)); - BOOST_FOREACH(CDynodeConfig::CDynodeEntry dne, dynodeConfig.getEntries()) { + for (const auto& dne : dynodeConfig.getEntries()) { if(dne.getAlias() == strAlias) { fFound = true; std::string strError; @@ -694,6 +718,9 @@ UniValue dynodebroadcast(const JSONRPCRequest& request) if (strCommand == "create-all") { + if (!EnsureWalletIsAvailable(request.fHelp)) + return NullUniValue; + // wait for reindex and/or import to finish if (fImporting || fReindex) throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish"); @@ -759,12 +786,12 @@ UniValue dynodebroadcast(const JSONRPCRequest& request) int nDos = 0; UniValue returnObj(UniValue::VOBJ); - BOOST_FOREACH(CDynodeBroadcast& dnb, vecDnb) { + for (const auto& dnb : vecDnb) { UniValue resultObj(UniValue::VOBJ); if(dnb.CheckSignature(nDos)) { nSuccessful++; - resultObj.push_back(Pair("outpoint", dnb.vin.prevout.ToStringShort())); + resultObj.push_back(Pair("outpoint", dnb.outpoint.ToStringShort())); resultObj.push_back(Pair("addr", dnb.addr.ToString())); resultObj.push_back(Pair("pubKeyCollateralAddress", CDynamicAddress(dnb.pubKeyCollateralAddress.GetID()).ToString())); resultObj.push_back(Pair("pubKeyDynode", CDynamicAddress(dnb.pubKeyDynode.GetID()).ToString())); @@ -774,7 +801,7 @@ UniValue dynodebroadcast(const JSONRPCRequest& request) resultObj.push_back(Pair("nLastPsq", dnb.nLastPsq)); UniValue lastPingObj(UniValue::VOBJ); - lastPingObj.push_back(Pair("outpoint", dnb.lastPing.vin.prevout.ToStringShort())); + lastPingObj.push_back(Pair("outpoint", dnb.lastPing.dynodeOutpoint.ToStringShort())); lastPingObj.push_back(Pair("blockHash", dnb.lastPing.blockHash.ToString())); lastPingObj.push_back(Pair("sigTime", dnb.lastPing.sigTime)); lastPingObj.push_back(Pair("vchSig", EncodeBase64(&dnb.lastPing.vchSig[0], dnb.lastPing.vchSig.size()))); @@ -798,8 +825,7 @@ UniValue dynodebroadcast(const JSONRPCRequest& request) if (request.params.size() < 2 || request.params.size() > 3) throw JSONRPCError(RPC_INVALID_PARAMETER, "dynodebroadcast relay \"hexstring\" ( fast )\n" "\nArguments:\n" - "1. \"hex\" (string, required) Broadcast messages hex string\n" - "2. fast (string, optional) If none, using safe method\n"); + "1. \"hex\" (string, required) Broadcast messages hex string\n"); std::vector vecDnb; @@ -808,26 +834,19 @@ UniValue dynodebroadcast(const JSONRPCRequest& request) int nSuccessful = 0; int nFailed = 0; - bool fSafe = request.params.size() == 2; UniValue returnObj(UniValue::VOBJ); // verify all signatures first, bailout if any of them broken - BOOST_FOREACH(CDynodeBroadcast& dnb, vecDnb) { + for (const auto& dnb : vecDnb) { UniValue resultObj(UniValue::VOBJ); - resultObj.push_back(Pair("outpoint", dnb.vin.prevout.ToStringShort())); + resultObj.push_back(Pair("outpoint", dnb.outpoint.ToStringShort())); resultObj.push_back(Pair("addr", dnb.addr.ToString())); int nDos = 0; bool fResult; if (dnb.CheckSignature(nDos)) { - if (fSafe) { - fResult = dnodeman.CheckDnbAndUpdateDynodeList(NULL, dnb, nDos, *g_connman); - } else { - dnodeman.UpdateDynodeList(dnb, *g_connman); - dnb.Relay(*g_connman); - fResult = true; - } + fResult = dnodeman.CheckDnbAndUpdateDynodeList(NULL, dnb, nDos, *g_connman); dnodeman.NotifyDynodeUpdates(*g_connman); } else fResult = false; @@ -871,20 +890,22 @@ UniValue sentinelping(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode +{ // category name actor (function) okSafe argNames + // --------------------- ---------------------- ------------------- ------ ---- /* Dynamic features */ - { "dynamic", "dynode", &dynode, true }, - { "dynamic", "dynodelist", &dynodelist, true }, - { "dynamic", "dynodebroadcast", &dynodebroadcast, true }, - { "dynamic", "getpoolinfo", &getpoolinfo, true }, - { "dynamic", "sentinelping", &sentinelping, true }, + { "dynamic", "dynode", &dynode, true, {} }, + { "dynamic", "dynodelist", &dynodelist, true, {} }, + { "dynamic", "dynodebroadcast", &dynodebroadcast, true, {} }, + { "dynamic", "getpoolinfo", &getpoolinfo, true, {} }, + { "dynamic", "sentinelping", &sentinelping, true, {} }, #ifdef ENABLE_WALLET - { "dynamic", "privatesend", &privatesend, false }, + { "dynamic", "privatesend", &privatesend, false, {} }, #endif // ENABLE_WALLET }; -void RegisterDynodeRPCCommands(CRPCTable &tableRPC) +void RegisterDynodeRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } + diff --git a/src/rpcgovernance.cpp b/src/rpcgovernance.cpp index e982f86398..7821fd5278 100644 --- a/src/rpcgovernance.cpp +++ b/src/rpcgovernance.cpp @@ -25,7 +25,7 @@ #include "wallet/wallet.h" #endif // ENABLE_WALLET -#include +bool EnsureWalletIsAvailable(bool avoidException); UniValue gobject(const JSONRPCRequest& request) { @@ -51,7 +51,7 @@ UniValue gobject(const JSONRPCRequest& request) #endif // ENABLE_WALLET " submit - Submit governance object to network\n" " deserialize - Deserialize governance object from hex string to JSON\n" - " count - Count governance objects and votes\n" + " count - Count governance objects and votes (additional param: 'json' or 'all', default: 'json')\n" " get - Get governance object by hash\n" " getvotes - Get all votes for a governance object hash (including old votes)\n" " getcurrentvotes - Get only current (tallying) votes for a governance object hash (does not include old votes)\n" @@ -63,8 +63,19 @@ UniValue gobject(const JSONRPCRequest& request) ); - if(strCommand == "count") - return governance.ToString(); + if(strCommand == "count") { + std::string strMode{"json"}; + + if (request.params.size() == 2) { + strMode = request.params[1].get_str(); + } + + if (request.params.size() > 2 || (strMode != "json" && strMode != "all")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'gobject count ( \"json\"|\"all\" )'"); + } + + return strMode == "json" ? governance.ToJson() : governance.ToString(); + } /* ------ Example Governance Item ------ @@ -103,12 +114,12 @@ UniValue gobject(const JSONRPCRequest& request) int nRevision = 1; int64_t nTime = GetAdjustedTime(); - std::string strData = request.params[1].get_str(); + std::string strDataHex = request.params[1].get_str(); - CGovernanceObject govobj(hashParent, nRevision, nTime, uint256(), strData); + CGovernanceObject govobj(hashParent, nRevision, nTime, uint256(), strDataHex); if(govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { - CProposalValidator validator(strData); + CProposalValidator validator(strDataHex); if(!validator.Validate()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages()); } @@ -128,6 +139,9 @@ UniValue gobject(const JSONRPCRequest& request) // PREPARE THE GOVERNANCE OBJECT BY CREATING A COLLATERAL TRANSACTION if(strCommand == "prepare") { + if (!EnsureWalletIsAvailable(request.fHelp)) + return NullUniValue; + if (request.params.size() != 5) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'gobject prepare