aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release-process.md37
-rwxr-xr-xqa/rpc-tests/receivedby.py225
-rw-r--r--qa/rpc-tests/util.py4
-rw-r--r--qa/rpc-tests/util.sh8
-rwxr-xr-xqa/rpc-tests/zapwallettxes.sh161
-rw-r--r--src/Makefile.am2
-rw-r--r--src/bloom.cpp3
-rw-r--r--src/bloom.h2
-rw-r--r--src/chainparams.cpp2
-rw-r--r--src/clientversion.h2
-rw-r--r--src/compat/glibc_compat.cpp2
-rw-r--r--src/compat/glibc_sanity.cpp2
-rw-r--r--src/core.cpp25
-rw-r--r--src/core.h99
-rw-r--r--src/init.cpp36
-rw-r--r--src/main.cpp59
-rw-r--r--src/main.h8
-rw-r--r--src/miner.cpp22
-rw-r--r--src/net.cpp24
-rw-r--r--src/net.h6
-rw-r--r--src/netbase.h2
-rw-r--r--src/qt/addressbookpage.cpp2
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/coincontroldialog.cpp21
-rw-r--r--src/qt/notificator.h2
-rw-r--r--src/qt/optionsdialog.cpp2
-rw-r--r--src/qt/optionsmodel.cpp2
-rw-r--r--src/qt/receiverequestdialog.cpp2
-rw-r--r--src/qt/rpcconsole.cpp3
-rw-r--r--src/qt/rpcconsole.h1
-rw-r--r--src/qt/test/test_main.cpp2
-rw-r--r--src/rpcrawtransaction.cpp16
-rw-r--r--src/script.cpp6
-rw-r--r--src/script.h13
-rw-r--r--src/serialize.h34
-rw-r--r--src/test/DoS_tests.cpp12
-rw-r--r--src/test/accounting_tests.cpp12
-rw-r--r--src/test/bloom_tests.cpp26
-rw-r--r--src/test/miner_tests.cpp12
-rw-r--r--src/test/multisig_tests.cpp8
-rw-r--r--src/test/pmt_tests.cpp4
-rw-r--r--src/test/script_P2SH_tests.cpp18
-rw-r--r--src/test/script_tests.cpp12
-rw-r--r--src/test/sighash_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp14
-rw-r--r--src/test/wallet_tests.cpp10
-rw-r--r--src/util.h2
-rw-r--r--src/wallet.cpp37
-rw-r--r--src/wallet.h6
-rw-r--r--src/walletdb.cpp10
-rw-r--r--src/walletdb.h4
52 files changed, 773 insertions, 261 deletions
diff --git a/doc/release-process.md b/doc/release-process.md
index 5b96e53753..affe6ed13a 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -50,8 +50,7 @@ Release Process
wget 'ftp://ftp.simplesystems.org/pub/png/src/history/libpng16/libpng-1.6.8.tar.gz'
wget 'https://fukuchi.org/works/qrencode/qrencode-3.4.3.tar.bz2'
wget 'https://downloads.sourceforge.net/project/boost/boost/1.55.0/boost_1_55_0.tar.bz2'
- wget 'https://svn.boost.org/trac/boost/raw-attachment/ticket/7262/boost-mingw.patch' -O \
- boost-mingw-gas-cross-compile-2013-03-03.patch
+ wget 'https://svn.boost.org/trac/boost/raw-attachment/ticket/7262/boost-mingw.patch' -O boost-mingw-gas-cross-compile-2013-03-03.patch
wget 'https://download.qt-project.org/official_releases/qt/5.2/5.2.0/single/qt-everywhere-opensource-src-5.2.0.tar.gz'
wget 'https://download.qt-project.org/archive/qt/4.6/qt-everywhere-opensource-src-4.6.4.tar.gz'
wget 'https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.bz2'
@@ -61,10 +60,8 @@ Release Process
wget 'http://www.opensource.apple.com/tarballs/ld64/ld64-127.2.tar.gz'
wget 'http://cdrkit.org/releases/cdrkit-1.1.11.tar.gz'
wget 'https://github.com/theuni/libdmg-hfsplus/archive/libdmg-hfsplus-v0.1.tar.gz'
- wget 'http://llvm.org/releases/3.2/clang+llvm-3.2-x86-linux-ubuntu-12.04.tar.gz' -O \
- clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz
- wget 'https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff' -O \
- cdrkit-deterministic.patch
+ wget 'http://llvm.org/releases/3.2/clang+llvm-3.2-x86-linux-ubuntu-12.04.tar.gz' -O clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz
+ wget 'https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff' -O cdrkit-deterministic.patch
cd ..
./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-linux.yml
mv build/out/boost-*.zip inputs/
@@ -180,34 +177,6 @@ Commit your signature to gitian.sigs:
### After 3 or more people have gitian-built, repackage gitian-signed zips:
-From a directory containing bitcoin source, gitian.sigs and gitian zips
-
- export VERSION=(new version, e.g. 0.8.0)
- mkdir bitcoin-${VERSION}-linux-gitian
- pushd bitcoin-${VERSION}-linux-gitian
- unzip ../bitcoin-${VERSION}-linux-gitian.zip
- mkdir gitian
- cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/
- for signer in $(ls ../gitian.sigs/${VERSION}/); do
- cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert
- cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig
- done
- zip -r bitcoin-${VERSION}-linux-gitian.zip *
- cp bitcoin-${VERSION}-linux-gitian.zip ../
- popd
- mkdir bitcoin-${VERSION}-win-gitian
- pushd bitcoin-${VERSION}-win-gitian
- unzip ../bitcoin-${VERSION}-win-gitian.zip
- mkdir gitian
- cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/
- for signer in $(ls ../gitian.sigs/${VERSION}-win/); do
- cp ../gitian.sigs/${VERSION}-win/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert
- cp ../gitian.sigs/${VERSION}-win/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig
- done
- zip -r bitcoin-${VERSION}-win-gitian.zip *
- cp bitcoin-${VERSION}-win-gitian.zip ../
- popd
-
- Upload gitian zips to SourceForge
- Announce the release:
diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py
new file mode 100755
index 0000000000..7f2d79b3c1
--- /dev/null
+++ b/qa/rpc-tests/receivedby.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Bitcoin Core developers
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# Exercise the listtransactions API
+
+# Add python-bitcoinrpc to module search path:
+
+import os
+import sys
+sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "python-bitcoinrpc"))
+
+import json
+import shutil
+import subprocess
+import tempfile
+import traceback
+
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+
+def get_sub_array_from_array(object_array, to_match):
+ '''
+ Finds and returns a sub array from an array of arrays.
+ to_match should be a unique idetifier of a sub array
+ '''
+ num_matched = 0
+ for item in object_array:
+ all_match = True
+ for key,value in to_match.items():
+ if item[key] != value:
+ all_match = False
+ if not all_match:
+ continue
+ return item
+ return []
+
+def check_array_result(object_array, to_match, expected, should_not_find = False):
+ """
+ Pass in array of JSON objects, a dictionary with key/value pairs
+ to match against, and another dictionary with expected key/value
+ pairs.
+ If the should_not_find flag is true, to_match should not be found in object_array
+ """
+ if should_not_find == True:
+ expected = { }
+ num_matched = 0
+ for item in object_array:
+ all_match = True
+ for key,value in to_match.items():
+ if item[key] != value:
+ all_match = False
+ if not all_match:
+ continue
+ for key,value in expected.items():
+ if item[key] != value:
+ raise AssertionError("%s : expected %s=%s"%(str(item), str(key), str(value)))
+ num_matched = num_matched+1
+ if num_matched == 0 and should_not_find != True:
+ raise AssertionError("No objects matched %s"%(str(to_match)))
+ if num_matched > 0 and should_not_find == True:
+ raise AssertionError("Objects was matched %s"%(str(to_match)))
+
+def run_test(nodes):
+ '''
+ listreceivedbyaddress Test
+ '''
+ # Send from node 0 to 1
+ addr = nodes[1].getnewaddress()
+ txid = nodes[0].sendtoaddress(addr, 0.1)
+ sync_mempools(nodes)
+
+ #Check not listed in listreceivedbyaddress because has 0 confirmations
+ check_array_result(nodes[1].listreceivedbyaddress(),
+ {"address":addr},
+ { },
+ True)
+ #Bury Tx under 10 block so it will be returned by listreceivedbyaddress
+ nodes[1].setgenerate(True, 10)
+ sync_blocks(nodes)
+ check_array_result(nodes[1].listreceivedbyaddress(),
+ {"address":addr},
+ {"address":addr, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]})
+ #With min confidence < 10
+ check_array_result(nodes[1].listreceivedbyaddress(5),
+ {"address":addr},
+ {"address":addr, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]})
+ #With min confidence > 10, should not find Tx
+ check_array_result(nodes[1].listreceivedbyaddress(11),{"address":addr},{ },True)
+
+ #Empty Tx
+ addr = nodes[1].getnewaddress()
+ check_array_result(nodes[1].listreceivedbyaddress(0,True),
+ {"address":addr},
+ {"address":addr, "account":"", "amount":0, "confirmations":0, "txids":[]})
+
+ '''
+ getreceivedbyaddress Test
+ '''
+ # Send from node 0 to 1
+ addr = nodes[1].getnewaddress()
+ txid = nodes[0].sendtoaddress(addr, 0.1)
+ sync_mempools(nodes)
+
+ #Check balance is 0 because of 0 confirmations
+ balance = nodes[1].getreceivedbyaddress(addr)
+ if balance != Decimal("0.0"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+
+ #Check balance is 0.1
+ balance = nodes[1].getreceivedbyaddress(addr,0)
+ if balance != Decimal("0.1"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+
+ #Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress
+ nodes[1].setgenerate(True, 10)
+ sync_blocks(nodes)
+ balance = nodes[1].getreceivedbyaddress(addr)
+ if balance != Decimal("0.1"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+
+ '''
+ listreceivedbyaccount + getreceivedbyaccount Test
+ '''
+ #set pre-state
+ addrArr = nodes[1].getnewaddress()
+ account = nodes[1].getaccount(addrArr)
+ received_by_account_json = get_sub_array_from_array(nodes[1].listreceivedbyaccount(),{"account":account})
+ if len(received_by_account_json) == 0:
+ raise AssertionError("No accounts found in node")
+ balance_by_account = rec_by_accountArr = nodes[1].getreceivedbyaccount(account)
+
+ txid = nodes[0].sendtoaddress(addr, 0.1)
+
+ # listreceivedbyaccount should return received_by_account_json because of 0 confirmations
+ check_array_result(nodes[1].listreceivedbyaccount(),
+ {"account":account},
+ received_by_account_json)
+
+ # getreceivedbyaddress should return same balance because of 0 confirmations
+ balance = nodes[1].getreceivedbyaccount(account)
+ if balance != balance_by_account:
+ raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+
+ nodes[1].setgenerate(True, 10)
+ sync_blocks(nodes)
+ # listreceivedbyaccount should return updated account balance
+ check_array_result(nodes[1].listreceivedbyaccount(),
+ {"account":account},
+ {"account":received_by_account_json["account"], "amount":(received_by_account_json["amount"] + Decimal("0.1"))})
+
+ # getreceivedbyaddress should return updates balance
+ balance = nodes[1].getreceivedbyaccount(account)
+ if balance != balance_by_account + Decimal("0.1"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+
+ #Create a new account named "mynewaccount" that has a 0 balance
+ nodes[1].getaccountaddress("mynewaccount")
+ received_by_account_json = get_sub_array_from_array(nodes[1].listreceivedbyaccount(0,True),{"account":"mynewaccount"})
+ if len(received_by_account_json) == 0:
+ raise AssertionError("No accounts found in node")
+
+ # Test includeempty of listreceivedbyaccount
+ if received_by_account_json["amount"] != Decimal("0.0"):
+ raise AssertionError("Wrong balance returned by listreceivedbyaccount, %0.2f"%(received_by_account_json["amount"]))
+
+ # Test getreceivedbyaccount for 0 amount accounts
+ balance = nodes[1].getreceivedbyaccount("mynewaccount")
+ if balance != Decimal("0.0"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+
+def main():
+ import optparse
+
+ parser = optparse.OptionParser(usage="%prog [options]")
+ parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
+ help="Leave bitcoinds and test.* datadir on exit or error")
+ parser.add_option("--srcdir", dest="srcdir", default="../../src",
+ help="Source directory containing bitcoind/bitcoin-cli (default: %default%)")
+ parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
+ help="Root directory for datadirs")
+ (options, args) = parser.parse_args()
+
+ os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']
+
+ check_json_precision()
+
+ success = False
+ nodes = []
+ try:
+ print("Initializing test directory "+options.tmpdir)
+ if not os.path.isdir(options.tmpdir):
+ os.makedirs(options.tmpdir)
+ initialize_chain(options.tmpdir)
+
+ nodes = start_nodes(2, options.tmpdir)
+ connect_nodes(nodes[1], 0)
+ sync_blocks(nodes)
+
+ run_test(nodes)
+
+ success = True
+
+ except AssertionError as e:
+ print("Assertion failed: "+e.message)
+ except Exception as e:
+ print("Unexpected exception caught during testing: "+str(e))
+ traceback.print_tb(sys.exc_info()[2])
+
+ if not options.nocleanup:
+ print("Cleaning up")
+ stop_nodes(nodes)
+ wait_bitcoinds()
+ shutil.rmtree(options.tmpdir)
+
+ if success:
+ print("Tests successful")
+ sys.exit(0)
+ else:
+ print("Failed")
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py
index eded098c7c..27c9f778f6 100644
--- a/qa/rpc-tests/util.py
+++ b/qa/rpc-tests/util.py
@@ -182,6 +182,10 @@ def wait_bitcoinds():
def connect_nodes(from_connection, node_num):
ip_port = "127.0.0.1:"+str(p2p_port(node_num))
from_connection.addnode(ip_port, "onetry")
+ # poll until version handshake complete to avoid race conditions
+ # with transaction relaying
+ while any(peer['version'] == 0 for peer in from_connection.getpeerinfo()):
+ time.sleep(0.1)
def find_output(node, txid, amount):
"""
diff --git a/qa/rpc-tests/util.sh b/qa/rpc-tests/util.sh
index 1e7bd6a7ee..b726ef627f 100644
--- a/qa/rpc-tests/util.sh
+++ b/qa/rpc-tests/util.sh
@@ -38,6 +38,10 @@ function AssertEqual {
if (( $( echo "$1 == $2" | bc ) == 0 ))
then
echoerr "AssertEqual: $1 != $2"
+ declare -f CleanUp > /dev/null 2>&1
+ if [[ $? -eq 0 ]] ; then
+ CleanUp
+ fi
exit 1
fi
}
@@ -49,6 +53,10 @@ function CheckBalance {
if (( $( echo "$B == $EXPECT" | bc ) == 0 ))
then
echoerr "bad balance: $B (expected $2)"
+ declare -f CleanUp > /dev/null 2>&1
+ if [[ $? -eq 0 ]] ; then
+ CleanUp
+ fi
exit 1
fi
}
diff --git a/qa/rpc-tests/zapwallettxes.sh b/qa/rpc-tests/zapwallettxes.sh
new file mode 100755
index 0000000000..bc52a7dacd
--- /dev/null
+++ b/qa/rpc-tests/zapwallettxes.sh
@@ -0,0 +1,161 @@
+#!/usr/bin/env bash
+
+# Test -zapwallettxes=<mode>
+
+if [ $# -lt 1 ]; then
+ echo "Usage: $0 path_to_binaries"
+ echo "e.g. $0 ../../src"
+ exit 1
+fi
+
+set -f
+
+BITCOIND=${1}/bitcoind
+CLI=${1}/bitcoin-cli
+
+DIR="${BASH_SOURCE%/*}"
+SENDANDWAIT="${DIR}/send.sh"
+if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
+. "$DIR/util.sh"
+
+D=$(mktemp -d test.XXXXX)
+
+D1=${D}/node1
+CreateDataDir "$D1" port=11000 rpcport=11001
+B1ARGS="-datadir=$D1"
+$BITCOIND $B1ARGS &
+B1PID=$!
+
+D2=${D}/node2
+CreateDataDir "$D2" port=11010 rpcport=11011
+B2ARGS="-datadir=$D2"
+$BITCOIND $B2ARGS &
+B2PID=$!
+
+function CleanUp {
+$CLI $B2ARGS stop > /dev/null 2>&1
+wait $B2PID
+$CLI $B1ARGS stop > /dev/null 2>&1
+wait $B1PID
+
+rm -rf $D
+}
+
+# 110 blocks, 10 mature == 500 XBT
+$CLI $B1ARGS setgenerate true 110
+$CLI $B2ARGS setgenerate true 110
+
+CheckBalance "$B1ARGS" 500
+CheckBalance "$B2ARGS" 500
+
+# Send 10 XBT
+TXID1_DEFAULT=$($CLI $B1ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 10)
+TXID2_DEFAULT=$($CLI $B2ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 10)
+
+CheckBalance $B1ARGS 490
+CheckBalance $B2ARGS 490
+
+# Move 10 XBT to testaccount
+TMP=$($CLI $B1ARGS move "" "testaccount" 10)
+TMP=$($CLI $B2ARGS move "" "testaccount" 10)
+
+CheckBalance $B1ARGS 10 "testaccount"
+CheckBalance $B2ARGS 10 "testaccount"
+
+# Send 1 XBT from testaccount
+TXID1_TESTACCOUNT=$($CLI $B1ARGS sendfrom "testaccount" "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1)
+TXID2_TESTACCOUNT=$($CLI $B2ARGS sendfrom "testaccount" "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1)
+
+CheckBalance $B1ARGS 9 "testaccount"
+CheckBalance $B2ARGS 9 "testaccount"
+
+CheckBalance $B1ARGS 489
+CheckBalance $B2ARGS 489
+
+# Confirm transactions
+$CLI $B1ARGS setgenerate true 1
+$CLI $B2ARGS setgenerate true 1
+
+# Create unconfirmed transaction
+TXID1_UNCONFIRMED=$($CLI $B1ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1)
+TXID2_UNCONFIRMED=$($CLI $B2ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1)
+
+# check balance (we created another 50 and spent 1 in the meantime)
+CheckBalance $B1ARGS 538
+CheckBalance $B2ARGS 538
+
+# Safety check, if unconfirmed transactions are there
+$CLI $B1ARGS gettransaction $TXID1_UNCONFIRMED > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "gettransaction1_1: $TXID1_UNCONFIRMED failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B2ARGS gettransaction $TXID2_UNCONFIRMED > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "gettransaction2_1: $TXID2_UNCONFIRMED failed"
+ CleanUp
+ exit 1
+fi
+
+# stop nodes
+$CLI $B2ARGS stop > /dev/null 2>&1
+wait $B2PID
+$CLI $B1ARGS stop > /dev/null 2>&1
+wait $B1PID
+
+# restart nodes with -zapwallettxes
+$BITCOIND -zapwallettxes=1 $B1ARGS &
+B1PID=$!
+$BITCOIND -zapwallettxes=2 $B2ARGS &
+B2PID=$!
+
+# check if confirmed transactions are there
+$CLI $B1ARGS gettransaction $TXID1_DEFAULT > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "check confirmed transaction 1: $TXID1_DEFAULT failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B2ARGS gettransaction $TXID2_DEFAULT > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "check confirmed transaction 2: $TXID2_DEFAULT failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B1ARGS gettransaction $TXID1_TESTACCOUNT > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "check confirmed transaction 3: $TXID1_TESTACCOUNT failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B2ARGS gettransaction $TXID2_TESTACCOUNT > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "check confirmed transaction 4: $TXID2_TESTACCOUNT failed"
+ CleanUp
+ exit 1
+fi
+
+# check if unconfirmed transaction is gone
+$CLI $B1ARGS gettransaction $TXID1_UNCONFIRMED > /dev/null 2>&1
+if [[ $? -eq 0 ]] ; then
+ echoerr "check unconfirmed transaction 1: $TXID1_UNCONFIRMED failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B2ARGS gettransaction $TXID2_UNCONFIRMED > /dev/null 2>&1
+if [[ $? -eq 0 ]] ; then
+ echoerr "check unconfirmed transaction 2: $TXID2_UNCONFIRMED failed"
+ CleanUp
+ exit 1
+fi
+
+# check zapwallet mode 1, testaccount balance must be 9 (keeping transaction metadata)
+CheckBalance $B1ARGS 9 "testaccount"
+
+# check zapwallet mode 2, testaccount balance must be 10 (dropping transaction metadata)
+CheckBalance $B2ARGS 10 "testaccount"
+
+echo "Tests successful, cleaning up"
+CleanUp
+exit 0
diff --git a/src/Makefile.am b/src/Makefile.am
index 3948ca0780..5ecded442c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,7 @@ $(LIBLEVELDB) $(LIBMEMENV):
endif
BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
-BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BITCOIN_CONFIG_INCLUDES) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
+BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
noinst_LIBRARIES = \
libbitcoin_server.a \
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 1bfcbd406f..26e366179c 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -99,7 +99,7 @@ bool CBloomFilter::IsWithinSizeConstraints() const
return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
}
-bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash)
+bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
{
bool fFound = false;
// Match if the filter contains the hash of tx
@@ -108,6 +108,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& ha
return true;
if (isEmpty)
return false;
+ const uint256& hash = tx.GetHash();
if (contains(hash))
fFound = true;
diff --git a/src/bloom.h b/src/bloom.h
index 75e3f38c55..956bead87f 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -83,7 +83,7 @@ public:
bool IsWithinSizeConstraints() const;
// Also adds any outputs which match the filter to the filter (to match their spending txes)
- bool IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash);
+ bool IsRelevantAndUpdate(const CTransaction& tx);
// Checks for empty and full filters to avoid wasting cpu
void UpdateEmptyFull();
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 31eac62d48..afbae6fc57 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -127,7 +127,7 @@ public:
// CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
// vMerkleTree: 4a5e1e
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
- CTransaction txNew;
+ CMutableTransaction txNew;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
diff --git a/src/clientversion.h b/src/clientversion.h
index 29b4aa3764..a30bbff06b 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -2,7 +2,7 @@
#define CLIENTVERSION_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#else
//
// client versioning and copyright year
diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp
index bb870c01f8..22f82e4259 100644
--- a/src/compat/glibc_compat.cpp
+++ b/src/compat/glibc_compat.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include <cstddef>
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
index 6e5bae8a48..d93602e0fe 100644
--- a/src/compat/glibc_sanity.cpp
+++ b/src/compat/glibc_sanity.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include <cstddef>
diff --git a/src/core.cpp b/src/core.cpp
index 6039986e6c..6c5ee1c0f8 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -91,11 +91,34 @@ std::string CFeeRate::ToString() const
return result;
}
-uint256 CTransaction::GetHash() const
+CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
+CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
+
+uint256 CMutableTransaction::GetHash() const
{
return SerializeHash(*this);
}
+void CTransaction::UpdateHash() const
+{
+ *const_cast<uint256*>(&hash) = SerializeHash(*this);
+}
+
+CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { }
+
+CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {
+ UpdateHash();
+}
+
+CTransaction& CTransaction::operator=(const CTransaction &tx) {
+ *const_cast<int*>(&nVersion) = tx.nVersion;
+ *const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
+ *const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
+ *const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
+ *const_cast<uint256*>(&hash) = tx.hash;
+ return *this;
+}
+
int64_t CTransaction::GetValueOut() const
{
int64_t nValueOut = 0;
diff --git a/src/core.h b/src/core.h
index 0e59129349..27fda95552 100644
--- a/src/core.h
+++ b/src/core.h
@@ -203,49 +203,59 @@ public:
};
+struct CMutableTransaction;
+
/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
*/
class CTransaction
{
+private:
+ /** Memory only. */
+ const uint256 hash;
+ void UpdateHash() const;
+
public:
static CFeeRate minTxFee;
static CFeeRate minRelayTxFee;
static const int CURRENT_VERSION=1;
- int nVersion;
- std::vector<CTxIn> vin;
- std::vector<CTxOut> vout;
- unsigned int nLockTime;
- CTransaction()
- {
- SetNull();
- }
+ // The local variables are made const to prevent unintended modification
+ // without updating the cached hash value. However, CTransaction is not
+ // actually immutable; deserialization and assignment are implemented,
+ // and bypass the constness. This is safe, as they update the entire
+ // structure, including the hash.
+ const int nVersion;
+ const std::vector<CTxIn> vin;
+ const std::vector<CTxOut> vout;
+ const unsigned int nLockTime;
- IMPLEMENT_SERIALIZE
- (
- READWRITE(this->nVersion);
+ /** Construct a CTransaction that qualifies as IsNull() */
+ CTransaction();
+
+ /** Convert a CMutableTransaction into a CTransaction. */
+ CTransaction(const CMutableTransaction &tx);
+
+ CTransaction& operator=(const CTransaction& tx);
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(*const_cast<int*>(&this->nVersion));
nVersion = this->nVersion;
- READWRITE(vin);
- READWRITE(vout);
- READWRITE(nLockTime);
+ READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
+ READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
+ READWRITE(*const_cast<unsigned int*>(&nLockTime));
+ if (fRead)
+ UpdateHash();
)
- void SetNull()
- {
- nVersion = CTransaction::CURRENT_VERSION;
- vin.clear();
- vout.clear();
- nLockTime = 0;
+ bool IsNull() const {
+ return vin.empty() && vout.empty();
}
- bool IsNull() const
- {
- return (vin.empty() && vout.empty());
+ const uint256& GetHash() const {
+ return hash;
}
- uint256 GetHash() const;
-
// Return sum of txouts.
int64_t GetValueOut() const;
// GetValueIn() is a method on CCoinsViewCache, because
@@ -261,22 +271,43 @@ public:
friend bool operator==(const CTransaction& a, const CTransaction& b)
{
- return (a.nVersion == b.nVersion &&
- a.vin == b.vin &&
- a.vout == b.vout &&
- a.nLockTime == b.nLockTime);
+ return a.hash == b.hash;
}
friend bool operator!=(const CTransaction& a, const CTransaction& b)
{
- return !(a == b);
+ return a.hash != b.hash;
}
-
std::string ToString() const;
void print() const;
};
+/** A mutable version of CTransaction. */
+struct CMutableTransaction
+{
+ int nVersion;
+ std::vector<CTxIn> vin;
+ std::vector<CTxOut> vout;
+ unsigned int nLockTime;
+
+ CMutableTransaction();
+ CMutableTransaction(const CTransaction& tx);
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(vin);
+ READWRITE(vout);
+ READWRITE(nLockTime);
+ )
+
+ /** Compute the hash of this CMutableTransaction. This is computed on the
+ * fly, as opposed to GetHash() in CTransaction, which uses a cached result.
+ */
+ uint256 GetHash() const;
+};
+
/** wrapper for CTxOut that provides a more compact serialization */
class CTxOutCompressor
{
@@ -465,12 +496,6 @@ public:
uint256 BuildMerkleTree() const;
- const uint256 &GetTxHash(unsigned int nIndex) const {
- assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
- assert(nIndex < vtx.size());
- return vMerkleTree[nIndex];
- }
-
std::vector<uint256> GetMerkleBranch(int nIndex) const;
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
void print() const;
diff --git a/src/init.cpp b/src/init.cpp
index 12d2d1bb44..7ef3bc5dac 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -4,7 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "init.h"
@@ -260,7 +260,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + _("(default: wallet.dat)") + "\n";
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
- strUsage += " -zapwallettxes " + _("Clear list of wallet transactions (diagnostic tool; implies -rescan)") + "\n";
+ strUsage += " -zapwallettxes=<mode> " + _("Delete all wallet transactions and only recover those part of the blockchain through -rescan on startup") + "\n";
+ strUsage += " " + _("(default: 1, 1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)") + "\n";
#endif
strUsage += "\n" + _("Debugging/Testing options:") + "\n";
@@ -536,7 +537,7 @@ bool AppInit2(boost::thread_group& threadGroup)
// -zapwallettx implies a rescan
if (GetBoolArg("-zapwallettxes", false)) {
if (SoftSetBoolArg("-rescan", true))
- LogPrintf("AppInit2 : parameter interaction: -zapwallettxes=1 -> setting -rescan=1\n");
+ LogPrintf("AppInit2 : parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n");
}
// Make sure enough file descriptors are available
@@ -993,11 +994,15 @@ bool AppInit2(boost::thread_group& threadGroup)
pwalletMain = NULL;
LogPrintf("Wallet disabled!\n");
} else {
+
+ // needed to restore wallet transaction meta data after -zapwallettxes
+ std::vector<CWalletTx> vWtx;
+
if (GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
pwalletMain = new CWallet(strWalletFile);
- DBErrors nZapWalletRet = pwalletMain->ZapWalletTx();
+ DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted"));
return false;
@@ -1092,6 +1097,29 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
pwalletMain->SetBestChain(chainActive.GetLocator());
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<uint256, CWalletTx>::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();
+ }
+ }
+ }
}
} // (!fDisableWallet)
#else // ENABLE_WALLET
diff --git a/src/main.cpp b/src/main.cpp
index 006ec7cabc..d3f04b95fa 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -130,8 +130,8 @@ namespace {
namespace {
struct CMainSignals {
- // Notifies listeners of updated transaction data (passing hash, transaction, and optionally the block it is found in.
- boost::signals2::signal<void (const uint256 &, const CTransaction &, const CBlock *)> SyncTransaction;
+ // Notifies listeners of updated transaction data (transaction, and optionally the block it is found in.
+ boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction;
// Notifies listeners of an erased transaction (currently disabled, requires transaction replacement).
boost::signals2::signal<void (const uint256 &)> EraseTransaction;
// Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible).
@@ -146,7 +146,7 @@ struct CMainSignals {
}
void RegisterWallet(CWalletInterface* pwalletIn) {
- g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3));
+ g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
g_signals.EraseTransaction.connect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1));
g_signals.UpdatedTransaction.connect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1));
@@ -160,7 +160,7 @@ void UnregisterWallet(CWalletInterface* pwalletIn) {
g_signals.SetBestChain.disconnect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1));
g_signals.UpdatedTransaction.disconnect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.EraseTransaction.disconnect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1));
- g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3));
+ g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
}
void UnregisterAllWallets() {
@@ -172,8 +172,8 @@ void UnregisterAllWallets() {
g_signals.SyncTransaction.disconnect_all_slots();
}
-void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) {
- g_signals.SyncTransaction(hash, tx, pblock);
+void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) {
+ g_signals.SyncTransaction(tx, pblock);
}
//////////////////////////////////////////////////////////////////////////////
@@ -952,7 +952,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
pool.addUnchecked(hash, entry);
}
- g_signals.SyncTransaction(hash, tx, NULL);
+ g_signals.SyncTransaction(tx, NULL);
return true;
}
@@ -1479,7 +1479,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev)
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash)
+void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
{
bool ret;
// mark inputs spent
@@ -1494,7 +1494,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
}
// add outputs
- ret = inputs.SetCoins(txhash, CCoins(tx, nHeight));
+ ret = inputs.SetCoins(tx.GetHash(), CCoins(tx, nHeight));
assert(ret);
}
@@ -1767,8 +1767,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) {
- for (unsigned int i = 0; i < block.vtx.size(); i++) {
- uint256 hash = block.GetTxHash(i);
+ BOOST_FOREACH(const CTransaction& tx, block.vtx) {
+ const uint256& hash = tx.GetHash();
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30");
@@ -1829,11 +1829,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
}
CTxUndo txundo;
- UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i));
+ UpdateCoins(tx, state, view, txundo, pindex->nHeight);
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
- vPos.push_back(std::make_pair(block.GetTxHash(i), pos));
+ vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64_t nTime = GetTimeMicros() - nStart;
@@ -1892,13 +1892,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
assert(ret);
// Watch for transactions paying to me
- for (unsigned int i = 0; i < block.vtx.size(); i++)
- g_signals.SyncTransaction(block.GetTxHash(i), block.vtx[i], &block);
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ g_signals.SyncTransaction(tx, &block);
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
g_signals.UpdatedTransaction(hashPrevBestCoinBase);
- hashPrevBestCoinBase = block.GetTxHash(0);
+ hashPrevBestCoinBase = block.vtx[0].GetHash();
return true;
}
@@ -1996,7 +1996,7 @@ bool static DisconnectTip(CValidationState &state) {
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- SyncWithWallets(tx.GetHash(), tx, NULL);
+ SyncWithWallets(tx, NULL);
}
return true;
}
@@ -2036,11 +2036,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
// Tell wallet about transactions that went from mempool
// to conflicted:
BOOST_FOREACH(const CTransaction &tx, txConflicted) {
- SyncWithWallets(tx.GetHash(), tx, NULL);
+ SyncWithWallets(tx, NULL);
}
// ... and about transactions that got confirmed:
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- SyncWithWallets(tx.GetHash(), tx, &block);
+ SyncWithWallets(tx, &block);
}
return true;
}
@@ -2381,16 +2381,11 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed");
- // Build the merkle tree already. We need it anyway later, and it makes the
- // block cache the transaction hashes, which means they don't need to be
- // recalculated many times during this block's validation.
- block.BuildMerkleTree();
-
// Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack:
set<uint256> uniqueTx;
- for (unsigned int i = 0; i < block.vtx.size(); i++) {
- uniqueTx.insert(block.GetTxHash(i));
+ BOOST_FOREACH(const CTransaction &tx, block.vtx) {
+ uniqueTx.insert(tx.GetHash());
}
if (uniqueTx.size() != block.vtx.size())
return state.DoS(100, error("CheckBlock() : duplicate transaction"),
@@ -2406,7 +2401,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
REJECT_INVALID, "bad-blk-sigops", true);
// Check merkle root
- if (fCheckMerkleRoot && block.hashMerkleRoot != block.vMerkleTree.back())
+ if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"),
REJECT_INVALID, "bad-txnmrklroot", true);
@@ -2682,8 +2677,8 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
- uint256 hash = block.vtx[i].GetHash();
- if (filter.IsRelevantAndUpdate(block.vtx[i], hash))
+ const uint256& hash = block.vtx[i].GetHash();
+ if (filter.IsRelevantAndUpdate(block.vtx[i]))
{
vMatch.push_back(true);
vMatchedTxn.push_back(make_pair(i, hash));
@@ -3832,7 +3827,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
{
mempool.check(pcoinsTip);
- RelayTransaction(tx, inv.hash);
+ RelayTransaction(tx);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
vEraseQueue.push_back(inv.hash);
@@ -3862,7 +3857,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
{
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx, orphanHash);
+ RelayTransaction(orphanTx);
mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash));
vWorkQueue.push_back(orphanHash);
vEraseQueue.push_back(orphanHash);
@@ -3947,7 +3942,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CTransaction tx;
bool fInMemPool = mempool.lookup(hash, tx);
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
- if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx, hash)) ||
+ if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) ||
(!pfrom->pfilter))
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
diff --git a/src/main.h b/src/main.h
index 5a0aedcde1..27041a0026 100644
--- a/src/main.h
+++ b/src/main.h
@@ -7,7 +7,7 @@
#define BITCOIN_MAIN_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "chainparams.h"
@@ -113,7 +113,7 @@ void UnregisterWallet(CWalletInterface* pwalletIn);
/** Unregister all wallets from core */
void UnregisterAllWallets();
/** Push an updated transaction to all registered wallets */
-void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL);
+void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL);
/** Register with a network node to receive its signals */
void RegisterNodeSignals(CNodeSignals& nodeSignals);
@@ -294,7 +294,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
std::vector<CScriptCheck> *pvChecks = NULL);
// Apply the effects of this transaction on the UTXO set represented by view
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash);
+void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight);
// Context-independent validity checks
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
@@ -1129,7 +1129,7 @@ public:
class CWalletInterface {
protected:
- virtual void SyncTransaction(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) =0;
+ virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) =0;
virtual void EraseFromWallet(const uint256 &hash) =0;
virtual void SetBestChain(const CBlockLocator &locator) =0;
virtual void UpdatedTransaction(const uint256 &hash) =0;
diff --git a/src/miner.cpp b/src/miner.cpp
index 3daf823fd8..6b1f58b229 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -87,14 +87,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
// Create coinbase tx
- CTransaction txNew;
+ CMutableTransaction txNew;
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1);
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
- // Add our coinbase tx as first transaction
- pblock->vtx.push_back(txNew);
+ // Add dummy coinbase tx as first transaction
+ pblock->vtx.push_back(CTransaction());
pblocktemplate->vTxFees.push_back(-1); // updated at end
pblocktemplate->vTxSigOps.push_back(-1); // updated at end
@@ -256,8 +256,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
continue;
CTxUndo txundo;
- uint256 hash = tx.GetHash();
- UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash);
+ const uint256& hash = tx.GetHash();
+ UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1);
// Added
pblock->vtx.push_back(tx);
@@ -296,7 +296,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
nLastBlockSize = nBlockSize;
LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
- pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
+ // Compute final coinbase transaction.
+ txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
+ txNew.vin[0].scriptSig = CScript() << OP_0 << OP_0;
+ pblock->vtx[0] = txNew;
pblocktemplate->vTxFees[0] = -nFees;
// Fill in header
@@ -304,7 +307,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
UpdateTime(*pblock, pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
pblock->nNonce = 0;
- pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0;
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
CBlockIndex indexDummy(*pblock);
@@ -330,9 +332,11 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
}
++nExtraNonce;
unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
- pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
- assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
+ CMutableTransaction txCoinbase(pblock->vtx[0]);
+ txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
+ assert(txCoinbase.vin[0].scriptSig.size() <= 100);
+ pblock->vtx[0] = txCoinbase;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}
diff --git a/src/net.cpp b/src/net.cpp
index 757a06aaed..811df43334 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -4,7 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "net.h"
@@ -528,10 +528,6 @@ void CNode::CloseSocketDisconnect()
pnodeSync = NULL;
}
-void CNode::Cleanup()
-{
-}
-
void CNode::PushVersion()
{
int nBestHeight = g_signals.GetHeight().get_value_or(0);
@@ -678,7 +674,6 @@ int CNetMessage::readHeader(const char *pch, unsigned int nBytes)
// switch state to reading message data
in_data = true;
- vRecv.resize(hdr.nMessageSize);
return nCopy;
}
@@ -688,6 +683,11 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes)
unsigned int nRemaining = hdr.nMessageSize - nDataPos;
unsigned int nCopy = std::min(nRemaining, nBytes);
+ if (vRecv.size() < nDataPos + nCopy) {
+ // Allocate up to 256 KiB ahead, but never more than the total message size.
+ vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
+ }
+
memcpy(&vRecv[nDataPos], pch, nCopy);
nDataPos += nCopy;
@@ -773,7 +773,6 @@ void ThreadSocketHandler()
// close socket and cleanup
pnode->CloseSocketDisconnect();
- pnode->Cleanup();
// hold in disconnected pool until all refs are released
if (pnode->fNetworkNode || pnode->fInbound)
@@ -1789,6 +1788,7 @@ public:
delete pnode;
vNodes.clear();
vNodesDisconnected.clear();
+ vhListenSocket.clear();
delete semOutbound;
semOutbound = NULL;
delete pnodeLocalHost;
@@ -1808,17 +1808,17 @@ instance_of_cnetcleanup;
-void RelayTransaction(const CTransaction& tx, const uint256& hash)
+void RelayTransaction(const CTransaction& tx)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000);
ss << tx;
- RelayTransaction(tx, hash, ss);
+ RelayTransaction(tx, ss);
}
-void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
+void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
{
- CInv inv(MSG_TX, hash);
+ CInv inv(MSG_TX, tx.GetHash());
{
LOCK(cs_mapRelay);
// Expire old relay messages
@@ -1840,7 +1840,7 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
LOCK(pnode->cs_filter);
if (pnode->pfilter)
{
- if (pnode->pfilter->IsRelevantAndUpdate(tx, hash))
+ if (pnode->pfilter->IsRelevantAndUpdate(tx))
pnode->PushInventory(inv);
} else
pnode->PushInventory(inv);
diff --git a/src/net.h b/src/net.h
index 14d578a72a..41dc618571 100644
--- a/src/net.h
+++ b/src/net.h
@@ -693,8 +693,6 @@ public:
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel);
void CloseSocketDisconnect();
- void Cleanup();
-
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
@@ -726,8 +724,8 @@ public:
class CTransaction;
-void RelayTransaction(const CTransaction& tx, const uint256& hash);
-void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss);
+void RelayTransaction(const CTransaction& tx);
+void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
diff --git a/src/netbase.h b/src/netbase.h
index 23cfb1f158..40a3d25676 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -6,7 +6,7 @@
#define BITCOIN_NETBASE_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "compat.h"
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 2dc56a5107..5df8f19729 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "addressbookpage.h"
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 387f6ede4b..76dddb103c 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "bitcoingui.h"
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 275fa35f39..e7a842df99 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -6,7 +6,7 @@
#define BITCOINGUI_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include <QMainWindow>
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 42d6da7d37..c6a6150392 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -440,7 +440,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// nPayAmount
qint64 nPayAmount = 0;
bool fDust = false;
- CTransaction txDummy;
+ CMutableTransaction txDummy;
foreach(const qint64 &amount, CoinControlDialog::payAmounts)
{
nPayAmount += amount;
@@ -521,7 +521,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority);
// Fee
- int64_t nFee = payTxFee.GetFee(nBytes);
+ int64_t nFee = payTxFee.GetFee(max((unsigned int)1000, nBytes));
// Min Fee
int64_t nMinFee = GetMinFee(txDummy, nBytes, AllowFree(dPriority), GMF_SEND);
@@ -582,6 +582,13 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l6->setText(sPriorityLabel); // Priority
l7->setText(fDust ? tr("yes") : tr("no")); // Dust
l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
+ if (nPayFee > 0)
+ {
+ l3->setText("~" + l3->text());
+ l4->setText("~" + l4->text());
+ if (nChange > 0)
+ l8->setText("~" + l8->text());
+ }
// turn labels "red"
l5->setStyleSheet((nBytes >= 1000) ? "color:red;" : ""); // Bytes >= 1000
@@ -599,12 +606,22 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minRelayTxFee.GetFee(546)));
+ // how many satoshis the estimated fee can vary per byte we guess wrong
+ double dFeeVary = (double)std::max(CTransaction::minTxFee.GetFeePerK(), payTxFee.GetFeePerK()) / 1000;
+ QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
+
+ l3->setToolTip(toolTip4);
+ l4->setToolTip(toolTip4);
l5->setToolTip(toolTip1);
l6->setToolTip(toolTip2);
l7->setToolTip(toolTip3);
+ l8->setToolTip(toolTip4);
+ dialog->findChild<QLabel *>("labelCoinControlFeeText") ->setToolTip(l3->toolTip());
+ dialog->findChild<QLabel *>("labelCoinControlAfterFeeText") ->setToolTip(l4->toolTip());
dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip());
dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
+ dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip());
// Insufficient funds
QLabel *label = dialog->findChild<QLabel *>("labelCoinControlInsuffFunds");
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index abab986992..3395e64350 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -6,7 +6,7 @@
#define NOTIFICATOR_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include <QIcon>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index abfd4123e0..12d54dff64 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "optionsdialog.h"
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 4dafd9d2af..6d985abaf8 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "optionsmodel.h"
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index d8dad15c0d..cc2f00916f 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -22,7 +22,7 @@
#endif
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h" /* for USE_QRCODE */
+#include "config/bitcoin-config.h" /* for USE_QRCODE */
#endif
#ifdef USE_QRCODE
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index f7491f4a42..e1f40ddd09 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -231,6 +231,7 @@ RPCConsole::RPCConsole(QWidget *parent) :
startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
+
ui->detailWidget->hide();
clear();
@@ -581,7 +582,7 @@ void RPCConsole::peerLayoutChanged()
if (fUnselect && selectedRow >= 0)
{
ui->peerWidget->selectionModel()->select(QItemSelection(selectedModelIndex.first(), selectedModelIndex.last()),
- QItemSelectionModel::Deselect);
+ QItemSelectionModel::Deselect);
}
if (fReselect)
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 3fee34d00e..3aeff3eace 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -13,7 +13,6 @@
#include <QDialog>
class ClientModel;
-class CNodeCombinedStats;
QT_BEGIN_NAMESPACE
class QItemSelection;
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 220da28cfe..03a2381c06 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -1,5 +1,5 @@
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#ifdef ENABLE_WALLET
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index dee7daeb2a..9771f8e685 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -349,7 +349,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
Array inputs = params[0].get_array();
Object sendTo = params[1].get_obj();
- CTransaction rawTx;
+ CMutableTransaction rawTx;
BOOST_FOREACH(const Value& input, inputs)
{
@@ -554,11 +554,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
- vector<CTransaction> txVariants;
+ vector<CMutableTransaction> txVariants;
while (!ssData.empty())
{
try {
- CTransaction tx;
+ CMutableTransaction tx;
ssData >> tx;
txVariants.push_back(tx);
}
@@ -572,7 +572,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
// mergedTx will end up with all the signatures; it
// starts as a clone of the rawtx:
- CTransaction mergedTx(txVariants[0]);
+ CMutableTransaction mergedTx(txVariants[0]);
bool fComplete = true;
// Fetch previous transactions (inputs):
@@ -713,7 +713,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
// ... and merge in other signatures:
- BOOST_FOREACH(const CTransaction& txv, txVariants)
+ BOOST_FOREACH(const CMutableTransaction& txv, txVariants)
{
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
@@ -770,7 +770,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
catch (std::exception &e) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
- uint256 hashTx = tx.GetHash();
+ const uint256 &hashTx = tx.GetHash();
CCoinsViewCache &view = *pcoinsTip;
CCoins existingCoins;
@@ -780,7 +780,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
// push to local node and sync with wallets
CValidationState state;
if (AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees))
- SyncWithWallets(hashTx, tx, NULL);
+ SyncWithWallets(tx, NULL);
else {
if(state.IsInvalid())
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
@@ -790,7 +790,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
- RelayTransaction(tx, hashTx);
+ RelayTransaction(tx);
return hashTx.GetHex();
}
diff --git a/src/script.cpp b/src/script.cpp
index b383a00a6e..c83d26885a 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -1636,7 +1636,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
}
-bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType)
+bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn];
@@ -1671,7 +1671,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
}
-bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType)
+bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn];
@@ -1689,7 +1689,7 @@ static CScript PushAll(const vector<valtype>& values)
return result;
}
-static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2)
{
diff --git a/src/script.h b/src/script.h
index a282e7dc04..ea988f0e40 100644
--- a/src/script.h
+++ b/src/script.h
@@ -20,6 +20,7 @@
class CCoins;
class CKeyStore;
class CTransaction;
+class CMutableTransaction;
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
@@ -769,12 +770,12 @@ public:
void Serialize(Stream &s, int nType, int nVersion) const {
std::vector<unsigned char> compr;
if (Compress(compr)) {
- s << CFlatData(&compr[0], &compr[compr.size()]);
+ s << CFlatData(compr);
return;
}
unsigned int nSize = script.size() + nSpecialScripts;
s << VARINT(nSize);
- s << CFlatData(&script[0], &script[script.size()]);
+ s << CFlatData(script);
}
template<typename Stream>
@@ -783,13 +784,13 @@ public:
s >> VARINT(nSize);
if (nSize < nSpecialScripts) {
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
- s >> REF(CFlatData(&vch[0], &vch[vch.size()]));
+ s >> REF(CFlatData(vch));
Decompress(nSize, vch);
return;
}
nSize -= nSpecialScripts;
script.resize(nSize);
- s >> REF(CFlatData(&script[0], &script[script.size()]));
+ s >> REF(CFlatData(script));
}
};
@@ -805,8 +806,8 @@ bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
-bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
-bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
+bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
+bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
diff --git a/src/serialize.h b/src/serialize.h
index 1341746592..5ac85554c6 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -37,6 +37,34 @@ inline T& REF(const T& val)
return const_cast<T&>(val);
}
+/** Get begin pointer of vector (non-const version).
+ * @note These functions avoid the undefined case of indexing into an empty
+ * vector, as well as that of indexing after the end of the vector.
+ */
+template <class T, class TAl>
+inline T* begin_ptr(std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : &v[0];
+}
+/** Get begin pointer of vector (const version) */
+template <class T, class TAl>
+inline const T* begin_ptr(const std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : &v[0];
+}
+/** Get end pointer of vector (non-const version) */
+template <class T, class TAl>
+inline T* end_ptr(std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : (&v[0] + v.size());
+}
+/** Get end pointer of vector (const version) */
+template <class T, class TAl>
+inline const T* end_ptr(const std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : (&v[0] + v.size());
+}
+
/////////////////////////////////////////////////////////////////
//
// Templates for serializing to anything that looks like a stream,
@@ -318,6 +346,12 @@ protected:
char* pend;
public:
CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { }
+ template <class T, class TAl>
+ explicit CFlatData(std::vector<T,TAl> &v)
+ {
+ pbegin = (char*)begin_ptr(v);
+ pend = (char*)end_ptr(v);
+ }
char* begin() { return pbegin; }
const char* begin() const { return pbegin; }
char* end() { return pend; }
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index fb06fb3435..3a45844411 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
// 50 orphan transactions:
for (int i = 0; i < 50; i++)
{
- CTransaction tx;
+ CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = GetRandHash();
@@ -184,7 +184,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
CTransaction txPrev = RandomOrphan();
- CTransaction tx;
+ CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = txPrev.GetHash();
@@ -201,7 +201,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
CTransaction txPrev = RandomOrphan();
- CTransaction tx;
+ CMutableTransaction tx;
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
@@ -242,10 +242,10 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
// 100 orphan transactions:
static const int NPREV=100;
- CTransaction orphans[NPREV];
+ CMutableTransaction orphans[NPREV];
for (int i = 0; i < NPREV; i++)
{
- CTransaction& tx = orphans[i];
+ CMutableTransaction& tx = orphans[i];
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = GetRandHash();
@@ -258,7 +258,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
}
// Create a transaction that depends on orphans:
- CTransaction tx;
+ CMutableTransaction tx;
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp
index e2a75da349..4bee0f6b6e 100644
--- a/src/test/accounting_tests.cpp
+++ b/src/test/accounting_tests.cpp
@@ -83,13 +83,21 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.mapValue["comment"] = "y";
- --wtx.nLockTime; // Just to change the hash :)
+ {
+ CMutableTransaction tx(wtx);
+ --tx.nLockTime; // Just to change the hash :)
+ *static_cast<CTransaction*>(&wtx) = CTransaction(tx);
+ }
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
wtx.mapValue["comment"] = "x";
- --wtx.nLockTime; // Just to change the hash :)
+ {
+ CMutableTransaction tx(wtx);
+ --tx.nLockTime; // Just to change the hash :)
+ *static_cast<CTransaction*>(&wtx) = CTransaction(tx);
+ }
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index abedd3093c..b56d998be2 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -118,33 +118,33 @@ BOOST_AUTO_TEST_CASE(bloom_match)
CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(uint256("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match tx hash");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
// byte-reversed tx hash
filter.insert(ParseHex("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized tx hash");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input signature");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input signature");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input pub key");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input pub key");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address");
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx, spendingTx.GetHash()), "Simple Bloom filter didn't add output");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx), "Simple Bloom filter didn't add output");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match COutPoint");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match COutPoint");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
COutPoint prevOutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
@@ -154,23 +154,23 @@ BOOST_AUTO_TEST_CASE(bloom_match)
memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int));
filter.insert(data);
}
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized COutPoint");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(uint256("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436"));
- BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random tx hash");
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431"));
- BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random address");
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random address");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1));
- BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about");
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
- BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about");
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
}
BOOST_AUTO_TEST_CASE(merkle_block_1)
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index bff6de41a3..47977cf295 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
CBlockTemplate *pblocktemplate;
- CTransaction tx,tx2;
+ CMutableTransaction tx,tx2;
CScript script;
uint256 hash;
@@ -68,10 +68,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
- pblock->vtx[0].vin[0].scriptSig = CScript();
- pblock->vtx[0].vin[0].scriptSig.push_back(blockinfo[i].extranonce);
- pblock->vtx[0].vin[0].scriptSig.push_back(chainActive.Height());
- pblock->vtx[0].vout[0].scriptPubKey = CScript();
+ CMutableTransaction txCoinbase(pblock->vtx[0]);
+ txCoinbase.vin[0].scriptSig = CScript();
+ txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
+ txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
+ txCoinbase.vout[0].scriptPubKey = CScript();
+ pblock->vtx[0] = CTransaction(txCoinbase);
if (txFirst.size() < 2)
txFirst.push_back(new CTransaction(pblock->vtx[0]));
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 3775abd633..452cf084a7 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -55,13 +55,13 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
CScript escrow;
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
- CTransaction txFrom; // Funding transaction
+ CMutableTransaction txFrom; // Funding transaction
txFrom.vout.resize(3);
txFrom.vout[0].scriptPubKey = a_and_b;
txFrom.vout[1].scriptPubKey = a_or_b;
txFrom.vout[2].scriptPubKey = escrow;
- CTransaction txTo[3]; // Spending transaction
+ CMutableTransaction txTo[3]; // Spending transaction
for (int i = 0; i < 3; i++)
{
txTo[i].vin.resize(1);
@@ -270,13 +270,13 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
CScript escrow;
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
- CTransaction txFrom; // Funding transaction
+ CMutableTransaction txFrom; // Funding transaction
txFrom.vout.resize(3);
txFrom.vout[0].scriptPubKey = a_and_b;
txFrom.vout[1].scriptPubKey = a_or_b;
txFrom.vout[2].scriptPubKey = escrow;
- CTransaction txTo[3]; // Spending transaction
+ CMutableTransaction txTo[3]; // Spending transaction
for (int i = 0; i < 3; i++)
{
txTo[i].vin.resize(1);
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 7d7e6681df..9dce4daac6 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -36,9 +36,9 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
// build a block with some dummy transactions
CBlock block;
for (unsigned int j=0; j<nTx; j++) {
- CTransaction tx;
+ CMutableTransaction tx;
tx.nLockTime = rand(); // actual transaction data doesn't matter; just make the nLockTime's unique
- block.vtx.push_back(tx);
+ block.vtx.push_back(CTransaction(tx));
}
// calculate actual merkle root and height
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 9b1290e0ea..a75593a8b2 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -30,11 +30,11 @@ static bool
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict)
{
// Create dummy to/from transactions:
- CTransaction txFrom;
+ CMutableTransaction txFrom;
txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey = scriptPubKey;
- CTransaction txTo;
+ CMutableTransaction txTo;
txTo.vin.resize(1);
txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0;
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(sign)
evalScripts[i].SetDestination(standardScripts[i].GetID());
}
- CTransaction txFrom; // Funding transaction:
+ CMutableTransaction txFrom; // Funding transaction:
string reason;
txFrom.vout.resize(8);
for (int i = 0; i < 4; i++)
@@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(sign)
}
BOOST_CHECK(IsStandardTx(txFrom, reason));
- CTransaction txTo[8]; // Spending transactions
+ CMutableTransaction txTo[8]; // Spending transactions
for (int i = 0; i < 8; i++)
{
txTo[i].vin.resize(1);
@@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(set)
keystore.AddCScript(inner[i]);
}
- CTransaction txFrom; // Funding transaction:
+ CMutableTransaction txFrom; // Funding transaction:
string reason;
txFrom.vout.resize(4);
for (int i = 0; i < 4; i++)
@@ -183,7 +183,7 @@ BOOST_AUTO_TEST_CASE(set)
}
BOOST_CHECK(IsStandardTx(txFrom, reason));
- CTransaction txTo[4]; // Spending transactions
+ CMutableTransaction txTo[4]; // Spending transactions
for (int i = 0; i < 4; i++)
{
txTo[i].vin.resize(1);
@@ -265,7 +265,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
keys.push_back(key[i].GetPubKey());
}
- CTransaction txFrom;
+ CMutableTransaction txFrom;
txFrom.vout.resize(6);
// First three are standard:
@@ -299,7 +299,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0));
- CTransaction txTo;
+ CMutableTransaction txTo;
txTo.vout.resize(1);
txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
@@ -326,7 +326,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].scriptSig = t;
}
- CTransaction txToNonStd;
+ CMutableTransaction txToNonStd;
txToNonStd.vout.resize(1);
txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
txToNonStd.vout[0].nValue = 1000;
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 29d518d707..cba582e941 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -240,11 +240,11 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CScript scriptPubKey12;
scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG;
- CTransaction txFrom12;
+ CMutableTransaction txFrom12;
txFrom12.vout.resize(1);
txFrom12.vout[0].scriptPubKey = scriptPubKey12;
- CTransaction txTo12;
+ CMutableTransaction txTo12;
txTo12.vin.resize(1);
txTo12.vout.resize(1);
txTo12.vin[0].prevout.n = 0;
@@ -274,11 +274,11 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
CScript scriptPubKey23;
scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG;
- CTransaction txFrom23;
+ CMutableTransaction txFrom23;
txFrom23.vout.resize(1);
txFrom23.vout[0].scriptPubKey = scriptPubKey23;
- CTransaction txTo23;
+ CMutableTransaction txTo23;
txTo23.vin.resize(1);
txTo23.vout.resize(1);
txTo23.vin[0].prevout.n = 0;
@@ -345,11 +345,11 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
keystore.AddKey(key);
}
- CTransaction txFrom;
+ CMutableTransaction txFrom;
txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey.SetDestination(keys[0].GetPubKey().GetID());
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
- CTransaction txTo;
+ CMutableTransaction txTo;
txTo.vin.resize(1);
txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0;
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 353fd60f7b..423ae4a789 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -28,7 +28,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
return 1;
}
- CTransaction txTmp(txTo);
+ CMutableTransaction txTmp(txTo);
// In case concatenating two scripts ends up with two codeseparators,
// or an extra one at the end, this prevents all those possible incompatibilities.
@@ -90,7 +90,7 @@ void static RandomScript(CScript &script) {
script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))];
}
-void static RandomTransaction(CTransaction &tx, bool fSingle) {
+void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
tx.nVersion = insecure_rand();
tx.vin.clear();
tx.vout.clear();
@@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(sighash_test)
#endif
for (int i=0; i<nRandomTests; i++) {
int nHashType = insecure_rand();
- CTransaction txTo;
+ CMutableTransaction txTo;
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
CScript scriptCode;
RandomScript(scriptCode);
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index feba5ee80e..238033f407 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
- CTransaction tx;
+ CMutableTransaction tx;
stream >> tx;
CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
@@ -224,10 +224,10 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
// paid to a TX_PUBKEYHASH.
//
-static std::vector<CTransaction>
+static std::vector<CMutableTransaction>
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet)
{
- std::vector<CTransaction> dummyTransactions;
+ std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2);
// Add some keys to the keystore:
@@ -261,9 +261,9 @@ BOOST_AUTO_TEST_CASE(test_Get)
CBasicKeyStore keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(coinsDummy);
- std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
+ std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
- CTransaction t1;
+ CMutableTransaction t1;
t1.vin.resize(3);
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
t1.vin[0].prevout.n = 1;
@@ -296,9 +296,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
CBasicKeyStore keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(coinsDummy);
- std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
+ std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
- CTransaction t;
+ CMutableTransaction t;
t.vin.resize(1);
t.vin[0].prevout.hash = dummyTransactions[0].GetHash();
t.vin[0].prevout.n = 1;
diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp
index 1993358826..86a83f5163 100644
--- a/src/test/wallet_tests.cpp
+++ b/src/test/wallet_tests.cpp
@@ -31,16 +31,18 @@ static vector<COutput> vCoins;
static void add_coin(int64_t nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
{
static int nextLockTime = 0;
- CTransaction tx;
+ CMutableTransaction tx;
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
tx.vout.resize(nInput+1);
tx.vout[nInput].nValue = nValue;
+ if (fIsFromMe) {
+ // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(),
+ // so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
+ tx.vin.resize(1);
+ }
CWalletTx* wtx = new CWalletTx(&wallet, tx);
if (fIsFromMe)
{
- // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(),
- // so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
- wtx->vin.resize(1);
wtx->fDebitCached = true;
wtx->nDebitCached = 1;
}
diff --git a/src/util.h b/src/util.h
index da1810a3d3..5eb6f03826 100644
--- a/src/util.h
+++ b/src/util.h
@@ -7,7 +7,7 @@
#define BITCOIN_UTIL_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "compat.h"
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 3176cf893a..e74980e9e7 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -603,11 +603,11 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
// Add a transaction to the wallet, or update it.
// pblock is optional, but should be provided if the transaction is known to be in a block.
// If fUpdate is true, existing transactions will be updated.
-bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{
{
AssertLockHeld(cs_wallet);
- bool fExisted = mapWallet.count(hash);
+ bool fExisted = mapWallet.count(tx.GetHash());
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{
@@ -621,10 +621,10 @@ bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction&
return false;
}
-void CWallet::SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock)
+void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
{
LOCK2(cs_main, cs_wallet);
- if (!AddToWalletIfInvolvingMe(hash, tx, pblock, true))
+ if (!AddToWalletIfInvolvingMe(tx, pblock, true))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
@@ -870,7 +870,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
ReadBlockFromDisk(block, pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
- if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
+ if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
ret++;
}
pindex = chainActive.Next(pindex);
@@ -909,9 +909,8 @@ void CWalletTx::RelayWalletTransaction()
if (!IsCoinBase())
{
if (GetDepthInMainChain() == 0) {
- uint256 hash = GetHash();
- LogPrintf("Relaying wtx %s\n", hash.ToString());
- RelayTransaction((CTransaction)*this, hash);
+ LogPrintf("Relaying wtx %s\n", GetHash().ToString());
+ RelayTransaction((CTransaction)*this);
}
}
}
@@ -1245,6 +1244,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}
wtxNew.BindWallet(this);
+ CMutableTransaction txNew;
{
LOCK2(cs_main, cs_wallet);
@@ -1252,8 +1252,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
nFeeRet = payTxFee.GetFeePerK();
while (true)
{
- wtxNew.vin.clear();
- wtxNew.vout.clear();
+ txNew.vin.clear();
+ txNew.vout.clear();
wtxNew.fFromMe = true;
int64_t nTotalValue = nValue + nFeeRet;
@@ -1267,7 +1267,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
strFailReason = _("Transaction amount too small");
return false;
}
- wtxNew.vout.push_back(txout);
+ txNew.vout.push_back(txout);
}
// Choose coins to use
@@ -1331,8 +1331,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
else
{
// Insert change txn at random position:
- vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1);
- wtxNew.vout.insert(position, newTxOut);
+ vector<CTxOut>::iterator position = txNew.vout.begin()+GetRandInt(txNew.vout.size()+1);
+ txNew.vout.insert(position, newTxOut);
}
}
else
@@ -1340,17 +1340,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Fill vin
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
+ txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
// Sign
int nIn = 0;
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
+ if (!SignSignature(*this, *coin.first, txNew, nIn++))
{
strFailReason = _("Signing transaction failed");
return false;
}
+ // Embed the constructed transaction data in wtxNew.
+ *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
+
// Limit size
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_STANDARD_TX_SIZE)
@@ -1511,11 +1514,11 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
}
-DBErrors CWallet::ZapWalletTx()
+DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
if (!fFileBacked)
return DB_LOAD_OK;
- DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this);
+ DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE)
{
if (CDB::Rewrite(strWalletFile, "\x04pool"))
diff --git a/src/wallet.h b/src/wallet.h
index 7df656fc25..8494ce9a34 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -244,8 +244,8 @@ public:
void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet=false);
- void SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock);
- bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate);
+ void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
+ bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
void EraseFromWallet(const uint256 &hash);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
@@ -341,7 +341,7 @@ public:
void SetBestChain(const CBlockLocator& loc);
DBErrors LoadWallet(bool& fFirstRunRet);
- DBErrors ZapWalletTx();
+ DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 80e9dded5f..3ce2ef019c 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -680,7 +680,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
return result;
}
-DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
+DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vector<CWalletTx>& vWtx)
{
pwallet->vchDefaultKey = CPubKey();
CWalletScanState wss;
@@ -725,7 +725,11 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
uint256 hash;
ssKey >> hash;
+ CWalletTx wtx;
+ ssValue >> wtx;
+
vTxHash.push_back(hash);
+ vWtx.push_back(wtx);
}
}
pcursor->close();
@@ -743,11 +747,11 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
return result;
}
-DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet)
+DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
{
// build list of wallet TXs
vector<uint256> vTxHash;
- DBErrors err = FindWalletTx(pwallet, vTxHash);
+ DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
if (err != DB_LOAD_OK)
return err;
diff --git a/src/walletdb.h b/src/walletdb.h
index 3bfb436050..8eb716acbb 100644
--- a/src/walletdb.h
+++ b/src/walletdb.h
@@ -122,8 +122,8 @@ public:
DBErrors ReorderTransactions(CWallet*);
DBErrors LoadWallet(CWallet* pwallet);
- DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash);
- DBErrors ZapWalletTx(CWallet* pwallet);
+ DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
+ DBErrors ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx);
static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
static bool Recover(CDBEnv& dbenv, std::string filename);
};