aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/devtools/github-merge.py55
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus6
-rw-r--r--doc/developer-notes.md73
-rw-r--r--src/bitcoin-tx.cpp8
-rw-r--r--src/chainparamsbase.cpp5
-rw-r--r--src/chainparamsbase.h6
-rw-r--r--src/core_write.cpp2
-rw-r--r--src/init.cpp2
-rw-r--r--src/key.cpp8
-rw-r--r--src/key.h3
-rw-r--r--src/merkleblock.cpp2
-rw-r--r--src/miner.cpp4
-rw-r--r--src/net.cpp98
-rw-r--r--src/net.h6
-rw-r--r--src/net_processing.cpp158
-rw-r--r--src/netaddress.cpp6
-rw-r--r--src/netaddress.h1
-rw-r--r--src/primitives/transaction.h4
-rw-r--r--src/qt/bantablemodel.cpp4
-rw-r--r--src/qt/rpcconsole.cpp2
-rw-r--r--src/rest.cpp9
-rw-r--r--src/rpc/blockchain.cpp5
-rw-r--r--src/rpc/rawtransaction.cpp78
-rw-r--r--src/script/interpreter.cpp6
-rw-r--r--src/test/amount_tests.cpp38
-rw-r--r--src/test/net_tests.cpp13
-rw-r--r--src/utiltime.cpp12
-rw-r--r--src/validation.cpp8
-rw-r--r--src/validation.h3
-rw-r--r--src/wallet/db.cpp9
-rw-r--r--src/wallet/db.h1
-rw-r--r--src/wallet/feebumper.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp42
-rw-r--r--src/wallet/wallet.cpp152
-rw-r--r--src/wallet/wallet.h15
-rwxr-xr-xtest/functional/fundrawtransaction.py5
-rwxr-xr-xtest/functional/import-abort-rescan.py66
-rwxr-xr-xtest/functional/net.py35
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet.py28
-rw-r--r--test/util/data/blanktxv1.json2
-rw-r--r--test/util/data/blanktxv2.json2
-rw-r--r--test/util/data/tt-delin1-out.json2
-rw-r--r--test/util/data/tt-delout1-out.json2
-rw-r--r--test/util/data/tt-locktime317000-out.json2
-rw-r--r--test/util/data/txcreate1.json2
-rw-r--r--test/util/data/txcreate2.json2
-rw-r--r--test/util/data/txcreatedata1.json2
-rw-r--r--test/util/data/txcreatedata2.json2
-rw-r--r--test/util/data/txcreatedata_seq0.json2
-rw-r--r--test/util/data/txcreatedata_seq1.json2
-rw-r--r--test/util/data/txcreatemultisig1.json2
-rw-r--r--test/util/data/txcreatemultisig2.json2
-rw-r--r--test/util/data/txcreatemultisig3.json2
-rw-r--r--test/util/data/txcreatemultisig4.json2
-rw-r--r--test/util/data/txcreateoutpubkey1.json2
-rw-r--r--test/util/data/txcreateoutpubkey2.json2
-rw-r--r--test/util/data/txcreateoutpubkey3.json2
-rw-r--r--test/util/data/txcreatescript1.json2
-rw-r--r--test/util/data/txcreatescript2.json2
-rw-r--r--test/util/data/txcreatescript3.json2
-rw-r--r--test/util/data/txcreatescript4.json2
-rw-r--r--test/util/data/txcreatesignv1.json2
63 files changed, 583 insertions, 444 deletions
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index 3fee39143d..03ccf5b624 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016 The Bitcoin Core developers
+# Copyright (c) 2016-2017 Bitcoin Core Developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,7 @@
# In case of a clean merge that is accepted by the user, the local branch with
# name $BRANCH is overwritten with the merged result, and optionally pushed.
from __future__ import division,print_function,unicode_literals
-import os
+import os,sys
from sys import stdin,stdout,stderr
import argparse
import hashlib
@@ -127,6 +127,9 @@ def tree_sha512sum(commit='HEAD'):
raise IOError('Non-zero return value executing git cat-file')
return overall.hexdigest()
+def print_merge_details(pull, title, branch, base_branch, head_branch):
+ print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
+ subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
def parse_arguments():
epilog = '''
@@ -171,7 +174,7 @@ def main():
info = retrieve_pr_info(repo,pull)
if info is None:
exit(1)
- title = info['title']
+ title = info['title'].strip()
# precedence order for destination branch argument:
# - command line argument
# - githubmerge.branch setting
@@ -256,8 +259,7 @@ def main():
printf("ERROR: Cannot update message.",file=stderr)
exit(4)
- print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
- subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
+ print_merge_details(pull, title, branch, base_branch, head_branch)
print()
# Run test command if configured.
@@ -276,12 +278,6 @@ def main():
print("Difference with github ignored.",file=stderr)
else:
exit(6)
- reply = ask_prompt("Press 'd' to accept the diff.")
- if reply.lower() == 'd':
- print("Diff accepted.",file=stderr)
- else:
- print("ERROR: Diff rejected.",file=stderr)
- exit(6)
else:
# Verify the result manually.
print("Dropping you on a shell so you can try building/testing the merged source.",file=stderr)
@@ -290,12 +286,6 @@ def main():
if os.path.isfile('/etc/debian_version'): # Show pull number on Debian default prompt
os.putenv('debian_chroot',pull)
subprocess.call([BASH,'-i'])
- reply = ask_prompt("Type 'm' to accept the merge.")
- if reply.lower() == 'm':
- print("Merge accepted.",file=stderr)
- else:
- print("ERROR: Merge rejected.",file=stderr)
- exit(7)
second_sha512 = tree_sha512sum()
if first_sha512 != second_sha512:
@@ -303,16 +293,19 @@ def main():
exit(8)
# Sign the merge commit.
- reply = ask_prompt("Type 's' to sign off on the merge.")
- if reply == 's':
- try:
- subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit'])
- except subprocess.CalledProcessError as e:
- print("Error signing, exiting.",file=stderr)
+ print_merge_details(pull, title, branch, base_branch, head_branch)
+ while True:
+ reply = ask_prompt("Type 's' to sign off on the above merge, or 'x' to reject and exit.").lower()
+ if reply == 's':
+ try:
+ subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit'])
+ break
+ except subprocess.CalledProcessError as e:
+ print("Error signing, exiting.",file=stderr)
+ exit(1)
+ elif reply == 'x':
+ print("Not signing off on merge, exiting.",file=stderr)
exit(1)
- else:
- print("Not signing off on merge, exiting.",file=stderr)
- exit(1)
# Put the result in branch.
subprocess.check_call([GIT,'checkout','-q',branch])
@@ -326,9 +319,13 @@ def main():
subprocess.call([GIT,'branch','-q','-D',local_merge_branch],stderr=devnull)
# Push the result.
- reply = ask_prompt("Type 'push' to push the result to %s, branch %s." % (host_repo,branch))
- if reply.lower() == 'push':
- subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch])
+ while True:
+ reply = ask_prompt("Type 'push' to push the result to %s, branch %s, or 'x' to exit without pushing." % (host_repo,branch)).lower()
+ if reply == 'push':
+ subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch])
+ break
+ elif reply == 'x':
+ exit(1)
if __name__ == '__main__':
main()
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index 5995f9f438..23a568ad13 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -302,7 +302,6 @@ def copyFramework(framework, path, verbose):
if os.path.exists(fromContentsDir):
toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory)
shutil.copytree(fromContentsDir, toContentsDir, symlinks=True)
- contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory)
if verbose >= 3:
print("Copied Contents:", fromContentsDir)
print(" to:", toContentsDir)
@@ -675,9 +674,8 @@ else:
if verbose >= 2:
print("+ Installing qt.conf +")
-f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb")
-f.write(qt_conf.encode())
-f.close()
+with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f:
+ f.write(qt_conf.encode())
# ------------------------------------------------
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 797507cd3e..fd75ada79f 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -495,3 +495,76 @@ Git and GitHub tips
This will add an `upstream-pull` remote to your git repository, which can be fetched using `git fetch --all`
or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`,
`git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER.
+
+RPC interface guidelines
+--------------------------
+
+A few guidelines for introducing and reviewing new RPC interfaces:
+
+- Method naming: use consecutive lower-case names such as `getrawtransaction` and `submitblock`
+
+ - *Rationale*: Consistency with existing interface.
+
+- Argument naming: use snake case `fee_delta` (and not, e.g. camel case `feeDelta`)
+
+ - *Rationale*: Consistency with existing interface.
+
+- Use the JSON parser for parsing, don't manually parse integers or strings from
+ arguments unless absolutely necessary.
+
+ - *Rationale*: Introduces hand-rolled string manipulation code at both the caller and callee sites,
+ which is error prone, and it is easy to get things such as escaping wrong.
+ JSON already supports nested data structures, no need to re-invent the wheel.
+
+ - *Exception*: AmountToValue can parse amounts as string. This was introduced because many JSON
+ parsers and formatters hard-code handling decimal numbers as floating point
+ values, resulting in potential loss of precision. This is unacceptable for
+ monetary values. **Always** use `AmountToValue` and `ValueToAmount` when
+ inputting or outputting monetary values. The only exceptions to this are
+ `prioritisetransaction` and `getblocktemplate` because their interface
+ is specified as-is in BIP22.
+
+- Missing arguments and 'null' should be treated the same: as default values. If there is no
+ default value, both cases should fail in the same way.
+
+ - *Rationale*: Avoids surprises when switching to name-based arguments. Missing name-based arguments
+ are passed as 'null'.
+
+ - *Exception*: Many legacy exceptions to this exist, one of the worst ones is
+ `getbalance` which follows a completely different code path based on the
+ number of arguments. We are still in the process of cleaning these up. Do not introduce
+ new ones.
+
+- Try not to overload methods on argument type. E.g. don't make `getblock(true)` and `getblock("hash")`
+ do different things.
+
+ - *Rationale*: This is impossible to use with `bitcoin-cli`, and can be surprising to users.
+
+ - *Exception*: Some RPC calls can take both an `int` and `bool`, most notably when a bool was switched
+ to a multi-value, or due to other historical reasons. **Always** have false map to 0 and
+ true to 1 in this case.
+
+- Don't forget to fill in the argument names correctly in the RPC command table.
+
+ - *Rationale*: If not, the call can not be used with name-based arguments.
+
+- Set okSafeMode in the RPC command table to a sensible value: safe mode is when the
+ blockchain is regarded to be in a confused state, and the client deems it unsafe to
+ do anything irreversible such as send. Anything that just queries should be permitted.
+
+ - *Rationale*: Troubleshooting a node in safe mode is difficult if half the
+ RPCs don't work.
+
+- Add every non-string RPC argument `(method, idx, name)` to the table `vRPCConvertParams` in `rpc/client.cpp`.
+
+ - *Rationale*: `bitcoin-cli` and the GUI debug console use this table to determine how to
+ convert a plaintext command line to JSON. If the types don't match, the method can be unusable
+ from there.
+
+- A RPC method must either be a wallet method or a non-wallet method. Do not
+ introduce new methods such as `getinfo` and `signrawtransaction` that differ
+ in behavior based on presence of a wallet.
+
+ - *Rationale*: as well as complicating the implementation and interfering
+ with the introduction of multi-wallet, wallet and non-wallet code should be
+ separated to avoid introducing circular dependencies between code units.
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 83b855cbcf..45738b5df8 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -657,11 +657,13 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
MutateTxDelOutput(tx, commandVal);
else if (command == "outaddr")
MutateTxAddOutAddr(tx, commandVal);
- else if (command == "outpubkey")
+ else if (command == "outpubkey") {
+ if (!ecc) { ecc.reset(new Secp256k1Init()); }
MutateTxAddOutPubKey(tx, commandVal);
- else if (command == "outmultisig")
+ } else if (command == "outmultisig") {
+ if (!ecc) { ecc.reset(new Secp256k1Init()); }
MutateTxAddOutMultiSig(tx, commandVal);
- else if (command == "outscript")
+ } else if (command == "outscript")
MutateTxAddOutScript(tx, commandVal);
else if (command == "outdata")
MutateTxAddOutData(tx, commandVal);
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index cb71a8b550..d013cc1450 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -103,8 +103,3 @@ std::string ChainNameFromCommandLine()
return CBaseChainParams::TESTNET;
return CBaseChainParams::MAIN;
}
-
-bool AreBaseParamsConfigured()
-{
- return pCurrentBaseParams != NULL;
-}
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index 59493afb9b..84350cf65b 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -53,10 +53,4 @@ void SelectBaseParams(const std::string& chain);
*/
std::string ChainNameFromCommandLine();
-/**
- * Return true if SelectBaseParamsFromCommandLine() has been called to select
- * a network.
- */
-bool AreBaseParamsConfigured();
-
#endif // BITCOIN_CHAINPARAMSBASE_H
diff --git a/src/core_write.cpp b/src/core_write.cpp
index a3ca87c8b5..d116e617ee 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -151,6 +151,8 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
entry.pushKV("version", tx.nVersion);
+ entry.pushKV("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));
+ entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
entry.pushKV("locktime", (int64_t)tx.nLockTime);
UniValue vin(UniValue::VARR);
diff --git a/src/init.cpp b/src/init.cpp
index f06c9e1100..64f571f284 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -436,6 +436,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT));
+ strUsage += HelpMessageOpt("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT));
+
strUsage += HelpMessageOpt("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT));
strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT));
strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT));
diff --git a/src/key.cpp b/src/key.cpp
index b4f0dc8202..5a75647f1a 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -131,14 +131,6 @@ void CKey::MakeNewKey(bool fCompressedIn) {
fCompressed = fCompressedIn;
}
-bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
- if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
- return false;
- fCompressed = fCompressedIn;
- fValid = true;
- return true;
-}
-
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
CPrivKey privkey;
diff --git a/src/key.h b/src/key.h
index 925a8d186d..2c6f151727 100644
--- a/src/key.h
+++ b/src/key.h
@@ -94,9 +94,6 @@ public:
//! Check whether the public key corresponding to this private key is (to be) compressed.
bool IsCompressed() const { return fCompressed; }
- //! Initialize from a CPrivKey (serialized OpenSSL private key data).
- bool SetPrivKey(const CPrivKey& vchPrivKey, bool fCompressed);
-
//! Generate a new private key using a cryptographic PRNG.
void MakeNewKey(bool fCompressed);
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index e3f3e4621a..78d7cd6001 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -65,7 +65,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve
} else {
// calculate left hash
uint256 left = CalcHash(height-1, pos*2, vTxid), right;
- // calculate right hash if not beyond the end of the array - copy left hash otherwise1
+ // calculate right hash if not beyond the end of the array - copy left hash otherwise
if (pos*2+1 < CalcTreeWidth(height-1))
right = CalcHash(height-1, pos*2+1, vTxid);
else
diff --git a/src/miner.cpp b/src/miner.cpp
index 386d75c4be..69a89bd617 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -317,9 +317,7 @@ int BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& already
bool BlockAssembler::SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx)
{
assert (it != mempool.mapTx.end());
- if (mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it))
- return true;
- return false;
+ return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it);
}
void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, CTxMemPool::txiter entry, std::vector<CTxMemPool::txiter>& sortedEntries)
diff --git a/src/net.cpp b/src/net.cpp
index bd2b177ef3..ed4c752606 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -710,7 +710,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
handled = msg.readData(pch, nBytes);
if (handled < 0)
- return false;
+ return false;
if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {
LogPrint(BCLog::NET, "Oversized message from peer=%i, disconnecting\n", GetId());
@@ -788,7 +788,7 @@ int CNetMessage::readHeader(const char *pch, unsigned int nBytes)
// reject messages larger than MAX_SIZE
if (hdr.nMessageSize > MAX_SIZE)
- return -1;
+ return -1;
// switch state to reading message data
in_data = true;
@@ -1301,59 +1301,55 @@ void CConnman::ThreadSocketHandler()
}
if (recvSet || errorSet)
{
+ // typical socket buffer is 8K-64K
+ char pchBuf[0x10000];
+ int nBytes = 0;
{
- {
- // typical socket buffer is 8K-64K
- char pchBuf[0x10000];
- int nBytes = 0;
- {
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
- nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
- }
- if (nBytes > 0)
- {
- bool notify = false;
- if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
- pnode->CloseSocketDisconnect();
- RecordBytesRecv(nBytes);
- if (notify) {
- size_t nSizeAdded = 0;
- auto it(pnode->vRecvMsg.begin());
- for (; it != pnode->vRecvMsg.end(); ++it) {
- if (!it->complete())
- break;
- nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE;
- }
- {
- LOCK(pnode->cs_vProcessMsg);
- pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);
- pnode->nProcessQueueSize += nSizeAdded;
- pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;
- }
- WakeMessageHandler();
- }
- }
- else if (nBytes == 0)
- {
- // socket closed gracefully
- if (!pnode->fDisconnect) {
- LogPrint(BCLog::NET, "socket closed\n");
- }
- pnode->CloseSocketDisconnect();
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
+ nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
+ }
+ if (nBytes > 0)
+ {
+ bool notify = false;
+ if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
+ pnode->CloseSocketDisconnect();
+ RecordBytesRecv(nBytes);
+ if (notify) {
+ size_t nSizeAdded = 0;
+ auto it(pnode->vRecvMsg.begin());
+ for (; it != pnode->vRecvMsg.end(); ++it) {
+ if (!it->complete())
+ break;
+ nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE;
}
- else if (nBytes < 0)
{
- // error
- int nErr = WSAGetLastError();
- if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
- {
- if (!pnode->fDisconnect)
- LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
- pnode->CloseSocketDisconnect();
- }
+ LOCK(pnode->cs_vProcessMsg);
+ pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);
+ pnode->nProcessQueueSize += nSizeAdded;
+ pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;
}
+ WakeMessageHandler();
+ }
+ }
+ else if (nBytes == 0)
+ {
+ // socket closed gracefully
+ if (!pnode->fDisconnect) {
+ LogPrint(BCLog::NET, "socket closed\n");
+ }
+ pnode->CloseSocketDisconnect();
+ }
+ else if (nBytes < 0)
+ {
+ // error
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
+ {
+ if (!pnode->fDisconnect)
+ LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
+ pnode->CloseSocketDisconnect();
}
}
}
diff --git a/src/net.h b/src/net.h
index 497b86b150..4a63ef84e7 100644
--- a/src/net.h
+++ b/src/net.h
@@ -699,15 +699,15 @@ private:
public:
NodeId GetId() const {
- return id;
+ return id;
}
uint64_t GetLocalNonce() const {
- return nLocalHostNonce;
+ return nLocalHostNonce;
}
int GetMyStartingHeight() const {
- return nMyStartingHeight;
+ return nMyStartingHeight;
}
int GetRefCount()
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 2e7b99baa4..718a7de031 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2681,100 +2681,100 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
// this maintains the order of responses
if (!pfrom->vRecvGetData.empty()) return true;
- // Don't bother if send buffer is too full to respond anyway
- if (pfrom->fPauseSend)
- return false;
+ // Don't bother if send buffer is too full to respond anyway
+ if (pfrom->fPauseSend)
+ return false;
- std::list<CNetMessage> msgs;
- {
- LOCK(pfrom->cs_vProcessMsg);
- if (pfrom->vProcessMsg.empty())
- return false;
- // Just take one message
- msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin());
- pfrom->nProcessQueueSize -= msgs.front().vRecv.size() + CMessageHeader::HEADER_SIZE;
- pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman.GetReceiveFloodSize();
- fMoreWork = !pfrom->vProcessMsg.empty();
- }
- CNetMessage& msg(msgs.front());
-
- msg.SetVersion(pfrom->GetRecvVersion());
- // Scan for message start
- if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
- LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id);
- pfrom->fDisconnect = true;
+ std::list<CNetMessage> msgs;
+ {
+ LOCK(pfrom->cs_vProcessMsg);
+ if (pfrom->vProcessMsg.empty())
return false;
- }
+ // Just take one message
+ msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin());
+ pfrom->nProcessQueueSize -= msgs.front().vRecv.size() + CMessageHeader::HEADER_SIZE;
+ pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman.GetReceiveFloodSize();
+ fMoreWork = !pfrom->vProcessMsg.empty();
+ }
+ CNetMessage& msg(msgs.front());
+
+ msg.SetVersion(pfrom->GetRecvVersion());
+ // Scan for message start
+ if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
+ LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id);
+ pfrom->fDisconnect = true;
+ return false;
+ }
- // Read header
- CMessageHeader& hdr = msg.hdr;
- if (!hdr.IsValid(chainparams.MessageStart()))
- {
- LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id);
- return fMoreWork;
- }
- std::string strCommand = hdr.GetCommand();
+ // Read header
+ CMessageHeader& hdr = msg.hdr;
+ if (!hdr.IsValid(chainparams.MessageStart()))
+ {
+ LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id);
+ return fMoreWork;
+ }
+ std::string strCommand = hdr.GetCommand();
+
+ // Message size
+ unsigned int nMessageSize = hdr.nMessageSize;
- // Message size
- unsigned int nMessageSize = hdr.nMessageSize;
+ // Checksum
+ CDataStream& vRecv = msg.vRecv;
+ const uint256& hash = msg.GetMessageHash();
+ if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0)
+ {
+ LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
+ SanitizeString(strCommand), nMessageSize,
+ HexStr(hash.begin(), hash.begin()+CMessageHeader::CHECKSUM_SIZE),
+ HexStr(hdr.pchChecksum, hdr.pchChecksum+CMessageHeader::CHECKSUM_SIZE));
+ return fMoreWork;
+ }
- // Checksum
- CDataStream& vRecv = msg.vRecv;
- const uint256& hash = msg.GetMessageHash();
- if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0)
+ // Process message
+ bool fRet = false;
+ try
+ {
+ fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc);
+ if (interruptMsgProc)
+ return false;
+ if (!pfrom->vRecvGetData.empty())
+ fMoreWork = true;
+ }
+ catch (const std::ios_base::failure& e)
+ {
+ connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
+ if (strstr(e.what(), "end of data"))
{
- LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
- SanitizeString(strCommand), nMessageSize,
- HexStr(hash.begin(), hash.begin()+CMessageHeader::CHECKSUM_SIZE),
- HexStr(hdr.pchChecksum, hdr.pchChecksum+CMessageHeader::CHECKSUM_SIZE));
- return fMoreWork;
+ // Allow exceptions from under-length message on vRecv
+ LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
-
- // Process message
- bool fRet = false;
- try
+ else if (strstr(e.what(), "size too large"))
{
- fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc);
- if (interruptMsgProc)
- return false;
- if (!pfrom->vRecvGetData.empty())
- fMoreWork = true;
+ // Allow exceptions from over-long size
+ LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
- catch (const std::ios_base::failure& e)
+ else if (strstr(e.what(), "non-canonical ReadCompactSize()"))
{
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
- if (strstr(e.what(), "end of data"))
- {
- // Allow exceptions from under-length message on vRecv
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "size too large"))
- {
- // Allow exceptions from over-long size
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "non-canonical ReadCompactSize()"))
- {
- // Allow exceptions from non-canonical encoding
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else
- {
- PrintExceptionContinue(&e, "ProcessMessages()");
- }
+ // Allow exceptions from non-canonical encoding
+ LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
- catch (const std::exception& e) {
+ else
+ {
PrintExceptionContinue(&e, "ProcessMessages()");
- } catch (...) {
- PrintExceptionContinue(NULL, "ProcessMessages()");
}
+ }
+ catch (const std::exception& e) {
+ PrintExceptionContinue(&e, "ProcessMessages()");
+ } catch (...) {
+ PrintExceptionContinue(NULL, "ProcessMessages()");
+ }
- if (!fRet) {
- LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id);
- }
+ if (!fRet) {
+ LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id);
+ }
- LOCK(cs_main);
- SendRejectsAndCheckIfBanned(pfrom, connman);
+ LOCK(cs_main);
+ SendRejectsAndCheckIfBanned(pfrom, connman);
return fMoreWork;
}
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index ab07270f3f..34a7029862 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -179,12 +179,6 @@ bool CNetAddr::IsLocal() const
return false;
}
-bool CNetAddr::IsMulticast() const
-{
- return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0)
- || (GetByte(15) == 0xFF);
-}
-
bool CNetAddr::IsValid() const
{
// Cleanup 3-byte shifted addresses caused by garbage in size field
diff --git a/src/netaddress.h b/src/netaddress.h
index a85c2b7452..fbc4d1a65f 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -65,7 +65,6 @@ class CNetAddr
bool IsLocal() const;
bool IsRoutable() const;
bool IsValid() const;
- bool IsMulticast() const;
enum Network GetNetwork() const;
std::string ToString() const;
std::string ToStringIP() const;
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index d413e8b087..5059030309 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -22,8 +22,8 @@ public:
uint256 hash;
uint32_t n;
- COutPoint() { SetNull(); }
- COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
+ COutPoint(): n((uint32_t) -1) { }
+ COutPoint(const uint256& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { }
ADD_SERIALIZE_METHODS;
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 4b34e73eb7..f8a99506c1 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -181,7 +181,5 @@ void BanTableModel::sort(int column, Qt::SortOrder order)
bool BanTableModel::shouldShow()
{
- if (priv->size() > 0)
- return true;
- return false;
+ return priv->size() > 0;
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index bb8aa23de8..7f2f83d9f7 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -829,7 +829,7 @@ void RPCConsole::on_lineEdit_returnPressed()
cmdBeforeBrowsing = QString();
- message(CMD_REQUEST, cmd);
+ message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
Q_EMIT cmdRequest(cmd);
cmd = QString::fromStdString(strFilteredCmd);
diff --git a/src/rest.cpp b/src/rest.cpp
index 9dcaf269d6..7537ed4502 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -5,6 +5,7 @@
#include "chain.h"
#include "chainparams.h"
+#include "core_io.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "validation.h"
@@ -56,10 +57,6 @@ struct CCoin {
}
};
-/* Defined in rawtransaction.cpp */
-void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
-
static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string message)
{
req->WriteHeader("Content-Type", "text/plain");
@@ -383,7 +380,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
case RF_JSON: {
UniValue objTx(UniValue::VOBJ);
- TxToJSON(*tx, hashBlock, objTx);
+ TxToUniv(*tx, hashBlock, objTx);
std::string strJSON = objTx.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
@@ -577,7 +574,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// include the script in a json output
UniValue o(UniValue::VOBJ);
- ScriptPubKeyToJSON(coin.out.scriptPubKey, o, true);
+ ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true);
utxo.push_back(Pair("scriptPubKey", o));
utxos.push_back(utxo);
}
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 01066d0eb2..8f446aee65 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -12,6 +12,7 @@
#include "coins.h"
#include "consensus/validation.h"
#include "validation.h"
+#include "core_io.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "rpc/server.h"
@@ -123,7 +124,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
if(txDetails)
{
UniValue objTx(UniValue::VOBJ);
- TxToJSON(*tx, uint256(), objTx);
+ TxToUniv(*tx, uint256(), objTx);
txs.push_back(objTx);
}
else
@@ -975,7 +976,7 @@ UniValue gettxout(const JSONRPCRequest& request)
ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
UniValue o(UniValue::VOBJ);
- ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
+ ScriptPubKeyToUniv(coins.vout[n].scriptPubKey, o, true);
ret.push_back(Pair("scriptPubKey", o));
ret.push_back(Pair("version", coins.nVersion));
ret.push_back(Pair("coinbase", coins.fCoinBase));
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 717e9d75f3..3947fb3f7d 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -34,77 +34,15 @@
#include <univalue.h>
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
-{
- txnouttype type;
- std::vector<CTxDestination> addresses;
- int nRequired;
-
- out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey)));
- if (fIncludeHex)
- out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
-
- if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
- out.push_back(Pair("type", GetTxnOutputType(type)));
- return;
- }
-
- out.push_back(Pair("reqSigs", nRequired));
- out.push_back(Pair("type", GetTxnOutputType(type)));
-
- UniValue a(UniValue::VARR);
- BOOST_FOREACH(const CTxDestination& addr, addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
- out.push_back(Pair("addresses", a));
-}
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
- entry.push_back(Pair("txid", tx.GetHash().GetHex()));
- entry.push_back(Pair("hash", tx.GetWitnessHash().GetHex()));
- entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
- entry.push_back(Pair("vsize", (int)::GetVirtualTransactionSize(tx)));
- entry.push_back(Pair("version", tx.nVersion));
- entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
-
- UniValue vin(UniValue::VARR);
- for (unsigned int i = 0; i < tx.vin.size(); i++) {
- const CTxIn& txin = tx.vin[i];
- UniValue in(UniValue::VOBJ);
- if (tx.IsCoinBase())
- in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
- else {
- in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
- in.push_back(Pair("vout", (int64_t)txin.prevout.n));
- UniValue o(UniValue::VOBJ);
- o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true)));
- o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
- in.push_back(Pair("scriptSig", o));
- }
- if (tx.HasWitness()) {
- UniValue txinwitness(UniValue::VARR);
- for (unsigned int j = 0; j < tx.vin[i].scriptWitness.stack.size(); j++) {
- std::vector<unsigned char> item = tx.vin[i].scriptWitness.stack[j];
- txinwitness.push_back(HexStr(item.begin(), item.end()));
- }
- in.push_back(Pair("txinwitness", txinwitness));
- }
- in.push_back(Pair("sequence", (int64_t)txin.nSequence));
- vin.push_back(in);
- }
- entry.push_back(Pair("vin", vin));
- UniValue vout(UniValue::VARR);
- for (unsigned int i = 0; i < tx.vout.size(); i++) {
- const CTxOut& txout = tx.vout[i];
- UniValue out(UniValue::VOBJ);
- out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
- out.push_back(Pair("n", (int64_t)i));
- UniValue o(UniValue::VOBJ);
- ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
- out.push_back(Pair("scriptPubKey", o));
- vout.push_back(out);
- }
- entry.push_back(Pair("vout", vout));
+ // Call into TxToUniv() in bitcoin-common to decode the transaction hex.
+ //
+ // Blockchain contextual information (confirmations and blocktime) is not
+ // available to code in bitcoin-common, so we query them here and push the
+ // data into the returned UniValue.
+ TxToUniv(tx, uint256(), entry);
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
@@ -525,7 +463,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
UniValue result(UniValue::VOBJ);
- TxToJSON(CTransaction(std::move(mtx)), uint256(), result);
+ TxToUniv(CTransaction(std::move(mtx)), uint256(), result);
return result;
}
@@ -565,7 +503,7 @@ UniValue decodescript(const JSONRPCRequest& request)
} else {
// Empty scripts are valid
}
- ScriptPubKeyToJSON(script, r, false);
+ ScriptPubKeyToUniv(script, r, false);
UniValue type;
type = find_value(r, "type");
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 8ecf0bbdac..f4e5313a78 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -247,10 +247,10 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
- static const CScriptNum bnFalse(0);
- static const CScriptNum bnTrue(1);
+ // static const CScriptNum bnFalse(0);
+ // static const CScriptNum bnTrue(1);
static const valtype vchFalse(0);
- static const valtype vchZero(0);
+ // static const valtype vchZero(0);
static const valtype vchTrue(1, 1);
CScript::const_iterator pc = script.begin();
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index fd6f88b366..c95def5e87 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -9,9 +9,16 @@
BOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(MoneyRangeTest)
+{
+ BOOST_CHECK_EQUAL(MoneyRange(CAmount(-1)), false);
+ BOOST_CHECK_EQUAL(MoneyRange(MAX_MONEY + CAmount(1)), false);
+ BOOST_CHECK_EQUAL(MoneyRange(CAmount(1)), true);
+}
+
BOOST_AUTO_TEST_CASE(GetFeeTest)
{
- CFeeRate feeRate;
+ CFeeRate feeRate, altFeeRate;
feeRate = CFeeRate(0);
// Must always return 0
@@ -53,6 +60,11 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK_EQUAL(feeRate.GetFee(8), -1); // Special case: returns -1 instead of 0
BOOST_CHECK_EQUAL(feeRate.GetFee(9), -1);
+ // check alternate constructor
+ feeRate = CFeeRate(1000);
+ altFeeRate = CFeeRate(feeRate);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(100), altFeeRate.GetFee(100));
+
// Check full constructor
// default value
BOOST_CHECK(CFeeRate(CAmount(-1), 1000) == CFeeRate(-1));
@@ -68,4 +80,28 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
CFeeRate(MAX_MONEY, std::numeric_limits<size_t>::max() >> 1).GetFeePerK();
}
+BOOST_AUTO_TEST_CASE(BinaryOperatorTest)
+{
+ CFeeRate a, b;
+ a = CFeeRate(1);
+ b = CFeeRate(2);
+ BOOST_CHECK(a < b);
+ BOOST_CHECK(b > a);
+ BOOST_CHECK(a == a);
+ BOOST_CHECK(a <= b);
+ BOOST_CHECK(a <= a);
+ BOOST_CHECK(b >= a);
+ BOOST_CHECK(b >= b);
+ // a should be 0.00000002 BTC/kB now
+ a += a;
+ BOOST_CHECK(a == b);
+}
+
+BOOST_AUTO_TEST_CASE(ToStringTest)
+{
+ CFeeRate feeRate;
+ feeRate = CFeeRate(1);
+ BOOST_CHECK_EQUAL(feeRate.ToString(), "0.00000001 BTC/kB");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index b9ed4952bb..0c7f3e5e23 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -11,6 +11,7 @@
#include "net.h"
#include "netbase.h"
#include "chainparams.h"
+#include "util.h"
class CAddrManSerializationMock : public CAddrMan
{
@@ -72,6 +73,18 @@ CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(cnode_listen_port)
+{
+ // test default
+ unsigned short port = GetListenPort();
+ BOOST_CHECK(port == Params().GetDefaultPort());
+ // test set port
+ unsigned short altPort = 12345;
+ SoftSetArg("-port", std::to_string(altPort));
+ port = GetListenPort();
+ BOOST_CHECK(port == altPort);
+}
+
BOOST_AUTO_TEST_CASE(caddrdb_read)
{
CAddrManUncorrupted addrmanUncorrupted;
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index a9936a645a..510f540b1d 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -9,14 +9,17 @@
#include "utiltime.h"
+#include <atomic>
+
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
-static int64_t nMockTime = 0; //!< For unit testing
+static std::atomic<int64_t> nMockTime(0); //!< For unit testing
int64_t GetTime()
{
- if (nMockTime) return nMockTime;
+ int64_t mocktime = nMockTime.load(std::memory_order_relaxed);
+ if (mocktime) return mocktime;
time_t now = time(NULL);
assert(now > 0);
@@ -25,7 +28,7 @@ int64_t GetTime()
void SetMockTime(int64_t nMockTimeIn)
{
- nMockTime = nMockTimeIn;
+ nMockTime.store(nMockTimeIn, std::memory_order_relaxed);
}
int64_t GetTimeMillis()
@@ -52,7 +55,8 @@ int64_t GetSystemTimeInSeconds()
/** Return a time useful for the debug log */
int64_t GetLogTimeMicros()
{
- if (nMockTime) return nMockTime*1000000;
+ int64_t mocktime = nMockTime.load(std::memory_order_relaxed);
+ if (mocktime) return mocktime*1000000;
return GetTimeMicros();
}
diff --git a/src/validation.cpp b/src/validation.cpp
index 6c60be45a1..f189b741cd 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1299,10 +1299,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
- if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) {
- return false;
- }
- return true;
+ return VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error);
}
int GetSpendHeight(const CCoinsViewCache& inputs)
@@ -2537,6 +2534,9 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
return false;
}
+ int nStopAtHeight = GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);
+ if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
+
return true;
}
diff --git a/src/validation.h b/src/validation.h
index c0f9b6d513..24ebf238df 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -145,6 +145,9 @@ static const int MAX_UNCONNECTING_HEADERS = 10;
static const bool DEFAULT_PEERBLOOMFILTERS = true;
+/** Default for -stopatheight */
+static const int DEFAULT_STOPATHEIGHT = 0;
+
struct BlockHasher
{
size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); }
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index c810476f96..25f6bdd9d9 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -466,15 +466,6 @@ void CDBEnv::CloseDb(const std::string& strFile)
}
}
-bool CDBEnv::RemoveDb(const std::string& strFile)
-{
- this->CloseDb(strFile);
-
- LOCK(cs_db);
- int rc = dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
- return (rc == 0);
-}
-
bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
{
if (dbw.IsDummy()) {
diff --git a/src/wallet/db.h b/src/wallet/db.h
index a0719820ac..1a46448cc7 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -72,7 +72,6 @@ public:
void CheckpointLSN(const std::string& strFile);
void CloseDb(const std::string& strFile);
- bool RemoveDb(const std::string& strFile);
DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
{
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 82e5974065..f5b63c1ecd 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -160,7 +160,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
} else {
// if user specified a confirm target then don't consider any global payTxFee
if (specifiedConfirmTarget) {
- nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, CAmount(0));
+ nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, true);
}
// otherwise use the regular wallet logic to select payTxFee or default confirm target
else {
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index f8006a6255..d1e7485d04 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -729,6 +729,8 @@ UniValue getbalance(const JSONRPCRequest& request)
if (request.params.size() == 0)
return ValueFromAmount(pwallet->GetBalance());
+ const std::string* account = request.params[0].get_str() != "*" ? &request.params[0].get_str() : nullptr;
+
int nMinDepth = 1;
if (request.params.size() > 1)
nMinDepth = request.params[1].get_int();
@@ -737,41 +739,7 @@ UniValue getbalance(const JSONRPCRequest& request)
if(request.params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
- if (request.params[0].get_str() == "*") {
- // Calculate total balance in a very different way from GetBalance().
- // The biggest difference is that GetBalance() sums up all unspent
- // TxOuts paying to the wallet, while this sums up both spent and
- // unspent TxOuts paying to the wallet, and then subtracts the values of
- // TxIns spending from the wallet. This also has fewer restrictions on
- // which unconfirmed transactions are considered trusted.
- CAmount nBalance = 0;
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
- const CWalletTx& wtx = pairWtx.second;
- if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
- continue;
-
- CAmount allFee;
- std::string strSentAccount;
- std::list<COutputEntry> listReceived;
- std::list<COutputEntry> listSent;
- wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
- if (wtx.GetDepthInMainChain() >= nMinDepth)
- {
- BOOST_FOREACH(const COutputEntry& r, listReceived)
- nBalance += r.amount;
- }
- BOOST_FOREACH(const COutputEntry& s, listSent)
- nBalance -= s.amount;
- nBalance -= allFee;
- }
- return ValueFromAmount(nBalance);
- }
-
- std::string strAccount = AccountFromValue(request.params[0]);
-
- CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, filter);
-
- return ValueFromAmount(nBalance);
+ return ValueFromAmount(pwallet->GetLegacyBalance(filter, nMinDepth, account));
}
UniValue getunconfirmedbalance(const JSONRPCRequest &request)
@@ -901,7 +869,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
// Check funds
- CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
if (nAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
@@ -1010,7 +978,7 @@ UniValue sendmany(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
// Check funds
- CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
if (totalAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 211be76c45..a8f818a494 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1124,12 +1124,12 @@ void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
LOCK2(cs_main, cs_wallet);
- // TODO: Tempoarily ensure that mempool removals are notified before
+ // TODO: Temporarily ensure that mempool removals are notified before
// connected transactions. This shouldn't matter, but the abandoned
// state of transactions in our wallet is currently cleared when we
// receive another notification and there is a race condition where
// notification of a connected conflict might cause an outside process
- // to abandon a transaction and then have it inadvertantly cleared by
+ // to abandon a transaction and then have it inadvertently cleared by
// the notification that the conflicted transaction was evicted.
for (const CTransactionRef& ptx : vtxConflicted) {
@@ -1457,41 +1457,6 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
}
-void CWalletTx::GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
- CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
-{
- nReceived = nSent = nFee = 0;
-
- CAmount allFee;
- std::string strSentAccount;
- std::list<COutputEntry> listReceived;
- std::list<COutputEntry> listSent;
- GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
-
- if (strAccount == strSentAccount)
- {
- BOOST_FOREACH(const COutputEntry& s, listSent)
- nSent += s.amount;
- nFee = allFee;
- }
- {
- LOCK(pwallet->cs_wallet);
- BOOST_FOREACH(const COutputEntry& r, listReceived)
- {
- if (pwallet->mapAddressBook.count(r.destination))
- {
- std::map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
- if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
- nReceived += r.amount;
- }
- else if (strAccount.empty())
- {
- nReceived += r.amount;
- }
- }
- }
-}
-
/**
* Scan the block chain (starting in pindexStart) for transactions
* from or to us. If fUpdate is true, found transactions that already
@@ -1526,6 +1491,10 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
{
if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0)
ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((GuessVerificationProgress(chainParams.TxData(), pindex) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
+ if (GetTime() >= nNow + 60) {
+ nNow = GetTime();
+ LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
+ }
CBlock block;
if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
@@ -1539,10 +1508,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
ret = nullptr;
}
pindex = chainActive.Next(pindex);
- if (GetTime() >= nNow + 60) {
- nNow = GetTime();
- LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
- }
}
if (pindex && fAbortRescan) {
LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
@@ -1975,6 +1940,49 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
return nTotal;
}
+// Calculate total balance in a different way from GetBalance. The biggest
+// difference is that GetBalance sums up all unspent TxOuts paying to the
+// wallet, while this sums up both spent and unspent TxOuts paying to the
+// wallet, and then subtracts the values of TxIns spending from the wallet. This
+// also has fewer restrictions on which unconfirmed transactions are considered
+// trusted.
+CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const
+{
+ LOCK2(cs_main, cs_wallet);
+
+ CAmount balance = 0;
+ for (const auto& entry : mapWallet) {
+ const CWalletTx& wtx = entry.second;
+ const int depth = wtx.GetDepthInMainChain();
+ if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.GetBlocksToMaturity() > 0) {
+ continue;
+ }
+
+ // Loop through tx outputs and add incoming payments. For outgoing txs,
+ // treat change outputs specially, as part of the amount debited.
+ CAmount debit = wtx.GetDebit(filter);
+ const bool outgoing = debit > 0;
+ for (const CTxOut& out : wtx.tx->vout) {
+ if (outgoing && IsChange(out)) {
+ debit -= out.nValue;
+ } else if (IsMine(out) & filter && depth >= minDepth && (!account || *account == GetAccountName(out.scriptPubKey))) {
+ balance += out.nValue;
+ }
+ }
+
+ // For outgoing txs, subtract amount debited.
+ if (outgoing && (!account || *account == wtx.strFromAccount)) {
+ balance -= debit;
+ }
+ }
+
+ if (account) {
+ balance += CWalletDB(*dbw).GetAccountCreditDebit(*account);
+ }
+
+ return balance;
+}
+
void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const CCoinControl *coinControl, bool fIncludeZeroValue) const
{
vCoins.clear();
@@ -2555,9 +2563,10 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
std::vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut;
txNew.vout.insert(position, newTxOut);
}
- }
- else
+ } else {
reservekey.ReturnKey();
+ nChangePosInOut = -1;
+ }
// Fill vin
//
@@ -2769,17 +2778,12 @@ CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
}
-CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator)
+CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, bool ignoreUserSetFee)
{
// payTxFee is the user-set global for desired feerate
- return GetMinimumFee(nTxBytes, nConfirmTarget, pool, estimator, payTxFee.GetFee(nTxBytes));
-}
-
-CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, CAmount targetFee)
-{
- CAmount nFeeNeeded = targetFee;
+ CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
// User didn't set: use -txconfirmtarget to estimate...
- if (nFeeNeeded == 0) {
+ if (nFeeNeeded == 0 || ignoreUserSetFee) {
int estimateFoundTarget = nConfirmTarget;
nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, &estimateFoundTarget, pool).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
@@ -2911,6 +2915,21 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
}
+const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
+{
+ CTxDestination address;
+ if (ExtractDestination(scriptPubKey, address) && !scriptPubKey.IsUnspendable()) {
+ auto mi = mapAddressBook.find(address);
+ if (mi != mapAddressBook.end()) {
+ return mi->second.name;
+ }
+ }
+ // A scriptPubKey that doesn't have an entry in the address book is
+ // associated with the default account ("").
+ const static std::string DEFAULT_ACCOUNT_NAME;
+ return DEFAULT_ACCOUNT_NAME;
+}
+
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
{
if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
@@ -3257,37 +3276,6 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
return ret;
}
-CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CWalletDB walletdb(*dbw);
- return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
-}
-
-CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CAmount nBalance = 0;
-
- // Tally wallet transactions
- for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
- continue;
-
- CAmount nReceived, nSent, nFee;
- wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
-
- if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- nBalance += nReceived;
- nBalance -= nSent + nFee;
- }
-
- // Tally internal accounting entries
- nBalance += walletdb.GetAccountCreditDebit(strAccount);
-
- return nBalance;
-}
-
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index a52ae99ed1..8015cc8492 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -451,9 +451,6 @@ public:
void GetAmounts(std::list<COutputEntry>& listReceived,
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
- void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
- CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
-
bool IsFromMe(const isminefilter& filter) const
{
return (GetDebit(filter) > 0);
@@ -918,6 +915,7 @@ public:
CAmount GetWatchOnlyBalance() const;
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
+ CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const;
/**
* Insert additional inputs into the transaction by
@@ -947,12 +945,7 @@ public:
* Estimate the minimum fee considering user set parameters
* and the required fee
*/
- static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator);
- /**
- * Estimate the minimum fee considering required fee and targetFee or if 0
- * then fee estimation for nConfirmTarget
- */
- static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, CAmount targetFee);
+ static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, bool ignoreUserSetFee = false);
/**
* Return the minimum required fee taking into account the
* floating relay fee and user set minimum transaction fee
@@ -972,8 +965,6 @@ public:
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
- CAmount GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter);
- CAmount GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter);
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
isminetype IsMine(const CTxIn& txin) const;
@@ -1004,6 +995,8 @@ public:
bool DelAddressBook(const CTxDestination& address);
+ const std::string& GetAccountName(const CScript& scriptPubKey) const;
+
void Inventory(const uint256 &hash) override
{
{
diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py
index b86ea2d877..e0ca94a6b3 100755
--- a/test/functional/fundrawtransaction.py
+++ b/test/functional/fundrawtransaction.py
@@ -53,6 +53,11 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[0].generate(121)
self.sync_all()
+ # ensure that setting changePosition in fundraw with an exact match is handled properly
+ rawmatch = self.nodes[2].createrawtransaction([], {self.nodes[2].getnewaddress():50})
+ rawmatch = self.nodes[2].fundrawtransaction(rawmatch, {"changePosition":1, "subtractFeeFromOutputs":[0]})
+ assert_equal(rawmatch["changepos"], -1)
+
watchonly_address = self.nodes[0].getnewaddress()
watchonly_pubkey = self.nodes[0].validateaddress(watchonly_address)["pubkey"]
watchonly_amount = Decimal(200)
diff --git a/test/functional/import-abort-rescan.py b/test/functional/import-abort-rescan.py
new file mode 100755
index 0000000000..ffe45bbb1d
--- /dev/null
+++ b/test/functional/import-abort-rescan.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test wallet import RPCs.
+
+Test rescan behavior of importprivkey when aborted. The test ensures that:
+1. The abortrescan command indeed stops the rescan process.
+2. Subsequent rescan catches the aborted address UTXO
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (assert_equal, get_rpc_proxy)
+from decimal import Decimal
+import threading # for bg importprivkey
+import time # for sleep
+
+class ImportAbortRescanTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+
+ def run_test(self):
+ # Generate for BTC
+ assert_equal(self.nodes[0].getbalance(), 0)
+ assert_equal(self.nodes[1].getbalance(), 0)
+ self.nodes[0].generate(300)
+ assert_equal(self.nodes[1].getbalance(), 0)
+ # Make blocks with spam to cause rescan delay
+ for i in range(5):
+ for j in range(5):
+ self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)
+ self.nodes[0].generate(10)
+ addr = self.nodes[0].getnewaddress()
+ privkey = self.nodes[0].dumpprivkey(addr)
+ self.nodes[0].sendtoaddress(addr, 0.123)
+ self.nodes[0].generate(10) # mature tx
+ self.sync_all()
+
+ # Import this address in the background ...
+ node1ref = get_rpc_proxy(self.nodes[1].url, 1, timeout=600)
+ importthread = threading.Thread(target=node1ref.importprivkey, args=[privkey])
+ importthread.start()
+ # ... then abort rescan; try a bunch until abortres becomes true,
+ # because we will start checking before above thread starts processing
+ for i in range(2000):
+ time.sleep(0.001)
+ abortres = self.nodes[1].abortrescan()
+ if abortres: break
+ assert abortres # if false, we failed to abort
+ # import should die soon
+ for i in range(10):
+ time.sleep(0.1)
+ deadres = not importthread.isAlive()
+ if deadres: break
+
+ assert deadres # if false, importthread did not die soon enough
+ assert_equal(self.nodes[1].getbalance(), 0.0)
+
+ # Import a different address and let it run
+ self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress()))
+ # Expect original privkey to now also be discovered and added to balance
+ assert_equal(self.nodes[1].getbalance(), Decimal("0.123"))
+
+if __name__ == "__main__":
+ ImportAbortRescanTest().main()
diff --git a/test/functional/net.py b/test/functional/net.py
index a82cdabf52..9eae140455 100755
--- a/test/functional/net.py
+++ b/test/functional/net.py
@@ -32,6 +32,39 @@ class NetTest(BitcoinTestFramework):
self.sync_all()
def run_test(self):
+ self._test_connection_count()
+ self._test_getnettotals()
+ self._test_getnetworkinginfo()
+ self._test_getaddednodeinfo()
+
+ def _test_connection_count(self):
+ # connect_nodes_bi connects each node to the other
+ assert_equal(self.nodes[0].getconnectioncount(), 2)
+
+ def _test_getnettotals(self):
+ # check that getnettotals totalbytesrecv and totalbytessent
+ # are consistent with getpeerinfo
+ peer_info = self.nodes[0].getpeerinfo()
+ assert_equal(len(peer_info), 2)
+ net_totals = self.nodes[0].getnettotals()
+ assert_equal(sum([peer['bytesrecv'] for peer in peer_info]),
+ net_totals['totalbytesrecv'])
+ assert_equal(sum([peer['bytessent'] for peer in peer_info]),
+ net_totals['totalbytessent'])
+ # test getnettotals and getpeerinfo by doing a ping
+ # the bytes sent/received should change
+ # note ping and pong are 32 bytes each
+ self.nodes[0].ping()
+ time.sleep(0.1)
+ peer_info_after_ping = self.nodes[0].getpeerinfo()
+ net_totals_after_ping = self.nodes[0].getnettotals()
+ for before, after in zip(peer_info, peer_info_after_ping):
+ assert_equal(before['bytesrecv_per_msg']['pong'] + 32, after['bytesrecv_per_msg']['pong'])
+ assert_equal(before['bytessent_per_msg']['ping'] + 32, after['bytessent_per_msg']['ping'])
+ assert_equal(net_totals['totalbytesrecv'] + 32*2, net_totals_after_ping['totalbytesrecv'])
+ assert_equal(net_totals['totalbytessent'] + 32*2, net_totals_after_ping['totalbytessent'])
+
+ def _test_getnetworkinginfo(self):
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
@@ -49,7 +82,7 @@ class NetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
- # test getaddednodeinfo
+ def _test_getaddednodeinfo(self):
assert_equal(self.nodes[0].getaddednodeinfo(), [])
# add a node (node2) to node0
ip_port = "127.0.0.1:{}".format(p2p_port(2))
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 2932f82970..0996b1bc20 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -109,6 +109,7 @@ BASE_SCRIPTS= [
'rpcnamedargs.py',
'listsinceblock.py',
'p2p-leaktests.py',
+ 'import-abort-rescan.py',
]
EXTENDED_SCRIPTS = [
diff --git a/test/functional/wallet.py b/test/functional/wallet.py
index 80f74fa108..558ffadfd4 100755
--- a/test/functional/wallet.py
+++ b/test/functional/wallet.py
@@ -6,7 +6,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-class WalletTest (BitcoinTestFramework):
+class WalletTest(BitcoinTestFramework):
def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
"""Return curr_balance after asserting the fee was in range"""
@@ -28,7 +28,7 @@ class WalletTest (BitcoinTestFramework):
self.is_network_split=False
self.sync_all()
- def run_test (self):
+ def run_test(self):
# Check that there's no UTXO on none of the nodes
assert_equal(len(self.nodes[0].listunspent()), 0)
@@ -52,13 +52,33 @@ class WalletTest (BitcoinTestFramework):
assert_equal(self.nodes[2].getbalance(), 0)
# Check that only first and second nodes have UTXOs
- assert_equal(len(self.nodes[0].listunspent()), 1)
+ utxos = self.nodes[0].listunspent()
+ assert_equal(len(utxos), 1)
assert_equal(len(self.nodes[1].listunspent()), 1)
assert_equal(len(self.nodes[2].listunspent()), 0)
# Send 21 BTC from 0 to 2 using sendtoaddress call.
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)
- self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)
+ mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)
+
+ self.log.info("test gettxout")
+ # utxo spent in mempool should be visible if you exclude mempool
+ # but invisible if you include mempool
+ confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"]
+ txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False)
+ assert_equal(txout['value'], 50)
+ txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True)
+ assert txout is None
+ # new utxo from mempool should be invisible if you exclude mempool
+ # but visible if you include mempool
+ txout = self.nodes[0].gettxout(mempool_txid, 0, False)
+ assert txout is None
+ txout1 = self.nodes[0].gettxout(mempool_txid, 0, True)
+ txout2 = self.nodes[0].gettxout(mempool_txid, 1, True)
+ # note the mempool tx will have randomly assigned indices
+ # but 10 will go to node2 and the rest will go to node0
+ balance = self.nodes[0].getbalance()
+ assert_equal(set([txout1['value'], txout2['value']]), set([10, balance]))
walletinfo = self.nodes[0].getwalletinfo()
assert_equal(walletinfo['immature_balance'], 0)
diff --git a/test/util/data/blanktxv1.json b/test/util/data/blanktxv1.json
index 51c25a5a98..9fe2de649b 100644
--- a/test/util/data/blanktxv1.json
+++ b/test/util/data/blanktxv1.json
@@ -2,6 +2,8 @@
"txid": "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43",
"hash": "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43",
"version": 1,
+ "size": 10,
+ "vsize": 10,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/blanktxv2.json b/test/util/data/blanktxv2.json
index 266919f445..e97626e421 100644
--- a/test/util/data/blanktxv2.json
+++ b/test/util/data/blanktxv2.json
@@ -2,6 +2,8 @@
"txid": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a",
"hash": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a",
"version": 2,
+ "size": 10,
+ "vsize": 10,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/tt-delin1-out.json b/test/util/data/tt-delin1-out.json
index 712a2c27f8..f6dfbb51cc 100644
--- a/test/util/data/tt-delin1-out.json
+++ b/test/util/data/tt-delin1-out.json
@@ -2,6 +2,8 @@
"txid": "81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd",
"hash": "81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd",
"version": 1,
+ "size": 3040,
+ "vsize": 3040,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/tt-delout1-out.json b/test/util/data/tt-delout1-out.json
index afc4e95762..6769ed79ff 100644
--- a/test/util/data/tt-delout1-out.json
+++ b/test/util/data/tt-delout1-out.json
@@ -2,6 +2,8 @@
"txid": "c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493",
"hash": "c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493",
"version": 1,
+ "size": 3155,
+ "vsize": 3155,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/tt-locktime317000-out.json b/test/util/data/tt-locktime317000-out.json
index 2b9075f8ac..82b64df075 100644
--- a/test/util/data/tt-locktime317000-out.json
+++ b/test/util/data/tt-locktime317000-out.json
@@ -2,6 +2,8 @@
"txid": "aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5",
"hash": "aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5",
"version": 1,
+ "size": 3189,
+ "vsize": 3189,
"locktime": 317000,
"vin": [
{
diff --git a/test/util/data/txcreate1.json b/test/util/data/txcreate1.json
index f83e036f33..36741044c9 100644
--- a/test/util/data/txcreate1.json
+++ b/test/util/data/txcreate1.json
@@ -2,6 +2,8 @@
"txid": "fe7d174f42dce0cffa7a527e9bc8368956057619ec817648f6138b98f2533e8f",
"hash": "fe7d174f42dce0cffa7a527e9bc8368956057619ec817648f6138b98f2533e8f",
"version": 2,
+ "size": 201,
+ "vsize": 201,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreate2.json b/test/util/data/txcreate2.json
index fb5e177db7..23fe7ace67 100644
--- a/test/util/data/txcreate2.json
+++ b/test/util/data/txcreate2.json
@@ -2,6 +2,8 @@
"txid": "0481afb29931341d0d7861d8a2f6f26456fa042abf54a23e96440ed7946e0715",
"hash": "0481afb29931341d0d7861d8a2f6f26456fa042abf54a23e96440ed7946e0715",
"version": 2,
+ "size": 19,
+ "vsize": 19,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatedata1.json b/test/util/data/txcreatedata1.json
index 760518d30a..e65a1859eb 100644
--- a/test/util/data/txcreatedata1.json
+++ b/test/util/data/txcreatedata1.json
@@ -2,6 +2,8 @@
"txid": "07894b4d12fe7853dd911402db1620920d261b9627c447f931417d330c25f06e",
"hash": "07894b4d12fe7853dd911402db1620920d261b9627c447f931417d330c25f06e",
"version": 1,
+ "size": 176,
+ "vsize": 176,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreatedata2.json b/test/util/data/txcreatedata2.json
index 3c6da40f90..8f1544e1c0 100644
--- a/test/util/data/txcreatedata2.json
+++ b/test/util/data/txcreatedata2.json
@@ -2,6 +2,8 @@
"txid": "c14b007fa3a6c1e7765919c1d14c1cfc2b8642c3a5d3be4b1fa8c4ccfec98bb0",
"hash": "c14b007fa3a6c1e7765919c1d14c1cfc2b8642c3a5d3be4b1fa8c4ccfec98bb0",
"version": 2,
+ "size": 176,
+ "vsize": 176,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreatedata_seq0.json b/test/util/data/txcreatedata_seq0.json
index d272a4c447..e52401f418 100644
--- a/test/util/data/txcreatedata_seq0.json
+++ b/test/util/data/txcreatedata_seq0.json
@@ -2,6 +2,8 @@
"txid": "8df6ed527472542dd5e137c242a7c5a9f337ac34f7b257ae4af886aeaebb51b0",
"hash": "8df6ed527472542dd5e137c242a7c5a9f337ac34f7b257ae4af886aeaebb51b0",
"version": 2,
+ "size": 85,
+ "vsize": 85,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreatedata_seq1.json b/test/util/data/txcreatedata_seq1.json
index d323255418..093ff4a56b 100644
--- a/test/util/data/txcreatedata_seq1.json
+++ b/test/util/data/txcreatedata_seq1.json
@@ -2,6 +2,8 @@
"txid": "c4dea671b0d7b48f8ab10bc46650e8329d3c5766931f548f513847a19f5ba75b",
"hash": "c4dea671b0d7b48f8ab10bc46650e8329d3c5766931f548f513847a19f5ba75b",
"version": 1,
+ "size": 126,
+ "vsize": 126,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreatemultisig1.json b/test/util/data/txcreatemultisig1.json
index f6ce43c202..0cc530836a 100644
--- a/test/util/data/txcreatemultisig1.json
+++ b/test/util/data/txcreatemultisig1.json
@@ -2,6 +2,8 @@
"txid": "0d1d4edfc217d9db3ab6a9298f26a52eae3c52f55a6cb8ccbc14f7c727572894",
"hash": "0d1d4edfc217d9db3ab6a9298f26a52eae3c52f55a6cb8ccbc14f7c727572894",
"version": 1,
+ "size": 124,
+ "vsize": 124,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatemultisig2.json b/test/util/data/txcreatemultisig2.json
index e09d22060f..8ad2ffdc65 100644
--- a/test/util/data/txcreatemultisig2.json
+++ b/test/util/data/txcreatemultisig2.json
@@ -2,6 +2,8 @@
"txid": "0d861f278a3b7bce7cb5a88d71e6e6a903336f95ad5a2c29b295b63835b6eee3",
"hash": "0d861f278a3b7bce7cb5a88d71e6e6a903336f95ad5a2c29b295b63835b6eee3",
"version": 1,
+ "size": 42,
+ "vsize": 42,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatemultisig3.json b/test/util/data/txcreatemultisig3.json
index 88e32bd310..086bf44b8a 100644
--- a/test/util/data/txcreatemultisig3.json
+++ b/test/util/data/txcreatemultisig3.json
@@ -2,6 +2,8 @@
"txid": "ccc552220b46a3b5140048b03395987ce4f0fa1ddf8c635bba1fa44e0f8c1d7f",
"hash": "ccc552220b46a3b5140048b03395987ce4f0fa1ddf8c635bba1fa44e0f8c1d7f",
"version": 1,
+ "size": 53,
+ "vsize": 53,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatemultisig4.json b/test/util/data/txcreatemultisig4.json
index fc69c7269c..d23ccc045e 100644
--- a/test/util/data/txcreatemultisig4.json
+++ b/test/util/data/txcreatemultisig4.json
@@ -2,6 +2,8 @@
"txid": "5e8b1cc73234e208d4b7ca9075f136b908c34101be7a048df4ba9ac758b61567",
"hash": "5e8b1cc73234e208d4b7ca9075f136b908c34101be7a048df4ba9ac758b61567",
"version": 1,
+ "size": 42,
+ "vsize": 42,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreateoutpubkey1.json b/test/util/data/txcreateoutpubkey1.json
index 6019fa2dcd..f10aaecf7a 100644
--- a/test/util/data/txcreateoutpubkey1.json
+++ b/test/util/data/txcreateoutpubkey1.json
@@ -2,6 +2,8 @@
"txid": "f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f",
"hash": "f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f",
"version": 1,
+ "size": 54,
+ "vsize": 54,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreateoutpubkey2.json b/test/util/data/txcreateoutpubkey2.json
index 6fc3d57527..5a473b76c3 100644
--- a/test/util/data/txcreateoutpubkey2.json
+++ b/test/util/data/txcreateoutpubkey2.json
@@ -2,6 +2,8 @@
"txid": "70f2a088cde460e677415fa1fb71895e90c231e6ed38ed203a35b6f848e9cc73",
"hash": "70f2a088cde460e677415fa1fb71895e90c231e6ed38ed203a35b6f848e9cc73",
"version": 1,
+ "size": 41,
+ "vsize": 41,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreateoutpubkey3.json b/test/util/data/txcreateoutpubkey3.json
index a1a25fc834..b8389b8f7e 100644
--- a/test/util/data/txcreateoutpubkey3.json
+++ b/test/util/data/txcreateoutpubkey3.json
@@ -2,6 +2,8 @@
"txid": "bfc7e898ee9f6a9652d7b8cca147e2da134502e2ada0f279ed634fc8cf833f8c",
"hash": "bfc7e898ee9f6a9652d7b8cca147e2da134502e2ada0f279ed634fc8cf833f8c",
"version": 1,
+ "size": 42,
+ "vsize": 42,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatescript1.json b/test/util/data/txcreatescript1.json
index 8ffecba411..823168e9fb 100644
--- a/test/util/data/txcreatescript1.json
+++ b/test/util/data/txcreatescript1.json
@@ -2,6 +2,8 @@
"txid": "f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9",
"hash": "f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9",
"version": 1,
+ "size": 20,
+ "vsize": 20,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatescript2.json b/test/util/data/txcreatescript2.json
index 41eb69f1af..d4c7e10c78 100644
--- a/test/util/data/txcreatescript2.json
+++ b/test/util/data/txcreatescript2.json
@@ -2,6 +2,8 @@
"txid": "6e07a7cc075e0703f32ee8c4e5373fe654bfbc315148fda364e1be286ff290d0",
"hash": "6e07a7cc075e0703f32ee8c4e5373fe654bfbc315148fda364e1be286ff290d0",
"version": 1,
+ "size": 42,
+ "vsize": 42,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatescript3.json b/test/util/data/txcreatescript3.json
index 90e7e27f9f..001e69511f 100644
--- a/test/util/data/txcreatescript3.json
+++ b/test/util/data/txcreatescript3.json
@@ -2,6 +2,8 @@
"txid": "8a234037b088e987c877030efc83374a07441c321bf9dc6dd2f206bc26507df8",
"hash": "8a234037b088e987c877030efc83374a07441c321bf9dc6dd2f206bc26507df8",
"version": 1,
+ "size": 53,
+ "vsize": 53,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatescript4.json b/test/util/data/txcreatescript4.json
index 11783751a4..20094bcd44 100644
--- a/test/util/data/txcreatescript4.json
+++ b/test/util/data/txcreatescript4.json
@@ -2,6 +2,8 @@
"txid": "24225cf5e9391100d6b218134b9f03383ca4c880a1f634ac12990cf28b66adbc",
"hash": "24225cf5e9391100d6b218134b9f03383ca4c880a1f634ac12990cf28b66adbc",
"version": 1,
+ "size": 42,
+ "vsize": 42,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatesignv1.json b/test/util/data/txcreatesignv1.json
index ff39e71b40..519d3ab066 100644
--- a/test/util/data/txcreatesignv1.json
+++ b/test/util/data/txcreatesignv1.json
@@ -2,6 +2,8 @@
"txid": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
"hash": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
"version": 1,
+ "size": 224,
+ "vsize": 224,
"locktime": 0,
"vin": [
{