mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 11:32:46 +01:00
Merged in Darksend/InstantX/Masternodes
This doesn't include any of the changes in the darkcoin/v0.10.18.x branch. Those will be brought over into this commit history.
This commit is contained in:
parent
601457c2fe
commit
78c5ca53f6
23
.gitignore
vendored
23
.gitignore
vendored
@ -1,11 +1,11 @@
|
||||
*.tar.gz
|
||||
|
||||
*.exe
|
||||
src/bitcoin
|
||||
src/bitcoind
|
||||
src/bitcoin-cli
|
||||
src/test/test_bitcoin
|
||||
src/qt/test/test_bitcoin-qt
|
||||
src/darkcoin
|
||||
src/darkcoind
|
||||
src/darkcoin-cli
|
||||
src/test/test_darkcoin
|
||||
src/qt/test/test_darkcoin-qt
|
||||
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
@ -36,7 +36,7 @@ src/qt/test/moc*.cpp
|
||||
*.o
|
||||
*.o-*
|
||||
*.patch
|
||||
.bitcoin
|
||||
.darkcoin
|
||||
*.a
|
||||
*.pb.cc
|
||||
*.pb.h
|
||||
@ -51,12 +51,12 @@ src/qt/test/moc*.cpp
|
||||
# Compilation and Qt preprocessor part
|
||||
*.qm
|
||||
Makefile
|
||||
bitcoin-qt
|
||||
Bitcoin-Qt.app
|
||||
darkcoin-qt
|
||||
Darkcoin-Qt.app
|
||||
|
||||
# Unit-tests
|
||||
Makefile.test
|
||||
bitcoin-qt_test
|
||||
darkcoin-qt_test
|
||||
|
||||
# Resources cpp
|
||||
qrc_*.cpp
|
||||
@ -71,7 +71,7 @@ build
|
||||
#lcov
|
||||
*.gcno
|
||||
/*.info
|
||||
test_bitcoin.coverage/
|
||||
test_darkcoin.coverage/
|
||||
total.coverage/
|
||||
coverage_percent.txt
|
||||
|
||||
@ -83,3 +83,6 @@ qa/pull-tester/run-bitcoind-for-test.sh
|
||||
qa/pull-tester/build-tests.sh
|
||||
|
||||
!src/leveldb*/Makefile
|
||||
|
||||
.cproject
|
||||
.project
|
@ -4,9 +4,9 @@ SUBDIRS = src
|
||||
|
||||
GZIP_ENV="-9n"
|
||||
|
||||
BITCOIND_BIN=$(top_builddir)/src/bitcoind$(EXEEXT)
|
||||
BITCOIN_QT_BIN=$(top_builddir)/src/qt/bitcoin-qt$(EXEEXT)
|
||||
BITCOIN_CLI_BIN=$(top_builddir)/src/bitcoin-cli$(EXEEXT)
|
||||
BITCOIND_BIN=$(top_builddir)/src/darkcoind$(EXEEXT)
|
||||
BITCOIN_QT_BIN=$(top_builddir)/src/qt/darkcoin-qt$(EXEEXT)
|
||||
BITCOIN_CLI_BIN=$(top_builddir)/src/darkcoin-cli$(EXEEXT)
|
||||
BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT)
|
||||
|
||||
OSX_APP=Bitcoin-Qt.app
|
||||
|
22
TODO.md
22
TODO.md
@ -28,16 +28,22 @@ DONE:
|
||||
MANDATORY:
|
||||
----------
|
||||
|
||||
- Add masternode payment checks a.k.a. enforcement (based on blockheight)
|
||||
- Fix mining protocol to include correct pow and masternodes
|
||||
- Check rpcminer (should be working though)
|
||||
|
||||
|
||||
OPTIONAL:
|
||||
---------
|
||||
BUGS:
|
||||
-----
|
||||
|
||||
- Include Evan's public key for msg signing
|
||||
- Darksend, Instant Transactions, Atomic Transfers, etc. pp.
|
||||
- Include centralized checkpoint syncing (peercoin style)
|
||||
- Remove Bitcoin dead weight (SHA256, hardcoded keys, nodes)
|
||||
- Daemon and CLI tool can't connect to testnet/regtest instances (wrong port?)
|
||||
- Daemon and CLI tool can't authenticate via RPC (uh-oh?)
|
||||
- Qt wallet can't find the config file in testnet mode (wrong path?)
|
||||
|
||||
|
||||
ADDITIONAL:
|
||||
-----------
|
||||
|
||||
- Include trusted public key for message signing
|
||||
- Masternodes, Enforcement, Darksend, InstantX, Atomic Transfers, ...
|
||||
- Remove Bitcoin dead weight (SHA256, hardcoded keys, seednodes, ...)
|
||||
- Update strings
|
||||
- Write tests
|
||||
|
12
configure.ac
12
configure.ac
@ -1,12 +1,12 @@
|
||||
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
||||
AC_PREREQ([2.60])
|
||||
define(_CLIENT_VERSION_MAJOR, 0)
|
||||
define(_CLIENT_VERSION_MINOR, 9)
|
||||
define(_CLIENT_VERSION_REVISION, 3)
|
||||
define(_CLIENT_VERSION_MINOR, 11)
|
||||
define(_CLIENT_VERSION_REVISION, 0)
|
||||
define(_CLIENT_VERSION_BUILD, 0)
|
||||
define(_CLIENT_VERSION_IS_RELEASE, true)
|
||||
define(_COPYRIGHT_YEAR, 2014)
|
||||
AC_INIT([Bitcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@bitcoin.org],[bitcoin])
|
||||
define(_COPYRIGHT_YEAR, 2015)
|
||||
AC_INIT([Darkcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@darkcoin.io],[darkcoin])
|
||||
AC_CONFIG_AUX_DIR([src/build-aux])
|
||||
AC_CONFIG_MACRO_DIR([src/m4])
|
||||
AC_CANONICAL_HOST
|
||||
@ -660,7 +660,7 @@ if test x$bitcoin_enable_qt != xno; then
|
||||
AC_MSG_WARN("xgettext is required to update qt translations")
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to build test_bitcoin-qt])
|
||||
AC_MSG_CHECKING([whether to build test_darkcoin-qt])
|
||||
if test x$use_tests$bitcoin_enable_qt_test = xyesyes; then
|
||||
AC_MSG_RESULT([yes])
|
||||
BUILD_TEST_QT="test"
|
||||
@ -669,7 +669,7 @@ if test x$bitcoin_enable_qt != xno; then
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to build test_bitcoin])
|
||||
AC_MSG_CHECKING([whether to build test_darkcoin])
|
||||
if test x$use_tests = xyes; then
|
||||
AC_MSG_RESULT([yes])
|
||||
BUILD_TEST="test"
|
||||
|
@ -3,28 +3,29 @@ include Makefile.include
|
||||
AM_CPPFLAGS += -I$(builddir)
|
||||
|
||||
noinst_LIBRARIES = \
|
||||
libbitcoin_server.a \
|
||||
libbitcoin_common.a \
|
||||
libbitcoin_cli.a
|
||||
libdarkcoin_server.a \
|
||||
libdarkcoin_common.a \
|
||||
libdarkcoin_cli.a
|
||||
if ENABLE_WALLET
|
||||
noinst_LIBRARIES += libbitcoin_wallet.a
|
||||
noinst_LIBRARIES += libdarkcoin_wallet.a
|
||||
endif
|
||||
|
||||
bin_PROGRAMS =
|
||||
|
||||
if BUILD_BITCOIND
|
||||
bin_PROGRAMS += bitcoind
|
||||
bin_PROGRAMS += darkcoind
|
||||
endif
|
||||
|
||||
if BUILD_BITCOIN_CLI
|
||||
bin_PROGRAMS += bitcoin-cli
|
||||
bin_PROGRAMS += darkcoin-cli
|
||||
endif
|
||||
|
||||
SUBDIRS = . $(BUILD_QT) $(BUILD_TEST)
|
||||
DIST_SUBDIRS = . qt test
|
||||
.PHONY: FORCE
|
||||
# bitcoin core #
|
||||
# darkcoin core #
|
||||
BITCOIN_CORE_H = \
|
||||
activemasternode.h \
|
||||
addrman.h \
|
||||
alert.h \
|
||||
allocators.h \
|
||||
@ -39,14 +40,17 @@ BITCOIN_CORE_H = \
|
||||
compat.h \
|
||||
core.h \
|
||||
crypter.h \
|
||||
darksend.h \
|
||||
db.h \
|
||||
hash.h \
|
||||
init.h \
|
||||
instantx.h \
|
||||
key.h \
|
||||
keystore.h \
|
||||
leveldbwrapper.h \
|
||||
limitedmap.h \
|
||||
main.h \
|
||||
masternode.h \
|
||||
miner.h \
|
||||
mruset.h \
|
||||
netbase.h \
|
||||
@ -99,7 +103,8 @@ obj/build.h: FORCE
|
||||
$(abs_top_srcdir)
|
||||
version.o: obj/build.h
|
||||
|
||||
libbitcoin_server_a_SOURCES = \
|
||||
libdarkcoin_server_a_SOURCES = \
|
||||
activemasternode.cpp \
|
||||
addrman.cpp \
|
||||
alert.cpp \
|
||||
bloom.cpp \
|
||||
@ -113,6 +118,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
net.cpp \
|
||||
noui.cpp \
|
||||
rpcblockchain.cpp \
|
||||
rpcdarksend.cpp \
|
||||
rpcmining.cpp \
|
||||
rpcmisc.cpp \
|
||||
rpcnet.cpp \
|
||||
@ -123,7 +129,8 @@ libbitcoin_server_a_SOURCES = \
|
||||
$(JSON_H) \
|
||||
$(BITCOIN_CORE_H)
|
||||
|
||||
libbitcoin_wallet_a_SOURCES = \
|
||||
libdarkcoin_wallet_a_SOURCES = \
|
||||
activemasternode.cpp \
|
||||
db.cpp \
|
||||
crypter.cpp \
|
||||
rpcdump.cpp \
|
||||
@ -132,11 +139,15 @@ libbitcoin_wallet_a_SOURCES = \
|
||||
walletdb.cpp \
|
||||
$(BITCOIN_CORE_H)
|
||||
|
||||
libbitcoin_common_a_SOURCES = \
|
||||
libdarkcoin_common_a_SOURCES = \
|
||||
activemasternode.cpp \
|
||||
base58.cpp \
|
||||
allocators.cpp \
|
||||
chainparams.cpp \
|
||||
core.cpp \
|
||||
darksend.cpp \
|
||||
masternode.cpp \
|
||||
instantx.cpp \
|
||||
hash.cpp \
|
||||
key.cpp \
|
||||
netbase.cpp \
|
||||
@ -161,47 +172,47 @@ libbitcoin_common_a_SOURCES = \
|
||||
$(BITCOIN_CORE_H)
|
||||
|
||||
if GLIBC_BACK_COMPAT
|
||||
libbitcoin_common_a_SOURCES += compat/glibc_compat.cpp
|
||||
libbitcoin_common_a_SOURCES += compat/glibcxx_compat.cpp
|
||||
libdarkcoin_common_a_SOURCES += compat/glibc_compat.cpp
|
||||
libdarkcoin_common_a_SOURCES += compat/glibcxx_compat.cpp
|
||||
endif
|
||||
|
||||
libbitcoin_cli_a_SOURCES = \
|
||||
libdarkcoin_cli_a_SOURCES = \
|
||||
rpcclient.cpp \
|
||||
$(BITCOIN_CORE_H)
|
||||
|
||||
nodist_libbitcoin_common_a_SOURCES = $(top_srcdir)/src/obj/build.h
|
||||
nodist_libdarkcoin_common_a_SOURCES = $(top_srcdir)/src/obj/build.h
|
||||
#
|
||||
|
||||
# bitcoind binary #
|
||||
bitcoind_LDADD = \
|
||||
libbitcoin_server.a \
|
||||
libbitcoin_cli.a \
|
||||
libbitcoin_common.a \
|
||||
# darkcoind binary #
|
||||
darkcoind_LDADD = \
|
||||
libdarkcoin_server.a \
|
||||
libdarkcoin_cli.a \
|
||||
libdarkcoin_common.a \
|
||||
$(LIBLEVELDB) \
|
||||
$(LIBMEMENV)
|
||||
if ENABLE_WALLET
|
||||
bitcoind_LDADD += libbitcoin_wallet.a
|
||||
darkcoind_LDADD += libdarkcoin_wallet.a
|
||||
endif
|
||||
bitcoind_SOURCES = bitcoind.cpp
|
||||
darkcoind_SOURCES = darkcoind.cpp
|
||||
#
|
||||
|
||||
if TARGET_WINDOWS
|
||||
bitcoind_SOURCES += bitcoind-res.rc
|
||||
darkcoind_SOURCES += bitcoind-res.rc
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS += $(BDB_CPPFLAGS)
|
||||
bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS)
|
||||
darkcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS)
|
||||
|
||||
# bitcoin-cli binary #
|
||||
bitcoin_cli_LDADD = \
|
||||
libbitcoin_cli.a \
|
||||
libbitcoin_common.a \
|
||||
# darkcoin-cli binary #
|
||||
darkcoin_cli_LDADD = \
|
||||
libdarkcoin_cli.a \
|
||||
libdarkcoin_common.a \
|
||||
$(BOOST_LIBS)
|
||||
bitcoin_cli_SOURCES = bitcoin-cli.cpp
|
||||
darkcoin_cli_SOURCES = darkcoin-cli.cpp
|
||||
#
|
||||
|
||||
if TARGET_WINDOWS
|
||||
bitcoin_cli_SOURCES += bitcoin-cli-res.rc
|
||||
darkcoin_cli_SOURCES += bitcoin-cli-res.rc
|
||||
endif
|
||||
|
||||
# NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race
|
||||
@ -212,7 +223,7 @@ leveldb/%.a:
|
||||
CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \
|
||||
OPT="$(CXXFLAGS) $(CPPFLAGS)"
|
||||
|
||||
qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_cli_a_SOURCES)
|
||||
qt/bitcoinstrings.cpp: $(libdarkcoin_server_a_SOURCES) $(libdarkcoin_common_a_SOURCES) $(libdarkcoin_cli_a_SOURCES)
|
||||
@test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
|
||||
@cd $(top_srcdir); XGETTEXT=$(XGETTEXT) share/qt/extract_strings_qt.py
|
||||
|
||||
|
@ -12,11 +12,11 @@ AM_CPPFLAGS = $(INCLUDES) \
|
||||
AM_CPPFLAGS += $(LEVELDB_CPPFLAGS)
|
||||
AM_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
|
||||
LIBBITCOIN_SERVER=$(top_builddir)/src/libbitcoin_server.a
|
||||
LIBBITCOIN_WALLET=$(top_builddir)/src/libbitcoin_wallet.a
|
||||
LIBBITCOIN_COMMON=$(top_builddir)/src/libbitcoin_common.a
|
||||
LIBBITCOIN_CLI=$(top_builddir)/src/libbitcoin_cli.a
|
||||
LIBBITCOINQT=$(top_builddir)/src/qt/libbitcoinqt.a
|
||||
LIBBITCOIN_SERVER=$(top_builddir)/src/libdarkcoin_server.a
|
||||
LIBBITCOIN_WALLET=$(top_builddir)/src/libdarkcoin_wallet.a
|
||||
LIBBITCOIN_COMMON=$(top_builddir)/src/libdarkcoin_common.a
|
||||
LIBBITCOIN_CLI=$(top_builddir)/src/libdarkcoin_cli.a
|
||||
LIBBITCOINQT=$(top_builddir)/src/qt/libdarkcoinqt.a
|
||||
|
||||
$(LIBBITCOIN):
|
||||
$(MAKE) -C $(top_builddir)/src $(@F)
|
||||
|
320
src/activemasternode.cpp
Normal file
320
src/activemasternode.cpp
Normal file
@ -0,0 +1,320 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "protocol.h"
|
||||
#include "activemasternode.h"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
//
|
||||
// Bootup the masternode, look for a 1000DRK input and register on the network
|
||||
//
|
||||
void CActiveMasternode::RegisterAsMasterNode(bool stop)
|
||||
{
|
||||
if(!fMasterNode) return;
|
||||
|
||||
//need correct adjusted time to send ping
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
if(fIsInitialDownload) {
|
||||
isCapableMasterNode = MASTERNODE_SYNC_IN_PROCESS;
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sync in progress. Must wait until sync is complete to start masternode.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string errorMessage;
|
||||
|
||||
CKey key2;
|
||||
CPubKey pubkey2;
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2))
|
||||
{
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(isCapableMasterNode == MASTERNODE_INPUT_TOO_NEW || isCapableMasterNode == MASTERNODE_NOT_CAPABLE || isCapableMasterNode == MASTERNODE_SYNC_IN_PROCESS){
|
||||
isCapableMasterNode = MASTERNODE_NOT_PROCESSED;
|
||||
}
|
||||
|
||||
if(isCapableMasterNode == MASTERNODE_NOT_PROCESSED) {
|
||||
if(strMasterNodeAddr.empty()) {
|
||||
if(!GetLocal(masterNodeSignAddr)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Can't detect external address. Please use the masternodeaddr configuration option.\n");
|
||||
isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
masterNodeSignAddr = CService(strMasterNodeAddr);
|
||||
}
|
||||
|
||||
if((Params().NetworkID() == CChainParams::TESTNET && masterNodeSignAddr.GetPort() != 19999) || (!(Params().NetworkID() == CChainParams::TESTNET) && masterNodeSignAddr.GetPort() != 9999)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Invalid port\n");
|
||||
isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Checking inbound connection to '%s'\n", masterNodeSignAddr.ToString().c_str());
|
||||
|
||||
if(ConnectNode((CAddress)masterNodeSignAddr, masterNodeSignAddr.ToString().c_str())){
|
||||
masternodePortOpen = MASTERNODE_PORT_OPEN;
|
||||
} else {
|
||||
masternodePortOpen = MASTERNODE_PORT_NOT_OPEN;
|
||||
isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Port not open.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(pwalletMain->IsLocked()){
|
||||
isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Not capable.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
isCapableMasterNode = MASTERNODE_NOT_CAPABLE;
|
||||
|
||||
CKey SecretKey;
|
||||
// Choose coins to use
|
||||
if(GetMasterNodeVin(vinMasternode, pubkeyMasterNode, SecretKey)) {
|
||||
|
||||
if(GetInputAge(vinMasternode) < MASTERNODE_MIN_CONFIRMATIONS){
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Input must have least %d confirmations - %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS, GetInputAge(vinMasternode));
|
||||
isCapableMasterNode = MASTERNODE_INPUT_TOO_NEW;
|
||||
return;
|
||||
}
|
||||
|
||||
int protocolVersion = PROTOCOL_VERSION;
|
||||
|
||||
masterNodeSignatureTime = GetAdjustedTime();
|
||||
|
||||
std::string vchPubKey(pubkeyMasterNode.begin(), pubkeyMasterNode.end());
|
||||
std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
|
||||
std::string strMessage = masterNodeSignAddr.ToString() + boost::lexical_cast<std::string>(masterNodeSignatureTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(protocolVersion);
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, SecretKey)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sign message failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkeyMasterNode, vchMasterNodeSignature, strMessage, errorMessage)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Verify message failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Is capable master node!\n");
|
||||
|
||||
isCapableMasterNode = MASTERNODE_IS_CAPABLE;
|
||||
|
||||
pwalletMain->LockCoin(vinMasternode.prevout);
|
||||
|
||||
bool found = false;
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes)
|
||||
if(mn.vin == vinMasternode)
|
||||
found = true;
|
||||
|
||||
if(!found) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Adding myself to masternode list %s - %s\n", masterNodeSignAddr.ToString().c_str(), vinMasternode.ToString().c_str());
|
||||
CMasterNode mn(masterNodeSignAddr, vinMasternode, pubkeyMasterNode, vchMasterNodeSignature, masterNodeSignatureTime, pubkey2, PROTOCOL_VERSION);
|
||||
mn.UpdateLastSeen(masterNodeSignatureTime);
|
||||
darkSendMasterNodes.push_back(mn);
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Masternode input = %s\n", vinMasternode.ToString().c_str());
|
||||
}
|
||||
|
||||
//relay to all
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
pnode->PushMessage("dsee", vinMasternode, masterNodeSignAddr, vchMasterNodeSignature, masterNodeSignatureTime, pubkeyMasterNode, pubkey2, -1, -1, masterNodeSignatureTime, protocolVersion);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(isCapableMasterNode != MASTERNODE_IS_CAPABLE && isCapableMasterNode != MASTERNODE_REMOTELY_ENABLED) return;
|
||||
|
||||
masterNodeSignatureTime = GetAdjustedTime();
|
||||
|
||||
std::string strMessage = masterNodeSignAddr.ToString() + boost::lexical_cast<std::string>(masterNodeSignatureTime) + boost::lexical_cast<std::string>(stop);
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, key2)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sign message failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Verify message failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {
|
||||
//LogPrintf(" -- %s\n", mn.vin.ToString().c_str());
|
||||
|
||||
if(mn.vin == vinMasternode) {
|
||||
found = true;
|
||||
mn.UpdateLastSeen();
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Darksend Masternode List doesn't include our masternode, Shutting down masternode pinging service! %s\n", vinMasternode.ToString().c_str());
|
||||
isCapableMasterNode = MASTERNODE_STOPPED;
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Masternode input = %s\n", vinMasternode.ToString().c_str());
|
||||
|
||||
if (stop) isCapableMasterNode = MASTERNODE_STOPPED;
|
||||
|
||||
//relay to all peers
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
pnode->PushMessage("dseep", vinMasternode, vchMasterNodeSignature, masterNodeSignatureTime, stop);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Bootup the masternode, look for a 1000DRK input and register on the network
|
||||
// Takes 2 parameters to start a remote masternode
|
||||
//
|
||||
bool CActiveMasternode::RegisterAsMasterNodeRemoteOnly(std::string strMasterNodeAddr, std::string strMasterNodePrivKey)
|
||||
{
|
||||
if(!fMasterNode) return false;
|
||||
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Address %s MasterNodePrivKey %s\n", strMasterNodeAddr.c_str(), strMasterNodePrivKey.c_str());
|
||||
|
||||
std::string errorMessage;
|
||||
|
||||
CKey key2;
|
||||
CPubKey pubkey2;
|
||||
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2))
|
||||
{
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
CService masterNodeSignAddr = CService(strMasterNodeAddr);
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes){
|
||||
if(mn.addr == masterNodeSignAddr){
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Address in use\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if((Params().NetworkID() == CChainParams::TESTNET && masterNodeSignAddr.GetPort() != 19999) || (!(Params().NetworkID() == CChainParams::TESTNET) && masterNodeSignAddr.GetPort() != 9999)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Invalid port\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Checking inbound connection to '%s'\n", masterNodeSignAddr.ToString().c_str());
|
||||
|
||||
if(!ConnectNode((CAddress)masterNodeSignAddr, masterNodeSignAddr.ToString().c_str())){
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Error connecting to port\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pwalletMain->IsLocked()){
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Wallet is locked\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CKey SecretKey;
|
||||
CTxIn vinMasternode;
|
||||
CPubKey pubkeyMasterNode;
|
||||
int masterNodeSignatureTime = 0;
|
||||
|
||||
// Choose coins to use
|
||||
while (GetMasterNodeVin(vinMasternode, pubkeyMasterNode, SecretKey)) {
|
||||
// don't use a vin that's registered
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes)
|
||||
if(mn.vin == vinMasternode)
|
||||
continue;
|
||||
|
||||
if(GetInputAge(vinMasternode) < MASTERNODE_MIN_CONFIRMATIONS)
|
||||
continue;
|
||||
|
||||
masterNodeSignatureTime = GetAdjustedTime();
|
||||
|
||||
std::string vchPubKey(pubkeyMasterNode.begin(), pubkeyMasterNode.end());
|
||||
std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
|
||||
std::string strMessage = masterNodeSignAddr.ToString() + boost::lexical_cast<std::string>(masterNodeSignatureTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(PROTOCOL_VERSION);
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, SecretKey)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Sign message failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkeyMasterNode, vchMasterNodeSignature, strMessage, errorMessage)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Verify message failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Is capable master node!\n");
|
||||
|
||||
pwalletMain->LockCoin(vinMasternode.prevout);
|
||||
|
||||
int protocolVersion = PROTOCOL_VERSION;
|
||||
//relay to all
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
pnode->PushMessage("dsee", vinMasternode, masterNodeSignAddr, vchMasterNodeSignature, masterNodeSignatureTime, pubkeyMasterNode, pubkey2, -1, -1, masterNodeSignatureTime, protocolVersion);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - No sutable vin found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey)
|
||||
{
|
||||
int64_t nValueIn = 0;
|
||||
CScript pubScript;
|
||||
|
||||
// try once before we try to denominate
|
||||
if (!pwalletMain->SelectCoinsMasternode(vin, nValueIn, pubScript))
|
||||
{
|
||||
if(fDebug) LogPrintf("CActiveMasternode::GetMasterNodeVin - I'm not a capable masternode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pubScript, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
CKeyID keyID;
|
||||
if (!address2.GetKeyID(keyID)) {
|
||||
LogPrintf("CActiveMasternode::GetMasterNodeVin - Address does not refer to a key\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pwalletMain->GetKey(keyID, secretKey)) {
|
||||
LogPrintf ("CActiveMasternode::GetMasterNodeVin - Private key for address is not known\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pubkey = secretKey.GetPubKey();
|
||||
return true;
|
||||
}
|
||||
|
||||
// when starting a masternode, this can enable to run as a hot wallet with no funds
|
||||
bool CActiveMasternode::EnableHotColdMasterNode(CTxIn& vin, int64_t sigTime, CService& addr)
|
||||
{
|
||||
if(!fMasterNode) return false;
|
||||
|
||||
isCapableMasterNode = MASTERNODE_REMOTELY_ENABLED;
|
||||
|
||||
vinMasternode = vin;
|
||||
masterNodeSignatureTime = sigTime;
|
||||
masterNodeSignAddr = addr;
|
||||
|
||||
LogPrintf("CActiveMasternode::EnableHotColdMasterNode() - Enabled! You may shut down the cold daemon.\n");
|
||||
|
||||
return true;
|
||||
}
|
54
src/activemasternode.h
Normal file
54
src/activemasternode.h
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef ACTIVEMASTERNODE_H
|
||||
#define ACTIVEMASTERNODE_H
|
||||
|
||||
#include "bignum.h"
|
||||
#include "sync.h"
|
||||
#include "net.h"
|
||||
#include "key.h"
|
||||
#include "core.h"
|
||||
#include "init.h"
|
||||
#include "wallet.h"
|
||||
#include "darksend.h"
|
||||
|
||||
// Responsible for activating the masternode and pinging the network
|
||||
class CActiveMasternode
|
||||
{
|
||||
public:
|
||||
CTxIn vinMasternode;
|
||||
CPubKey pubkeyMasterNode;
|
||||
CPubKey pubkeyMasterNode2;
|
||||
|
||||
std::string strMasterNodeSignMessage;
|
||||
std::vector<unsigned char> vchMasterNodeSignature;
|
||||
|
||||
std::string masterNodeAddr;
|
||||
CService masterNodeSignAddr;
|
||||
|
||||
int isCapableMasterNode;
|
||||
int64_t masterNodeSignatureTime;
|
||||
int masternodePortOpen;
|
||||
|
||||
CActiveMasternode()
|
||||
{
|
||||
isCapableMasterNode = MASTERNODE_NOT_PROCESSED;
|
||||
masternodePortOpen = 0;
|
||||
}
|
||||
|
||||
// get 1000DRK input that can be used for the masternode
|
||||
bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey);
|
||||
|
||||
// start the masternode and register with the network
|
||||
void RegisterAsMasterNode(bool stop);
|
||||
// start a remote masternode
|
||||
bool RegisterAsMasterNodeRemoteOnly(std::string strMasterNodeAddr, std::string strMasterNodePrivKey);
|
||||
|
||||
// enable hot wallet mode (run a masternode with no funds)
|
||||
bool EnableHotColdMasterNode(CTxIn& vin, int64_t sigTime, CService& addr);
|
||||
};
|
||||
|
||||
#endif
|
@ -92,7 +92,7 @@ public:
|
||||
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
|
||||
};
|
||||
|
||||
/** base58-encoded Bitcoin addresses.
|
||||
/** base58-encoded Darkcoin addresses.
|
||||
* Public-key-hash-addresses have version 0 (or 111 testnet).
|
||||
* The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
|
||||
* Script-hash-addresses have version 5 (or 196 testnet).
|
||||
|
@ -136,7 +136,7 @@ public:
|
||||
|
||||
if (sn < (int64_t)0)
|
||||
{
|
||||
// Since the minimum signed integer cannot be represented as positive so long as its type is signed,
|
||||
// Since the minimum signed integer cannot be represented as positive so long as its type is signed,
|
||||
// and it's not well-defined what happens if you make it unsigned before negating it,
|
||||
// we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate
|
||||
n = -(sn + 1);
|
||||
@ -284,7 +284,7 @@ public:
|
||||
// and 0xc0de000000 is compact (0x0600c0de)
|
||||
// (0x05c0de00) would be -0x40de000000
|
||||
//
|
||||
// Bitcoin only uses this "compact" format for encoding difficulty
|
||||
// Darkcoin only uses this "compact" format for encoding difficulty
|
||||
// targets, which are unsigned 256bit quantities. Thus, all the
|
||||
// complexities of the sign bit and using base 256 are probably an
|
||||
// implementation accident.
|
||||
|
@ -67,7 +67,7 @@ public:
|
||||
|
||||
base58Prefixes[PUBKEY_ADDRESS] = list_of(76); // Darkcoin addresses start with X
|
||||
base58Prefixes[SCRIPT_ADDRESS] = list_of(5);
|
||||
base58Prefixes[SECRET_KEY] = list_of(128);
|
||||
base58Prefixes[SECRET_KEY] = list_of(204);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = list_of(0x04)(0x88)(0xB2)(0x1E);
|
||||
base58Prefixes[EXT_SECRET_KEY] = list_of(0x04)(0x88)(0xAD)(0xE4);
|
||||
|
||||
|
@ -26,7 +26,7 @@ struct CDNSSeedData {
|
||||
|
||||
/**
|
||||
* CChainParams defines various tweakable parameters of a given instance of the
|
||||
* Bitcoin system. There are three: the main network on which people trade goods
|
||||
* Darkcoin system. There are three: the main network on which people trade goods
|
||||
* and services, the public test network which gets reset from time to time and
|
||||
* a regression test mode which is intended for private networks only. It has
|
||||
* minimal difficulty to ensure that blocks can be found instantly.
|
||||
|
@ -334,7 +334,7 @@ public:
|
||||
// Calculate the size of the cache (in number of transactions)
|
||||
unsigned int GetCacheSize();
|
||||
|
||||
/** Amount of bitcoins coming in to a transaction
|
||||
/** Amount of darkcoins coming in to a transaction
|
||||
Note that lightweight clients may not know anything besides the hash of previous transactions,
|
||||
so may not be able to calculate this.
|
||||
|
||||
|
26
src/core.h
26
src/core.h
@ -12,6 +12,30 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define START_MASTERNODE_PAYMENTS_TESTNET 1403568776 //Tue, 24 Jun 2014 00:12:56 GMT
|
||||
#define START_MASTERNODE_PAYMENTS 1403728576 //Wed, 25 Jun 2014 20:36:16 GMT
|
||||
|
||||
static const int64_t DARKSEND_COLLATERAL = (0.1*COIN);
|
||||
static const int64_t DARKSEND_FEE = (0.0125*COIN);
|
||||
static const int64_t DARKSEND_POOL_MAX = (999.99*COIN);
|
||||
|
||||
#define MASTERNODE_NOT_PROCESSED 0 // initial state
|
||||
#define MASTERNODE_IS_CAPABLE 1
|
||||
#define MASTERNODE_NOT_CAPABLE 2
|
||||
#define MASTERNODE_STOPPED 3
|
||||
#define MASTERNODE_INPUT_TOO_NEW 4
|
||||
#define MASTERNODE_PORT_NOT_OPEN 6
|
||||
#define MASTERNODE_PORT_OPEN 7
|
||||
#define MASTERNODE_SYNC_IN_PROCESS 8
|
||||
#define MASTERNODE_REMOTELY_ENABLED 9
|
||||
|
||||
#define MASTERNODE_MIN_CONFIRMATIONS 15
|
||||
#define MASTERNODE_MIN_DSEEP_SECONDS (30*60)
|
||||
#define MASTERNODE_MIN_DSEE_SECONDS (5*60)
|
||||
#define MASTERNODE_PING_SECONDS (1*60)
|
||||
#define MASTERNODE_EXPIRATION_SECONDS (65*60)
|
||||
#define MASTERNODE_REMOVAL_SECONDS (70*60)
|
||||
|
||||
class CTransaction;
|
||||
|
||||
/** No amount larger than this (in satoshi) is valid */
|
||||
@ -72,6 +96,7 @@ class CTxIn
|
||||
public:
|
||||
COutPoint prevout;
|
||||
CScript scriptSig;
|
||||
CScript prevPubKey;
|
||||
unsigned int nSequence;
|
||||
|
||||
CTxIn()
|
||||
@ -400,6 +425,7 @@ public:
|
||||
std::vector<CTransaction> vtx;
|
||||
|
||||
// memory only
|
||||
mutable CScript payee;
|
||||
mutable std::vector<uint256> vMerkleTree;
|
||||
|
||||
CBlock()
|
||||
|
2183
src/darksend.cpp
Normal file
2183
src/darksend.cpp
Normal file
File diff suppressed because it is too large
Load Diff
433
src/darksend.h
Normal file
433
src/darksend.h
Normal file
@ -0,0 +1,433 @@
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef DARKSEND_H
|
||||
#define DARKSEND_H
|
||||
|
||||
#include "core.h"
|
||||
#include "masternode.h"
|
||||
#include "main.h"
|
||||
#include "activemasternode.h"
|
||||
|
||||
class CTxIn;
|
||||
class CDarkSendPool;
|
||||
class CDarkSendSigner;
|
||||
class CMasterNodeVote;
|
||||
class CBitcoinAddress;
|
||||
class CDarksendQueue;
|
||||
class CDarksendBroadcastTx;
|
||||
class CActiveMasternode;
|
||||
|
||||
#define POOL_MAX_TRANSACTIONS 3 // wait for X transactions to merge and publish
|
||||
#define POOL_STATUS_UNKNOWN 0 // waiting for update
|
||||
#define POOL_STATUS_IDLE 1 // waiting for update
|
||||
#define POOL_STATUS_QUEUE 2 // waiting in a queue
|
||||
#define POOL_STATUS_ACCEPTING_ENTRIES 3 // accepting entries
|
||||
#define POOL_STATUS_FINALIZE_TRANSACTION 4 // master node will broadcast what it accepted
|
||||
#define POOL_STATUS_SIGNING 5 // check inputs/outputs, sign final tx
|
||||
#define POOL_STATUS_TRANSMISSION 6 // transmit transaction
|
||||
#define POOL_STATUS_ERROR 7 // error
|
||||
#define POOL_STATUS_SUCCESS 8 // success
|
||||
|
||||
// status update message constants
|
||||
#define MASTERNODE_ACCEPTED 1
|
||||
#define MASTERNODE_REJECTED 0
|
||||
#define MASTERNODE_RESET -1
|
||||
|
||||
#define DARKSEND_QUEUE_TIMEOUT 120
|
||||
#define DARKSEND_SIGNING_TIMEOUT 30
|
||||
|
||||
extern CDarkSendPool darkSendPool;
|
||||
extern CDarkSendSigner darkSendSigner;
|
||||
extern std::vector<CDarksendQueue> vecDarksendQueue;
|
||||
extern std::string strMasterNodePrivKey;
|
||||
extern map<uint256, CDarksendBroadcastTx> mapDarksendBroadcastTxes;
|
||||
extern CActiveMasternode activeMasternode;
|
||||
|
||||
//specific messages for the Darksend protocol
|
||||
void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
|
||||
// get the darksend chain depth for a given input
|
||||
int GetInputDarksendRounds(CTxIn in, int rounds=0);
|
||||
|
||||
|
||||
// An input in the darksend pool
|
||||
class CDarkSendEntryVin
|
||||
{
|
||||
public:
|
||||
bool isSigSet;
|
||||
CTxIn vin;
|
||||
|
||||
CDarkSendEntryVin()
|
||||
{
|
||||
isSigSet = false;
|
||||
vin = CTxIn();
|
||||
}
|
||||
};
|
||||
|
||||
// A clients transaction in the darksend pool
|
||||
class CDarkSendEntry
|
||||
{
|
||||
public:
|
||||
bool isSet;
|
||||
std::vector<CDarkSendEntryVin> sev;
|
||||
int64_t amount;
|
||||
CTransaction collateral;
|
||||
std::vector<CTxOut> vout;
|
||||
CTransaction txSupporting;
|
||||
int64_t addedTime;
|
||||
|
||||
CDarkSendEntry()
|
||||
{
|
||||
isSet = false;
|
||||
collateral = CTransaction();
|
||||
amount = 0;
|
||||
}
|
||||
|
||||
bool Add(const std::vector<CTxIn> vinIn, int64_t amountIn, const CTransaction collateralIn, const std::vector<CTxOut> voutIn)
|
||||
{
|
||||
if(isSet){return false;}
|
||||
|
||||
BOOST_FOREACH(const CTxIn v, vinIn) {
|
||||
CDarkSendEntryVin s = CDarkSendEntryVin();
|
||||
s.vin = v;
|
||||
sev.push_back(s);
|
||||
}
|
||||
vout = voutIn;
|
||||
amount = amountIn;
|
||||
collateral = collateralIn;
|
||||
isSet = true;
|
||||
addedTime = GetTime();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddSig(const CTxIn& vin)
|
||||
{
|
||||
BOOST_FOREACH(CDarkSendEntryVin& s, sev) {
|
||||
if(s.vin.prevout == vin.prevout && s.vin.nSequence == vin.nSequence){
|
||||
if(s.isSigSet){return false;}
|
||||
s.vin.scriptSig = vin.scriptSig;
|
||||
s.vin.prevPubKey = vin.prevPubKey;
|
||||
s.isSigSet = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsExpired()
|
||||
{
|
||||
return (GetTime() - addedTime) > DARKSEND_QUEUE_TIMEOUT;// 120 seconds
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// A currently inprogress darksend merge and denomination information
|
||||
//
|
||||
class CDarksendQueue
|
||||
{
|
||||
public:
|
||||
CTxIn vin;
|
||||
int64_t time;
|
||||
int nDenom;
|
||||
bool ready; //ready for submit
|
||||
std::vector<unsigned char> vchSig;
|
||||
|
||||
CDarksendQueue()
|
||||
{
|
||||
nDenom = 0;
|
||||
vin = CTxIn();
|
||||
time = 0;
|
||||
vchSig.clear();
|
||||
ready = false;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
READWRITE(nDenom);
|
||||
READWRITE(vin);
|
||||
READWRITE(time);
|
||||
READWRITE(ready);
|
||||
READWRITE(vchSig);
|
||||
)
|
||||
|
||||
bool GetAddress(CService &addr)
|
||||
{
|
||||
BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
|
||||
if(mn.vin == vin){
|
||||
addr = mn.addr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetProtocolVersion(int &protocolVersion)
|
||||
{
|
||||
BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
|
||||
if(mn.vin == vin){
|
||||
protocolVersion = mn.protocolVersion;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Sign();
|
||||
bool Relay();
|
||||
|
||||
bool IsExpired()
|
||||
{
|
||||
return (GetTime() - time) > DARKSEND_QUEUE_TIMEOUT;// 120 seconds
|
||||
}
|
||||
|
||||
bool CheckSignature();
|
||||
|
||||
};
|
||||
|
||||
// store darksend tx signature information
|
||||
class CDarksendBroadcastTx
|
||||
{
|
||||
public:
|
||||
CTransaction tx;
|
||||
CTxIn vin;
|
||||
vector<unsigned char> vchSig;
|
||||
int64_t sigTime;
|
||||
};
|
||||
|
||||
//
|
||||
// Helper object for signing and checking signatures
|
||||
//
|
||||
class CDarkSendSigner
|
||||
{
|
||||
public:
|
||||
bool IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey);
|
||||
bool SetKey(std::string strSecret, std::string& errorMessage, CKey& key, CPubKey& pubkey);
|
||||
bool SignMessage(std::string strMessage, std::string& errorMessage, std::vector<unsigned char>& vchSig, CKey key);
|
||||
bool VerifyMessage(CPubKey pubkey, std::vector<unsigned char>& vchSig, std::string strMessage, std::string& errorMessage);
|
||||
};
|
||||
|
||||
class CDarksendSession
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// Used to keep track of current status of darksend pool
|
||||
//
|
||||
class CDarkSendPool
|
||||
{
|
||||
public:
|
||||
static const int MIN_PEER_PROTO_VERSION = 70051;
|
||||
|
||||
// clients entries
|
||||
std::vector<CDarkSendEntry> myEntries;
|
||||
// masternode entries
|
||||
std::vector<CDarkSendEntry> entries;
|
||||
// the finalized transaction ready for signing
|
||||
CTransaction finalTransaction;
|
||||
|
||||
int64_t lastTimeChanged;
|
||||
int64_t lastAutoDenomination;
|
||||
|
||||
unsigned int state;
|
||||
unsigned int entriesCount;
|
||||
unsigned int lastEntryAccepted;
|
||||
unsigned int countEntriesAccepted;
|
||||
|
||||
// where collateral should be made out to
|
||||
CScript collateralPubKey;
|
||||
|
||||
std::vector<CTxIn> lockedCoins;
|
||||
|
||||
uint256 masterNodeBlockHash;
|
||||
|
||||
std::string lastMessage;
|
||||
bool completedTransaction;
|
||||
bool unitTest;
|
||||
CService submittedToMasternode;
|
||||
|
||||
int sessionID;
|
||||
int sessionDenom; //Users must submit an denom matching this
|
||||
int sessionUsers; //N Users have said they'll join
|
||||
bool sessionFoundMasternode; //If we've found a compatible masternode
|
||||
int sessionTries;
|
||||
int64_t sessionTotalValue; //used for autoDenom
|
||||
std::vector<CTransaction> vecSessionCollateral;
|
||||
|
||||
int lastSplitUpBlock;
|
||||
int splitUpInARow; // how many splits we've done since a success?
|
||||
int cachedLastSuccess;
|
||||
int cachedNumBlocks; //used for the overview screen
|
||||
int minBlockSpacing; //required blocks between mixes
|
||||
CTransaction txCollateral;
|
||||
|
||||
std::vector<int64_t> vecDisabledDenominations;
|
||||
|
||||
//incremented whenever a DSQ comes through
|
||||
int64_t nDsqCount;
|
||||
|
||||
CDarkSendPool()
|
||||
{
|
||||
/* DarkSend uses collateral addresses to trust parties entering the pool
|
||||
to behave themselves. If they don't it takes their money. */
|
||||
|
||||
std::string strAddress = "";
|
||||
if(!(Params().NetworkID() == CChainParams::TESTNET)) {
|
||||
strAddress = "Xq19GqFvajRrEdDHYRKGYjTsQfpV5jyipF";
|
||||
} else {
|
||||
strAddress = "mxE2Rp3oYpSEFdsN5TdHWhZvEHm3PJQQVm";
|
||||
}
|
||||
|
||||
lastSplitUpBlock = 0;
|
||||
cachedLastSuccess = 0;
|
||||
cachedNumBlocks = 0;
|
||||
unitTest = false;
|
||||
splitUpInARow = 0;
|
||||
txCollateral = CTransaction();
|
||||
minBlockSpacing = 1;
|
||||
nDsqCount = 0;
|
||||
vecDisabledDenominations.clear();
|
||||
|
||||
SetCollateralAddress(strAddress);
|
||||
SetNull();
|
||||
}
|
||||
|
||||
void SetMinBlockSpacing(int minBlockSpacingIn){
|
||||
minBlockSpacing = minBlockSpacingIn;
|
||||
}
|
||||
|
||||
bool SetCollateralAddress(std::string strAddress);
|
||||
void SetNull(bool clearEverything=false);
|
||||
|
||||
void UnlockCoins();
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
return (state == POOL_STATUS_ACCEPTING_ENTRIES && entries.empty() && myEntries.empty());
|
||||
}
|
||||
|
||||
int GetState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
int GetEntriesCount() const
|
||||
{
|
||||
if(fMasterNode){
|
||||
return entries.size();
|
||||
} else {
|
||||
return entriesCount;
|
||||
}
|
||||
}
|
||||
|
||||
int GetLastEntryAccepted() const
|
||||
{
|
||||
return lastEntryAccepted;
|
||||
}
|
||||
|
||||
int GetCountEntriesAccepted() const
|
||||
{
|
||||
return countEntriesAccepted;
|
||||
}
|
||||
|
||||
int GetMyTransactionCount() const
|
||||
{
|
||||
return myEntries.size();
|
||||
}
|
||||
|
||||
void UpdateState(unsigned int newState)
|
||||
{
|
||||
if (fMasterNode && (newState == POOL_STATUS_ERROR || newState == POOL_STATUS_SUCCESS)){
|
||||
LogPrintf("CDarkSendPool::UpdateState() - Can't set state to ERROR or SUCCESS as a masternode. \n");
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("CDarkSendPool::UpdateState() == %d | %d \n", state, newState);
|
||||
if(state != newState){
|
||||
lastTimeChanged = GetTimeMillis();
|
||||
if(fMasterNode) {
|
||||
RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET);
|
||||
}
|
||||
}
|
||||
state = newState;
|
||||
}
|
||||
|
||||
int GetMaxPoolTransactions()
|
||||
{
|
||||
//if we're on testnet, just use two transactions per merge
|
||||
if(Params().NetworkID() == CChainParams::TESTNET) return 2;
|
||||
|
||||
//use the production amount
|
||||
return POOL_MAX_TRANSACTIONS;
|
||||
}
|
||||
|
||||
//Do we have enough users to take entries?
|
||||
bool IsSessionReady(){
|
||||
return sessionUsers >= GetMaxPoolTransactions();
|
||||
}
|
||||
|
||||
// Are these outputs compatible with other client in the pool?
|
||||
bool IsCompatibleWithEntries(std::vector<CTxOut> vout);
|
||||
// Is this amount compatible with other client in the pool?
|
||||
bool IsCompatibleWithSession(int64_t nAmount, CTransaction txCollateral, std::string& strReason);
|
||||
|
||||
// Passively run Darksend in the background according to the configuration in settings (only for QT)
|
||||
bool DoAutomaticDenominating(bool fDryRun=false, bool ready=false);
|
||||
|
||||
|
||||
// check for process in Darksend
|
||||
void Check();
|
||||
// charge fees to bad actors
|
||||
void ChargeFees();
|
||||
// rarely charge fees to pay miners
|
||||
void ChargeRandomFees();
|
||||
void CheckTimeout();
|
||||
// check to make sure a signature matches an input in the pool
|
||||
bool SignatureValid(const CScript& newSig, const CTxIn& newVin);
|
||||
// if the collateral is valid given by a client
|
||||
bool IsCollateralValid(const CTransaction& txCollateral);
|
||||
// add a clients entry to the pool
|
||||
bool AddEntry(const std::vector<CTxIn>& newInput, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector<CTxOut>& newOutput, std::string& error);
|
||||
// add signature to a vin
|
||||
bool AddScriptSig(const CTxIn& newVin);
|
||||
// are all inputs signed?
|
||||
bool SignaturesComplete();
|
||||
// as a client, send a transaction to a masternode to start the denomination process
|
||||
void SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout, int64_t amount);
|
||||
// get masternode updates about the progress of darksend
|
||||
bool StatusUpdate(int newState, int newEntriesCount, int newAccepted, std::string& error, int newSessionID=0);
|
||||
|
||||
// as a client, check and sign the final transaction
|
||||
bool SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node);
|
||||
|
||||
// get block hash by height
|
||||
bool GetBlockHash(uint256& hash, int nBlockHeight);
|
||||
// get the last valid block hash for a given modulus
|
||||
bool GetLastValidBlockHash(uint256& hash, int mod=1, int nBlockHeight=0);
|
||||
// process a new block
|
||||
void NewBlock();
|
||||
void CompletedTransaction(bool error, std::string lastMessageNew);
|
||||
void ClearLastMessage();
|
||||
// used for liquidity providers
|
||||
bool SendRandomPaymentToSelf();
|
||||
// split up large inputs or make fee sized inputs
|
||||
bool SplitUpMoney(bool justCollateral=false);
|
||||
// get the denominations for a list of outputs (returns a bitshifted integer)
|
||||
int GetDenominations(const std::vector<CTxOut>& vout);
|
||||
// get the denominations for a specific amount of darkcoin.
|
||||
int GetDenominationsByAmount(int64_t nAmount);
|
||||
int GetDenominationsByAmounts(std::vector<int64_t>& vecAmount);
|
||||
};
|
||||
|
||||
|
||||
void ConnectToDarkSendMasterNodeWinner();
|
||||
|
||||
void ThreadCheckDarkSendPool();
|
||||
|
||||
#endif
|
86
src/init.cpp
86
src/init.cpp
@ -20,6 +20,7 @@
|
||||
#include "txdb.h"
|
||||
#include "ui_interface.h"
|
||||
#include "util.h"
|
||||
#include "activemasternode.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "db.h"
|
||||
#include "wallet.h"
|
||||
@ -1079,7 +1080,84 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
}
|
||||
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
|
||||
|
||||
// ********************************************************* Step 10: load peers
|
||||
// ********************************************************* Step 10: setup DarkSend
|
||||
|
||||
//string strNode = "23.23.186.131";
|
||||
//CAddress addr;
|
||||
//ConnectNode(addr, strNode.c_str(), true);
|
||||
|
||||
fMasterNode = GetBoolArg("-masternode", false);
|
||||
if(fMasterNode) {
|
||||
LogPrintf("IS DARKSEND MASTER NODE\n");
|
||||
strMasterNodeAddr = GetArg("-masternodeaddr", "");
|
||||
|
||||
LogPrintf(" addr %s\n", strMasterNodeAddr.c_str());
|
||||
|
||||
if(!strMasterNodeAddr.empty()){
|
||||
CService addrTest = CService(strMasterNodeAddr);
|
||||
if (!addrTest.IsValid()) {
|
||||
printf("Invalid -masternodeaddr address: '%s'\n", mapArgs["-strMasterNodeAddr"].c_str());
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
strMasterNodePrivKey = GetArg("-masternodeprivkey", "");
|
||||
if(!strMasterNodePrivKey.empty()){
|
||||
std::string errorMessage;
|
||||
|
||||
CKey key;
|
||||
CPubKey pubkey;
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key, pubkey))
|
||||
{
|
||||
return InitError(_("Invalid masternodeprivkey. Please see documenation."));
|
||||
}
|
||||
|
||||
activeMasternode.pubkeyMasterNode2 = pubkey;
|
||||
|
||||
} else {
|
||||
return InitError(_("You must specify a masternodeprivkey in the configuration. Please see documentation for help."));
|
||||
}
|
||||
}
|
||||
|
||||
fEnableDarksend = GetBoolArg("-enabledarksend", false);
|
||||
|
||||
nDarksendRounds = GetArg("-darksendrounds", 2);
|
||||
if(nDarksendRounds > 8) nDarksendRounds = 8;
|
||||
if(nDarksendRounds < 1) nDarksendRounds = 1;
|
||||
|
||||
nLiquidityProvider = GetArg("-liquidityprovider", 0); //1-100
|
||||
if(nLiquidityProvider != 0) {
|
||||
darkSendPool.SetMinBlockSpacing(std::min(nLiquidityProvider,100)*15);
|
||||
fEnableDarksend = true;
|
||||
nDarksendRounds = 99999;
|
||||
}
|
||||
|
||||
nAnonymizeDarkcoinAmount = GetArg("-anonymizedarkcoinamount", 0);
|
||||
if(nAnonymizeDarkcoinAmount > 999999) nAnonymizeDarkcoinAmount = 999999;
|
||||
if(nAnonymizeDarkcoinAmount < 2) nAnonymizeDarkcoinAmount = 2;
|
||||
|
||||
bool fEnableInstantX = GetBoolArg("-enableinstantx", true);
|
||||
if(fEnableInstantX){
|
||||
nInstantXDepth = GetArg("-instantxdepth", 1);
|
||||
if(nInstantXDepth > 60) nInstantXDepth = 60;
|
||||
if(nInstantXDepth < 0) nAnonymizeDarkcoinAmount = 0;
|
||||
} else {
|
||||
nInstantXDepth = 0;
|
||||
}
|
||||
|
||||
LogPrintf("nInstantXDepth %d\n", nInstantXDepth);
|
||||
LogPrintf("Darksend rounds %d\n", nDarksendRounds);
|
||||
LogPrintf("Anonymize Darkcoin Amount %d\n", nAnonymizeDarkcoinAmount);
|
||||
|
||||
darkSendDenominations.push_back( (100 * COIN)+1 );
|
||||
darkSendDenominations.push_back( (10 * COIN)+1 );
|
||||
darkSendDenominations.push_back( (1 * COIN)+1 );
|
||||
darkSendDenominations.push_back( (.1 * COIN)+1 );
|
||||
|
||||
threadGroup.create_thread(boost::bind(&ThreadCheckDarkSendPool));
|
||||
|
||||
// ********************************************************* Step 11: load peers
|
||||
|
||||
uiInterface.InitMessage(_("Loading addresses..."));
|
||||
|
||||
@ -1094,7 +1172,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
LogPrintf("Loaded %i addresses from peers.dat %dms\n",
|
||||
addrman.size(), GetTimeMillis() - nStart);
|
||||
|
||||
// ********************************************************* Step 11: start node
|
||||
// ********************************************************* Step 12: start node
|
||||
|
||||
if (!CheckDiskSpace())
|
||||
return false;
|
||||
@ -1106,7 +1184,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
|
||||
//// debug print
|
||||
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
|
||||
LogPrintf("nBestHeight = %d\n", chainActive.Height());
|
||||
LogPrintf("chainActive.Tip()->nHeight = %d\n", chainActive.Height());
|
||||
#ifdef ENABLE_WALLET
|
||||
LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0);
|
||||
LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0);
|
||||
@ -1125,7 +1203,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", -1));
|
||||
#endif
|
||||
|
||||
// ********************************************************* Step 12: finished
|
||||
// ********************************************************* Step 13: finished
|
||||
|
||||
uiInterface.InitMessage(_("Done loading"));
|
||||
|
||||
|
459
src/instantx.cpp
Normal file
459
src/instantx.cpp
Normal file
@ -0,0 +1,459 @@
|
||||
|
||||
|
||||
|
||||
#include "bignum.h"
|
||||
#include "sync.h"
|
||||
#include "net.h"
|
||||
#include "key.h"
|
||||
#include "util.h"
|
||||
#include "script.h"
|
||||
#include "base58.h"
|
||||
#include "protocol.h"
|
||||
#include "instantx.h"
|
||||
#include "masternode.h"
|
||||
#include "activemasternode.h"
|
||||
#include "darksend.h"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
std::vector<CTransactionLock> vecTxLocks;
|
||||
|
||||
std::map<uint256, CTransaction> mapTxLockReq;
|
||||
std::map<uint256, CTransaction> mapTxLockReqRejected;
|
||||
std::map<uint256, CTransactionLock> mapTxLocks;
|
||||
|
||||
#define INSTANTX_SIGNATURES_REQUIRED 2
|
||||
|
||||
//txlock - Locks transaction
|
||||
//
|
||||
//step 1.) Broadcast intention to lock transaction inputs, "txlreg", CTransaction
|
||||
//step 2.) Top 10 masternodes, open connect to top 1 masternode. Send "txvote", CTransaction, Signature, Approve
|
||||
//step 3.) Top 1 masternode, waits for 10 messages. Upon success, sends "txlock'
|
||||
|
||||
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
{
|
||||
return;
|
||||
|
||||
if (strCommand == "txlreq")
|
||||
{
|
||||
//LogPrintf("ProcessMessageInstantX::txlreq\n");
|
||||
CDataStream vMsg(vRecv);
|
||||
CTransaction tx;
|
||||
vRecv >> tx;
|
||||
|
||||
CInv inv(MSG_TXLOCK_REQUEST, tx.GetHash());
|
||||
pfrom->AddInventoryKnown(inv);
|
||||
|
||||
if(mapTxLockReq.count(inv.hash) || mapTxLockReqRejected.count(inv.hash)){
|
||||
return;
|
||||
}
|
||||
|
||||
int nTxAge = GetInputAge(tx.vin[0]);
|
||||
if(nTxAge < 5){
|
||||
LogPrintf("ProcessMessageInstantX::txlreq - Transaction not found / too new: %s\n", tx.GetHash().ToString().c_str());
|
||||
return;
|
||||
}
|
||||
int nBlockHeight = chainActive.Tip()->nHeight - nTxAge; //calculate the height
|
||||
|
||||
BOOST_FOREACH(const CTxOut o, tx.vout){
|
||||
if(!o.scriptPubKey.IsNormalPaymentScript()){
|
||||
LogPrintf ("ProcessMessageInstantX::txlreq - Invalid Script %s\n", tx.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool fMissingInputs = false;
|
||||
CValidationState state;
|
||||
|
||||
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
||||
{
|
||||
RelayTransactionLockReq(tx, inv.hash);
|
||||
DoConsensusVote(tx, true, nBlockHeight);
|
||||
|
||||
mapTxLockReq.insert(make_pair(inv.hash, tx));
|
||||
|
||||
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : accepted %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
tx.GetHash().ToString().c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
mapTxLockReqRejected.insert(make_pair(inv.hash, tx));
|
||||
|
||||
// can we get the conflicting transaction as proof?
|
||||
|
||||
RelayTransactionLockReq(tx, inv.hash);
|
||||
DoConsensusVote(tx, false, nBlockHeight);
|
||||
|
||||
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
tx.GetHash().ToString().c_str()
|
||||
);
|
||||
|
||||
//record prevout, increment the amount of times seen. Ban if over 100
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (strCommand == "txlvote") //InstantX Lock Consensus Votes
|
||||
{
|
||||
CConsensusVote ctx;
|
||||
vRecv >> ctx;
|
||||
|
||||
ProcessConsensusVote(ctx);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (strCommand == "txlock") //InstantX Lock Transaction Inputs
|
||||
{
|
||||
LogPrintf("ProcessMessageInstantX::txlock\n");
|
||||
|
||||
CDataStream vMsg(vRecv);
|
||||
CTransactionLock ctxl;
|
||||
vRecv >> ctxl;
|
||||
|
||||
CInv inv(MSG_TXLOCK, ctxl.GetHash());
|
||||
pfrom->AddInventoryKnown(inv);
|
||||
|
||||
LogPrintf(" -- ProcessMessageInstantX::txlock %d %s\n", mapTxLocks.count(inv.hash), inv.hash.ToString().c_str());
|
||||
|
||||
|
||||
if(!mapTxLocks.count(inv.hash)){
|
||||
if(ctxl.CountSignatures() < INSTANTX_SIGNATURES_REQUIRED){
|
||||
LogPrintf("InstantX::txlock - not enough signatures\n");
|
||||
return;
|
||||
}
|
||||
if(!ctxl.SignaturesValid()){
|
||||
LogPrintf("InstantX::txlock - got invalid TransactionLock, rejected\n");
|
||||
return;
|
||||
}
|
||||
if(!ctxl.AllInFavor()){
|
||||
LogPrintf("InstantX::txlock - not all in favor of lock, rejected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const CTxOut o, ctxl.tx.vout){
|
||||
if(!o.scriptPubKey.IsNormalPaymentScript()){
|
||||
LogPrintf ("ProcessMessageInstantX::cxlock - Invalid Script %s\n", ctxl.tx.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
mapTxLocks.insert(make_pair(inv.hash, ctxl));
|
||||
|
||||
//we should have the lock request in place
|
||||
if(!mapTxLockReq.count(inv.hash)){
|
||||
//if we don't
|
||||
bool fMissingInputs = false;
|
||||
CValidationState state;
|
||||
|
||||
if (AcceptToMemoryPool(mempool, state, ctxl.tx, true, &fMissingInputs))
|
||||
{
|
||||
mapTxLockReq.insert(make_pair(inv.hash, ctxl.tx));
|
||||
|
||||
LogPrintf("ProcessMessageInstantX::txlock - Transaction Lock Request: %s %s : accepted (no reversing) %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
ctxl.tx.GetHash().ToString().c_str()
|
||||
);
|
||||
|
||||
} else {
|
||||
// we have a conflicting transaction (an attack)
|
||||
CValidationState state;
|
||||
DisconnectBlockAndInputs(state, ctxl.tx);
|
||||
|
||||
if (AcceptToMemoryPool(mempool, state, ctxl.tx, true, &fMissingInputs))
|
||||
{
|
||||
mapTxLockReq.insert(make_pair(inv.hash, ctxl.tx));
|
||||
|
||||
LogPrintf("ProcessMessageInstantX::txlock - Transaction Lock Request: %s %s : accepted (reversed) %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
ctxl.tx.GetHash().ToString().c_str()
|
||||
);
|
||||
} else {
|
||||
LogPrintf("ProcessMessageInstantX::txlock - Transaction Lock Request: %s %s : rejected (reversed) %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
ctxl.tx.GetHash().ToString().c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//broadcast the new lock
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if(!pnode->fRelayTxes)
|
||||
continue;
|
||||
|
||||
pnode->PushMessage("txlock", ctxl);
|
||||
}
|
||||
|
||||
pwalletMain->UpdatedTransaction(ctxl.GetHash());
|
||||
|
||||
LogPrintf("InstantX :: Got Transaction Lock: %s %s : accepted %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
ctxl.GetHash().ToString().c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if we need to vote on this transaction
|
||||
void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight)
|
||||
{
|
||||
if(!fMasterNode) {
|
||||
LogPrintf("InstantX::DoConsensusVote - Not masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int winner = GetCurrentMasterNode(1, nBlockHeight);
|
||||
int n = GetMasternodeRank(activeMasternode.vinMasternode, nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
|
||||
|
||||
if(n == -1 || winner == -1)
|
||||
{
|
||||
LogPrintf("InstantX::DoConsensusVote - Unknown Masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(n == 1)
|
||||
{ // winner, I'll be keeping track of this
|
||||
LogPrintf("InstantX::DoConsensusVote - Managing Masternode\n");
|
||||
CTransactionLock newLock;
|
||||
newLock.nBlockHeight = nBlockHeight;
|
||||
newLock.tx = tx;
|
||||
vecTxLocks.push_back(newLock);
|
||||
}
|
||||
|
||||
CConsensusVote ctx;
|
||||
ctx.vinMasternode = activeMasternode.vinMasternode;
|
||||
ctx.approved = approved;
|
||||
ctx.txHash = tx.GetHash();
|
||||
ctx.nBlockHeight = nBlockHeight;
|
||||
if(!ctx.Sign()){
|
||||
LogPrintf("InstantX::DoConsensusVote - Failed to sign consensus vote\n");
|
||||
return;
|
||||
}
|
||||
if(!ctx.SignatureValid()) {
|
||||
LogPrintf("InstantX::DoConsensusVote - Signature invalid\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(n == 1){ //I'm the winner
|
||||
ProcessConsensusVote(ctx);
|
||||
} else if(n <= 10){ // not winner, but in the top10
|
||||
if(ConnectNode((CAddress)darkSendMasterNodes[winner].addr, NULL, true)){
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if(darkSendMasterNodes[winner].addr != pnode->addr) continue;
|
||||
|
||||
pnode->PushMessage("txlvote", ctx);
|
||||
LogPrintf("InstantX::DoConsensusVote --- connected, sending vote %s\n", pnode->addr.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
LogPrintf("InstantX::DoConsensusVote --- error connecting \n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//received a consensus vote
|
||||
void ProcessConsensusVote(CConsensusVote& ctx)
|
||||
{
|
||||
if(!fMasterNode) {
|
||||
LogPrintf("InstantX::ProcessConsensusVote - Not masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int winner = GetCurrentMasterNode(1, ctx.nBlockHeight);
|
||||
if(winner == -1) {
|
||||
LogPrintf("InstantX::ProcessConsensusVote - Can't detect winning masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//We're not the winning masternode
|
||||
if(darkSendMasterNodes[winner].vin != activeMasternode.vinMasternode) {
|
||||
LogPrintf("InstantX::ProcessConsensusVote - I'm not the winning masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int n = GetMasternodeRank(ctx.vinMasternode, ctx.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
|
||||
|
||||
if(n == -1)
|
||||
{
|
||||
LogPrintf("InstantX::ProcessConsensusVote - Unknown Masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(n > 10)
|
||||
{
|
||||
LogPrintf("InstantX::ProcessConsensusVote - Masternode not in the top 10\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!ctx.SignatureValid()) {
|
||||
LogPrintf("InstantX::ProcessConsensusVote - Signature invalid\n");
|
||||
//don't ban, it could just be a non-synced masternode
|
||||
return;
|
||||
}
|
||||
|
||||
//compile consessus vote
|
||||
BOOST_FOREACH(CTransactionLock& ctxl, vecTxLocks){
|
||||
if(ctxl.nBlockHeight == ctx.nBlockHeight){
|
||||
ctxl.AddSignature(ctx);
|
||||
if(ctxl.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
|
||||
LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete, broadcasting!\n");
|
||||
|
||||
CInv inv(MSG_TXLOCK, ctxl.GetHash());
|
||||
mapTxLocks.insert(make_pair(inv.hash, ctxl));
|
||||
|
||||
//broadcast the new lock
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes){
|
||||
pnode->PushMessage("txlock", ctxl);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void CleanTransactionLocksList()
|
||||
{
|
||||
if(chainActive.Tip() == NULL) return;
|
||||
|
||||
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin();
|
||||
|
||||
while(it != mapTxLocks.end()) {
|
||||
if(chainActive.Tip()->nHeight - it->second.nBlockHeight > 3){ //keep them for an hour
|
||||
LogPrintf("Removing old transaction lock %s\n", it->second.GetHash().ToString().c_str());
|
||||
mapTxLocks.erase(it++);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CConsensusVote::SignatureValid()
|
||||
{
|
||||
std::string errorMessage;
|
||||
std::string strMessage = txHash.ToString().c_str() + boost::lexical_cast<std::string>(nBlockHeight) + boost::lexical_cast<std::string>(approved);
|
||||
LogPrintf("verify strMessage %s \n", strMessage.c_str());
|
||||
|
||||
int n = GetMasternodeByVin(vinMasternode);
|
||||
|
||||
if(n == -1)
|
||||
{
|
||||
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Unknown Masternode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogPrintf("verify addr %s \n", darkSendMasterNodes[0].addr.ToString().c_str());
|
||||
LogPrintf("verify addr %s \n", darkSendMasterNodes[1].addr.ToString().c_str());
|
||||
LogPrintf("verify addr %d %s \n", n, darkSendMasterNodes[n].addr.ToString().c_str());
|
||||
|
||||
CScript pubkey;
|
||||
pubkey.SetDestination(darkSendMasterNodes[n].pubkey2.GetID());
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pubkey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
LogPrintf("verify pubkey2 %s \n", address2.ToString().c_str());
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(darkSendMasterNodes[n].pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
|
||||
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Verify message failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConsensusVote::Sign()
|
||||
{
|
||||
std::string errorMessage;
|
||||
|
||||
CKey key2;
|
||||
CPubKey pubkey2;
|
||||
std::string strMessage = txHash.ToString().c_str() + boost::lexical_cast<std::string>(nBlockHeight) + boost::lexical_cast<std::string>(approved);
|
||||
LogPrintf("signing strMessage %s \n", strMessage.c_str());
|
||||
LogPrintf("signing privkey %s \n", strMasterNodePrivKey.c_str());
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2))
|
||||
{
|
||||
LogPrintf("Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
CScript pubkey;
|
||||
pubkey.SetDestination(pubkey2.GetID());
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pubkey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
LogPrintf("signing pubkey2 %s \n", address2.ToString().c_str());
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, key2)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sign message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
|
||||
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Verify message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CTransactionLock::SignaturesValid()
|
||||
{
|
||||
|
||||
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
|
||||
{
|
||||
int n = GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
|
||||
|
||||
if(n == -1)
|
||||
{
|
||||
LogPrintf("InstantX::DoConsensusVote - Unknown Masternode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(n > 10)
|
||||
{
|
||||
LogPrintf("InstantX::DoConsensusVote - Masternode not in the top 10\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!vote.SignatureValid()){
|
||||
LogPrintf("InstantX::CTransactionLock::SignaturesValid - Signature not valid\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTransactionLock::AllInFavor()
|
||||
{
|
||||
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
|
||||
if(vote.approved == false) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTransactionLock::AddSignature(CConsensusVote cv)
|
||||
{
|
||||
vecConsensusVotes.push_back(cv);
|
||||
}
|
||||
|
||||
int CTransactionLock::CountSignatures()
|
||||
{
|
||||
return vecConsensusVotes.size();
|
||||
}
|
89
src/instantx.h
Normal file
89
src/instantx.h
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef INSTANTX_H
|
||||
#define INSTANTX_H
|
||||
|
||||
#include "bignum.h"
|
||||
#include "sync.h"
|
||||
#include "net.h"
|
||||
#include "key.h"
|
||||
#include "core.h"
|
||||
#include "util.h"
|
||||
#include "script.h"
|
||||
#include "base58.h"
|
||||
#include "main.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
class CConsensusVote;
|
||||
class CTransaction;
|
||||
class CTransactionLock;
|
||||
|
||||
static const int MIN_INSTANTX_PROTO_VERSION = 70047;
|
||||
|
||||
extern map<uint256, CTransaction> mapTxLockReq;
|
||||
extern map<uint256, CTransactionLock> mapTxLocks;
|
||||
|
||||
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
|
||||
//check if we need to vote on this transaction
|
||||
void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight);
|
||||
|
||||
//process consensus vote message
|
||||
void ProcessConsensusVote(CConsensusVote& ctx);
|
||||
|
||||
// keep transaction locks in memory for an hour
|
||||
void CleanTransactionLocksList();
|
||||
|
||||
class CConsensusVote
|
||||
{
|
||||
public:
|
||||
CTxIn vinMasternode;
|
||||
bool approved;
|
||||
uint256 txHash;
|
||||
std::vector<unsigned char> vchMasterNodeSignature;
|
||||
int nBlockHeight;
|
||||
|
||||
bool SignatureValid();
|
||||
bool Sign();
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
READWRITE(txHash);
|
||||
READWRITE(vinMasternode);
|
||||
READWRITE(approved);
|
||||
READWRITE(vchMasterNodeSignature);
|
||||
READWRITE(nBlockHeight);
|
||||
)
|
||||
};
|
||||
|
||||
class CTransactionLock
|
||||
{
|
||||
public:
|
||||
int nBlockHeight;
|
||||
CTransaction tx;
|
||||
std::vector<CConsensusVote> vecConsensusVotes;
|
||||
|
||||
bool SignaturesValid();
|
||||
int CountSignatures();
|
||||
bool AllInFavor();
|
||||
void AddSignature(CConsensusVote cv);
|
||||
uint256 GetHash()
|
||||
{
|
||||
return tx.GetHash();
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
READWRITE(tx);
|
||||
READWRITE(nBlockHeight);
|
||||
READWRITE(vecConsensusVotes);
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
#endif
|
435
src/main.cpp
435
src/main.cpp
@ -12,6 +12,9 @@
|
||||
#include "checkpoints.h"
|
||||
#include "checkqueue.h"
|
||||
#include "init.h"
|
||||
#include "instantx.h"
|
||||
#include "darksend.h"
|
||||
#include "masternode.h"
|
||||
#include "net.h"
|
||||
#include "txdb.h"
|
||||
#include "txmempool.h"
|
||||
@ -74,7 +77,7 @@ void EraseOrphansFor(NodeId peer);
|
||||
// Constant stuff for coinbase transactions we create:
|
||||
CScript COINBASE_FLAGS;
|
||||
|
||||
const string strMessageMagic = "Bitcoin Signed Message:\n";
|
||||
const string strMessageMagic = "DarkCoin Signed Message:\n";
|
||||
|
||||
// Internal stuff
|
||||
namespace {
|
||||
@ -746,10 +749,29 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
|
||||
return chainActive.Height() - pindex->nHeight + 1;
|
||||
}
|
||||
|
||||
int GetInputAge(CTxIn& vin)
|
||||
{
|
||||
// Fetch previous transactions (inputs):
|
||||
CCoinsView viewDummy;
|
||||
CCoinsViewCache view(viewDummy);
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
CCoinsViewCache &viewChain = *pcoinsTip;
|
||||
CCoinsViewMemPool viewMempool(viewChain, mempool);
|
||||
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
|
||||
|
||||
const uint256& prevHash = vin.prevout.hash;
|
||||
CCoins coins;
|
||||
view.GetCoins(prevHash, coins); // this is certainly allowed to fail
|
||||
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
|
||||
}
|
||||
|
||||
if(!view.HaveCoins(vin.prevout.hash)) return -1;
|
||||
|
||||
const CCoins &coins = view.GetCoins(vin.prevout.hash);
|
||||
|
||||
return (chainActive.Tip()->nHeight+1) - coins.nHeight;
|
||||
}
|
||||
|
||||
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
||||
@ -845,7 +867,7 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree,
|
||||
|
||||
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fRejectInsaneFee)
|
||||
bool* pfMissingInputs, bool fRejectInsaneFee, bool ignoreFees)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
if (pfMissingInputs)
|
||||
@ -938,34 +960,36 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
unsigned int nSize = entry.GetTxSize();
|
||||
|
||||
// Don't accept it if it can't get into a block
|
||||
int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
|
||||
if (fLimitFree && nFees < txMinFee)
|
||||
return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d",
|
||||
hash.ToString(), nFees, txMinFee),
|
||||
REJECT_INSUFFICIENTFEE, "insufficient fee");
|
||||
if(!ignoreFees){
|
||||
int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
|
||||
if (fLimitFree && nFees < txMinFee)
|
||||
return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d",
|
||||
hash.ToString(), nFees, txMinFee),
|
||||
REJECT_INSUFFICIENTFEE, "insufficient fee");
|
||||
|
||||
// Continuously rate-limit free transactions
|
||||
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
|
||||
// be annoying or make others' transactions take longer to confirm.
|
||||
if (fLimitFree && nFees < CTransaction::nMinRelayTxFee)
|
||||
{
|
||||
static CCriticalSection csFreeLimiter;
|
||||
static double dFreeCount;
|
||||
static int64_t nLastTime;
|
||||
int64_t nNow = GetTime();
|
||||
// Continuously rate-limit free transactions
|
||||
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
|
||||
// be annoying or make others' transactions take longer to confirm.
|
||||
if (fLimitFree && nFees < CTransaction::nMinRelayTxFee)
|
||||
{
|
||||
static CCriticalSection csFreeLimiter;
|
||||
static double dFreeCount;
|
||||
static int64_t nLastTime;
|
||||
int64_t nNow = GetTime();
|
||||
|
||||
LOCK(csFreeLimiter);
|
||||
LOCK(csFreeLimiter);
|
||||
|
||||
// Use an exponentially decaying ~10-minute window:
|
||||
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
|
||||
nLastTime = nNow;
|
||||
// -limitfreerelay unit is thousand-bytes-per-minute
|
||||
// At default rate it would take over a month to fill 1GB
|
||||
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
|
||||
return state.DoS(0, error("AcceptToMemoryPool : free transaction rejected by rate limiter"),
|
||||
REJECT_INSUFFICIENTFEE, "insufficient priority");
|
||||
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
|
||||
dFreeCount += nSize;
|
||||
// Use an exponentially decaying ~10-minute window:
|
||||
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
|
||||
nLastTime = nNow;
|
||||
// -limitfreerelay unit is thousand-bytes-per-minute
|
||||
// At default rate it would take over a month to fill 1GB
|
||||
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
|
||||
return state.DoS(0, error("AcceptToMemoryPool : free transaction rejected by rate limiter"),
|
||||
REJECT_INSUFFICIENTFEE, "insufficient priority");
|
||||
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
|
||||
dFreeCount += nSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (fRejectInsaneFee && nFees > CTransaction::nMinRelayTxFee * 10000)
|
||||
@ -988,6 +1012,123 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AcceptableInputs(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool ignoreFees)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
if (!CheckTransaction(tx, state))
|
||||
return error("AcceptToMemoryPool: : CheckTransaction failed");
|
||||
|
||||
// Coinbase is only valid in a block, not as a loose transaction
|
||||
if (tx.IsCoinBase())
|
||||
return state.DoS(100, error("AcceptToMemoryPool: : coinbase as individual tx"),
|
||||
REJECT_INVALID, "coinbase");
|
||||
|
||||
// is it already in the memory pool?
|
||||
uint256 hash = tx.GetHash();
|
||||
if (pool.exists(hash))
|
||||
return false;
|
||||
|
||||
// Check for conflicts with in-memory transactions
|
||||
{
|
||||
LOCK(pool.cs); // protect pool.mapNextTx
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
{
|
||||
COutPoint outpoint = tx.vin[i].prevout;
|
||||
if (pool.mapNextTx.count(outpoint))
|
||||
{
|
||||
// Disable replacement feature for now
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
CCoinsView dummy;
|
||||
CCoinsViewCache view(dummy);
|
||||
|
||||
{
|
||||
LOCK(pool.cs);
|
||||
CCoinsViewMemPool viewMemPool(*pcoinsTip, pool);
|
||||
view.SetBackend(viewMemPool);
|
||||
|
||||
// do we already have it?
|
||||
if (view.HaveCoins(hash))
|
||||
return false;
|
||||
|
||||
// do all inputs exist?
|
||||
// Note that this does not check for the presence of actual outputs (see the next check for that),
|
||||
// only helps filling in pfMissingInputs (to determine missing vs spent).
|
||||
BOOST_FOREACH(const CTxIn txin, tx.vin) {
|
||||
if (!view.HaveCoins(txin.prevout.hash)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// are the actual inputs available?
|
||||
if (!view.HaveInputs(tx))
|
||||
return state.Invalid(error("AcceptToMemoryPool : inputs already spent"),
|
||||
REJECT_DUPLICATE, "bad-txns-inputs-spent");
|
||||
|
||||
// Bring the best block into scope
|
||||
view.GetBestBlock();
|
||||
|
||||
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
|
||||
view.SetBackend(dummy);
|
||||
}
|
||||
|
||||
// Don't accept it if it can't get into a block
|
||||
if(!ignoreFees){
|
||||
int64_t nValueIn = view.GetValueIn(tx);
|
||||
int64_t nValueOut = tx.GetValueOut();
|
||||
int64_t nFees = nValueIn-nValueOut;
|
||||
double dPriority = view.GetPriority(tx, chainActive.Height());
|
||||
|
||||
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height());
|
||||
unsigned int nSize = entry.GetTxSize();
|
||||
|
||||
int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
|
||||
if (nFees < txMinFee)
|
||||
return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d",
|
||||
hash.ToString(), nFees, txMinFee),
|
||||
REJECT_INSUFFICIENTFEE, "insufficient fee");
|
||||
|
||||
// Continuously rate-limit free transactions
|
||||
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
|
||||
// be annoying or make others' transactions take longer to confirm.
|
||||
if (nFees < CTransaction::nMinRelayTxFee)
|
||||
{
|
||||
static CCriticalSection csFreeLimiter;
|
||||
static double dFreeCount;
|
||||
static int64_t nLastTime;
|
||||
int64_t nNow = GetTime();
|
||||
|
||||
LOCK(csFreeLimiter);
|
||||
|
||||
// Use an exponentially decaying ~10-minute window:
|
||||
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
|
||||
nLastTime = nNow;
|
||||
// -limitfreerelay unit is thousand-bytes-per-minute
|
||||
// At default rate it would take over a month to fill 1GB
|
||||
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
|
||||
return state.DoS(0, error("AcceptToMemoryPool : free transaction rejected by rate limiter"),
|
||||
REJECT_INSUFFICIENTFEE, "insufficient priority");
|
||||
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
|
||||
dFreeCount += nSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Check against previous transactions
|
||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||
if (!CheckInputs(tx, state, view, false, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC))
|
||||
{
|
||||
return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const
|
||||
{
|
||||
@ -1447,14 +1588,12 @@ unsigned int static DarkGravityWave(const CBlockIndex* pindexLast, const CBlockH
|
||||
|
||||
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
|
||||
{
|
||||
uint retarget = DIFF_BTC;
|
||||
uint retarget = DIFF_DGW;
|
||||
|
||||
if (TestNet()) {
|
||||
if (pindexLast->nHeight + 1 >= 256) retarget = DIFF_DGW;
|
||||
}
|
||||
else {
|
||||
if (!TestNet()) {
|
||||
if (pindexLast->nHeight + 1 >= 34140) retarget = DIFF_DGW;
|
||||
else if (pindexLast->nHeight + 1 >= 15200) retarget = DIFF_KGW;
|
||||
else retarget = DIFF_BTC;
|
||||
}
|
||||
|
||||
// Default Bitcoin style retargeting
|
||||
@ -1505,7 +1644,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||
// Limit adjustment step
|
||||
//int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
|
||||
int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
|
||||
//LogPrintf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan);
|
||||
//LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan);
|
||||
LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan);
|
||||
if (nActualTimespan < nTargetTimespan/4)
|
||||
nActualTimespan = nTargetTimespan/4;
|
||||
@ -1523,7 +1662,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||
|
||||
/// debug print
|
||||
LogPrintf("GetNextWorkRequired RETARGET\n");
|
||||
//LogPrintf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
|
||||
//LogPrintf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);
|
||||
LogPrintf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);
|
||||
//LogPrintf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
|
||||
LogPrintf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString());
|
||||
@ -1940,6 +2079,178 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DisconnectBlockAndInputs
|
||||
|
||||
Remove conflicting blocks for successful InstantX transaction locks
|
||||
This should be very rare (Probably will never happen)
|
||||
*/
|
||||
bool DisconnectBlockAndInputs(CValidationState &state, CTransaction txLock)
|
||||
{
|
||||
/* // All modifications to the coin state will be done in this cache.
|
||||
// Only when all have succeeded, we push it to pcoinsTip.
|
||||
CCoinsViewCache view(*pcoinsTip, true);
|
||||
|
||||
CBlockIndex* BlockReading = chainActive.Tip();
|
||||
CBlockIndex* pindexNew = NULL;
|
||||
|
||||
int HeightMin = chainActive.Tip()->nHeight-5;
|
||||
bool foundConflictingTx = false;
|
||||
|
||||
//remove anything conflicting in the memory pool
|
||||
mempool.removeConflicts(txLock);
|
||||
|
||||
// List of what to disconnect (typically nothing)
|
||||
vector<CBlockIndex*> vDisconnect;
|
||||
|
||||
for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0 && !foundConflictingTx; i++) {
|
||||
vDisconnect.push_back(BlockReading);
|
||||
pindexNew = BlockReading->pprev; //new best block
|
||||
|
||||
CBlock block;
|
||||
if (!block.ReadFromDisk(BlockReading))
|
||||
return state.Abort(_("Failed to read block"));
|
||||
|
||||
// Queue memory transactions to resurrect.
|
||||
// We only do this for blocks after the last checkpoint (reorganisation before that
|
||||
// point should only happen with -reindex/-loadblock, or a misbehaving peer.
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx){
|
||||
if (!tx.IsCoinBase() && BlockReading->nHeight > HeightMin){
|
||||
BOOST_FOREACH(const CTxIn& in1, txLock.vin){
|
||||
BOOST_FOREACH(const CTxIn& in2, tx.vin){
|
||||
if(in1 == in2) foundConflictingTx = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
|
||||
BlockReading = BlockReading->pprev;
|
||||
}
|
||||
|
||||
if(!foundConflictingTx) {
|
||||
LogPrintf("DisconnectBlockAndInputs: Can't find a conflicting transaction to inputs\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vDisconnect.size() > 0) {
|
||||
LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %"PRIszu" blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString().c_str());
|
||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
||||
LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect shorter branch
|
||||
vector<CTransaction> vResurrect;
|
||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
||||
CBlock block;
|
||||
if (!block.ReadFromDisk(pindex))
|
||||
return state.Abort(_("Failed to read block"));
|
||||
int64 nStart = GetTimeMicros();
|
||||
if (!block.DisconnectBlock(state, pindex, view))
|
||||
return error("DisconnectBlockAndInputs/SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
|
||||
if (fBenchmark)
|
||||
LogPrintf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
|
||||
|
||||
// Queue memory transactions to resurrect.
|
||||
// We only do this for blocks after the last checkpoint (reorganisation before that
|
||||
// point should only happen with -reindex/-loadblock, or a misbehaving peer.
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx){
|
||||
if (!tx.IsCoinBase() && pindex->nHeight > HeightMin){
|
||||
bool isConflict = false;
|
||||
BOOST_FOREACH(const CTxIn& in1, txLock.vin){
|
||||
BOOST_FOREACH(const CTxIn& in2, tx.vin){
|
||||
if(in1 != in2) isConflict = true;
|
||||
}
|
||||
}
|
||||
if(!isConflict) vResurrect.push_back(tx);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure it's successfully written to disk before changing memory structure
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) {
|
||||
// Typical CCoins structures on disk are around 100 bytes in size.
|
||||
// Pushing a new one to the database can cause it to be written
|
||||
// twice (once in the log, and once in the tables). This is already
|
||||
// an overestimation, as most will delete an existing entry or
|
||||
// overwrite one. Still, use a conservative safety factor of 2.
|
||||
if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize()))
|
||||
return state.Error();
|
||||
FlushBlockFile();
|
||||
pblocktree->Sync();
|
||||
if (!pcoinsTip->Flush())
|
||||
return state.Abort(_("Failed to write to coin database"));
|
||||
}
|
||||
|
||||
// At this point, all changes have been done to the database.
|
||||
// Proceed by updating the memory structures.
|
||||
|
||||
// Disconnect shorter branch
|
||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
|
||||
if (pindex->pprev)
|
||||
pindex->pprev->pnext = NULL;
|
||||
|
||||
// Resurrect memory transactions that were in the disconnected branch
|
||||
BOOST_FOREACH(CTransaction& tx, vResurrect) {
|
||||
// ignore validation errors in resurrected transactions
|
||||
CValidationState stateDummy;
|
||||
if (!tx.AcceptToMemoryPool(stateDummy, true, false))
|
||||
mempool.remove(tx, true);
|
||||
}
|
||||
|
||||
// Update best block in wallet (so we can detect restored wallets)
|
||||
if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0))
|
||||
{
|
||||
const CBlockLocator locator(pindexNew);
|
||||
::SetBestChain(locator);
|
||||
}
|
||||
|
||||
// New best block
|
||||
hashBestChain = pindexNew->GetBlockHash();
|
||||
chainActive.Tip() = pindexNew;
|
||||
pblockindexFBBHLast = NULL;
|
||||
chainActive.Tip()->nHeight = chainActive.Tip()->nHeight;
|
||||
nBestChainWork = pindexNew->nChainWork;
|
||||
nTimeBestReceived = GetTime();
|
||||
nTransactionsUpdated++;
|
||||
LogPrintf("DisconnectBlockAndInputs / SetBestChain: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n",
|
||||
hashBestChain.ToString().c_str(), chainActive.Tip()->nHeight, log(nBestChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
|
||||
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str(),
|
||||
Checkpoints::GuessVerificationProgress(chainActive.Tip()));
|
||||
|
||||
// Check the version of the last 100 blocks to see if we need to upgrade:
|
||||
if (!fIsInitialDownload)
|
||||
{
|
||||
int nUpgraded = 0;
|
||||
const CBlockIndex* pindex = chainActive.Tip();
|
||||
for (int i = 0; i < 100 && pindex != NULL; i++)
|
||||
{
|
||||
if (pindex->nVersion > CBlock::CURRENT_VERSION)
|
||||
++nUpgraded;
|
||||
pindex = pindex->pprev;
|
||||
}
|
||||
if (nUpgraded > 0)
|
||||
LogPrintf("DisconnectBlockAndInputs/SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION);
|
||||
if (nUpgraded > 100/2)
|
||||
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
|
||||
strMiscWarning = _("Warning: This version is obsolete, upgrade required!");
|
||||
}
|
||||
|
||||
std::string strCmd = GetArg("-blocknotify", "");
|
||||
|
||||
if (!fIsInitialDownload && !strCmd.empty())
|
||||
{
|
||||
boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
|
||||
boost::thread t(runCommand, strCmd); // thread runs free
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
void static FlushBlockFile(bool fFinalize = false)
|
||||
{
|
||||
LOCK(cs_LastBlockFile);
|
||||
@ -2564,6 +2875,55 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
||||
return state.DoS(100, error("CheckBlock() : more than one coinbase"),
|
||||
REJECT_INVALID, "bad-cb-multiple");
|
||||
|
||||
bool MasternodePayments = false;
|
||||
|
||||
if(Params().NetworkID() == CChainParams::TESTNET){
|
||||
if(block.nTime > START_MASTERNODE_PAYMENTS_TESTNET) MasternodePayments = true;
|
||||
} else {
|
||||
if(block.nTime > START_MASTERNODE_PAYMENTS) MasternodePayments = true;
|
||||
}
|
||||
|
||||
if(MasternodePayments)
|
||||
{
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
|
||||
if(chainActive.Tip()->GetBlockHash() == block.hashPrevBlock){
|
||||
int64_t masternodePaymentAmount = GetMasternodePayment(chainActive.Tip()->nHeight+1, block.vtx[0].GetValueOut());
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
|
||||
// If we don't already have its previous block, skip masternode payment step
|
||||
if (!fIsInitialDownload && chainActive.Tip() != NULL)
|
||||
{
|
||||
bool foundPaymentAmount = false;
|
||||
bool foundPayee = false;
|
||||
|
||||
CScript payee;
|
||||
if(!masternodePayments.GetBlockPayee(chainActive.Tip()->nHeight+1, payee) || payee == CScript()){
|
||||
foundPayee = true; //doesn't require a specific payee
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < block.vtx[0].vout.size(); i++) {
|
||||
if(block.vtx[0].vout[i].nValue == masternodePaymentAmount )
|
||||
foundPaymentAmount = true;
|
||||
if(block.vtx[0].vout[i].scriptPubKey == payee )
|
||||
foundPayee = true;
|
||||
}
|
||||
|
||||
if(!foundPaymentAmount || !foundPayee) {
|
||||
CTxDestination address1;
|
||||
ExtractDestination(payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
LogPrintf("CheckBlock() : Couldn't find masternode payment(%d|%d) or payee(%d|%s) nHeight %d. \n", foundPaymentAmount, masternodePaymentAmount, foundPayee, address2.ToString().c_str(), chainActive.Tip()->nHeight+1);
|
||||
return state.DoS(100, error("CheckBlock() : Couldn't find masternode payment or payee"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LogPrintf("CheckBlock() : Skipping masternode payment check - nHeight %d Hash %s\n", chainActive.Tip()->nHeight+1, block.GetHash().ToString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check transactions
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
if (!CheckTransaction(tx, state))
|
||||
@ -4309,13 +4669,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
LogPrint("net", "Reject %s\n", SanitizeString(ss.str()));
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Ignore unknown commands for extensibility
|
||||
//probably one the extensions
|
||||
ProcessMessageDarksend(pfrom, strCommand, vRecv);
|
||||
ProcessMessageMasternode(pfrom, strCommand, vRecv);
|
||||
ProcessMessageInstantX(pfrom, strCommand, vRecv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Update the last seen time for this node's address
|
||||
if (pfrom->fNetworkNode)
|
||||
if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")
|
||||
|
14
src/main.h
14
src/main.h
@ -30,9 +30,6 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#define START_MASTERNODE_PAYMENTS_TESTNET 1403568776 //Tue, 24 Jun 2014 00:12:56 GMT
|
||||
#define START_MASTERNODE_PAYMENTS 1403728576 //Wed, 25 Jun 2014 20:36:16 GMT
|
||||
|
||||
// Define difficulty retarget algorithms
|
||||
enum DiffMode {
|
||||
DIFF_DEFAULT = 0, // Default to invalid 0
|
||||
@ -201,13 +198,11 @@ void Misbehaving(NodeId nodeid, int howmuch);
|
||||
|
||||
/** (try to) add transaction to memory pool **/
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fRejectInsaneFee=false);
|
||||
|
||||
|
||||
|
||||
|
||||
bool* pfMissingInputs, bool fRejectInsaneFee=false, bool ignoreFees=false);
|
||||
|
||||
bool AcceptableInputs(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool ignoreFees=true);
|
||||
|
||||
int GetInputAge(CTxIn& vin);
|
||||
|
||||
|
||||
struct CNodeStateStats {
|
||||
@ -608,6 +603,9 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
|
||||
* of problems. Note that in any case, coins may be modified. */
|
||||
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
|
||||
|
||||
/** Find a conflicting transcation in a block and disconnect all up to that point **/
|
||||
bool DisconnectBlockAndInputs(CValidationState &state, CTransaction txLock);
|
||||
|
||||
// Apply the effects of this block (with given index) on the UTXO set represented by coins
|
||||
bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
|
||||
|
||||
|
828
src/masternode.cpp
Normal file
828
src/masternode.cpp
Normal file
@ -0,0 +1,828 @@
|
||||
|
||||
|
||||
#include "masternode.h"
|
||||
#include "activemasternode.h"
|
||||
#include "darksend.h"
|
||||
#include "core.h"
|
||||
#include "util.h"
|
||||
#include "addrman.h"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
/** The list of active masternodes */
|
||||
std::vector<CMasterNode> darkSendMasterNodes;
|
||||
/** Object for who's going to get paid on which blocks */
|
||||
CMasternodePayments masternodePayments;
|
||||
// keep track of masternode votes I've seen
|
||||
map<uint256, int> mapSeenMasternodeVotes;
|
||||
// keep track of the scanning errors I've seen
|
||||
map<uint256, int> mapSeenMasternodeScanningErrors;
|
||||
// who's asked for the masternode list and the last time
|
||||
std::map<CNetAddr, int64_t> askedForMasternodeList;
|
||||
// which masternodes we've asked for
|
||||
std::map<COutPoint, int64_t> askedForMasternodeListEntry;
|
||||
|
||||
// manage the masternode connections
|
||||
void ProcessMasternodeConnections(){
|
||||
LOCK(cs_vNodes);
|
||||
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
//if it's our masternode, let it be
|
||||
if(darkSendPool.submittedToMasternode == pnode->addr) continue;
|
||||
|
||||
if(pnode->fDarkSendMaster){
|
||||
LogPrintf("Closing masternode connection %s \n", pnode->addr.ToString().c_str());
|
||||
pnode->CloseSocketDisconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
{
|
||||
if (strCommand == "dsee") { //DarkSend Election Entry
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
if(fIsInitialDownload) return;
|
||||
|
||||
CTxIn vin;
|
||||
CService addr;
|
||||
CPubKey pubkey;
|
||||
CPubKey pubkey2;
|
||||
vector<unsigned char> vchSig;
|
||||
int64_t sigTime;
|
||||
int count;
|
||||
int current;
|
||||
int64_t lastUpdated;
|
||||
int protocolVersion;
|
||||
std::string strMessage;
|
||||
|
||||
// 70047 and greater
|
||||
vRecv >> vin >> addr >> vchSig >> sigTime >> pubkey >> pubkey2 >> count >> current >> lastUpdated >> protocolVersion;
|
||||
|
||||
// make sure signature isn't in the future (past is OK)
|
||||
if (sigTime > GetAdjustedTime() + 60 * 60) {
|
||||
LogPrintf("dsee - Signature rejected, too far into the future %s\n", vin.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
bool isLocal = false; // addr.IsRFC1918();
|
||||
std::string vchPubKey(pubkey.begin(), pubkey.end());
|
||||
std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
|
||||
|
||||
strMessage = addr.ToString() + boost::lexical_cast<std::string>(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(protocolVersion);
|
||||
|
||||
if(protocolVersion < nMasternodeMinProtocol) {
|
||||
LogPrintf("dsee - ignoring outdated masternode %s protocol version %d\n", vin.ToString().c_str(), protocolVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
CScript pubkeyScript;
|
||||
pubkeyScript.SetDestination(pubkey.GetID());
|
||||
|
||||
if(pubkeyScript.size() != 25) {
|
||||
LogPrintf("dsee - pubkey the wrong size\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
CScript pubkeyScript2;
|
||||
pubkeyScript2.SetDestination(pubkey2.GetID());
|
||||
|
||||
if(pubkeyScript2.size() != 25) {
|
||||
LogPrintf("dsee - pubkey the wrong size\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string errorMessage = "";
|
||||
if(!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)){
|
||||
LogPrintf("dsee - Got bad masternode address signature\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
if((Params().NetworkID() == CChainParams::TESTNET && addr.GetPort() != 19999) || (!(Params().NetworkID() == CChainParams::TESTNET) && addr.GetPort() != 9999)) return;
|
||||
|
||||
//search existing masternode list, this is where we update existing masternodes with new dsee broadcasts
|
||||
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {
|
||||
if(mn.vin.prevout == vin.prevout) {
|
||||
// count == -1 when it's a new entry
|
||||
// e.g. We don't want the entry relayed/time updated when we're syncing the list
|
||||
// mn.pubkey = pubkey, IsVinAssociatedWithPubkey is validated once below,
|
||||
// after that they just need to match
|
||||
if(count == -1 && mn.pubkey == pubkey && !mn.UpdatedWithin(MASTERNODE_MIN_DSEE_SECONDS)){
|
||||
mn.UpdateLastSeen();
|
||||
|
||||
if(mn.now < sigTime){ //take the newest entry
|
||||
LogPrintf("dsee - Got updated entry for %s\n", addr.ToString().c_str());
|
||||
mn.pubkey2 = pubkey2;
|
||||
mn.now = sigTime;
|
||||
mn.sig = vchSig;
|
||||
mn.protocolVersion = protocolVersion;
|
||||
mn.addr = addr;
|
||||
|
||||
RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the vout that was signed is related to the transaction that spawned the masternode
|
||||
// - this is expensive, so it's only done once per masternode
|
||||
/* if(!darkSendSigner.IsVinAssociatedWithPubkey(vin, pubkey)) {
|
||||
LogPrintf("dsee - Got mismatched pubkey and vin\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
if(fDebug) LogPrintf("dsee - Got NEW masternode entry %s\n", addr.ToString().c_str());
|
||||
|
||||
// make sure it's still unspent
|
||||
// - this is checked later by .check() in many places and by ThreadCheckDarkSendPool()
|
||||
|
||||
CValidationState state;
|
||||
CTransaction tx = CTransaction();
|
||||
CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey);
|
||||
tx.vin.push_back(vin);
|
||||
tx.vout.push_back(vout);
|
||||
if(AcceptableInputs(mempool, state, tx)){
|
||||
if(fDebug) LogPrintf("dsee - Accepted masternode entry %i %i\n", count, current);
|
||||
|
||||
if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){
|
||||
LogPrintf("dsee - Input must have least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS);
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
return;
|
||||
}
|
||||
|
||||
// use this as a peer
|
||||
addrman.Add(CAddress(addr), pfrom->addr, 2*60*60);
|
||||
|
||||
// add our masternode
|
||||
CMasterNode mn(addr, vin, pubkey, vchSig, sigTime, pubkey2, protocolVersion);
|
||||
mn.UpdateLastSeen(lastUpdated);
|
||||
darkSendMasterNodes.push_back(mn);
|
||||
|
||||
/*// if it matches our masternodeprivkey, then we've been remotely activated
|
||||
if(pubkey2 == activeMasternode.pubkeyMasterNode2 && protocolVersion == PROTOCOL_VERSION){
|
||||
activeMasternode.EnableHotColdMasterNode(vin, sigTime, addr);
|
||||
}*/
|
||||
|
||||
if(count == -1 && !isLocal)
|
||||
RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion);
|
||||
|
||||
} else {
|
||||
LogPrintf("dsee - Rejected masternode entry %s\n", addr.ToString().c_str());
|
||||
|
||||
int nDoS = 0;
|
||||
if (state.IsInvalid(nDoS))
|
||||
{
|
||||
LogPrintf("dsee - %s from %s %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(),
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str());
|
||||
if (nDoS > 0)
|
||||
Misbehaving(pfrom->GetId(), nDoS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (strCommand == "dseep") { //DarkSend Election Entry Ping
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
if(fIsInitialDownload) return;
|
||||
|
||||
CTxIn vin;
|
||||
vector<unsigned char> vchSig;
|
||||
int64_t sigTime;
|
||||
bool stop;
|
||||
vRecv >> vin >> vchSig >> sigTime >> stop;
|
||||
|
||||
if (sigTime > GetAdjustedTime() + 60 * 60) {
|
||||
LogPrintf("dseep - Signature rejected, too far into the future %s\n", vin.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (sigTime <= GetAdjustedTime() - 60 * 60) {
|
||||
LogPrintf("dseep - Signature rejected, too far into the past %s - %d %d \n", vin.ToString().c_str(), sigTime, GetAdjustedTime());
|
||||
return;
|
||||
}
|
||||
|
||||
// see if we have this masternode
|
||||
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {
|
||||
if(mn.vin.prevout == vin.prevout) {
|
||||
// take this only if it's newer
|
||||
if(mn.lastDseep < sigTime){
|
||||
std::string strMessage = mn.addr.ToString() + boost::lexical_cast<std::string>(sigTime) + boost::lexical_cast<std::string>(stop);
|
||||
|
||||
std::string errorMessage = "";
|
||||
if(!darkSendSigner.VerifyMessage(mn.pubkey2, vchSig, strMessage, errorMessage)){
|
||||
LogPrintf("dseep - Got bad masternode address signature %s \n", vin.ToString().c_str());
|
||||
//Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
mn.lastDseep = sigTime;
|
||||
|
||||
if(!mn.UpdatedWithin(MASTERNODE_MIN_DSEEP_SECONDS)){
|
||||
mn.UpdateLastSeen();
|
||||
if(stop) {
|
||||
mn.Disable();
|
||||
mn.Check();
|
||||
}
|
||||
RelayDarkSendElectionEntryPing(vin, vchSig, sigTime, stop);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(fDebug) LogPrintf("dseep - Couldn't find masternode entry %s\n", vin.ToString().c_str());
|
||||
|
||||
std::map<COutPoint, int64_t>::iterator i = askedForMasternodeListEntry.find(vin.prevout);
|
||||
if (i != askedForMasternodeListEntry.end()){
|
||||
int64_t t = (*i).second;
|
||||
if (GetTime() < t) {
|
||||
// we've asked recently
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ask for the dsee info once from the node that sent dseep
|
||||
|
||||
LogPrintf("dseep - Asking source node for missing entry %s\n", vin.ToString().c_str());
|
||||
pfrom->PushMessage("dseg", vin);
|
||||
int64_t askAgain = GetTime()+(60*60*24);
|
||||
askedForMasternodeListEntry[vin.prevout] = askAgain;
|
||||
|
||||
} else if (strCommand == "dseg") { //Get masternode list or specific entry
|
||||
CTxIn vin;
|
||||
vRecv >> vin;
|
||||
|
||||
if(vin == CTxIn()) { //only should ask for this once
|
||||
//local network
|
||||
if(!pfrom->addr.IsRFC1918())
|
||||
{
|
||||
std::map<CNetAddr, int64_t>::iterator i = askedForMasternodeList.find(pfrom->addr);
|
||||
if (i != askedForMasternodeList.end())
|
||||
{
|
||||
int64_t t = (*i).second;
|
||||
if (GetTime() < t) {
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
LogPrintf("dseg - peer already asked me for the list\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t askAgain = GetTime()+(60*60*24);
|
||||
askedForMasternodeList[pfrom->addr] = askAgain;
|
||||
}
|
||||
} //else, asking for a specific node which is ok
|
||||
|
||||
int count = darkSendMasterNodes.size()-1;
|
||||
int i = 0;
|
||||
|
||||
BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
|
||||
|
||||
if(mn.addr.IsRFC1918()) continue; //local network
|
||||
|
||||
if(vin == CTxIn()){
|
||||
mn.Check();
|
||||
if(mn.IsEnabled()) {
|
||||
if(fDebug) LogPrintf("dseg - Sending masternode entry - %s \n", mn.addr.ToString().c_str());
|
||||
pfrom->PushMessage("dsee", mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2, count, i, mn.lastTimeSeen, mn.protocolVersion);
|
||||
}
|
||||
} else if (vin == mn.vin) {
|
||||
if(fDebug) LogPrintf("dseg - Sending masternode entry - %s \n", mn.addr.ToString().c_str());
|
||||
pfrom->PushMessage("dsee", mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2, count, i, mn.lastTimeSeen, mn.protocolVersion);
|
||||
LogPrintf("dseg - Sent 1 masternode entries to %s\n", pfrom->addr.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
LogPrintf("dseg - Sent %d masternode entries to %s\n", count, pfrom->addr.ToString().c_str());
|
||||
}
|
||||
|
||||
else if (strCommand == "mnget") { //Masternode Payments Request Sync
|
||||
|
||||
if(pfrom->HasFulfilledRequest("mnget")) {
|
||||
LogPrintf("mnget - peer already asked me for the list\n");
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
return;
|
||||
}
|
||||
|
||||
pfrom->FulfilledRequest("mnget");
|
||||
masternodePayments.Sync(pfrom);
|
||||
LogPrintf("mnget - Sent masternode winners to %s\n", pfrom->addr.ToString().c_str());
|
||||
}
|
||||
else if (strCommand == "mnw") { //Masternode Payments Declare Winner
|
||||
CMasternodePaymentWinner winner;
|
||||
vRecv >> winner;
|
||||
|
||||
if(chainActive.Tip() == NULL) return;
|
||||
|
||||
uint256 hash = winner.GetHash();
|
||||
if(mapSeenMasternodeVotes.count(hash)) {
|
||||
if(fDebug) LogPrintf("mnw - seen vote %s Height %d bestHeight %d\n", hash.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
if(winner.nBlockHeight < chainActive.Tip()->nHeight - 10 || winner.nBlockHeight > chainActive.Tip()->nHeight+20){
|
||||
LogPrintf("mnw - winner out of range %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
if(winner.vin.nSequence != std::numeric_limits<unsigned int>::max()){
|
||||
LogPrintf("mnw - invalid nSequence\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("mnw - winning vote %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight);
|
||||
|
||||
if(!masternodePayments.CheckSignature(winner)){
|
||||
LogPrintf("mnw - invalid signature\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
mapSeenMasternodeVotes.insert(make_pair(hash, 1));
|
||||
|
||||
if(masternodePayments.AddWinningMasternode(winner)){
|
||||
masternodePayments.Relay(winner);
|
||||
}
|
||||
} /*else if (strCommand == "mnse") { //Masternode Scanning Error
|
||||
CMasternodeScanningError entry;
|
||||
vRecv >> entry;
|
||||
|
||||
if(chainActive.Tip() == NULL) return;
|
||||
|
||||
uint256 hash = entry.GetHash();
|
||||
if(mapSeenMasternodeScanningErrors.count(hash)) {
|
||||
if(fDebug) LogPrintf("mnse - seen entry addr %d error %d\n", entry.addr.ToString().c_str(), entry.error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("mnse - seen entry addr %d error %d\n", entry.addr.ToString().c_str(), entry.error.c_str());
|
||||
|
||||
if(!masternodeScanningError.CheckSignature(entry)){
|
||||
LogPrintf("mnse - invalid signature\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
mapSeenMasternodeVotes.insert(make_pair(hash, 1));
|
||||
|
||||
if(masternodeScanningError.AddWinningMasternode(entry)){
|
||||
masternodeScanningError.Relay(entry);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
struct CompareValueOnly
|
||||
{
|
||||
bool operator()(const pair<int64_t, CTxIn>& t1,
|
||||
const pair<int64_t, CTxIn>& t2) const
|
||||
{
|
||||
return t1.first < t2.first;
|
||||
}
|
||||
};
|
||||
|
||||
struct CompareValueOnly2
|
||||
{
|
||||
bool operator()(const pair<int64_t, int>& t1,
|
||||
const pair<int64_t, int>& t2) const
|
||||
{
|
||||
return t1.first < t2.first;
|
||||
}
|
||||
};
|
||||
|
||||
int CountMasternodesAboveProtocol(int protocolVersion)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {
|
||||
if(mn.protocolVersion < protocolVersion) continue;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int GetMasternodeByVin(CTxIn& vin)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {
|
||||
if (mn.vin == vin) return i;
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GetCurrentMasterNode(int mod, int64_t nBlockHeight, int minProtocol)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned int score = 0;
|
||||
int winner = -1;
|
||||
|
||||
// scan for winner
|
||||
BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
|
||||
mn.Check();
|
||||
if(mn.protocolVersion < minProtocol) continue;
|
||||
if(!mn.IsEnabled()) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// calculate the score for each masternode
|
||||
uint256 n = mn.CalculateScore(mod, nBlockHeight);
|
||||
unsigned int n2 = 0;
|
||||
memcpy(&n2, &n, sizeof(n2));
|
||||
|
||||
// determine the winner
|
||||
if(n2 > score){
|
||||
score = n2;
|
||||
winner = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return winner;
|
||||
}
|
||||
|
||||
int GetMasternodeByRank(int findRank, int64_t nBlockHeight, int minProtocol)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
std::vector<pair<unsigned int, int> > vecMasternodeScores;
|
||||
|
||||
i = 0;
|
||||
BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
|
||||
mn.Check();
|
||||
if(mn.protocolVersion < minProtocol) continue;
|
||||
if(!mn.IsEnabled()) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint256 n = mn.CalculateScore(1, nBlockHeight);
|
||||
unsigned int n2 = 0;
|
||||
memcpy(&n2, &n, sizeof(n2));
|
||||
|
||||
vecMasternodeScores.push_back(make_pair(n2, i));
|
||||
i++;
|
||||
}
|
||||
|
||||
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly2());
|
||||
|
||||
int rank = 0;
|
||||
BOOST_FOREACH (PAIRTYPE(unsigned int, int)& s, vecMasternodeScores){
|
||||
rank++;
|
||||
if(rank == findRank) return s.second;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GetMasternodeRank(CTxIn& vin, int64_t nBlockHeight, int minProtocol)
|
||||
{
|
||||
std::vector<pair<unsigned int, CTxIn> > vecMasternodeScores;
|
||||
|
||||
BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
|
||||
mn.Check();
|
||||
if(mn.protocolVersion < minProtocol) continue;
|
||||
if(!mn.IsEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint256 n = mn.CalculateScore(1, nBlockHeight);
|
||||
unsigned int n2 = 0;
|
||||
memcpy(&n2, &n, sizeof(n2));
|
||||
|
||||
vecMasternodeScores.push_back(make_pair(n2, mn.vin));
|
||||
}
|
||||
|
||||
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly());
|
||||
|
||||
unsigned int rank = 0;
|
||||
BOOST_FOREACH (PAIRTYPE(unsigned int, CTxIn)& s, vecMasternodeScores){
|
||||
rank++;
|
||||
if(s.second == vin) return rank;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Deterministically calculate a given "score" for a masternode depending on how close it's hash is to
|
||||
// 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
|
||||
//
|
||||
uint256 CMasterNode::CalculateScore(int mod, int64_t nBlockHeight)
|
||||
{
|
||||
if(chainActive.Tip() == NULL) return 0;
|
||||
|
||||
uint256 hash = 0;
|
||||
if(!darkSendPool.GetLastValidBlockHash(hash, mod, nBlockHeight)) return 0;
|
||||
uint256 hash2 = HashX11(BEGIN(hash), END(hash));
|
||||
|
||||
// we'll make a 4 dimensional point in space
|
||||
// the closest masternode to that point wins
|
||||
uint64_t a1 = hash2.Get64(0);
|
||||
uint64_t a2 = hash2.Get64(1);
|
||||
uint64_t a3 = hash2.Get64(2);
|
||||
uint64_t a4 = hash2.Get64(3);
|
||||
|
||||
//copy part of our source hash
|
||||
int i1, i2, i3, i4;
|
||||
i1=0;i2=0;i3=0;i4=0;
|
||||
memcpy(&i1, &a1, 1);
|
||||
memcpy(&i2, &a2, 1);
|
||||
memcpy(&i3, &a3, 1);
|
||||
memcpy(&i4, &a4, 1);
|
||||
|
||||
//split up our mn hash
|
||||
uint64_t b1 = vin.prevout.hash.Get64(0);
|
||||
uint64_t b2 = vin.prevout.hash.Get64(1);
|
||||
uint64_t b3 = vin.prevout.hash.Get64(2);
|
||||
uint64_t b4 = vin.prevout.hash.Get64(3);
|
||||
|
||||
//move mn hash around
|
||||
b1 <<= (i1 % 64);
|
||||
b2 <<= (i2 % 64);
|
||||
b3 <<= (i3 % 64);
|
||||
b4 <<= (i4 % 64);
|
||||
|
||||
// calculate distance between target point and mn point
|
||||
uint256 r = 0;
|
||||
r += (a1 > b1 ? a1 - b1 : b1 - a1);
|
||||
r += (a2 > b2 ? a2 - b2 : b2 - a2);
|
||||
r += (a3 > b3 ? a3 - b3 : b3 - a3);
|
||||
r += (a4 > b4 ? a4 - b4 : b4 - a4);
|
||||
|
||||
/*
|
||||
LogPrintf(" -- MasterNode CalculateScore() n2 = %s \n", n2.ToString().c_str());
|
||||
LogPrintf(" -- MasterNode CalculateScore() vin = %s \n", vin.prevout.hash.GetHex().c_str());
|
||||
LogPrintf(" -- MasterNode CalculateScore() n3 = %s \n", n3.ToString().c_str());*/
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void CMasterNode::Check()
|
||||
{
|
||||
//once spent, stop doing the checks
|
||||
if(enabled==3) return;
|
||||
|
||||
|
||||
if(!UpdatedWithin(MASTERNODE_REMOVAL_SECONDS)){
|
||||
enabled = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!UpdatedWithin(MASTERNODE_EXPIRATION_SECONDS)){
|
||||
enabled = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!unitTest){
|
||||
CValidationState state;
|
||||
CTransaction tx = CTransaction();
|
||||
CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey);
|
||||
tx.vin.push_back(vin);
|
||||
tx.vout.push_back(vout);
|
||||
|
||||
if(!AcceptableInputs(mempool, state, tx)){
|
||||
enabled = 3;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
enabled = 1; // OK
|
||||
}
|
||||
|
||||
bool CMasternodePayments::CheckSignature(CMasternodePaymentWinner& winner)
|
||||
{
|
||||
//note: need to investigate why this is failing
|
||||
/* std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast<std::string>(winner.nBlockHeight);
|
||||
std::string strPubKey = (Params().NetworkID() == CChainParams::TESTNET) ? strTestPubKey : strMainPubKey;
|
||||
CPubKey pubkey(ParseHex(strPubKey));
|
||||
|
||||
std::string errorMessage = "";
|
||||
if(!darkSendSigner.VerifyMessage(pubkey, winner.vchSig, strMessage, errorMessage)){
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMasternodePayments::Sign(CMasternodePaymentWinner& winner)
|
||||
{
|
||||
std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast<std::string>(winner.nBlockHeight);
|
||||
|
||||
CKey key2;
|
||||
CPubKey pubkey2;
|
||||
std::string errorMessage = "";
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2))
|
||||
{
|
||||
LogPrintf("CMasternodePayments::Sign - Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, winner.vchSig, key2)) {
|
||||
LogPrintf("CMasternodePayments::Sign - Sign message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkey2, winner.vchSig, strMessage, errorMessage)) {
|
||||
LogPrintf("CMasternodePayments::Sign - Verify message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t CMasternodePayments::CalculateScore(uint256 blockHash, CTxIn& vin)
|
||||
{
|
||||
uint256 n1 = blockHash;
|
||||
uint256 n2 = HashX11(BEGIN(n1), END(n1));
|
||||
uint256 n3 = HashX11(BEGIN(vin.prevout.hash), END(vin.prevout.hash));
|
||||
uint256 n4 = n3 > n2 ? (n3 - n2) : (n2 - n3);
|
||||
|
||||
//printf(" -- CMasternodePayments CalculateScore() n2 = %d \n", n2.Get64());
|
||||
//printf(" -- CMasternodePayments CalculateScore() n3 = %d \n", n3.Get64());
|
||||
//printf(" -- CMasternodePayments CalculateScore() n4 = %d \n", n4.Get64());
|
||||
|
||||
return n4.Get64();
|
||||
}
|
||||
|
||||
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
|
||||
{
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
|
||||
if(winner.nBlockHeight == nBlockHeight) {
|
||||
|
||||
CTransaction tx;
|
||||
uint256 hash;
|
||||
if(GetTransaction(winner.vin.prevout.hash, tx, hash, true)){
|
||||
BOOST_FOREACH(CTxOut out, tx.vout){
|
||||
if(out.nValue == 1000*COIN){
|
||||
payee = out.scriptPubKey;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMasternodePayments::GetWinningMasternode(int nBlockHeight, CTxIn& vinOut)
|
||||
{
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
|
||||
if(winner.nBlockHeight == nBlockHeight) {
|
||||
vinOut = winner.vin;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
|
||||
{
|
||||
uint256 blockHash = 0;
|
||||
if(!darkSendPool.GetBlockHash(blockHash, winnerIn.nBlockHeight-576)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
winnerIn.score = CalculateScore(blockHash, winnerIn.vin);
|
||||
|
||||
bool foundBlock = false;
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
|
||||
if(winner.nBlockHeight == winnerIn.nBlockHeight) {
|
||||
foundBlock = true;
|
||||
if(winner.score < winnerIn.score){
|
||||
winner.score = winnerIn.score;
|
||||
winner.vin = winnerIn.vin;
|
||||
winner.vchSig = winnerIn.vchSig;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it's not in the vector
|
||||
if(!foundBlock){
|
||||
vWinning.push_back(winnerIn);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CMasternodePayments::CleanPaymentList()
|
||||
{
|
||||
if(chainActive.Tip() == NULL) return;
|
||||
|
||||
vector<CMasternodePaymentWinner>::iterator it;
|
||||
for(it=vWinning.begin();it<vWinning.end();it++){
|
||||
if(chainActive.Tip()->nHeight - (*it).nBlockHeight > 1000){
|
||||
if(fDebug) LogPrintf("CMasternodePayments::CleanPaymentList - Removing old masternode payment - block %d\n", (*it).nBlockHeight);
|
||||
vWinning.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CMasternodePayments::LastPayment(CMasterNode& mn)
|
||||
{
|
||||
if(chainActive.Tip() == NULL) return 0;
|
||||
|
||||
int ret = mn.GetMasternodeInputAge();
|
||||
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
|
||||
if(winner.vin == mn.vin && chainActive.Tip()->nHeight - winner.nBlockHeight < ret)
|
||||
ret = chainActive.Tip()->nHeight - winner.nBlockHeight;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
|
||||
{
|
||||
if(strMasterPrivKey.empty()) return false;
|
||||
CMasternodePaymentWinner winner;
|
||||
|
||||
uint256 blockHash = 0;
|
||||
if(!darkSendPool.GetBlockHash(blockHash, nBlockHeight-576)) return false;
|
||||
|
||||
BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) {
|
||||
mn.Check();
|
||||
|
||||
if(!mn.IsEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(LastPayment(mn) < darkSendMasterNodes.size()*.9) continue;
|
||||
|
||||
uint64_t score = CalculateScore(blockHash, mn.vin);
|
||||
if(score > winner.score){
|
||||
winner.score = score;
|
||||
winner.nBlockHeight = nBlockHeight;
|
||||
winner.vin = mn.vin;
|
||||
}
|
||||
}
|
||||
|
||||
if(winner.nBlockHeight == 0) return false; //no masternodes available
|
||||
|
||||
if(Sign(winner)){
|
||||
if(AddWinningMasternode(winner)){
|
||||
Relay(winner);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CMasternodePayments::Relay(CMasternodePaymentWinner& winner)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes){
|
||||
if(!pnode->fRelayTxes)
|
||||
continue;
|
||||
|
||||
pnode->PushMessage("mnw", winner);
|
||||
}
|
||||
}
|
||||
|
||||
void CMasternodePayments::Sync(CNode* node)
|
||||
{
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning)
|
||||
if(winner.nBlockHeight >= chainActive.Tip()->nHeight-10 && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20)
|
||||
node->PushMessage("mnw", winner);
|
||||
}
|
||||
|
||||
|
||||
bool CMasternodePayments::SetPrivKey(std::string strPrivKey)
|
||||
{
|
||||
CMasternodePaymentWinner winner;
|
||||
|
||||
// Test signing successful, proceed
|
||||
strMasterPrivKey = strPrivKey;
|
||||
|
||||
Sign(winner);
|
||||
|
||||
if(CheckSignature(winner)){
|
||||
LogPrintf("CMasternodePayments::SetPrivKey - Successfully initialized as masternode payments master\n");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
272
src/masternode.h
Normal file
272
src/masternode.h
Normal file
@ -0,0 +1,272 @@
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef MASTERNODE_H
|
||||
#define MASTERNODE_H
|
||||
|
||||
#include "bignum.h"
|
||||
#include "sync.h"
|
||||
#include "net.h"
|
||||
#include "key.h"
|
||||
#include "core.h"
|
||||
#include "util.h"
|
||||
#include "script.h"
|
||||
#include "base58.h"
|
||||
#include "main.h"
|
||||
|
||||
class CMasterNode;
|
||||
class CMasternodePayments;
|
||||
|
||||
#define MASTERNODE_NOT_PROCESSED 0 // initial state
|
||||
#define MASTERNODE_IS_CAPABLE 1
|
||||
#define MASTERNODE_NOT_CAPABLE 2
|
||||
#define MASTERNODE_STOPPED 3
|
||||
#define MASTERNODE_INPUT_TOO_NEW 4
|
||||
#define MASTERNODE_PORT_NOT_OPEN 6
|
||||
#define MASTERNODE_PORT_OPEN 7
|
||||
#define MASTERNODE_SYNC_IN_PROCESS 8
|
||||
#define MASTERNODE_REMOTELY_ENABLED 9
|
||||
|
||||
#define MASTERNODE_MIN_CONFIRMATIONS 15
|
||||
#define MASTERNODE_MIN_DSEEP_SECONDS (30*60)
|
||||
#define MASTERNODE_MIN_DSEE_SECONDS (5*60)
|
||||
#define MASTERNODE_PING_SECONDS (1*60)
|
||||
#define MASTERNODE_EXPIRATION_SECONDS (65*60)
|
||||
#define MASTERNODE_REMOVAL_SECONDS (70*60)
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern std::vector<CMasterNode> darkSendMasterNodes;
|
||||
extern CMasternodePayments masternodePayments;
|
||||
extern std::vector<CTxIn> vecMasternodeAskedFor;
|
||||
extern map<uint256, int> mapSeenMasternodeVotes;
|
||||
|
||||
|
||||
// manage the masternode connections
|
||||
void ProcessMasternodeConnections();
|
||||
int CountMasternodesAboveProtocol(int protocolVersion);
|
||||
|
||||
// Get the current winner for this block
|
||||
int GetCurrentMasterNode(int mod=1, int64_t nBlockHeight=0, int minProtocol=0);
|
||||
|
||||
int GetMasternodeByVin(CTxIn& vin);
|
||||
int GetMasternodeRank(CTxIn& vin, int64_t nBlockHeight=0, int minProtocol=0);
|
||||
int GetMasternodeByRank(int findRank, int64_t nBlockHeight=0, int minProtocol=0);
|
||||
|
||||
void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
|
||||
//
|
||||
// The Masternode Class. For managing the darksend process. It contains the input of the 1000DRK, signature to prove
|
||||
// it's the one who own that ip address and code for calculating the payment election.
|
||||
//
|
||||
class CMasterNode
|
||||
{
|
||||
public:
|
||||
CService addr;
|
||||
CTxIn vin;
|
||||
int64_t lastTimeSeen;
|
||||
CPubKey pubkey;
|
||||
CPubKey pubkey2;
|
||||
std::vector<unsigned char> sig;
|
||||
int64_t now; //dsee message times
|
||||
int64_t lastDseep;
|
||||
int cacheInputAge;
|
||||
int cacheInputAgeBlock;
|
||||
int enabled;
|
||||
bool unitTest;
|
||||
bool allowFreeTx;
|
||||
int protocolVersion;
|
||||
|
||||
//the dsq count from the last dsq broadcast of this node
|
||||
int64_t nLastDsq;
|
||||
|
||||
CMasterNode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector<unsigned char> newSig, int64_t newNow, CPubKey newPubkey2, int protocolVersionIn)
|
||||
{
|
||||
addr = newAddr;
|
||||
vin = newVin;
|
||||
pubkey = newPubkey;
|
||||
pubkey2 = newPubkey2;
|
||||
sig = newSig;
|
||||
now = newNow;
|
||||
enabled = 1;
|
||||
lastTimeSeen = 0;
|
||||
unitTest = false;
|
||||
cacheInputAge = 0;
|
||||
cacheInputAgeBlock = 0;
|
||||
nLastDsq = 0;
|
||||
lastDseep = 0;
|
||||
allowFreeTx = true;
|
||||
protocolVersion = protocolVersionIn;
|
||||
}
|
||||
|
||||
uint256 CalculateScore(int mod=1, int64_t nBlockHeight=0);
|
||||
|
||||
void UpdateLastSeen(int64_t override=0)
|
||||
{
|
||||
if(override == 0){
|
||||
lastTimeSeen = GetAdjustedTime();
|
||||
} else {
|
||||
lastTimeSeen = override;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t SliceHash(uint256& hash, int slice)
|
||||
{
|
||||
uint64_t n = 0;
|
||||
memcpy(&n, &hash+slice*64, 64);
|
||||
return n;
|
||||
}
|
||||
|
||||
void Check();
|
||||
|
||||
bool UpdatedWithin(int seconds)
|
||||
{
|
||||
// LogPrintf("UpdatedWithin %d, %d -- %d \n", GetAdjustedTime() , lastTimeSeen, (GetAdjustedTime() - lastTimeSeen) < seconds);
|
||||
|
||||
return (GetAdjustedTime() - lastTimeSeen) < seconds;
|
||||
}
|
||||
|
||||
void Disable()
|
||||
{
|
||||
lastTimeSeen = 0;
|
||||
}
|
||||
|
||||
bool IsEnabled()
|
||||
{
|
||||
return enabled == 1;
|
||||
}
|
||||
|
||||
int GetMasternodeInputAge()
|
||||
{
|
||||
if(chainActive.Tip() == NULL) return 0;
|
||||
|
||||
if(cacheInputAge == 0){
|
||||
cacheInputAge = GetInputAge(vin);
|
||||
cacheInputAgeBlock = chainActive.Tip()->nHeight;
|
||||
}
|
||||
|
||||
return cacheInputAge+(chainActive.Tip()->nHeight-cacheInputAgeBlock);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// for storing the winning payments
|
||||
class CMasternodePaymentWinner
|
||||
{
|
||||
public:
|
||||
int nBlockHeight;
|
||||
CTxIn vin;
|
||||
std::vector<unsigned char> vchSig;
|
||||
uint64_t score;
|
||||
|
||||
CMasternodePaymentWinner() {
|
||||
nBlockHeight = 0;
|
||||
score = 0;
|
||||
vin = CTxIn();
|
||||
}
|
||||
|
||||
uint256 GetHash(){
|
||||
uint256 n2 = HashX11(BEGIN(nBlockHeight), END(nBlockHeight));
|
||||
uint256 n3 = vin.prevout.hash > n2 ? (vin.prevout.hash - n2) : (n2 - vin.prevout.hash);
|
||||
|
||||
return n3;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE(
|
||||
READWRITE(nBlockHeight);
|
||||
READWRITE(score);
|
||||
READWRITE(vin);
|
||||
READWRITE(vchSig);
|
||||
)
|
||||
};
|
||||
|
||||
//
|
||||
// Masternode Payments Class
|
||||
// Keeps track of who should get paid for which blocks
|
||||
//
|
||||
|
||||
class CMasternodePayments
|
||||
{
|
||||
private:
|
||||
std::vector<CMasternodePaymentWinner> vWinning;
|
||||
int nSyncedFromPeer;
|
||||
std::string strMasterPrivKey;
|
||||
std::string strTestPubKey;
|
||||
std::string strMainPubKey;
|
||||
|
||||
public:
|
||||
|
||||
CMasternodePayments() {
|
||||
strMainPubKey = "04549ac134f694c0243f503e8c8a9a986f5de6610049c40b07816809b0d1d06a21b07be27b9bb555931773f62ba6cf35a25fd52f694d4e1106ccd237a7bb899fdd";
|
||||
strTestPubKey = "046f78dcf911fbd61910136f7f0f8d90578f68d0b3ac973b5040fb7afb501b5939f39b108b0569dca71488f5bbf498d92e4d1194f6f941307ffd95f75e76869f0e";
|
||||
}
|
||||
|
||||
bool SetPrivKey(std::string strPrivKey);
|
||||
bool CheckSignature(CMasternodePaymentWinner& winner);
|
||||
bool Sign(CMasternodePaymentWinner& winner);
|
||||
|
||||
// Deterministically calculate a given "score" for a masternode depending on how close it's hash is
|
||||
// to the blockHeight. The further away they are the better, the furthest will win the election
|
||||
// and get paid this block
|
||||
//
|
||||
|
||||
uint64_t CalculateScore(uint256 blockHash, CTxIn& vin);
|
||||
bool GetWinningMasternode(int nBlockHeight, CTxIn& vinOut);
|
||||
bool AddWinningMasternode(CMasternodePaymentWinner& winner);
|
||||
bool ProcessBlock(int nBlockHeight);
|
||||
void Relay(CMasternodePaymentWinner& winner);
|
||||
void Sync(CNode* node);
|
||||
void CleanPaymentList();
|
||||
int LastPayment(CMasterNode& mn);
|
||||
|
||||
//slow
|
||||
bool GetBlockPayee(int nBlockHeight, CScript& payee);
|
||||
};
|
||||
|
||||
/*//
|
||||
// Masternode Scanning Error
|
||||
// Enforces proof-of-service by scanning the masternode network
|
||||
//
|
||||
|
||||
class CMasternodePayments
|
||||
{
|
||||
private:
|
||||
std::vector<CMasternodePaymentWinner> vWinning;
|
||||
int nSyncedFromPeer;
|
||||
std::string strMasterPrivKey;
|
||||
std::string strTestPubKey;
|
||||
std::string strMainPubKey;
|
||||
|
||||
public:
|
||||
|
||||
CMasternodePayments() {
|
||||
strMainPubKey = "04549ac134f694c0243f503e8c8a9a986f5de6610049c40b07816809b0d1d06a21b07be27b9bb555931773f62ba6cf35a25fd52f694d4e1106ccd237a7bb899fdd";
|
||||
strTestPubKey = "046f78dcf911fbd61910136f7f0f8d90578f68d0b3ac973b5040fb7afb501b5939f39b108b0569dca71488f5bbf498d92e4d1194f6f941307ffd95f75e76869f0e";
|
||||
}
|
||||
|
||||
bool SetPrivKey(std::string strPrivKey);
|
||||
bool CheckSignature(CMasternodePaymentWinner& winner);
|
||||
bool Sign(CMasternodePaymentWinner& winner);
|
||||
|
||||
// Deterministically calculate a given "score" for a masternode depending on how close it's hash is
|
||||
// to the blockHeight. The further away they are the better, the furthest will win the election
|
||||
// and get paid this block
|
||||
//
|
||||
|
||||
uint64_t CalculateScore(uint256 blockHash, CTxIn& vin);
|
||||
bool GetWinningMasternode(int nBlockHeight, CTxIn& vinOut);
|
||||
bool AddWinningMasternode(CMasternodePaymentWinner& winner);
|
||||
bool ProcessBlock(int nBlockHeight);
|
||||
void Relay(CMasternodePaymentWinner& winner);
|
||||
void Sync(CNode* node);
|
||||
void CleanPaymentList();
|
||||
int LastPayment(CMasterNode& mn);
|
||||
|
||||
//slow
|
||||
bool GetBlockPayee(int nBlockHeight, CScript& payee);
|
||||
};*/
|
||||
|
||||
|
||||
#endif
|
@ -113,6 +113,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
return NULL;
|
||||
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
||||
|
||||
int payments = 1;
|
||||
// Create coinbase tx
|
||||
CTransaction txNew;
|
||||
txNew.vin.resize(1);
|
||||
@ -140,6 +141,19 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE);
|
||||
nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
|
||||
|
||||
// start masternode payments
|
||||
bool bMasterNodePayment = false;
|
||||
|
||||
if ( Params().NetworkID() == CChainParams::TESTNET ){
|
||||
if (GetTimeMicros() > START_MASTERNODE_PAYMENTS_TESTNET ){
|
||||
bMasterNodePayment = true;
|
||||
}
|
||||
}else{
|
||||
if (GetTimeMicros() > START_MASTERNODE_PAYMENTS){
|
||||
bMasterNodePayment = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect memory pool transactions into the block
|
||||
int64_t nFees = 0;
|
||||
{
|
||||
@ -147,6 +161,35 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
CBlockIndex* pindexPrev = chainActive.Tip();
|
||||
CCoinsViewCache view(*pcoinsTip, true);
|
||||
|
||||
if(bMasterNodePayment) {
|
||||
bool hasPayment = true;
|
||||
//spork
|
||||
if(!masternodePayments.GetBlockPayee(pindexPrev->nHeight+1, pblock->payee)){
|
||||
//no masternode detected
|
||||
int winningNode = GetCurrentMasterNode(1);
|
||||
if(winningNode >= 0){
|
||||
pblock->payee.SetDestination(darkSendMasterNodes[winningNode].pubkey.GetID());
|
||||
} else {
|
||||
LogPrintf("CreateNewBlock: Failed to detect masternode to pay\n");
|
||||
hasPayment = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasPayment){
|
||||
payments++;
|
||||
txNew.vout.resize(payments);
|
||||
|
||||
txNew.vout[payments-1].scriptPubKey = pblock->payee;
|
||||
txNew.vout[payments-1].nValue = 0;
|
||||
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pblock->payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
LogPrintf("Masternode payment to %s\n", address2.ToString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Priority order to process transactions
|
||||
list<COrphan> vOrphan; // list memory doesn't move
|
||||
map<uint256, vector<COrphan*> > mapDependers;
|
||||
@ -322,7 +365,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
nLastBlockSize = nBlockSize;
|
||||
LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
|
||||
|
||||
pblock->vtx[0].vout[0].nValue = GetBlockValue(GetNextWorkRequired(pindexPrev, pblock), pindexPrev->nHeight+1, nFees);
|
||||
int64_t blockValue = GetBlockValue(GetNextWorkRequired(pindexPrev, pblock), pindexPrev->nHeight+1, nFees);
|
||||
int64_t masternodePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue);
|
||||
|
||||
//create masternode payment
|
||||
if(payments > 1){
|
||||
pblock->vtx[0].vout[payments-1].nValue = masternodePayment;
|
||||
blockValue -= masternodePayment;
|
||||
}
|
||||
pblock->vtx[0].vout[0].nValue = blockValue;
|
||||
|
||||
pblocktemplate->vTxFees[0] = -nFees;
|
||||
|
||||
// Fill in header
|
||||
|
90
src/net.cpp
90
src/net.cpp
@ -13,6 +13,8 @@
|
||||
#include "chainparams.h"
|
||||
#include "core.h"
|
||||
#include "ui_interface.h"
|
||||
#include "darksend.h"
|
||||
#include "wallet.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <string.h>
|
||||
@ -437,7 +439,7 @@ CNode* FindNode(const CService& addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool darkSendMaster)
|
||||
{
|
||||
if (pszDest == NULL) {
|
||||
if (IsLocal(addrConnect))
|
||||
@ -447,6 +449,9 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
|
||||
CNode* pnode = FindNode((CService)addrConnect);
|
||||
if (pnode)
|
||||
{
|
||||
if(darkSendMaster)
|
||||
pnode->fDarkSendMaster = true;
|
||||
|
||||
pnode->AddRef();
|
||||
return pnode;
|
||||
}
|
||||
@ -486,6 +491,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
|
||||
}
|
||||
|
||||
pnode->nTimeConnected = GetTime();
|
||||
if(darkSendMaster) pnode->fDarkSendMaster = true;
|
||||
return pnode;
|
||||
}
|
||||
else
|
||||
@ -1843,6 +1849,88 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RelayTransactionLockReq(const CTransaction& tx, const uint256& hash, bool relayToAll)
|
||||
{
|
||||
CInv inv(MSG_TXLOCK_REQUEST, tx.GetHash());
|
||||
|
||||
//broadcast the new lock
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if(!relayToAll && !pnode->fRelayTxes)
|
||||
continue;
|
||||
|
||||
//there's no requests for transactions locks, so we should show it was propagated correctly
|
||||
//pwalletMain->mapRequestCount[tx.GetHash()]++;
|
||||
|
||||
pnode->PushMessage("txlreq", tx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RelayDarkSendFinalTransaction(const int sessionID, const CTransaction& txNew)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
pnode->PushMessage("dsf", sessionID, txNew);
|
||||
}
|
||||
}
|
||||
|
||||
void RelayDarkSendIn(const std::vector<CTxIn>& in, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector<CTxOut>& out)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if(darkSendPool.submittedToMasternode != pnode->addr) continue;
|
||||
LogPrintf("RelayDarkSendIn - found master, relaying message - %s \n", pnode->addr.ToString().c_str());
|
||||
pnode->PushMessage("dsi", in, nAmount, txCollateral, out);
|
||||
}
|
||||
}
|
||||
|
||||
void RelayDarkSendStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const std::string error)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
pnode->PushMessage("dssu", sessionID, newState, newEntriesCount, newAccepted, error);
|
||||
}
|
||||
}
|
||||
|
||||
void RelayDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector<unsigned char> vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if(!pnode->fRelayTxes) continue;
|
||||
|
||||
pnode->PushMessage("dsee", vin, addr, vchSig, nNow, pubkey, pubkey2, count, current, lastUpdated, protocolVersion);
|
||||
}
|
||||
}
|
||||
|
||||
void RelayDarkSendElectionEntryPing(const CTxIn vin, const std::vector<unsigned char> vchSig, const int64_t nNow, const bool stop)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if(!pnode->fRelayTxes) continue;
|
||||
|
||||
pnode->PushMessage("dseep", vin, vchSig, nNow, stop);
|
||||
}
|
||||
}
|
||||
|
||||
void RelayDarkSendCompletedTransaction(const int sessionID, const bool error, const std::string errorMessage)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
pnode->PushMessage("dsc", sessionID, error, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CNode::RecordBytesRecv(uint64_t bytes)
|
||||
{
|
||||
LOCK(cs_totalBytesRecv);
|
||||
|
47
src/net.h
47
src/net.h
@ -16,6 +16,7 @@
|
||||
#include "sync.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
#include "core.h"
|
||||
|
||||
#include <deque>
|
||||
#include <stdint.h>
|
||||
@ -50,7 +51,7 @@ bool GetMyExternalIP(CNetAddr& ipRet);
|
||||
void AddressCurrentlyConnected(const CService& addr);
|
||||
CNode* FindNode(const CNetAddr& ip);
|
||||
CNode* FindNode(const CService& ip);
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL);
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool darkSendMaster=false);
|
||||
void MapPort(bool fUseUPnP);
|
||||
unsigned short GetListenPort();
|
||||
bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
|
||||
@ -233,6 +234,7 @@ public:
|
||||
// b) the peer may tell us in their version message that we should not relay tx invs
|
||||
// until they have initialized their bloom filter.
|
||||
bool fRelayTxes;
|
||||
bool fDarkSendMaster;
|
||||
CSemaphoreGrant grantOutbound;
|
||||
CCriticalSection cs_filter;
|
||||
CBloomFilter* pfilter;
|
||||
@ -245,6 +247,8 @@ protected:
|
||||
static std::map<CNetAddr, int64_t> setBanned;
|
||||
static CCriticalSection cs_setBanned;
|
||||
|
||||
std::vector<std::string> vecRequestsFulfilled; //keep track of what client has asked for
|
||||
|
||||
// Basic fuzz-testing
|
||||
void Fuzz(int nChance); // modifies ssSend
|
||||
|
||||
@ -676,6 +680,38 @@ public:
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
|
||||
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9, const T10& a10)
|
||||
{
|
||||
try
|
||||
{
|
||||
BeginMessage(pszCommand);
|
||||
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10;
|
||||
EndMessage();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
AbortMessage();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool HasFulfilledRequest(std::string strRequest)
|
||||
{
|
||||
BOOST_FOREACH(std::string& type, vecRequestsFulfilled)
|
||||
{
|
||||
if(type == strRequest) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FulfilledRequest(std::string strRequest)
|
||||
{
|
||||
if(HasFulfilledRequest(strRequest)) return;
|
||||
vecRequestsFulfilled.push_back(strRequest);
|
||||
}
|
||||
|
||||
bool IsSubscribed(unsigned int nChannel);
|
||||
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
|
||||
@ -716,6 +752,15 @@ public:
|
||||
class CTransaction;
|
||||
void RelayTransaction(const CTransaction& tx, const uint256& hash);
|
||||
void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss);
|
||||
void RelayTransactionLockReq(const CTransaction& tx, const uint256& hash, bool relayToAll=false);
|
||||
void RelayDarkSendFinalTransaction(const int sessionID, const CTransaction& txNew);
|
||||
void RelayDarkSendIn(const std::vector<CTxIn>& in, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector<CTxOut>& out);
|
||||
void RelayDarkSendStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const std::string error="");
|
||||
void RelayDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector<unsigned char> vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion);
|
||||
void RelayDarkSendElectionEntryPing(const CTxIn vin, const std::vector<unsigned char> vchSig, const int64_t nNow, const bool stop);
|
||||
void RelayDarkSendCompletedTransaction(const int sessionID, const bool error, const std::string errorMessage);
|
||||
void RelayDarkSendMasterNodeContestant();
|
||||
|
||||
|
||||
/** Access to the (IP) address database (peers.dat) */
|
||||
class CAddrDB
|
||||
|
@ -135,6 +135,8 @@ enum
|
||||
// Nodes may always request a MSG_FILTERED_BLOCK in a getdata, however,
|
||||
// MSG_FILTERED_BLOCK should not appear in any invs except as a part of getdata.
|
||||
MSG_FILTERED_BLOCK,
|
||||
MSG_TXLOCK_REQUEST,
|
||||
MSG_TXLOCK,
|
||||
};
|
||||
|
||||
#endif // __INCLUDED_PROTOCOL_H__
|
||||
|
@ -5,12 +5,12 @@ AM_CPPFLAGS += -I$(top_srcdir)/src \
|
||||
-I$(top_builddir)/src/qt/forms \
|
||||
$(PROTOBUF_CFLAGS) \
|
||||
$(QR_CFLAGS)
|
||||
bin_PROGRAMS = bitcoin-qt
|
||||
noinst_LIBRARIES = libbitcoinqt.a
|
||||
bin_PROGRAMS = darkcoin-qt
|
||||
noinst_LIBRARIES = libdarkcoinqt.a
|
||||
SUBDIRS = . $(BUILD_TEST_QT)
|
||||
DIST_SUBDIRS = . test
|
||||
|
||||
# bitcoin qt core #
|
||||
# darkcoin qt core #
|
||||
QT_TS = \
|
||||
locale/bitcoin_ach.ts \
|
||||
locale/bitcoin_af_ZA.ts \
|
||||
@ -261,7 +261,7 @@ RES_ICONS = \
|
||||
res/icons/tx_mined.png
|
||||
|
||||
BITCOIN_QT_CPP = \
|
||||
bitcoin.cpp \
|
||||
darkcoin.cpp \
|
||||
bitcoinaddressvalidator.cpp \
|
||||
bitcoinamountfield.cpp \
|
||||
bitcoingui.cpp \
|
||||
@ -321,38 +321,38 @@ RES_MOVIES = $(wildcard res/movies/spinner-*.png)
|
||||
|
||||
BITCOIN_RC = res/bitcoin-qt-res.rc
|
||||
|
||||
libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \
|
||||
libdarkcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \
|
||||
-I$(top_srcdir)/src/qt/forms $(QT_DBUS_INCLUDES)
|
||||
libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
|
||||
libdarkcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
|
||||
$(QT_QRC) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
|
||||
|
||||
nodist_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \
|
||||
nodist_libdarkcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \
|
||||
$(PROTOBUF_H) $(QT_QRC_CPP)
|
||||
|
||||
BUILT_SOURCES = $(nodist_libbitcoinqt_a_SOURCES)
|
||||
BUILT_SOURCES = $(nodist_libdarkcoinqt_a_SOURCES)
|
||||
|
||||
#Generating these with a half-written protobuf header leads to wacky results.
|
||||
#This makes sure it's done.
|
||||
$(QT_MOC): $(PROTOBUF_H)
|
||||
$(QT_MOC_CPP): $(PROTOBUF_H)
|
||||
|
||||
# bitcoin-qt binary #
|
||||
bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \
|
||||
# darkcoin-qt binary #
|
||||
darkcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \
|
||||
-I$(top_srcdir)/src/qt/forms
|
||||
bitcoin_qt_SOURCES = bitcoin.cpp
|
||||
darkcoin_qt_SOURCES = darkcoin.cpp
|
||||
if TARGET_DARWIN
|
||||
bitcoin_qt_SOURCES += $(BITCOIN_MM)
|
||||
darkcoin_qt_SOURCES += $(BITCOIN_MM)
|
||||
endif
|
||||
if TARGET_WINDOWS
|
||||
bitcoin_qt_SOURCES += $(BITCOIN_RC)
|
||||
darkcoin_qt_SOURCES += $(BITCOIN_RC)
|
||||
endif
|
||||
bitcoin_qt_LDADD = libbitcoinqt.a $(LIBBITCOIN_SERVER)
|
||||
darkcoin_qt_LDADD = libdarkcoinqt.a $(LIBBITCOIN_SERVER)
|
||||
if ENABLE_WALLET
|
||||
bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
|
||||
darkcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
|
||||
endif
|
||||
bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||
darkcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
|
||||
bitcoin_qt_LDFLAGS = $(QT_LDFLAGS)
|
||||
darkcoin_qt_LDFLAGS = $(QT_LDFLAGS)
|
||||
|
||||
# forms/foo.h -> forms/ui_foo.h
|
||||
QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h))))
|
||||
@ -371,7 +371,7 @@ translate: bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(
|
||||
@QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts locale/bitcoin_en.ts
|
||||
|
||||
$(QT_QRC_CPP): $(QT_QRC) $(QT_QM) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) $(PROTOBUF_H)
|
||||
@cd $(abs_srcdir); test -f $(RCC) && QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin -o $(abs_builddir)/$@ $< || \
|
||||
@cd $(abs_srcdir); test -f $(RCC) && QT_SELECT=$(QT_SELECT) $(RCC) -name darkcoin -o $(abs_builddir)/$@ $< || \
|
||||
echo error: could not build $@
|
||||
$(SED) -e '/^\*\*.*Created:/d' $@ > $@.n && mv $@{.n,}
|
||||
$(SED) -e '/^\*\*.*by:/d' $@ > $@.n && mv $@{.n,}
|
||||
|
@ -370,7 +370,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
||||
CPubKey newKey;
|
||||
if(!wallet->GetKeyFromPool(newKey))
|
||||
{
|
||||
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
|
||||
WalletModel::UnlockContext ctx(walletModel->requestUnlock(true));
|
||||
if(!ctx.isValid())
|
||||
{
|
||||
// Unlock wallet failed or was cancelled
|
||||
|
@ -40,6 +40,9 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
|
||||
ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>."));
|
||||
setWindowTitle(tr("Encrypt wallet"));
|
||||
break;
|
||||
case UnlockAnonymize:
|
||||
ui->anonymizationCheckBox->setChecked(true);
|
||||
ui->anonymizationCheckBox->show();
|
||||
case Unlock: // Ask passphrase
|
||||
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
|
||||
ui->passLabel2->hide();
|
||||
@ -80,6 +83,7 @@ AskPassphraseDialog::~AskPassphraseDialog()
|
||||
void AskPassphraseDialog::setModel(WalletModel *model)
|
||||
{
|
||||
this->model = model;
|
||||
ui->anonymizationCheckBox->setChecked(model->isAnonymizeOnlyUnlocked());
|
||||
}
|
||||
|
||||
void AskPassphraseDialog::accept()
|
||||
@ -105,7 +109,7 @@ void AskPassphraseDialog::accept()
|
||||
break;
|
||||
}
|
||||
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
|
||||
tr("Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!") + "<br><br>" + tr("Are you sure you wish to encrypt your wallet?"),
|
||||
tr("Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DARKCOINS</b>!") + "<br><br>" + tr("Are you sure you wish to encrypt your wallet?"),
|
||||
QMessageBox::Yes|QMessageBox::Cancel,
|
||||
QMessageBox::Cancel);
|
||||
if(retval == QMessageBox::Yes)
|
||||
@ -116,9 +120,9 @@ void AskPassphraseDialog::accept()
|
||||
{
|
||||
QMessageBox::warning(this, tr("Wallet encrypted"),
|
||||
"<qt>" +
|
||||
tr("Bitcoin will close now to finish the encryption process. "
|
||||
tr("DarkCoin will close now to finish the encryption process. "
|
||||
"Remember that encrypting your wallet cannot fully protect "
|
||||
"your bitcoins from being stolen by malware infecting your computer.") +
|
||||
"your darkcoins from being stolen by malware infecting your computer.") +
|
||||
"<br><br><b>" +
|
||||
tr("IMPORTANT: Any previous backups you have made of your wallet file "
|
||||
"should be replaced with the newly generated, encrypted wallet file. "
|
||||
@ -145,8 +149,9 @@ void AskPassphraseDialog::accept()
|
||||
QDialog::reject(); // Cancelled
|
||||
}
|
||||
} break;
|
||||
case UnlockAnonymize:
|
||||
case Unlock:
|
||||
if(!model->setWalletLocked(false, oldpass))
|
||||
if(!model->setWalletLocked(false, oldpass, ui->anonymizationCheckBox->isChecked()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Wallet unlock failed"),
|
||||
tr("The passphrase entered for the wallet decryption was incorrect."));
|
||||
@ -200,6 +205,7 @@ void AskPassphraseDialog::textChanged()
|
||||
case Encrypt: // New passphrase x2
|
||||
acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
|
||||
break;
|
||||
case UnlockAnonymize: // Old passphrase x1
|
||||
case Unlock: // Old passphrase x1
|
||||
case Decrypt:
|
||||
acceptable = !ui->passEdit1->text().isEmpty();
|
||||
|
@ -22,6 +22,7 @@ class AskPassphraseDialog : public QDialog
|
||||
public:
|
||||
enum Mode {
|
||||
Encrypt, /**< Ask passphrase twice and encrypt */
|
||||
UnlockAnonymize, /**< Ask passphrase and unlock only for anonymization */
|
||||
Unlock, /**< Ask passphrase and unlock */
|
||||
ChangePass, /**< Ask old passphrase + new passphrase twice */
|
||||
Decrypt /**< Ask passphrase and decrypt wallet */
|
||||
|
@ -292,6 +292,9 @@ void BitcoinGUI::createActions(bool fIsTestnet)
|
||||
backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
|
||||
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this);
|
||||
changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
|
||||
unlockWalletAction = new QAction(tr("&Unlock Wallet..."), this);
|
||||
unlockWalletAction->setToolTip(tr("Unlock wallet"));
|
||||
lockWalletAction = new QAction(tr("&Lock Wallet"), this);
|
||||
signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this);
|
||||
signMessageAction->setStatusTip(tr("Sign messages with your Darkcoin addresses to prove you own them"));
|
||||
verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this);
|
||||
@ -323,6 +326,8 @@ void BitcoinGUI::createActions(bool fIsTestnet)
|
||||
connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool)));
|
||||
connect(backupWalletAction, SIGNAL(triggered()), walletFrame, SLOT(backupWallet()));
|
||||
connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase()));
|
||||
connect(unlockWalletAction, SIGNAL(triggered()), walletFrame, SLOT(unlockWallet()));
|
||||
connect(lockWalletAction, SIGNAL(triggered()), walletFrame, SLOT(lockWallet()));
|
||||
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
|
||||
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
|
||||
connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses()));
|
||||
@ -362,6 +367,8 @@ void BitcoinGUI::createMenuBar()
|
||||
{
|
||||
settings->addAction(encryptWalletAction);
|
||||
settings->addAction(changePassphraseAction);
|
||||
settings->addAction(unlockWalletAction);
|
||||
settings->addAction(lockWalletAction);
|
||||
settings->addSeparator();
|
||||
}
|
||||
settings->addAction(optionsAction);
|
||||
@ -891,6 +898,8 @@ void BitcoinGUI::setEncryptionStatus(int status)
|
||||
labelEncryptionIcon->hide();
|
||||
encryptWalletAction->setChecked(false);
|
||||
changePassphraseAction->setEnabled(false);
|
||||
unlockWalletAction->setVisible(false);
|
||||
lockWalletAction->setVisible(false);
|
||||
encryptWalletAction->setEnabled(true);
|
||||
break;
|
||||
case WalletModel::Unlocked:
|
||||
@ -899,6 +908,18 @@ void BitcoinGUI::setEncryptionStatus(int status)
|
||||
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
|
||||
encryptWalletAction->setChecked(true);
|
||||
changePassphraseAction->setEnabled(true);
|
||||
unlockWalletAction->setVisible(false);
|
||||
lockWalletAction->setVisible(true);
|
||||
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
|
||||
break;
|
||||
case WalletModel::UnlockedForAnonymizationOnly:
|
||||
labelEncryptionIcon->show();
|
||||
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b> for anonimization only"));
|
||||
encryptWalletAction->setChecked(true);
|
||||
changePassphraseAction->setEnabled(true);
|
||||
unlockWalletAction->setVisible(true);
|
||||
lockWalletAction->setVisible(true);
|
||||
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
|
||||
break;
|
||||
case WalletModel::Locked:
|
||||
@ -907,6 +928,8 @@ void BitcoinGUI::setEncryptionStatus(int status)
|
||||
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
|
||||
encryptWalletAction->setChecked(true);
|
||||
changePassphraseAction->setEnabled(true);
|
||||
unlockWalletAction->setVisible(true);
|
||||
lockWalletAction->setVisible(false);
|
||||
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
|
||||
break;
|
||||
}
|
||||
|
@ -90,6 +90,8 @@ private:
|
||||
QAction *encryptWalletAction;
|
||||
QAction *backupWalletAction;
|
||||
QAction *changePassphraseAction;
|
||||
QAction *unlockWalletAction;
|
||||
QAction *lockWalletAction;
|
||||
QAction *aboutQtAction;
|
||||
QAction *openRPCConsoleAction;
|
||||
QAction *openAction;
|
||||
|
@ -475,7 +475,7 @@ int main(int argc, char *argv[])
|
||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
|
||||
#endif
|
||||
|
||||
Q_INIT_RESOURCE(bitcoin);
|
||||
Q_INIT_RESOURCE(darkcoin);
|
||||
|
||||
GUIUtil::SubstituteFonts();
|
||||
|
74
src/qt/darksendconfig.cpp
Normal file
74
src/qt/darksendconfig.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "darksendconfig.h"
|
||||
#include "ui_darksendconfig.h"
|
||||
|
||||
#include "guiconstants.h"
|
||||
#include "walletmodel.h"
|
||||
#include "init.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QKeyEvent>
|
||||
#include <QSettings>
|
||||
|
||||
DarksendConfig::DarksendConfig(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::DarksendConfig),
|
||||
model(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->buttonBasic, SIGNAL(clicked()), this, SLOT(clickBasic()));
|
||||
connect(ui->buttonHigh, SIGNAL(clicked()), this, SLOT(clickHigh()));
|
||||
connect(ui->buttonMax, SIGNAL(clicked()), this, SLOT(clickMax()));
|
||||
}
|
||||
|
||||
DarksendConfig::~DarksendConfig()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void DarksendConfig::setModel(WalletModel *model)
|
||||
{
|
||||
this->model = model;
|
||||
}
|
||||
|
||||
void DarksendConfig::clickBasic()
|
||||
{
|
||||
configure(true, 1000, 2);
|
||||
|
||||
QMessageBox::information(this, tr("Darksend Configuration"),
|
||||
tr("Darksend was successfully set to basic (1000 DRK and 2 rounds). You can change this at any time by opening Darkcoin's configuration screen."));
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
void DarksendConfig::clickHigh()
|
||||
{
|
||||
configure(true, 1000, 4);
|
||||
|
||||
QMessageBox::information(this, tr("Darksend Configuration"),
|
||||
tr("Darksend was successfully set to high (1000 DRK and 4 rounds). You can change this at any time by opening Darkcoin's configuration screen."));
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
void DarksendConfig::clickMax()
|
||||
{
|
||||
configure(true, 1000, 8);
|
||||
|
||||
QMessageBox::information(this, tr("Darksend Configuration"),
|
||||
tr("Darksend was successfully set to maximum (1000 DRK and 8 rounds). You can change this at any time by opening Darkcoin's configuration screen."));
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
void DarksendConfig::configure(bool enabled, int coins, int rounds) {
|
||||
|
||||
QSettings settings;
|
||||
|
||||
settings.setValue("nDarksendRounds", rounds);
|
||||
settings.setValue("nAnonymizeDarkcoinAmount", coins);
|
||||
|
||||
nDarksendRounds = rounds;
|
||||
nAnonymizeDarkcoinAmount = coins;
|
||||
}
|
37
src/qt/darksendconfig.h
Normal file
37
src/qt/darksendconfig.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef DARKSENDCONFIG_H
|
||||
#define DARKSENDCONFIG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class DarksendConfig;
|
||||
}
|
||||
class WalletModel;
|
||||
|
||||
/** Multifunctional dialog to ask for passphrases. Used for encryption, unlocking, and changing the passphrase.
|
||||
*/
|
||||
class DarksendConfig : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
DarksendConfig(QWidget *parent = 0);
|
||||
~DarksendConfig();
|
||||
|
||||
void setModel(WalletModel *model);
|
||||
|
||||
|
||||
private:
|
||||
Ui::DarksendConfig *ui;
|
||||
WalletModel *model;
|
||||
void configure(bool enabled, int coins, int rounds);
|
||||
|
||||
private slots:
|
||||
|
||||
void clickBasic();
|
||||
void clickHigh();
|
||||
void clickMax();
|
||||
};
|
||||
|
||||
#endif // DARKSENDCONFIG_H
|
@ -99,6 +99,22 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="anonymizationCheckBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Serves to disable the trivial sendmoney when OS account compromised. Provides no real security.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>For anonymization only</string>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -130,6 +130,34 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2_Main">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>This setting determines the amount of individual masternodes that an input will be anonymized through. More rounds of anonymization gives a higher degree of privacy, but also costs more in fees.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Darksend Rounds To Use</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="darksendRounds">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabWallet">
|
||||
|
@ -741,13 +741,40 @@
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<widget class="Line" name="line">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkUseDarksend">
|
||||
<property name="text">
|
||||
<string>Darksend</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkInstantX">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>InstantX</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Balance:</string>
|
||||
</property>
|
||||
|
@ -134,6 +134,11 @@ void OptionsModel::Init()
|
||||
if (!SoftSetArg("-lang", settings.value("language").toString().toStdString()))
|
||||
addOverriddenOption("-lang");
|
||||
|
||||
if (settings.contains("nDarksendRounds"))
|
||||
SoftSetArg("-darksendrounds", settings.value("nDarksendRounds").toString().toStdString());
|
||||
if (settings.contains("nAnonymizeDarkcoinAmount"))
|
||||
SoftSetArg("-anonymizedarkcoinamount", settings.value("nAnonymizeDarkcoinAmount").toString().toStdString());
|
||||
|
||||
language = settings.value("language").toString();
|
||||
}
|
||||
|
||||
@ -218,6 +223,10 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
|
||||
return settings.value("nDatabaseCache");
|
||||
case ThreadsScriptVerif:
|
||||
return settings.value("nThreadsScriptVerif");
|
||||
case DarksendRounds:
|
||||
return QVariant(nDarksendRounds);
|
||||
case AnonymizeDarkcoinAmount:
|
||||
return QVariant(nAnonymizeDarkcoinAmount);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
@ -324,6 +333,16 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
|
||||
setRestartRequired(true);
|
||||
}
|
||||
break;
|
||||
case DarksendRounds:
|
||||
nDarksendRounds = value.toInt();
|
||||
settings.setValue("nDarksendRounds", nDarksendRounds);
|
||||
emit darksendRoundsChanged(nDarksendRounds);
|
||||
break;
|
||||
case AnonymizeDarkcoinAmount:
|
||||
nAnonymizeDarkcoinAmount = value.toInt();
|
||||
settings.setValue("nAnonymizeDarkcoinAmount", nAnonymizeDarkcoinAmount);
|
||||
emit anonymizeDarkcoinAmountChanged(nAnonymizeDarkcoinAmount);
|
||||
break;
|
||||
case CoinControlFeatures:
|
||||
fCoinControlFeatures = value.toBool();
|
||||
settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
|
||||
|
@ -43,6 +43,8 @@ public:
|
||||
DatabaseCache, // int
|
||||
SpendZeroConfChange, // bool
|
||||
OptionIDRowCount,
|
||||
DarksendRounds, // int
|
||||
AnonymizeDarkcoinAmount, //int
|
||||
};
|
||||
|
||||
void Init();
|
||||
@ -84,6 +86,8 @@ private:
|
||||
signals:
|
||||
void displayUnitChanged(int unit);
|
||||
void transactionFeeChanged(qint64);
|
||||
void darksendRoundsChanged(int);
|
||||
void anonymizeDarkcoinAmountChanged(int);
|
||||
void coinControlFeaturesChanged(bool);
|
||||
};
|
||||
|
||||
|
@ -20,14 +20,14 @@ BEGIN
|
||||
BEGIN
|
||||
BLOCK "040904E4" // U.S. English - multilingual (hex)
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Bitcoin"
|
||||
VALUE "FileDescription", "Bitcoin Core (OSS GUI client for Bitcoin)"
|
||||
VALUE "CompanyName", "Darkcoin"
|
||||
VALUE "FileDescription", "Darkcoin Core (OSS GUI client for Darkcoin)"
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "InternalName", "bitcoin-qt"
|
||||
VALUE "InternalName", "darkcoin-qt"
|
||||
VALUE "LegalCopyright", COPYRIGHT_STR
|
||||
VALUE "LegalTrademarks1", "Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php."
|
||||
VALUE "OriginalFilename", "bitcoin-qt.exe"
|
||||
VALUE "ProductName", "Bitcoin Core"
|
||||
VALUE "OriginalFilename", "darkcoin-qt.exe"
|
||||
VALUE "ProductName", "Darkcoin Core"
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
END
|
||||
END
|
||||
|
@ -45,6 +45,7 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
|
||||
connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked()));
|
||||
connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int)));
|
||||
connect(ui->lineEditCoinControlChange, SIGNAL(textEdited(const QString &)), this, SLOT(coinControlChangeEdited(const QString &)));
|
||||
connect(ui->checkUseDarksend, SIGNAL(stateChanged ( int )), this, SLOT(updateDisplayUnit()));
|
||||
|
||||
// Coin Control: clipboard actions
|
||||
QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
|
||||
@ -89,9 +90,11 @@ void SendCoinsDialog::setModel(WalletModel *model)
|
||||
entry->setModel(model);
|
||||
}
|
||||
}
|
||||
|
||||
setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
|
||||
connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
|
||||
}
|
||||
if(model && model->getOptionsModel())
|
||||
{
|
||||
setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getAnonymizedBalance());
|
||||
connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64)));
|
||||
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
||||
|
||||
// Coin Control
|
||||
@ -137,6 +140,27 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
QString strFunds = " Using <b>Anonymous Funds</b>";
|
||||
QString strFee = "";
|
||||
recipients[0].inputType = "ONLY_DENOMINATED";
|
||||
|
||||
if(ui->checkUseDarksend->isChecked()) {
|
||||
recipients[0].inputType = "ONLY_DENOMINATED";
|
||||
strFunds = "Using <b>Anonymous Funds</b>";
|
||||
strFee = "(Darksend requires this amount to be rounded up to the nearest 0.1DRK)";
|
||||
} else {
|
||||
recipients[0].inputType = "ALL_COINS";
|
||||
strFunds = "Using <b>ANY AVAILABLE Funds</b>";
|
||||
}
|
||||
|
||||
if(ui->checkInstantX->isChecked()) {
|
||||
recipients[0].useInstantX = true;
|
||||
strFunds += " and InstantX";
|
||||
} else {
|
||||
recipients[0].useInstantX = false;
|
||||
}
|
||||
|
||||
|
||||
// Format confirmation message
|
||||
QStringList formatted;
|
||||
foreach(const SendCoinsRecipient &rcp, recipients)
|
||||
@ -144,6 +168,8 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||
// generate bold amount string
|
||||
QString amount = "<b>" + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
|
||||
amount.append("</b>");
|
||||
amount.append(strFunds);
|
||||
|
||||
// generate monospace address string
|
||||
QString address = "<span style='font-family: monospace;'>" + rcp.address;
|
||||
address.append("</span>");
|
||||
@ -177,7 +203,7 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||
fNewRecipientAllowed = false;
|
||||
|
||||
|
||||
WalletModel::UnlockContext ctx(model->requestUnlock());
|
||||
WalletModel::UnlockContext ctx(model->requestUnlock(true));
|
||||
if(!ctx.isValid())
|
||||
{
|
||||
// Unlock wallet was cancelled
|
||||
@ -211,6 +237,7 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||
// append fee string if a fee is required
|
||||
questionString.append("<hr /><span style='color:#aa0000;'>");
|
||||
questionString.append(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));
|
||||
questionString.append(strFee);
|
||||
questionString.append("</span> ");
|
||||
questionString.append(tr("added as transaction fee"));
|
||||
}
|
||||
@ -401,20 +428,29 @@ bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv)
|
||||
return true;
|
||||
}
|
||||
|
||||
void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
|
||||
void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, qint64 anonymizedBalance)
|
||||
{
|
||||
Q_UNUSED(unconfirmedBalance);
|
||||
Q_UNUSED(immatureBalance);
|
||||
Q_UNUSED(anonymizedBalance);
|
||||
|
||||
if(model && model->getOptionsModel())
|
||||
{
|
||||
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), balance));
|
||||
uint64_t bal = 0;
|
||||
|
||||
if(ui->checkUseDarksend->isChecked()) {
|
||||
bal = anonymizedBalance;
|
||||
} else {
|
||||
bal = balance;
|
||||
}
|
||||
|
||||
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), bal));
|
||||
}
|
||||
}
|
||||
|
||||
void SendCoinsDialog::updateDisplayUnit()
|
||||
{
|
||||
setBalance(model->getBalance(), 0, 0);
|
||||
setBalance(model->getBalance(), 0, 0, 0);
|
||||
}
|
||||
|
||||
void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg)
|
||||
@ -451,6 +487,11 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
|
||||
msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
|
||||
msgParams.second = CClientUIInterface::MSG_ERROR;
|
||||
break;
|
||||
case WalletModel::AnonymizeOnlyUnlocked:
|
||||
QMessageBox::warning(this, tr("Send Coins"),
|
||||
tr("Error: The wallet was unlocked only to anonymize coins."),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
break;
|
||||
// included to prevent a compiler warning.
|
||||
case WalletModel::OK:
|
||||
default:
|
||||
|
@ -47,7 +47,7 @@ public slots:
|
||||
void accept();
|
||||
SendCoinsEntry *addEntry();
|
||||
void updateTabsAndLabels();
|
||||
void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance);
|
||||
void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, qint64 anonymizedBalance);
|
||||
|
||||
private:
|
||||
Ui::SendCoinsDialog *ui;
|
||||
|
@ -123,7 +123,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
WalletModel::UnlockContext ctx(model->requestUnlock());
|
||||
WalletModel::UnlockContext ctx(model->requestUnlock(true));
|
||||
if (!ctx.isValid())
|
||||
{
|
||||
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
|
||||
|
@ -5,8 +5,8 @@ AM_CPPFLAGS += -I$(top_srcdir)/src \
|
||||
-I$(top_builddir)/src/qt \
|
||||
$(PROTOBUF_CFLAGS) \
|
||||
$(QR_CFLAGS)
|
||||
bin_PROGRAMS = test_bitcoin-qt
|
||||
TESTS = test_bitcoin-qt
|
||||
bin_PROGRAMS = test_darkcoin-qt
|
||||
TESTS = test_darkcoin-qt
|
||||
|
||||
TEST_QT_MOC_CPP = moc_uritests.cpp
|
||||
|
||||
@ -21,26 +21,26 @@ TEST_QT_H = \
|
||||
|
||||
BUILT_SOURCES = $(TEST_QT_MOC_CPP)
|
||||
|
||||
test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) $(QT_TEST_INCLUDES)
|
||||
test_darkcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) $(QT_TEST_INCLUDES)
|
||||
|
||||
test_bitcoin_qt_SOURCES = \
|
||||
test_darkcoin_qt_SOURCES = \
|
||||
test_main.cpp \
|
||||
uritests.cpp \
|
||||
$(TEST_QT_H)
|
||||
if ENABLE_WALLET
|
||||
test_bitcoin_qt_SOURCES += \
|
||||
test_darkcoin_qt_SOURCES += \
|
||||
paymentservertests.cpp
|
||||
endif
|
||||
|
||||
nodist_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
|
||||
nodist_test_darkcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
|
||||
|
||||
test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
|
||||
test_darkcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
|
||||
if ENABLE_WALLET
|
||||
test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
|
||||
test_darkcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
|
||||
endif
|
||||
test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) \
|
||||
test_darkcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) \
|
||||
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
|
||||
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
|
||||
test_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS)
|
||||
test_darkcoin_qt_LDFLAGS = $(QT_LDFLAGS)
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES) *.gcda *.gcno
|
||||
|
@ -175,6 +175,13 @@ void WalletFrame::unlockWallet()
|
||||
walletView->unlockWallet();
|
||||
}
|
||||
|
||||
void WalletFrame::lockWallet()
|
||||
{
|
||||
WalletView *walletView = currentWalletView();
|
||||
if (walletView)
|
||||
walletView->lockWallet();
|
||||
}
|
||||
|
||||
void WalletFrame::usedSendingAddresses()
|
||||
{
|
||||
WalletView *walletView = currentWalletView();
|
||||
|
@ -70,6 +70,8 @@ public slots:
|
||||
void changePassphrase();
|
||||
/** Ask for passphrase to unlock wallet temporarily */
|
||||
void unlockWallet();
|
||||
/** Lock wallet */
|
||||
void lockWallet();
|
||||
|
||||
/** Show used sending addresses */
|
||||
void usedSendingAddresses();
|
||||
|
@ -66,6 +66,12 @@ qint64 WalletModel::getBalance(const CCoinControl *coinControl) const
|
||||
return wallet->GetBalance();
|
||||
}
|
||||
|
||||
|
||||
qint64 WalletModel::getAnonymizedBalance() const
|
||||
{
|
||||
return wallet->GetAnonymizedBalance();
|
||||
}
|
||||
|
||||
qint64 WalletModel::getUnconfirmedBalance() const
|
||||
{
|
||||
return wallet->GetUnconfirmedBalance();
|
||||
@ -108,10 +114,12 @@ void WalletModel::pollBalanceChanged()
|
||||
if(!lockWallet)
|
||||
return;
|
||||
|
||||
if(chainActive.Height() != cachedNumBlocks)
|
||||
if(chainActive.Height() != cachedNumBlocks || nDarksendRounds != cachedDarksendRounds)
|
||||
{
|
||||
// Balance and number of transactions might have changed
|
||||
cachedNumBlocks = chainActive.Height();
|
||||
cachedDarksendRounds = nDarksendRounds;
|
||||
cachedTxLocks = 0;
|
||||
|
||||
checkBalanceChanged();
|
||||
if(transactionTableModel)
|
||||
@ -124,13 +132,15 @@ void WalletModel::checkBalanceChanged()
|
||||
qint64 newBalance = getBalance();
|
||||
qint64 newUnconfirmedBalance = getUnconfirmedBalance();
|
||||
qint64 newImmatureBalance = getImmatureBalance();
|
||||
qint64 newAnonymizedBalance = getAnonymizedBalance();
|
||||
|
||||
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance)
|
||||
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance|| cachedAnonymizedBalance != newAnonymizedBalance)
|
||||
{
|
||||
cachedBalance = newBalance;
|
||||
cachedUnconfirmedBalance = newUnconfirmedBalance;
|
||||
cachedImmatureBalance = newImmatureBalance;
|
||||
emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance);
|
||||
cachedAnonymizedBalance = newAnonymizedBalance;
|
||||
emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance, newAnonymizedBalance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,6 +184,11 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
||||
return OK;
|
||||
}
|
||||
|
||||
if(isAnonymizeOnlyUnlocked())
|
||||
{
|
||||
return AnonymizeOnlyUnlocked;
|
||||
}
|
||||
|
||||
QSet<QString> setAddress; // Used to detect duplicates
|
||||
int nAddresses = 0;
|
||||
|
||||
@ -246,7 +261,18 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
||||
|
||||
CWalletTx *newTx = transaction.getTransaction();
|
||||
CReserveKey *keyChange = transaction.getPossibleKeyChange();
|
||||
bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, strFailReason, coinControl);
|
||||
|
||||
|
||||
AvailableCoinsType act = ONLY_DENOMINATED;
|
||||
if(recipients[0].inputType == "ONLY_NONDENOMINATED"){
|
||||
act = ONLY_NONDENOMINATED;
|
||||
} else if(recipients[0].inputType == "ONLY_DENOMINATED"){
|
||||
act = ONLY_DENOMINATED;
|
||||
} else if(recipients[0].inputType == "ALL_COINS"){
|
||||
act = ALL_COINS;
|
||||
}
|
||||
|
||||
bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, strFailReason, coinControl, act);
|
||||
transaction.setTransactionFee(nFeeRequired);
|
||||
|
||||
if(!fCreated)
|
||||
@ -268,11 +294,17 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
|
||||
{
|
||||
QByteArray transaction_array; /* store serialized transaction */
|
||||
|
||||
if(isAnonymizeOnlyUnlocked())
|
||||
{
|
||||
return AnonymizeOnlyUnlocked;
|
||||
}
|
||||
|
||||
{
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
CWalletTx *newTx = transaction.getTransaction();
|
||||
|
||||
// Store PaymentRequests in wtx.vOrderForm in wallet.
|
||||
std::string strCommand = "tx";
|
||||
foreach(const SendCoinsRecipient &rcp, transaction.getRecipients())
|
||||
{
|
||||
if (rcp.paymentRequest.IsInitialized())
|
||||
@ -283,11 +315,20 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
|
||||
newTx->vOrderForm.push_back(make_pair(key, value));
|
||||
}
|
||||
else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
|
||||
{
|
||||
newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString()));
|
||||
}
|
||||
|
||||
if(rcp.useInstantX) {
|
||||
strCommand = "txlreq";
|
||||
}
|
||||
}
|
||||
|
||||
CReserveKey *keyChange = transaction.getPossibleKeyChange();
|
||||
if(!wallet->CommitTransaction(*newTx, *keyChange))
|
||||
|
||||
transaction.getRecipients();
|
||||
|
||||
if(!wallet->CommitTransaction(*newTx, *keyChange, strCommand))
|
||||
return TransactionCommitFailed;
|
||||
|
||||
CTransaction* t = (CTransaction*)newTx;
|
||||
@ -358,6 +399,10 @@ WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
|
||||
{
|
||||
return Locked;
|
||||
}
|
||||
else if (wallet->fWalletUnlockAnonymizeOnly)
|
||||
{
|
||||
return UnlockedForAnonymizationOnly;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unlocked;
|
||||
@ -378,7 +423,7 @@ bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphr
|
||||
}
|
||||
}
|
||||
|
||||
bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
|
||||
bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase, bool anonymizeOnly)
|
||||
{
|
||||
if(locked)
|
||||
{
|
||||
@ -388,10 +433,15 @@ bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
|
||||
else
|
||||
{
|
||||
// Unlock
|
||||
return wallet->Unlock(passPhrase);
|
||||
return wallet->Unlock(passPhrase, anonymizeOnly);
|
||||
}
|
||||
}
|
||||
|
||||
bool WalletModel::isAnonymizeOnlyUnlocked()
|
||||
{
|
||||
return wallet->fWalletUnlockAnonymizeOnly;
|
||||
}
|
||||
|
||||
bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
|
||||
{
|
||||
bool retval;
|
||||
@ -489,9 +539,16 @@ void WalletModel::unsubscribeFromCoreSignals()
|
||||
}
|
||||
|
||||
// WalletModel::UnlockContext implementation
|
||||
WalletModel::UnlockContext WalletModel::requestUnlock()
|
||||
WalletModel::UnlockContext WalletModel::requestUnlock(bool relock)
|
||||
{
|
||||
bool was_locked = getEncryptionStatus() == Locked;
|
||||
|
||||
if (!was_locked && isAnonymizeOnlyUnlocked())
|
||||
{
|
||||
setWalletLocked(true);
|
||||
was_locked = getEncryptionStatus() == Locked;
|
||||
}
|
||||
|
||||
if(was_locked)
|
||||
{
|
||||
// Request UI to unlock wallet
|
||||
@ -500,7 +557,8 @@ WalletModel::UnlockContext WalletModel::requestUnlock()
|
||||
// If wallet is still locked, unlock was failed or cancelled, mark context as invalid
|
||||
bool valid = getEncryptionStatus() != Locked;
|
||||
|
||||
return UnlockContext(this, valid, was_locked);
|
||||
return UnlockContext(this, valid, relock);
|
||||
// return UnlockContext(this, valid, was_locked && !isAnonymizeOnlyUnlocked());
|
||||
}
|
||||
|
||||
WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
|
||||
|
@ -48,6 +48,8 @@ public:
|
||||
QString address;
|
||||
QString label;
|
||||
qint64 amount;
|
||||
std::string inputType;
|
||||
bool useInstantX;
|
||||
// If from a payment request, this is used for storing the memo
|
||||
QString message;
|
||||
|
||||
@ -110,14 +112,16 @@ public:
|
||||
AmountWithFeeExceedsBalance,
|
||||
DuplicateAddress,
|
||||
TransactionCreationFailed, // Error returned when wallet is still locked
|
||||
TransactionCommitFailed
|
||||
TransactionCommitFailed,
|
||||
AnonymizeOnlyUnlocked
|
||||
};
|
||||
|
||||
enum EncryptionStatus
|
||||
{
|
||||
Unencrypted, // !wallet->IsCrypted()
|
||||
Locked, // wallet->IsCrypted() && wallet->IsLocked()
|
||||
Unlocked // wallet->IsCrypted() && !wallet->IsLocked()
|
||||
Unlocked, // wallet->IsCrypted() && !wallet->IsLocked()
|
||||
UnlockedForAnonymizationOnly // wallet->IsCrypted() && !wallet->IsLocked() && wallet->fWalletUnlockAnonymizeOnly
|
||||
};
|
||||
|
||||
OptionsModel *getOptionsModel();
|
||||
@ -126,6 +130,7 @@ public:
|
||||
RecentRequestsTableModel *getRecentRequestsTableModel();
|
||||
|
||||
qint64 getBalance(const CCoinControl *coinControl = NULL) const;
|
||||
qint64 getAnonymizedBalance() const;
|
||||
qint64 getUnconfirmedBalance() const;
|
||||
qint64 getImmatureBalance() const;
|
||||
int getNumTransactions() const;
|
||||
@ -151,8 +156,10 @@ public:
|
||||
// Wallet encryption
|
||||
bool setWalletEncrypted(bool encrypted, const SecureString &passphrase);
|
||||
// Passphrase only needed when unlocking
|
||||
bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString());
|
||||
bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString(), bool anonymizeOnly=false);
|
||||
bool changePassphrase(const SecureString &oldPass, const SecureString &newPass);
|
||||
// Is wallet unlocked for anonymization only?
|
||||
bool isAnonymizeOnlyUnlocked();
|
||||
// Wallet backup
|
||||
bool backupWallet(const QString &filename);
|
||||
|
||||
@ -176,7 +183,7 @@ public:
|
||||
void CopyFrom(const UnlockContext& rhs);
|
||||
};
|
||||
|
||||
UnlockContext requestUnlock();
|
||||
UnlockContext requestUnlock(bool relock);
|
||||
|
||||
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
|
||||
void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs);
|
||||
@ -206,7 +213,10 @@ private:
|
||||
qint64 cachedBalance;
|
||||
qint64 cachedUnconfirmedBalance;
|
||||
qint64 cachedImmatureBalance;
|
||||
qint64 cachedAnonymizedBalance;
|
||||
qint64 cachedNumTransactions;
|
||||
int cachedTxLocks;
|
||||
int cachedDarksendRounds;
|
||||
EncryptionStatus cachedEncryptionStatus;
|
||||
int cachedNumBlocks;
|
||||
|
||||
@ -218,7 +228,7 @@ private:
|
||||
|
||||
signals:
|
||||
// Signal that balance in wallet changed
|
||||
void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance);
|
||||
void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, qint64 anonymizedBalance);
|
||||
|
||||
// Number of transactions in wallet changed
|
||||
void numTransactionsChanged(int count);
|
||||
|
@ -254,14 +254,23 @@ void WalletView::unlockWallet()
|
||||
if(!walletModel)
|
||||
return;
|
||||
// Unlock wallet when requested by wallet model
|
||||
if (walletModel->getEncryptionStatus() == WalletModel::Locked)
|
||||
|
||||
if (walletModel->getEncryptionStatus() == WalletModel::Locked || walletModel->getEncryptionStatus() == WalletModel::UnlockedForAnonymizationOnly)
|
||||
{
|
||||
AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
|
||||
AskPassphraseDialog dlg(AskPassphraseDialog::UnlockAnonymize, this);
|
||||
dlg.setModel(walletModel);
|
||||
dlg.exec();
|
||||
}
|
||||
}
|
||||
|
||||
void WalletView::lockWallet()
|
||||
{
|
||||
if(!walletModel)
|
||||
return;
|
||||
|
||||
walletModel->setWalletLocked(true);
|
||||
}
|
||||
|
||||
void WalletView::usedSendingAddresses()
|
||||
{
|
||||
if(!walletModel)
|
||||
|
@ -91,6 +91,8 @@ public slots:
|
||||
void changePassphrase();
|
||||
/** Ask for passphrase to unlock wallet temporarily */
|
||||
void unlockWallet();
|
||||
/** Lock wallet */
|
||||
void lockWallet();
|
||||
|
||||
/** Show used sending addresses */
|
||||
void usedSendingAddresses();
|
||||
|
323
src/rpcdarksend.cpp
Normal file
323
src/rpcdarksend.cpp
Normal file
@ -0,0 +1,323 @@
|
||||
// Copyright (c) 2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "main.h"
|
||||
#include "core.h"
|
||||
#include "db.h"
|
||||
#include "init.h"
|
||||
#include "masternode.h"
|
||||
#include "activemasternode.h"
|
||||
#include "rpcserver.h"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <fstream>
|
||||
using namespace json_spirit;
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
Value darksend(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() == 0)
|
||||
throw runtime_error(
|
||||
"darksend <darkcoinaddress> <amount>\n"
|
||||
"darkcoinaddress, reset, or auto (AutoDenominate)"
|
||||
"<amount> is a real and is rounded to the nearest 0.00000001"
|
||||
+ HelpRequiringPassphrase());
|
||||
|
||||
if(fMasterNode)
|
||||
return "DarkSend is not supported from masternodes";
|
||||
|
||||
if (pwalletMain->IsLocked())
|
||||
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
|
||||
|
||||
if(params[0].get_str() == "auto"){
|
||||
darkSendPool.DoAutomaticDenominating();
|
||||
return "DoAutomaticDenominating";
|
||||
}
|
||||
|
||||
if(params[0].get_str() == "reset"){
|
||||
darkSendPool.SetNull(true);
|
||||
darkSendPool.UnlockCoins();
|
||||
return "successfully reset darksend";
|
||||
}
|
||||
|
||||
if (params.size() != 2)
|
||||
throw runtime_error(
|
||||
"darksend <darkcoinaddress> <amount>\n"
|
||||
"darkcoinaddress, denominate, or auto (AutoDenominate)"
|
||||
"<amount> is a real and is rounded to the nearest 0.00000001"
|
||||
+ HelpRequiringPassphrase());
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DarkCoin address");
|
||||
|
||||
// Amount
|
||||
int64_t nAmount = AmountFromValue(params[1]);
|
||||
|
||||
// Wallet comments
|
||||
CWalletTx wtx;
|
||||
string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx, ONLY_DENOMINATED);
|
||||
if (strError != "")
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strError);
|
||||
|
||||
return wtx.GetHash().GetHex();
|
||||
}
|
||||
|
||||
|
||||
Value getpoolinfo(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 0)
|
||||
throw runtime_error(
|
||||
"getpoolinfo\n"
|
||||
"Returns an object containing anonymous pool-related information.");
|
||||
|
||||
Object obj;
|
||||
obj.push_back(Pair("current_masternode", GetCurrentMasterNode()));
|
||||
obj.push_back(Pair("state", darkSendPool.GetState()));
|
||||
obj.push_back(Pair("entries", darkSendPool.GetEntriesCount()));
|
||||
obj.push_back(Pair("entries_accepted", darkSendPool.GetCountEntriesAccepted()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
Value masternode(const Array& params, bool fHelp)
|
||||
{
|
||||
string strCommand;
|
||||
if (params.size() >= 1)
|
||||
strCommand = params[0].get_str();
|
||||
|
||||
if (fHelp ||
|
||||
(strCommand != "start" && strCommand != "start-many" && strCommand != "stop" && strCommand != "list" && strCommand != "count" && strCommand != "enforce"
|
||||
&& strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect"))
|
||||
throw runtime_error(
|
||||
"masternode <start|start-many|stop|list|count|debug|current|winners|genkey|enforce> passphrase\n");
|
||||
|
||||
if (strCommand == "stop")
|
||||
{
|
||||
if(!fMasterNode) return "you must set masternode=1 in the configuration";
|
||||
|
||||
if(pwalletMain->IsLocked()) {
|
||||
SecureString strWalletPass;
|
||||
strWalletPass.reserve(100);
|
||||
|
||||
if (params.size() == 2){
|
||||
strWalletPass = params[1].get_str().c_str();
|
||||
} else {
|
||||
throw runtime_error(
|
||||
"Your wallet is locked, passphrase is required\n");
|
||||
}
|
||||
|
||||
if(!pwalletMain->Unlock(strWalletPass)){
|
||||
return "incorrect passphrase";
|
||||
}
|
||||
}
|
||||
|
||||
activeMasternode.RegisterAsMasterNode(true);
|
||||
pwalletMain->Lock();
|
||||
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_STOPPED) return "successfully stopped masternode";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_NOT_CAPABLE) return "not capable masternode";
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
if (strCommand == "list")
|
||||
{
|
||||
std::string strCommand = "active";
|
||||
|
||||
if (params.size() == 2){
|
||||
strCommand = params[1].get_str().c_str();
|
||||
}
|
||||
|
||||
if (strCommand != "active" && strCommand != "vin" && strCommand != "pubkey" && strCommand != "lastseen" && strCommand != "activeseconds" && strCommand != "rank" && strCommand != "protocol"){
|
||||
throw runtime_error(
|
||||
"list supports 'active', 'vin', 'pubkey', 'lastseen', 'activeseconds', 'rank', 'protocol'\n");
|
||||
}
|
||||
|
||||
Object obj;
|
||||
BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) {
|
||||
mn.Check();
|
||||
|
||||
if(strCommand == "active"){
|
||||
obj.push_back(Pair(mn.addr.ToString().c_str(), (int)mn.IsEnabled()));
|
||||
} else if (strCommand == "vin") {
|
||||
obj.push_back(Pair(mn.addr.ToString().c_str(), mn.vin.prevout.hash.ToString().c_str()));
|
||||
} else if (strCommand == "pubkey") {
|
||||
CScript pubkey;
|
||||
pubkey.SetDestination(mn.pubkey.GetID());
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pubkey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
obj.push_back(Pair(mn.addr.ToString().c_str(), address2.ToString().c_str()));
|
||||
} else if (strCommand == "protocol") {
|
||||
obj.push_back(Pair(mn.addr.ToString().c_str(), (int64_t)mn.protocolVersion));
|
||||
} else if (strCommand == "lastseen") {
|
||||
obj.push_back(Pair(mn.addr.ToString().c_str(), (int64_t)mn.lastTimeSeen));
|
||||
} else if (strCommand == "activeseconds") {
|
||||
obj.push_back(Pair(mn.addr.ToString().c_str(), (int64_t)(mn.lastTimeSeen - mn.now)));
|
||||
} else if (strCommand == "rank") {
|
||||
obj.push_back(Pair(mn.addr.ToString().c_str(), (int)(GetMasternodeRank(mn.vin, chainActive.Tip()->nHeight))));
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
if (strCommand == "count") return (int)darkSendMasterNodes.size();
|
||||
|
||||
if (strCommand == "start")
|
||||
{
|
||||
if(!fMasterNode) return "you must set masternode=1 in the configuration";
|
||||
|
||||
if(pwalletMain->IsLocked()) {
|
||||
SecureString strWalletPass;
|
||||
strWalletPass.reserve(100);
|
||||
|
||||
if (params.size() == 2){
|
||||
strWalletPass = params[1].get_str().c_str();
|
||||
} else {
|
||||
throw runtime_error(
|
||||
"Your wallet is locked, passphrase is required\n");
|
||||
}
|
||||
|
||||
if(!pwalletMain->Unlock(strWalletPass)){
|
||||
return "incorrect passphrase";
|
||||
}
|
||||
}
|
||||
|
||||
activeMasternode.RegisterAsMasterNode(false);
|
||||
pwalletMain->Lock();
|
||||
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_REMOTELY_ENABLED) return "masternode started remotely";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_INPUT_TOO_NEW) return "masternode input must have at least 15 confirmations";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_STOPPED) return "masternode is stopped";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_IS_CAPABLE) return "successfully started masternode";
|
||||
if(activeMasternode.masternodePortOpen == MASTERNODE_PORT_NOT_OPEN) return "inbound port is not open. Please open it and try again. (19999 for testnet and 9999 for mainnet)";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_NOT_CAPABLE) return "not capable masternode";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_SYNC_IN_PROCESS) return "sync in process. Must wait until client is synced to start.";
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
if (strCommand == "start-many")
|
||||
{
|
||||
boost::filesystem::path pathDebug = GetDataDir() / "masternode.conf";
|
||||
std::ifstream infile(pathDebug.string().c_str());
|
||||
|
||||
std::string line;
|
||||
int total = 0;
|
||||
int successful = 0;
|
||||
int fail = 0;
|
||||
while (std::getline(infile, line))
|
||||
{
|
||||
std::istringstream iss(line);
|
||||
std::string a, b;
|
||||
if (!(iss >> a >> b)) { break; } // error
|
||||
|
||||
total++;
|
||||
if(activeMasternode.RegisterAsMasterNodeRemoteOnly(a, b)){
|
||||
successful++;
|
||||
} else {
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
printf(" Successfully started %d masternodes, failed to start %d, total %d\n", successful, fail, total);
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
if (strCommand == "debug")
|
||||
{
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_REMOTELY_ENABLED) return "masternode started remotely";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_INPUT_TOO_NEW) return "masternode input must have at least 15 confirmations";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_IS_CAPABLE) return "successfully started masternode";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_STOPPED) return "masternode is stopped";
|
||||
if(activeMasternode.masternodePortOpen == MASTERNODE_PORT_NOT_OPEN) return "inbound port is not open. Please open it and try again. (19999 for testnet and 9999 for mainnet)";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_NOT_CAPABLE) return "not capable masternode";
|
||||
if(activeMasternode.isCapableMasterNode == MASTERNODE_SYNC_IN_PROCESS) return "sync in process. Must wait until client is synced to start.";
|
||||
|
||||
CTxIn vin = CTxIn();
|
||||
CPubKey pubkey = CScript();
|
||||
CKey key;
|
||||
bool found = activeMasternode.GetMasterNodeVin(vin, pubkey, key);
|
||||
if(!found){
|
||||
return "Missing masternode input, please look at the documentation for instructions on masternode creation";
|
||||
} else {
|
||||
return "No problems were found";
|
||||
}
|
||||
}
|
||||
|
||||
if (strCommand == "create")
|
||||
{
|
||||
|
||||
return "Not implemented yet, please look at the documentation for instructions on masternode creation";
|
||||
}
|
||||
|
||||
if (strCommand == "current")
|
||||
{
|
||||
int winner = GetCurrentMasterNode(1);
|
||||
if(winner >= 0) {
|
||||
return darkSendMasterNodes[winner].addr.ToString().c_str();
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
if (strCommand == "genkey")
|
||||
{
|
||||
CKey secret;
|
||||
secret.MakeNewKey(false);
|
||||
|
||||
return CBitcoinSecret(secret).ToString();
|
||||
}
|
||||
|
||||
if (strCommand == "winners")
|
||||
{
|
||||
Object obj;
|
||||
|
||||
for(int nHeight = chainActive.Tip()->nHeight-10; nHeight < chainActive.Tip()->nHeight+20; nHeight++)
|
||||
{
|
||||
CScript payee;
|
||||
if(masternodePayments.GetBlockPayee(nHeight, payee)){
|
||||
CTxDestination address1;
|
||||
ExtractDestination(payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
obj.push_back(Pair(boost::lexical_cast<std::string>(nHeight), address2.ToString().c_str()));
|
||||
} else {
|
||||
obj.push_back(Pair(boost::lexical_cast<std::string>(nHeight), ""));
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
if(strCommand == "enforce")
|
||||
{
|
||||
return (uint64_t)enforceMasternodePaymentsTime;
|
||||
}
|
||||
|
||||
if(strCommand == "connect")
|
||||
{
|
||||
std::string strAddress = "";
|
||||
if (params.size() == 2){
|
||||
strAddress = params[1].get_str().c_str();
|
||||
} else {
|
||||
throw runtime_error(
|
||||
"Masternode address required\n");
|
||||
}
|
||||
|
||||
CService addr = CService(strAddress);
|
||||
|
||||
if(ConnectNode((CAddress)addr, NULL, true)){
|
||||
return "successfully connected";
|
||||
} else {
|
||||
return "error connecting";
|
||||
}
|
||||
}
|
||||
|
||||
return Value::null;
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ Value getwork(const Array& params, bool fHelp)
|
||||
// Clear pindexPrev so future getworks make a new block, despite any failures from here on
|
||||
pindexPrev = NULL;
|
||||
|
||||
// Store the pindexBest used before CreateNewBlock, to avoid races
|
||||
// Store the chainActive.Tip() used before CreateNewBlock, to avoid races
|
||||
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||
CBlockIndex* pindexPrevNew = chainActive.Tip();
|
||||
nStart = GetTime();
|
||||
@ -498,7 +498,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
||||
// Clear pindexPrev so future calls make a new block, despite any failures from here on
|
||||
pindexPrev = NULL;
|
||||
|
||||
// Store the pindexBest used before CreateNewBlock, to avoid races
|
||||
// Store the chainActive.Tip() used before CreateNewBlock, to avoid races
|
||||
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||
CBlockIndex* pindexPrevNew = chainActive.Tip();
|
||||
nStart = GetTime();
|
||||
|
@ -269,6 +269,10 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */
|
||||
{ "verifymessage", &verifymessage, false, false, false },
|
||||
|
||||
/* Darkcoin features */
|
||||
{ "darksend", &darksend, false, false, true },
|
||||
{ "masternode", &masternode, false, false, true },
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
/* Wallet */
|
||||
{ "addmultisigaddress", &addmultisigaddress, false, false, true },
|
||||
@ -315,6 +319,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "gethashespersec", &gethashespersec, true, false, false },
|
||||
{ "getwork", &getwork, true, false, true },
|
||||
{ "setgenerate", &setgenerate, true, true, false },
|
||||
|
||||
#endif // ENABLE_WALLET
|
||||
};
|
||||
|
||||
@ -508,7 +513,7 @@ void StartRPCThreads()
|
||||
{
|
||||
unsigned char rand_pwd[32];
|
||||
RAND_bytes(rand_pwd, 32);
|
||||
string strWhatAmI = "To use bitcoind";
|
||||
string strWhatAmI = "To use darkcoind";
|
||||
if (mapArgs.count("-server"))
|
||||
strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
|
||||
else if (mapArgs.count("-daemon"))
|
||||
@ -517,13 +522,13 @@ void StartRPCThreads()
|
||||
_("%s, you must set a rpcpassword in the configuration file:\n"
|
||||
"%s\n"
|
||||
"It is recommended you use the following random password:\n"
|
||||
"rpcuser=bitcoinrpc\n"
|
||||
"rpcuser=darkcoinrpc\n"
|
||||
"rpcpassword=%s\n"
|
||||
"(you do not need to remember this password)\n"
|
||||
"The username and password MUST NOT be the same.\n"
|
||||
"If the file does not exist, create it with owner-readable-only file permissions.\n"
|
||||
"It is also recommended to set alertnotify so you are notified of problems;\n"
|
||||
"for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@foo.com\n"),
|
||||
"for example: alertnotify=echo %%s | mail -s \"Darkcoin Alert\" admin@foo.com\n"),
|
||||
strWhatAmI,
|
||||
GetConfigFile().string(),
|
||||
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
|
||||
@ -889,7 +894,7 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
|
||||
}
|
||||
|
||||
std::string HelpExampleCli(string methodname, string args){
|
||||
return "> bitcoin-cli " + methodname + " " + args + "\n";
|
||||
return "> darkcoin-cli " + methodname + " " + args + "\n";
|
||||
}
|
||||
|
||||
std::string HelpExampleRpc(string methodname, string args){
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Bitcoin RPC command dispatcher.
|
||||
* Darkcoin RPC command dispatcher.
|
||||
*/
|
||||
class CRPCTable
|
||||
{
|
||||
@ -188,4 +188,9 @@ extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool
|
||||
extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
|
||||
extern json_spirit::Value darksend(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value masternode(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||
// Copyright (c) 2014 The Darkcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
@ -76,13 +77,13 @@ Value getnewaddress(const Array& params, bool fHelp)
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error(
|
||||
"getnewaddress ( \"account\" )\n"
|
||||
"\nReturns a new Bitcoin address for receiving payments.\n"
|
||||
"\nReturns a new Darkcoin address for receiving payments.\n"
|
||||
"If 'account' is specified (recommended), it is added to the address book \n"
|
||||
"so payments received with the address will be credited to 'account'.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, optional) The account name for the address to be linked to. if not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
|
||||
"\nResult:\n"
|
||||
"\"bitcoinaddress\" (string) The new bitcoin address\n"
|
||||
"\"darkcoinaddress\" (string) The new darkcoin address\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getnewaddress", "")
|
||||
+ HelpExampleCli("getnewaddress", "\"\"")
|
||||
@ -153,11 +154,11 @@ Value getaccountaddress(const Array& params, bool fHelp)
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"getaccountaddress \"account\"\n"
|
||||
"\nReturns the current Bitcoin address for receiving payments to this account.\n"
|
||||
"\nReturns the current Darkcoin address for receiving payments to this account.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n"
|
||||
"\nResult:\n"
|
||||
"\"bitcoinaddress\" (string) The account bitcoin address\n"
|
||||
"\"darkcoinaddress\" (string) The account darkcoin address\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaccountaddress", "")
|
||||
+ HelpExampleCli("getaccountaddress", "\"\"")
|
||||
@ -181,7 +182,7 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error(
|
||||
"getrawchangeaddress\n"
|
||||
"\nReturns a new Bitcoin address, for receiving change.\n"
|
||||
"\nReturns a new Darkcoin address, for receiving change.\n"
|
||||
"This is for use with raw transactions, NOT normal use.\n"
|
||||
"\nResult:\n"
|
||||
"\"address\" (string) The address\n"
|
||||
@ -210,19 +211,19 @@ Value setaccount(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||
throw runtime_error(
|
||||
"setaccount \"bitcoinaddress\" \"account\"\n"
|
||||
"setaccount \"darkcoinaddress\" \"account\"\n"
|
||||
"\nSets the account associated with the given address.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"bitcoinaddress\" (string, required) The bitcoin address to be associated with an account.\n"
|
||||
"1. \"darkcoinaddress\" (string, required) The darkcoin address to be associated with an account.\n"
|
||||
"2. \"account\" (string, required) The account to assign the address to.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
|
||||
+ HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
|
||||
+ HelpExampleCli("setaccount", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\" \"tabby\"")
|
||||
+ HelpExampleRpc("setaccount", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\", \"tabby\"")
|
||||
);
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Darkcoin address");
|
||||
|
||||
|
||||
string strAccount;
|
||||
@ -247,20 +248,20 @@ Value getaccount(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"getaccount \"bitcoinaddress\"\n"
|
||||
"getaccount \"darkcoinaddress\"\n"
|
||||
"\nReturns the account associated with the given address.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"bitcoinaddress\" (string, required) The bitcoin address for account lookup.\n"
|
||||
"1. \"darkcoinaddress\" (string, required) The darkcoin address for account lookup.\n"
|
||||
"\nResult:\n"
|
||||
"\"accountname\" (string) the account address\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
|
||||
+ HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
|
||||
+ HelpExampleCli("getaccount", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\"")
|
||||
+ HelpExampleRpc("getaccount", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\"")
|
||||
);
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Darkcoin address");
|
||||
|
||||
string strAccount;
|
||||
map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
|
||||
@ -280,7 +281,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
|
||||
"1. \"account\" (string, required) The account name.\n"
|
||||
"\nResult:\n"
|
||||
"[ (json array of string)\n"
|
||||
" \"bitcoinaddress\" (string) a bitcoin address associated with the given account\n"
|
||||
" \"darkcoinaddress\" (string) a darkcoin address associated with the given account\n"
|
||||
" ,...\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
@ -306,11 +307,11 @@ Value sendtoaddress(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 2 || params.size() > 4)
|
||||
throw runtime_error(
|
||||
"sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" )\n"
|
||||
"sendtoaddress \"darkcoinaddress\" amount ( \"comment\" \"comment-to\" )\n"
|
||||
"\nSent an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
|
||||
+ HelpRequiringPassphrase() +
|
||||
"\nArguments:\n"
|
||||
"1. \"bitcoinaddress\" (string, required) The bitcoin address to send to.\n"
|
||||
"1. \"darkcoinaddress\" (string, required) The darkcoin address to send to.\n"
|
||||
"2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
|
||||
"3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
|
||||
" This is not part of the transaction, just kept in your wallet.\n"
|
||||
@ -327,7 +328,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Darkcoin address");
|
||||
|
||||
// Amount
|
||||
int64_t nAmount = AmountFromValue(params[1]);
|
||||
@ -360,7 +361,7 @@ Value listaddressgroupings(const Array& params, bool fHelp)
|
||||
"[\n"
|
||||
" [\n"
|
||||
" [\n"
|
||||
" \"bitcoinaddress\", (string) The bitcoin address\n"
|
||||
" \"darkcoinaddress\", (string) The darkcoin address\n"
|
||||
" amount, (numeric) The amount in btc\n"
|
||||
" \"account\" (string, optional) The account\n"
|
||||
" ]\n"
|
||||
@ -399,11 +400,11 @@ Value signmessage(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 2)
|
||||
throw runtime_error(
|
||||
"signmessage \"bitcoinaddress\" \"message\"\n"
|
||||
"signmessage \"darkcoinaddress\" \"message\"\n"
|
||||
"\nSign a message with the private key of an address"
|
||||
+ HelpRequiringPassphrase() + "\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the private key.\n"
|
||||
"1. \"darkcoinaddress\" (string, required) The darkcoin address to use for the private key.\n"
|
||||
"2. \"message\" (string, required) The message to create a signature of.\n"
|
||||
"\nResult:\n"
|
||||
"\"signature\" (string) The signature of the message encoded in base 64\n"
|
||||
@ -411,11 +412,11 @@ Value signmessage(const Array& params, bool fHelp)
|
||||
"\nUnlock the wallet for 30 seconds\n"
|
||||
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
|
||||
"\nCreate the signature\n"
|
||||
+ HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
|
||||
+ HelpExampleCli("signmessage", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\" \"my message\"") +
|
||||
"\nVerify the signature\n"
|
||||
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
|
||||
+ HelpExampleCli("verifymessage", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\" \"signature\" \"my message\"") +
|
||||
"\nAs json rpc\n"
|
||||
+ HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
|
||||
+ HelpExampleRpc("signmessage", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\", \"my message\"")
|
||||
);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
@ -450,29 +451,29 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||
throw runtime_error(
|
||||
"getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n"
|
||||
"\nReturns the total amount received by the given bitcoinaddress in transactions with at least minconf confirmations.\n"
|
||||
"getreceivedbyaddress \"darkcoinaddress\" ( minconf )\n"
|
||||
"\nReturns the total amount received by the given darkcoinaddress in transactions with at least minconf confirmations.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"bitcoinaddress\" (string, required) The bitcoin address for transactions.\n"
|
||||
"1. \"darkcoinaddress\" (string, required) The darkcoin address for transactions.\n"
|
||||
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
|
||||
"\nResult:\n"
|
||||
"amount (numeric) The total amount in btc received at this address.\n"
|
||||
"\nExamples:\n"
|
||||
"\nThe amount from transactions with at least 1 confirmation\n"
|
||||
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") +
|
||||
+ HelpExampleCli("getreceivedbyaddress", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\"") +
|
||||
"\nThe amount including unconfirmed transactions, zero confirmations\n"
|
||||
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 0") +
|
||||
+ HelpExampleCli("getreceivedbyaddress", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\" 0") +
|
||||
"\nThe amount with at least 6 confirmation, very safe\n"
|
||||
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 6") +
|
||||
+ HelpExampleCli("getreceivedbyaddress", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\" 6") +
|
||||
"\nAs a json rpc call\n"
|
||||
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
|
||||
+ HelpExampleRpc("getreceivedbyaddress", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\", 6")
|
||||
);
|
||||
|
||||
// Bitcoin address
|
||||
// Darkcoin address
|
||||
CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
|
||||
CScript scriptPubKey;
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Darkcoin address");
|
||||
scriptPubKey.SetDestination(address.Get());
|
||||
if (!IsMine(*pwalletMain,scriptPubKey))
|
||||
return (double)0.0;
|
||||
@ -732,13 +733,13 @@ Value sendfrom(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 3 || params.size() > 6)
|
||||
throw runtime_error(
|
||||
"sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
|
||||
"\nSent an amount from an account to a bitcoin address.\n"
|
||||
"sendfrom \"fromaccount\" \"todarkcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
|
||||
"\nSent an amount from an account to a darkcoin address.\n"
|
||||
"The amount is a real and is rounded to the nearest 0.00000001."
|
||||
+ HelpRequiringPassphrase() + "\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
|
||||
"2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
|
||||
"2. \"todarkcoinaddress\" (string, required) The darkcoin address to send funds to.\n"
|
||||
"3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
|
||||
"4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
|
||||
"5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
|
||||
@ -760,7 +761,7 @@ Value sendfrom(const Array& params, bool fHelp)
|
||||
string strAccount = AccountFromValue(params[0]);
|
||||
CBitcoinAddress address(params[1].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Darkcoin address");
|
||||
int64_t nAmount = AmountFromValue(params[2]);
|
||||
int nMinDepth = 1;
|
||||
if (params.size() > 3)
|
||||
@ -800,7 +801,7 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
"1. \"fromaccount\" (string, required) The account to send the funds from, can be \"\" for the default account\n"
|
||||
"2. \"amounts\" (string, required) A json object with addresses and amounts\n"
|
||||
" {\n"
|
||||
" \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
|
||||
" \"address\":amount (numeric) The darkcoin address is the key, the numeric amount in btc is the value\n"
|
||||
" ,...\n"
|
||||
" }\n"
|
||||
"3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
|
||||
@ -810,11 +811,11 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
" the number of addresses.\n"
|
||||
"\nExamples:\n"
|
||||
"\nSend two amounts to two different addresses:\n"
|
||||
+ HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
|
||||
+ HelpExampleCli("sendmany", "\"tabby\" \"{\\\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
|
||||
"\nSend two amounts to two different addresses setting the confirmation and comment:\n"
|
||||
+ HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
|
||||
+ HelpExampleCli("sendmany", "\"tabby\" \"{\\\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
|
||||
"\nAs a json rpc call\n"
|
||||
+ HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
|
||||
+ HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
|
||||
);
|
||||
|
||||
string strAccount = AccountFromValue(params[0]);
|
||||
@ -836,7 +837,7 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
{
|
||||
CBitcoinAddress address(s.name_);
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Darkcoin address: ")+s.name_);
|
||||
|
||||
if (setAddress.count(address))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
|
||||
@ -879,26 +880,26 @@ Value addmultisigaddress(const Array& params, bool fHelp)
|
||||
{
|
||||
string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
|
||||
"\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
|
||||
"Each key is a Bitcoin address or hex-encoded public key.\n"
|
||||
"Each key is a Darkcoin address or hex-encoded public key.\n"
|
||||
"If 'account' is specified, assign address to that account.\n"
|
||||
|
||||
"\nArguments:\n"
|
||||
"1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
|
||||
"2. \"keysobject\" (string, required) A json array of bitcoin addresses or hex-encoded public keys\n"
|
||||
"2. \"keysobject\" (string, required) A json array of darkcoin addresses or hex-encoded public keys\n"
|
||||
" [\n"
|
||||
" \"address\" (string) bitcoin address or hex-encoded public key\n"
|
||||
" \"address\" (string) darkcoin address or hex-encoded public key\n"
|
||||
" ...,\n"
|
||||
" ]\n"
|
||||
"3. \"account\" (string, optional) An account to assign the addresses to.\n"
|
||||
|
||||
"\nResult:\n"
|
||||
"\"bitcoinaddress\" (string) A bitcoin address associated with the keys.\n"
|
||||
"\"darkcoinaddress\" (string) A darkcoin address associated with the keys.\n"
|
||||
|
||||
"\nExamples:\n"
|
||||
"\nAdd a multisig address from 2 addresses\n"
|
||||
+ HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
|
||||
+ HelpExampleCli("addmultisigaddress", "2 \"[\\\"Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs\\\",\\\"XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1\\\"]\"") +
|
||||
"\nAs json rpc call\n"
|
||||
+ HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
|
||||
+ HelpExampleRpc("addmultisigaddress", "2, \"[\\\"Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs\\\",\\\"XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1\\\"]\"")
|
||||
;
|
||||
throw runtime_error(msg);
|
||||
}
|
||||
@ -1192,7 +1193,7 @@ Value listtransactions(const Array& params, bool fHelp)
|
||||
" {\n"
|
||||
" \"account\":\"accountname\", (string) The account name associated with the transaction. \n"
|
||||
" It will be \"\" for the default account.\n"
|
||||
" \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n"
|
||||
" \"address\":\"darkcoinaddress\", (string) The darkcoin address of the transaction. Not present for \n"
|
||||
" move transactions (category = move).\n"
|
||||
" \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
|
||||
" transaction between accounts, and not associated with an address,\n"
|
||||
@ -1365,7 +1366,7 @@ Value listsinceblock(const Array& params, bool fHelp)
|
||||
"{\n"
|
||||
" \"transactions\": [\n"
|
||||
" \"account\":\"accountname\", (string) The account name associated with the transaction. Will be \"\" for the default account.\n"
|
||||
" \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
|
||||
" \"address\":\"darkcoinaddress\", (string) The darkcoin address of the transaction. Not present for move transactions (category = move).\n"
|
||||
" \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
|
||||
" \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
|
||||
" outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
|
||||
@ -1452,7 +1453,7 @@ Value gettransaction(const Array& params, bool fHelp)
|
||||
" \"details\" : [\n"
|
||||
" {\n"
|
||||
" \"account\" : \"accountname\", (string) The account name involved in the transaction, can be \"\" for the default account.\n"
|
||||
" \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n"
|
||||
" \"address\" : \"darkcoinaddress\", (string) The darkcoin address involved in the transaction\n"
|
||||
" \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
|
||||
" \"amount\" : x.xxx (numeric) The amount in btc\n"
|
||||
" }\n"
|
||||
@ -1560,11 +1561,11 @@ static void LockWallet(CWallet* pWallet)
|
||||
|
||||
Value walletpassphrase(const Array& params, bool fHelp)
|
||||
{
|
||||
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
|
||||
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
|
||||
throw runtime_error(
|
||||
"walletpassphrase \"passphrase\" timeout\n"
|
||||
"walletpassphrase \"passphrase\" <timeout> <anonymizeOnly>\n"
|
||||
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
|
||||
"This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
|
||||
"This is needed prior to performing transactions related to private keys such as sending darkcoins\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"passphrase\" (string, required) The wallet passphrase\n"
|
||||
"2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
|
||||
@ -1577,7 +1578,8 @@ Value walletpassphrase(const Array& params, bool fHelp)
|
||||
"\nLock the wallet again (before 60 seconds)\n"
|
||||
+ HelpExampleCli("walletlock", "") +
|
||||
"\nAs json rpc call\n"
|
||||
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
|
||||
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60") +
|
||||
"if [anonymizeonly] is true sending functions are disabled."
|
||||
);
|
||||
|
||||
if (fHelp)
|
||||
@ -1594,12 +1596,21 @@ Value walletpassphrase(const Array& params, bool fHelp)
|
||||
|
||||
if (strWalletPass.length() > 0)
|
||||
{
|
||||
if (!pwalletMain->Unlock(strWalletPass))
|
||||
bool anonymizeOnly;
|
||||
if (params.size() == 3)
|
||||
anonymizeOnly = params[2].get_bool();
|
||||
else
|
||||
anonymizeOnly = false;
|
||||
|
||||
if (!pwalletMain->IsLocked() && pwalletMain->fWalletUnlockAnonymizeOnly && anonymizeOnly)
|
||||
throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked.");
|
||||
|
||||
if (!pwalletMain->Unlock(strWalletPass, anonymizeOnly))
|
||||
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
|
||||
}
|
||||
else
|
||||
throw runtime_error(
|
||||
"walletpassphrase <passphrase> <timeout>\n"
|
||||
"walletpassphrase <passphrase> <timeout> <anonymizeOnly>\n"
|
||||
"Stores the wallet decryption key in memory for <timeout> seconds.");
|
||||
|
||||
pwalletMain->TopUpKeyPool();
|
||||
@ -1704,10 +1715,10 @@ Value encryptwallet(const Array& params, bool fHelp)
|
||||
"\nExamples:\n"
|
||||
"\nEncrypt you wallet\n"
|
||||
+ HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
|
||||
"\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
|
||||
"\nNow set the passphrase to use the wallet, such as for signing or sending darkcoin\n"
|
||||
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
|
||||
"\nNow we can so something like sign\n"
|
||||
+ HelpExampleCli("signmessage", "\"bitcoinaddress\" \"test message\"") +
|
||||
+ HelpExampleCli("signmessage", "\"darkcoinaddress\" \"test message\"") +
|
||||
"\nNow lock the wallet again by removing the passphrase\n"
|
||||
+ HelpExampleCli("walletlock", "") +
|
||||
"\nAs a json rpc call\n"
|
||||
@ -1737,7 +1748,7 @@ Value encryptwallet(const Array& params, bool fHelp)
|
||||
// slack space in .dat files; that is bad if the old data is
|
||||
// unencrypted private keys. So:
|
||||
StartShutdown();
|
||||
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
|
||||
return "wallet encrypted; darkcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
|
||||
}
|
||||
|
||||
Value lockunspent(const Array& params, bool fHelp)
|
||||
@ -1747,7 +1758,7 @@ Value lockunspent(const Array& params, bool fHelp)
|
||||
"lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
|
||||
"\nUpdates list of temporarily unspendable outputs.\n"
|
||||
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
|
||||
"A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
|
||||
"A locked transaction output will not be chosen by automatic coin selection, when spending darkcoins.\n"
|
||||
"Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
|
||||
"is always cleared (by virtue of process exit) when a node stops or fails.\n"
|
||||
"Also see the listunspent call\n"
|
||||
@ -1896,7 +1907,7 @@ Value getwalletinfo(const Array& params, bool fHelp)
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
|
||||
" \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
|
||||
" \"balance\": xxxxxxx, (numeric) the total darkcoin balance of the wallet\n"
|
||||
" \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
|
||||
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
|
||||
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
|
||||
|
@ -2057,3 +2057,28 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CScript::IsNormalPaymentScript() const
|
||||
{
|
||||
if(this->size() != 25) return false;
|
||||
|
||||
std::string str;
|
||||
opcodetype opcode;
|
||||
const_iterator pc = begin();
|
||||
int i = 0;
|
||||
while (pc < end())
|
||||
{
|
||||
GetOp(pc, opcode);
|
||||
|
||||
if( i == 0 && opcode != OP_DUP) return false;
|
||||
else if(i == 1 && opcode != OP_HASH160) return false;
|
||||
else if(i == 3 && opcode != OP_EQUALVERIFY) return false;
|
||||
else if(i == 4 && opcode != OP_CHECKSIG) return false;
|
||||
else if(i == 5) return false;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -641,7 +641,7 @@ public:
|
||||
return nFound;
|
||||
}
|
||||
|
||||
// Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs
|
||||
// Pre-version-0.6, Darkcoin always counted CHECKMULTISIGs
|
||||
// as 20 sigops. With pay-to-script-hash, that changed:
|
||||
// CHECKMULTISIGs serialized in scriptSigs are
|
||||
// counted more accurately, assuming they are of the form
|
||||
@ -652,6 +652,7 @@ public:
|
||||
// pay-to-script-hash transactions:
|
||||
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
||||
|
||||
bool IsNormalPaymentScript() const;
|
||||
bool IsPayToScriptHash() const;
|
||||
|
||||
// Called by IsStandardTx and P2SH VerifyScript (which makes it consensus-critical).
|
||||
|
@ -2,9 +2,9 @@ include $(top_srcdir)/src/Makefile.include
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/src
|
||||
|
||||
bin_PROGRAMS = test_bitcoin
|
||||
bin_PROGRAMS = test_darkcoin
|
||||
|
||||
TESTS = test_bitcoin
|
||||
TESTS = test_darkcoin
|
||||
|
||||
JSON_TEST_FILES = \
|
||||
data/script_valid.json \
|
||||
@ -22,16 +22,16 @@ RAW_TEST_FILES = data/alertTests.raw
|
||||
|
||||
BUILT_SOURCES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
|
||||
|
||||
# test_bitcoin binary #
|
||||
test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(TESTDEFS)
|
||||
test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||
# test_darkcoin binary #
|
||||
test_darkcoin_CPPFLAGS = $(AM_CPPFLAGS) $(TESTDEFS)
|
||||
test_darkcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB)
|
||||
if ENABLE_WALLET
|
||||
test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
|
||||
test_darkcoin_LDADD += $(LIBBITCOIN_WALLET)
|
||||
endif
|
||||
test_bitcoin_LDADD += $(BDB_LIBS)
|
||||
test_darkcoin_LDADD += $(BDB_LIBS)
|
||||
|
||||
test_bitcoin_SOURCES = \
|
||||
test_darkcoin_SOURCES = \
|
||||
alert_tests.cpp \
|
||||
allocator_tests.cpp \
|
||||
base32_tests.cpp \
|
||||
@ -57,7 +57,7 @@ test_bitcoin_SOURCES = \
|
||||
script_tests.cpp \
|
||||
serialize_tests.cpp \
|
||||
sigopcount_tests.cpp \
|
||||
test_bitcoin.cpp \
|
||||
test_darkcoin.cpp \
|
||||
transaction_tests.cpp \
|
||||
uint256_tests.cpp \
|
||||
util_tests.cpp \
|
||||
@ -66,12 +66,12 @@ test_bitcoin_SOURCES = \
|
||||
$(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
||||
|
||||
if ENABLE_WALLET
|
||||
test_bitcoin_SOURCES += \
|
||||
test_darkcoin_SOURCES += \
|
||||
accounting_tests.cpp \
|
||||
wallet_tests.cpp \
|
||||
rpc_wallet_tests.cpp
|
||||
endif
|
||||
|
||||
nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES)
|
||||
nodist_test_darkcoin_SOURCES = $(BUILT_SOURCES)
|
||||
|
||||
CLEANFILES = *.gcda *.gcno $(BUILT_SOURCES)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "txdb.h"
|
||||
#include "ui_interface.h"
|
||||
#include "util.h"
|
||||
#include "activemasternode.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "db.h"
|
||||
#include "wallet.h"
|
@ -368,6 +368,11 @@ public:
|
||||
return sizeof(pn);
|
||||
}
|
||||
|
||||
uint64_t Get64(int n=0) const
|
||||
{
|
||||
return pn[2*n] | (uint64_t)pn[2*n+1] << 32;
|
||||
}
|
||||
|
||||
uint64_t GetLow64() const
|
||||
{
|
||||
assert(WIDTH >= 2);
|
||||
|
16
src/util.cpp
16
src/util.cpp
@ -87,6 +87,22 @@ namespace boost {
|
||||
|
||||
using namespace std;
|
||||
|
||||
//Darkcoin only features
|
||||
bool fMasterNode = false;
|
||||
string strMasterNodePrivKey = "";
|
||||
string strMasterNodeAddr = "";
|
||||
int nInstantXDepth = 1;
|
||||
int nDarksendRounds = 2;
|
||||
int nAnonymizeDarkcoinAmount = 1000;
|
||||
int nLiquidityProvider = 0;
|
||||
/** Spork enforcement enabled time */
|
||||
int64_t enforceMasternodePaymentsTime = 4085657524;
|
||||
int nMasternodeMinProtocol = 0;
|
||||
bool fSucessfullyLoaded = false;
|
||||
bool fEnableDarksend = false;
|
||||
/** All denominations used by darksend */
|
||||
std::vector<int64_t> darkSendDenominations;
|
||||
|
||||
map<string, string> mapArgs;
|
||||
map<string, vector<string> > mapMultiArgs;
|
||||
bool fDebug = false;
|
||||
|
13
src/util.h
13
src/util.h
@ -92,7 +92,20 @@ inline void MilliSleep(int64_t n)
|
||||
#endif
|
||||
}
|
||||
|
||||
//Darkcoin only features
|
||||
|
||||
extern bool fMasterNode;
|
||||
extern int nInstantXDepth;
|
||||
extern int nDarksendRounds;
|
||||
extern int nAnonymizeDarkcoinAmount;
|
||||
extern int nLiquidityProvider;
|
||||
extern bool fEnableDarksend;
|
||||
extern int64_t enforceMasternodePaymentsTime;
|
||||
extern std::string strMasterNodeAddr;
|
||||
extern int nMasternodeMinProtocol;
|
||||
extern int keysLoaded;
|
||||
extern bool fSucessfullyLoaded;
|
||||
extern std::vector<int64_t> darkSendDenominations;
|
||||
|
||||
extern std::map<std::string, std::string> mapArgs;
|
||||
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
|
||||
|
@ -27,13 +27,13 @@ extern const std::string CLIENT_DATE;
|
||||
// network protocol versioning
|
||||
//
|
||||
|
||||
static const int PROTOCOL_VERSION = 71000;
|
||||
static const int PROTOCOL_VERSION = 70052;
|
||||
|
||||
// intial proto version, to be increased after version/verack negotiation
|
||||
static const int INIT_PROTO_VERSION = 209;
|
||||
|
||||
// disconnect from peers older than this proto version
|
||||
static const int MIN_PEER_PROTO_VERSION = 70043;
|
||||
static const int MIN_PEER_PROTO_VERSION = 70046;
|
||||
|
||||
// nTime field added to CAddress, starting with this version;
|
||||
// if possible, avoid requesting addresses nodes older than this
|
||||
|
597
src/wallet.cpp
597
src/wallet.cpp
@ -145,8 +145,14 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
|
||||
return CCryptoKeyStore::AddCScript(redeemScript);
|
||||
}
|
||||
|
||||
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
|
||||
bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool anonymizeOnly)
|
||||
{
|
||||
if (!IsLocked())
|
||||
{
|
||||
fWalletUnlockAnonymizeOnly = anonymizeOnly;
|
||||
return true;
|
||||
}
|
||||
|
||||
CCrypter crypter;
|
||||
CKeyingMaterial vMasterKey;
|
||||
|
||||
@ -159,7 +165,10 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
|
||||
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
|
||||
continue; // try another master key
|
||||
if (CCryptoKeyStore::Unlock(vMasterKey))
|
||||
{
|
||||
fWalletUnlockAnonymizeOnly = anonymizeOnly;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -683,6 +692,26 @@ int64_t CWallet::GetDebit(const CTxIn &txin) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t CWallet::IsDenominated(const CTxIn &txin) const
|
||||
{
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
|
||||
if (mi != mapWallet.end())
|
||||
{
|
||||
const CWalletTx& prev = (*mi).second;
|
||||
if (txin.prevout.n < prev.vout.size()){
|
||||
BOOST_FOREACH(int64_t d, darkSendDenominations){
|
||||
if(prev.vout[txin.prevout.n].nValue == d) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CWallet::IsChange(const CTxOut& txout) const
|
||||
{
|
||||
CTxDestination address;
|
||||
@ -905,14 +934,19 @@ void CWallet::ReacceptWalletTransactions()
|
||||
}
|
||||
}
|
||||
|
||||
void CWalletTx::RelayWalletTransaction()
|
||||
void CWalletTx::RelayWalletTransaction(std::string strCommand)
|
||||
{
|
||||
if (!IsCoinBase())
|
||||
{
|
||||
if (GetDepthInMainChain() == 0) {
|
||||
uint256 hash = GetHash();
|
||||
LogPrintf("Relaying wtx %s\n", hash.ToString());
|
||||
RelayTransaction((CTransaction)*this, hash);
|
||||
|
||||
if(strCommand == "txlreq"){
|
||||
RelayTransactionLockReq((CTransaction)*this, hash, true);
|
||||
} else {
|
||||
RelayTransaction((CTransaction)*this, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -994,6 +1028,95 @@ int64_t CWallet::GetBalance() const
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
int64_t CWallet::GetAnonymizedBalance() const
|
||||
{
|
||||
int64_t nTotal = 0;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
if (pcoin->IsTrusted()){
|
||||
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
|
||||
|
||||
COutput out = COutput(pcoin, i, pcoin->GetDepthInMainChain());
|
||||
CTxIn vin = CTxIn(out.tx->GetHash(), out.i);
|
||||
|
||||
if(IsSpent(out.tx->GetHash(), i) || !IsMine(pcoin->vout[i]) || !IsDenominated(vin)) continue;
|
||||
|
||||
int rounds = GetInputDarksendRounds(vin);
|
||||
if(rounds >= nDarksendRounds){
|
||||
nTotal += pcoin->vout[i].nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
double CWallet::GetAverageAnonymizedRounds() const
|
||||
{
|
||||
double fTotal = 0;
|
||||
double fCount = 0;
|
||||
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
|
||||
|
||||
COutput out = COutput(pcoin, i, pcoin->GetDepthInMainChain());
|
||||
CTxIn vin = CTxIn(out.tx->GetHash(), out.i);
|
||||
|
||||
if(IsSpent(out.tx->GetHash(), i) || !IsMine(pcoin->vout[i]) || !IsDenominated(vin)) continue;
|
||||
|
||||
int rounds = GetInputDarksendRounds(vin);
|
||||
fTotal += (float)rounds;
|
||||
fCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(fCount == 0) return 0;
|
||||
|
||||
return fTotal/fCount;
|
||||
}
|
||||
|
||||
int64_t CWallet::GetDenominatedBalance(bool onlyDenom, bool onlyUnconfirmed) const
|
||||
{
|
||||
int64_t nTotal = 0;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
|
||||
bool isDenom = false;
|
||||
for (unsigned int i = 0; i < pcoin->vout.size(); i++)
|
||||
BOOST_FOREACH(int64_t d, darkSendDenominations)
|
||||
if(pcoin->vout[i].nValue == d)
|
||||
isDenom = true;
|
||||
|
||||
if(onlyUnconfirmed){
|
||||
if (!pcoin->IsTrusted()){
|
||||
if(onlyDenom == isDenom){
|
||||
nTotal += pcoin->GetAvailableCredit();
|
||||
}
|
||||
}
|
||||
} else if (pcoin->IsTrusted()) {
|
||||
if(onlyDenom == isDenom) {
|
||||
nTotal += pcoin->GetAvailableCredit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
int64_t CWallet::GetUnconfirmedBalance() const
|
||||
{
|
||||
int64_t nTotal = 0;
|
||||
@ -1024,7 +1147,7 @@ int64_t CWallet::GetImmatureBalance() const
|
||||
}
|
||||
|
||||
// populate vCoins with vector of spendable COutputs
|
||||
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const
|
||||
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, AvailableCoinsType coin_type) const
|
||||
{
|
||||
vCoins.clear();
|
||||
|
||||
@ -1049,6 +1172,25 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
|
||||
continue;
|
||||
|
||||
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
|
||||
bool found = false;
|
||||
if(coin_type == ONLY_DENOMINATED) {
|
||||
//should make this a vector
|
||||
|
||||
COutput out = COutput(pcoin, i, pcoin->GetDepthInMainChain());
|
||||
CTxIn vin = CTxIn(out.tx->GetHash(), out.i);
|
||||
int rounds = GetInputDarksendRounds(vin);
|
||||
if(rounds >= nDarksendRounds) found = true;
|
||||
} else if(coin_type == ONLY_NONDENOMINATED) {
|
||||
found = true;
|
||||
BOOST_FOREACH(int64_t d, darkSendDenominations)
|
||||
if(pcoin->vout[i].nValue == d)
|
||||
found = false;
|
||||
|
||||
} else {
|
||||
found = true;
|
||||
}
|
||||
if(!found) continue;
|
||||
|
||||
if (!(IsSpent(wtxid, i)) && IsMine(pcoin->vout[i]) &&
|
||||
!IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0 &&
|
||||
(!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
|
||||
@ -1104,6 +1246,26 @@ static void ApproximateBestSubset(vector<pair<int64_t, pair<const CWalletTx*,uns
|
||||
}
|
||||
}
|
||||
|
||||
/* select coins with 1 unspent output */
|
||||
bool CWallet::SelectCoinsMasternode(CTxIn& vin, int64_t& nValueRet, CScript& pubScript) const
|
||||
{
|
||||
CCoinControl *coinControl=NULL;
|
||||
vector<COutput> vCoins;
|
||||
AvailableCoins(vCoins, true, coinControl, ALL_COINS);
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
{
|
||||
if(out.tx->vout[out.i].nValue == 1000*COIN){ //exactly
|
||||
vin = CTxIn(out.tx->GetHash(),out.i);
|
||||
pubScript = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
|
||||
nValueRet = out.tx->vout[out.i].nValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
|
||||
set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const
|
||||
{
|
||||
@ -1202,11 +1364,34 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl* coinControl) const
|
||||
bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl* coinControl, AvailableCoinsType coin_type) const
|
||||
{
|
||||
vector<COutput> vCoins;
|
||||
AvailableCoins(vCoins, true, coinControl);
|
||||
|
||||
//if we're doing only denominated, we need to round up to the nearest .1DRK
|
||||
if(coin_type == ONLY_DENOMINATED){
|
||||
// denominate our funds
|
||||
std::vector<CTxOut> vOut;
|
||||
|
||||
// Make outputs by looping through denominations, from large to small
|
||||
BOOST_FOREACH(int64_t v, darkSendDenominations)
|
||||
{
|
||||
int added = 0;
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
{
|
||||
if(out.tx->vout[out.i].nValue == v //make sure it's the denom we're looking for
|
||||
&& nValueRet + out.tx->vout[out.i].nValue < nTargetValue + (0.1*COIN)+1 //round the amount up to .1DRK over
|
||||
&& added <= 50){ //don't add more than 50 of one denom type
|
||||
nValueRet += out.tx->vout[out.i].nValue;
|
||||
setCoinsRet.insert(make_pair(out.tx, out.i));
|
||||
added++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (nValueRet >= nTargetValue);
|
||||
}
|
||||
|
||||
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
|
||||
if (coinControl && coinControl->HasSelected())
|
||||
{
|
||||
@ -1223,11 +1408,227 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
|
||||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet)));
|
||||
}
|
||||
|
||||
struct CompareByPriority
|
||||
{
|
||||
bool operator()(const COutput& t1,
|
||||
const COutput& t2) const
|
||||
{
|
||||
return t1.Priority() > t2.Priority();
|
||||
}
|
||||
};
|
||||
|
||||
bool CWallet::SelectCoinsDark(int64_t nValueMin, int64_t nValueMax, std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax, bool& hasFeeInput) const
|
||||
{
|
||||
CCoinControl *coinControl=NULL;
|
||||
|
||||
vector<COutput> vCoins;
|
||||
AvailableCoins(vCoins, false, coinControl, ALL_COINS);
|
||||
|
||||
set<pair<const CWalletTx*,unsigned int> > setCoinsRet2;
|
||||
|
||||
//order the array so fees are first, then denominated money, then the rest.
|
||||
sort(vCoins.rbegin(), vCoins.rend(), CompareByPriority());
|
||||
|
||||
//the first thing we get is a fee input, then we'll use as many denominated as possible. then the rest
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
{
|
||||
//there's no reason to allow inputs less than 1 COIN into DS (other than denominations smaller than that amount)
|
||||
if(out.tx->vout[out.i].nValue <= 1*COIN && out.tx->vout[out.i].nValue != (.1*COIN)+1) continue;
|
||||
if(fMasterNode && out.tx->vout[out.i].nValue == 1000*COIN) continue; //masternode input
|
||||
|
||||
if(nValueRet + out.tx->vout[out.i].nValue <= nValueMax){
|
||||
CTxIn vin = CTxIn(out.tx->GetHash(),out.i);
|
||||
|
||||
int rounds = GetInputDarksendRounds(vin);
|
||||
if(rounds >= nDarksendRoundsMax) continue;
|
||||
if(rounds < nDarksendRoundsMin) continue;
|
||||
|
||||
vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
|
||||
nValueRet += out.tx->vout[out.i].nValue;
|
||||
setCoinsRet.push_back(vin);
|
||||
setCoinsRet2.insert(make_pair(out.tx, out.i));
|
||||
}
|
||||
}
|
||||
|
||||
// if it's more than min, we're good to return
|
||||
if(nValueRet >= nValueMin) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CWallet::SelectCoinsCollateral(std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet) const
|
||||
{
|
||||
CCoinControl *coinControl=NULL;
|
||||
|
||||
vector<COutput> vCoins;
|
||||
|
||||
//printf(" selecting coins for collateral\n");
|
||||
AvailableCoins(vCoins, false, coinControl, ALL_COINS);
|
||||
|
||||
//printf("found coins %d\n", (int)vCoins.size());
|
||||
|
||||
set<pair<const CWalletTx*,unsigned int> > setCoinsRet2;
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
{
|
||||
// collateral inputs will always be a multiple of DARSEND_COLLATERAL, up to five
|
||||
if(
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 5)+DARKSEND_FEE ||
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 4)+DARKSEND_FEE ||
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 3)+DARKSEND_FEE ||
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 2)+DARKSEND_FEE ||
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 1)+DARKSEND_FEE
|
||||
){
|
||||
CTxIn vin = CTxIn(out.tx->GetHash(),out.i);
|
||||
|
||||
vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
|
||||
nValueRet += out.tx->vout[out.i].nValue;
|
||||
setCoinsRet.push_back(vin);
|
||||
setCoinsRet2.insert(make_pair(out.tx, out.i));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int CWallet::CountInputsWithAmount(int64_t nInputAmount)
|
||||
{
|
||||
int64_t nTotal = 0;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
if (pcoin->IsTrusted()){
|
||||
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
|
||||
COutput out = COutput(pcoin, i, pcoin->GetDepthInMainChain());
|
||||
CTxIn vin = CTxIn(out.tx->GetHash(), out.i);
|
||||
|
||||
if(out.tx->vout[out.i].nValue != nInputAmount) continue;
|
||||
|
||||
if(IsSpent(out.tx->GetHash(), i) || !IsMine(pcoin->vout[i]) || !IsDenominated(vin)) continue;
|
||||
|
||||
int rounds = GetInputDarksendRounds(vin);
|
||||
if(rounds >= nDarksendRounds){
|
||||
nTotal++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
bool CWallet::HasDarksendFeeInputs() const
|
||||
{
|
||||
CCoinControl *coinControl=NULL;
|
||||
|
||||
vector<COutput> vCoins;
|
||||
AvailableCoins(vCoins, false, coinControl, ALL_COINS);
|
||||
|
||||
bool found_collateral = false;
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
{
|
||||
if(
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 5)+DARKSEND_FEE ||
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 4)+DARKSEND_FEE ||
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 3)+DARKSEND_FEE ||
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 2)+DARKSEND_FEE ||
|
||||
out.tx->vout[out.i].nValue == (DARKSEND_COLLATERAL * 1)+DARKSEND_FEE
|
||||
) found_collateral = true;
|
||||
|
||||
}
|
||||
|
||||
return found_collateral;
|
||||
}
|
||||
|
||||
bool CWallet::SelectCoinsWithoutDenomination(int64_t nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const
|
||||
{
|
||||
CCoinControl *coinControl=NULL;
|
||||
|
||||
vector<COutput> vCoins;
|
||||
AvailableCoins(vCoins, true, coinControl, ONLY_NONDENOMINATED);
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
{
|
||||
nValueRet += out.tx->vout[out.i].nValue;
|
||||
setCoinsRet.insert(make_pair(out.tx, out.i));
|
||||
}
|
||||
return (nValueRet >= nTargetValue);
|
||||
}
|
||||
|
||||
bool CWallet::CreateCollateralTransaction(CTransaction& txCollateral, std::string strReason)
|
||||
{
|
||||
/*
|
||||
To doublespend a collateral transaction, it will require a fee higher than this. So there's
|
||||
still a significant cost.
|
||||
*/
|
||||
int64_t nFeeRet = 0.001*COIN;
|
||||
|
||||
txCollateral.vin.clear();
|
||||
txCollateral.vout.clear();
|
||||
|
||||
CReserveKey reservekey(this);
|
||||
int64_t nValueIn2 = 0;
|
||||
std::vector<CTxIn> vCoinsCollateral;
|
||||
|
||||
if (!SelectCoinsCollateral(vCoinsCollateral, nValueIn2))
|
||||
{
|
||||
strReason = "Error: Darksend requires a collateral transaction and could not locate an acceptable input!";
|
||||
return false;
|
||||
}
|
||||
|
||||
// make our change address
|
||||
CScript scriptChange;
|
||||
CPubKey vchPubKey;
|
||||
assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
|
||||
scriptChange.SetDestination(vchPubKey.GetID());
|
||||
reservekey.KeepKey();
|
||||
|
||||
BOOST_FOREACH(CTxIn v, vCoinsCollateral)
|
||||
txCollateral.vin.push_back(v);
|
||||
|
||||
if(nValueIn2 - DARKSEND_COLLATERAL - nFeeRet > 0) {
|
||||
//pay collateral charge in fees
|
||||
CTxOut vout3 = CTxOut(nValueIn2 - DARKSEND_COLLATERAL, scriptChange);
|
||||
txCollateral.vout.push_back(vout3);
|
||||
}
|
||||
|
||||
int vinNumber = 0;
|
||||
BOOST_FOREACH(CTxIn v, txCollateral.vin) {
|
||||
if(!SignSignature(*this, v.prevPubKey, txCollateral, vinNumber, int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))) {
|
||||
BOOST_FOREACH(CTxIn v, vCoinsCollateral)
|
||||
UnlockCoin(v.prevout);
|
||||
|
||||
strReason = "CDarkSendPool::Sign - Unable to sign collateral transaction! \n";
|
||||
return false;
|
||||
}
|
||||
vinNumber++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::ConvertList(std::vector<CTxIn> vCoins, std::vector<int64_t>& vecAmounts)
|
||||
{
|
||||
BOOST_FOREACH(CTxIn i, vCoins){
|
||||
if (mapWallet.count(i.prevout.hash))
|
||||
{
|
||||
CWalletTx& wtx = mapWallet[i.prevout.hash];
|
||||
if(i.prevout.n < wtx.vout.size()){
|
||||
vecAmounts.push_back(wtx.vout[i.prevout.n].nValue);
|
||||
}
|
||||
} else {
|
||||
LogPrintf("ConvertList -- Couldn't find transaction\n");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
|
||||
CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl)
|
||||
CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, AvailableCoinsType coin_type)
|
||||
{
|
||||
int64_t nValue = 0;
|
||||
BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
|
||||
@ -1274,11 +1675,19 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
|
||||
// Choose coins to use
|
||||
set<pair<const CWalletTx*,unsigned int> > setCoins;
|
||||
int64_t nValueIn = 0;
|
||||
if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl))
|
||||
if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl, coin_type))
|
||||
{
|
||||
strFailReason = _("Insufficient funds");
|
||||
if(coin_type == ALL_COINS)
|
||||
strFailReason = _("Insufficient funds");
|
||||
else if (coin_type == ONLY_NONDENOMINATED)
|
||||
strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction");
|
||||
else
|
||||
strFailReason = _("Unable to locate enough Darksend denominated funds for this transaction");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
|
||||
{
|
||||
int64_t nCredit = pcoin.first->vout[pcoin.second].nValue;
|
||||
@ -1399,7 +1808,7 @@ bool CWallet::CreateTransaction(CScript scriptPubKey, int64_t nValue,
|
||||
}
|
||||
|
||||
// Call after CreateTransaction unless you want to abort
|
||||
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
||||
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std::string strCommand)
|
||||
{
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
@ -1440,7 +1849,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
||||
LogPrintf("CommitTransaction() : Error: Transaction not valid");
|
||||
return false;
|
||||
}
|
||||
wtxNew.RelayWalletTransaction();
|
||||
wtxNew.RelayWalletTransaction(strCommand);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1448,19 +1857,31 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
|
||||
|
||||
|
||||
|
||||
string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew)
|
||||
string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, AvailableCoinsType coin_type)
|
||||
{
|
||||
CReserveKey reservekey(this);
|
||||
int64_t nFeeRequired;
|
||||
CCoinControl *coinControl=NULL;
|
||||
|
||||
if (IsLocked())
|
||||
{
|
||||
string strError = _("Error: Wallet locked, unable to create transaction!");
|
||||
LogPrintf("SendMoney() : %s", strError);
|
||||
LogPrintf("SendMoney() : %s\n", strError.c_str());
|
||||
return strError;
|
||||
}
|
||||
string strError;
|
||||
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError))
|
||||
if (fWalletUnlockAnonymizeOnly)
|
||||
{
|
||||
string strError = _("Error: Wallet unlocked for anonymization only, unable to create transaction.");
|
||||
LogPrintf("SendMoney() : %s\n", strError.c_str());
|
||||
return strError;
|
||||
}
|
||||
|
||||
CWalletTx wtx;
|
||||
std::vector<std::pair<CScript, int64_t> > vecSend;
|
||||
vecSend.push_back(make_pair(scriptPubKey, nValue));
|
||||
string strError = "";
|
||||
|
||||
if (!CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, strError, coinControl, coin_type))
|
||||
{
|
||||
if (nValue + nFeeRequired > 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));
|
||||
@ -1476,7 +1897,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe
|
||||
|
||||
|
||||
|
||||
string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nValue, CWalletTx& wtxNew)
|
||||
string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nValue, CWalletTx& wtxNew, AvailableCoinsType coin_type)
|
||||
{
|
||||
// Check amount
|
||||
if (nValue <= 0)
|
||||
@ -1488,11 +1909,141 @@ string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nV
|
||||
CScript scriptPubKey;
|
||||
scriptPubKey.SetDestination(address);
|
||||
|
||||
return SendMoney(scriptPubKey, nValue, wtxNew);
|
||||
return SendMoney(scriptPubKey, nValue, wtxNew, coin_type);
|
||||
}
|
||||
|
||||
int64_t CWallet::GetTotalValue(std::vector<CTxIn> vCoins) {
|
||||
int64_t nTotalValue = 0;
|
||||
CWalletTx wtx;
|
||||
BOOST_FOREACH(CTxIn i, vCoins){
|
||||
if (mapWallet.count(i.prevout.hash))
|
||||
{
|
||||
CWalletTx& wtx = mapWallet[i.prevout.hash];
|
||||
if(i.prevout.n < wtx.vout.size()){
|
||||
nTotalValue += wtx.vout[i.prevout.n].nValue;
|
||||
}
|
||||
} else {
|
||||
LogPrintf("GetTotalValue -- Couldn't find transaction\n");
|
||||
}
|
||||
}
|
||||
return nTotalValue;
|
||||
}
|
||||
|
||||
string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds, int64_t maxAmount)
|
||||
{
|
||||
if (IsLocked())
|
||||
return _("Error: Wallet locked, unable to create transaction!");
|
||||
|
||||
if(darkSendPool.GetState() != POOL_STATUS_ERROR && darkSendPool.GetState() != POOL_STATUS_SUCCESS){
|
||||
if(darkSendPool.GetMyTransactionCount() > 0){
|
||||
return _("Error: You already have pending entries in the Darksend pool");
|
||||
}
|
||||
}
|
||||
|
||||
// ** find the coins we'll use
|
||||
std::vector<CTxIn> vCoins;
|
||||
int64_t nValueIn = 0;
|
||||
CReserveKey reservekey(this);
|
||||
|
||||
//make sure we
|
||||
bool hasFeeInput = false;
|
||||
|
||||
//select coins we'll use
|
||||
if (!SelectCoinsDark(1*COIN, maxAmount, vCoins, nValueIn, minRounds, maxRounds, hasFeeInput))
|
||||
{
|
||||
vCoins.clear();
|
||||
|
||||
return _("Insufficient funds");
|
||||
}
|
||||
|
||||
// calculate total value out
|
||||
int64_t nTotalValue = GetTotalValue(vCoins);
|
||||
|
||||
LogPrintf("PrepareDarksendDenominate - preparing darksend denominate . Asked for: %d, Got: %d \n", maxAmount, nTotalValue);
|
||||
|
||||
//--------------
|
||||
|
||||
BOOST_FOREACH(CTxIn v, vCoins)
|
||||
LockCoin(v.prevout);
|
||||
|
||||
// denominate our funds
|
||||
int64_t nValueLeft = nTotalValue;
|
||||
std::vector<CTxOut> vOut;
|
||||
|
||||
//if minRounds >= 0, we want to use our exact denominations.
|
||||
if(minRounds >= 0){
|
||||
CWalletTx wtx;
|
||||
BOOST_FOREACH(CTxIn i, vCoins){
|
||||
if (mapWallet.count(i.prevout.hash))
|
||||
{
|
||||
CWalletTx& wtx = mapWallet[i.prevout.hash];
|
||||
if(i.prevout.n < wtx.vout.size()){
|
||||
CScript scriptChange;
|
||||
CPubKey vchPubKey;
|
||||
//use a unique change address
|
||||
assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
|
||||
scriptChange.SetDestination(vchPubKey.GetID());
|
||||
reservekey.KeepKey();
|
||||
|
||||
CTxOut o(wtx.vout[i.prevout.n].nValue, scriptChange);
|
||||
vOut.push_back(o);
|
||||
|
||||
//increment outputs and subtract denomination amount
|
||||
nValueLeft -= wtx.vout[i.prevout.n].nValue;
|
||||
}
|
||||
} else {
|
||||
LogPrintf("GetTotalValue -- Couldn't find transaction\n");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Make outputs by looping through denominations, from small to large
|
||||
BOOST_REVERSE_FOREACH(int64_t v, darkSendDenominations){
|
||||
int nOutputs = 0;
|
||||
|
||||
if(std::find(darkSendPool.vecDisabledDenominations.begin(),
|
||||
darkSendPool.vecDisabledDenominations.end(), v) !=
|
||||
darkSendPool.vecDisabledDenominations.end()){
|
||||
continue;
|
||||
}
|
||||
|
||||
// add each output up to 10 times until it can't be added again
|
||||
while(nValueLeft - v >= 0 && nOutputs <= 10) {
|
||||
CScript scriptChange;
|
||||
CPubKey vchPubKey;
|
||||
//use a unique change address
|
||||
assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
|
||||
scriptChange.SetDestination(vchPubKey.GetID());
|
||||
reservekey.KeepKey();
|
||||
|
||||
CTxOut o(v, scriptChange);
|
||||
vOut.push_back(o);
|
||||
|
||||
//increment outputs and subtract denomination amount
|
||||
nOutputs++;
|
||||
nValueLeft -= v;
|
||||
}
|
||||
|
||||
if(nValueLeft == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have anything left over, send it back as change
|
||||
if(nValueLeft > 0){
|
||||
CScript scriptChange;
|
||||
CPubKey vchPubKey;
|
||||
assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
|
||||
scriptChange.SetDestination(vchPubKey.GetID());
|
||||
reservekey.KeepKey();
|
||||
|
||||
CTxOut o(nValueLeft, scriptChange);
|
||||
vOut.push_back(o);
|
||||
}
|
||||
|
||||
darkSendPool.SendDarksendDenominate(vCoins, vOut, nValueIn);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
||||
{
|
||||
@ -1591,6 +2142,20 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||
return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString());
|
||||
}
|
||||
|
||||
bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
|
||||
{
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
|
||||
if (mi != mapWallet.end())
|
||||
{
|
||||
wtx = (*mi).second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
||||
{
|
||||
if (fFileBacked)
|
||||
|
81
src/wallet.h
81
src/wallet.h
@ -7,6 +7,7 @@
|
||||
#define BITCOIN_WALLET_H
|
||||
|
||||
#include "core.h"
|
||||
#include "darksend.h"
|
||||
#include "crypter.h"
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
@ -51,6 +52,13 @@ enum WalletFeature
|
||||
FEATURE_LATEST = 61000
|
||||
};
|
||||
|
||||
enum AvailableCoinsType
|
||||
{
|
||||
ALL_COINS = 1,
|
||||
ONLY_DENOMINATED = 2,
|
||||
ONLY_NONDENOMINATED = 3
|
||||
};
|
||||
|
||||
|
||||
/** A key pool entry */
|
||||
class CKeyPool
|
||||
@ -101,7 +109,6 @@ public:
|
||||
class CWallet : public CCryptoKeyStore, public CWalletInterface
|
||||
{
|
||||
private:
|
||||
bool SelectCoins(int64_t nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl *coinControl = NULL) const;
|
||||
|
||||
CWalletDB *pwalletdbEncryption;
|
||||
|
||||
@ -125,6 +132,17 @@ private:
|
||||
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
|
||||
|
||||
public:
|
||||
bool SelectCoins(int64_t nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS) const;
|
||||
bool SelectCoinsDark(int64_t nValueMin, int64_t nValueMax, std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax, bool& hasFeeInput) const;
|
||||
bool SelectCoinsDarkDenominated(int64_t nTargetValue, std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet) const;
|
||||
bool SelectCoinsMasternode(CTxIn& vin, int64_t& nValueRet, CScript& pubScript) const;
|
||||
bool HasDarksendFeeInputs() const;
|
||||
int CountInputsWithAmount(int64_t nInputAmount);
|
||||
|
||||
bool SelectCoinsCollateral(std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet) const ;
|
||||
bool SelectCoinsWithoutDenomination(int64_t nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const;
|
||||
bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
|
||||
|
||||
/// Main wallet lock.
|
||||
/// This lock protects all the fields added by CWallet
|
||||
/// except for:
|
||||
@ -133,6 +151,7 @@ public:
|
||||
mutable CCriticalSection cs_wallet;
|
||||
|
||||
bool fFileBacked;
|
||||
bool fWalletUnlockAnonymizeOnly;
|
||||
std::string strWalletFile;
|
||||
|
||||
std::set<int64_t> setKeyPool;
|
||||
@ -164,6 +183,7 @@ public:
|
||||
nNextResend = 0;
|
||||
nLastResend = 0;
|
||||
nTimeFirstKey = 0;
|
||||
fWalletUnlockAnonymizeOnly = false;
|
||||
}
|
||||
|
||||
std::map<uint256, CWalletTx> mapWallet;
|
||||
@ -184,7 +204,7 @@ public:
|
||||
// check whether we are allowed to upgrade (or already support) to the named feature
|
||||
bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
|
||||
|
||||
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL) const;
|
||||
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS) const;
|
||||
bool SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const;
|
||||
|
||||
bool IsSpent(const uint256& hash, unsigned int n) const;
|
||||
@ -194,6 +214,7 @@ public:
|
||||
void UnlockCoin(COutPoint& output);
|
||||
void UnlockAllCoins();
|
||||
void ListLockedCoins(std::vector<COutPoint>& vOutpts);
|
||||
int64_t GetTotalValue(std::vector<CTxIn> vCoins);
|
||||
|
||||
// keystore implementation
|
||||
// Generate a new key
|
||||
@ -223,7 +244,7 @@ public:
|
||||
/// Look up a destination data tuple in the store, return true if found false otherwise
|
||||
bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const;
|
||||
|
||||
bool Unlock(const SecureString& strWalletPassphrase);
|
||||
bool Unlock(const SecureString& strWalletPassphrase, bool anonimizeOnly = false);
|
||||
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
|
||||
bool EncryptWallet(const SecureString& strWalletPassphrase);
|
||||
|
||||
@ -254,13 +275,21 @@ public:
|
||||
int64_t GetBalance() const;
|
||||
int64_t GetUnconfirmedBalance() const;
|
||||
int64_t GetImmatureBalance() const;
|
||||
int64_t GetAnonymizedBalance() const;
|
||||
double GetAverageAnonymizedRounds() const;
|
||||
int64_t GetDenominatedBalance(bool onlyDenom=true, bool onlyUnconfirmed=false) const;
|
||||
|
||||
bool CreateTransaction(const std::vector<std::pair<CScript, int64_t> >& vecSend,
|
||||
CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL);
|
||||
CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS);
|
||||
|
||||
bool CreateTransaction(CScript scriptPubKey, int64_t nValue,
|
||||
CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL);
|
||||
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
|
||||
std::string SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew);
|
||||
std::string SendMoneyToDestination(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew);
|
||||
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std::string strCommand="tx");
|
||||
std::string SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, AvailableCoinsType coin_type=ALL_COINS);
|
||||
std::string SendMoneyToDestination(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew, AvailableCoinsType coin_type=ALL_COINS);
|
||||
std::string PrepareDarksendDenominate(int minRounds, int maxRounds, int64_t maxAmount);
|
||||
bool CreateCollateralTransaction(CTransaction& txCollateral, std::string strReason);
|
||||
bool ConvertList(std::vector<CTxIn> vCoins, std::vector<int64_t>& vecAmounts);
|
||||
|
||||
bool NewKeyPool();
|
||||
bool TopUpKeyPool(unsigned int kpSize = 0);
|
||||
@ -277,6 +306,23 @@ public:
|
||||
|
||||
std::set<CTxDestination> GetAccountAddresses(std::string strAccount) const;
|
||||
|
||||
int64_t IsDenominated(const CTxIn &txin) const;
|
||||
|
||||
int64_t IsDenominated(const CTransaction& tx) const
|
||||
{
|
||||
/*
|
||||
Return false if ANY inputs are non-denom
|
||||
*/
|
||||
bool ret = true;
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
{
|
||||
if(!IsDenominated(txin)) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool IsMine(const CTxIn& txin) const;
|
||||
int64_t GetDebit(const CTxIn& txin) const;
|
||||
bool IsMine(const CTxOut& txout) const
|
||||
@ -588,6 +634,13 @@ public:
|
||||
return nDebitCached;
|
||||
}
|
||||
|
||||
int64_t IsDenominated() const
|
||||
{
|
||||
if (vin.empty())
|
||||
return 0;
|
||||
return pwallet->IsDenominated(*this);
|
||||
}
|
||||
|
||||
int64_t GetCredit(bool fUseCache=true) const
|
||||
{
|
||||
// Must wait until coinbase is safely deep enough in the chain before valuing it
|
||||
@ -699,7 +752,7 @@ public:
|
||||
int64_t GetTxTime() const;
|
||||
int GetRequestCount() const;
|
||||
|
||||
void RelayWalletTransaction();
|
||||
void RelayWalletTransaction(std::string strCommand="tx");
|
||||
|
||||
std::set<uint256> GetConflicts() const;
|
||||
};
|
||||
@ -724,6 +777,18 @@ public:
|
||||
return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString().c_str(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str());
|
||||
}
|
||||
|
||||
//Used with Darksend. Will return fees, then denominations, everything else, then very small inputs that aren't fees
|
||||
int Priority() const
|
||||
{
|
||||
if(tx->vout[i].nValue == DARKSEND_FEE) return -20000;
|
||||
BOOST_FOREACH(int64_t d, darkSendDenominations)
|
||||
if(tx->vout[i].nValue == d) return 10000;
|
||||
if(tx->vout[i].nValue < 1*COIN) return 20000;
|
||||
|
||||
//nondenom return largest first
|
||||
return -(tx->vout[i].nValue/COIN);
|
||||
}
|
||||
|
||||
void print() const
|
||||
{
|
||||
LogPrintf("%s\n", ToString().c_str());
|
||||
|
Loading…
Reference in New Issue
Block a user