aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bitcoin-qt.pro4
-rw-r--r--contrib/gitian-descriptors/README2
-rw-r--r--contrib/gitian-descriptors/gitian-win32.yml4
-rw-r--r--contrib/gitian-descriptors/qt-win32.yml8
-rwxr-xr-xcontrib/verifysfbinaries/verify.sh119
-rw-r--r--doc/release-process.txt4
-rw-r--r--src/bitcoinrpc.cpp3
-rw-r--r--src/bitcoinrpc.h1
-rw-r--r--src/irc.cpp5
-rw-r--r--src/main.cpp8
-rw-r--r--src/main.h18
-rw-r--r--src/makefile.linux-mingw2
-rw-r--r--src/makefile.mingw3
-rw-r--r--src/makefile.osx2
-rw-r--r--src/makefile.unix2
-rw-r--r--src/net.cpp2
-rw-r--r--src/qt/bitcoingui.cpp58
-rw-r--r--src/qt/bitcoingui.h3
-rw-r--r--src/rpcrawtransaction.cpp141
-rw-r--r--src/rpcwallet.cpp63
-rw-r--r--src/test/rpc_tests.cpp99
-rw-r--r--src/txdb.cpp3
-rw-r--r--src/wallet.cpp14
23 files changed, 443 insertions, 125 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index cd9755e8fa..9f24b55186 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -95,13 +95,13 @@ contains(BITCOIN_NEED_QT_PLUGINS, 1) {
INCLUDEPATH += src/leveldb/include src/leveldb/helpers
LIBS += $$PWD/src/leveldb/libleveldb.a $$PWD/src/leveldb/libmemenv.a
!windows {
- genleveldb.commands = cd $$PWD/src/leveldb ; $(MAKE) libleveldb.a libmemenv.a
+ genleveldb.commands = cd $$PWD/src/leveldb && $(MAKE) libleveldb.a libmemenv.a
} else {
# make an educated guess about what the ranlib command is called
isEmpty(QMAKE_RANLIB) {
QMAKE_RANLIB = $$replace(QMAKE_STRIP, strip, ranlib)
}
- genleveldb.commands = cd $$PWD/src/leveldb ; CC=$$QMAKE_CC CXX=$$QMAKE_CXX TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$$BOOST_INCLUDE_PATH" LDFLAGS="-L$$BOOST_LIB_PATH" $(MAKE) libleveldb.a libmemenv.a ; $$QMAKE_RANLIB $$PWD/src/leveldb/libleveldb.a ; $$QMAKE_RANLIB $$PWD/src/leveldb/libmemenv.a
+ genleveldb.commands = cd $$PWD/src/leveldb && CC=$$QMAKE_CC CXX=$$QMAKE_CXX TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$$BOOST_INCLUDE_PATH" LDFLAGS="-L$$BOOST_LIB_PATH" $(MAKE) libleveldb.a libmemenv.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libleveldb.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libmemenv.a
}
genleveldb.target = $$PWD/src/leveldb/libleveldb.a
genleveldb.depends = FORCE
diff --git a/contrib/gitian-descriptors/README b/contrib/gitian-descriptors/README
index 1d3910b994..46c7668ab9 100644
--- a/contrib/gitian-descriptors/README
+++ b/contrib/gitian-descriptors/README
@@ -31,7 +31,7 @@ Once you've got the right hardware and software:
wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
wget 'https://downloads.sourceforge.net/project/libpng/zlib/1.2.6/zlib-1.2.6.tar.gz'
wget 'https://downloads.sourceforge.net/project/libpng/libpng15/older-releases/1.5.9/libpng-1.5.9.tar.gz'
- wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.2.tar.gz'
+ wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.3.tar.gz'
cd ../..
cd gitian-builder
diff --git a/contrib/gitian-descriptors/gitian-win32.yml b/contrib/gitian-descriptors/gitian-win32.yml
index c5979614d3..9df42a0bec 100644
--- a/contrib/gitian-descriptors/gitian-win32.yml
+++ b/contrib/gitian-descriptors/gitian-win32.yml
@@ -15,14 +15,14 @@ remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
files:
-- "qt-win32-4.8.2-gitian-r1.zip"
+- "qt-win32-4.8.3-gitian-r1.zip"
- "boost-win32-1.50.0-gitian2.zip"
- "bitcoin-deps-0.0.5.zip"
script: |
#
mkdir $HOME/qt
cd $HOME/qt
- unzip ../build/qt-win32-4.8.2-gitian-r1.zip
+ unzip ../build/qt-win32-4.8.3-gitian-r1.zip
cd $HOME/build/
export PATH=$PATH:$HOME/qt/bin/
#
diff --git a/contrib/gitian-descriptors/qt-win32.yml b/contrib/gitian-descriptors/qt-win32.yml
index 87887dec87..0b711790e6 100644
--- a/contrib/gitian-descriptors/qt-win32.yml
+++ b/contrib/gitian-descriptors/qt-win32.yml
@@ -11,15 +11,15 @@ packages:
reference_datetime: "2011-01-30 00:00:00"
remotes: []
files:
-- "qt-everywhere-opensource-src-4.8.2.tar.gz"
+- "qt-everywhere-opensource-src-4.8.3.tar.gz"
script: |
INSTDIR="$HOME/qt/"
mkdir $INSTDIR
SRCDIR="$INSTDIR/src/"
mkdir $SRCDIR
#
- tar xzf qt-everywhere-opensource-src-4.8.2.tar.gz
- cd qt-everywhere-opensource-src-4.8.2
+ tar xzf qt-everywhere-opensource-src-4.8.3.tar.gz
+ cd qt-everywhere-opensource-src-4.8.3
sed 's/$TODAY/2011-01-30/' -i configure
sed 's/i686-pc-mingw32-/i586-mingw32msvc-/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
sed --posix 's|QMAKE_CFLAGS\t\t= -pipe|QMAKE_CFLAGS\t\t= -pipe -isystem /usr/i586-mingw32msvc/include/ -frandom-seed=qtbuild|' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
@@ -51,4 +51,4 @@ script: |
# as zip stores file timestamps, use faketime to intercept stat calls to set dates for all files to reference date
export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
- zip -r $OUTDIR/qt-win32-4.8.2-gitian-r1.zip *
+ zip -r $OUTDIR/qt-win32-4.8.3-gitian-r1.zip *
diff --git a/contrib/verifysfbinaries/verify.sh b/contrib/verifysfbinaries/verify.sh
new file mode 100755
index 0000000000..336de3ec1f
--- /dev/null
+++ b/contrib/verifysfbinaries/verify.sh
@@ -0,0 +1,119 @@
+#!/bin/bash
+
+### This script attempts to download the signature file SHA256SUMS.asc from SourceForge
+### It first checks if the signature passes, and then downloads the files specified in
+### the file, and checks if the hashes of these files match those that are specified
+### in the signature file.
+### The script returns 0 if everything passes the checks. It returns 1 if either the
+### signature check or the hash check doesn't pass. If an error occurs the return value is 2
+
+function clean_up {
+ for file in $*
+ do
+ rm "$file" 2> /dev/null
+ done
+}
+
+WORKINGDIR="/tmp/bitcoin"
+TMPFILE="hashes.tmp"
+
+#this URL is used if a version number is not specified as an argument to the script
+SIGNATUREFILE="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.7.1/test/SHA256SUMS.asc"
+
+SIGNATUREFILENAME="SHA256SUMS.asc"
+RCSUBDIR="test/"
+BASEDIR="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/"
+VERSIONPREFIX="bitcoin-"
+RCVERSIONSTRING="rc"
+
+if [ ! -d "$WORKINGDIR" ]; then
+ mkdir "$WORKINGDIR"
+fi
+
+cd "$WORKINGDIR"
+
+#test if a version number has been passed as an argument
+if [ -n "$1" ]; then
+ #let's also check if the version number includes the prefix 'bitcoin-',
+ # and add this prefix if it doesn't
+ if [[ $1 == "$VERSIONPREFIX"* ]]; then
+ VERSION="$1"
+ else
+ VERSION="$VERSIONPREFIX$1"
+ fi
+
+ #now let's see if the version string contains "rc", and strip it off if it does
+ # and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME
+ if [[ $VERSION == *"$RCVERSIONSTRING"* ]]; then
+ BASEDIR="$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/"
+ BASEDIR="$BASEDIR$RCSUBDIR"
+ else
+ BASEDIR="$BASEDIR$VERSION/"
+ fi
+
+ SIGNATUREFILE="$BASEDIR$SIGNATUREFILENAME"
+else
+ BASEDIR="${SIGNATUREFILE%/*}/"
+fi
+
+#first we fetch the file containing the signature
+WGETOUT=$(wget -N "$BASEDIR$SIGNATUREFILENAME" 2>&1)
+
+#and then see if wget completed successfully
+if [ $? -ne 0 ]; then
+ echo "Error: couldn't fetch signature file. Have you specified the version number in the following format?"
+ echo "[bitcoin-]<version>-[rc[0-9]] (example: bitcoin-0.7.1-rc1)"
+ echo "wget output:"
+ echo "$WGETOUT"|sed 's/^/\t/g'
+ exit 2
+fi
+
+#then we check it
+GPGOUT=$(gpg --yes --decrypt --output "$TMPFILE" "$SIGNATUREFILENAME" 2>&1)
+
+#return value 0: good signature
+#return value 1: bad signature
+#return value 2: gpg error
+
+RET="$?"
+if [ $RET -ne 0 ]; then
+ if [ $RET -eq 1 ]; then
+ #and notify the user if it's bad
+ echo "Bad signature."
+ elif [ $RET -eq 2 ]; then
+ #or if a gpg error has occured
+ echo "gpg error. Do you have Gavin's code signing key installed?"
+ fi
+
+ echo "gpg output:"
+ echo "$GPGOUT"|sed 's/^/\t/g'
+ clean_up $SIGNATUREFILENAME $TMPFILE
+ exit "$RET"
+fi
+
+#here we extract the filenames from the signature file
+FILES=$(awk '{print $2}' "$TMPFILE")
+
+#and download these one by one
+for file in in $FILES
+do
+ wget --quiet -N "$BASEDIR$file"
+done
+
+#check hashes
+DIFF=$(diff <(sha256sum $FILES) "$TMPFILE")
+
+if [ $? -eq 1 ]; then
+ echo "Hashes don't match."
+ echo "Offending files:"
+ echo "$DIFF"|grep "^<"|awk '{print "\t"$3}'
+ exit 1
+elif [ $? -gt 1 ]; then
+ echo "Error executing 'diff'"
+ exit 2
+fi
+
+#everything matches! clean up the mess
+clean_up $FILES $SIGNATUREFILENAME $TMPFILE
+
+exit 0
diff --git a/doc/release-process.txt b/doc/release-process.txt
index 2a3eb17c20..02f0c47f47 100644
--- a/doc/release-process.txt
+++ b/doc/release-process.txt
@@ -30,12 +30,12 @@
wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz'
wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2'
wget 'http://downloads.sourceforge.net/project/boost/boost/1.50.0/boost_1_50_0.tar.bz2'
- wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.2.tar.gz'
+ wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.3.tar.gz'
cd ..
./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-win32.yml
mv build/out/boost-win32-1.50.0-gitian2.zip inputs/
./bin/gbuild ../bitcoin/contrib/gitian-descriptors/qt-win32.yml
- mv build/out/qt-win32-4.8.2-gitian-r1.zip inputs/
+ mv build/out/qt-win32-4.8.3-gitian-r1.zip inputs/
./bin/gbuild ../bitcoin/contrib/gitian-descriptors/deps-win32.yml
mv build/out/bitcoin-deps-0.0.5.zip inputs/
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 725037addc..21e37c75e1 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -234,6 +234,7 @@ static const CRPCCommand vRPCCommands[] =
{ "sendfrom", &sendfrom, false, false },
{ "sendmany", &sendmany, false, false },
{ "addmultisigaddress", &addmultisigaddress, false, false },
+ { "createmultisig", &createmultisig, true, true },
{ "getrawmempool", &getrawmempool, true, false },
{ "getblock", &getblock, false, false },
{ "getblockhash", &getblockhash, false, false },
@@ -1160,6 +1161,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]);
+ if (strMethod == "createmultisig" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "createmultisig" && n > 1) ConvertTo<Array>(params[1]);
if (strMethod == "listunspent" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listunspent" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]);
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 9290697664..dc4dc303a8 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -158,6 +158,7 @@ extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value createmultisig(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp);
diff --git a/src/irc.cpp b/src/irc.cpp
index 17d5ff1a5a..e8471a6630 100644
--- a/src/irc.cpp
+++ b/src/irc.cpp
@@ -192,6 +192,8 @@ void ThreadIRCSeed(void* parg)
// Make this thread recognisable as the IRC seeding thread
RenameThread("bitcoin-ircseed");
+ printf("ThreadIRCSeed started\n");
+
try
{
ThreadIRCSeed2(parg);
@@ -218,7 +220,8 @@ void ThreadIRCSeed2(void* parg)
if (!GetBoolArg("-irc", false))
return;
- printf("ThreadIRCSeed started\n");
+ printf("ThreadIRCSeed trying to connect...\n");
+
int nErrorWait = 10;
int nRetryWait = 10;
int nNameRetry = 0;
diff --git a/src/main.cpp b/src/main.cpp
index b1fdc2ed52..43bd5dd472 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1382,14 +1382,8 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmod
const CCoins &coins = inputs.GetCoins(prevout.hash);
// Verify signature
- if (!VerifySignature(coins, *this, i, fStrictPayToScriptHash, fStrictEncodings, 0)) {
- // only during transition phase for P2SH: do not invoke anti-DoS code for
- // potentially old clients relaying bad P2SH transactions
- if (fStrictPayToScriptHash && VerifySignature(coins, *this, i, false, fStrictEncodings, 0))
- return error("CheckInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
-
+ if (!VerifySignature(coins, *this, i, fStrictPayToScriptHash, fStrictEncodings, 0))
return DoS(100,error("CheckInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
- }
}
}
}
diff --git a/src/main.h b/src/main.h
index 1751ccc562..744c0e4b51 100644
--- a/src/main.h
+++ b/src/main.h
@@ -24,21 +24,34 @@ class CNode;
class CBlockIndexWorkComparator;
+/** The maximum allowed size for a serialized block, in bytes (network rule) */
static const unsigned int MAX_BLOCK_SIZE = 1000000;
+/** The maximum size for mined blocks */
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
+/** The maximum allowed number of signature check operations in a block (network rule) */
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
+/** The maximum number of orphan transactions kept in memory */
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
+/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
+/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
+/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
+/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
+/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
+/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
static const int64 MIN_TX_FEE = 50000;
+/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */
static const int64 MIN_RELAY_TX_FEE = 10000;
+/** No amount larger than this (in satoshi) is valid */
static const int64 MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
+/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
-// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
+/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
#ifdef USE_UPNP
static const int fHaveUPnP = true;
@@ -1825,6 +1838,9 @@ public:
// Calculate statistics about the unspent transaction output set
virtual bool GetStats(CCoinsStats &stats);
+
+ // As we use CCoinsViews polymorphically, have a virtual destructor
+ virtual ~CCoinsView() {};
};
/** CCoinsView backed by another CCoinsView */
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index f4adbb2bff..64268dd0aa 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -92,7 +92,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += -I"$(CURDIR)/leveldb/include"
DEFS += -I"$(CURDIR)/leveldb/helpers"
leveldb/libleveldb.a:
- @echo "Building LevelDB ..."; cd leveldb; TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" make libleveldb.a libmemenv.a; cd ..
+ @echo "Building LevelDB ..." && cd leveldb && CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" make libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd ..
obj/leveldb.o: leveldb/libleveldb.a
obj/build.h: FORCE
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 945ec77099..85d63e9ceb 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -94,8 +94,9 @@ test check: test_bitcoin.exe FORCE
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
+# TODO: If this fails, try adding a ranlib libleveldb.a && ranlib libmemenv.a
leveldb/libleveldb.a:
- cd leveldb; make libleveldb.a libmemenv.a; cd ..
+ cd leveldb && make libleveldb.a libmemenv.a && cd ..
obj/leveldb.o: leveldb/libleveldb.lib
obj/%.o: %.cpp $(HEADERS)
diff --git a/src/makefile.osx b/src/makefile.osx
index f3e17d0d13..9629545c0a 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -128,7 +128,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- @echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..
+ @echo "Building LevelDB ..." && cd leveldb && make libleveldb.a libmemenv.a && cd ..
obj/leveldb.o: leveldb/libleveldb.a
# auto-generated dependencies:
diff --git a/src/makefile.unix b/src/makefile.unix
index df05f7990a..653f512e82 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -144,7 +144,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- @echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..;
+ @echo "Building LevelDB ..." && cd leveldb && make libleveldb.a libmemenv.a && cd ..
obj/leveldb.o: leveldb/libleveldb.a
# auto-generated dependencies:
diff --git a/src/net.cpp b/src/net.cpp
index 272e6ff0b4..b54f8c15f7 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1309,6 +1309,8 @@ void DumpAddresses()
void ThreadDumpAddress2(void* parg)
{
+ printf("ThreadDumpAddress started\n");
+
vnThreadsRunning[THREAD_DUMPADDRESS]++;
while (!fShutdown)
{
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index c92403833a..988f4185b9 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -176,6 +176,9 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
// Clicking on "Sign Message" in the receive coins page sends you to the sign message tab
connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString)));
+ // Install event filter to be able to catch status tip events (QEvent::StatusTip)
+ this->installEventFilter(this);
+
gotoOverviewPage();
}
@@ -193,31 +196,36 @@ void BitcoinGUI::createActions()
QActionGroup *tabGroup = new QActionGroup(this);
overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
- overviewAction->setToolTip(tr("Show general overview of wallet"));
+ overviewAction->setStatusTip(tr("Show general overview of wallet"));
+ overviewAction->setToolTip(overviewAction->statusTip());
overviewAction->setCheckable(true);
overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
tabGroup->addAction(overviewAction);
sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
- sendCoinsAction->setToolTip(tr("Send coins to a Bitcoin address"));
+ sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
+ sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
sendCoinsAction->setCheckable(true);
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this);
- receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments"));
+ receiveCoinsAction->setStatusTip(tr("Show the list of addresses for receiving payments"));
+ receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
receiveCoinsAction->setCheckable(true);
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
- historyAction->setToolTip(tr("Browse transaction history"));
+ historyAction->setStatusTip(tr("Browse transaction history"));
+ historyAction->setToolTip(historyAction->statusTip());
historyAction->setCheckable(true);
historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
tabGroup->addAction(historyAction);
addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
- addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels"));
+ addressBookAction->setStatusTip(tr("Edit the list of stored addresses and labels"));
+ addressBookAction->setToolTip(addressBookAction->statusTip());
addressBookAction->setCheckable(true);
addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5));
tabGroup->addAction(addressBookAction);
@@ -234,33 +242,37 @@ void BitcoinGUI::createActions()
connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
- quitAction->setToolTip(tr("Quit application"));
+ quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin"), this);
- aboutAction->setToolTip(tr("Show information about Bitcoin"));
+ aboutAction->setStatusTip(tr("Show information about Bitcoin"));
aboutAction->setMenuRole(QAction::AboutRole);
aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
- aboutQtAction->setToolTip(tr("Show information about Qt"));
+ aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
- optionsAction->setToolTip(tr("Modify configuration options for Bitcoin"));
+ optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin"));
optionsAction->setMenuRole(QAction::PreferencesRole);
toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
+ toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
- encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
+ encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
encryptWalletAction->setCheckable(true);
backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
- backupWalletAction->setToolTip(tr("Backup wallet to another location"));
+ backupWalletAction->setStatusTip(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"));
+ changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this);
+ signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this);
+ verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
- exportAction->setToolTip(tr("Export the data in the current tab to a file"));
+ exportAction->setStatusTip(tr("Export the data in the current tab to a file"));
+ exportAction->setToolTip(exportAction->statusTip());
openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this);
- openRPCConsoleAction->setToolTip(tr("Open debugging and diagnostic console"));
+ openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
@@ -338,7 +350,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
#endif
if(trayIcon)
{
- trayIcon->setToolTip(tr("Bitcoin client") + QString(" ") + tr("[testnet]"));
+ // Just attach " [testnet]" to the existing tooltip
+ trayIcon->setToolTip(trayIcon->toolTip() + QString(" ") + tr("[testnet]"));
trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet"));
}
@@ -472,6 +485,9 @@ void BitcoinGUI::setNumConnections(int count)
void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
{
+ // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text)
+ statusBar()->clearMessage();
+
// don't show / hide progress bar and its label if we have no connection to the network
if (!clientModel || (clientModel->getNumConnections() == 0 && !clientModel->isImporting()))
{
@@ -748,6 +764,18 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
event->acceptProposedAction();
}
+bool BitcoinGUI::eventFilter(QObject *object, QEvent *event)
+{
+ // Catch status tip events
+ if (event->type() == QEvent::StatusTip)
+ {
+ // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
+ if (progressBarLabel->isVisible() && progressBar->isVisible())
+ return true;
+ }
+ return QMainWindow::eventFilter(object, event);
+}
+
void BitcoinGUI::handleURI(QString strURI)
{
// URI has to be valid
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index c67e887c0f..a48911ee7f 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -52,6 +52,7 @@ protected:
void closeEvent(QCloseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
+ bool eventFilter(QObject *object, QEvent *event);
private:
ClientModel *clientModel;
@@ -172,7 +173,7 @@ private slots:
/** 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 */
+ /** Simply calls showNormalIfMinimized(true) for use in SLOT() macro */
void toggleHidden();
};
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 4714bfdd20..e82f4ad91d 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -18,6 +18,39 @@ using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
+//
+// Utilities: convert hex-encoded Values
+// (throws error if not hex).
+//
+uint256 ParseHashV(const Value& v, string strName)
+{
+ string strHex;
+ if (v.type() == str_type)
+ strHex = v.get_str();
+ if (!IsHex(strHex)) // Note: IsHex("") is false
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ uint256 result;
+ result.SetHex(strHex);
+ return result;
+}
+uint256 ParseHashO(const Object& o, string strKey)
+{
+ return ParseHashV(find_value(o, strKey), strKey);
+}
+vector<unsigned char> ParseHexV(const Value& v, string strName)
+{
+ string strHex;
+ if (v.type() == str_type)
+ strHex = v.get_str();
+ if (!IsHex(strHex))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ return ParseHex(strHex);
+}
+vector<unsigned char> ParseHexO(const Object& o, string strKey)
+{
+ return ParseHexV(find_value(o, strKey), strKey);
+}
+
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
{
txnouttype type;
@@ -109,8 +142,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
"If verbose is non-zero, returns an Object\n"
"with information about <txid>.");
- uint256 hash;
- hash.SetHex(params[0].get_str());
+ uint256 hash = ParseHashV(params[0], "parameter 1");
bool fVerbose = false;
if (params.size() > 1)
@@ -178,10 +210,10 @@ Value listunspent(const Array& params, bool fHelp)
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue;
- if(setAddress.size())
+ if (setAddress.size())
{
CTxDestination address;
- if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
+ if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
continue;
if (!setAddress.count(address))
@@ -194,6 +226,17 @@ Value listunspent(const Array& params, bool fHelp)
entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
entry.push_back(Pair("vout", out.i));
entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
+ if (pk.IsPayToScriptHash())
+ {
+ CTxDestination address;
+ if (ExtractDestination(pk, address))
+ {
+ const CScriptID& hash = boost::get<const CScriptID&>(address);
+ CScript redeemScript;
+ if (pwalletMain->GetCScript(hash, redeemScript))
+ entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
+ }
+ }
entry.push_back(Pair("amount",ValueFromAmount(nValue)));
entry.push_back(Pair("confirmations",out.nDepth));
results.push_back(entry);
@@ -221,16 +264,11 @@ Value createrawtransaction(const Array& params, bool fHelp)
CTransaction rawTx;
- BOOST_FOREACH(Value& input, inputs)
+ BOOST_FOREACH(const Value& input, inputs)
{
const Object& o = input.get_obj();
- const Value& txid_v = find_value(o, "txid");
- if (txid_v.type() != str_type)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
- string txid = txid_v.get_str();
- if (!IsHex(txid))
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
+ uint256 txid = ParseHashO(o, "txid");
const Value& vout_v = find_value(o, "vout");
if (vout_v.type() != int_type)
@@ -239,7 +277,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
if (nOutput < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
- CTxIn in(COutPoint(uint256(txid), nOutput));
+ CTxIn in(COutPoint(txid, nOutput));
rawTx.vin.push_back(in);
}
@@ -274,9 +312,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
"decoderawtransaction <hex string>\n"
"Return a JSON object representing the serialized, hex-encoded transaction.");
- RPCTypeCheck(params, list_of(str_type));
-
- vector<unsigned char> txData(ParseHex(params[0].get_str()));
+ vector<unsigned char> txData(ParseHexV(params[0], "argument"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
try {
@@ -296,7 +332,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 4)
throw runtime_error(
- "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
+ "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
"Sign inputs for raw transaction (serialized, hex-encoded).\n"
"Second optional argument (may be null) is an array of previous transaction outputs that\n"
"this transaction depends on but may not yet be in the block chain.\n"
@@ -311,7 +347,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
- vector<unsigned char> txData(ParseHex(params[0].get_str()));
+ vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
vector<CTransaction> txVariants;
while (!ssData.empty())
@@ -352,6 +388,28 @@ Value signrawtransaction(const Array& params, bool fHelp)
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
}
+ bool fGivenKeys = false;
+ CBasicKeyStore tempKeystore;
+ if (params.size() > 2 && params[2].type() != null_type)
+ {
+ fGivenKeys = true;
+ Array keys = params[2].get_array();
+ BOOST_FOREACH(Value k, keys)
+ {
+ CBitcoinSecret vchSecret;
+ bool fGood = vchSecret.SetString(k.get_str());
+ if (!fGood)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
+ CKey key;
+ bool fCompressed;
+ CSecret secret = vchSecret.GetSecret(fCompressed);
+ key.SetSecret(secret, fCompressed);
+ tempKeystore.AddKey(key);
+ }
+ }
+ else
+ EnsureWalletIsUnlocked();
+
// Add previous txouts given in the RPC call:
if (params.size() > 1 && params[1].type() != null_type)
{
@@ -363,22 +421,15 @@ Value signrawtransaction(const Array& params, bool fHelp)
Object prevOut = p.get_obj();
- RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
+ RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
- string txidHex = find_value(prevOut, "txid").get_str();
- if (!IsHex(txidHex))
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
- uint256 txid;
- txid.SetHex(txidHex);
+ uint256 txid = ParseHashO(prevOut, "txid");
int nOut = find_value(prevOut, "vout").get_int();
if (nOut < 0)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
- string pkHex = find_value(prevOut, "scriptPubKey").get_str();
- if (!IsHex(pkHex))
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
- vector<unsigned char> pkData(ParseHex(pkHex));
+ vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
CCoins coins;
@@ -391,33 +442,23 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
// what todo if txid is known, but the actual output isn't?
}
+ if ((unsigned int)nOut >= coins.vout.size())
+ coins.vout.resize(nOut+1);
coins.vout[nOut].scriptPubKey = scriptPubKey;
coins.vout[nOut].nValue = 0; // we don't know the actual output value
view.SetCoins(txid, coins);
- }
- }
- bool fGivenKeys = false;
- CBasicKeyStore tempKeystore;
- if (params.size() > 2 && params[2].type() != null_type)
- {
- fGivenKeys = true;
- Array keys = params[2].get_array();
- BOOST_FOREACH(Value k, keys)
- {
- CBitcoinSecret vchSecret;
- bool fGood = vchSecret.SetString(k.get_str());
- if (!fGood)
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
- CKey key;
- bool fCompressed;
- CSecret secret = vchSecret.GetSecret(fCompressed);
- key.SetSecret(secret, fCompressed);
- tempKeystore.AddKey(key);
+ // if redeemScript given and not using the local wallet (private keys
+ // given), add redeemScript to the tempKeystore so it can be signed:
+ Value v = find_value(prevOut, "redeemScript");
+ if (fGivenKeys && scriptPubKey.IsPayToScriptHash() && !(v == Value::null))
+ {
+ vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
+ CScript redeemScript(rsData.begin(), rsData.end());
+ tempKeystore.AddCScript(redeemScript);
+ }
}
}
- else
- EnsureWalletIsUnlocked();
const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
@@ -484,10 +525,8 @@ Value sendrawtransaction(const Array& params, bool fHelp)
"sendrawtransaction <hex string>\n"
"Submits raw transaction (serialized, hex-encoded) to local node and network.");
- RPCTypeCheck(params, list_of(str_type));
-
// parse hex string from parameter
- vector<unsigned char> txData(ParseHex(params[0].get_str()));
+ vector<unsigned char> txData(ParseHexV(params[0], "parameter"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 57e8eb55c6..29b3298b99 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -702,22 +702,13 @@ Value sendmany(const Array& params, bool fHelp)
return wtx.GetHash().GetHex();
}
-Value addmultisigaddress(const Array& params, bool fHelp)
+//
+// Used by addmultisigaddress / createmultisig:
+//
+static CScript _createmultisig(const Array& params)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
- {
- string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
- "Add a nrequired-to-sign multisignature address to the wallet\"\n"
- "each key is a Bitcoin address or hex-encoded public key\n"
- "If [account] is specified, assign address to [account].";
- throw runtime_error(msg);
- }
-
int nRequired = params[0].get_int();
const Array& keys = params[1].get_array();
- string strAccount;
- if (params.size() > 2)
- strAccount = AccountFromValue(params[2]);
// Gather public keys
if (nRequired < 1)
@@ -760,10 +751,28 @@ Value addmultisigaddress(const Array& params, bool fHelp)
throw runtime_error(" Invalid public key: "+ks);
}
}
+ CScript result;
+ result.SetMultisig(nRequired, pubkeys);
+ return result;
+}
+
+Value addmultisigaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 3)
+ {
+ string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
+ "Add a nrequired-to-sign multisignature address to the wallet\"\n"
+ "each key is a Bitcoin address or hex-encoded public key\n"
+ "If [account] is specified, assign address to [account].";
+ throw runtime_error(msg);
+ }
+
+ string strAccount;
+ if (params.size() > 2)
+ strAccount = AccountFromValue(params[2]);
// Construct using pay-to-script-hash:
- CScript inner;
- inner.SetMultisig(nRequired, pubkeys);
+ CScript inner = _createmultisig(params);
CScriptID innerID = inner.GetID();
pwalletMain->AddCScript(inner);
@@ -771,6 +780,30 @@ Value addmultisigaddress(const Array& params, bool fHelp)
return CBitcoinAddress(innerID).ToString();
}
+Value createmultisig(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 2)
+ {
+ string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
+ "Creates a multi-signature address and returns a json object\n"
+ "with keys:\n"
+ "address : bitcoin address\n"
+ "redeemScript : hex-encoded redemption script";
+ throw runtime_error(msg);
+ }
+
+ // Construct using pay-to-script-hash:
+ CScript inner = _createmultisig(params);
+ CScriptID innerID = inner.GetID();
+ CBitcoinAddress address(innerID);
+
+ Object result;
+ result.push_back(Pair("address", address.ToString()));
+ result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
+
+ return result;
+}
+
struct tallyitem
{
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index eb820ade6d..f8fe443b87 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -1,5 +1,6 @@
-#include <boost/test/unit_test.hpp>
+#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
#include "base58.h"
#include "util.h"
@@ -22,14 +23,7 @@ createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
return result;
}
-// This can be removed this when addmultisigaddress is enabled on main net:
-struct TestNetFixture
-{
- TestNetFixture() { fTestNet = true; }
- ~TestNetFixture() { fTestNet = false; }
-};
-
-BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture)
+BOOST_AUTO_TEST_CASE(rpc_addmultisig)
{
rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
@@ -66,4 +60,91 @@ BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture)
BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
}
+static Value CallRPC(string args)
+{
+ vector<string> vArgs;
+ boost::split(vArgs, args, boost::is_any_of(" \t"));
+ string strMethod = vArgs[0];
+ vArgs.erase(vArgs.begin());
+ Array params = RPCConvertValues(strMethod, vArgs);
+
+ rpcfn_type method = tableRPC[strMethod]->actor;
+ try {
+ Value result = (*method)(params, false);
+ return result;
+ }
+ catch (Object& objError)
+ {
+ throw runtime_error(find_value(objError, "message").get_str());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(rpc_rawparams)
+{
+ // Test raw transaction API argument handling
+ Value r;
+
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
+ BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
+ BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
+ BOOST_CHECK_THROW(r=CallRPC("listunspent 0 1 [] extra"), runtime_error);
+ BOOST_CHECK(r.get_array().empty());
+
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [] {}"));
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), runtime_error);
+
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error);
+ string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx));
+ BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
+ BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0);
+ BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error);
+
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx));
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY"));
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY"));
+ BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error);
+
+ // Only check failure cases for sendrawtransaction, there's no network to send to...
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC(string("sendrawtransaction ")+rawtx+" extra"), runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(rpc_rawsign)
+{
+ Value r;
+ // input is a 1-of-2 multisig (so is output):
+ string prevout =
+ "[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
+ "\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\","
+ "\"redeemScript\":\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"}]";
+ r = CallRPC(string("createrawtransaction ")+prevout+" "+
+ "{\"3HqAe9LtNBjnsfM4CyYaWTnvCaUYT7v4oZ\":11}");
+ string notsigned = r.get_str();
+ string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
+ string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
+ r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]");
+ BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false);
+ r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]");
+ BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 67d15cb58f..6550f57876 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -58,7 +58,8 @@ bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockI
CLevelDBBatch batch;
for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
BatchWriteCoins(batch, it->first, it->second);
- BatchWriteHashBestChain(batch, pindex->GetBlockHash());
+ if (pindex)
+ BatchWriteHashBestChain(batch, pindex->GetBlockHash());
return db.WriteBatch(batch);
}
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 552d4868c4..ae9f695e9f 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -820,21 +820,17 @@ void CWallet::ReacceptWalletTransactions()
void CWalletTx::RelayWalletTransaction()
{
- CCoinsViewCache& coins = *pcoinsTip;
BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
{
- if (!tx.IsCoinBase())
- {
- uint256 hash = tx.GetHash();
- if (!coins.HaveCoins(hash))
- RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
+ if (!tx.IsCoinBase()) {
+ if (tx.GetDepthInMainChain() == 0)
+ RelayMessage(CInv(MSG_TX, tx.GetHash()), (CTransaction)tx);
}
}
if (!IsCoinBase())
{
- uint256 hash = GetHash();
- if (!coins.HaveCoins(hash))
- {
+ if (GetDepthInMainChain() == 0) {
+ uint256 hash = GetHash();
printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
}