diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..912eeb9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,19 @@
+src/diamondd
+src/test_diamond
+
+# Ignore build dir
+build/
+
+# Compilation and Qt preprocessor part
+*.qm
+Makefile
+paycoin-qt
+
+# Resources cpp
+qrc_*.cpp
+
+# Qt creator
+*.pro.user
+
+# Mac specific
+.DS_Store
diff --git a/COPYING b/COPYING
index 8a76dbc..1554b1a 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (c) 2014 Diamond Developers
+Copyright (c) 2013-2016 Diamond Foundation
Copyright (c) 2011-2012 PPCoin Developers
Copyright (c) 2009-2012 Bitcoin Developers
diff --git a/README.md b/README.md
index e6e0674..026f3e4 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,46 @@
+------------------------------------------
+Diamond (DMD) Old Version - Do not use this Source !!
+---
+
+
+please be aware this codebase is soon set inactive
+DMD Diamond move forward to DMDv3 codebase
+balance from DMDv2 addresses will be available with same private keys in DMDv3
+
+to stay up to date following us on bitcointalk
+https://bitcointalk.org/index.php?topic=580725.0
+and twitter @dmdcoin
+
+
+------------------------------------------
Diamond (DMD)
+
+Instructions for compiling in Linux.
+
+Update ubuntu
+
+ sudo apt-get update
+
+*install git to download the source code
+
+ sudo apt-get install git
+
+*install the other necessary components
+
+ sudo apt-get install build-essential libboost1.55-all-dev libcurl4-openssl-dev libdb5.1-dev libdb5.1++-dev
+
+*navigate to the home directory
+
+ cd ~ *download the diamond source code
+
+ git clone https://github.com/DMDcoin/Diamond.git
+
+*navigate to the downloaded files
+
+ cd ~ *navigate to the src file in the source code
+ cd Diamond/src
+
+
+*build diamondd !This will take a while!
+
+ make -f makefile.unix USE_UPNP=-
diff --git a/contrib/macdeploy/fancy.plist b/contrib/macdeploy/fancy.plist
index 08c2a06..f7668b2 100644
--- a/contrib/macdeploy/fancy.plist
+++ b/contrib/macdeploy/fancy.plist
@@ -22,7 +22,7 @@
370
156
- NovaCoin-Qt.app
+ Diamond-Qt.app
128
156
diff --git a/contrib/macdeploy/notes.txt b/contrib/macdeploy/notes.txt
index 9b592fc..fd50d23 100644
--- a/contrib/macdeploy/notes.txt
+++ b/contrib/macdeploy/notes.txt
@@ -6,7 +6,7 @@ You will need the appscript package for the fancy disk image creation to work.
Install it by invoking "sudo easy_install appscript".
Ths script should be invoked in the target directory like this:
-$source_dir/contrib/macdeploy/macdeployqtplus NovaCoin-Qt.app -add-qt-tr da,de,es,hu,ru,uk,zh_CN,zh_TW -dmg -fancy $source_dir/contrib/macdeploy/fancy.plist -verbose 2
+$source_dir/contrib/macdeploy/macdeployqtplus Diamond-Qt.app -add-qt-tr da,de,es,hu,ru,uk,zh_CN,zh_TW -dmg -fancy $source_dir/contrib/macdeploy/fancy.plist -verbose 2
During the process, the disk image window will pop up briefly where the fancy
settings are applied. This is normal, please do not interfere.
@@ -19,8 +19,8 @@ Fill in the following.
Enable custom process step: [x]
Command: %{sourceDir}/contrib/macdeploy/macdeployqtplus
Working directory: %{buildDir}
-Command arguments: NovaCoin-Qt.app -add-qt-tr da,de,es,hu,ru,uk,zh_CN,zh_TW -dmg -fancy %{sourceDir}/contrib/macdeploy/fancy.plist -verbose 2
+Command arguments: Diamond-Qt.app -add-qt-tr da,de,es,hu,ru,uk,zh_CN,zh_TW -dmg -fancy %{sourceDir}/contrib/macdeploy/fancy.plist -verbose 2
After that you can start the deployment process through the menu with
-Build -> Deploy Project "novacoin-qt"
+Build -> Deploy Project "diamond-qt"
diff --git a/diamond.pro b/diamond.pro
index fa29a64..f4d851d 100644
--- a/diamond.pro
+++ b/diamond.pro
@@ -1,6 +1,6 @@
TEMPLATE = app
TARGET = diamond-qt
-VERSION = 0.1.0.2
+VERSION = 2.1.0.4
INCLUDEPATH += src src/json src/qt
QT += core gui network
DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN __NO_SYSTEM_INCLUDES
@@ -15,23 +15,34 @@ UI_DIR = build
# UNCOMMENT THIS SECTION TO BUILD ON WINDOWS
# Change paths if needed, these use the foocoin/deps.git repository locations
+win32 {
BOOST_LIB_SUFFIX=-mgw48-mt-s-1_55
BOOST_INCLUDE_PATH=C:/deps/boost_1_55_0
BOOST_LIB_PATH=C:/deps/boost_1_55_0/stage/lib
BDB_INCLUDE_PATH=C:/deps/db-4.8.30.NC/build_windows
BDB_LIB_PATH=C:/deps/db-4.8.30.NC/build_windows
-OPENSSL_INCLUDE_PATH=C:/deps/openssl-1.0.1g/include
-OPENSSL_LIB_PATH=C:/deps/openssl-1.0.1g
+OPENSSL_INCLUDE_PATH=C:/deps/openssl-1.0.1h/include
+OPENSSL_LIB_PATH=C:/deps/openssl-1.0.1h
MINIUPNPC_INCLUDE_PATH=C:/deps
-LIBPNG_INCLUDE_PATH=C:/deps/libpng-1.6.8
-LIBPNG_LIB_PATH=C:/deps/libpng-1.6.8/.libs
+LIBPNG_INCLUDE_PATH=C:/deps/libpng-1.6.10
+LIBPNG_LIB_PATH=C:/deps/libpng-1.6.10/.libs
MINIUPNPC_LIB_PATH=C:/deps/miniupnpc
+QRENCODE_INCLUDE_PATH=C:/deps/qrencode-3.4.3
QRENCODE_LIB_PATH=C:/deps/qrencode-3.4.3/.libs
+RELEASE=1
+CONFIG += static
+}
+
+# OS X Mavericks 10.9 build
+macx:QMAKE_MAC_SDK = macosx10.9
+macx:QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.9
+macx:USE_QRCODE=1
# use: qmake "RELEASE=1"
contains(RELEASE, 1) {
# Mac: compile for maximum compatibility (10.5, 32-bit)
- macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk
+# macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk
+
!windows:!macx {
# Linux: static link
@@ -48,6 +59,7 @@ QMAKE_LFLAGS *= -fstack-protector-all --param ssp-buffer-size=1
}
# for extra security on Windows: enable ASLR and DEP via GCC linker flags
win32:QMAKE_LFLAGS *= -Wl,--dynamicbase -Wl,--nxcompat
+win32:QMAKE_LFLAGS *= -Wl,--large-address-aware -static
lessThan(QT_MAJOR_VERSION, 5): win32: QMAKE_LFLAGS *= -static
# use: qmake "USE_QRCODE=1"
@@ -111,8 +123,27 @@ contains(BITCOIN_NEED_QT_PLUGINS, 1) {
DEFINES += HAVE_BUILD_INFO
}
-QMAKE_CXXFLAGS += -msse2
-QMAKE_CFLAGS += -msse2
+# If we have an ARM device, we can't use SSE2 instructions, so don't try to use them
+# Because of scrypt_mine.cpp, we also have to add a compile
+# flag that states we *really* don't have SSE
+QMAKE_XCPUARCH = $$QMAKE_HOST.arch
+equals(QMAKE_XCPUARCH, armv7l) {
+ message(Building without SSE2 support)
+ QMAKE_CXXFLAGS += -DNOSSE
+ QMAKE_CFLAGS += -DNOSSE
+}
+else:equals(QMAKE_XCPUARCH, armv6l) {
+ message(Building without SSE2 support)
+ QMAKE_CXXFLAGS += -DNOSSE
+ QMAKE_CFLAGS += -DNOSSE
+}
+else {
+ message(Building with SSE2 support)
+ QMAKE_CXXFLAGS += -msse2
+ QMAKE_CFLAGS += -msse2
+}
+#endif
+
QMAKE_CXXFLAGS_WARN_ON = -fdiagnostics-show-option -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wstack-protector
# Input
@@ -121,6 +152,8 @@ HEADERS += src/qt/bitcoingui.h \
src/qt/transactiontablemodel.h \
src/qt/addresstablemodel.h \
src/qt/optionsdialog.h \
+ src/qt/coincontroldialog.h \
+ src/qt/coincontroltreewidget.h \
src/qt/sendcoinsdialog.h \
src/qt/addressbookpage.h \
src/qt/signverifymessagedialog.h \
@@ -133,6 +166,7 @@ HEADERS += src/qt/bitcoingui.h \
src/bignum.h \
src/checkpoints.h \
src/compat.h \
+ src/coincontrol.h \
src/sync.h \
src/util.h \
src/uint256.h \
@@ -194,13 +228,17 @@ HEADERS += src/qt/bitcoingui.h \
src/hash.h \
src/scrypt.h \
src/sph_groestl.h \
- src/sph_types.h
+ src/sph_types.h \
+ src/auxpow.h \
+ src/reactors.h
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/transactiontablemodel.cpp \
src/qt/addresstablemodel.cpp \
src/qt/optionsdialog.cpp \
src/qt/sendcoinsdialog.cpp \
+ src/qt/coincontroldialog.cpp \
+ src/qt/coincontroltreewidget.cpp \
src/qt/addressbookpage.cpp \
src/qt/signverifymessagedialog.cpp \
src/qt/aboutdialog.cpp \
@@ -258,16 +296,21 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/kernel.cpp \
src/scrypt-x86.S \
src/scrypt-x86_64.S \
+ src/scrypt-arm.S \
src/scrypt_mine.cpp \
src/pbkdf2.cpp \
src/hash.cpp \
src/scrypt.cpp \
- src/groestl.c
+ src/groestl.c \
+ src/auxpow.cpp \
+ src/reactors.cpp \
+ src/reactorlist.cpp
RESOURCES += \
src/qt/bitcoin.qrc
FORMS += \
+ src/qt/forms/coincontroldialog.ui \
src/qt/forms/sendcoinsdialog.ui \
src/qt/forms/addressbookpage.ui \
src/qt/forms/signverifymessagedialog.ui \
@@ -372,7 +415,7 @@ macx:HEADERS += src/qt/macdockiconhandler.h
macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm
macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit
macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0
-macx:ICON = src/qt/res/icons/bitcoin.icns
+macx:ICON = src/qt/res/icons/Diamond.icns
macx:TARGET = "diamond-qt"
macx:QMAKE_CFLAGS_THREAD += -pthread
macx:QMAKE_LFLAGS_THREAD += -pthread
diff --git a/doc/README b/doc/README
index b567cb8..902345c 100644
--- a/doc/README
+++ b/doc/README
@@ -1,10 +1,6 @@
+Diamond 2.0.5.7
-Copyright (c) 2013-2014 Diamond Developers
-
-
-Diamond 0.3.0 BETA
-
-Copyright (c) 2013-2014 Diamond Developers
+Copyright (c) 2013-2015 Diamond Foundation
Copyright (c) 2013 NovaCoin Developers
Copyright (c) 2011-2012 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying
@@ -45,6 +41,6 @@ Start up the new diamondd.
See the documentation/wiki at the Diamond site:
- http://diamond.cc/
+ http://bit.diamonds/
for help and more information.
diff --git a/doc/README_windows.txt b/doc/README_windows.txt
index 68f0a9e..12aaa1c 100644
--- a/doc/README_windows.txt
+++ b/doc/README_windows.txt
@@ -1,10 +1,6 @@
+Diamond 2.0.5.7
-Copyright (c) 2013-2014 Diamond Developers
-
-
-Diamond 0.3.0 BETA
-
-Copyright (c) 2013-2014 Diamond Developers
+Copyright (c) 2013-2015 Diamond Foundation
Copyright (c) 2013 NovaCoin Developers
Copyright (c) 2011-2012 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying
@@ -47,6 +43,6 @@ Start up the new diamondd.
See the documentation/wiki at the Diamond site:
- http://diamond.cc/
+ http://bit.diamonds/
for help and more information.
diff --git a/doc/build-unix.txt b/doc/build-unix.txt
index 3dffb22..3388063 100644
--- a/doc/build-unix.txt
+++ b/doc/build-unix.txt
@@ -10,16 +10,26 @@ software written by Thomas Bernard.
UNIX BUILD NOTES
================
-To Build
+To Build On i386, amd64
--------
cd src/
-make -f makefile.unix # Headless bitcoin
+make -f makefile.unix # Headless diamond
+
+To Build On armv6l
+--------
+cd src/
+make -f makefile.unix xCPUARCH=armv6l # Headless diamond
+
+To Build On armv7l
+--------
+cd src/
+make -f makefile.unix xCPUARCH=armv7l # Headless diamond
See readme-qt.rst for instructions on building Bitcoin QT,
the graphical bitcoin.
-Dependencies
+Dependencies for i386, amd64
------------
Library Purpose Description
@@ -29,6 +39,19 @@ Dependencies
libboost Boost C++ Library
miniupnpc UPnP Support Optional firewall-jumping support
libqrencode QRCode generation Optional QRCode generation
+ libgmp3 GMP Multiple precision arithmetic library
+
+Dependencies for armv6l, armv7l
+------------
+
+ Library Purpose Description
+ ------- ------- -----------
+ libssl SSL Support Secure communications
+ libdb5.1 Berkeley DB Blockchain & wallet storage
+ libboost Boost C++ Library
+ miniupnpc UPnP Support Optional firewall-jumping support
+ libqrencode QRCode generation Optional QRCode generation
+ libgmp3 GMP Multiple precision arithmetic library
Note that libexecinfo should be installed, if you building under *BSD systems.
This library provides backtrace facility.
diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst
index 294f31a..faa28ea 100644
--- a/doc/readme-qt.rst
+++ b/doc/readme-qt.rst
@@ -1,20 +1,20 @@
-Bitcoin-qt: Qt4 GUI for Bitcoin
+Diamond-qt: Qt5 GUI for Diamond
===============================
Build instructions
===================
-Debian
+Debian (i386, amd64)
-------
-First, make sure that the required packages for Qt4 development of your
-distribution are installed, for Debian and Ubuntu these are:
+First, make sure that the required packages for Qt5 development of your
+distribution are installed, for Debian and Ubuntu (i386, amd64) these are:
::
- apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \
+ apt-get install qt5-qmake libqt5-dev build-essential libboost-dev libboost-system-dev \
libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \
- libssl-dev libdb4.8++-dev
+ libssl-dev libdb4.8++-dev libminiupnpc-dev libminiupnpc8
then execute the following:
@@ -23,9 +23,28 @@ then execute the following:
qmake
make
-Alternatively, install Qt Creator and open the `bitcoin-qt.pro` file.
+Debian (armv6l, armv7l)
+-------
+
+First, make sure that the required packages for Qt5 development of your
+distribution are installed, for Debian and Ubuntu (i386, amd64) these are:
+
+::
+
+ apt-get install qt5-qmake libqt5-dev build-essential libboost-dev libboost-system-dev \
+ libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \
+ libssl-dev libdb5.1++-dev libminiupnpc-dev libminiupnpc8
+
+then execute the following:
+
+::
+
+ qmake
+ make
+
+Alternatively, install Qt Creator and open the `diamond.pro` file.
-An executable named `bitcoin-qt` will be built.
+An executable named `diamond-qt` will be built.
Windows
@@ -59,7 +78,7 @@ Mac OS X
::
sudo port selfupdate
- sudo port install boost db48 miniupnpc
+ sudo port install boost db48 miniupnpc qrencode
- Open the .pro file in Qt Creator and build as normal (cmd-B)
@@ -138,7 +157,7 @@ Ubuntu 11.10 warning
====================
Ubuntu 11.10 has a package called 'qt-at-spi' installed by default. At the time of writing, having that package
-installed causes bitcoin-qt to crash intermittently. The issue has been reported as `launchpad bug 857790`_, but
+installed causes Diamond-qt to crash intermittently. The issue has been reported as `launchpad bug 857790`_, but
isn't yet fixed.
Until the bug is fixed, you can remove the qt-at-spi package to work around the problem, though this will presumably
diff --git a/src/auxpow.cpp b/src/auxpow.cpp
new file mode 100644
index 0000000..f8248c8
--- /dev/null
+++ b/src/auxpow.cpp
@@ -0,0 +1,129 @@
+// Copyright (c) 2011 Vince Durham
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#include "script.h"
+#include "auxpow.h"
+#include "init.h"
+
+using namespace std;
+using namespace boost;
+
+unsigned char pchMergedMiningHeader[] = { 0xfa, 0xbe, 'm', 'm' } ;
+
+void RemoveMergedMiningHeader(vector& vchAux)
+{
+ if (vchAux.begin() != std::search(vchAux.begin(), vchAux.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader)))
+ throw runtime_error("merged mining aux too short");
+ vchAux.erase(vchAux.begin(), vchAux.begin() + sizeof(pchMergedMiningHeader));
+}
+
+bool CAuxPow::Check(uint256 hashAuxBlock, int nChainID)
+{
+ if (nIndex != 0)
+ return error("AuxPow is not a generate");
+
+ if (!fTestNet && parentBlock.GetChainID() == nChainID)
+ return error("Aux POW parent has our chain ID");
+
+ if (vChainMerkleBranch.size() > 30)
+ return error("Aux POW chain merkle branch too long");
+
+ // Check that the chain merkle root is in the coinbase
+ uint256 nRootHash = CBlock::CheckMerkleBranch(hashAuxBlock, vChainMerkleBranch, nChainIndex);
+ vector vchRootHash(nRootHash.begin(), nRootHash.end());
+ std::reverse(vchRootHash.begin(), vchRootHash.end()); // correct endian
+
+ // Check that we are in the parent block merkle tree
+ if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != parentBlock.hashMerkleRoot)
+ return error("Aux POW merkle root incorrect");
+
+ const CScript script = vin[0].scriptSig;
+
+ // Check that the same work is not submitted twice to our chain.
+ //
+
+ CScript::const_iterator pcHead =
+ std::search(script.begin(), script.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader));
+
+ CScript::const_iterator pc =
+ std::search(script.begin(), script.end(), vchRootHash.begin(), vchRootHash.end());
+
+ if (pc == script.end())
+ return error("Aux POW missing chain merkle root in parent coinbase");
+
+ if (pcHead != script.end())
+ {
+ // Enforce only one chain merkle root by checking that a single instance of the merged
+ // mining header exists just before.
+ if (script.end() != std::search(pcHead + 1, script.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader)))
+ return error("Multiple merged mining headers in coinbase");
+ if (pcHead + sizeof(pchMergedMiningHeader) != pc)
+ return error("Merged mining header is not just before chain merkle root");
+ }
+ else
+ {
+ // For backward compatibility.
+ // Enforce only one chain merkle root by checking that it starts early in the coinbase.
+ // 8-12 bytes are enough to encode extraNonce and nBits.
+ if (pc - script.begin() > 20)
+ return error("Aux POW chain merkle root must start in the first 20 bytes of the parent coinbase");
+ }
+
+
+ // Ensure we are at a deterministic point in the merkle leaves by hashing
+ // a nonce and our chain ID and comparing to the index.
+ pc += vchRootHash.size();
+ if (script.end() - pc < 8)
+ return error("Aux POW missing chain merkle tree size and nonce in parent coinbase");
+
+ int nSize;
+ memcpy(&nSize, &pc[0], 4);
+ if (nSize != (1 << vChainMerkleBranch.size()))
+ return error("Aux POW merkle branch size does not match parent coinbase");
+
+ int nNonce;
+ memcpy(&nNonce, &pc[4], 4);
+
+ // Choose a pseudo-random slot in the chain merkle tree
+ // but have it be fixed for a size/nonce/chain combination.
+ //
+ // This prevents the same work from being used twice for the
+ // same chain while reducing the chance that two chains clash
+ // for the same slot.
+ int rand = nNonce;
+ rand = rand * 1103515245 + 12345;
+ rand += nChainID;
+ rand = rand * 1103515245 + 12345;
+
+ if (nChainIndex != (rand % nSize))
+ return error("Aux POW wrong index");
+
+ return true;
+}
+
+CScript MakeCoinbaseWithAux(unsigned int nHeight, unsigned int nExtraNonce,
+ vector& vchAux) {
+ vector vchAuxWithHeader(UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader));
+ vchAuxWithHeader.insert(vchAuxWithHeader.end(), vchAux.begin(), vchAux.end());
+
+ // Push OP_2 just in case we want versioning later
+ /* BIP34: v2 coin base must start with nHeight */
+ return(((CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS) << OP_2 << vchAuxWithHeader);
+}
+
+
+void IncrementExtraNonceWithAux(CBlock* pblock, CBlockIndex* pindexPrev,
+ unsigned int& nExtraNonce, vector& vchAux) {
+
+ // Update nExtraNonce
+ static uint256 hashPrevBlock;
+ if (hashPrevBlock != pblock->hashPrevBlock)
+ {
+ nExtraNonce = 0;
+ hashPrevBlock = pblock->hashPrevBlock;
+ }
+ ++nExtraNonce;
+
+ pblock->vtx[0].vin[0].scriptSig = MakeCoinbaseWithAux(pindexPrev->nHeight + 1, nExtraNonce, vchAux);
+ pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+}
diff --git a/src/auxpow.h b/src/auxpow.h
new file mode 100644
index 0000000..854d172
--- /dev/null
+++ b/src/auxpow.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_AUXPOW_H
+#define BITCOIN_AUXPOW_H
+
+#include "main.h"
+
+class CAuxPow : public CMerkleTx
+{
+public:
+ CAuxPow(const CTransaction& txIn) : CMerkleTx(txIn)
+ {
+ }
+
+ CAuxPow() :CMerkleTx()
+ {
+ }
+
+ // Merkle branch with root vchAux
+ // root must be present inside the coinbase
+ std::vector vChainMerkleBranch;
+ // Index of chain in chains merkle tree
+ int nChainIndex;
+ CBlock parentBlock;
+
+ IMPLEMENT_SERIALIZE
+ (
+ nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action);
+ nVersion = this->nVersion;
+ READWRITE(vChainMerkleBranch);
+ READWRITE(nChainIndex);
+
+ // Always serialize the saved parent block as header so that the size of CAuxPow
+ // is consistent.
+ nSerSize += SerReadWrite(s, parentBlock, nType | SER_BLOCKHEADERONLY, nVersion, ser_action);
+ )
+
+ bool Check(uint256 hashAuxBlock, int nChainID);
+
+ uint256 GetParentBlockHash() {
+ return(parentBlock.GetHashGroestl());
+ }
+};
+
+template
+int ReadWriteAuxPow(Stream& s, const boost::shared_ptr& auxpow, int nType, int nVersion, CSerActionGetSerializeSize ser_action)
+{
+ if (nVersion & BLOCK_VERSION_AUXPOW)
+ {
+ return ::GetSerializeSize(*auxpow, nType, nVersion);
+ }
+ return 0;
+}
+
+template
+int ReadWriteAuxPow(Stream& s, const boost::shared_ptr& auxpow, int nType, int nVersion, CSerActionSerialize ser_action)
+{
+ if (nVersion & BLOCK_VERSION_AUXPOW)
+ {
+ return SerReadWrite(s, *auxpow, nType, nVersion, ser_action);
+ }
+ return 0;
+}
+
+template
+int ReadWriteAuxPow(Stream& s, boost::shared_ptr& auxpow, int nType, int nVersion, CSerActionUnserialize ser_action)
+{
+ if (nVersion & BLOCK_VERSION_AUXPOW)
+ {
+ auxpow.reset(new CAuxPow());
+ return SerReadWrite(s, *auxpow, nType, nVersion, ser_action);
+ }
+ else
+ {
+ auxpow.reset();
+ return 0;
+ }
+}
+
+extern void RemoveMergedMiningHeader(std::vector& vchAux);
+extern void IncrementExtraNonceWithAux(CBlock* pblock, CBlockIndex* pindexPrev,
+ unsigned int& nExtraNonce, std::vector& vchAux);
+extern CScript MakeCoinbaseWithAux(unsigned int nBits, unsigned int nExtraNonce,
+ std::vector& vchAux);
+#endif
diff --git a/src/base58.h b/src/base58.h
index 3451e7a..2c616a9 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -280,7 +280,6 @@ class CBitcoinAddress : public CBase58Data
SCRIPT_ADDRESS = 8,
PUBKEY_ADDRESS_TEST = 111,
SCRIPT_ADDRESS_TEST = 196,
-
};
bool Set(const CKeyID &id) {
@@ -403,10 +402,16 @@ bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const {
class CBitcoinSecret : public CBase58Data
{
public:
+ enum
+ {
+ PRIVKEY_ADDRESS = CBitcoinAddress::PUBKEY_ADDRESS + 128,
+ PRIVKEY_ADDRESS_TEST = CBitcoinAddress::PUBKEY_ADDRESS_TEST + 128,
+ };
+
void SetSecret(const CSecret& vchSecret, bool fCompressed)
{
assert(vchSecret.size() == 32);
- SetData(128 + (fTestNet ? CBitcoinAddress::PUBKEY_ADDRESS_TEST : CBitcoinAddress::PUBKEY_ADDRESS), &vchSecret[0], vchSecret.size());
+ SetData(fTestNet ? PRIVKEY_ADDRESS_TEST : PRIVKEY_ADDRESS, &vchSecret[0], vchSecret.size());
if (fCompressed)
vchData.push_back(1);
}
@@ -425,10 +430,10 @@ class CBitcoinSecret : public CBase58Data
bool fExpectTestNet = false;
switch(nVersion)
{
- case (128 + CBitcoinAddress::PUBKEY_ADDRESS):
+ case PRIVKEY_ADDRESS:
break;
- case (128 + CBitcoinAddress::PUBKEY_ADDRESS_TEST):
+ case PRIVKEY_ADDRESS_TEST:
fExpectTestNet = true;
break;
diff --git a/src/bignum.h b/src/bignum.h
index c214275..c04fb0b 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -250,7 +250,6 @@ class CBigNum : public BIGNUM
return n;
}
-
void setvch(const std::vector& vch)
{
std::vector vch2(vch.size() + 4);
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 725e127..a2f4c68 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -208,8 +208,9 @@ static const CRPCCommand vRPCCommands[] =
{ "getpeerinfo", &getpeerinfo, true, false },
{ "getdifficulty", &getdifficulty, true, false },
{ "getgenerate", &getgenerate, true, false },
- //{ "setgenerate", &setgenerate, true, false },
+ { "setgenerate", &setgenerate, true, false },
{ "gethashespersec", &gethashespersec, true, false },
+ { "getnetworkhashps", &getnetworkhashps, true, false },
{ "getinfo", &getinfo, true, false },
{ "getmininginfo", &getmininginfo, true, false },
{ "getnewaddress", &getnewaddress, true, false },
@@ -246,10 +247,11 @@ static const CRPCCommand vRPCCommands[] =
{ "signmessage", &signmessage, false, false },
{ "verifymessage", &verifymessage, false, false },
{ "getwork", &getwork, true, false },
- { "getworkex", &getworkex, true, false },
+ { "getworkaux", &getworkaux, true, false },
{ "listaccounts", &listaccounts, false, false },
{ "settxfee", &settxfee, false, false },
{ "getblocktemplate", &getblocktemplate, true, false },
+ { "getauxblock", &getauxblock, true, false },
{ "submitblock", &submitblock, false, false },
{ "listsinceblock", &listsinceblock, false, false },
{ "dumpprivkey", &dumpprivkey, false, false },
@@ -261,12 +263,19 @@ static const CRPCCommand vRPCCommands[] =
{ "signrawtransaction", &signrawtransaction, false, false },
{ "sendrawtransaction", &sendrawtransaction, false, false },
{ "getcheckpoint", &getcheckpoint, true, false },
- { "reservebalance", &reservebalance, false, true},
- { "checkwallet", &checkwallet, false, true},
- { "repairwallet", &repairwallet, false, true},
- { "resendtx", &resendtx, false, true},
- { "makekeypair", &makekeypair, false, true},
- { "sendalert", &sendalert, false, false},
+ { "reservebalance", &reservebalance, false, true },
+ { "checkwallet", &checkwallet, false, true },
+ { "repairwallet", &repairwallet, false, true },
+ { "resendtx", &resendtx, false, true },
+ { "makekeypair", &makekeypair, false, true },
+ { "sendalert", &sendalert, false, false },
+ { "setchangeaddress", &setchangeaddress, true, false },
+ { "getchangeaddress", &getchangeaddress, true, false },
+ { "getscrapeaddress", &getscrapeaddress, true, false },
+ { "listscrapeaddresses", &listscrapeaddresses, true, false },
+ { "setscrapeaddress", &setscrapeaddress, true, true },
+ { "deletescrapeaddress", &deletescrapeaddress, true, true },
+ { "listreactordata", &listreactordata, true, false }
};
CRPCTable::CRPCTable()
@@ -511,7 +520,8 @@ bool ClientAllowed(const boost::asio::ip::address& address)
|| address.to_v6().is_v4_mapped()))
return ClientAllowed(address.to_v6().to_v4());
- std::string ipv4addr = address.to_string();
+ // danbi: not used
+ // std::string ipv4addr = address.to_string();
if (address == asio::ip::address_v4::loopback()
|| address == asio::ip::address_v6::loopback()
@@ -742,7 +752,7 @@ void ThreadRPCServer2(void* parg)
uiInterface.ThreadSafeMessageBox(strprintf(
_("%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=diamondrpc\n"
"rpcpassword=%s\n"
"(you do not need to remember this password)\n"
"If the file does not exist, create it with owner-readable-only file permissions.\n"),
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 09472eb..47d04c0 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -74,6 +74,9 @@ int CommandLineRPC(int argc, char *argv[]);
/** Convert parameter values for RPC call from strings to command-specific JSON objects. */
json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector &strParams);
+/** Call the RPC service directly (placed here to allow for more in depth tests). */
+json_spirit::Object CallRPC(const std::string &strMethod, const json_spirit::Array ¶ms);
+
/*
Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
the right number of arguments are passed, just that any passed are the correct type.
@@ -127,6 +130,9 @@ extern int64 nWalletUnlockTime;
extern int64 AmountFromValue(const json_spirit::Value& value);
extern json_spirit::Value ValueFromAmount(int64 amount);
extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
+
+extern double GetPoSKernelPS();
+
extern std::string HexBits(unsigned int nBits);
extern std::string HelpRequiringPassphrase();
extern void EnsureWalletIsUnlocked();
@@ -143,9 +149,10 @@ extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHe
extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getworkex(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getworkaux(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getauxblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp);
@@ -185,6 +192,7 @@ extern json_spirit::Value makekeypair(const json_spirit::Array& params, bool fHe
extern json_spirit::Value validatepubkey(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getnewpubkey(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value listreactordata(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp);
@@ -201,5 +209,12 @@ extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fH
extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblockbynumber(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getcheckpoint(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value setchangeaddress(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getchangeaddress(const json_spirit::Array& params, bool fHelp);
+
+extern json_spirit::Value setscrapeaddress(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getscrapeaddress(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value listscrapeaddresses(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value deletescrapeaddress(const json_spirit::Array& params, bool fHelp);
#endif
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index fa9d3c1..8cc9d25 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -36,7 +36,10 @@ namespace Checkpoints
(317997, uint256("0x000000007458dc82830320e592b9e0585efa68d01c3de479c14843af4942528e"))
(386222, uint256("0x000006a8c97fcba6e69278f2c5e21c2266ed12ecea07045e9214cb23f3d5eeaa"))
(386232, uint256("0x000004bf5ce28d4bf81a7f993de4443d5a5b2bd3290e7935f3096e5b7c40fe36"))
-
+ (443923, uint256("0x0000000001f9b10759fa67418e4c20a772ec39c3eff33742cb5899c7b50d7348"))
+ (468356, uint256("0x000000000543a19eaf97aa0ad933cb6423dedacb09786f4891126ac02bd8b7d4"))
+ (895493, uint256("0x0000000003140f322a3913d0d67b77b462b0bcdd2a4a0ec0cd791de743cf9202"))
+ (1500000, uint256("0x0000000008040b20b2e7ebdea7cf0c57d43195ec1da886b652339cb87253f369"))
;
static MapCheckpoints mapCheckpointsTestnet =
@@ -359,8 +362,8 @@ namespace Checkpoints
// sync-checkpoint should always be accepted block
assert(mapBlockIndex.count(hashSyncCheckpoint));
const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
- return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity ||
- pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime());
+ return((nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity) ||
+ (pindexSync->GetBlockTime() + nStakeMinAgeFixed < GetAdjustedTime()));
}
// Is the sync-checkpoint too old?
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 4f5db11..46147fb 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -118,7 +118,7 @@ class CSyncCheckpoint : public CUnsignedSyncCheckpoint
uint256 GetHash() const
{
- return SerializeHash(*this);
+ return(SerializeHash2(*this));
}
bool RelayTo(CNode* pnode) const
diff --git a/src/clientversion.h b/src/clientversion.h
index 2bfa6e6..55df318 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -7,9 +7,9 @@
// These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 2
-#define CLIENT_VERSION_MINOR 0
-#define CLIENT_VERSION_REVISION 1
-#define CLIENT_VERSION_BUILD 0
+#define CLIENT_VERSION_MINOR 1
+#define CLIENT_VERSION_REVISION 0
+#define CLIENT_VERSION_BUILD 4
// Converts the parameter X to a string after macro replacement on X has been performed.
// Don't merge these into one macro!
diff --git a/src/coincontrol.h b/src/coincontrol.h
new file mode 100644
index 0000000..236b586
--- /dev/null
+++ b/src/coincontrol.h
@@ -0,0 +1,57 @@
+#ifndef COINCONTROL_H
+#define COINCONTROL_H
+
+/** Coin Control Features. */
+class CCoinControl
+{
+public:
+ CTxDestination destChange;
+
+ CCoinControl()
+ {
+ SetNull();
+ }
+
+ void SetNull()
+ {
+ destChange = CNoDestination();
+ setSelected.clear();
+ }
+
+ bool HasSelected() const
+ {
+ return (setSelected.size() > 0);
+ }
+
+ bool IsSelected(const uint256& hash, unsigned int n) const
+ {
+ COutPoint outpt(hash, n);
+ return (setSelected.count(outpt) > 0);
+ }
+
+ void Select(COutPoint& output)
+ {
+ setSelected.insert(output);
+ }
+
+ void UnSelect(COutPoint& output)
+ {
+ setSelected.erase(output);
+ }
+
+ void UnSelectAll()
+ {
+ setSelected.clear();
+ }
+
+ void ListSelected(std::vector& vOutpoints)
+ {
+ vOutpoints.assign(setSelected.begin(), setSelected.end());
+ }
+
+private:
+ std::set setSelected;
+
+};
+
+#endif // COINCONTROL_H
diff --git a/src/db.cpp b/src/db.cpp
index 221cadf..dbde1a7 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -9,6 +9,7 @@
#include "util.h"
#include "main.h"
#include "kernel.h"
+#include "auxpow.h"
#include
#include
#include
@@ -85,7 +86,11 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
dbenv.set_lg_bsize(1048576);
dbenv.set_lg_max(10485760);
- dbenv.set_lk_max_locks(10000);
+
+ // Bugfix: Bump lk_max_locks default to 537000, to safely handle reorgs with up to 5 blocks reversed
+ // dbenv.set_lk_max_locks(10000);
+ dbenv.set_lk_max_locks(537000);
+
dbenv.set_lk_max_objects(10000);
dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
dbenv.set_flags(DB_AUTO_COMMIT, 1);
@@ -106,6 +111,30 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
fDbEnvInit = true;
fMockDb = false;
+
+ // Check that the number of locks is sufficient (to prevent chain fork possibility, read http://bitcoin.org/may15 for more info)
+ u_int32_t nMaxLocks;
+ if (!dbenv.get_lk_max_locks(&nMaxLocks))
+ {
+ int nBlocks, nDeepReorg;
+ std::string strMessage;
+
+ nBlocks = nMaxLocks / 48768;
+ nDeepReorg = (nBlocks - 1) / 2;
+
+ printf("Final lk_max_locks is %lu, sufficient for (worst case) %d block%s in a single transaction (up to a %d-deep reorganization)\n", (unsigned long)nMaxLocks, nBlocks, (nBlocks == 1) ? "" : "s", nDeepReorg);
+ if (nDeepReorg < 3)
+ {
+ if (nBlocks < 1)
+ strMessage = strprintf(("Warning: DB_CONFIG has set_lk_max_locks %lu, which may be too low for a single block. If this limit is reached, Diamond may stop working."), (unsigned long)nMaxLocks);
+ else
+ strMessage = strprintf(("Warning: DB_CONFIG has set_lk_max_locks %lu, which may be too low for a common blockchain reorganization. If this limit is reached, Diamond may stop working."), (unsigned long)nMaxLocks);
+
+ strMiscWarning = strMessage;
+ printf("*** %s\n", strMessage.c_str());
+ }
+ }
+
return true;
}
@@ -622,7 +651,6 @@ bool CTxDB::LoadBlockIndex()
// Calculate bnChainTrust
vector > vSortedByHeight;
- map a = mapBlockIndex;
vSortedByHeight.reserve(mapBlockIndex.size());
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
{
@@ -652,7 +680,6 @@ bool CTxDB::LoadBlockIndex()
pindexBest = mapBlockIndex[hashBestChain];
nBestHeight = pindexBest->nHeight;
bnBestChainTrust = pindexBest->bnChainTrust;
-
printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%s date=%s\n",
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(),
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
@@ -677,13 +704,16 @@ bool CTxDB::LoadBlockIndex()
map, CBlockIndex*> mapBlockPos;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{
+ // calculate totalCoin for other routines that get called
+ totalCoin = pindex->nMoneySupply / COIN;
if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
break;
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("LoadBlockIndex() : block.ReadFromDisk failed");
// check level 1: verify block validity
- if (nCheckLevel>0 && !block.CheckBlock())
+ // DK properly pass totalCoin
+ if (nCheckLevel>0 && !block.CheckBlock(true, true, totalCoin))
{
printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
pindexFork = pindex->pprev;
@@ -805,10 +835,12 @@ bool CTxDB::LoadBlockIndexGuts()
if (!pcursor)
return false;
+ int count=0;
// Load mapBlockIndex
unsigned int fFlags = DB_SET_RANGE;
while (true)
{
+ count++;
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
if (fFlags == DB_SET_RANGE)
@@ -824,75 +856,117 @@ bool CTxDB::LoadBlockIndexGuts()
// Unserialize
try {
- string strType;
- ssKey >> strType;
- if (strType == "blockindex" && !fRequestShutdown)
- {
- CDiskBlockIndex diskindex;
- ssValue >> diskindex;
-
- totalCoinDB = diskindex.nMoneySupply / COIN;
- // Construct block index object
- uint256 blockHash;
- if(totalCoinDB <= VALUE_CHANGE)
- blockHash = diskindex.GetBlockHashScrypt();
- else
- blockHash = diskindex.GetBlockHashGroest();
-
- // Construct block index object
- CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
- pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
- pindexNew->pnext = InsertBlockIndex(diskindex.hashNext);
- pindexNew->nFile = diskindex.nFile;
- pindexNew->nBlockPos = diskindex.nBlockPos;
- pindexNew->nHeight = diskindex.nHeight;
- pindexNew->nMint = diskindex.nMint;
- pindexNew->nMoneySupply = diskindex.nMoneySupply;
- pindexNew->nFlags = diskindex.nFlags;
- pindexNew->nStakeModifier = diskindex.nStakeModifier;
- pindexNew->prevoutStake = diskindex.prevoutStake;
- pindexNew->nStakeTime = diskindex.nStakeTime;
- pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
- pindexNew->nVersion = diskindex.nVersion;
- pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
- pindexNew->nTime = diskindex.nTime;
- pindexNew->nBits = diskindex.nBits;
- pindexNew->nNonce = diskindex.nNonce;
-
- if(pindexNew->nMoneySupply / COIN == VALUE_CHANGE)
+ string strType;
+ ssKey >> strType;
+ if (strType == "blockindex" && !fRequestShutdown)
{
- pindexSave = pindexNew;
+ CDiskBlockIndex diskindex;
+ ssValue >> diskindex;
+
+ totalCoin = diskindex.nMoneySupply / COIN;
+ uint256 blockHash = diskindex.GetBlockHash();
+
+ // clean up junk from the block index
+ if (totalCoin == 0) {
+ // printf("money supply = 0\n");
+ // diskindex.print();
+ if (blockHash != (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
+ {
+ // not the genesis block, garbage anyway
+ // printf("deleted\n");
+ continue;
+ }
+ }
+ if(!fTestNet && (totalCoin == VALUE_CHANGE)) {
+// printf("height = %d, hash = %s\n", diskindex.nHeight, diskindex.GetBlockHash().ToString().c_str());
+// diskindex.print();
+ if (diskindex.hashNext == uint256("0x92134c4608025b6bd945731158391079590d0e7e0c60bd7d09a50c0b0251c6ac"))
+ {
+ // assign proper hash value
+// printf("changed\n");
+ diskindex.hashNext = uint256("0x00000d652b612a94e1c830bf4e05106438ea6b53372b29206f0b820d91a9b67b");
+ }
+ if (diskindex.GetBlockHash() == uint256("0xe12ddb2c35d84403b0a045574ecce223f7e2f0db4506e76ed3d43bc464ace40c"))
+ {
+ // this hash version should not be here, delete
+// printf("deleted\n");
+ continue;
+ }
+ }
+ // end cleanup
+
+ // Construct block index object
+ CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
+ pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
+ pindexNew->pnext = InsertBlockIndex(diskindex.hashNext);
+ pindexNew->nFile = diskindex.nFile;
+ pindexNew->nBlockPos = diskindex.nBlockPos;
+ pindexNew->nHeight = diskindex.nHeight;
+ pindexNew->nMint = diskindex.nMint;
+ pindexNew->nMoneySupply = diskindex.nMoneySupply;
+ pindexNew->nFlags = diskindex.nFlags;
+ pindexNew->nStakeModifier = diskindex.nStakeModifier;
+ pindexNew->prevoutStake = diskindex.prevoutStake;
+ pindexNew->nStakeTime = diskindex.nStakeTime;
+ pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
+ pindexNew->nVersion = diskindex.nVersion;
+ pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
+ pindexNew->nTime = diskindex.nTime;
+ pindexNew->nBits = diskindex.nBits;
+ pindexNew->nNonce = diskindex.nNonce;
+ pindexNew->auxpow = diskindex.auxpow;
+
+ if(!fTestNet && (totalCoin == VALUE_CHANGE))
+ pindexSave = pindexNew;
+ if(!fTestNet && (totalCoin == VALUE_CHANGE + 1))
+ pindexSaveNext = pindexNew;
+
+ // Watch for genesis block
+ if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
+ pindexGenesisBlock = pindexNew;
+
+ if (!pindexNew->CheckIndex())
+ return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
+
+ // ppcoin: build setStakeSeen
+ if (pindexNew->IsProofOfStake())
+ setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
}
- if(pindexNew->nMoneySupply / COIN == VALUE_CHANGE + 1)
+ else
{
- pindexSaveNext = pindexNew;
+ break; // if shutdown requested or finished loading block index
}
-
- // Watch for genesis block
- if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
- pindexGenesisBlock = pindexNew;
-
- if (!pindexNew->CheckIndex())
- return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
-
- // ppcoin: build setStakeSeen
- if (pindexNew->IsProofOfStake())
- setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
- }
- else
- {
- break; // if shutdown requested or finished loading block index
- }
} // try
catch (std::exception &e) {
return error("%s() : deserialize error", __PRETTY_FUNCTION__);
}
}
+
+// printf("loaded %d in block index\n", count);
+
if(pindexSaveNext != NULL && pindexSave != NULL && pindexSave->pnext == NULL)
+ {
+// printf("linked pnext at switch block\n");
pindexSave->pnext = pindexSaveNext;
+ }
pcursor->close();
+#if 0
+ printf ("verify mapBlockIndex\n");
+ count=0;
+ BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
+ {
+ CBlockIndex* pindex = item.second;
+ if (pindex->nHeight == 0) {
+ printf("nHeight=0 count=%d\n", count);
+ pindex->print();
+ }
+ count++;
+ }
+ printf("end verify\n");
+#endif
+
return true;
}
diff --git a/src/hash.h b/src/hash.h
index d46a463..97e366f 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -13,12 +13,19 @@
#include
#include
+// danbi: try to improve Groestl hashing
+#if defined(__GNUC__)
+ #define DATA_ALIGN16(x) x __attribute__ ((aligned(16)))
+#else
+ #define DATA_ALIGN16(x) __declspec(align(16)) x
+#endif
+
template
inline uint256 HashGroestl(const T1 pbegin, const T1 pend)
{
sph_groestl512_context ctx_gr[2];
- static unsigned char pblank[1];
- uint512 hash[2];
+ DATA_ALIGN16(static unsigned char pblank[1]);
+ DATA_ALIGN16(uint512 hash[2]);
sph_groestl512_init(&ctx_gr[0]);
sph_groestl512 (&ctx_gr[0], (pbegin == pend ? pblank : static_cast(&pbegin[0])), (pend - pbegin) * sizeof(pbegin[0]));
diff --git a/src/init.cpp b/src/init.cpp
index 990d191..07d3e98 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -10,6 +10,7 @@
#include "util.h"
#include "ui_interface.h"
#include "checkpoints.h"
+#include "reactors.h"
#include
#include
#include
@@ -27,6 +28,8 @@ using namespace boost;
CWallet* pwalletMain;
CClientUIInterface uiInterface;
+bool fUseFastIndex;
+
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
@@ -81,7 +84,7 @@ void Shutdown(void* parg)
delete pwalletMain;
NewThread(ExitTimeout, NULL);
Sleep(50);
- printf("DiamondCoin exited\n\n");
+ printf("Diamond exited\n\n");
fExit = true;
#ifndef QT_GUI
// ensure non-UI client gets exited here, but let Bitcoin-Qt reach 'return 0;' in bitcoin.cpp
@@ -124,7 +127,7 @@ bool AppInit(int argc, char* argv[])
//
// Parameters
//
- // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
+ // If Qt is used, parameters/diamond.conf are parsed in qt/bitcoin.cpp's main()
ParseParameters(argc, argv);
if (!boost::filesystem::is_directory(GetDataDir(false)))
{
@@ -136,12 +139,12 @@ bool AppInit(int argc, char* argv[])
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
// First part of help message is specific to bitcoind / RPC client
- std::string strUsage = _("DiamondCoin version") + " " + FormatFullVersion() + "\n\n" +
+ std::string strUsage = _("Diamond version") + " " + FormatFullVersion() + "\n\n" +
_("Usage:") + "\n" +
- " DiamondCoind [options] " + "\n" +
- " DiamondCoind [options] [params] " + _("Send command to -server or DiamondCoind") + "\n" +
- " DiamondCoind [options] help " + _("List commands") + "\n" +
- " DiamondCoind [options] help " + _("Get help for a command") + "\n";
+ " Diamondd [options] " + "\n" +
+ " Diamondd [options] [params] " + _("Send command to -server or Diamondd") + "\n" +
+ " Diamondd [options] help " + _("List commands") + "\n" +
+ " Diamondd [options] help " + _("Get help for a command") + "\n";
strUsage += "\n" + HelpMessage();
@@ -151,7 +154,7 @@ bool AppInit(int argc, char* argv[])
// Command-line RPC
for (int i = 1; i < argc; i++)
- if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "DiamondCoin:"))
+ if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "Diamond:"))
fCommandLine = true;
if (fCommandLine)
@@ -191,13 +194,13 @@ int main(int argc, char* argv[])
bool static InitError(const std::string &str)
{
- uiInterface.ThreadSafeMessageBox(str, _("DiamondCoin"), CClientUIInterface::OK | CClientUIInterface::MODAL);
+ uiInterface.ThreadSafeMessageBox(str, _("Diamond"), CClientUIInterface::OK | CClientUIInterface::MODAL);
return false;
}
bool static InitWarning(const std::string &str)
{
- uiInterface.ThreadSafeMessageBox(str, _("DiamondCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ uiInterface.ThreadSafeMessageBox(str, _("Diamond"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
return true;
}
@@ -219,8 +222,8 @@ std::string HelpMessage()
{
string strUsage = _("Options:") + "\n" +
" -? " + _("This help message") + "\n" +
- " -conf= " + _("Specify configuration file (default: DiamondCoin.conf)") + "\n" +
- " -pid= " + _("Specify pid file (default: DiamondCoind.pid)") + "\n" +
+ " -conf= " + _("Specify configuration file (default: Diamond.conf)") + "\n" +
+ " -pid= " + _("Specify pid file (default: Diamondd.pid)") + "\n" +
" -gen " + _("Generate coins") + "\n" +
" -gen=0 " + _("Don't generate coins") + "\n" +
" -datadir= " + _("Specify data directory") + "\n" +
@@ -239,7 +242,7 @@ std::string HelpMessage()
" -externalip= " + _("Specify your own public address") + "\n" +
" -onlynet= " + _("Only connect to nodes in network (IPv4, IPv6 or Tor)") + "\n" +
" -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" +
- " -irc " + _("Find peers using internet relay chat (default: 1)") + "\n" +
+ " -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" +
" -bind= " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
" -dnsseed " + _("Find peers using DNS lookup (default: 0)") + "\n" +
@@ -278,11 +281,13 @@ std::string HelpMessage()
" -rpcallowip= " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
" -rpcconnect= " + _("Send commands to node running on (default: 127.0.0.1)") + "\n" +
" -blocknotify= " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
- " -walletnotify= " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" +
+ " -walletnotify= " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" +
" -upgradewallet " + _("Upgrade wallet to latest format") + "\n" +
" -keypool= " + _("Set key pool size to (default: 100)") + "\n" +
" -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" +
" -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" +
+ " -zapwallettxes= " + _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup\n") +
+ " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)\n") +
" -checkblocks= " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
" -checklevel= " + _("How thorough the block verification is (0-6, default: 1)") + "\n" +
" -loadblock= " + _("Imports blocks from external blk000?.dat file") + "\n" +
@@ -351,7 +356,6 @@ bool AppInit2()
// ********************************************************* Step 2: parameter interactions
fTestNet = GetBoolArg("-testnet");
- //fTestNet = true;
if (fTestNet) {
SoftSetBoolArg("-irc", true);
}
@@ -389,6 +393,11 @@ bool AppInit2()
SoftSetBoolArg("-rescan", true);
}
+ if (GetBoolArg("-zapwallettxes", false)) {
+ // -zapwallettx implies a rescan
+ SoftSetBoolArg("-rescan", true);
+ }
+
// ********************************************************* Step 3: parameter-to-internal-flags
fDebug = GetBoolArg("-debug");
@@ -419,7 +428,7 @@ bool AppInit2()
fPrintToConsole = GetBoolArg("-printtoconsole");
fPrintToDebugger = GetBoolArg("-printtodebugger");
fLogTimestamps = GetBoolArg("-logtimestamps");
- fLogTimestamps = true;
+
if (mapArgs.count("-timeout"))
{
int nNewTimeout = GetArg("-timeout", 5000);
@@ -427,6 +436,16 @@ bool AppInit2()
nConnectTimeout = nNewTimeout;
}
+ fUseFastIndex = GetBoolArg("-fastindex", true);
+
+ if (mapArgs.count("-changeaddress"))
+ {
+ CBitcoinAddress address(GetArg("-changeaddress", ""));
+ if (!address.IsValid())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Diamond address");
+ changeAddress = address.Get();
+ }
+
// Continue to put "/P2SH/" in the coinbase to monitor
// BIP16 support.
// This can be removed eventually...
@@ -452,7 +471,7 @@ bool AppInit2()
if (file) fclose(file);
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock())
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. DiamondCoin is probably already running."), strDataDir.c_str()));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Diamond is probably already running."), strDataDir.c_str()));
#if !defined(WIN32) && !defined(QT_GUI)
if (fDaemon)
@@ -479,7 +498,7 @@ bool AppInit2()
if (GetBoolArg("-shrinkdebugfile", !fDebug))
ShrinkDebugFile();
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
- printf("DiamondCoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
+ printf("Diamond version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
printf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
if (!fLogTimestamps)
printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
@@ -488,13 +507,14 @@ bool AppInit2()
std::ostringstream strErrors;
if (fDaemon)
- fprintf(stdout, "DiamondCoin server starting\n");
+ fprintf(stdout, "Diamond server starting\n");
int64 nStart;
// ********************************************************* Step 5: verify database integrity
uiInterface.InitMessage(_("Verifying database integrity..."));
+ printf("Verifying database integrity...\n");
if (!bitdb.Open(GetDataDir()))
{
@@ -520,7 +540,7 @@ bool AppInit2()
" Original wallet.dat saved as wallet.{timestamp}.bak in %s; if"
" your balance or transactions are incorrect you should"
" restore from a backup."), strDataDir.c_str());
- uiInterface.ThreadSafeMessageBox(msg, _("DiamondCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ uiInterface.ThreadSafeMessageBox(msg, _("Diamond"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
}
if (r == CDBEnv::RECOVER_FAIL)
return InitError(_("wallet.dat corrupt, salvage failed"));
@@ -647,7 +667,6 @@ bool AppInit2()
BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest);
- AddOneShot("54.229.220.59");
// TODO: replace this by DNSseed
// AddOneShot(string(""));
@@ -717,6 +736,25 @@ bool AppInit2()
// ********************************************************* Step 8: load wallet
+ // needed to restore wallet transaction meta data after -zapwallettxes
+ std::vector vWtx;
+
+ if (GetBoolArg("-zapwallettxes", false)) {
+ uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
+ printf("Zapping all transactions from wallet...\n");
+
+ pwalletMain = new CWallet("wallet.dat");
+ DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx);
+ if (nZapWalletRet != DB_LOAD_OK) {
+ uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted"));
+ printf("Error loading wallet.dat: Wallet corrupted\n");
+ return false;
+ }
+
+ delete pwalletMain;
+ pwalletMain = NULL;
+ }
+
uiInterface.InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n");
nStart = GetTimeMillis();
@@ -731,13 +769,13 @@ bool AppInit2()
{
string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect."));
- uiInterface.ThreadSafeMessageBox(msg, _("DiamondCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ uiInterface.ThreadSafeMessageBox(msg, _("Diamond"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
}
else if (nLoadWalletRet == DB_TOO_NEW)
- strErrors << _("Error loading wallet.dat: Wallet requires newer version of DiamondCoin") << "\n";
+ strErrors << _("Error loading wallet.dat: Wallet requires newer version of Diamond") << "\n";
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
- strErrors << _("Wallet needed to be rewritten: restart DiamondCoin to complete") << "\n";
+ strErrors << _("Wallet needed to be rewritten: restart Diamond to complete") << "\n";
printf("%s", strErrors.str().c_str());
return InitError(strErrors.str());
}
@@ -796,6 +834,31 @@ bool AppInit2()
nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+
+ nWalletDBUpdated++;
+
+ // Restore wallet transaction metadata after -zapwallettxes=1
+ if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
+ {
+ BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
+ {
+ uint256 hash = wtxOld.GetHash();
+ std::map::iterator mi = pwalletMain->mapWallet.find(hash);
+ if (mi != pwalletMain->mapWallet.end())
+ {
+ const CWalletTx* copyFrom = &wtxOld;
+ CWalletTx* copyTo = &mi->second;
+ copyTo->mapValue = copyFrom->mapValue;
+ copyTo->vOrderForm = copyFrom->vOrderForm;
+ copyTo->nTimeReceived = copyFrom->nTimeReceived;
+ copyTo->nTimeSmart = copyFrom->nTimeSmart;
+ copyTo->fFromMe = copyFrom->fFromMe;
+ copyTo->strFromAccount = copyFrom->strFromAccount;
+ copyTo->nOrderPos = copyFrom->nOrderPos;
+ copyTo->WriteToDisk();
+ }
+ }
+ }
}
// ********************************************************* Step 9: import blocks
@@ -803,6 +866,7 @@ bool AppInit2()
if (mapArgs.count("-loadblock"))
{
uiInterface.InitMessage(_("Importing blockchain data file."));
+ printf("Importing blockchain data file.\n");
BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
{
@@ -815,6 +879,7 @@ bool AppInit2()
filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat";
if (filesystem::exists(pathBootstrap)) {
uiInterface.InitMessage(_("Importing bootstrap blockchain data file."));
+ printf("Importing bootstrap blockchain data file.\n");
FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
if (file) {
@@ -839,7 +904,16 @@ bool AppInit2()
printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n",
addrman.size(), GetTimeMillis() - nStart);
- // ********************************************************* Step 11: start node
+ // ********************************************************* Step 11: initialize reactor db
+
+ uiInterface.InitMessage(_("Loading reactors..."));
+ printf("Loading reactors...\n");
+ nStart = GetTimeMillis();
+
+ InitReactors();
+ printf(" reactors %" PRI64d "ms\n", GetTimeMillis() - nStart);
+
+ // ********************************************************* Step 12: start node
if (!CheckDiskSpace())
return false;
@@ -859,7 +933,7 @@ bool AppInit2()
if (fServer)
NewThread(ThreadRPCServer, NULL);
- // ********************************************************* Step 12: finished
+ // ********************************************************* Step 13: finished
uiInterface.InitMessage(_("Done loading"));
printf("Done loading\n");
diff --git a/src/irc.cpp b/src/irc.cpp
index 157a031..4132ba8 100644
--- a/src/irc.cpp
+++ b/src/irc.cpp
@@ -214,7 +214,7 @@ void ThreadIRCSeed2(void* parg)
return;
// ... or if IRC is not enabled.
- if (!GetBoolArg("-irc", true))
+ if (!GetBoolArg("-irc", false))
return;
printf("ThreadIRCSeed started\n");
diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h
index 28c49dd..3cd8eb0 100644
--- a/src/json/json_spirit_writer_template.h
+++ b/src/json/json_spirit_writer_template.h
@@ -28,7 +28,7 @@ namespace json_spirit
template< class String_type >
String_type non_printable_to_string( unsigned int c )
{
- typedef typename String_type::value_type Char_type;
+ //typedef typename String_type::value_type Char_type;
String_type result( 6, '\\' );
diff --git a/src/kernel.cpp b/src/kernel.cpp
index 0b8498e..3fcad2d 100644
--- a/src/kernel.cpp
+++ b/src/kernel.cpp
@@ -3,9 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include
-//#include
+
#include "kernel.h"
#include "db.h"
+#include "auxpow.h"
using namespace std;
@@ -32,6 +33,29 @@ static std::map mapStakeModifierCheckpoints =
( 317997, 0xfd318368u )
;
+/* Selects the appropriate minimal stake age */
+uint GetStakeMinAge(uint nStakeTime) {
+
+ if(fTestNet)
+ return(nStakeMinAge);
+
+ if(nStakeTime > nLiveTimeSwitch)
+ return(nStakeMinAgeFixed);
+ else
+ return(nStakeMinAge);
+}
+
+// Get time weight
+int64 GetWeight(int64 nIntervalBeginning, int64 nIntervalEnd) {
+ uint nStakeMinAgeCurrent = GetStakeMinAge(nIntervalEnd);
+
+ // Kernel hash weight starts from 0 at the min age
+ // this change increases active coins participating the hash and helps
+ // to secure the network when proof-of-stake difficulty is low
+
+ return(min(nIntervalEnd - nIntervalBeginning - nStakeMinAgeCurrent, (int64)nStakeMaxAge));
+}
+
// Get the last stake modifier and its generation time from a given block
static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64& nStakeModifier, int64& nModifierTime)
{
@@ -59,9 +83,7 @@ static int64 GetStakeModifierSelectionInterval()
{
int64 nSelectionInterval = 0;
for (int nSection=0; nSection<64; nSection++)
- {
nSelectionInterval += GetStakeModifierSelectionIntervalSection(nSection);
- }
return nSelectionInterval;
}
@@ -143,10 +165,16 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModif
return error("ComputeNextStakeModifier: unable to get last modifier");
if (fDebug)
{
- printf("ComputeNextStakeModifier: prev modifier=0x%016"PRI64x" time=%s\n", nStakeModifier, DateTimeStrFormat(nModifierTime).c_str());
+ printf("ComputeNextStakeModifier: prev modifier=0x%016"PRI64x" time=%s epoch=%u\n", nStakeModifier, DateTimeStrFormat(nModifierTime).c_str(), (unsigned int)nModifierTime);
}
if (nModifierTime / nModifierInterval >= pindexPrev->GetBlockTime() / nModifierInterval)
+ {
+ if (fDebug)
+ {
+ printf("ComputeNextStakeModifier: no new interval keep current modifier: pindexPrev nHeight=%d nTime=%u\n", pindexPrev->nHeight, (unsigned int)pindexPrev->GetBlockTime());
+ }
return true;
+ }
// Sort candidate blocks by timestamp
vector > vSortedByTimestamp;
@@ -221,27 +249,25 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier
{
nStakeModifier = 0;
if (!mapBlockIndex.count(hashBlockFrom))
- return false;
+ return error("GetKernelStakeModifier() : block not indexed");
const CBlockIndex* pindexFrom = mapBlockIndex[hashBlockFrom];
nStakeModifierHeight = pindexFrom->nHeight;
nStakeModifierTime = pindexFrom->GetBlockTime();
+
+ uint nStakeMinAgeCurrent = GetStakeMinAge(nStakeModifierTime);
+
int64 nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval();
const CBlockIndex* pindex = pindexFrom;
-
// loop to find the stake modifier later by a selection interval
while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval)
{
if (!pindex->pnext)
{ // reached best block; may happen if node is behind on block chain
- if (fPrintProofOfStake || (pindex->GetBlockTime() + nStakeMinAge - nStakeModifierSelectionInterval > GetAdjustedTime()))
+ if(fPrintProofOfStake || (pindex->GetBlockTime() + nStakeMinAgeCurrent - nStakeModifierSelectionInterval > GetAdjustedTime()))
return error("GetKernelStakeModifier() : reached best block %s at height %d from block %s",
pindex->GetBlockHash().ToString().c_str(), pindex->nHeight, hashBlockFrom.ToString().c_str());
else
- {
- // printf(">> nStakeModifierTime = %"PRI64d", pindexFrom->GetBlockTime() = %"PRI64d", nStakeModifierSelectionInterval = %"PRI64d"\n",
- // nStakeModifierTime, pindexFrom->GetBlockTime(), nStakeModifierSelectionInterval);
return false;
- }
}
pindex = pindex->pnext;
if (pindex->GeneratedStakeModifier())
@@ -279,60 +305,35 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier
//
bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake)
{
- if(totalCoin < VALUE_CHANGE && pindexBest->nHeight > 376497 && !fTestNet)
- return false;
-
if (nTimeTx < txPrev.nTime) // Transaction timestamp violation
return error("CheckStakeKernelHash() : nTime violation");
unsigned int nTimeBlockFrom = blockFrom.GetBlockTime();
- if (nTimeBlockFrom + nStakeMinAge > nTimeTx) // Min age requirement
+
+ uint nStakeMinAgeCurrent = GetStakeMinAge(nTimeBlockFrom);
+
+ if(nTimeBlockFrom + nStakeMinAgeCurrent > nTimeTx) // Min age requirement
return error("CheckStakeKernelHash() : min age violation");
CBigNum bnTargetPerCoinDay;
bnTargetPerCoinDay.SetCompact(nBits);
int64 nValueIn = txPrev.vout[prevout.n].nValue;
+ uint256 hashBlockFrom = blockFrom.GetHash(true);
+
// v0.3 protocol kernel hash weight starts from 0 at the min age
// this change increases active coins participating the hash and helps
// to secure the network when proof-of-stake difficulty is low
- int64 nTimeWeight = min((int64)nTimeTx - txPrev.nTime, (int64)nStakeMaxAge) - nStakeMinAge;
- CBigNum bnCoinDayWeight;
-
- if(fTestNet)
-// bnCoinDayWeight = CBigNum((nValueIn) * nTimeWeight * 10000 / COIN / (24 * 60 * 60));
- if(nValueIn < 100)
- bnCoinDayWeight = CBigNum(100 * nTimeWeight * 10000 / (24 * 60 * 60));
- else
- bnCoinDayWeight = CBigNum((nValueIn) * nTimeWeight * 10000 / COIN / (24 * 60 * 60));
- else
- {
- if(totalCoin < VALUE_CHANGE)
- bnCoinDayWeight = CBigNum(nValueIn) * nTimeWeight / COIN / (24 * 60 * 60);
- else
- {
- if(nValueIn < 100)
- bnCoinDayWeight = CBigNum(100 * nTimeWeight * 10000 / (24 * 60 * 60));
- else
- bnCoinDayWeight = CBigNum((nValueIn) * nTimeWeight * 10000 / COIN / (24 * 60 * 60));
- }
- }
-
- // printf(">>> CheckStakeKernelHash: nTimeWeight = %"PRI64d"\n", nTimeWeight);
+ int64 nTimeWeight = min((int64)nTimeTx - txPrev.nTime, (int64)nStakeMaxAge) - nStakeMinAgeCurrent;
+ CBigNum bnCoinDayWeight = CBigNum(nValueIn) * nTimeWeight / COIN / (24 * 60 * 60);
// Calculate hash
CDataStream ss(SER_GETHASH, 0);
uint64 nStakeModifier = 0;
int nStakeModifierHeight = 0;
int64 nStakeModifierTime = 0;
- if (!GetKernelStakeModifier(blockFrom.GetHashScrypt(), nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake) &&
-
- !GetKernelStakeModifier(blockFrom.GetHashGroestl(), nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake))
- {
- // printf(">>> CheckStakeKernelHash: GetKernelStakeModifier return false\n");
+ if (!GetKernelStakeModifier(hashBlockFrom, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake))
return false;
- }
- // printf(">>> CheckStakeKernelHash: passed GetKernelStakeModifier\n");
ss << nStakeModifier;
ss << nTimeBlockFrom << nTxPrevOffset << txPrev.nTime << prevout.n << nTimeTx;
@@ -342,10 +343,9 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
printf("CheckStakeKernelHash() : using modifier 0x%016"PRI64x" at height=%d timestamp=%s for block from height=%d timestamp=%s\n",
nStakeModifier, nStakeModifierHeight,
DateTimeStrFormat(nStakeModifierTime).c_str(),
- mapBlockIndex[blockFrom.GetHash()]->nHeight,
+ mapBlockIndex[hashBlockFrom]->nHeight,
DateTimeStrFormat(blockFrom.GetBlockTime()).c_str());
- printf("CheckStakeKernelHash() : check protocol=%s modifier=0x%016"PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
- "0.3",
+ printf("CheckStakeKernelHash() : check modifier=0x%016"PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
nStakeModifier,
nTimeBlockFrom, nTxPrevOffset, txPrev.nTime, prevout.n, nTimeTx,
hashProofOfStake.ToString().c_str());
@@ -354,10 +354,11 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
// Now check if proof-of-stake hash meets target protocol
if (CBigNum(hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay)
{
- //qDebug() << "hashProofOfStake = " << CBigNum(hashProofOfStake).ToString().c_str();
- //qDebug() << "bnCoinDayWeight = " << bnCoinDayWeight.ToString().c_str();
- //qDebug() << "bnTargetPerCoinDay = " << bnTargetPerCoinDay.ToString().c_str();
- //printf(">>> CheckStakeKernelHash - hashProofOfStake too much\n");
+// printf("hashProofOfStake = %s\n", CBigNum(hashProofOfStake).ToString().c_str());
+// printf("bnCoinDayWeight = %s\n", bnCoinDayWeight.ToString().c_str());
+// printf("bnTargetPerCoinDay = %s\n", bnTargetPerCoinDay.ToString().c_str());
+// printf("nBits = %d\n", nBits);
+// printf(">>> CheckStakeKernelHash - hashProofOfStake too much\n");
return false;
}
@@ -366,10 +367,9 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
printf("CheckStakeKernelHash() : using modifier 0x%016"PRI64x" at height=%d timestamp=%s for block from height=%d timestamp=%s\n",
nStakeModifier, nStakeModifierHeight,
DateTimeStrFormat(nStakeModifierTime).c_str(),
- mapBlockIndex[blockFrom.GetHash()]->nHeight,
+ mapBlockIndex[hashBlockFrom]->nHeight,
DateTimeStrFormat(blockFrom.GetBlockTime()).c_str());
- printf("CheckStakeKernelHash() : pass protocol=%s modifier=0x%016"PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
- "0.3",
+ printf("CheckStakeKernelHash() : pass modifier=0x%016"PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
nStakeModifier,
nTimeBlockFrom, nTxPrevOffset, txPrev.nTime, prevout.n, nTimeTx,
hashProofOfStake.ToString().c_str());
@@ -435,8 +435,6 @@ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierCheck
{
if (fTestNet) return true; // Testnet has no checkpoints
if (mapStakeModifierCheckpoints.count(nHeight))
- {
return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight];
- }
return true;
}
diff --git a/src/kernel.h b/src/kernel.h
index 9241173..cf0e3f4 100644
--- a/src/kernel.h
+++ b/src/kernel.h
@@ -14,6 +14,9 @@ extern unsigned int nModifierInterval;
// ratio of group interval length between the last group and the first group
static const int MODIFIER_INTERVAL_RATIO = 3;
+/* Selects the appropriate minimal stake age */
+uint GetStakeMinAge(uint nStakeTime);
+
// Compute the hash modifier for proof-of-stake
bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModifier, bool& fGeneratedStakeModifier);
@@ -34,4 +37,7 @@ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex);
// Check stake modifier hard checkpoints
bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum);
+// Get time weight using supplied timestamps
+int64 GetWeight(int64 nIntervalBeginning, int64 nIntervalEnd);
+
#endif // PPCOIN_KERNEL_H
diff --git a/src/main.cpp b/src/main.cpp
index 1e40a7e..53d08b7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,11 +7,12 @@
#include "checkpoints.h"
#include "db.h"
#include "net.h"
-#include "init.h"
+#include "init.h"
+#include "auxpow.h"
#include "ui_interface.h"
#include "kernel.h"
#include "scrypt_mine.h"
-#include "scrypt.h"
+#include "reactors.h"
#include
#include
#include
@@ -26,7 +27,7 @@ using namespace boost;
//
CCriticalSection cs_setpwalletRegistered;
-set setpwalletRegistered;
+set setpwalletRegistered;
CCriticalSection cs_main;
@@ -40,16 +41,18 @@ static CBigNum bnProofOfWorkLimit(~uint256(0) >> 20);
static CBigNum bnProofOfWorkLimit_1(~uint256(0) >> 32);
static CBigNum bnProofOfStakeLimit(~uint256(0) >> 20);
-static CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 16);
-static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 20);
-uint256 nPoWBase = uint256("0x00000000ffff0000000000000000000000000000000000000000000000000000"); // difficulty-1 target
-unsigned int nStakeMinAge = 60 * 60 * 24 * 7; // minimum age for coin age: 2d
+static CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 24);
+static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 16);
+unsigned int nStakeMinAge = 60 * 60 * 24 * 7; // minimum age for coin age: 7d
+unsigned int nStakeMinAgeFixed = 60 * 60 * 24 * 9; /* must be > 8.82 days */
unsigned int nStakeMaxAge = 60 * 60 * 24 * 30; // stake age of full weight: 30d
int64 nStakeTargetSpacing = 60; // 1-minute block spacing
int64 nWorkTargetSpacing = 60; // 1-minute block spacing
-int64 coinMax = 0;
-int64 totalCoinDB = 0;
+static const int64 POW_RESTART = 577850; // When (block) to unstuck PoW
+
+bool fSignWorkBlock = true;
+
int64 totalCoin = -1;
int64 nChainStartTime = 1373654826;
int nCoinbaseMaturity = 30;
@@ -421,7 +424,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
}
// Update the tx's hashBlock
- hashBlock = pblock->GetHash();
+ hashBlock = pblock->GetHash(true);
// Locate the transaction
for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
@@ -472,15 +475,15 @@ bool CTransaction::CheckTransaction() const
if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake())
return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction"));
- if(totalCoin < VALUE_CHANGE)
- {
+ if(fTestNet ||
+ (!fTestNet && ((totalCoin <= VALUE_CHANGE) || (totalCoin > POS_RESTART)))) {
// ppcoin: enforce minimum output amount
- if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT)
+ if ((!txout.IsEmpty()) && (!IsCoinStake()) && txout.nValue < MIN_TXOUT_AMOUNT)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum"));
}
else
{
- if (txout.nValue < 0)
+ if ((!txout.IsEmpty()) && txout.nValue < 0)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
}
@@ -503,7 +506,7 @@ bool CTransaction::CheckTransaction() const
if (IsCoinBase())
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
- return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
+ return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size is invalid"));
}
else
{
@@ -623,7 +626,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
if (pfMissingInputs)
*pfMissingInputs = true;
- return false;
+ return error("CTxMemPool::accept() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
}
// Check for non-standard pay-to-script-hash in inputs
@@ -772,7 +775,7 @@ int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
// Make sure the merkle branch connects to this block
if (!fMerkleVerified)
{
- if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
+ if(CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
return 0;
fMerkleVerified = true;
}
@@ -786,7 +789,7 @@ int CMerkleTx::GetBlocksToMaturity() const
{
if (!(IsCoinBase() || IsCoinStake()))
return 0;
- return max(0, (nCoinbaseMaturity+20) - GetDepthInMainChain());
+ return max(0, (nCoinbaseMaturity + 1) - GetDepthInMainChain());
}
@@ -832,14 +835,12 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
return false;
}
-
bool CWalletTx::AcceptWalletTransaction()
{
CTxDB txdb("r");
return AcceptWalletTransaction(txdb);
}
-
int CTxIndex::GetDepthInMainChain() const
{
// Read block header
@@ -847,7 +848,7 @@ int CTxIndex::GetDepthInMainChain() const
if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false))
return 0;
// Find the block in the index
- map::iterator mi = mapBlockIndex.find(block.GetHash());
+ map::iterator mi = mapBlockIndex.find(block.GetHash(true));
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
@@ -875,7 +876,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock)
{
CBlock block;
if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
- hashBlock = block.GetHash();
+ hashBlock = block.GetHash(true);
return true;
}
}
@@ -916,15 +917,20 @@ bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
}
if (!ReadFromDisk(pindex->nFile, pindex->nBlockPos, fReadTransactions))
return false;
- totalCoinDB = 1;
- uint256 hash1 = GetHashScrypt();
- totalCoinDB = coinMax;
- uint256 hash2 = GetHashGroestl();
- if (hash1 != pindex->GetBlockHash() && hash2 != pindex->GetBlockHash())
+// if (GetHashScrypt() != pindex->GetBlockHash() && GetHashGroestl() != pindex->GetBlockHash())
+ // send totalCoins to speed up GetHash()
+ if (GetHash(false, pindex->nMoneySupply / COIN ) != pindex->GetBlockHash())
return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
return true;
}
+void CBlock::SetAuxPow(CAuxPow* pow) {
+ if(pow != NULL)
+ nVersion |= BLOCK_VERSION_AUXPOW;
+ else
+ nVersion &= ~BLOCK_VERSION_AUXPOW;
+ auxpow.reset(pow);
+}
uint256 static GetOrphanRoot(const CBlock* pblock)
{
@@ -934,7 +940,6 @@ uint256 static GetOrphanRoot(const CBlock* pblock)
return pblock->GetHash();
}
-
// ppcoin: find block wanted by given orphan block
uint256 WantedByOrphan(const CBlock* pblockOrphan)
{
@@ -953,15 +958,12 @@ int generateMTRandom(unsigned int s, int range)
}
-static const int64 nMinSubsidy = 1 * COIN;
-static const int CUTOFF_HEIGHT = 100800; // Height at the end of 5 weeks
// miner's coin base reward based on nBits
int64 GetProofOfWorkReward(int nHeight, int64 nFees, uint256 prevHash)
{
int64 nSubsidy = COIN;
- if(totalCoin < VALUE_CHANGE)
- {
+ if(fTestNet || (totalCoin <= VALUE_CHANGE)) {
std::string cseed_str = prevHash.ToString().substr(6,7);
const char* cseed = cseed_str.c_str();
long seed = hex2long(cseed);
@@ -983,86 +985,90 @@ int64 GetProofOfWorkReward(int nHeight, int64 nFees, uint256 prevHash)
}
else
{
- if(totalCoin > 1000000)
- nSubsidy = 10 * CENT;
- else if(totalCoin > 2500000)
- nSubsidy = 2 * CENT;
+ // Diamond v2 coin mechanics
+ // 0.20 reward after 1,000,000 created
+ // 0.04 reward after 2,500,000 created
+ if (totalCoin >= 2500000)
+ nSubsidy = 4 * CENT;
+ else if (totalCoin >= 1000000)
+ nSubsidy = 20 * CENT;
}
return nSubsidy + nFees;
}
// miner's coin stake reward based on nBits and coin age spent (coin-days)
// simple algorithm, not depend on the diff
-const int YEARLY_BLOCKCOUNT = 525600; // 365 * 1440
-int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight)
+int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight, float reactorRate)
{
- if(totalCoin >= VALUE_CHANGE || fTestNet)
+ int64 nRewardCoinYear;
+ int64 nSubsidy = 0;
+
+ if (totalCoin > VALUE_CHANGE || fTestNet)
{
- int64 nRewardCoinYear;
- int nSubsidy = 0;
nRewardCoinYear = MAX_MINT_PROOF_OF_STAKE;
- if(fTestNet)
- nSubsidy = nCoinAge * 50 * MAX_MINT_PROOF_OF_STAKE * 33 / (365 * 33 + 8) / COIN;
- if(totalCoin > VALUE_CHANGE)
- {
- nSubsidy = nCoinAge * 50 * MAX_MINT_PROOF_OF_STAKE * 33 / (365 * 33 + 8) / COIN;
- }
- else if(totalCoin > VALUE_CHANGE + 4000)
- {
- nSubsidy = nCoinAge / COIN * 50 * MAX_MINT_PROOF_OF_STAKE * 33 / (365 * 33 + 8);
- }
- else if(totalCoin > 1500000)
- {
- nSubsidy = nCoinAge / COIN * 25 * MAX_MINT_PROOF_OF_STAKE * 33 / (365 * 33 + 8);
- }
- else if(totalCoin > 2500000)
- {
- nSubsidy = nCoinAge / COIN * 5 * MAX_MINT_PROOF_OF_STAKE * 33 / (365 * 33 + 8);
- }
- else if(totalCoin > 3500000)
- {
- nSubsidy = nCoinAge / COIN * 1 * MAX_MINT_PROOF_OF_STAKE * 33 / (365 * 33 + 8);
- }
+ if(fTestNet) {
+ nRewardCoinYear = 25 * CENT;
+ nRewardCoinYear = GetAdjustedCoinYear(nRewardCoinYear, nTime, reactorRate);
+ nSubsidy = nCoinAge * nRewardCoinYear / 365;
+ } else {
+ // Diamond v2 PoS spec:
+ // 50% algorithm switch to 1,500,000 coins
+ // 25% from 1,500,000 to 2,500,000 coins
+ // 5% from 2,500,000 to 3,500,000 coins
+ // 1% ever since 3,500,000 coins
+ if (totalCoin > 3500000)
+ nRewardCoinYear = 1 * CENT;
+ else if (totalCoin > 2500000)
+ nRewardCoinYear = 5 * CENT;
+ else if (totalCoin > 1500000)
+ nRewardCoinYear = 25 * CENT;
+ else
+ nRewardCoinYear = 50 * CENT;
+
+ if(nTime > REACTOR_START_TIME)
+ nRewardCoinYear = GetAdjustedCoinYear(nRewardCoinYear, nTime, reactorRate);
+
+ nSubsidy = nCoinAge * nRewardCoinYear / 365;
+ }
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d" nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits);
return nSubsidy;
}
+ // DEAD CODE, nothing past this line runs anymore...
else
{
- int64 nRewardCoinYear;
-
- CBigNum bnRewardCoinYearLimit = MAX_MINT_PROOF_OF_STAKE; // Base stake mint rate, 100% year interest
- CBigNum bnTarget;
- bnTarget.SetCompact(nBits);
- CBigNum bnTargetLimit = bnProofOfStakeLimit;
- bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
+ CBigNum bnRewardCoinYearLimit = MAX_MINT_PROOF_OF_STAKE; // Base stake mint rate, 100% year interest
+ CBigNum bnTarget;
+ bnTarget.SetCompact(nBits);
+ CBigNum bnTargetLimit = bnProofOfStakeLimit;
+ bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
- // Diamond: reward for coin-year is cut in half every 64x multiply of PoS difficulty
- // A reasonably continuous curve is used to avoid shock to market
- // (nRewardCoinYearLimit / nRewardCoinYear) ** 4 == bnProofOfStakeLimit / bnTarget
- //
- // Human readable form:
- //
- // nRewardCoinYear = 1 / (posdiff ^ 1/4)
+ // Diamond: reward for coin-year is cut in half every 64x multiply of PoS difficulty
+ // A reasonably continuous curve is used to avoid shock to market
+ // (nRewardCoinYearLimit / nRewardCoinYear) ** 4 == bnProofOfStakeLimit / bnTarget
+ //
+ // Human readable form:
+ //
+ // nRewardCoinYear = 1 / (posdiff ^ 1/4)
- CBigNum bnLowerBound = 1 * CENT; // Lower interest bound is 1% per year
- CBigNum bnUpperBound = bnRewardCoinYearLimit;
- while (bnLowerBound + CENT <= bnUpperBound)
- {
- CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
- if (fDebug && GetBoolArg("-printcreation"))
- printf("GetProofOfStakeReward() : lower=%"PRI64d" upper=%"PRI64d" mid=%"PRI64d"\n", bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64());
- if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnTarget)
- bnUpperBound = bnMidValue;
- else
- bnLowerBound = bnMidValue;
- }
+ CBigNum bnLowerBound = 1 * CENT; // Lower interest bound is 1% per year
+ CBigNum bnUpperBound = bnRewardCoinYearLimit;
+ while (bnLowerBound + CENT <= bnUpperBound)
+ {
+ CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
+ if (fDebug && GetBoolArg("-printcreation"))
+ printf("GetProofOfStakeReward() : lower=%"PRI64d" upper=%"PRI64d" mid=%"PRI64d"\n", bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64());
+ if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnTarget)
+ bnUpperBound = bnMidValue;
+ else
+ bnLowerBound = bnMidValue;
+ }
- nRewardCoinYear = bnUpperBound.getuint64();
- nRewardCoinYear = min((nRewardCoinYear / CENT) * CENT, MAX_MINT_PROOF_OF_STAKE);
+ nRewardCoinYear = bnUpperBound.getuint64();
+ nRewardCoinYear = min((nRewardCoinYear / CENT) * CENT, MAX_MINT_PROOF_OF_STAKE);
- int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear;
+ nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear;
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d" nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits);
return nSubsidy;
@@ -1119,18 +1125,20 @@ const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfSta
return pindex;
}
-unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake)
+unsigned int GetNextTargetRequired_v1(const CBlockIndex* pindexLast, bool fProofOfStake)
{
if(fTestNet && !fProofOfStake && pindexLast->nHeight <= 100)
return bnProofOfWorkLimit.GetCompact();
- CBigNum bnTargetLimit = !fProofOfStake ? bnProofOfWorkLimit : bnProofOfStakeLimit;
+ // cruft from alorithm switch time
if(pindexLast->nHeight >= 386221 && pindexLast->nHeight <= 386226)
return bnProofOfWorkLimit.GetCompact();
if(pindexLast->nHeight >= 386232 && pindexLast->nHeight <= 386233)
return bnProofOfWorkLimit_1.GetCompact();
+ CBigNum bnTargetLimit = fProofOfStake ? bnProofOfStakeLimit : bnProofOfWorkLimit;
+
if (pindexLast == NULL)
return bnTargetLimit.GetCompact(); // genesis block
@@ -1141,42 +1149,116 @@ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfS
if (pindexPrevPrev->pprev == NULL)
return bnTargetLimit.GetCompact(); // second block
- int64 nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime();
-
// ppcoin: target change every block
// ppcoin: retarget with exponential moving toward target spacing
CBigNum bnNew;
bnNew.SetCompact(pindexPrev->nBits);
int64 nTargetSpacing = fProofOfStake? nStakeTargetSpacing : min(nTargetSpacingWorkMax, (int64) nWorkTargetSpacing * (1 + pindexLast->nHeight - pindexPrev->nHeight));
-
int64 nInterval = nTargetTimespan / nTargetSpacing;
+ int64 nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime();
+
+ // fix block spacing
+ // danbi: post 2.0.4 implement new pacing algorithm for PoW & PoS
+ if (nBestHeight > POW_RESTART)
+ {
+ if (nActualSpacing < 0)
+ {
+ if (fDebug && GetBoolArg("-printjunk")) printf(">> %s nActualSpacing = %"PRI64d" corrected to nTargetSpacing (%"PRI64d").\n", fProofOfStake ? "PoS" : "PoW", nActualSpacing, nTargetSpacing);
+ nActualSpacing=nTargetSpacing;
+ }
+ else if (nActualSpacing > nTargetTimespan)
+ {
+ if (fDebug && GetBoolArg("-printjunk")) printf(">> %s nActualSpacing = %"PRI64d" corrected to nTargetTimespan (%"PRI64d").\n", fProofOfStake ? "PoS" : "PoW", nActualSpacing, nTargetTimespan);
+ nActualSpacing=nTargetTimespan;
+ }
+ }
+ // danbi: old pre 2.0.4 PoS pacing algorithm
+ else if (fProofOfStake && GetTotalCoin() > POS_RESTART)
+ {
+ if(nActualSpacing < 0)
+ {
+ if (fDebug && GetBoolArg("-printjunk")) printf(">> %s nActualSpacing = %"PRI64d" corrected to 1.\n", fProofOfStake ? "PoS" : "PoW", nActualSpacing);
+ nActualSpacing = 1;
+ }
+ else if(nActualSpacing > nTargetTimespan)
+ {
+ if (fDebug && GetBoolArg("-printjunk")) printf(">> %s nActualSpacing = %"PRI64d" corrected to nTargetTimespan (%"PRI64d").\n", fProofOfStake ? "PoS" : "PoW", nActualSpacing, nTargetTimespan);
+ nActualSpacing = nTargetTimespan;
+ }
+ }
+
+
bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
bnNew /= ((nInterval + 1) * nTargetSpacing);
- if (bnNew > bnTargetLimit)
+ // danbi: make sure we don't emit negative numbers even if we miscalculated
+ if ((bnNew <= 0 && nBestHeight > POW_RESTART) || bnNew > bnTargetLimit)
bnNew = bnTargetLimit;
return bnNew.GetCompact();
}
-bool CheckProofOfWork(uint256 hash, unsigned int nBits)
+unsigned int GetNextTargetRequired_v2(const CBlockIndex* pindexLast, bool fProofOfStake)
{
- if(pindexBest != NULL)
- printf("pindexBest = %d", pindexBest->nMoneySupply / COIN);
- CBigNum bnTarget;
- bnTarget.SetCompact(nBits);
+ CBigNum bnTargetLimit = bnProofOfWorkLimit;
- // Check range
- if (bnTarget <= 0 || bnTarget > bnProofOfWorkLimit)
- return false;
+ if(fProofOfStake)
+ bnTargetLimit = bnProofOfStakeLimit;
- // Check proof of work matches claimed amount
- if (hash > bnTarget.getuint256())
- return false;
+ if (pindexLast == NULL)
+ return bnTargetLimit.GetCompact(); // genesis block
- return true;
+ const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake);
+ if (pindexPrev->pprev == NULL)
+ return bnTargetLimit.GetCompact(); // first block
+ const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, fProofOfStake);
+ if (pindexPrevPrev->pprev == NULL)
+ return bnTargetLimit.GetCompact(); // second block
+
+ int64 nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime();
+ if(nActualSpacing < 0)
+ {
+ nActualSpacing = 1;
+ }
+ else if(nActualSpacing > nTargetTimespan)
+ {
+ nActualSpacing = nTargetTimespan;
+ }
+
+ // ppcoin: target change every block
+ // ppcoin: retarget with exponential moving toward target spacing
+ CBigNum bnNew;
+ bnNew.SetCompact(pindexPrev->nBits);
+
+ int64 nTargetSpacing = fProofOfStake? nStakeTargetSpacing : nWorkTargetSpacing;
+ int64 nInterval = nTargetTimespan / nTargetSpacing;
+ bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
+ bnNew /= ((nInterval + 1) * nTargetSpacing);
+
+ // danbi: make sure we don't emit negative numbers even if we miscalculated
+ if (bnNew <= 0 || bnNew > bnTargetLimit)
+ bnNew = bnTargetLimit;
+
+ /* Disable legacy PoW block signature */
+ if(fSignWorkBlock) {
+ if((fTestNet && (pindexPrev->nHeight + 1 >= nTestStage2)) ||
+ (!fTestNet && (pindexPrev->nHeight + 1 >= nLiveFork1))) {
+ fSignWorkBlock = false;
+ }
+ }
+
+ return bnNew.GetCompact();
+}
+
+
+unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake)
+{
+ if(!fTestNet && (totalCoin < 1000000))
+ return GetNextTargetRequired_v1(pindexLast, fProofOfStake);
+ else return GetNextTargetRequired_v2(pindexLast, fProofOfStake);
}
+
// Return maximum amount of blocks that other nodes claim to have
int GetNumBlocksOfPeers()
{
@@ -1333,7 +1415,6 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map& mapTes
return true;
}
-
const CTxOut& CTransaction::GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const
{
MapPrevTx::const_iterator mi = inputs.find(input.prevout.hash);
@@ -1347,7 +1428,6 @@ const CTxOut& CTransaction::GetOutputFor(const CTxIn& input, const MapPrevTx& in
return txPrev.vout[input.prevout.n];
}
-
int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const
{
if (IsCoinBase())
@@ -1362,7 +1442,6 @@ int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const
}
-
unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
{
if (IsCoinBase())
@@ -1378,7 +1457,6 @@ unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
return nSigOps;
}
-
bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs,
map& mapTestPool, const CDiskTxPos& posThisTx,
const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash)
@@ -1466,9 +1544,16 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs,
uint64 nCoinAge;
if (!GetCoinAge(txdb, nCoinAge))
return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
- int64 nStakeReward = GetValueOut() - nValueIn;
- if (nStakeReward > GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime, pindexBlock->nHeight) - GetMinFee() + MIN_TX_FEE)
- return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str()));
+
+ // If vout[0] is not empty check if this is a reactor stake.
+ if (!vout[0].IsEmpty()) {
+ // OP_REACTOR is stored in vout[0] destination is stored in vout[1]
+ return IsReactorStake(GetReactorDBFile(), vout[0].scriptPubKey, vout[1].scriptPubKey, nTime, nValueIn, GetValueOut(), nCoinAge, pindexBlock->nBits, pindexBlock->nHeight);
+ } else {
+ int64 nStakeReward = GetValueOut() - nValueIn;
+ if (nStakeReward > GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime, pindexBlock->nHeight) - GetMinFee() + MIN_TX_FEE)
+ return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str()));
+ }
}
else
{
@@ -1567,7 +1652,7 @@ bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex)
bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
{
// Check it again in case a previous version let a bad block in
- if (!CheckBlock(!fJustCheck, !fJustCheck))
+ if(!CheckBlock(!fJustCheck, !fJustCheck, GetTotalCoin()))
return false;
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
@@ -1592,7 +1677,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
// Since we're just checking the block and not actually connecting it, it might not (and probably shouldn't) be on the disk to get the transaction from
nTxPos = 1;
else
- nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - (2 * GetSizeOfCompactSize(0)) + GetSizeOfCompactSize(vtx.size());
+ nTxPos = pindex->nBlockPos + ::GetSerializeSize(*this, SER_DISK | SER_BLOCKHEADERONLY, CLIENT_VERSION) + GetSizeOfCompactSize(vtx.size());
map mapQueuedChanges;
int64 nFees = 0;
@@ -1681,24 +1766,35 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
// printf("==> Got prevHash = %s\n", prevHash.ToString().c_str());
}
- if(totalCoin < VALUE_CHANGE)
- {
- if (vtx[0].GetValueOut() > GetProofOfWorkReward(pindex->nHeight, nFees, prevHash))
- return false;
- }
- else
- if (vtx[0].GetValueOut() > GetProofOfWorkReward(pindex->nHeight, nFees, prevHash) + GetDevCoin(totalCoin))
- return false;
-
- if(totalCoin >= VALUE_CHANGE && IsProofOfWork())
- {
- CBitcoinAddress address(!fTestNet ? DEV_ADDRESS : DEV_ADDRESS_TEST);
- CScript scriptPubKey;
- scriptPubKey.SetDestination(address.Get());
- if (vtx[0].vout[1].scriptPubKey != scriptPubKey)
- return error("ConnectBlock() : coinbase does not pay to the dev address)");
- if (vtx[0].vout[1].nValue < GetDevCoin(totalCoin))
- return error("ConnectBlock() : coinbase does not pay enough to dev addresss");
+ // danbi: update totalCoin as we are one behind here
+ // XXX: this might backfire in case of error...
+ totalCoin = pindex->nMoneySupply / COIN;
+
+ int nPrevHeight = 0;
+ if(pindex->pprev)
+ nPrevHeight = pindex->pprev->nHeight;
+
+ bool fContribution = false;
+ if((fTestNet && (nPrevHeight + 1 < nTestStage1)) ||
+ (!fTestNet && ((totalCoin > VALUE_CHANGE) && (nPrevHeight + 1 < nLiveFork1))))
+ fContribution = true;
+
+ if(IsProofOfWork()) {
+ if(fContribution) {
+ if(vtx[0].GetValueOut() > GetProofOfWorkReward(pindex->nHeight, nFees, prevHash) + GetContributionAmount(totalCoin))
+ return(error("ConnectBlock() : claiming to have created too much (contribution included)"));
+
+ CBitcoinAddress address = GetFoundationAddress(totalCoin);
+ CScript scriptPubKey;
+ scriptPubKey.SetDestination(address.Get());
+ if(vtx[0].vout[1].scriptPubKey != scriptPubKey)
+ return(error("ConnectBlock() : coinbase does not pay to the foundation address)"));
+ if(vtx[0].vout[1].nValue < GetContributionAmount(totalCoin))
+ return(error("ConnectBlock() : coinbase does not pay enough to foundation addresss"));
+ } else {
+ if(vtx[0].GetValueOut() > GetProofOfWorkReward(pindex->nHeight, nFees, prevHash))
+ return(error("ConnectBlock() : claiming to have created too much"));
+ }
}
// Update block index on disk without changing it in memory.
@@ -1708,7 +1804,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
CDiskBlockIndex blockindexPrev(pindex->pprev);
blockindexPrev.hashNext = pindex->GetBlockHash();
if (!txdb.WriteBlockIndex(blockindexPrev))
- return error("ConnectBlock() : WriteBlockIndex failed");
+ return error("ConnectBlock() : WriteBlockIndex for blockindexPrev failed");
}
// Watch for transactions paying to me
@@ -1840,7 +1936,6 @@ bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew)
return true;
}
-
bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
{
uint256 hash = GetHash();
@@ -1922,8 +2017,9 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
bnBestChainTrust = pindexNew->bnChainTrust;
nTimeBestReceived = GetTime();
nTransactionsUpdated++;
- printf("SetBestChain: new best=%s height=%d trust=%s date=%s\n",
+ printf("SetBestChain: new best=%s height=%d trust=%s moneysupply=%s date=%s\n",
hashBestChain.ToString().c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(),
+ FormatMoney(pindexBest->nMoneySupply).c_str(),
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
printf("Stake checkpoint: %x\n", pindexBest->nStakeModifierChecksum);
@@ -1960,7 +2056,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
// ppcoin: total coin age spent in transaction, in the unit of coin-days.
// Only those coins meeting minimum age requirement counts. As those
// transactions not in main chain are not currently indexed so we
-// might not find out about their coin age. Older transactions are
+// might not find out about their coin age. Older transactions are
// guaranteed to be in main chain by sync-checkpoint. This rule is
// introduced to help nodes establish a consistent view of the coin
// age (trust score) of competing branches.
@@ -1986,7 +2082,7 @@ bool CTransaction::GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const
CBlock block;
if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
return false; // unable to read block of previous transaction
- if (block.GetBlockTime() + nStakeMinAge > nTime)
+ if(block.GetBlockTime() + GetStakeMinAge(block.GetBlockTime()) > nTime)
continue; // only count coins meeting min age requirement
int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
@@ -1996,11 +2092,7 @@ bool CTransaction::GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const
printf("coin age nValueIn=%"PRI64d" nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString().c_str());
}
- CBigNum bnCoinDay;
- if(totalCoin >= VALUE_CHANGE)
- bnCoinDay = bnCentSecond * CENT / (24 * 60 * 60);
- else
- bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
+ CBigNum bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
if (fDebug && GetBoolArg("-printcoinage"))
printf("coin age bnCoinDay=%s\n", bnCoinDay.ToString().c_str());
nCoinAge = bnCoinDay.getuint64();
@@ -2046,17 +2138,8 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
{
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
-
- //test
- if(pindexNew->pprev->nHeight >= 3)
- {
- int i = 1;
- i++;
- i++;
- }
}
-
// ppcoin: compute chain trust score
pindexNew->bnChainTrust = (pindexNew->pprev ? pindexNew->pprev->bnChainTrust : 0) + pindexNew->GetBlockTrust();
@@ -2115,25 +2198,84 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
return true;
}
+// Start accepting AUX POW at this block
+//
+// Even if we do not accept AUX POW ourselves, we can always be the parent chain.
-bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
-{
- totalCoin = GetTotalCoin();
- if(totalCoin >= VALUE_CHANGE && !fTestNet)
+int GetAuxPowStartBlock() {
+ if(fTestNet)
+ return(nTestStage4);
+ else
+ return(INT_MAX);
+}
+
+int GetOurChainID() {
+ return(0x0000);
+}
+
+bool CBlock::CheckProofOfWork(int64 totalCoin) const {
+ int nHeight = GetBlockHeight();
+ CBigNum bnTarget;
+ bnTarget.SetCompact(nBits);
+
+ if(nHeight >= GetAuxPowStartBlock()) {
+
+ // Prevent same work from being submitted twice:
+ // - this block must have our chain ID
+ // - parent block must not have the same chain ID (see CAuxPow::Check)
+ // - index of this chain in chain merkle tree must be pre-determined (see CAuxPow::Check)
+ if (!fTestNet && nHeight != INT_MAX && GetChainID() != GetOurChainID())
+ return error("CheckProofOfWork() : block does not have our chain ID");
+
+ if(auxpow.get() != NULL) {
+
+ if(!(nVersion & BLOCK_VERSION_AUXPOW))
+ return(error("CheckProofOfWork() : AuxPoW block version is not valid"));
+
+ if(!auxpow->Check(GetHashGroestl(), GetChainID()))
+ return(error("CheckProofOfWork() : AuxPoW is not valid"));
+
+ if(bnTarget <= 0 || (bnTarget > bnProofOfWorkLimit) || (auxpow->GetParentBlockHash() > bnTarget.getuint256()))
+ return(error("CheckProofOfWork() : AuxPoW failed"));
+ }
+ else
+ {
+
+ if(bnTarget <= 0 || (bnTarget > bnProofOfWorkLimit) || (GetHashGroestl() > bnTarget.getuint256()))
+ return(error("CheckProofOfWork() : PoW failed"));
+
+ }
+ }
+ else
{
- nStakeTargetSpacing = 10 * 60; //pos block spacing is 10 mins
- nCoinbaseMaturity = 180; //coinbase maturity change to 180 blocks
+ if(auxpow.get() != NULL)
+ return(error("CheckProofOfWork() : AuxPoW is not allowed at this block height"));
+
+ if(bnTarget <= 0 || (bnTarget > bnProofOfWorkLimit) || (GetHash(false, totalCoin) > bnTarget.getuint256()))
+ return(error("CheckProofOfWork() : proof of work failed"));
}
- //just for test
- if(pindexBest != NULL && pindexBest->nHeight > 50 && fTestNet)
- nCoinbaseMaturity = 15;
+ return(true);
+}
- if(totalCoin > VALUE_CHANGE)
+bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, int64 totalCoin) const {
+
+ // Update the coin mechanics variables post algorithm change
+ // Changing any of these requires a fork
+ if(!fTestNet) {
+ if (totalCoin >= 1000000) {
+ // after first reward reduction
+ nStakeTargetSpacing = 100; // PoS block spacing set to 100 seconds
+ nWorkTargetSpacing = 100; // PoW block spacing set to 100 seconds
+ nCoinbaseMaturity = 180; // coinbase maturity does not change
+ nStakeMinAge = 60 * 60 * 24 * 3; // min age is lowered from 7 to 3 days
+ }
+ else if (totalCoin > VALUE_CHANGE)
{
- nStakeMinAge = 30 * 24 * 60 * 60;
- nStakeMaxAge = -1;
+ nStakeTargetSpacing = 10 * 60; //pos block spacing is 10 mins
+ nCoinbaseMaturity = 180; //coinbase maturity change to 180 blocks
}
+ }
// These are checks that are independent of context
// that can be verified before saving an orphan block.
@@ -2142,13 +2284,14 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return DoS(100, error("CheckBlock() : size limits failed"));
- totalCoinDB = 1;
- uint256 hash1 = GetHashScrypt();
- totalCoinDB = coinMax;
- uint256 hash2 = GetHashGroestl();
// Check proof of work matches claimed amount
- if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(hash1, nBits) && !CheckProofOfWork(hash2, nBits))
- return DoS(50, error("CheckBlock() : proof of work failed"));
+ // XXX: danbi - need to check both algos or we make it hard for initial sync
+ // can't use GetHash() optimization, because we are also called when
+ // new block comes during initial sync and that might come from "future"
+ // compromise: use optimization, but decrease penalty (was 50)
+// if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHashScrypt(), nBits) && !CheckProofOfWork(GetHashGroestl(), nBits))
+ if(fCheckPOW && IsProofOfWork() && !CheckProofOfWork(totalCoin))
+ return(error("CheckBlock() : proof of work failed"));
// Check timestamp
if (GetBlockTime() > GetAdjustedTime() + nMaxClockDrift)
@@ -2166,17 +2309,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
if (vtx[i].IsCoinStake())
return DoS(100, error("CheckBlock() : coinstake in wrong position"));
- if(totalCoin >= VALUE_CHANGE)
- {
- if (IsProofOfStake() && (vtx[0].vout.size() != 2 || !vtx[0].vout[0].IsEmpty() || !vtx[0].vout[1].IsEmpty() ))
- return error("CheckBlock() : coinbase output not empty for proof-of-stake block");
- }
- else
- {
- if (IsProofOfStake() && (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty()))
- return error("CheckBlock() : coinbase output not empty for proof-of-stake block");
- }
-
// Check coinbase timestamp
if (GetBlockTime() > (int64)vtx[0].nTime + nMaxClockDrift)
return DoS(50, error("CheckBlock() : coinbase timestamp is too early"));
@@ -2216,16 +2348,11 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
// Check merkle root
if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree())
- return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
-
- // ppcoin: check block signature
- if (!CheckBlockSignature())
- return DoS(100, error("CheckBlock() : bad block signature"));
+ return(error("CheckBlock() : block %d merkle root hash mismatch", GetBlockHeight()));
return true;
}
-
bool CBlock::AcceptBlock()
{
// Check for duplicate
@@ -2240,14 +2367,42 @@ bool CBlock::AcceptBlock()
CBlockIndex* pindexPrev = (*mi).second;
int nHeight = pindexPrev->nHeight+1;
+ int64 nMaxDrift = nMaxClockDrift;
+ if((fTestNet && (nHeight >= nTestStage3)) ||
+ (!fTestNet && (nHeight >= nLiveFork1))) {
+ nMaxDrift = nNewMaxClockDrift;
+ }
+
+ if(GetBlockTime() > GetAdjustedTime() + nMaxDrift)
+ return(error("AcceptBlock() : block time stamp too far in the future"));
+
+ if(GetBlockTime() > (int64)vtx[0].nTime + nMaxDrift)
+ return(error("AcceptBlock() : coin base time stamp is too early"));
+
+ if((GetBlockTime() <= pindexPrev->GetMedianTimePast()) ||
+ (GetBlockTime() + nMaxDrift < pindexPrev->GetBlockTime()))
+ return(error("AcceptBlock() : block time stamp is too early"));
+
+ if(IsProofOfStake()) {
+ if((fTestNet && (nHeight < nTestStage1)) ||
+ (!fTestNet && ((totalCoin > VALUE_CHANGE) && (nHeight < nLiveFork1)))) {
+ /* vtx[0] must have 2 empty outputs */
+ if((vtx[0].vout.size() != 2) || !vtx[0].vout[0].IsEmpty() || !vtx[0].vout[1].IsEmpty())
+ return(error("AcceptBlock() : coin base outputs invalid for proof-of-stake block"));
+ } else {
+ /* vtx[0] must have 1 empty output */
+ if((vtx[0].vout.size() != 1) || !vtx[0].vout[0].IsEmpty())
+ return(error("AcceptBlock() : coin base output invalid for proof-of-stake block"));
+ }
+ }
+
+ if(!CheckBlockSignature(nHeight))
+ return(error("AcceptBlock() : bad block signature"));
+
// Check proof-of-work or proof-of-stake
if (nBits != GetNextTargetRequired(pindexPrev, IsProofOfStake()))
return DoS(100, error("AcceptBlock() : incorrect %s", IsProofOfWork() ? "proof-of-work" : "proof-of-stake"));
- // Check timestamp against prev
- if (GetBlockTime() <= pindexPrev->GetMedianTimePast() || GetBlockTime() + nMaxClockDrift < pindexPrev->GetBlockTime())
- return error("AcceptBlock() : block's timestamp is too early");
-
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.IsFinal(nHeight, GetBlockTime()))
@@ -2308,13 +2463,11 @@ bool CBlock::AcceptBlock()
CBigNum CBlockIndex::GetBlockTrust() const
{
- CBigNum bnTarget;
- bnTarget.SetCompact(nBits);
- if (bnTarget <= 0)
- return 0;
- return (IsProofOfStake()? (CBigNum(1)<<256) / (bnTarget+1) : 1);
-
-
+ CBigNum bnTarget;
+ bnTarget.SetCompact(nBits);
+ if (bnTarget <= 0)
+ return 0;
+ return (IsProofOfStake()? (CBigNum(1)<<256) / (bnTarget+1) : 1);
}
bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck)
@@ -2346,7 +2499,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str());
// Preliminary checks
- if (!pblock->CheckBlock())
+ if(!pblock->CheckBlock(true, true, GetTotalCoin()))
return error("ProcessBlock() : CheckBlock FAILED");
// ppcoin: verify hash target and signature of coinstake tx
@@ -2379,8 +2532,19 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
if (bnNewBlock > bnRequired)
{
if (pfrom)
- pfrom->Misbehaving(100);
- return error("ProcessBlock() : block with too little %s", pblock->IsProofOfStake()? "proof-of-stake" : "proof-of-work");
+ pfrom->Misbehaving(10); // danbi: was 100, but that's way too heavy handed
+ if (fDebug)
+ {
+ printf("ProcessBlock(): ");
+ pblock->print();
+ printf("\n");
+ }
+ // danbi: Only refuse this block if time distance between the last sync checkpoint
+ // and the block's time is less than the checkpoints max span
+ if (deltaTime < CHECKPOINT_MAX_SPAN)
+ return error("ProcessBlock() : block with too little %s", pblock->IsProofOfStake()? "proof-of-stake" : "proof-of-work");
+ else
+ return printf("ProcessBlock(CHECKPOINT_MAX_SPAN) : block with too little %s", pblock->IsProofOfStake()? "proof-of-stake" : "proof-of-work");
}
}
@@ -2433,9 +2597,10 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
++mi)
{
CBlock* pblockOrphan = (*mi).second;
+ uint256 ohash = pblockOrphan->GetHash();
if (pblockOrphan->AcceptBlock())
- vWorkQueue.push_back(pblockOrphan->GetHash());
- mapOrphanBlocks.erase(pblockOrphan->GetHash());
+ vWorkQueue.push_back(ohash);
+ mapOrphanBlocks.erase(ohash);
setStakeSeenOrphan.erase(pblockOrphan->GetProofOfStake());
delete pblockOrphan;
}
@@ -2459,6 +2624,8 @@ bool CBlock::SignBlock(const CKeyStore& keystore)
if(!IsProofOfStake())
{
+ if(!fSignWorkBlock) return(true);
+
for(unsigned int i = 0; i < vtx[0].vout.size(); i++)
{
const CTxOut& txout = vtx[0].vout[i];
@@ -2501,7 +2668,6 @@ bool CBlock::SignBlock(const CKeyStore& keystore)
if (key.GetPubKey() != vchPubKey)
return false;
-
return key.Sign(GetHashScrypt(), vchBlockSig);
}
}
@@ -2511,7 +2677,7 @@ bool CBlock::SignBlock(const CKeyStore& keystore)
}
// ppcoin: check block signature
-bool CBlock::CheckBlockSignature() const
+bool CBlock::CheckBlockSignature(int nHeight) const
{
if (GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
return vchBlockSig.empty();
@@ -2533,15 +2699,17 @@ bool CBlock::CheckBlockSignature() const
return false;
if (vchBlockSig.empty())
return false;
- totalCoinDB = 1;
- uint256 hash1 = GetHashScrypt();
- totalCoinDB = coinMax;
- uint256 hash2 = GetHashGroestl();
- return (key.Verify(hash1, vchBlockSig) || key.Verify(hash2, vchBlockSig));
+ return (key.Verify(GetHashScrypt(), vchBlockSig) || key.Verify(GetHashGroestl(), vchBlockSig));
}
}
else
{
+ if((fTestNet && (nHeight >= nTestStage2)) ||
+ (!fTestNet && (nHeight >= nLiveFork1))) {
+ /* Insist on empty PoW block signatures */
+ return(vchBlockSig.empty());
+ }
+
for(unsigned int i = 0; i < vtx[0].vout.size(); i++)
{
const CTxOut& txout = vtx[0].vout[i];
@@ -2558,11 +2726,7 @@ bool CBlock::CheckBlockSignature() const
continue;
if (vchBlockSig.empty())
continue;
- totalCoinDB = 1;
- uint256 hash1 = GetHashScrypt();
- totalCoinDB = coinMax;
- uint256 hash2 = GetHashGroestl();
- if(!key.Verify(hash1, vchBlockSig) && !key.Verify(hash2, vchBlockSig))
+ if(!key.Verify(GetHashScrypt(), vchBlockSig) && !key.Verify(GetHashGroestl(), vchBlockSig))
continue;
return true;
@@ -2651,13 +2815,15 @@ bool LoadBlockIndex(bool fAllowNew)
pchMessageStart[2] = 0xc0;
pchMessageStart[3] = 0xef;
- bnProofOfStakeLimit = bnProofOfStakeLimitTestNet; // 0x00000fff PoS base target is fixed in testnet
- bnProofOfWorkLimit = bnProofOfWorkLimitTestNet; // 0x0000ffff PoW base target is fixed in testnet
- nStakeMinAge = 5 * 60; // test net min age is 5 min
- nStakeMaxAge = 60 * 60; // test net max age is 60 min
- nModifierInterval = 60; // test modifier interval is 2 minutes
- nCoinbaseMaturity = 180; // test maturity is 10 blocks
- nStakeTargetSpacing = 3 * 60; // test block spacing is 3 minutes
+ bnProofOfStakeLimit = bnProofOfStakeLimitTestNet;
+ bnProofOfWorkLimit = bnProofOfWorkLimitTestNet;
+
+ nStakeMinAge = 60 * 60;
+ nStakeMinAgeFixed = 60 * 60;
+ nStakeMaxAge = 2 * 24 * 60 * 60;
+ nModifierInterval = 5 * 60;
+ nCoinbaseMaturity = 10;
+ nStakeTargetSpacing = 100;
}
//
@@ -2676,34 +2842,90 @@ bool LoadBlockIndex(bool fAllowNew)
if (!fAllowNew)
return false;
- // Genesis block
- const char* pszTimestamp = "Friday, July 12, 11:19 AM: Cavendish wins eventful 13th stage of Tour de France as Froome loses chunk of overall lead";
CTransaction txNew;
- txNew.nTime = nChainStartTime;
- txNew.vin.resize(1);
- txNew.vout.resize(1);
- txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
- txNew.vout[0].SetEmpty();
- txNew.strTxComment = "text:Diamond genesis block";
-
CBlock block;
- block.vtx.push_back(txNew);
- block.hashPrevBlock = 0;
- block.hashMerkleRoot = block.BuildMerkleTree();
- block.nVersion = 1;
- block.nTime = 1373654846;
- block.nBits = bnProofOfWorkLimit.GetCompact();
- block.nNonce = 11111111;
+
+ if(!fTestNet) {
+
+ /* Livenet genesis */
+ const char* pszTimestamp = "Friday, July 12, 11:19 AM: Cavendish wins eventful 13th stage of Tour de France as Froome loses chunk of overall lead";
+ txNew.nVersion = 2;
+ txNew.nTime = nChainStartTime;
+ txNew.vin.resize(1);
+ txNew.vout.resize(1);
+ txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
+ txNew.vout[0].SetEmpty();
+ txNew.strTxComment = "text:Diamond genesis block";
+
+ block.vtx.push_back(txNew);
+ block.hashPrevBlock = 0;
+ block.hashMerkleRoot = block.BuildMerkleTree();
+ block.nVersion = 1;
+ block.nTime = 1373654846;
+ block.nBits = bnProofOfWorkLimit.GetCompact();
+ block.nNonce = 11111111;
+
+ } else {
+
+ /* Testnet genesis */
+ const char* pszTimestamp = "Let it ride!";
+ txNew.nVersion = 2;
+ txNew.nTime = 1453766400;
+ txNew.vin.resize(1);
+ txNew.vout.resize(1);
+ txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
+ txNew.vout[0].SetEmpty();
+ txNew.strTxComment = "text:Diamond testnet genesis";
+
+ block.vtx.push_back(txNew);
+ block.hashPrevBlock = 0;
+ block.hashMerkleRoot = block.BuildMerkleTree();
+ block.nVersion = 1;
+ block.nTime = 1453939200;
+ block.nBits = bnProofOfWorkLimit.GetCompact();
+ block.nNonce = 10211336;
+
+ }
//// debug print
block.print();
- printf("block.GetHash() == %s\n", block.GetHashScrypt().ToString().c_str());
+ printf("block.GetHash() == %s\n", fTestNet ? block.GetHashGroestl().ToString().c_str() : block.GetHashScrypt().ToString().c_str());
printf("block.hashMerkleRoot == %s\n", block.hashMerkleRoot.ToString().c_str());
printf("block.nTime = %u \n", block.nTime);
printf("block.nNonce = %u \n", block.nNonce);
- assert(block.hashMerkleRoot == uint256("0xaaaa88b5c5c937bcd7709c86903197009e02495dba5b919488d996dec10d26c4"));
- assert(block.GetHashScrypt() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet));
+ if(!fTestNet) assert(block.hashMerkleRoot == uint256("0xaaaa88b5c5c937bcd7709c86903197009e02495dba5b919488d996dec10d26c4"));
+ else assert(block.hashMerkleRoot == uint256("0x6db63a9f5ba6b72c48781a584e859909ada5430b216804d08fbbd9f1c3129273"));
+
+ /* Groestl testnet block mining */
+ if(false && (block.GetHashGroestl() != hashGenesisBlockTestNet)) {
+
+ printf("Genesis block mining...\n");
+
+ uint256 hashTarget = CBigNum().SetCompact(block.nBits).getuint256();
+ uint256 hash;
+
+ while(true) {
+ hash = block.GetHashGroestl();
+ if(hash <= hashTarget) break;
+ if(!(block.nNonce & 0xFFF))
+ printf("nonce %08X: hash = %s (target = %s)\n",
+ block.nNonce, hash.ToString().c_str(),
+ hashTarget.ToString().c_str());
+ ++block.nNonce;
+ if(!block.nNonce) {
+ printf("nonce limit reached, incrementing time\n");
+ ++block.nTime;
+ }
+ }
+ printf("block.nTime = %u \n", block.nTime);
+ printf("block.nNonce = %u \n", block.nNonce);
+ printf("block.GetHash = %s\n", block.GetHashGroestl().ToString().c_str());
+ }
+
+ block.print();
+ if(!fTestNet) assert(block.GetHashScrypt() == hashGenesisBlock);
+ else assert(block.GetHashGroestl() == hashGenesisBlockTestNet);
// Start new block file
unsigned int nFile;
@@ -2786,11 +3008,12 @@ void PrintBlockTree()
// print item
CBlock block;
block.ReadFromDisk(pindex);
+// danbi: optimization for GetHash() possible here
printf("%d (%u,%u) %s %08x %s mint %7s tx %"PRIszu"",
pindex->nHeight,
pindex->nFile,
pindex->nBlockPos,
- block.GetHash().ToString().c_str(),
+ block.GetHash(true).ToString().c_str(),
block.nBits,
DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
FormatMoney(pindex->nMint).c_str(),
@@ -3004,9 +3227,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true;
}
+ // print what we got
+ if (fDebug) printf("%s from %s\n", strCommand.c_str(), pfrom->addr.ToString().c_str());
-
-
+ // make sure we have current totalCoin
+ totalCoin = GetTotalCoin();
if (strCommand == "version")
{
@@ -3031,8 +3256,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return false;
}
- if (pfrom->nVersion == 10300)
- pfrom->nVersion = 300;
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty())
@@ -3054,6 +3277,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true;
}
+ /* Disconnect all obsolete clients after 20 June 2016 12:00:00 UTC */
+ uint nAdjTime = GetAdjustedTime();
+ if(nAdjTime > 1466424000) {
+ if(pfrom->nVersion < MIN_PROTOCOL_VERSION) {
+ printf("obsolete node %s with client %d, disconnecting\n",
+ pfrom->addr.ToString().c_str(), pfrom->nVersion);
+ pfrom->fDisconnect = true;
+ return(true);
+ }
+ }
+
// ppcoin: record my external IP reported by peer
if (addrFrom.IsRoutable() && addrMe.IsRoutable())
addrSeenByPeer = addrMe;
@@ -3203,7 +3437,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
}
// Do not store addresses outside our network
- if (fReachable)
+ // danbi: ignore reachable if we do OneShot
+ if (fReachable || pfrom->fOneShot)
vAddrOk.push_back(addr);
}
addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
@@ -3213,7 +3448,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fDisconnect = true;
}
-
else if (strCommand == "inv")
{
vector vInv;
@@ -3274,14 +3508,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return error("message getdata size() = %"PRIszu"", vInv.size());
}
- if (fDebugNet || (vInv.size() != 1))
+ if (fDebugNet && (vInv.size() != 1))
printf("received getdata (%"PRIszu" invsz)\n", vInv.size());
BOOST_FOREACH(const CInv& inv, vInv)
{
if (fShutdown)
return true;
- if (fDebugNet || (vInv.size() == 1))
+ if (fDebugNet && (vInv.size() == 1))
printf("received getdata for: %s\n", inv.ToString().c_str());
if (inv.type == MSG_BLOCK)
@@ -3298,7 +3532,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (inv.hash == pfrom->hashContinue)
{
// ppcoin: send latest proof-of-work block to allow the
- // download node to accept as orphan (proof-of-stake
+ // download node to accept as orphan (proof-of-stake
// block might be rejected by stake connection check)
vector vInv;
vInv.push_back(CInv(MSG_BLOCK, GetLastBlockIndex(pindexBest, false)->GetBlockHash()));
@@ -3349,25 +3583,30 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Send the rest of the chain
if (pindex)
pindex = pindex->pnext;
- int nLimit = 500;
- printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
+ int nLimit = 500 + locator.GetDistanceBack();
+ unsigned int nBytes = 0;
+ if (fDebug) printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
if (pindex->GetBlockHash() == hashStop)
{
- printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ if (fDebug) printf(" getblocks (hashStop) stopping at %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
// ppcoin: tell downloading node about the latest block if it's
// without risk being rejected due to stake connection check
- if (hashStop != hashBestChain && pindex->GetBlockTime() + nStakeMinAge > pindexBest->GetBlockTime())
+ if((hashStop != hashBestChain) &&
+ (pindex->GetBlockTime() + nStakeMinAgeFixed > pindexBest->GetBlockTime()))
pfrom->PushInventory(CInv(MSG_BLOCK, hashBestChain));
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
- if (--nLimit <= 0)
+ CBlock block;
+ block.ReadFromDisk(pindex, true);
+ nBytes += block.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION);
+ if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
{
// When this block is requested, we'll send an inv that'll make them
// getblocks the next batch of inventory.
- printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ if (fDebug) printf(" getblocks (nLimit) stopping at limit %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
pfrom->hashContinue = pindex->GetBlockHash();
break;
}
@@ -3497,11 +3736,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
CBlock block;
vRecv >> block;
+ uint256 hashBlock = block.GetHash();
- printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str());
+ printf("received block %s height %d\n",
+ hashBlock.ToString().substr(0,20).c_str(), block.GetBlockHeight());
// block.print();
- CInv inv(MSG_BLOCK, block.GetHash());
+ CInv inv(MSG_BLOCK, hashBlock);
pfrom->AddInventoryKnown(inv);
if (ProcessBlock(pfrom, &block))
@@ -3933,50 +4174,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// BitcoinMiner
-//
-
-int static FormatHashBlocks(void* pbuffer, unsigned int len)
-{
- unsigned char* pdata = (unsigned char*)pbuffer;
- unsigned int blocks = 1 + ((len + 8) / 64);
- unsigned char* pend = pdata + 64 * blocks;
- memset(pdata + len, 0, 64 * blocks - len);
- pdata[len] = 0x80;
- unsigned int bits = len * 8;
- pend[-1] = (bits >> 0) & 0xff;
- pend[-2] = (bits >> 8) & 0xff;
- pend[-3] = (bits >> 16) & 0xff;
- pend[-4] = (bits >> 24) & 0xff;
- return blocks;
-}
-
-static const unsigned int pSHA256InitState[8] =
-{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
-
-void SHA256Transform(void* pstate, void* pinput, const void* pinit)
-{
- SHA256_CTX ctx;
- unsigned char data[64];
-
- SHA256_Init(&ctx);
-
- for (int i = 0; i < 16; i++)
- ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]);
-
- for (int i = 0; i < 8; i++)
- ctx.h[i] = ((uint32_t*)pinit)[i];
-
- SHA256_Update(&ctx, data, sizeof(data));
- for (int i = 0; i < 8; i++)
- ((uint32_t*)pstate)[i] = ctx.h[i];
-}
-
// Some explaining would be appreciated
class COrphan
{
@@ -4005,7 +4202,7 @@ class COrphan
uint64 nLastBlockTx = 0;
uint64 nLastBlockSize = 0;
int64 nLastCoinStakeSearchInterval = 0;
-
+
// We want to sort transactions by priority and fee, so:
typedef boost::tuple TxPriority;
class TxPriorityCompare
@@ -4041,21 +4238,29 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
if (!pblock.get())
return NULL;
+ int nPrevHeight = pindexBest->nHeight;
+
+ bool fContribution = false;
+ if((fTestNet && (nPrevHeight + 1 < nTestStage1)) ||
+ (!fTestNet && ((totalCoin > VALUE_CHANGE) && (nPrevHeight + 1 < nLiveFork1))))
+ fContribution = true;
+
// Create coinbase tx
CTransaction txNew;
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
- if(totalCoin >= VALUE_CHANGE)
- {
- CBitcoinAddress address(!fTestNet ? DEV_ADDRESS : DEV_ADDRESS_TEST);
+ if(fContribution) {
+ CBitcoinAddress address = GetFoundationAddress(totalCoin);
txNew.vout.resize(2);
- txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
- txNew.vout[1].scriptPubKey.SetDestination(address.Get());
- }
- else
- {
+ if(!fProofOfStake) {
+ txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+ txNew.vout[1].scriptPubKey.SetDestination(address.Get());
+ }
+ } else {
txNew.vout.resize(1);
- txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+ if(!fProofOfStake) {
+ txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+ }
}
// Add our coinbase tx as first transaction
@@ -4096,17 +4301,17 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
int64 nSearchTime = txCoinStake.nTime; // search to current time
if (nSearchTime > nLastCoinStakeSearchTime)
{
- // printf(">>> OK1\n");
if (pwallet->CreateCoinStake(*pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake))
{
- if (txCoinStake.nTime >= max(pindexPrev->GetMedianTimePast()+1, pindexPrev->GetBlockTime() - nMaxClockDrift))
+ if(txCoinStake.nTime >= max(pindexPrev->GetMedianTimePast() + 1,
+ pindexPrev->GetBlockTime() - nNewMaxClockDrift))
{ // make sure coinstake would meet timestamp protocol
// as it would be the same as the block timestamp
- pblock->vtx.push_back(txCoinStake);
pblock->vtx[0].vout[0].SetEmpty();
- if(totalCoin >= VALUE_CHANGE)
+ if(fContribution)
pblock->vtx[0].vout[1].SetEmpty();
pblock->vtx[0].nTime = txCoinStake.nTime;
+ pblock->vtx.push_back(txCoinStake);
}
}
nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime;
@@ -4153,7 +4358,7 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
if (!mempool.mapTx.count(txin.prevout.hash))
{
printf("ERROR: mempool transaction missing input\n");
- if (fDebug) assert("mempool transaction missing input" == 0);
+ // if (fDebug) assert("mempool transaction missing input" == 0);
fMissingInputs = true;
if (porphan)
vOrphan.pop_back();
@@ -4311,8 +4516,8 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
if (pblock->IsProofOfWork())
{
pblock->vtx[0].vout[0].nValue = GetProofOfWorkReward(pindexPrev->nHeight+1, nFees, pindexPrev->GetBlockHash());
- if(totalCoin >= VALUE_CHANGE)
- pblock->vtx[0].vout[1].nValue = GetDevCoin(totalCoin);
+ if(fContribution)
+ pblock->vtx[0].vout[1].nValue = GetContributionAmount(totalCoin);
}
// Fill in header
@@ -4320,7 +4525,7 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
if (pblock->IsProofOfStake())
pblock->nTime = pblock->vtx[1].nTime; //same as coinstake timestamp
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime());
- pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift);
+ pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nNewMaxClockDrift);
if (pblock->IsProofOfWork())
pblock->UpdateTime(pindexPrev);
pblock->nNonce = 0;
@@ -4348,49 +4553,33 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
}
-void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1)
-{
- //
- // Pre-build hash buffers
- //
- struct
- {
- struct unnamed2
- {
- int nVersion;
- uint256 hashPrevBlock;
- uint256 hashMerkleRoot;
- unsigned int nTime;
- unsigned int nBits;
- unsigned int nNonce;
- }
- block;
- unsigned char pchPadding0[64];
- uint256 hash1;
- unsigned char pchPadding1[64];
- }
- tmp;
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.block.nVersion = pblock->nVersion;
- tmp.block.hashPrevBlock = pblock->hashPrevBlock;
- tmp.block.hashMerkleRoot = pblock->hashMerkleRoot;
- tmp.block.nTime = pblock->nTime;
- tmp.block.nBits = pblock->nBits;
- tmp.block.nNonce = pblock->nNonce;
-
- FormatHashBlocks(&tmp.block, sizeof(tmp.block));
- FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
-
- // Byte swap all the input buffer
- for (unsigned int i = 0; i < sizeof(tmp)/4; i++)
- ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
-
- // Precalc the first half of the first hash, which stays constant
- SHA256Transform(pmidstate, &tmp.block, pSHA256InitState);
-
- memcpy(pdata, &tmp.block, 128);
- memcpy(phash1, &tmp.hash1, 64);
+void FormatDataBuffer(CBlock *pblock, uint *pdata) {
+ uint i;
+
+ struct {
+ int nVersion;
+ uint256 hashPrevBlock;
+ uint256 hashMerkleRoot;
+ uint nTime;
+ uint nBits;
+ uint nNonce;
+ } data;
+
+ data.nVersion = pblock->nVersion;
+ data.hashPrevBlock = pblock->hashPrevBlock;
+ data.hashMerkleRoot = pblock->hashMerkleRoot;
+ data.nTime = pblock->nTime;
+ data.nBits = pblock->nBits;
+ data.nNonce = pblock->nNonce;
+
+ /* Block header size in bits */
+ pdata[31] = 640;
+ /* Convert LE to BE and copy */
+ for(i = 0; i < 20; i++)
+ pdata[i] = ByteReverse(((uint *) &data)[i]);
+ /* Erase the remaining part */
+ for(i = 20; i < 31; i++)
+ pdata[i] = 0;
}
@@ -4399,17 +4588,37 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
uint256 hash = pblock->GetHash();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
- if (hash > hashTarget && pblock->IsProofOfWork())
- return error("BitcoinMiner : proof-of-work not meeting target");
+ if(pblock->IsProofOfWork()) {
+ CAuxPow *auxpow = pblock->auxpow.get();
+
+ if(auxpow != NULL) {
+ if(!auxpow->Check(hash, pblock->GetChainID()))
+ return(error("AuxPoW is not valid"));
+
+ if(auxpow->GetParentBlockHash() > hashTarget)
+ return(error("AuxPoW parent hash %s is not under target %s",
+ auxpow->GetParentBlockHash().GetHex().c_str(), hashTarget.GetHex().c_str()));
+
+ printf("DiamondMiner:\n");
+ printf("AUX proof-of-work found \n our hash: %s \n parent hash: %s \n target: %s\n",
+ hash.GetHex().c_str(), auxpow->GetParentBlockHash().GetHex().c_str(), hashTarget.GetHex().c_str());
+ } else {
+ if(hash > hashTarget)
+ return(error("DiamondMiner : proof-of-work not meeting target"));
+
+ printf("DiamondMiner:\n");
+ printf("proof-of-work found \n hash: %s \ntarget: %s\n",
+ hash.GetHex().c_str(), hashTarget.GetHex().c_str());
+ }
+ } else {
+
+ printf("DiamondMiner:\n");
+ printf("proof-of-stake found \n hash: %s \ntarget: %s\n",
+ hash.GetHex().c_str(), hashTarget.GetHex().c_str());
+ }
- //// debug print
- printf("BitcoinMiner:\n");
- printf("new block found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
pblock->print();
- if(totalCoin >= VALUE_CHANGE)
- printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue + pblock->vtx[0].vout[1].nValue).c_str());
- else
- printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
+ printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
// Found a solution
{
@@ -4423,7 +4632,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
// Track how many getdata requests this block gets
{
LOCK(wallet.cs_wallet);
- wallet.mapRequestCount[pblock->GetHash()] = 0;
+ wallet.mapRequestCount[hash] = 0;
}
// Process this block the same as if we had received it from another node
@@ -4442,8 +4651,6 @@ static int nLimitProcessors = -1;
void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
{
- void *scratchbuf = scrypt_buffer_alloc();
-
printf("CPUMiner started for proof-of-%s\n", fProofOfStake? "stake" : "work");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
@@ -4453,20 +4660,20 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
// Each thread has its own key and counter
CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
- totalCoin = GetTotalCoin();
+
while (fGenerateBitcoins || fProofOfStake)
{
totalCoin = GetTotalCoin();
- if(totalCoin < VALUE_CHANGE && fProofOfStake)
- break;
if (fShutdown)
return;
- while (vNodes.empty() || IsInitialBlockDownload())
+
+ while (vNodes.empty() || IsInitialBlockDownload() || pwallet->IsLocked())
{
+ nLastCoinStakeSearchInterval = 0;
Sleep(1000);
if (fShutdown)
return;
- if ((!fGenerateBitcoins) && !fProofOfStake)
+ if (!fGenerateBitcoins && !fProofOfStake)
return;
}
@@ -4510,20 +4717,19 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
continue;
}
-// printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(),
-// ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
+ //printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(),
+ // ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
//
// Pre-build hash buffers
//
- char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf);
- char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf);
- char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf);
+ char pdatabuf[128+16];
+ char *pdata = alignup<16>(pdatabuf);
- FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1);
+ FormatDataBuffer(pblock.get(), (uint *) pdata);
unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
- unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
+// unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
//
@@ -4532,96 +4738,31 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
int64 nStart = GetTime();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
- unsigned int max_nonce = 0xffff0000;
- block_header res_header;
- uint256 result;
-
while (true)
{
-
+ // always calculate totalCoin
totalCoin = GetTotalCoin();
- unsigned int nHashesDone = 0;
-
- uint256 thash;
- char scratchpad[SCRYPT_SCRATCHPAD_SIZE];
-
- if(totalCoin < VALUE_CHANGE)
+ // new block, use groestl
+ uint256 hash = pblock->GetHashGroestl();
+ if (hash <= hashTarget)
{
- //scrypt_1024_1_1_256_sp(BEGIN(pblock->nVersion), BEGIN(thash), scratchpad);
-
- if (thash <= hashTarget)
+ if (!pblock->SignBlock(*pwalletMain))
{
- // Found a solution
- SetThreadPriority(THREAD_PRIORITY_NORMAL);
- CheckWork(pblock.get(), *pwallet, reservekey);
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
+ strMintWarning = strMintMessage;
break;
}
- pblock->nNonce += 1;
- nHashesDone += 1;
- if ((pblock->nNonce & 0xFF) == 0)
- break;
-// unsigned int nNonceFound;
-
-// nNonceFound = scanhash_scrypt(
-// (block_header *)&pblock->nVersion,
-// scratchbuf,
-// max_nonce,
-// nHashesDone,
-// UBEGIN(result),
-// &res_header
-// );
-
-// // Check if something found
-// if (nNonceFound != (unsigned int) -1 && totalCoin < VALUE_CHANGE)
-// {
-// if (result <= hashTarget && totalCoin < VALUE_CHANGE)
-// {
-// // Found a solution
-// pblock->nNonce = nNonceFound;
-// assert(result == pblock->GetHash());
-// if (!pblock->SignBlock(*pwalletMain))
-// {
-// // strMintWarning = strMintMessage;
-// break;
-// }
-// strMintWarning = "";
-
-// SetThreadPriority(THREAD_PRIORITY_NORMAL);
-// CheckWork(pblock.get(), *pwalletMain, reservekey);
-// SetThreadPriority(THREAD_PRIORITY_LOWEST);
-// break;
-// }
-// else
-// break;
-// }
-// else
-// break;
- }
- else
- {
- uint256 hash;
- hash = pblock->GetHash();
- if (hash <= hashTarget)
- {
- if (!pblock->SignBlock(*pwalletMain))
- {
-// strMintWarning = strMintMessage;
- break;
- }
- strMintWarning = "";
- // nHashesDone += pblock->nNonce;
- SetThreadPriority(THREAD_PRIORITY_NORMAL);
+ strMintWarning = "";
+ SetThreadPriority(THREAD_PRIORITY_NORMAL);
- printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
- pblock->print();
+ printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
+ pblock->print();
- CheckWork(pblock.get(), *pwalletMain, reservekey);
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
- break;
- }
- ++pblock->nNonce;
+ CheckWork(pblock.get(), *pwalletMain, reservekey);
+ SetThreadPriority(THREAD_PRIORITY_LOWEST);
+ break;
}
+ ++pblock->nNonce;
+
// Meter hashes/sec
static int64 nHashCounter;
if (nHPSTimerStart == 0)
@@ -4630,12 +4771,7 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
nHashCounter = 0;
}
else
- {
- if(totalCoin < VALUE_CHANGE)
- nHashCounter += nHashesDone;
- else
- nHashCounter += 1;
- }
+ nHashCounter++;
if (GetTimeMillis() - nHPSTimerStart > 4000)
{
static CCriticalSection cs;
@@ -4646,12 +4782,12 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
nHPSTimerStart = GetTimeMillis();
nHashCounter = 0;
-// static int64 nLogTime;
-// if (GetTime() - nLogTime > 30 * 60)
-// {
-// nLogTime = GetTime();
+ static int64 nLogTime;
+ if (GetTime() - nLogTime > 30 * 60)
+ {
+ nLogTime = GetTime();
printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0);
-// }
+ }
}
}
}
@@ -4665,16 +4801,8 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
return;
if (vNodes.empty())
break;
- if(totalCoin < VALUE_CHANGE)
- {
- if (nBlockNonce >= 0xffff0000)
- break;
- }
- else
- {
- if (++pblock->nNonce >= 0xffff0000)
- break;
- }
+ if (pblock->nNonce >= 0xffff0000)
+ break;
if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
if (pindexPrev != pindexBest)
@@ -4682,16 +4810,13 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
// Update nTime every few seconds
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime());
- pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift);
+ pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nNewMaxClockDrift);
pblock->UpdateTime(pindexPrev);
nBlockTime = ByteReverse(pblock->nTime);
-
- if (pblock->GetBlockTime() >= (int64)pblock->vtx[0].nTime + nMaxClockDrift)
+ if (pblock->GetBlockTime() >= (int64)pblock->vtx[0].nTime + nNewMaxClockDrift)
break; // need to update coinbase timestamp
}
}
-
- scrypt_buffer_free(scratchbuf);
}
void static ThreadBitcoinMiner(void* parg)
@@ -4744,30 +4869,103 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
}
}
-
-int64 GetDevCoin(int64 totalCoin) {
- if(totalCoin < 1000000)
+// Diamond coin mechanics
+// Foundation contribution
+// 0.05 until 1000000 coins generated
+// 0.01 afterwards
+// Changing this requires a fork
+int64 GetContributionAmount(int64 totalCoin) {
+ if (totalCoin < 1000000)
return 0.05 * COIN;
else
return 0.01 * COIN;
}
-uint256 CBlock::GetHash() const
+// Return Foundation Address to send contributions to
+// address changes every 500000 coin in order to reduce wallet bloat
+//
+CBitcoinAddress GetFoundationAddress(int64 totalCoin) {
+ if (fTestNet)
+ return CBitcoinAddress("mzN2GRXyBuw7uWxEEBcxUeyga4Ka7xAscJ"); // test Foundation address
+
+ if (totalCoin < 1000000)
+ return CBitcoinAddress("dZi9hpA5nBC6tSAbPSsiMjb6HeQTprcWHz");
+ else if (totalCoin < 1500000)
+ return CBitcoinAddress("dTZMqKTYGUwF3aLFx31anxsNKrtaWn6U3x");
+ else if (totalCoin < 2000000)
+ return CBitcoinAddress("dPbhK6rPtaBeGepU1nqghZRy4NWot5T7dG");
+ else if (totalCoin < 2500000)
+ return CBitcoinAddress("dbXsr1iVzF6KDRxDspAbvtCpdscF28bD8J");
+ else
+ return CBitcoinAddress ("dSDEptc8gJzbEe3Kfta8McvnBmapk6fcrR");
+}
+
+uint256 CBlock::GetHash(bool existingBlock, int64 coins) const
{
- if((totalCoinDB <= VALUE_CHANGE && totalCoin == -1) || (totalCoin >= 0 && totalCoin < VALUE_CHANGE))
- {
- uint256 thash;
- void * scratchbuff = scrypt_buffer_alloc();
+ if(fTestNet)
+ return(GetHashGroestl());
- scrypt_hash(CVOIDBEGIN(nVersion), sizeof(block_header), UINTBEGIN(thash), scratchbuff);
+ // existingBlock is set by default to false
+ // coins is set by default to (global) totalCoin
+ //
+ // There are two distinct cases when we are called
+ // existingBlock=true - a block already in the blockchain index
+ // both coins and totalCoin are ignored
+ // existingBlock=false - for a new block or when totalCoins is known
+ // in the context. The parameter coins is used in this case
+
+if (fDebug && GetBoolArg("-printjunk") && coins != totalCoin) {
+ printf("COMP: coins(%"PRI64d") != totalCoin(%"PRI64d")\n", coins, totalCoin);
+}
+// special case
+if (coins == 0 && !(totalCoin == 0)) {
+ printf("CBlock::GetHash: coins is 0, totalCoin is %"PRI64d"\n", totalCoin);
+ coins=totalCoin;
+}
- scrypt_buffer_free(scratchbuff);
+ if (existingBlock)
+ {
+ //printf("CBlock::GetHash() look up an existing block\n");
+ // We first check Groestl hash as that's less expensive and
+ // there are enough groestl blocks now
+ uint256 hash_groestl = GetHashGroestl();
+ if (hash_groestl == uint256("0xe12ddb2c35d84403b0a045574ecce223f7e2f0db4506e76ed3d43bc464ace40c")) {
+ printf("GetHash(true): hash fixed up (groestl)\n");
+ return uint256("0x000009d32c4f8ec5d66a65e88c8099da31452de0daec3b0b68926659b50b4e8f");
+ }
+ CBlockIndex* pblockindex_groestl = mapBlockIndex[hash_groestl];
+ if (pblockindex_groestl)
+ return hash_groestl;
+
+ // we are here so it must be Scrypt
+ uint256 hash_scrypt = GetHashScrypt();
+ if (hash_scrypt == uint256("0x92134c4608025b6bd945731158391079590d0e7e0c60bd7d09a50c0b0251c6ac")) {
+ printf("GetHash(true): hash fixed up (scrypt)\n");
+ return uint256("0x00000d652b612a94e1c830bf4e05106438ea6b53372b29206f0b820d91a9b67b");
+ }
+ // find the index position(s)
+ CBlockIndex* pblockindex_scrypt = mapBlockIndex[hash_scrypt];
+ if (pblockindex_scrypt)
+ return hash_scrypt;
- return thash;
+ // XXX: We are here, asked for an existing hash but did not find it!
+ printf("CBlock::GetHash(true): neither scrypt nor groestl hash found in the block index! Failing back..\n");
}
- else if((totalCoinDB > VALUE_CHANGE && totalCoin == -1) || (totalCoin >= VALUE_CHANGE))
+
+ if (coins <= VALUE_CHANGE)
{
- return HashGroestl(BEGIN(nVersion), END(nNonce));
+ uint256 hash_scrypt = GetHashScrypt();
+ if (hash_scrypt == uint256("0x92134c4608025b6bd945731158391079590d0e7e0c60bd7d09a50c0b0251c6ac")) {
+ printf("GetHash(): hash fixed up (scrypt)\n");
+ return uint256("0x00000d652b612a94e1c830bf4e05106438ea6b53372b29206f0b820d91a9b67b");
+ }
+ return hash_scrypt;
+ }
+
+ uint256 hash_groestl = GetHashGroestl();
+ if (hash_groestl == uint256("0xe12ddb2c35d84403b0a045574ecce223f7e2f0db4506e76ed3d43bc464ace40c")) {
+ printf("GetHash(): hash fixed up (groestl)\n");
+ return uint256("0x000009d32c4f8ec5d66a65e88c8099da31452de0daec3b0b68926659b50b4e8f");
}
- return HashGroestl(BEGIN(nVersion), END(nNonce));
+ return hash_groestl;
}
diff --git a/src/main.h b/src/main.h
index 0418f93..43a6607 100644
--- a/src/main.h
+++ b/src/main.h
@@ -13,6 +13,7 @@
#include "bitcoinrpc.h"
#include
#include "hash.h"
+#include "base58.h"
class CWallet;
class CBlock;
@@ -25,6 +26,7 @@ class CAddress;
class CInv;
class CRequestTracker;
class CNode;
+class CAuxPow;
static const unsigned int MAX_BLOCK_SIZE = 1000000;
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
@@ -39,12 +41,21 @@ static const int64 CIRCULATION_MONEY = MAX_MONEY;
static const double TAX_PERCENTAGE = 0.01;
static const int64 MAX_MINT_PROOF_OF_STAKE = 1 * CENT;
static const int64 MIN_TXOUT_AMOUNT = MIN_TX_FEE;
-static const int64 VALUE_CHANGE = 369494;
-#define DEV_ADDRESS "dZi9hpA5nBC6tSAbPSsiMjb6HeQTprcWHz"
-#define DEV_ADDRESS_TEST "mwmPTAA7cSDY8Dd5rRHuYitwS2hByXQpdA"
+static const int64 VALUE_CHANGE = 369494; // When to switch to Groestl
+static const int64 POS_RESTART = 450000; // When to apply fixes to enable PoS
-inline int64_t PastDrift(int64 nTime) { return nTime - 15 * 60; } // up to 1 day from the past
-inline int64_t FutureDrift(int64 nTime) { return nTime + 15 * 60; } // up to 1 day from the future
+static const int nTestStage1 = 315; /* Testnet: disable foundation PoW share */
+static const int nTestStage2 = 330; /* Testnet: disable PoW block signature */
+static const int nTestStage3 = 340; /* Testnet: reduce time drifts */
+static const int nTestStage4 = 440; /* Testnet: enable merged mining */
+
+/* Testnet: SHA-256 transaction hashing after 8-Feb-2016 15:00 UTC */
+static const unsigned int nTestTxSwitch = 1454943600;
+
+static const int nLiveFork1 = 1549200; /* Livenet: cumulative hard fork */
+
+/* Livenet: SHA-256 transaction hashing and fixed min. stake age */
+static const unsigned int nLiveTimeSwitch = ~0U;
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
@@ -57,14 +68,15 @@ static const int fHaveUPnP = false;
#endif
static const uint256 hashGenesisBlockOfficial("0x2d8b2c67b7f56e70b9b16b377b988bb1bcb7a92b5b01c0fedcc60dc9c46ab511");
-static const uint256 hashGenesisBlockTestNet ("0xa0d5631064182289fbd9cf2451ddada6d698f65dfa44bc20b3c6e6548fdd2666");
+static const uint256 hashGenesisBlockTestNet ("0x0000004b5393b6564f68472ce799a25c56fc63f45d55b7b1f450ac5836598a20");
static const int64 nMaxClockDrift = 2 * 60 * 60; // two hours
+static const int64 nNewMaxClockDrift = 15 * 60;
+
+extern bool fOldMerkleHash;
extern CScript COINBASE_FLAGS;
-extern int64 coinMax;
-extern int64 totalCoinDB;
extern int64 totalCoin;
extern CCriticalSection cs_main;
extern std::map mapBlockIndex;
@@ -72,6 +84,7 @@ extern std::set > setStakeSeen;
extern uint256 hashGenesisBlock;
extern CBlockIndex* pindexGenesisBlock;
extern unsigned int nStakeMinAge;
+extern unsigned int nStakeMinAgeFixed;
extern int nCoinbaseMaturity;
extern int nBestHeight;
extern CBigNum bnBestChainTrust;
@@ -93,17 +106,19 @@ extern std::map mapOrphanBlocks;
// Settings
extern int64 nTransactionFee;
+extern bool fUseFastIndex;
+// where to deposit change
+extern CTxDestination changeAddress;
// Minimum disk space required - used in CheckDiskSpace()
static const uint64 nMinDiskSpace = 52428800;
-
class CReserveKey;
class CTxDB;
class CTxIndex;
-
-int64 GetDevCoin(int64 totalCoin);
+int64 GetContributionAmount(int64 totalCoin);
+CBitcoinAddress GetFoundationAddress(int64 totalCoin);
void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn);
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true);
@@ -120,11 +135,10 @@ bool LoadExternalBlockFile(FILE* fileIn);
void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake=false);
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
-void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
+void FormatDataBuffer(CBlock *pblock, unsigned int *pdata);
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
-bool CheckProofOfWork(uint256 hash, unsigned int nBits);
int64 GetProofOfWorkReward(int nHeight, int64 nFees, uint256 prevHash);
-int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight);
+int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight, float reactorRate = 0);
unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime);
int GetNumBlocksOfPeers();
@@ -143,8 +157,6 @@ void ResendWalletTransactions();
-
-
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
/** Position on disk for a particular transaction. */
@@ -390,7 +402,7 @@ class CTxOut
uint256 GetHash() const
{
- return SerializeHash(*this);
+ return(SerializeHash2(*this));
}
friend bool operator==(const CTxOut& a, const CTxOut& b)
@@ -441,8 +453,7 @@ typedef std::map > MapPrevTx;
class CTransaction
{
public:
- static const int LEGACY_VERSION_1=1;
- static const int CURRENT_VERSION = 2;
+ static const int CURRENT_VERSION = 3;
int nVersion;
unsigned int nTime;
@@ -468,14 +479,19 @@ class CTransaction
READWRITE(vin);
READWRITE(vout);
READWRITE(nLockTime);
- if(this->nVersion > LEGACY_VERSION_1) {
+ if(this->nVersion > 1) {
READWRITE(strTxComment); }
)
void SetNull()
{
- nVersion = CTransaction::CURRENT_VERSION;
nTime = GetAdjustedTime();
+ if((fTestNet && (nTime < nTestTxSwitch)) ||
+ (!fTestNet)) {
+ nVersion = 2;
+ } else {
+ nVersion = CTransaction::CURRENT_VERSION;
+ }
vin.clear();
vout.clear();
nLockTime = 0;
@@ -488,9 +504,13 @@ class CTransaction
return (vin.empty() && vout.empty());
}
- uint256 GetHash() const
- {
- return SerializeHash(*this);
+ uint256 GetHash() const {
+ if((fTestNet && (nTime < nTestTxSwitch)) ||
+ (!fTestNet)) {
+ return(SerializeHash2(*this));
+ } else {
+ return(SerializeHash1(*this));
+ }
}
bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
@@ -546,10 +566,28 @@ class CTransaction
bool IsCoinStake() const
{
- // ppcoin: the coin stake transaction is marked with the first output empty
- return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());
+ /* Reactor stakes are marked with an OP code in the first output all
+ * other stakes are marked by having the first output left empty. */
+ if (!vout[0].IsEmpty() && vout[0].scriptPubKey[0] == OP_REACTOR) {
+ return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].scriptPubKey[0] == OP_REACTOR);
+ } else {
+ return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());
+ }
}
+ bool IsCoinBaseOrStake() const
+ {
+ return (IsCoinBase() || IsCoinStake());
+ }
+
+ /** Check if a stake transaction is a reactor stake
+ this is defined in reactors.cpp and is utilized in ConnectInputs.
+ Passes the database filename so that tests can be ran on a mockdb
+ instead of using the db in the datadir.
+ @ return True for valid and DoS or false for all else.
+ */
+ bool IsReactorStake(std::string strFileName, CScript scriptPubKeyType, CScript scriptPubKeyAddress, unsigned int nTime, int64 nValueIn, int64 nValueOut, uint64 nCoinAge, unsigned int nBits, int nHeight);
+
/** Check for standard transaction types
@return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
@@ -662,7 +700,7 @@ class CTransaction
{
std::string str;
str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
- str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%d)\n",
+ str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%d), TxComment=%s\n",
GetHash().ToString().substr(0,10).c_str(),
nTime,
nVersion,
@@ -838,7 +876,29 @@ class CTxIndex
};
+template
+int ReadWriteAuxPow(Stream& s, const boost::shared_ptr& auxpow, int nType,
+ int nVersion, CSerActionSerialize ser_action);
+
+template
+int ReadWriteAuxPow(Stream& s, boost::shared_ptr& auxpow, int nType,
+ int nVersion, CSerActionUnserialize ser_action);
+
+template
+int ReadWriteAuxPow(Stream& s, const boost::shared_ptr& auxpow, int nType,
+ int nVersion, CSerActionGetSerializeSize ser_action);
+
+enum {
+ // primary version
+ BLOCK_VERSION_DEFAULT = (1 << 0),
+
+ // modifiers
+ BLOCK_VERSION_AUXPOW = (1 << 8),
+ // bits allocated for chain ID
+ BLOCK_VERSION_CHAIN_START = (1 << 16),
+ BLOCK_VERSION_CHAIN_END = (1 << 30),
+};
/** Nodes collect new transactions into a block, hash them into a hash tree,
@@ -866,6 +926,9 @@ class CBlock
// network and disk
std::vector vtx;
+ // header
+ boost::shared_ptr auxpow;
+
// ppcoin: block signature - signed by one of the coin base txout[N]'s owner
std::vector vchBlockSig;
@@ -891,8 +954,10 @@ class CBlock
READWRITE(nBits);
READWRITE(nNonce);
+ nSerSize += ReadWriteAuxPow(s, auxpow, nType, nVersion, ser_action);
+
// ConnectBlock depends on vtx following header to generate CDiskTxPos
- if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))
+ if(!(nType & (SER_BLOCKHEADERONLY)))
{
READWRITE(vtx);
READWRITE(vchBlockSig);
@@ -916,6 +981,7 @@ class CBlock
vchBlockSig.clear();
vMerkleTree.clear();
nDoS = 0;
+ auxpow.reset();
}
bool IsNull() const
@@ -923,7 +989,37 @@ class CBlock
return (nBits == 0);
}
- uint256 GetHash() const;
+ int GetChainID() const {
+ return(nVersion / BLOCK_VERSION_CHAIN_START);
+ }
+
+ void SetAuxPow(CAuxPow* pow);
+
+ /* Extracts block height from v2+ coin base;
+ * ignores nVersion because it's unreliable */
+ int GetBlockHeight() const {
+ /* Prevents a crash if called on a block header alone */
+ if(vtx.size()) {
+ /* Serialised CScript */
+ std::vector::const_iterator scriptsig = vtx[0].vin[0].scriptSig.begin();
+ unsigned char i, scount = scriptsig[0];
+ /* Optimise: nTime is 4 bytes always,
+ * nHeight must be less for a long time;
+ * check against a threshold when the time comes */
+ if(scount < 4) {
+ int height = 0;
+ unsigned char *pheight = (unsigned char *) &height;
+ for(i = 0; i < scount; i++)
+ pheight[i] = scriptsig[i + 1];
+ /* v2+ block with nHeight in coin base */
+ return(height);
+ }
+ }
+ /* Not found */
+ return(-1);
+ }
+
+ uint256 GetHash(bool existingBlock=false, int64 coins=totalCoin) const;
uint256 GetHashScrypt() const
{
@@ -984,8 +1080,7 @@ class CBlock
return maxTransactionTime;
}
- uint256 BuildMerkleTree() const
- {
+ uint256 BuildMerkleTree() const {
vMerkleTree.clear();
BOOST_FOREACH(const CTransaction& tx, vtx)
vMerkleTree.push_back(tx.GetHash());
@@ -995,8 +1090,8 @@ class CBlock
for (int i = 0; i < nSize; i += 2)
{
int i2 = std::min(i+1, nSize-1);
- vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
- BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
+ vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
+ BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
}
j += nSize;
}
@@ -1019,16 +1114,16 @@ class CBlock
return vMerkleBranch;
}
- static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex)
- {
+ static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch,
+ int nIndex) {
if (nIndex == -1)
return 0;
BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
{
- if (nIndex & 1)
- hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
+ if(nIndex & 1)
+ hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
else
- hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
+ hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
nIndex >>= 1;
}
return hash;
@@ -1080,15 +1175,10 @@ class CBlock
return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
}
- totalCoinDB = 1;
- uint256 hash1 = GetHashScrypt();
- totalCoinDB = coinMax;
- uint256 hash2 = GetHashGroestl();
// Check the header
- if (fReadTransactions && IsProofOfWork() && !CheckProofOfWork(hash1, nBits) && !CheckProofOfWork(hash2, nBits))
- {
- return error("CBlock::ReadFromDisk() : errors in block header");
- }
+// if (fReadTransactions && IsProofOfWork() && !CheckProofOfWork(GetHashScrypt(), nBits) && !CheckProofOfWork(GetHashGroestl(), nBits))
+// return error("CBlock::ReadFromDisk() : errors in block header");
+
return true;
}
@@ -1120,11 +1210,12 @@ class CBlock
bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew);
bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
- bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true) const;
+ bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true, int64 totalCoin=0) const;
bool AcceptBlock();
bool GetCoinAge(uint64& nCoinAge) const; // ppcoin: calculate total coin age spent in block
bool SignBlock(const CKeyStore& keystore);
- bool CheckBlockSignature() const;
+ bool CheckBlockSignature(int nHeight) const;
+ bool CheckProofOfWork(int64 totalCoin) const;
private:
bool SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew);
@@ -1157,7 +1248,7 @@ class CBlockIndex
int64 nMoneySupply;
unsigned int nFlags; // ppcoin: block index flags
- enum
+ enum
{
BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block
BLOCK_STAKE_ENTROPY = (1 << 1), // entropy bit for stake modifier
@@ -1179,6 +1270,9 @@ class CBlockIndex
unsigned int nBits;
unsigned int nNonce;
+ // if this is an aux work block
+ boost::shared_ptr auxpow;
+
CBlockIndex()
{
phashBlock = NULL;
@@ -1202,6 +1296,7 @@ class CBlockIndex
nTime = 0;
nBits = 0;
nNonce = 0;
+ auxpow.reset();
}
CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block)
@@ -1236,6 +1331,7 @@ class CBlockIndex
nTime = block.nTime;
nBits = block.nBits;
nNonce = block.nNonce;
+ auxpow = block.auxpow;
}
CBlock GetBlockHeader() const
@@ -1248,6 +1344,7 @@ class CBlockIndex
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
+ block.auxpow = auxpow;
return block;
}
@@ -1355,11 +1452,11 @@ class CBlockIndex
pprev, pnext, nFile, nBlockPos, nHeight,
FormatMoney(nMint).c_str(), FormatMoney(nMoneySupply).c_str(),
GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW",
- nStakeModifier, nStakeModifierChecksum,
+ nStakeModifier, nStakeModifierChecksum,
hashProofOfStake.ToString().c_str(),
prevoutStake.ToString().c_str(), nStakeTime,
hashMerkleRoot.ToString().c_str(),
- GetBlockHash().ToString().c_str());
+ phashBlock ? GetBlockHash().ToString().c_str() : "*not initialized*");
}
void print() const
@@ -1373,12 +1470,16 @@ class CBlockIndex
/** Used to marshal pointers into hashes for db storage. */
class CDiskBlockIndex : public CBlockIndex
{
+private:
+ uint256 blockHash;
+
public:
uint256 hashPrev;
uint256 hashNext;
CDiskBlockIndex()
{
+ blockHash = 0;
hashPrev = 0;
hashNext = 0;
}
@@ -1422,34 +1523,15 @@ class CDiskBlockIndex : public CBlockIndex
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
+ READWRITE(blockHash);
+ ReadWriteAuxPow(s, auxpow, nType, this->nVersion, ser_action);
)
uint256 GetBlockHash() const
{
- CBlock block;
- block.nVersion = nVersion;
- block.hashPrevBlock = hashPrev;
- block.hashMerkleRoot = hashMerkleRoot;
- block.nTime = nTime;
- block.nBits = nBits;
- block.nNonce = nNonce;
- return block.GetHash();
- }
-
- uint256 GetBlockHashScrypt() const
- {
- CBlock block;
- block.nVersion = nVersion;
- block.hashPrevBlock = hashPrev;
- block.hashMerkleRoot = hashMerkleRoot;
- block.nTime = nTime;
- block.nBits = nBits;
- block.nNonce = nNonce;
- return block.GetHashScrypt();
- }
+ if (fUseFastIndex && (nTime < GetAdjustedTime() - 24 * 60 * 60) && blockHash != 0)
+ return blockHash;
- uint256 GetBlockHashGroest() const
- {
CBlock block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
@@ -1457,7 +1539,8 @@ class CDiskBlockIndex : public CBlockIndex
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
- return block.GetHashGroestl();
+ const_cast(this)->blockHash = block.GetHash();
+ return blockHash;
}
std::string ToString() const
diff --git a/src/makefile.bsd b/src/makefile.bsd
index 10a6e66..7b5fcbf 100644
--- a/src/makefile.bsd
+++ b/src/makefile.bsd
@@ -2,8 +2,15 @@
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-USE_UPNP:=0
-USE_IPV6:=1
+USE_UPNP:=-
+USE_IPV6:=-
+BOOST_INCLUDE_PATH=/usr/local/include
+BDB_INCLUDE_PATH=/usr/local/include/db48
+BOOST_LIB_PATH=/usr/local/lib
+BDB_LIB_PATH=/usr/local/lib/db48
+STATIC=1
+CC=clang
+CXX=clang++
LINK:=$(CXX)
@@ -35,7 +42,7 @@ LIBS += \
-l db_cxx$(BDB_LIB_SUFFIX) \
-l ssl \
-l crypto \
- -l execinfo
+ -l execinfo -l elf
ifndef USE_UPNP
override USE_UPNP = -
@@ -52,7 +59,7 @@ endif
LIBS+= \
-Wl,-B$(LMODE2) \
-l z \
- -l dl \
+# -l dl \
-l pthread
@@ -94,7 +101,7 @@ DEBUGFLAGS=-g
# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only
# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work.
-xCXXFLAGS=-O0 -msse2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
+xCXXFLAGS=-O2 -msse2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
$(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
# LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only
@@ -102,6 +109,8 @@ xCXXFLAGS=-O0 -msse2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unus
xLDFLAGS=$(LDHARDENING) $(LDFLAGS)
OBJS= \
+ obj/hash.o \
+ obj/groestl.o \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -133,13 +142,15 @@ OBJS= \
obj/pbkdf2.o \
obj/scrypt_mine.o \
obj/scrypt-x86.o \
- obj/scrypt-x86_64.o
-
+ obj/scrypt-x86_64.o \
+ obj/auxpow.o \
+ obj/reactors.o \
+ obj/reactorlist.o
all: diamondd
test check: test_diamond FORCE
- ./test_BottleCaps
+ ./test_diamond
# auto-generated dependencies:
-include obj/*.P
@@ -163,6 +174,14 @@ obj/%.o: %.cpp
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
+obj/%.o: %.c
+ $(CC) -c $(xCXXFLAGS) -fpermissive -MMD -MF $(@:%.o=%.d) -o $@ $<
+ @cp $(@:%.o=%.d) $(@:%.o=%.P); \
+ sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+ -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
+ rm -f $(@:%.o=%.d)
+
+
diamondd: $(OBJS:obj/%=obj/%)
$(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS)
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 5f65ab2..34c4be4 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -87,7 +87,10 @@ OBJS= \
obj/pbkdf2.o \
obj/scrypt_mine.o \
obj/scrypt-x86.o \
- obj/scrypt-x86_64.o
+ obj/scrypt-x86_64.o \
+ obj/auxpow.o \
+ obj/reactors.o \
+ obj/reactorlist.o
all: diamondd.exe
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 3ac9843..34f7061 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -6,20 +6,20 @@ USE_UPNP:=0
USE_IPV6:=1
INCLUDEPATHS= \
- -I"C:\boost_1_53_0" \
- -I"C:\db-4.8.30.NC\build_unix" \
- -I"C:\openssl-1.0.1e\include
-
+ -I"C:\deps\boost_1_55_0" \
+ -I"C:\deps\db-4.8.30.NC\build_unix" \
+ -I"C:\deps\openssl-1.0.1e\include
+
LIBPATHS= \
- -L"C:\boost_1_53_0\stage/lib" \
- -L"C:\db-4.8.30.NC\build_unix" \
- -L"C:\openssl-1.0.1e"
+ -L"C:\deps\boost_1_55_0\stage/lib" \
+ -L"C:\deps\db-4.8.30.NC\build_unix" \
+ -L"C:\deps\openssl-1.0.1e"
LIBS= \
- -l boost_system-mgw45-mt-d-1_53 \
- -l boost_filesystem-mgw45-mt-d-1_53 \
- -l boost_program_options-mgw45-mt-d-1_53 \
- -l boost_thread-mgw45-mt-d-1_53 \
+ -l boost_system-mgw45-mt-d-1_55 \
+ -l boost_filesystem-mgw45-mt-d-1_55 \
+ -l boost_program_options-mgw45-mt-d-1_55 \
+ -l boost_thread-mgw45-mt-d-1_55 \
-l db_cxx \
-l ssl \
-l crypto
@@ -27,7 +27,8 @@ LIBS= \
DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -D__NO_SYSTEM_INCLUDES
DEBUGFLAGS=-g
CFLAGS=-mthreads -O2 -msse2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
-LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat
+LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat -Wl,--large-address-aware -static
+
TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
@@ -35,8 +36,8 @@ ifndef USE_UPNP
override USE_UPNP = -
endif
ifneq (${USE_UPNP}, -)
- INCLUDEPATHS += -I"C:\miniupnpc-1.6-mgw"
- LIBPATHS += -L"C:\miniupnpc-1.6-mgw"
+ INCLUDEPATHS += -I"C:\deps\miniupnpc-1.6-mgw"
+ LIBPATHS += -L"C:\deps\miniupnpc-1.6-mgw"
LIBS += -l miniupnpc -l iphlpapi
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
@@ -82,7 +83,10 @@ OBJS= \
obj/pbkdf2.o \
obj/scrypt_mine.o \
obj/scrypt-x86.o \
- obj/scrypt-x86_64.o
+ obj/scrypt-x86_64.o \
+ obj/auxpow.o \
+ obj/reactors.o \
+ obj/reactorlist.o
all: diamondd.exe
diff --git a/src/makefile.osx b/src/makefile.osx
index 7e66fec..a08de85 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -6,7 +6,7 @@
# Mac OS X makefile for bitcoin
# Originally by Laszlo Hanyecz (solar@heliacal.net)
-CXX=llvm-g++
+CXX=clang++
DEPSDIR=/opt/local
INCLUDEPATHS= \
@@ -59,14 +59,15 @@ DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DBOOST_SPIRIT_THREADSAFE
ifdef RELEASE
# Compile for maximum compatibility and smallest size.
# This requires that dependencies are compiled
-# the same way.
-CFLAGS = -mmacosx-version-min=10.5 -arch x86_64 -O3 -msse2
+# the same way. Use this if you build on pre-Mavericks system
+#xCXXFLAGS = -mmacosx-version-min=10.5 -arch x86_64 -O3 -msse2
+xCXXFLAGS = -O3 -msse2
else
-CFLAGS = -g -msse2
+xCXXFLAGS = -g -msse2
endif
# ppc doesn't work because we don't support big-endian
-CFLAGS += -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
+xCXXFLAGS += -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
$(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
OBJS= \
@@ -98,10 +99,15 @@ OBJS= \
obj/walletdb.o \
obj/noui.o \
obj/pbkdf2.o \
+ obj/hash.o \
+ obj/groestl.o \
obj/kernel.o \
obj/scrypt_mine.o \
obj/scrypt-x86.o \
- obj/scrypt-x86_64.o
+ obj/scrypt-x86_64.o \
+ obj/auxpow.o \
+ obj/reactors.o \
+ obj/reactorlist.o
ifndef USE_UPNP
override USE_UPNP = -
@@ -134,12 +140,20 @@ version.cpp: obj/build.h
DEFS += -DHAVE_BUILD_INFO
obj/%.o: %.cpp
- $(CXX) -c $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
+ $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
+obj/%.o: %.c
+ $(CC) -c $(xCXXFLAGS) -fpermissive -MMD -MF $(@:%.o=%.d) -o $@ $<
+ @cp $(@:%.o=%.d) $(@:%.o=%.P); \
+ sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+ -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
+ rm -f $(@:%.o=%.d)
+
+
obj/scrypt-x86.o: scrypt-x86.S
$(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
@@ -147,19 +161,19 @@ obj/scrypt-x86_64.o: scrypt-x86_64.S
$(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
diamondd: $(OBJS:obj/%=obj/%)
- $(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
+ $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp
- $(CXX) -c $(TESTDEFS) $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
+ $(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
test_diamond: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- $(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) $(TESTLIBS)
+ $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) $(TESTLIBS)
clean:
-rm -f diamondd test_diamond
diff --git a/src/makefile.unix b/src/makefile.unix
index 6d878e0..dd2369a 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -94,9 +94,19 @@ DEBUGFLAGS=-g
# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only
# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work.
-xCXXFLAGS=-O2 -msse2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
+xCXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
$(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
+# If we have an ARM device, we can't use SSE2 instructions, so don't try to use them
+# xCPUARCH is passed in as a define (xCPUARCH=armv7l, xCPUARCH=armv6l)
+ifeq ($(xCPUARCH),armv7l)
+ xCXXFLAGS+= -DNOSSE
+else ifeq ($(xCPUARCH),armv6l)
+ xCXXFLAGS+= -DNOSSE
+else
+ xCXXFLAGS+=-msse2
+endif
+
# LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only
# adds some defaults in front. Unfortunately, LDFLAGS=... $(LDFLAGS) does not work.
xLDFLAGS=$(LDHARDENING) $(LDFLAGS)
@@ -135,8 +145,11 @@ OBJS= \
obj/pbkdf2.o \
obj/scrypt_mine.o \
obj/scrypt-x86.o \
- obj/scrypt-x86_64.o
-
+ obj/scrypt-x86_64.o \
+ obj/scrypt-arm.o \
+ obj/auxpow.o \
+ obj/reactors.o \
+ obj/reactorlist.o
all: diamondd
@@ -158,6 +171,9 @@ obj/scrypt-x86.o: scrypt-x86.S
obj/scrypt-x86_64.o: scrypt-x86_64.S
$(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
+obj/scrypt-arm.o: scrypt-arm.S
+ $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
+
obj/%.o: %.cpp
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
diff --git a/src/net.cpp b/src/net.cpp
index 03ec7ef..9e263af 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -25,7 +25,7 @@
using namespace std;
using namespace boost;
-static const int MAX_OUTBOUND_CONNECTIONS = 12;
+static const int MAX_OUTBOUND_CONNECTIONS = 16;
void ThreadMessageHandler2(void* parg);
void ThreadSocketHandler2(void* parg);
@@ -57,7 +57,7 @@ static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
CAddress addrSeenByPeer(CService("0.0.0.0", 0), nLocalServices);
uint64 nLocalHostNonce = 0;
-array vnThreadsRunning;
+boost::array vnThreadsRunning;
static std::vector vhListenSocket;
CAddrMan addrman;
@@ -174,14 +174,16 @@ bool RecvLine(SOCKET hSocket, string& strLine)
if (nBytes == 0)
{
// socket closed
- printf("socket closed\n");
+ if (fDebugNet)
+ printf("socket closed\n");
return false;
}
else
{
// socket error
int nErr = WSAGetLastError();
- printf("recv failed: %d\n", nErr);
+ if (fDebugNet)
+ printf("recv failed: %d\n", nErr);
return false;
}
}
@@ -485,9 +487,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout)
/// debug print
- printf("trying connection %s lastseen=%.1fhrs\n",
- pszDest ? pszDest : addrConnect.ToString().c_str(),
- pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
+ if (fDebugNet)
+ printf("trying connection %s lastseen=%.1fhrs\n",
+ pszDest ? pszDest : addrConnect.ToString().c_str(),
+ pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
// Connect
SOCKET hSocket;
@@ -496,7 +499,8 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout)
addrman.Attempt(addrConnect);
/// debug print
- printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str());
+ if (fDebugNet)
+ printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str());
// Set to non-blocking
#ifdef WIN32
@@ -534,7 +538,8 @@ void CNode::CloseSocketDisconnect()
fDisconnect = true;
if (hSocket != INVALID_SOCKET)
{
- printf("disconnecting node %s\n", addrName.c_str());
+ if (fDebugNet)
+ printf("disconnecting node %s\n", addrName.c_str());
closesocket(hSocket);
hSocket = INVALID_SOCKET;
vRecv.clear();
@@ -558,10 +563,6 @@ void CNode::PushVersion()
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), nBestHeight);
}
-
-
-
-
std::map CNode::setBanned;
CCriticalSection CNode::cs_setBanned;
@@ -570,22 +571,39 @@ void CNode::ClearBanned()
setBanned.clear();
}
-bool CNode::IsBanned(CNetAddr ip)
+// return how many seconds left, if banned
+int64 CNode::IsBanned(CNetAddr ip)
{
- bool fResult = false;
{
LOCK(cs_setBanned);
std::map::iterator i = setBanned.find(ip);
if (i != setBanned.end())
{
int64 t = (*i).second;
- if (GetTime() < t)
- fResult = true;
+ int64 left = t - GetTime();
+ if (left < 0)
+ left=0;
+ return left;
}
}
- return fResult;
+ return 0;
}
+bool CNode::ConnectAllowed(CNetAddr ip)
+{
+ const string strAddress = ip.ToString();
+ const vector& vAllow = mapMultiArgs["-connectallowip"];
+ // no ACL specified, everyone plays
+ if (vAllow.empty())
+ return true;
+ BOOST_FOREACH(string strAllow, vAllow)
+ if (WildcardMatch(strAddress, strAllow))
+ return true;
+ return false;
+}
+
+extern CMedianFilter cPeerBlockCounts;
+
bool CNode::Misbehaving(int howmuch)
{
if (addr.IsLocal())
@@ -605,6 +623,9 @@ bool CNode::Misbehaving(int howmuch)
setBanned[addr] = banTime;
}
CloseSocketDisconnect();
+
+ cPeerBlockCounts.removeLast(nStartingHeight); // remove this node's reported number of blocks
+
return true;
} else
printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
@@ -787,7 +808,8 @@ void ThreadSocketHandler2(void* parg)
if (have_fds)
{
int nErr = WSAGetLastError();
- printf("socket select error %d\n", nErr);
+ if (fDebugNet)
+ printf("socket select error %d\n", nErr);
for (unsigned int i = 0; i <= hSocketMax; i++)
FD_SET(i, &fdsetRecv);
}
@@ -812,6 +834,7 @@ void ThreadSocketHandler2(void* parg)
SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
+ int bsec = 0; // how many seconds left in a ban
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
@@ -838,9 +861,14 @@ void ThreadSocketHandler2(void* parg)
closesocket(hSocket);
}
}
- else if (CNode::IsBanned(addr))
+ else if (!CNode::ConnectAllowed(addr))
+ {
+ printf("connection from %s dropped (forbidden)\n", addr.ToString().c_str());
+ closesocket(hSocket);
+ }
+ else if ((bsec = CNode::IsBanned(addr)))
{
- printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
+ printf("connection from %s dropped (banned %d sec)\n", addr.ToString().c_str(), bsec);
closesocket(hSocket);
}
else
@@ -1031,10 +1059,14 @@ void ThreadMapPort2(void* parg)
#ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
-#else
+#elif MINIUPNPC_API_VERSION < 14
/* miniupnpc 1.6 */
int error = 0;
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
+#else
+ /* miniupnpc 1.9 */
+ int error = 0;
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
#endif
struct UPNPUrls urls;
@@ -1149,6 +1181,8 @@ void MapPort()
// The first name is used as information source for addrman.
// The second name should resolve to a list of seed addresses.
static const char *strDNSSeed[][2] = {
+ {"seed.bit.diamonds", "seed.bit.diamonds"},
+ {"dmdseed.danbo.bg", "dmdseed.danbo.bg"},
{"", ""},
};
@@ -1195,6 +1229,7 @@ void ThreadDNSAddressSeed2(void* parg)
int nOneDay = 24*3600;
CAddress addr = CAddress(CService(ip, GetDefaultPort()));
addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
+ SetReachable(addr.GetNetwork());
vAdd.push_back(addr);
found++;
}
@@ -1220,6 +1255,7 @@ void ThreadDNSAddressSeed2(void* parg)
unsigned int pnSeed[] =
{
+ 0x131544c1
};
void DumpAddresses()
@@ -1380,6 +1416,7 @@ void ThreadOpenConnections2(void* parg)
memcpy(&ip, &pnSeed[i], sizeof(ip));
CAddress addr(CService(ip, GetDefaultPort()));
addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
+ SetReachable(addr.GetNetwork());
vAdd.push_back(addr);
}
addrman.Add(vAdd, CNetAddr("127.0.0.1"));
@@ -1845,18 +1882,12 @@ void StartNode(void* parg)
// Start threads
//
-
if (!GetBoolArg("-dnsseed", true))
printf("DNS seeding disabled\n");
else
if (!NewThread(ThreadDNSAddressSeed, NULL))
printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
- if (!GetBoolArg("-dnsseed", false))
- printf("DNS seeding disabled\n");
- if (GetBoolArg("-dnsseed", false))
- printf("DNS seeding NYI\n");
-
// Map ports with UPnP
if (fUseUPnP)
MapPort();
diff --git a/src/net.h b/src/net.h
index 16cd95f..e8cdc7c 100644
--- a/src/net.h
+++ b/src/net.h
@@ -26,8 +26,8 @@ extern int nBestHeight;
-inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
-inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
+inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
+inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
void AddOneShot(std::string strDest);
bool RecvLine(SOCKET hSocket, std::string& strLine);
@@ -637,7 +637,8 @@ class CNode
// between nodes running old code and nodes running
// new code.
static void ClearBanned(); // needed for unit testing
- static bool IsBanned(CNetAddr ip);
+ static int64 IsBanned(CNetAddr ip);
+ static bool ConnectAllowed(CNetAddr ip);
bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
void copyStats(CNodeStats &stats);
};
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 95d6493..06ab06d 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -368,13 +368,15 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
if (nRet == 0)
{
- printf("connection timeout\n");
+ if (fDebugNet)
+ printf("connection timeout\n");
closesocket(hSocket);
return false;
}
if (nRet == SOCKET_ERROR)
{
- printf("select() for connection failed: %i\n",WSAGetLastError());
+ if (fDebugNet)
+ printf("select() for connection failed: %i\n",WSAGetLastError());
closesocket(hSocket);
return false;
}
@@ -385,13 +387,15 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
#endif
{
- printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
+ if (fDebugNet)
+ printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
closesocket(hSocket);
return false;
}
if (nRet != 0)
{
- printf("connect() failed after select(): %s\n",strerror(nRet));
+ if (fDebugNet)
+ printf("connect() failed after select(): %s\n",strerror(nRet));
closesocket(hSocket);
return false;
}
@@ -402,7 +406,8 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
else
#endif
{
- printf("connect() failed: %i\n",WSAGetLastError());
+ if (fDebugNet)
+ printf("connect() failed: %i\n",WSAGetLastError());
closesocket(hSocket);
return false;
}
diff --git a/src/obj-test/.gitignore b/src/obj-test/.gitignore
index d6b7ef3..dd3727e 100644
--- a/src/obj-test/.gitignore
+++ b/src/obj-test/.gitignore
@@ -1,2 +1,3 @@
+#Ignore all files except the .gitignore
*
!.gitignore
diff --git a/src/obj/.gitignore b/src/obj/.gitignore
new file mode 100644
index 0000000..dd3727e
--- /dev/null
+++ b/src/obj/.gitignore
@@ -0,0 +1,3 @@
+#Ignore all files except the .gitignore
+*
+!.gitignore
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index ce96743..f4ab713 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -121,14 +121,26 @@ void AddressBookPage::setModel(AddressTableModel *model)
// Receive filter
proxyModel->setFilterRole(AddressTableModel::TypeRole);
proxyModel->setFilterFixedString(AddressTableModel::Receive);
+
+ // Set this slightly earlier so that we can adjust our columns by tab.
+ ui->tableView->setModel(proxyModel);
+ // Only display the scrape address for receiving tab (cheap hack).
+ ui->tableView->horizontalHeader()->resizeSection(
+ AddressTableModel::ScrapeAddress, 320);
break;
case SendingTab:
// Send filter
proxyModel->setFilterRole(AddressTableModel::TypeRole);
proxyModel->setFilterFixedString(AddressTableModel::Send);
+
+ // Set this slightly earlier so that we can adjust our columns by tab.
+ ui->tableView->setModel(proxyModel);
+ // Do not display the scrape address for the send tab (cheap hack).
+ ui->tableView->horizontalHeader()->resizeSection(
+ AddressTableModel::ScrapeAddress, 0);
+
break;
}
- ui->tableView->setModel(proxyModel);
ui->tableView->sortByColumn(0, Qt::AscendingOrder);
// Set column widths
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index e65d391..64de9fb 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -21,8 +21,11 @@ struct AddressTableEntry
Type type;
QString label;
QString address;
+ QString scrape_address;
AddressTableEntry() {}
+ AddressTableEntry(Type type, const QString &label, const QString &address, const QString &scrape_address):
+ type(type), label(label), address(address), scrape_address(scrape_address) {}
AddressTableEntry(Type type, const QString &label, const QString &address):
type(type), label(label), address(address) {}
};
@@ -64,9 +67,21 @@ class AddressTablePriv
const CBitcoinAddress& address = item.first;
const std::string& strName = item.second;
bool fMine = IsMine(*wallet, address.Get());
- cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending,
- QString::fromStdString(strName),
- QString::fromStdString(address.ToString())));
+
+ if (fMine) {
+ std::string addr;
+ if (wallet->HasScrapeAddress(address.ToString()))
+ wallet->ReadScrapeAddress(address.ToString(), addr);
+
+ cachedAddressTable.append(AddressTableEntry(AddressTableEntry::Receiving,
+ QString::fromStdString(strName),
+ QString::fromStdString(address.ToString()),
+ QString::fromStdString(addr)));
+ } else {
+ cachedAddressTable.append(AddressTableEntry(AddressTableEntry::Sending,
+ QString::fromStdString(strName),
+ QString::fromStdString(address.ToString())));
+ }
}
}
}
@@ -81,6 +96,7 @@ class AddressTablePriv
int lowerIndex = (lower - cachedAddressTable.begin());
int upperIndex = (upper - cachedAddressTable.begin());
bool inModel = (lower != upper);
+
AddressTableEntry::Type newEntryType = isMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending;
switch(status)
@@ -139,7 +155,7 @@ class AddressTablePriv
AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) :
QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0)
{
- columns << tr("Label") << tr("Address");
+ columns << tr("Label") << tr("Address") << tr("Scrape Address");
priv = new AddressTablePriv(wallet, this);
priv->refreshAddressTable();
}
@@ -183,6 +199,17 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const
}
case Address:
return rec->address;
+
+ case ScrapeAddress:
+ // No scrape address for sending tab.
+ if (rec->type == AddressTableEntry::Sending)
+ break;
+
+ if (rec->scrape_address.isEmpty() && role == Qt::DisplayRole) {
+ return tr("(no scrape address)");
+ } else {
+ return rec->scrape_address;
+ }
}
}
else if (role == Qt::FontRole)
@@ -243,6 +270,35 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
}
}
break;
+ case ScrapeAddress:
+ // No scrape address for sending tab.
+ if (rec->type == AddressTableEntry::Sending)
+ break;
+
+ /* If passing an empty string delete the current scrape address if
+ * one exists. */
+ if (value.toString().toStdString().empty()) {
+ if (wallet->HasScrapeAddress(rec->address.toStdString()))
+ if (!wallet->EraseScrapeAddress(rec->address.toStdString()))
+ return false;
+ } else {
+ // Confirm the scrape address is a valid address before setting it
+ if (!walletModel->validateAddress(value.toString())) {
+ editStatus = INVALID_ADDRESS;
+ return false;
+ }
+
+ /* Confirm we are not setting the scrape address to the same
+ * address as the staking address. */
+ if (rec->address == value.toString())
+ return false;
+
+ if (!wallet->WriteScrapeAddress(rec->address.toStdString(), value.toString().toStdString()))
+ return false;
+ }
+
+ rec->scrape_address = value.toString();
+ break;
}
return true;
@@ -270,9 +326,10 @@ Qt::ItemFlags AddressTableModel::flags(const QModelIndex & index) const
Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
// Can edit address and label for sending addresses,
- // and only label for receiving addresses.
+ // label and scrapeadddress for receiving addresses.
if(rec->type == AddressTableEntry::Sending ||
- (rec->type == AddressTableEntry::Receiving && index.column()==Label))
+ (rec->type == AddressTableEntry::Receiving && index.column()==Label) ||
+ (rec->type == AddressTableEntry::Receiving && index.column()==ScrapeAddress))
{
retval |= Qt::ItemIsEditable;
}
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 42974e3..0803ffe 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -20,7 +20,8 @@ class AddressTableModel : public QAbstractTableModel
enum ColumnIndex {
Label = 0, /**< User specified label */
- Address = 1 /**< Bitcoin address */
+ Address = 1, /**< Bitcoin address */
+ ScrapeAddress = 2 /**< Diamond scrape address (receiving tab only) */
};
enum RoleIndex {
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 5ad1e78..def9959 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -4,6 +4,8 @@
#include "guiconstants.h"
#include "walletmodel.h"
+#include "util.h"
+
#include
#include
#include
@@ -33,6 +35,10 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of 10 or more random characters, or eight or more words."));
setWindowTitle(tr("Encrypt wallet"));
break;
+ case(UnlockStaking):
+ ui->mintingCheckBox->setChecked(true);
+ ui->mintingCheckBox->show();
+ // fallthru
case Unlock: // Ask passphrase
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
ui->passLabel2->hide();
@@ -138,6 +144,7 @@ void AskPassphraseDialog::accept()
QDialog::reject(); // Cancelled
}
} break;
+ case(UnlockStaking):
case Unlock:
if(!model->setWalletLocked(false, oldpass))
{
@@ -146,6 +153,7 @@ void AskPassphraseDialog::accept()
}
else
{
+ fStakingOnly = ui->mintingCheckBox->isChecked();
QDialog::accept(); // Success
}
break;
@@ -193,6 +201,7 @@ void AskPassphraseDialog::textChanged()
case Encrypt: // New passphrase x2
acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
break;
+ case(UnlockStaking):
case Unlock: // Old passphrase x1
case Decrypt:
acceptable = !ui->passEdit1->text().isEmpty();
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index b500ff4..0ddb24f 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -19,6 +19,7 @@ class AskPassphraseDialog : public QDialog
enum Mode {
Encrypt, /**< Ask passphrase twice and encrypt */
Unlock, /**< Ask passphrase and unlock */
+ UnlockStaking, /* Ask passphrase and unlock for staking only */
ChangePass, /**< Ask old passphrase + new passphrase twice */
Decrypt /**< Ask passphrase and decrypt wallet */
};
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index d9e11c5..c7c2dcd 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -22,7 +22,7 @@
res/icons/editpaste.png
res/icons/editcopy.png
res/icons/add.png
- res/icons/Diamond-128.png
+ res/icons/Diamond-128.png
res/icons/Diamond-16.png
res/icons/edit.png
res/icons/history.png
@@ -31,11 +31,13 @@
res/icons/synced.png
res/icons/remove.png
res/icons/tx_mined.png
+ res/icons/tx_minted.png
res/icons/tx_input.png
res/icons/tx_output.png
res/icons/tx_inout.png
res/icons/lock_closed.png
res/icons/lock_open.png
+ res/icons/minting.png
res/icons/key.png
res/icons/filesave.png
res/icons/qrcode.png
@@ -45,7 +47,7 @@
res/images/about.png
res/images/diamond-splash.jpg
res/images/background.png
- res/images/wallet.png
+ res/images/diamond.png
res/movies/update_spinner.mng
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 2a78694..2c5651b 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -25,6 +25,8 @@
#include "notificator.h"
#include "guiutil.h"
#include "rpcconsole.h"
+#include "wallet.h"
+#include "version.h"
#ifdef Q_OS_MAC
#include "macdockiconhandler.h"
@@ -63,20 +65,25 @@
#include
+extern CWallet *pwalletMain;
+extern int64 nLastCoinStakeSearchInterval;
+extern unsigned int nStakeTargetSpacing;
+
BitcoinGUI::BitcoinGUI(QWidget *parent):
QMainWindow(parent),
clientModel(0),
walletModel(0),
encryptWalletAction(0),
changePassphraseAction(0),
+ lockWalletToggleAction(0),
aboutQtAction(0),
trayIcon(0),
notificator(0),
rpcConsole(0)
{
resize(850, 550);
- setWindowTitle(tr("Diamond") + " - " + tr("Wallet"));
- setStyleSheet("QMainWindow{border-image: url(:/images/main_backg)} QToolButton:!hover {color:white;} QToolButton:hover {background-color:rgb(59, 88, 104);color:white;} QToolTip {background-color:#1f333e; color:white;}");
+ setWindowTitle(tr("Diamond") + " - " + tr("Wallet") + " " + QString::fromStdString(CLIENT_BUILD));
+ setStyleSheet("QMainWindow{border-image: url(:/images/main_backg)} QToolButton:!hover {color:white; border-style: none;} QToolButton:hover {background-color:rgb(59, 88, 104);color:white; border-style: none;} QToolTip {background-color:#1f333e; color:white; border-style: none;}");
#ifndef Q_OS_MAC
qApp->setWindowIcon(QIcon(":icons/bitcoin"));
@@ -131,22 +138,38 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
// Status bar notification icons
QFrame *frameBlocks = new QFrame();
frameBlocks->setContentsMargins(0,0,0,0);
- frameBlocks->setMinimumWidth(56);
- frameBlocks->setMaximumWidth(56);
+ frameBlocks->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
labelEncryptionIcon = new QLabel();
+ labelMintingIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelEncryptionIcon);
frameBlocksLayout->addStretch();
+ frameBlocksLayout->addWidget(labelMintingIcon);
+ frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelConnectionsIcon);
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelBlocksIcon);
frameBlocksLayout->addStretch();
+ // Set minting pixmap
+ labelMintingIcon->setPixmap(QIcon(":/icons/minting").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelMintingIcon->setEnabled(false);
+ // Add timer to update minting icon
+ QTimer *timerMintingIcon = new QTimer(labelMintingIcon);
+ timerMintingIcon->start(MODEL_UPDATE_DELAY);
+ connect(timerMintingIcon, SIGNAL(timeout()), this, SLOT(updateMintingIcon()));
+ // Add timer to update minting weights
+ QTimer *timerMintingWeights = new QTimer(labelMintingIcon);
+ timerMintingWeights->start(30 * 1000);
+ connect(timerMintingWeights, SIGNAL(timeout()), this, SLOT(updateMintingWeights()));
+ // Set initial values for user and network weights
+ nWeight, nNetworkWeight = 0;
+
// Progress bar and label for blocks download
progressBarLabel = new QLabel();
progressBarLabel->setVisible(false);
@@ -168,7 +191,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
statusBar()->addPermanentWidget(frameBlocks);
syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this);
- // this->setStyleSheet("background-color: #effbef;");
+ // this->setStyleSheet("background-color: #effbef;");
// Clicking on a transaction on the overview page simply sends you to transaction history page
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage()));
@@ -263,6 +286,7 @@ void BitcoinGUI::createActions()
backupWalletAction->setToolTip(tr("Backup wallet to another location"));
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this);
changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
+ lockWalletToggleAction = new QAction(this);
signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this);
verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this);
@@ -279,6 +303,7 @@ void BitcoinGUI::createActions()
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
+ connect(lockWalletToggleAction, SIGNAL(triggered()), this, SLOT(lockWalletToggle()));
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
}
@@ -305,6 +330,7 @@ void BitcoinGUI::createMenuBar()
QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
settings->addAction(encryptWalletAction);
settings->addAction(changePassphraseAction);
+ settings->addAction(lockWalletToggleAction);
settings->addSeparator();
settings->addAction(optionsAction);
@@ -314,7 +340,7 @@ void BitcoinGUI::createMenuBar()
help->addAction(aboutAction);
help->addAction(aboutQtAction);
- // QString ss("QMenuBar::item { background-color: #effbef; color: black }");
+ // QString ss("QMenuBar::item { background-color: #effbef; color: black }");
// appMenuBar->setStyleSheet(ss);
}
@@ -330,6 +356,7 @@ void BitcoinGUI::createToolBars()
QToolBar *toolbar2 = addToolBar(tr("Actions toolbar"));
toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ toolbar2->addAction(lockWalletToggleAction);
toolbar2->addAction(exportAction);
}
@@ -343,10 +370,10 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
{
setWindowTitle(windowTitle() + QString(" ") + tr("[testnet]"));
#ifndef Q_OS_MAC
- qApp->setWindowIcon(QIcon(":icons/bitcoin_testnet"));
- setWindowIcon(QIcon(":icons/bitcoin_testnet"));
+ qApp->setWindowIcon(QIcon(":icons/Diamond_testnet"));
+ setWindowIcon(QIcon(":icons/Diamond_testnet"));
#else
- MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
+ MacDockIconHandler::instance()->setIcon(QIcon(":icons/Diamond_testnet"));
#endif
if(trayIcon)
{
@@ -396,7 +423,7 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel)
// Balloon pop-up for new transaction
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(incomingTransaction(QModelIndex,int,int)));
+ this, SLOT(incomingTransaction(QModelIndex,int,int)));
// Ask for passphrase if needed
connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
@@ -413,13 +440,13 @@ void BitcoinGUI::createTrayIcon()
trayIcon->setToolTip(tr("Diamond client"));
trayIcon->setIcon(QIcon(":/icons/toolbar"));
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
- this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
+ this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
trayIcon->show();
#else
// Note: On Mac, the dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
trayIconMenu = dockIconHandler->dockMenu();
- dockIconHandler->setMainWindow((QMainWindow*)this);
+ dockIconHandler->setMainWindow((QMainWindow*)this);
#endif
// Configuration of the tray icon (or dock icon) icon menu
@@ -531,7 +558,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
progressBar->setVisible(false);
}
- tooltip = tr("Current difficulty is %1.").arg(clientModel->GetDifficulty()) + QString("
") + tooltip;
+ tooltip = tr("Current difficulty is %1.").arg(clientModel->GetDifficulty()) + QString("
") + tooltip;
QDateTime lastBlockDate = clientModel->getLastBlockDate();
int secs = lastBlockDate.secsTo(QDateTime::currentDateTime());
@@ -639,12 +666,12 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
{
QString strMessage =
tr("This transaction is over the size limit. You can still send it for a fee of %1, "
- "which goes to the nodes that process your transaction and helps to support the network. "
- "Do you want to pay the fee?").arg(
- BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
+ "which goes to the nodes that process your transaction and helps to support the network. "
+ "Do you want to pay the fee?").arg(
+ BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
QMessageBox::StandardButton retval = QMessageBox::question(
- this, tr("Confirm transaction fee"), strMessage,
- QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
+ this, tr("Confirm transaction fee"), strMessage,
+ QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
*payFee = (retval == QMessageBox::Yes);
}
@@ -654,32 +681,32 @@ void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int
return;
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
- .data(Qt::EditRole).toULongLong();
+ .data(Qt::EditRole).toULongLong();
if(!clientModel->inInitialBlockDownload())
{
// On new transaction, make an info balloon
// Unless the initial block download is in progress, to prevent balloon-spam
QString date = ttm->index(start, TransactionTableModel::Date, parent)
- .data().toString();
+ .data().toString();
QString type = ttm->index(start, TransactionTableModel::Type, parent)
- .data().toString();
+ .data().toString();
QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
- .data().toString();
+ .data().toString();
QIcon icon = qvariant_cast(ttm->index(start,
- TransactionTableModel::ToAddress, parent)
- .data(Qt::DecorationRole));
+ TransactionTableModel::ToAddress, parent)
+ .data(Qt::DecorationRole));
notificator->notify(Notificator::Information,
- (amount)<0 ? tr("Sent transaction") :
- tr("Incoming transaction"),
- tr("Date: %1\n"
- "Amount: %2\n"
- "Type: %3\n"
- "Address: %4\n")
- .arg(date)
- .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true))
- .arg(type)
- .arg(address), icon);
+ (amount)<0 ? tr("Sent transaction") :
+ tr("Incoming transaction"),
+ tr("Date: %1\n"
+ "Amount: %2\n"
+ "Type: %3\n"
+ "Address: %4\n")
+ .arg(date)
+ .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true))
+ .arg(type)
+ .arg(address), icon);
}
}
@@ -797,24 +824,33 @@ void BitcoinGUI::setEncryptionStatus(int status)
case WalletModel::Unencrypted:
labelEncryptionIcon->hide();
encryptWalletAction->setChecked(false);
- changePassphraseAction->setEnabled(false);
encryptWalletAction->setEnabled(true);
+ changePassphraseAction->setEnabled(false);
+ lockWalletToggleAction->setVisible(false);
break;
case WalletModel::Unlocked:
labelEncryptionIcon->show();
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently unlocked"));
+ labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently unlocked."));
encryptWalletAction->setChecked(true);
- changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
+ changePassphraseAction->setEnabled(true);
+ lockWalletToggleAction->setVisible(true);
+ lockWalletToggleAction->setIcon(QIcon(":/icons/lock_closed"));
+ lockWalletToggleAction->setText(tr("&Lock Wallet"));
+ lockWalletToggleAction->setToolTip(tr("Lock wallet"));
break;
case WalletModel::Locked:
labelEncryptionIcon->show();
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently locked"));
+ labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently locked."));
encryptWalletAction->setChecked(true);
- changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
+ changePassphraseAction->setEnabled(true);
+ lockWalletToggleAction->setVisible(true);
+ lockWalletToggleAction->setIcon(QIcon(":/icons/lock_open"));
+ lockWalletToggleAction->setText(tr("&Unlock Wallet..."));
+ lockWalletToggleAction->setToolTip(tr("Unlock wallet"));
break;
}
}
@@ -824,7 +860,7 @@ void BitcoinGUI::encryptWallet(bool status)
if(!walletModel)
return;
AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
- AskPassphraseDialog::Decrypt, this);
+ AskPassphraseDialog::Decrypt, this);
dlg.setModel(walletModel);
dlg.exec();
@@ -857,12 +893,28 @@ void BitcoinGUI::unlockWallet()
{
if(!walletModel)
return;
+
// Unlock wallet when requested by wallet model
if(walletModel->getEncryptionStatus() == WalletModel::Locked)
{
- AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
+ AskPassphraseDialog::Mode mode = AskPassphraseDialog::Unlock;
+ AskPassphraseDialog dlg(mode, this);
+ dlg.setModel(walletModel);
+ dlg.exec();
+ }
+}
+
+void BitcoinGUI::lockWalletToggle()
+{
+ if(!walletModel)
+ return;
+
+ if(walletModel->getEncryptionStatus() == WalletModel::Locked) {
+ AskPassphraseDialog dlg(AskPassphraseDialog::UnlockStaking, this);
dlg.setModel(walletModel);
dlg.exec();
+ } else {
+ walletModel->setWalletLocked(true);
}
}
@@ -892,3 +944,51 @@ void BitcoinGUI::toggleHidden()
{
showNormalIfMinimized(true);
}
+
+void BitcoinGUI::updateMintingIcon()
+{
+ if (pwalletMain && pwalletMain->IsLocked())
+ {
+ labelMintingIcon->setToolTip(tr("Not minting because wallet is locked."));
+ labelMintingIcon->setEnabled(false);
+ }
+ else if (vNodes.empty())
+ {
+ labelMintingIcon->setToolTip(tr("Not minting because wallet is offline."));
+ labelMintingIcon->setEnabled(false);
+ }
+ else if (IsInitialBlockDownload())
+ {
+ labelMintingIcon->setToolTip(tr("Not minting because wallet is syncing."));
+ labelMintingIcon->setEnabled(false);
+ }
+ else if (!nWeight)
+ {
+ labelMintingIcon->setToolTip(tr("Not minting because you don't have mature coins."));
+ labelMintingIcon->setEnabled(false);
+ }
+ else if (nLastCoinStakeSearchInterval)
+ {
+ labelMintingIcon->setEnabled(true);
+ labelMintingIcon->setToolTip(tr("Minting.
Your weight is %1.
Network weight is %2.").arg(nWeight).arg(nNetworkWeight));
+ }
+ else
+ {
+ labelMintingIcon->setToolTip(tr("Not minting."));
+ labelMintingIcon->setEnabled(false);
+ }
+}
+
+void BitcoinGUI::updateMintingWeights()
+{
+ // Only update if we have the network's current number of blocks, or weight(s) are zero (fixes lagging GUI)
+ if ((clientModel && clientModel->getNumBlocks() == clientModel->getNumBlocksOfPeers()) || !nWeight || !nNetworkWeight)
+ {
+ nWeight = 0;
+
+ if (pwalletMain)
+ pwalletMain->GetStakeWeight(*pwalletMain, nMinMax, nMinMax, nWeight);
+
+ nNetworkWeight = GetPoSKernelPS();
+ }
+}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index c67e887..c6306f5 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -67,6 +67,7 @@ class BitcoinGUI : public QMainWindow
SignVerifyMessageDialog *signVerifyMessageDialog;
QLabel *labelEncryptionIcon;
+ QLabel *labelMintingIcon;
QLabel *labelConnectionsIcon;
QLabel *labelBlocksIcon;
QLabel *progressBarLabel;
@@ -88,6 +89,7 @@ class BitcoinGUI : public QMainWindow
QAction *encryptWalletAction;
QAction *backupWalletAction;
QAction *changePassphraseAction;
+ QAction *lockWalletToggleAction;
QAction *aboutQtAction;
QAction *openRPCConsoleAction;
@@ -98,6 +100,10 @@ class BitcoinGUI : public QMainWindow
QMovie *syncIconMovie;
+ unsigned long long nMinMax;
+ unsigned long long nWeight;
+ unsigned long long nNetworkWeight;
+
/** Create the main UI actions. */
void createActions();
/** Create the menu bar and sub-menus. */
@@ -169,11 +175,18 @@ private slots:
void changePassphrase();
/** Ask for passphrase to unlock wallet temporarily */
void unlockWallet();
+ /** Toggle unlocking wallet */
+ void lockWalletToggle();
/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */
void showNormalIfMinimized(bool fToggleHidden = false);
/** simply calls showNormalIfMinimized(true) for use in SLOT() macro */
void toggleHidden();
+
+ /** Update info about minting */
+ void updateMintingIcon();
+ /** Update minting weight info */
+ void updateMintingWeights();
};
#endif
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 469e1ee..c386c83 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -10,7 +10,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"%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=diamondrpc\n"
"rpcpassword=%s\n"
"(you do not need to remember this password)\n"
"If the file does not exist, create it with owner-readable-only file "
@@ -44,7 +44,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when the best block changes (%s in cmd is replaced by block "
"hash)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Listen for JSON-RPC connections on (default: 8344 or testnet: 18344)"),
+"Listen for JSON-RPC connections on (default: 17772 or testnet: 27772)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Number of seconds to keep misbehaving peers from reconnecting (default: "
"86400)"),
@@ -116,7 +116,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=: '%s'")
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -reservebalance="),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"),
QT_TRANSLATE_NOOP("bitcoin-core", "List commands"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on (default: 27772 or testnet: 17772)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on (default: 17771 or testnet: 27771)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
@@ -174,4 +174,4 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Diamon
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete, upgrade required!"),
QT_TRANSLATE_NOOP("bitcoin-core", "wallet.dat corrupt, salvage failed"),
-};
\ No newline at end of file
+};
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
new file mode 100644
index 0000000..b2aadeb
--- /dev/null
+++ b/src/qt/coincontroldialog.cpp
@@ -0,0 +1,742 @@
+#include "coincontroldialog.h"
+#include "ui_coincontroldialog.h"
+
+#include "init.h"
+#include "bitcoinunits.h"
+#include "walletmodel.h"
+#include "addresstablemodel.h"
+#include "optionsmodel.h"
+#include "coincontrol.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+QList CoinControlDialog::payAmounts;
+CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
+
+CoinControlDialog::CoinControlDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::CoinControlDialog),
+ model(0)
+{
+ ui->setupUi(this);
+
+ // context menu actions
+ QAction *copyAddressAction = new QAction(tr("Copy address"), this);
+ QAction *copyLabelAction = new QAction(tr("Copy label"), this);
+ QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
+ copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this
+ //lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this
+ //unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this
+
+ // context menu
+ contextMenu = new QMenu();
+ contextMenu->addAction(copyAddressAction);
+ contextMenu->addAction(copyLabelAction);
+ contextMenu->addAction(copyAmountAction);
+ contextMenu->addAction(copyTransactionHashAction);
+ //contextMenu->addSeparator();
+ //contextMenu->addAction(lockAction);
+ //contextMenu->addAction(unlockAction);
+
+ // context menu signals
+ connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
+ connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
+ connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
+ connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
+ connect(copyTransactionHashAction, SIGNAL(triggered()), this, SLOT(copyTransactionHash()));
+ //connect(lockAction, SIGNAL(triggered()), this, SLOT(lockCoin()));
+ //connect(unlockAction, SIGNAL(triggered()), this, SLOT(unlockCoin()));
+
+ // clipboard actions
+ QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
+ QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);
+ QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
+ QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
+ QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
+ QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
+ QAction *clipboardLowOutputAction = new QAction(tr("Copy low output"), this);
+ QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
+
+ connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity()));
+ connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(clipboardAmount()));
+ connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee()));
+ connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee()));
+ connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes()));
+ connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(clipboardPriority()));
+ connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput()));
+ connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange()));
+
+ ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
+ ui->labelCoinControlAmount->addAction(clipboardAmountAction);
+ ui->labelCoinControlFee->addAction(clipboardFeeAction);
+ ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
+ ui->labelCoinControlBytes->addAction(clipboardBytesAction);
+ ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
+ ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
+ ui->labelCoinControlChange->addAction(clipboardChangeAction);
+
+ // toggle tree/list mode
+ connect(ui->radioTreeMode, SIGNAL(toggled(bool)), this, SLOT(radioTreeMode(bool)));
+ connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool)));
+
+ // click on checkbox
+ connect(ui->treeWidget, SIGNAL(itemChanged( QTreeWidgetItem*, int)), this, SLOT(viewItemChanged( QTreeWidgetItem*, int)));
+
+ // click on header
+#if QT_VERSION < 0x050000
+ ui->treeWidget->header()->setClickable(true);
+#else
+ ui->treeWidget->header()->setSectionsClickable(true);
+#endif
+ connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int)));
+
+ // ok button
+ connect(ui->buttonBox, SIGNAL(clicked( QAbstractButton*)), this, SLOT(buttonBoxClicked(QAbstractButton*)));
+
+ // (un)select all
+ connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked()));
+
+ ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
+ ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100);
+ ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170);
+ ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 290);
+ ui->treeWidget->setColumnWidth(COLUMN_DATE, 110);
+ ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100);
+ ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100);
+ ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but dont show it
+ ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but dont show it
+ ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but dont show it
+ ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but dont show it
+
+ // default view is sorted by amount desc
+ sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder);
+}
+
+CoinControlDialog::~CoinControlDialog()
+{
+ delete ui;
+}
+
+void CoinControlDialog::setModel(WalletModel *model)
+{
+ this->model = model;
+
+ if(model && model->getOptionsModel() && model->getAddressTableModel())
+ {
+ updateView();
+ //updateLabelLocked();
+ CoinControlDialog::updateLabels(model, this);
+ }
+}
+
+// helper function str_pad
+QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding)
+{
+ while (s.length() < nPadLength)
+ s = sPadding + s;
+
+ return s;
+}
+
+// ok button
+void CoinControlDialog::buttonBoxClicked(QAbstractButton* button)
+{
+ if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
+ done(QDialog::Accepted); // closes the dialog
+}
+
+// (un)select all
+void CoinControlDialog::buttonSelectAllClicked()
+{
+ Qt::CheckState state = Qt::Checked;
+ for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
+ {
+ if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != Qt::Unchecked)
+ {
+ state = Qt::Unchecked;
+ break;
+ }
+ }
+ ui->treeWidget->setEnabled(false);
+ for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
+ if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != state)
+ ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state);
+ ui->treeWidget->setEnabled(true);
+ CoinControlDialog::updateLabels(model, this);
+}
+
+// context menu
+void CoinControlDialog::showMenu(const QPoint &point)
+{
+ QTreeWidgetItem *item = ui->treeWidget->itemAt(point);
+ if(item)
+ {
+ contextMenuItem = item;
+
+ // disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu
+ if (item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode)
+ {
+ copyTransactionHashAction->setEnabled(true);
+ //if (model->isLockedCoin(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()))
+ //{
+ // lockAction->setEnabled(false);
+ // unlockAction->setEnabled(true);
+ //}
+ //else
+ //{
+ // lockAction->setEnabled(true);
+ // unlockAction->setEnabled(false);
+ //}
+ }
+ else // this means click on parent node in tree mode -> disable all
+ {
+ copyTransactionHashAction->setEnabled(false);
+ //lockAction->setEnabled(false);
+ //unlockAction->setEnabled(false);
+ }
+
+ // show context menu
+ contextMenu->exec(QCursor::pos());
+ }
+}
+
+// context menu action: copy amount
+void CoinControlDialog::copyAmount()
+{
+ QApplication::clipboard()->setText(contextMenuItem->text(COLUMN_AMOUNT));
+}
+
+// context menu action: copy label
+void CoinControlDialog::copyLabel()
+{
+ if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_LABEL).length() == 0 && contextMenuItem->parent())
+ QApplication::clipboard()->setText(contextMenuItem->parent()->text(COLUMN_LABEL));
+ else
+ QApplication::clipboard()->setText(contextMenuItem->text(COLUMN_LABEL));
+}
+
+// context menu action: copy address
+void CoinControlDialog::copyAddress()
+{
+ if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_ADDRESS).length() == 0 && contextMenuItem->parent())
+ QApplication::clipboard()->setText(contextMenuItem->parent()->text(COLUMN_ADDRESS));
+ else
+ QApplication::clipboard()->setText(contextMenuItem->text(COLUMN_ADDRESS));
+}
+
+// context menu action: copy transaction id
+void CoinControlDialog::copyTransactionHash()
+{
+ QApplication::clipboard()->setText(contextMenuItem->text(COLUMN_TXHASH));
+}
+
+// context menu action: lock coin
+/*void CoinControlDialog::lockCoin()
+{
+ if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked)
+ contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
+
+ COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
+ model->lockCoin(outpt);
+ contextMenuItem->setDisabled(true);
+ contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed"));
+ updateLabelLocked();
+}*/
+
+// context menu action: unlock coin
+/*void CoinControlDialog::unlockCoin()
+{
+ COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
+ model->unlockCoin(outpt);
+ contextMenuItem->setDisabled(false);
+ contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());
+ updateLabelLocked();
+}*/
+
+// copy label "Quantity" to clipboard
+void CoinControlDialog::clipboardQuantity()
+{
+ QApplication::clipboard()->setText(ui->labelCoinControlQuantity->text());
+}
+
+// copy label "Amount" to clipboard
+void CoinControlDialog::clipboardAmount()
+{
+ QApplication::clipboard()->setText(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" ")));
+}
+
+// copy label "Fee" to clipboard
+void CoinControlDialog::clipboardFee()
+{
+ QApplication::clipboard()->setText(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")));
+}
+
+// copy label "After fee" to clipboard
+void CoinControlDialog::clipboardAfterFee()
+{
+ QApplication::clipboard()->setText(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")));
+}
+
+// copy label "Bytes" to clipboard
+void CoinControlDialog::clipboardBytes()
+{
+ QApplication::clipboard()->setText(ui->labelCoinControlBytes->text());
+}
+
+// copy label "Priority" to clipboard
+void CoinControlDialog::clipboardPriority()
+{
+ QApplication::clipboard()->setText(ui->labelCoinControlPriority->text());
+}
+
+// copy label "Low output" to clipboard
+void CoinControlDialog::clipboardLowOutput()
+{
+ QApplication::clipboard()->setText(ui->labelCoinControlLowOutput->text());
+}
+
+// copy label "Change" to clipboard
+void CoinControlDialog::clipboardChange()
+{
+ QApplication::clipboard()->setText(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")));
+}
+
+// treeview: sort
+void CoinControlDialog::sortView(int column, Qt::SortOrder order)
+{
+ sortColumn = column;
+ sortOrder = order;
+ ui->treeWidget->sortItems(column, order);
+ ui->treeWidget->header()->setSortIndicator((sortColumn == COLUMN_AMOUNT_INT64 ? COLUMN_AMOUNT : (sortColumn == COLUMN_PRIORITY_INT64 ? COLUMN_PRIORITY : sortColumn)), sortOrder);
+}
+
+// treeview: clicked on header
+void CoinControlDialog::headerSectionClicked(int logicalIndex)
+{
+ if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing
+ {
+ ui->treeWidget->header()->setSortIndicator((sortColumn == COLUMN_AMOUNT_INT64 ? COLUMN_AMOUNT : (sortColumn == COLUMN_PRIORITY_INT64 ? COLUMN_PRIORITY : sortColumn)), sortOrder);
+ }
+ else
+ {
+ if (logicalIndex == COLUMN_AMOUNT) // sort by amount
+ logicalIndex = COLUMN_AMOUNT_INT64;
+
+ if (logicalIndex == COLUMN_PRIORITY) // sort by priority
+ logicalIndex = COLUMN_PRIORITY_INT64;
+
+ if (sortColumn == logicalIndex)
+ sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder);
+ else
+ {
+ sortColumn = logicalIndex;
+ sortOrder = ((sortColumn == COLUMN_AMOUNT_INT64 || sortColumn == COLUMN_PRIORITY_INT64 || sortColumn == COLUMN_DATE || sortColumn == COLUMN_CONFIRMATIONS) ? Qt::DescendingOrder : Qt::AscendingOrder); // if amount,date,conf,priority then default => desc, else default => asc
+ }
+
+ sortView(sortColumn, sortOrder);
+ }
+}
+
+// toggle tree mode
+void CoinControlDialog::radioTreeMode(bool checked)
+{
+ if (checked && model)
+ updateView();
+}
+
+// toggle list mode
+void CoinControlDialog::radioListMode(bool checked)
+{
+ if (checked && model)
+ updateView();
+}
+
+// checkbox clicked by user
+void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
+{
+ if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode)
+ {
+ COutPoint outpt(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt());
+
+ if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked)
+ coinControl->UnSelect(outpt);
+ else if (item->isDisabled()) // locked (this happens if "check all" through parent node)
+ item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
+ else
+ coinControl->Select(outpt);
+
+ // selection changed -> update labels
+ if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all
+ CoinControlDialog::updateLabels(model, this);
+ }
+}
+
+// helper function, return human readable label for priority number
+QString CoinControlDialog::getPriorityLabel(double dPriority)
+{
+ if (dPriority > 576000ULL) // at least medium, this number is from AllowFree(), the other thresholds are kinda random
+ {
+ if (dPriority > 5760000000ULL) return tr("highest");
+ else if (dPriority > 576000000ULL) return tr("high");
+ else if (dPriority > 57600000ULL) return tr("medium-high");
+ else return tr("medium");
+ }
+ else
+ {
+ if (dPriority > 5760ULL) return tr("low-medium");
+ else if (dPriority > 58ULL) return tr("low");
+ else return tr("lowest");
+ }
+}
+
+// shows count of locked unspent outputs
+/*void CoinControlDialog::updateLabelLocked()
+{
+ vector vOutpts;
+ model->listLockedCoins(vOutpts);
+ if (vOutpts.size() > 0)
+ {
+ ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));
+ ui->labelLocked->setVisible(true);
+ }
+ else ui->labelLocked->setVisible(false);
+}*/
+
+void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
+{
+ if (!model) return;
+
+ // nPayAmount
+ qint64 nPayAmount = 0;
+ bool fLowOutput = false;
+ bool fDust = false;
+ CTransaction txDummy;
+ foreach(const qint64 &amount, CoinControlDialog::payAmounts)
+ {
+ nPayAmount += amount;
+
+ if (amount > 0)
+ {
+ if (amount < CENT)
+ fLowOutput = true;
+
+ CTxOut txout(amount, (CScript)vector(24, 0));
+ txDummy.vout.push_back(txout);
+ }
+ }
+
+ QString sPriorityLabel = "";
+ int64 nAmount = 0;
+ int64 nPayFee = 0;
+ int64 nAfterFee = 0;
+ int64 nChange = 0;
+ unsigned int nBytes = 0;
+ unsigned int nBytesInputs = 0;
+ double dPriority = 0;
+ double dPriorityInputs = 0;
+ unsigned int nQuantity = 0;
+
+ vector vCoinControl;
+ vector vOutputs;
+ coinControl->ListSelected(vCoinControl);
+ model->getOutputs(vCoinControl, vOutputs);
+
+ BOOST_FOREACH(const COutput& out, vOutputs)
+ {
+ // Quantity
+ nQuantity++;
+
+ // Amount
+ nAmount += out.tx->vout[out.i].nValue;
+
+ // Priority
+ dPriorityInputs += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
+
+ // Bytes
+ CTxDestination address;
+ if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
+ {
+ CPubKey pubkey;
+ CKeyID *keyid = boost::get< CKeyID >(&address);
+ if (keyid && model->getPubKey(*keyid, pubkey))
+ nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
+ else
+ nBytesInputs += 148; // in all error cases, simply assume 148 here
+ }
+ else nBytesInputs += 148;
+ }
+
+ // calculation
+ if (nQuantity > 0)
+ {
+ // Bytes
+ nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here
+
+ // Priority
+ dPriority = dPriorityInputs / nBytes;
+ sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority);
+
+ // Fee
+ int64 nFee = nTransactionFee * (1 + (int64)nBytes / 1000);
+
+ // Min Fee
+ int64 nMinFee = txDummy.GetMinFee(1, false, GMF_SEND);
+
+ nPayFee = max(nFee, nMinFee);
+
+ if (nPayAmount > 0)
+ {
+ nChange = nAmount - nPayFee - nPayAmount;
+
+ // if sub-cent change is required, the fee must be raised to at least CTransaction::nMinTxFee
+ if (nPayFee < CENT && nChange > 0 && nChange < CENT)
+ {
+ if (nChange < CENT) // change < 0.01 => simply move all change to fees
+ {
+ nPayFee = nChange;
+ nChange = 0;
+ }
+ else
+ {
+ nChange = nChange + nPayFee - CENT;
+ nPayFee = CENT;
+ }
+ }
+
+ if (nChange == 0)
+ nBytes -= 34;
+ }
+
+ // after fee
+ nAfterFee = nAmount - nPayFee;
+ if (nAfterFee < 0)
+ nAfterFee = 0;
+ }
+
+ // actually update labels
+ int nDisplayUnit = BitcoinUnits::BTC;
+ if (model && model->getOptionsModel())
+ nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
+
+ QLabel *l1 = dialog->findChild("labelCoinControlQuantity");
+ QLabel *l2 = dialog->findChild("labelCoinControlAmount");
+ QLabel *l3 = dialog->findChild("labelCoinControlFee");
+ QLabel *l4 = dialog->findChild("labelCoinControlAfterFee");
+ QLabel *l5 = dialog->findChild("labelCoinControlBytes");
+ QLabel *l6 = dialog->findChild("labelCoinControlPriority");
+ QLabel *l7 = dialog->findChild("labelCoinControlLowOutput");
+ QLabel *l8 = dialog->findChild("labelCoinControlChange");
+
+ // enable/disable "low output" and "change"
+ dialog->findChild("labelCoinControlLowOutputText")->setEnabled(nPayAmount > 0);
+ dialog->findChild("labelCoinControlLowOutput") ->setEnabled(nPayAmount > 0);
+ dialog->findChild("labelCoinControlChangeText") ->setEnabled(nPayAmount > 0);
+ dialog->findChild("labelCoinControlChange") ->setEnabled(nPayAmount > 0);
+
+ // stats
+ l1->setText(QString::number(nQuantity)); // Quantity
+ l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount
+ l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee
+ l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
+ l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes
+ l6->setText(sPriorityLabel); // Priority
+ l7->setText((fLowOutput ? (fDust ? tr("DUST") : tr("yes")) : tr("no"))); // Low Output / Dust
+ l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
+
+ // turn labels "red"
+ l5->setStyleSheet((nBytes >= 10000) ? "color:red;" : ""); // Bytes >= 10000
+ l6->setStyleSheet((dPriority <= 576000) ? "color:red;" : ""); // Priority < "medium"
+ l7->setStyleSheet((fLowOutput) ? "color:red;" : ""); // Low Output = "yes"
+ l8->setStyleSheet((nChange > 0 && nChange < CENT) ? "color:red;" : ""); // Change < 0.01BTC
+
+ // tool tips
+ l5->setToolTip(tr("This label turns red, if the transaction size is bigger than 10000 bytes.\n\n This means a fee of at least %1 per kb is required.\n\n Can vary +/- 1 Byte per input.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)));
+ l6->setToolTip(tr("Transactions with higher priority get more likely into a block.\n\nThis label turns red, if the priority is smaller than \"medium\".\n\n This means a fee of at least %1 per kb is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)));
+ l7->setToolTip(tr("This label turns red, if any recipient receives an amount smaller than %1.\n\n This means a fee of at least %2 is required. \n\n Amounts below 0.546 times the minimum relay fee are shown as DUST.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)).arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)));
+ l8->setToolTip(tr("This label turns red, if the change is smaller than %1.\n\n This means a fee of at least %2 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)).arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)));
+ dialog->findChild("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
+ dialog->findChild("labelCoinControlPriorityText") ->setToolTip(l6->toolTip());
+ dialog->findChild("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
+ dialog->findChild("labelCoinControlChangeText") ->setToolTip(l8->toolTip());
+
+ // Insufficient funds
+ QLabel *label = dialog->findChild("labelCoinControlInsuffFunds");
+ if (label)
+ label->setVisible(nChange < 0);
+}
+
+void CoinControlDialog::updateView()
+{
+ bool treeMode = ui->radioTreeMode->isChecked();
+
+ ui->treeWidget->clear();
+ ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox
+ ui->treeWidget->setAlternatingRowColors(!treeMode);
+ QFlags flgCheckbox=Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
+ QFlags flgTristate=Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
+
+ int nDisplayUnit = BitcoinUnits::BTC;
+ if (model && model->getOptionsModel())
+ nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
+
+ map > mapCoins;
+ model->listCoins(mapCoins);
+
+ BOOST_FOREACH(PAIRTYPE(QString, vector) coins, mapCoins)
+ {
+ QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
+ QString sWalletAddress = coins.first;
+ QString sWalletLabel = "";
+ if (model->getAddressTableModel())
+ sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
+ if (sWalletLabel.length() == 0)
+ sWalletLabel = tr("(no label)");
+
+ if (treeMode)
+ {
+ // wallet address
+ ui->treeWidget->addTopLevelItem(itemWalletAddress);
+
+ itemWalletAddress->setFlags(flgTristate);
+ itemWalletAddress->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked);
+
+ for (int i = 0; i < ui->treeWidget->columnCount(); i++)
+ itemWalletAddress->setBackground(i, QColor(248, 247, 246));
+
+ // label
+ itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel);
+
+ // address
+ itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress);
+ }
+
+ int64 nSum = 0;
+ double dPrioritySum = 0;
+ int nChildren = 0;
+ int nInputSum = 0;
+ BOOST_FOREACH(const COutput& out, coins.second)
+ {
+ int nInputSize = 148; // 180 if uncompressed public key
+ nSum += out.tx->vout[out.i].nValue;
+ nChildren++;
+
+ QTreeWidgetItem *itemOutput;
+ if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress);
+ else itemOutput = new QTreeWidgetItem(ui->treeWidget);
+ itemOutput->setFlags(flgCheckbox);
+ itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked);
+
+ // address
+ CTxDestination outputAddress;
+ QString sAddress = "";
+ if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, outputAddress))
+ {
+ sAddress = CBitcoinAddress(outputAddress).ToString().c_str();
+
+ // if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
+ if (!treeMode || (!(sAddress == sWalletAddress)))
+ itemOutput->setText(COLUMN_ADDRESS, sAddress);
+
+ CPubKey pubkey;
+ CKeyID *keyid = boost::get< CKeyID >(&outputAddress);
+ if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed())
+ nInputSize = 180;
+ }
+
+ // label
+ if (!(sAddress == sWalletAddress)) // change
+ {
+ // tooltip from where the change comes from
+ itemOutput->setToolTip(COLUMN_LABEL, tr("change from %1 (%2)").arg(sWalletLabel).arg(sWalletAddress));
+ itemOutput->setText(COLUMN_LABEL, tr("(change)"));
+ }
+ else if (!treeMode)
+ {
+ QString sLabel = "";
+ if (model->getAddressTableModel())
+ sLabel = model->getAddressTableModel()->labelForAddress(sAddress);
+ if (sLabel.length() == 0)
+ sLabel = tr("(no label)");
+ itemOutput->setText(COLUMN_LABEL, sLabel);
+ }
+
+ // amount
+ itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue));
+ itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly
+
+ // date
+ itemOutput->setText(COLUMN_DATE, QDateTime::fromTime_t(out.tx->GetTxTime()).toUTC().toString("yy-MM-dd hh:mm"));
+
+ // immature PoS reward
+ if (out.tx->IsCoinStake() && out.tx->GetBlocksToMaturity() > 0 && out.tx->GetDepthInMainChain() > 0) {
+ itemOutput->setBackground(COLUMN_CONFIRMATIONS, Qt::red);
+ itemOutput->setDisabled(true);
+ }
+
+ // confirmations
+ itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
+
+ // priority
+ double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
+ itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority));
+ itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64)dPriority), 20, " "));
+ dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
+ nInputSum += nInputSize;
+
+ // transaction hash
+ uint256 txhash = out.tx->GetHash();
+ itemOutput->setText(COLUMN_TXHASH, txhash.GetHex().c_str());
+
+ // vout index
+ itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i));
+
+ // disable locked coins
+ /*if (model->isLockedCoin(txhash, out.i))
+ {
+ COutPoint outpt(txhash, out.i);
+ coinControl->UnSelect(outpt); // just to be sure
+ itemOutput->setDisabled(true);
+ itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed"));
+ }*/
+
+ // set checkbox
+ if (coinControl->IsSelected(txhash, out.i))
+ itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Checked);
+ }
+
+ // amount
+ if (treeMode)
+ {
+ dPrioritySum = dPrioritySum / (nInputSum + 78);
+ itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
+ itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
+ itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
+ itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum));
+ itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64)dPrioritySum), 20, " "));
+ }
+ }
+
+ // expand all partially selected
+ if (treeMode)
+ {
+ for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
+ if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked)
+ ui->treeWidget->topLevelItem(i)->setExpanded(true);
+ }
+
+ // sort view
+ sortView(sortColumn, sortOrder);
+ ui->treeWidget->setEnabled(true);
+}
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
new file mode 100644
index 0000000..5d0a90b
--- /dev/null
+++ b/src/qt/coincontroldialog.h
@@ -0,0 +1,92 @@
+#ifndef COINCONTROLDIALOG_H
+#define COINCONTROLDIALOG_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Ui {
+ class CoinControlDialog;
+}
+class WalletModel;
+class CCoinControl;
+
+class CoinControlDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CoinControlDialog(QWidget *parent = 0);
+ ~CoinControlDialog();
+
+ void setModel(WalletModel *model);
+
+ // static because also called from sendcoinsdialog
+ static void updateLabels(WalletModel*, QDialog*);
+ static QString getPriorityLabel(double);
+
+ static QList payAmounts;
+ static CCoinControl *coinControl;
+
+private:
+ Ui::CoinControlDialog *ui;
+ WalletModel *model;
+ int sortColumn;
+ Qt::SortOrder sortOrder;
+
+ QMenu *contextMenu;
+ QTreeWidgetItem *contextMenuItem;
+ QAction *copyTransactionHashAction;
+ //QAction *lockAction;
+ //QAction *unlockAction;
+
+ QString strPad(QString, int, QString);
+ void sortView(int, Qt::SortOrder);
+ void updateView();
+
+ enum
+ {
+ COLUMN_CHECKBOX,
+ COLUMN_AMOUNT,
+ COLUMN_LABEL,
+ COLUMN_ADDRESS,
+ COLUMN_DATE,
+ COLUMN_CONFIRMATIONS,
+ COLUMN_PRIORITY,
+ COLUMN_TXHASH,
+ COLUMN_VOUT_INDEX,
+ COLUMN_AMOUNT_INT64,
+ COLUMN_PRIORITY_INT64
+ };
+
+private slots:
+ void showMenu(const QPoint &);
+ void copyAmount();
+ void copyLabel();
+ void copyAddress();
+ void copyTransactionHash();
+ //void lockCoin();
+ //void unlockCoin();
+ void clipboardQuantity();
+ void clipboardAmount();
+ void clipboardFee();
+ void clipboardAfterFee();
+ void clipboardBytes();
+ void clipboardPriority();
+ void clipboardLowOutput();
+ void clipboardChange();
+ void radioTreeMode(bool);
+ void radioListMode(bool);
+ void viewItemChanged(QTreeWidgetItem*, int);
+ void headerSectionClicked(int);
+ void buttonBoxClicked(QAbstractButton*);
+ void buttonSelectAllClicked();
+ //void updateLabelLocked();
+};
+
+#endif // COINCONTROLDIALOG_H
diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp
new file mode 100644
index 0000000..0c1b514
--- /dev/null
+++ b/src/qt/coincontroltreewidget.cpp
@@ -0,0 +1,28 @@
+#include "coincontroltreewidget.h"
+#include "coincontroldialog.h"
+
+CoinControlTreeWidget::CoinControlTreeWidget(QWidget *parent) :
+ QTreeWidget(parent)
+{
+
+}
+
+void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Space) // press spacebar -> select checkbox
+ {
+ event->ignore();
+ int COLUMN_CHECKBOX = 0;
+ this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked));
+ }
+ else if (event->key() == Qt::Key_Escape) // press esc -> close dialog
+ {
+ event->ignore();
+ CoinControlDialog *coinControlDialog = (CoinControlDialog*)this->parentWidget();
+ coinControlDialog->done(QDialog::Accepted);
+ }
+ else
+ {
+ this->QTreeWidget::keyPressEvent(event);
+ }
+}
diff --git a/src/qt/coincontroltreewidget.h b/src/qt/coincontroltreewidget.h
new file mode 100644
index 0000000..d981f72
--- /dev/null
+++ b/src/qt/coincontroltreewidget.h
@@ -0,0 +1,17 @@
+#ifndef COINCONTROLTREEWIDGET_H
+#define COINCONTROLTREEWIDGET_H
+
+#include
+#include
+
+class CoinControlTreeWidget : public QTreeWidget {
+Q_OBJECT
+
+public:
+ explicit CoinControlTreeWidget(QWidget *parent = 0);
+
+protected:
+ virtual void keyPressEvent(QKeyEvent *event);
+};
+
+#endif // COINCONTROLTREEWIDGET_H
\ No newline at end of file
diff --git a/src/qt/forms/aboutdialog.ui b/src/qt/forms/aboutdialog.ui
index ad188b9..af5428b 100644
--- a/src/qt/forms/aboutdialog.ui
+++ b/src/qt/forms/aboutdialog.ui
@@ -11,7 +11,7 @@
- About DiamondCoin
+ About Diamond
-
@@ -50,7 +50,7 @@
IBeamCursor
- <b>DMDCoin</b> version
+ <b>Diamond</b> version
Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
@@ -63,7 +63,7 @@
IBeamCursor
- 2.0.1
+ 2.1.0.0
Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
@@ -94,7 +94,7 @@
Copyright © 2009-2014 Bitcoin Developers
Copyright © 2012-2014 PPCoin Developers
-Copyright © 2014 DiamondCoin Developers
+Copyright © 2013-2016 Diamond Foundation
diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui
index 69597e8..8dacba1 100644
--- a/src/qt/forms/addressbookpage.ui
+++ b/src/qt/forms/addressbookpage.ui
@@ -14,14 +14,16 @@
Address Book
- AddressBookPage{background:transparent; color: white;}
+
+ AddressBookPage{background:transparent; color: white;}
+ QTableView {background-color:rgb(69, 87, 96); color:white;}
+ QToolTip {background-color:#1f333e; color:white; border-style: none;}
+ QPushButton {background-color:rgb(69, 87, 96); color: white;}
+
-
-
- color:white;
-
These are your Diamond addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you.
@@ -483,10 +485,6 @@
Double-click to edit address or label
-
- QTableView {background-color:rgb(69, 87, 96); color:white;}
-QToolTip {background-color:#1f333e; color:white;}
-
false
@@ -514,9 +512,6 @@ QToolTip {background-color:#1f333e; color:white;}
Create a new address
-
- background-color:rgb(69, 87, 96); color: white;
-
&New Address
@@ -531,9 +526,6 @@ QToolTip {background-color:#1f333e; color:white;}
Copy the currently selected address to the system clipboard
-
- background-color:rgb(69, 87, 96); color: white;
-
&Copy Address
@@ -545,9 +537,6 @@ QToolTip {background-color:#1f333e; color:white;}
-
-
- background-color:rgb(69, 87, 96); color: white;
-
Show &QR Code
@@ -562,9 +551,6 @@ QToolTip {background-color:#1f333e; color:white;}
Sign a message to prove you own a Diamond address
-
- background-color:rgb(69, 87, 96); color: white;
-
Sign &Message
@@ -579,9 +565,6 @@ QToolTip {background-color:#1f333e; color:white;}
Verify a message to ensure it was signed with a specified Diamond address
-
- background-color:rgb(69, 87, 96); color: white;
-
&Verify Message
@@ -596,9 +579,6 @@ QToolTip {background-color:#1f333e; color:white;}
Delete the currently selected address from the list
-
- background-color:rgb(69, 87, 96); color: white;
-
&Delete
diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui
index 2516904..204d282 100644
--- a/src/qt/forms/askpassphrasedialog.ui
+++ b/src/qt/forms/askpassphrasedialog.ui
@@ -99,6 +99,22 @@
+ -
+
+
+ true
+
+
+ Serves to disable trivial use of sendmoney when the OS account is compromised. Provides no real security.
+
+
+ For minting only
+
+
+ false
+
+
+
-
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
new file mode 100644
index 0000000..29ff1fd
--- /dev/null
+++ b/src/qt/forms/coincontroldialog.ui
@@ -0,0 +1,554 @@
+
+
+ CoinControlDialog
+
+
+
+ 0
+ 0
+ 1000
+ 500
+
+
+
+ Coin Control
+
+
+ QTableView {background-color:rgb(69, 87, 96); color:white;}
+QToolTip {background-color:#1f333e; color:white; border-style: none;}
+
+
+
+
-
+
+
+ 0
+
+
+ 10
+
+
-
+
+
+ 10
+
+
+ 10
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ font-weight:bold;
+
+
+ Quantity:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ font-weight:bold;
+
+
+ Bytes:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ font-weight:bold;
+
+
+ Amount:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0.00 DMD
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ font-weight:bold;
+
+
+ Priority:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ font-weight:bold;
+
+
+ Fee:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0.00 DMD
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ false
+
+
+ font-weight:bold;
+
+
+ Low Output:
+
+
+
+ -
+
+
+ false
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ no
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ font-weight:bold;
+
+
+ After Fee:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0.00 DMD
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ false
+
+
+ font-weight:bold;
+
+
+ Change:
+
+
+
+ -
+
+
+ false
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0.00 DMD
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 40
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Sunken
+
+
+
+
+ 10
+ 0
+ 781
+ 41
+
+
+
+
+ 14
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ (un)select all
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Tree mode
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ List mode
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::CustomContextMenu
+
+
+ false
+
+
+ 11
+
+
+ true
+
+
+ false
+
+
+
+
+
+
+
+
+ Amount
+
+
+
+
+ Label
+
+
+
+
+ Address
+
+
+
+
+ Date
+
+
+
+
+ Confirmations
+
+
+ Confirmed
+
+
+
+
+ Priority
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Ok
+
+
+
+
+
+
+
+ CoinControlTreeWidget
+ QTreeWidget
+
+
+
+
+
+
diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui
index 10577f4..d6ec6bb 100644
--- a/src/qt/forms/editaddressdialog.ui
+++ b/src/qt/forms/editaddressdialog.ui
@@ -38,7 +38,7 @@
The label associated with this address book entry
-
+ background-color:#1f333e; color:white; border: none;
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 6402c2c..6bca13e 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -33,7 +33,7 @@
-
- Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended.
+ Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.001 recommended.
Qt::PlainText
@@ -343,6 +343,16 @@
+ -
+
+
+ Whether to show coin control features or not.
+
+
+ Display coin &control features (experts only!)
+
+
+
-
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 5361d26..756d570 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -22,7 +22,7 @@
-
- background-color:rgba(255, 255, 255, 40); color: white;
+ background-color:transparent; color:white;
QFrame::StyledPanel
@@ -56,7 +56,7 @@
The displayed information may be out of date. Your wallet automatically synchronizes with the Diamond network after a connection is established, but this process has not completed yet.
- QToolTip {background-color:#1f333e; color:white;}
+ QToolTip {background-color:#1f333e; color:white; border-style: none;}
QLabel { color: red; background:transparent;}
@@ -119,7 +119,7 @@ QLabel { color: red; background:transparent;}
QLabel {background:transparent;}
-QToolTip {background-color:#1f333e; color:white;}
+QToolTip {background-color:#1f333e; color:white; border-style: none;}
0 DMD
@@ -155,7 +155,7 @@ QToolTip {background-color:#1f333e; color:white;}
QLabel {background:transparent;}
-QToolTip {background-color:#1f333e; color:white;}
+QToolTip {background-color:#1f333e; color:white; border-style: none;}
0 DMD
@@ -191,7 +191,7 @@ QToolTip {background-color:#1f333e; color:white;}
QLabel {background:transparent;}
-QToolTip {background-color:#1f333e; color:white;}
+QToolTip {background-color:#1f333e; color:white; border-style: none;}
0 DMD
@@ -224,7 +224,7 @@ QToolTip {background-color:#1f333e; color:white;}
QLabel {background:transparent;}
-QToolTip {background-color:#1f333e; color:white;}
+QToolTip {background-color:#1f333e; color:white; border-style: none;}
0 DMD
@@ -251,7 +251,7 @@ QToolTip {background-color:#1f333e; color:white;}
QLabel {background:transparent;}
-QToolTip {background-color:#1f333e; color:white;}
+QToolTip {background-color:#1f333e; color:white; border-style: none;}
0
@@ -308,7 +308,7 @@ QToolTip {background-color:#1f333e; color:white;}
-
- background-color:rgba(255, 255, 255, 40); color: white;
+ background-color:transparent; color:white;
QFrame::StyledPanel
@@ -325,7 +325,7 @@ QToolTip {background-color:#1f333e; color:white;}
background:transparent;
- <html><head/><body><p><span style=" font-weight:600; color:#ffffff;">Recent transactions</span></p></body></html>
+ <b>Recent transactions</b>
@@ -335,7 +335,7 @@ QToolTip {background-color:#1f333e; color:white;}
The displayed information may be out of date. Your wallet automatically synchronizes with the Diamond network after a connection is established, but this process has not completed yet.
- QToolTip {background-color:#1f333e; color:white;}
+ QToolTip {background-color:#1f333e; color:white; border-style: none;}
QLabel { color: red; background:transparent; }
@@ -365,7 +365,7 @@ QLabel { color: red; background:transparent; }
QListView { background: transparent; }
-QToolTip {background-color:#1f333e; color:white;}
+QToolTip {background-color:#1f333e; color:white; border-style: none;}
QFrame::NoFrame
@@ -381,31 +381,21 @@ QToolTip {background-color:#1f333e; color:white;}
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
- false
+
+
+ Qt::Vertical
-
- Unlock wallet
+
+
+ 20
+ 40
+
-
+
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 715d244..6cb282d 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -6,24 +6,601 @@
0
0
- 686
- 234
+ 831
+ 390
Send Coins
- SendCoinsDialog {background:transparent; color:white;}
-QToolTip {background-color:#1f333e; color:white;}
-
+
+ SendCoinsDialog {background:transparent; color:white;}
+ QPushButton {background-color:rgb(69, 87, 96); color:white;}
+ QLabel {background-color:transparent; color:white;}
+ QFrame {background-color:transparent; color:white;}
+ QCheckBox {background-color:transparent; color:white;}
+ QLineEdit {background-color:#1f333e; color:white; border: none;}
+ QToolTip {background-color:#1f333e; color:white; border-style: none;}
+
+
+ 8
+
-
-
-
- background-color:rgb(69, 87, 96)
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Sunken
+
+
+ 6
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 6
+
+
-
+
+
+ 0
+
+
+ 10
+
+
+ 10
+
+
-
+
+
+ 15
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ true
+
+
+
+ Coin Control Features
+
+
+
+
+
+ -
+
+
+ 8
+
+
+ 10
+
+
-
+
+
+ Inputs...
+
+
+
+ -
+
+
+ automatically selected
+
+
+ 5
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Insufficient funds!
+
+
+ 5
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 1
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ 20
+
+
+ 0
+
+
+ 10
+
+
-
+
+
+ 10
+
+
+ 14
+
+
+ 10
+
+
+ 4
+
+
+ 6
+
+
-
+
+
+ Quantity:
+
+
+ 0
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0
+
+
+ 0
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ Bytes:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 14
+
+
+ 6
+
+
+ 4
+
+
+ 6
+
+
-
+
+
+ Amount:
+
+
+ 0
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0.00 DMD
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ Priority:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ medium
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 14
+
+
+ 6
+
+
+ 4
+
+
+ 6
+
+
-
+
+
+ Fee:
+
+
+ 0
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0.00 DMD
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ Low Output:
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ no
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 14
+
+
+ 6
+
+
+ 4
+
+
+ 6
+
+
-
+
+
+ After Fee:
+
+
+ 0
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0.00 DMD
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+ -
+
+
+ Change
+
+
+
+ -
+
+
+
+ Monospace
+ 10
+
+
+
+ IBeamCursor
+
+
+ Qt::ActionsContextMenu
+
+
+ 0.00 DMD
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 12
+
+
+ QLayout::SetDefaultConstraint
+
+
+ 5
+
+
+ 5
+
+
-
+
+
+ custom change address
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 3
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 800
+ 1
+
+
+
+
+
+
+
+
+
+ -
+
QFrame::StyledPanel
@@ -34,15 +611,12 @@ QToolTip {background-color:#1f333e; color:white;}
-
- <html><head/><body><p><span style=" color:#ffffff;">Transaction comment:</span></p></body></html>
+ Transaction comment:
-
-
- color:white;
-
@@ -50,10 +624,6 @@ QToolTip {background-color:#1f333e; color:white;}
-
-
-
-background-color:rgba(255, 255, 255, 40); color: white;
-
true
@@ -67,7 +637,7 @@ background-color:rgba(255, 255, 255, 40); color: white;
- background:transparent;
+ background-color:rgb(59, 88, 104);
@@ -113,10 +683,6 @@ background-color:rgba(255, 255, 255, 40); color: white;
Send to multiple recipients at once
-
- QPushButton {background-color:rgb(69, 87, 96); color: white;}
-QToolTip {background-color:#1f333e; color:white;}
-
Add &Recipient
@@ -143,10 +709,6 @@ QToolTip {background-color:#1f333e; color:white;}
Remove all transaction fields
-
- QPushButton {background-color:rgb(69, 87, 96); color: white;}
-QToolTip {background-color:#1f333e; color:white;}
-
Clear &All
@@ -169,6 +731,12 @@ QToolTip {background-color:#1f333e; color:white;}
-
+
+
+ 0
+ 0
+
+
Balance:
@@ -176,6 +744,12 @@ QToolTip {background-color:#1f333e; color:white;}
-
+
+
+ 0
+ 0
+
+
IBeamCursor
@@ -213,10 +787,6 @@ QToolTip {background-color:#1f333e; color:white;}
Confirm the send action
-
- QPushButton {background-color:rgb(69, 87, 96); color: white;}
-QToolTip {background-color:#1f333e; color:white;}
-
S&end
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index 3fcb25a..516fe4f 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -14,9 +14,10 @@
Form
- background-color:rgb(69, 87, 96);
-QPushButton{background-color:rgba(97, 147, 174, 255);color:white;}
-QToolTip {background-color:#1f333e !important; color:white !important;}
+ background-color:transparent;
+ QLabel {background-color:transparent; color:white;}
+ QToolTip {background-color:#1f333e !important; color:white !important; border-style: none;}
+
QFrame::StyledPanel
@@ -31,7 +32,7 @@ QToolTip {background-color:#1f333e !important; color:white !important;}
-
- <html><head/><body><p><span style=" color:#ffffff;">A&mount:</span></p></body></html>
+ A&mount:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
@@ -44,7 +45,7 @@ QToolTip {background-color:#1f333e !important; color:white !important;}
-
- <html><head/><body><p><span style=" color:#ffffff;">Pay &To:</span></p></body></html>
+ Pay &To:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
@@ -58,7 +59,8 @@ QToolTip {background-color:#1f333e !important; color:white !important;}
color:white;
-QToolTip {background-color:#1f333e; color:white;}
+ QToolTip {background-color:#1f333e; color:white; border-style: none;}
+
@@ -75,9 +77,6 @@ QToolTip {background-color:#1f333e; color:white;}
Enter a label for this address to add it to your address book
-
- QToolTip {background-color:#1f333e; color:white;}
-
@@ -85,7 +84,7 @@ QToolTip {background-color:#1f333e; color:white;}
-
- <html><head/><body><p><span style=" color:#ffffff;">&Label:</span></p></body></html>
+ &Label:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
@@ -105,9 +104,6 @@ QToolTip {background-color:#1f333e; color:white;}
The address to send the payment to (e.g. dc8hQjs9oy9AHPCSF5aTvkcRVECojV3joC)
-
- QToolTip {background-color:#1f333e; color:white;}
-
34
@@ -118,9 +114,6 @@ QToolTip {background-color:#1f333e; color:white;}
Choose address from address book
-
- QToolTip {background-color:#1f333e; color:white;}
-
@@ -138,9 +131,6 @@ QToolTip {background-color:#1f333e; color:white;}
Paste address from clipboard
-
- QToolTip {background-color:#1f333e; color:white;}
-
@@ -158,9 +148,6 @@ QToolTip {background-color:#1f333e; color:white;}
Remove this recipient
-
- QToolTip {background-color:#1f333e; color:white;}
-
diff --git a/src/qt/forms/transactiondescdialog.ui b/src/qt/forms/transactiondescdialog.ui
index 2203e6a..f3300c1 100644
--- a/src/qt/forms/transactiondescdialog.ui
+++ b/src/qt/forms/transactiondescdialog.ui
@@ -14,7 +14,7 @@
Transaction details
- TransactionDescDialog{background: transparent;}
+ TransactionDescDialog{background: transparent; color:white;}
-
@@ -22,9 +22,6 @@
This pane shows a detailed description of the transaction
-
-
-
true
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index e5494de..add7991 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+
#include
#include
diff --git a/src/qt/locale/bitcoin_en.qm b/src/qt/locale/bitcoin_en.qm
deleted file mode 100644
index 78bebd4..0000000
Binary files a/src/qt/locale/bitcoin_en.qm and /dev/null differ
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index a4eb463..6f12bd5 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -2708,7 +2708,7 @@ Address: %4
%s, you must set a rpcpassword in the configuration file:
%s
It is recommended you use the following random password:
-rpcuser=bitcoinrpc
+rpcuser=diamondrpc
rpcpassword=%s
(you do not need to remember this password)
If the file does not exist, create it with owner-readable-only file permissions.
@@ -2716,7 +2716,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
%s, you must set a rpcpassword in the configuration file:
%s
It is recommended you use the following random password:
-rpcuser=bitcoinrpc
+rpcuser=diamondrpc
rpcpassword=%s
(you do not need to remember this password)
If the file does not exist, create it with owner-readable-only file permissions.
diff --git a/src/qt/locale/bitcoin_ru.qm b/src/qt/locale/bitcoin_ru.qm
deleted file mode 100644
index afb610b..0000000
Binary files a/src/qt/locale/bitcoin_ru.qm and /dev/null differ
diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts
index 56abb9a..f75445e 100644
--- a/src/qt/locale/bitcoin_ru.ts
+++ b/src/qt/locale/bitcoin_ru.ts
@@ -1406,8 +1406,8 @@ Address: %4
- The address to send the payment to (e.g. dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
- Адрес получателя платежа (например dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ The address to send the payment to (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ Адрес получателя платежа (например 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
@@ -1436,8 +1436,8 @@ Address: %4
- Enter a BottleCaps address (e.g. dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
- Введите BottleCaps-адрес (например dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ Enter a BottleCaps address (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ Введите BottleCaps-адрес (например 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
@@ -1460,8 +1460,8 @@ Address: %4
- The address to sign the message with (e.g. dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
- Адрес, которым вы хотите подписать сообщение (напр. dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ The address to sign the message with (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ Адрес, которым вы хотите подписать сообщение (напр. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
@@ -1524,8 +1524,8 @@ Address: %4
- The address the message was signed with (e.g. dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
- Адрес, которым было подписано сообщение (напр. dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ The address the message was signed with (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ Адрес, которым было подписано сообщение (напр. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
@@ -1540,8 +1540,8 @@ Address: %4
- Enter a BottleCaps address (e.g. dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
- Введите адрес BottleCaps (напр. dZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ Enter a BottleCaps address (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
+ Введите адрес BottleCaps (напр. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)
@@ -2721,7 +2721,7 @@ Address: %4
%s, you must set a rpcpassword in the configuration file:
%s
It is recommended you use the following random password:
-rpcuser=bitcoinrpc
+rpcuser=diamondrpc
rpcpassword=%s
(you do not need to remember this password)
If the file does not exist, create it with owner-readable-only file permissions.
@@ -2729,7 +2729,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
%s, вы должны установить опцию rpcpassword в конфигурационном файле:
%s
Рекомендуется использовать следующий случайный пароль:
-rpcuser=bitcoinrpc
+rpcuser=diamondrpc
rpcpassword=%s
(вам не нужно запоминать этот пароль)
Если файл не существует, создайте его и установите права доступа только для владельца.
diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h
index 2092fb2..08a8110 100644
--- a/src/qt/macdockiconhandler.h
+++ b/src/qt/macdockiconhandler.h
@@ -1,7 +1,8 @@
#ifndef MACDOCKICONHANDLER_H
#define MACDOCKICONHANDLER_H
-#include
+#include
+#include
class QMenu;
class QIcon;
@@ -24,6 +25,7 @@ class MacDockIconHandler : public QObject
QMenu *dockMenu();
void setIcon(const QIcon &icon);
+ void setMainWindow(QMainWindow *window);
static MacDockIconHandler *instance();
void handleDockIconClickEvent();
@@ -39,6 +41,7 @@ public slots:
DockIconClickEventHandler *m_dockIconClickEventHandler;
QWidget *m_dummyWidget;
QMenu *m_dockMenu;
+ QMainWindow *mainWindow;
};
#endif // MACDOCKICONCLICKHANDLER_H
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index 6d1cd64..0c3ee5f 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -4,7 +4,6 @@
#include
#include
-//extern void qt_mac_set_dock_menu(QMenu*);
#include
#include
@@ -53,13 +52,19 @@ - (void)handleDockClickEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAp
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
+ this->setMainWindow(NULL);
[pool release];
}
+void MacDockIconHandler::setMainWindow(QMainWindow *window) {
+ this->mainWindow = window;
+}
+
MacDockIconHandler::~MacDockIconHandler()
{
[this->m_dockIconClickEventHandler release];
delete this->m_dummyWidget;
+ this->setMainWindow(NULL);
}
QMenu *MacDockIconHandler::dockMenu()
@@ -109,5 +114,10 @@ - (void)handleDockClickEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAp
void MacDockIconHandler::handleDockIconClickEvent()
{
+ if (this->mainWindow)
+ {
+ this->mainWindow->activateWindow();
+ this->mainWindow->show();
+ }
emit this->dockIconClicked();
}
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 8028190..3a92be0 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -18,8 +18,10 @@
#ifdef Q_OS_MAC
#include
+#if QT_VERSION < 0x050000
extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret);
#endif
+#endif
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
@@ -269,7 +271,9 @@ void Notificator::notifyGrowl(Class cls, const QString &title, const QString &te
quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
quotedText.replace("\\", "\\\\").replace("\"", "\\");
QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp");
+#if QT_VERSION < 0x050000
qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp), 0);
+#endif
}
#endif
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 1a438cb..e13bc24 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -148,6 +148,7 @@ void OptionsDialog::setMapper()
mapper->addMapping(ui->lang, OptionsModel::Language);
mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses);
+ mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures);
}
void OptionsDialog::enableApplyButton()
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 756fe61..abc09a0 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -45,6 +45,7 @@ void OptionsModel::Init()
bDisplayAddresses = settings.value("bDisplayAddresses", false).toBool();
fMinimizeToTray = settings.value("fMinimizeToTray", false).toBool();
fMinimizeOnClose = settings.value("fMinimizeOnClose", false).toBool();
+ fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool();
nTransactionFee = settings.value("nTransactionFee").toLongLong();
language = settings.value("language", "").toString();
@@ -170,6 +171,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return QVariant(bitdb.GetDetach());
case Language:
return settings.value("language", "");
+ case CoinControlFeatures:
+ return QVariant(fCoinControlFeatures);
default:
return QVariant();
}
@@ -239,6 +242,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
case Fee:
nTransactionFee = value.toLongLong();
settings.setValue("nTransactionFee", nTransactionFee);
+ emit transactionFeeChanged(nTransactionFee);
break;
case DisplayUnit:
nDisplayUnit = value.toInt();
@@ -258,6 +262,12 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
case Language:
settings.setValue("language", value);
break;
+ case CoinControlFeatures: {
+ fCoinControlFeatures = value.toBool();
+ settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
+ emit coinControlFeaturesChanged(fCoinControlFeatures);
+ }
+ break;
default:
break;
}
@@ -272,6 +282,11 @@ qint64 OptionsModel::getTransactionFee()
return nTransactionFee;
}
+bool OptionsModel::getCoinControlFeatures()
+{
+ return fCoinControlFeatures;
+}
+
bool OptionsModel::getMinimizeToTray()
{
return fMinimizeToTray;
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 34724ad..263b95e 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -30,6 +30,7 @@ class OptionsModel : public QAbstractListModel
DisplayAddresses, // bool
DetachDatabases, // bool
Language, // QString
+ CoinControlFeatures, // bool
OptionIDRowCount,
};
@@ -48,6 +49,7 @@ class OptionsModel : public QAbstractListModel
bool getMinimizeOnClose();
int getDisplayUnit();
bool getDisplayAddresses();
+ bool getCoinControlFeatures();
QString getLanguage() { return language; }
private:
@@ -55,10 +57,13 @@ class OptionsModel : public QAbstractListModel
bool bDisplayAddresses;
bool fMinimizeToTray;
bool fMinimizeOnClose;
+ bool fCoinControlFeatures;
QString language;
signals:
void displayUnitChanged(int unit);
+ void transactionFeeChanged(qint64);
+ void coinControlFeaturesChanged(bool);
};
#endif // OPTIONSMODEL_H
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 5b455f9..716e1f5 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -154,24 +154,6 @@ void OverviewPage::setNumTransactions(int count)
ui->labelNumTransactions->setText(QLocale::system().toString(count));
}
-void OverviewPage::unlockWallet()
-{
- if(model->getEncryptionStatus() == WalletModel::Locked)
- {
- AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
- dlg.setModel(model);
- if(dlg.exec() == QDialog::Accepted)
- {
- ui->unlockWalletButton->setText(QString("Lock wallet"));
- }
- }
- else
- {
- model->setWalletLocked(true);
- ui->unlockWalletButton->setText(QString("Unlock wallet"));
- }
-}
-
void OverviewPage::setModel(WalletModel *model)
{
this->model = model;
@@ -183,7 +165,7 @@ void OverviewPage::setModel(WalletModel *model)
filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
- filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
+ filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
ui->listTransactions->setModel(filter);
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
@@ -196,14 +178,6 @@ void OverviewPage::setModel(WalletModel *model)
connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
-
- // Unlock wallet button
- WalletModel::EncryptionStatus status = model->getEncryptionStatus();
- if(status == WalletModel::Unencrypted)
- {
- ui->unlockWalletButton->setDisabled(true);
- }
- connect(ui->unlockWalletButton, SIGNAL(clicked()), this, SLOT(unlockWallet()));
}
// update the display unit, to not use the default ("DMD")
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 2ed43b7..59fbb1d 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -29,7 +29,6 @@ class OverviewPage : public QWidget
public slots:
void setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance);
void setNumTransactions(int count);
- void unlockWallet();
signals:
void transactionClicked(const QModelIndex &index);
diff --git a/src/qt/res/bitcoin-qt.rc b/src/qt/res/bitcoin-qt.rc
index b0ea7a9..26d5d1c 100644
--- a/src/qt/res/bitcoin-qt.rc
+++ b/src/qt/res/bitcoin-qt.rc
@@ -22,7 +22,7 @@ BEGIN
VALUE "FileDescription", "Diamond-Qt (OSS GUI client for Diamond)"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "Diamond-qt"
- VALUE "LegalCopyright", "2009-2014 The Bitcoin developers, 2012-2014 The Diamond & PPCoin developers"
+ VALUE "LegalCopyright", "2009-2014 The Bitcoin developers, 2012-2013 PPCoin developers, 2013-2015 Diamond Foundation"
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", "Diamond-qt.exe"
VALUE "ProductName", "Diamond-Qt"
diff --git a/src/qt/res/icons/Diamond.icns b/src/qt/res/icons/Diamond.icns
index 83a5c43..71d5376 100644
Binary files a/src/qt/res/icons/Diamond.icns and b/src/qt/res/icons/Diamond.icns differ
diff --git a/src/qt/res/icons/bitcoin_testnet.png b/src/qt/res/icons/Diamond_testnet.png
similarity index 100%
rename from src/qt/res/icons/bitcoin_testnet.png
rename to src/qt/res/icons/Diamond_testnet.png
diff --git a/src/qt/res/icons/New folder/mining.png b/src/qt/res/icons/New folder/mining.png
deleted file mode 100644
index e1c4ebc..0000000
Binary files a/src/qt/res/icons/New folder/mining.png and /dev/null differ
diff --git a/src/qt/res/icons/New folder/mining_active.png b/src/qt/res/icons/New folder/mining_active.png
deleted file mode 100644
index 8be8766..0000000
Binary files a/src/qt/res/icons/New folder/mining_active.png and /dev/null differ
diff --git a/src/qt/res/icons/New folder/mining_inactive.png b/src/qt/res/icons/New folder/mining_inactive.png
deleted file mode 100644
index cee171f..0000000
Binary files a/src/qt/res/icons/New folder/mining_inactive.png and /dev/null differ
diff --git a/src/qt/res/icons/mining.png b/src/qt/res/icons/mining.png
new file mode 100644
index 0000000..8217870
Binary files /dev/null and b/src/qt/res/icons/mining.png differ
diff --git a/src/qt/res/icons/minting.png b/src/qt/res/icons/minting.png
new file mode 100644
index 0000000..18bb7d6
Binary files /dev/null and b/src/qt/res/icons/minting.png differ
diff --git a/src/qt/res/icons/tx_minted.png b/src/qt/res/icons/tx_minted.png
new file mode 100644
index 0000000..6fd6afe
Binary files /dev/null and b/src/qt/res/icons/tx_minted.png differ
diff --git a/src/qt/res/images/diamond-splash.jpg b/src/qt/res/images/diamond-splash.jpg
index ff47832..6d02745 100644
Binary files a/src/qt/res/images/diamond-splash.jpg and b/src/qt/res/images/diamond-splash.jpg differ
diff --git a/src/qt/res/images/diamond.png b/src/qt/res/images/diamond.png
new file mode 100644
index 0000000..882d645
Binary files /dev/null and b/src/qt/res/images/diamond.png differ
diff --git a/src/qt/res/images/wallet.png b/src/qt/res/images/wallet.png
deleted file mode 100644
index ad7d975..0000000
Binary files a/src/qt/res/images/wallet.png and /dev/null differ
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 0aa82d1..b7f72da 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -2,9 +2,12 @@
#include "ui_rpcconsole.h"
#include "clientmodel.h"
-#include "bitcoinrpc.h"
#include "guiutil.h"
+#ifndef Q_MOC_RUN
+#include "bitcoinrpc.h"
+#endif
+
#include
#include
#include
@@ -20,7 +23,7 @@
// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel
-const int CONSOLE_SCROLLBACK = 50;
+//const int CONSOLE_SCROLLBACK = 50;
const int CONSOLE_HISTORY = 50;
const QSize ICON_SIZE(24, 24);
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index efbaed4..dfce5b3 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -1,18 +1,23 @@
#include "sendcoinsdialog.h"
#include "ui_sendcoinsdialog.h"
+#include "init.h"
#include "walletmodel.h"
+#include "addresstablemodel.h"
+#include "addressbookpage.h"
#include "bitcoinunits.h"
#include "addressbookpage.h"
#include "optionsmodel.h"
#include "sendcoinsentry.h"
#include "guiutil.h"
#include "askpassphrasedialog.h"
-#include "base58.h"
+#include "coincontrol.h"
+#include "coincontroldialog.h"
#include
#include
#include
#include
+#include
SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
QDialog(parent),
@@ -31,7 +36,39 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry()));
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
-
+
+ // Coin Control
+ ui->lineEditCoinControlChange->setFont(GUIUtil::bitcoinAddressFont());
+ 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 &)));
+
+ // Coin Control: clipboard actions
+ QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
+ QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);
+ QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
+ QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
+ QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
+ QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
+ QAction *clipboardLowOutputAction = new QAction(tr("Copy low output"), this);
+ QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
+ connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity()));
+ connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAmount()));
+ connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee()));
+ connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee()));
+ connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes()));
+ connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardPriority()));
+ connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput()));
+ connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange()));
+ ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
+ ui->labelCoinControlAmount->addAction(clipboardAmountAction);
+ ui->labelCoinControlFee->addAction(clipboardFeeAction);
+ ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
+ ui->labelCoinControlBytes->addAction(clipboardBytesAction);
+ ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
+ ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
+ ui->labelCoinControlChange->addAction(clipboardChangeAction);
+
fNewRecipientAllowed = true;
}
@@ -52,6 +89,12 @@ void SendCoinsDialog::setModel(WalletModel *model)
setBalance(model->getBalance(), model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance());
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
+ connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool)));
+ connect(model->getOptionsModel(), SIGNAL(transactionFeeChanged(qint64)), this, SLOT(coinControlUpdateLabels()));
+ ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures());
+ coinControlUpdateLabels();
}
}
@@ -124,7 +167,13 @@ void SendCoinsDialog::on_sendButton_clicked()
return;
}
- WalletModel::SendCoinsReturn sendstatus = model->sendCoins(txcomment, recipients);
+ WalletModel::SendCoinsReturn sendstatus;
+
+ if (!model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures())
+ sendstatus = model->sendCoins(txcomment,recipients);
+ else
+ sendstatus = model->sendCoins(txcomment,recipients, CoinControlDialog::coinControl);
+
switch(sendstatus.status)
{
case WalletModel::InvalidAddress:
@@ -167,6 +216,8 @@ void SendCoinsDialog::on_sendButton_clicked()
break;
case WalletModel::OK:
accept();
+ CoinControlDialog::coinControl->UnSelectAll();
+ coinControlUpdateLabels();
break;
}
fNewRecipientAllowed = true;
@@ -202,6 +253,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry()
entry->setModel(model);
ui->entries->addWidget(entry);
connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
+ connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels()));
updateRemoveEnabled();
@@ -229,6 +281,7 @@ void SendCoinsDialog::updateRemoveEnabled()
}
}
setupTabChain(0);
+ coinControlUpdateLabels();
}
void SendCoinsDialog::removeEntry(SendCoinsEntry* entry)
@@ -311,3 +364,152 @@ void SendCoinsDialog::updateDisplayUnit()
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->getBalance()));
}
}
+
+ // Coin Control: copy label "Quantity" to clipboard
+ void SendCoinsDialog::coinControlClipboardQuantity()
+ {
+ QApplication::clipboard()->setText(ui->labelCoinControlQuantity->text());
+ }
+
+ // Coin Control: copy label "Amount" to clipboard
+ void SendCoinsDialog::coinControlClipboardAmount()
+ {
+ QApplication::clipboard()->setText(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" ")));
+ }
+
+ // Coin Control: copy label "Fee" to clipboard
+ void SendCoinsDialog::coinControlClipboardFee()
+ {
+ QApplication::clipboard()->setText(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")));
+ }
+
+ // Coin Control: copy label "After fee" to clipboard
+ void SendCoinsDialog::coinControlClipboardAfterFee()
+ {
+ QApplication::clipboard()->setText(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")));
+ }
+
+ // Coin Control: copy label "Bytes" to clipboard
+ void SendCoinsDialog::coinControlClipboardBytes()
+ {
+ QApplication::clipboard()->setText(ui->labelCoinControlBytes->text());
+ }
+
+ // Coin Control: copy label "Priority" to clipboard
+ void SendCoinsDialog::coinControlClipboardPriority()
+ {
+ QApplication::clipboard()->setText(ui->labelCoinControlPriority->text());
+ }
+
+ // Coin Control: copy label "Low output" to clipboard
+ void SendCoinsDialog::coinControlClipboardLowOutput()
+ {
+ QApplication::clipboard()->setText(ui->labelCoinControlLowOutput->text());
+ }
+
+ // Coin Control: copy label "Change" to clipboard
+ void SendCoinsDialog::coinControlClipboardChange()
+ {
+ QApplication::clipboard()->setText(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")));
+ }
+
+ // Coin Control: settings menu - coin control enabled/disabled by user
+ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
+ {
+ ui->frameCoinControl->setVisible(checked);
+
+ if (!checked && model) // coin control features disabled
+ CoinControlDialog::coinControl->SetNull();
+ }
+
+ // Coin Control: button inputs -> show actual coin control dialog
+ void SendCoinsDialog::coinControlButtonClicked()
+ {
+ CoinControlDialog dlg;
+ dlg.setModel(model);
+ dlg.exec();
+ coinControlUpdateLabels();
+ }
+
+ // Coin Control: checkbox custom change address
+ void SendCoinsDialog::coinControlChangeChecked(int state)
+ {
+ if (model)
+ {
+ if (state == Qt::Checked)
+ CoinControlDialog::coinControl->destChange = CBitcoinAddress(ui->lineEditCoinControlChange->text().toStdString()).Get();
+ else
+ CoinControlDialog::coinControl->destChange = CNoDestination();
+ }
+
+ ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked));
+ ui->labelCoinControlChangeLabel->setEnabled((state == Qt::Checked));
+ }
+
+ // Coin Control: custom change address changed
+ void SendCoinsDialog::coinControlChangeEdited(const QString & text)
+ {
+ if (model)
+ {
+ CoinControlDialog::coinControl->destChange = CBitcoinAddress(text.toStdString()).Get();
+
+ // label for the change address
+ ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}");
+ if (text.isEmpty())
+ ui->labelCoinControlChangeLabel->setText("");
+ else if (!CBitcoinAddress(text.toStdString()).IsValid())
+ {
+ ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
+ ui->labelCoinControlChangeLabel->setText(tr("WARNING: Invalid Bitcoin address"));
+ }
+ else
+ {
+ QString associatedLabel = model->getAddressTableModel()->labelForAddress(text);
+ if (!associatedLabel.isEmpty())
+ ui->labelCoinControlChangeLabel->setText(associatedLabel);
+ else
+ {
+ CPubKey pubkey;
+ CKeyID keyid;
+ CBitcoinAddress(text.toStdString()).GetKeyID(keyid);
+ if (model->getPubKey(keyid, pubkey))
+ ui->labelCoinControlChangeLabel->setText(tr("(no label)"));
+ else
+ {
+ ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
+ ui->labelCoinControlChangeLabel->setText(tr("WARNING: unknown change address"));
+ }
+ }
+ }
+ }
+ }
+
+ // Coin Control: update labels
+ void SendCoinsDialog::coinControlUpdateLabels()
+ {
+ if (!model || !model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures())
+ return;
+ // set pay amounts
+ CoinControlDialog::payAmounts.clear();
+ for(int i = 0; i < ui->entries->count(); ++i)
+ {
+ SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget());
+ if(entry)
+ CoinControlDialog::payAmounts.append(entry->getValue().amount);
+ }
+ if (CoinControlDialog::coinControl->HasSelected())
+ {
+ // actual coin control calculation
+ CoinControlDialog::updateLabels(model, this);
+ // show coin control stats
+ ui->labelCoinControlAutomaticallySelected->hide();
+ ui->widgetCoinControl->show();
+ }
+ else
+ {
+ // hide coin control stats
+ ui->labelCoinControlAutomaticallySelected->show();
+ ui->widgetCoinControl->hide();
+ ui->labelCoinControlInsuffFunds->hide();
+ }
+}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 32bb61a..68424bb 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -2,6 +2,7 @@
#define SENDCOINSDIALOG_H
#include
+#include
namespace Ui {
class SendCoinsDialog;
@@ -49,6 +50,19 @@ private slots:
void on_sendButton_clicked();
void removeEntry(SendCoinsEntry* entry);
void updateDisplayUnit();
+ void coinControlFeatureChanged(bool);
+ void coinControlButtonClicked();
+ void coinControlChangeChecked(int);
+ void coinControlChangeEdited(const QString &);
+ void coinControlUpdateLabels();
+ void coinControlClipboardQuantity();
+ void coinControlClipboardAmount();
+ void coinControlClipboardFee();
+ void coinControlClipboardAfterFee();
+ void coinControlClipboardBytes();
+ void coinControlClipboardPriority();
+ void coinControlClipboardLowOutput();
+ void coinControlClipboardChange();
};
#endif // SENDCOINSDIALOG_H
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index f00cf1b..2bed6cb 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -23,7 +23,10 @@ SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
#if QT_VERSION >= 0x040700
/* Do not move this to the XML file, Qt before 4.7 will choke on it */
ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
+ ui->addAsLabel->setStyleSheet("background-color:#1f333e; color:white; border:none;");
ui->payTo->setPlaceholderText(tr("Enter a valid Diamond address"));
+ ui->payTo->setStyleSheet("background-color:#1f333e; color:white; border:none;");
+ ui->payAmount->setStyleSheet("background-color:#1f333e; color:white; border:none;");
#endif
setFocusPolicy(Qt::TabFocus);
setFocusProxy(ui->payTo);
@@ -72,6 +75,7 @@ void SendCoinsEntry::setModel(WalletModel *model)
if(model && model->getOptionsModel())
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+ connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged()));
clear();
}
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index 0ac14c1..4148128 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -39,6 +39,7 @@ public slots:
signals:
void removeEntry(SendCoinsEntry *entry);
+ void payAmountChanged();
private slots:
void on_deleteButton_clicked();
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 361e691..ae10db6 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -220,7 +220,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
strHTML += "" + tr("Transaction ID") + ": " + wtx.GetHash().ToString().c_str() + "
";
if (wtx.IsCoinBase() || wtx.IsCoinStake())
- strHTML += "
" + tr("Generated coins must mature 50 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
";
+ strHTML += "
" + tr("Generated coins must mature 200 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
";
//
// Debug view
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 18858e2..3e453d0 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -34,7 +34,42 @@ QList TransactionRecord::decomposeTransaction(const CWallet *
if (wtx.IsCoinStake())
{
// Stake generation
- parts.append(TransactionRecord(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut()));
+ TransactionRecord sub(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut());
+ CTxDestination stakingAddress, rewardAddress;
+ /* vout[0] is blank, just marks the transaction as stake
+ * vout[1] is the first stake output and therefore always related to
+ * the staking address. */
+ if (ExtractDestination(wtx.vout[1].scriptPubKey, stakingAddress)) {
+ if (ExtractDestination(wtx.vout[wtx.vout.size() - 1].scriptPubKey, rewardAddress)) {
+ /* If the staking address isn't in the wallet than this is an
+ * external scrape received from another wallet. */
+ if (!IsMine(*wallet, stakingAddress)) {
+ sub.type = TransactionRecord::ExternalScrape;
+ // In this instance the reward is always in the last output.
+ sub.credit = wtx.vout[wtx.vout.size() - 1].nValue;
+ sub.address = CBitcoinAddress(rewardAddress).ToString();
+ /* The reward address is not in the wallet but the address is
+ * so the reward went to a scrape, treat it like a normal mint
+ * but display the scrape address. */
+ } else if (!IsMine(*wallet, rewardAddress)) {
+ sub.type = TransactionRecord::ScrapeToExternal;
+ sub.address = CBitcoinAddress(rewardAddress).ToString();
+ /* The address is in the wallet but it's different than the staking
+ * address, display the reward address and the stake amount. */
+ } else if (CBitcoinAddress(stakingAddress).ToString() != CBitcoinAddress(rewardAddress).ToString()) {
+ sub.type = TransactionRecord::LocalScrape;
+ sub.address = CBitcoinAddress(rewardAddress).ToString();
+ // The reweard went to the same address as the staking address (not a scrape)
+ } else {
+ sub.address = CBitcoinAddress(stakingAddress).ToString();
+ }
+ // No destination in the last output (this should not happen)
+ } else {
+ sub.address = CBitcoinAddress(stakingAddress).ToString();
+ }
+ }
+
+ parts.append(sub);
}
else if (nNet > 0 || wtx.IsCoinBase())
{
@@ -197,7 +232,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
}
// For generated transactions, determine maturity
- if(type == TransactionRecord::Generated || type == TransactionRecord::StakeMint)
+ if(type == TransactionRecord::Generated || type == TransactionRecord::StakeMint || type == TransactionRecord::ExternalScrape || type == TransactionRecord::LocalScrape || type == TransactionRecord::ScrapeToExternal)
{
int64 nCredit = wtx.GetCredit(true);
if (nCredit == 0)
@@ -233,4 +268,3 @@ std::string TransactionRecord::getTxID()
{
return hash.ToString() + strprintf("-%03d", idx);
}
-
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index 8d4ab03..0b60931 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -69,7 +69,10 @@ class TransactionRecord
RecvWithAddress,
RecvFromOther,
SendToSelf,
- StakeMint
+ StakeMint,
+ ExternalScrape,
+ LocalScrape,
+ ScrapeToExternal
};
/** Number of confirmation needed for transaction */
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 0638a8b..c302f6b 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -295,14 +295,19 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons
status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
break;
}
- if(wtx->type == TransactionRecord::Generated || wtx->type == TransactionRecord::StakeMint)
+ if(wtx->type == TransactionRecord::Generated || wtx->type == TransactionRecord::StakeMint || wtx->type == TransactionRecord::ExternalScrape || wtx->type == TransactionRecord::LocalScrape || wtx->type == TransactionRecord::ScrapeToExternal)
{
switch(wtx->status.maturity)
{
case TransactionStatus::Immature:
- status += "\n" + tr("Mined balance will be available when it matures in %n more block(s)", "", wtx->status.matures_in);
+ wtx->type == TransactionRecord::ScrapeToExternal ? status += "\n" + tr("Minted balance will be available at reward address in %n more blocks", "",
+ wtx->status.matures_in) :
+ status += "\n" + tr("Mined balance will be available in %n more blocks", "",
+ wtx->status.matures_in);
break;
case TransactionStatus::Mature:
+ if (wtx->type == TransactionRecord::ScrapeToExternal)
+ status += "\n" + tr("Minted balance is available at the reward address not found in this wallet.");
break;
case TransactionStatus::MaturesWarning:
status += "\n" + tr("This block was not received by any other nodes and will probably not be accepted!");
@@ -360,9 +365,15 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const
case TransactionRecord::SendToSelf:
return tr("Payment to yourself");
case TransactionRecord::StakeMint:
- return tr("Mint");
+ return tr("Minted");
case TransactionRecord::Generated:
return tr("Mined");
+ case TransactionRecord::ExternalScrape:
+ return tr("External scrape");
+ case TransactionRecord::LocalScrape:
+ return tr("Local scrape");
+ case TransactionRecord::ScrapeToExternal:
+ return tr("Scraped to external");
default:
return QString();
}
@@ -373,12 +384,15 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx
switch(wtx->type)
{
case TransactionRecord::Generated:
+ {
+ QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit);
+ return QIcon(":/icons/tx_mined");
+ }
case TransactionRecord::StakeMint:
- {
- QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit);
- float dd = str.toFloat();
- return QIcon(":/icons/tx_mined");
- }
+ {
+ QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit);
+ return QIcon(":/icons/tx_minted");
+ }
case TransactionRecord::RecvWithAddress:
case TransactionRecord::RecvFromOther:
return QIcon(":/icons/tx_input");
@@ -400,6 +414,9 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b
case TransactionRecord::RecvWithAddress:
case TransactionRecord::SendToAddress:
case TransactionRecord::Generated:
+ case TransactionRecord::ExternalScrape:
+ case TransactionRecord::LocalScrape:
+ case TransactionRecord::ScrapeToExternal:
return lookupAddress(wtx->address, tooltip);
case TransactionRecord::SendToOther:
return QString::fromStdString(wtx->address);
@@ -417,6 +434,9 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
case TransactionRecord::RecvWithAddress:
case TransactionRecord::SendToAddress:
case TransactionRecord::Generated:
+ case TransactionRecord::ExternalScrape:
+ case TransactionRecord::LocalScrape:
+ case TransactionRecord::ScrapeToExternal:
{
QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
if(label.isEmpty())
@@ -435,7 +455,9 @@ QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool
QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit);
if(showUnconfirmed)
{
- if(!wtx->status.confirmed || wtx->status.maturity != TransactionStatus::Mature)
+ /* Always display ScrapeToExternal transactions as if the coins are
+ * immature because they are not and will never be in this wallet. */
+ if(!wtx->status.confirmed || wtx->status.maturity != TransactionStatus::Mature || wtx->type == TransactionRecord::ScrapeToExternal)
{
str = QString("[") + str + QString("]");
}
@@ -445,7 +467,7 @@ QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool
QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) const
{
- if(wtx->type == TransactionRecord::Generated || wtx->type == TransactionRecord::StakeMint)
+ if(wtx->type == TransactionRecord::Generated || wtx->type == TransactionRecord::StakeMint || wtx->type == TransactionRecord::ExternalScrape || wtx->type == TransactionRecord::LocalScrape)
{
switch(wtx->status.maturity)
{
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 564be3f..427fdb0 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -35,8 +35,7 @@ TransactionView::TransactionView(QWidget *parent) :
{
// Build filter row
setContentsMargins(0,0,0,0);
- setStyleSheet("background-color:rgba(255, 255, 255, 40); color: white;");
-
+ setStyleSheet("background-color:#1f333e; color: white;");
QHBoxLayout *hlayout = new QHBoxLayout();
hlayout->setContentsMargins(0,0,0,0);
@@ -76,7 +75,7 @@ TransactionView::TransactionView(QWidget *parent) :
typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
TransactionFilterProxy::TYPE(TransactionRecord::SendToOther));
typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
- typeWidget->addItem(tr("Mint"), TransactionFilterProxy::TYPE(TransactionRecord::StakeMint));
+ typeWidget->addItem(tr("Minted"), TransactionFilterProxy::TYPE(TransactionRecord::StakeMint));
typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
@@ -86,6 +85,7 @@ TransactionView::TransactionView(QWidget *parent) :
#if QT_VERSION >= 0x040700
/* Do not move this to the XML file, Qt before 4.7 will choke on it */
addressWidget->setPlaceholderText(tr("Enter address or label to search"));
+ addressWidget->setStyleSheet("background-color:#1f333e; color:white; border:none;");
#endif
hlayout->addWidget(addressWidget);
@@ -170,12 +170,12 @@ void TransactionView::setModel(WalletModel *model)
transactionView->setModel(transactionProxyModel);
transactionView->setAlternatingRowColors(true);
- transactionView->setStyleSheet("QTableView{alternate-background-color: rgb(37,59,72); background-color: rgb(60,93,112); selection-background-color: rgb(97,147,174);} QToolTip{background-color:#1f333e; color:white}");
+ transactionView->setStyleSheet("QTableView{alternate-background-color: rgb(37,59,72); background-color: rgb(60,93,112); selection-background-color: rgb(97,147,174);} QToolTip{background-color:#1f333e; color:white; border-style: none;}");
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
transactionView->setSortingEnabled(true);
- transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
+ transactionView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder);
transactionView->verticalHeader()->hide();
transactionView->horizontalHeader()->resizeSection(
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 34850d8..5e2b28f 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -129,7 +129,7 @@ bool WalletModel::validateAddress(const QString &address)
return addressParsed.IsValid();
}
-WalletModel::SendCoinsReturn WalletModel::sendCoins(const QString &txcomment, const QList &recipients)
+WalletModel::SendCoinsReturn WalletModel::sendCoins(const QString &txcomment, const QList &recipients, const CCoinControl *coinControl)
{
qint64 total = 0;
QSet setAddress;
@@ -161,12 +161,18 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QString &txcomment, co
return DuplicateAddress;
}
- if(total > getBalance())
+ int64 nBalance = 0;
+ std::vector vCoins;
+ wallet->AvailableCoins(vCoins, true, coinControl);
+
+ BOOST_FOREACH(const COutput& out, vCoins)
+ nBalance += out.tx->vout[out.i].nValue;
+ if(total > nBalance)
{
return AmountExceedsBalance;
}
- if((total + nTransactionFee) > getBalance())
+ if((total + nTransactionFee) > nBalance)
{
return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
}
@@ -189,11 +195,11 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QString &txcomment, co
std::string strTxComment = txcomment.toStdString();
if (!strTxComment.empty())
strTxComment = "text:" + strTxComment;
- bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strTxComment);
+ bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strTxComment, coinControl);
if(!fCreated)
{
- if((total + nFeeRequired) > wallet->GetBalance())
+ if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future
{
return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
}
@@ -247,20 +253,18 @@ TransactionTableModel *WalletModel::getTransactionTableModel()
return transactionTableModel;
}
-WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
-{
+WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const {
+
if(!wallet->IsCrypted())
- {
- return Unencrypted;
- }
- else if(wallet->IsLocked())
- {
- return Locked;
- }
+ return(Unencrypted);
+
+ if(wallet->IsLocked())
+ return(Locked);
+
+ if(fStakingOnly)
+ return(UnlockedStaking);
else
- {
- return Unlocked;
- }
+ return(Unlocked);
}
bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
@@ -352,15 +356,22 @@ void WalletModel::unsubscribeFromCoreSignals()
WalletModel::UnlockContext WalletModel::requestUnlock()
{
bool was_locked = getEncryptionStatus() == Locked;
+
+ if((!was_locked) && fStakingOnly) {
+ setWalletLocked(true);
+ was_locked = getEncryptionStatus() == Locked;
+ }
+
if(was_locked)
{
// Request UI to unlock wallet
emit requireUnlock();
}
+
// 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, was_locked && !fStakingOnly));
}
WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
@@ -384,3 +395,70 @@ void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
*this = rhs;
rhs.relock = false;
}
+
+ bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
+ {
+ return wallet->GetPubKey(address, vchPubKeyOut);
+ }
+
+ // returns a list of COutputs from COutPoints
+ void WalletModel::getOutputs(const std::vector& vOutpoints, std::vector& vOutputs)
+ {
+ BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
+ {
+ if (!wallet->mapWallet.count(outpoint.hash)) continue;
+ COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, wallet->mapWallet[outpoint.hash].GetDepthInMainChain());
+ vOutputs.push_back(out);
+ }
+ }
+
+ // AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
+ void WalletModel::listCoins(std::map >& mapCoins) const
+ {
+ std::vector vCoins;
+ wallet->AvailableCoins(vCoins);
+ std::vector vLockedCoins;
+
+ // add locked coins
+ BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
+ {
+ if (!wallet->mapWallet.count(outpoint.hash)) continue;
+ COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, wallet->mapWallet[outpoint.hash].GetDepthInMainChain());
+ vCoins.push_back(out);
+ }
+
+ BOOST_FOREACH(const COutput& out, vCoins)
+ {
+ COutput cout = out;
+
+ while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
+ {
+ if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
+ cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0);
+ }
+
+ CTxDestination address;
+ if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue;
+ mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
+ }
+ }
+
+ bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
+ {
+ return false;
+ }
+
+ void WalletModel::lockCoin(COutPoint& output)
+ {
+ return;
+ }
+
+ void WalletModel::unlockCoin(COutPoint& output)
+ {
+ return;
+ }
+
+ void WalletModel::listLockedCoins(std::vector& vOutpts)
+ {
+ return;
+ }
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 5890b42..ef50f29 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -2,6 +2,8 @@
#define WALLETMODEL_H
#include
+#include
+#include