aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release-notes.md29
-rwxr-xr-xqa/pull-tester/rpc-tests.sh1
-rwxr-xr-xqa/rpc-tests/mempool_spendcoinbase.py69
-rw-r--r--qa/rpc-tests/util.py12
-rw-r--r--src/init.cpp10
-rw-r--r--src/init.h6
-rw-r--r--src/main.cpp149
-rw-r--r--src/main.h184
-rw-r--r--src/rpcblockchain.cpp6
9 files changed, 305 insertions, 161 deletions
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 6aaea67790..f804e8c11b 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -95,3 +95,32 @@ are done, it always returns an immediate error with code -28 to all calls.
This new behaviour can be useful for clients to know that a server is already
started and will be available soon (for instance, so that they do not
have to start it themselves).
+
+Improved signing security
+=========================
+
+For 0.10 the security of signing against unusual attacks has been
+improved by making the signatures constant time and deterministic.
+
+This change is a result of switching signing to use libsecp256k1
+instead of OpenSSL. Libsecp256k1 is a cryptographic library
+optimized for the curve Bitcoin uses which was created by Bitcoin
+Core developer Pieter Wuille.
+
+There exist attacks[1] against most ECC implementations where an
+attacker on shared virtual machine hardware could extract a private
+key if they could cause a target to sign using the same key hundreds
+of times. While using shared hosts and reusing keys are inadvisable
+for other reasons, it's a better practice to avoid the exposure.
+
+OpenSSL has code in their source repository for derandomization
+and reduction in timing leaks, and we've eagerly wanted to use
+it for a long time but this functionality has still not made its
+way into a released version of OpenSSL. Libsecp256k1 achieves
+significantly stronger protection: As far as we're aware this is
+the only deployed implementation of constant time signing for
+the curve Bitcoin uses and we have reason to believe that
+libsecp256k1 is better tested and more thoroughly reviewed
+than the implementation in OpenSSL.
+
+[1] https://eprint.iacr.org/2014/161.pdf
diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh
index b888135492..a93b80686b 100755
--- a/qa/pull-tester/rpc-tests.sh
+++ b/qa/pull-tester/rpc-tests.sh
@@ -23,6 +23,7 @@ if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then
${BUILDDIR}/qa/rpc-tests/txn_doublespend.py --mineblock --srcdir "${BUILDDIR}/src"
${BUILDDIR}/qa/rpc-tests/getchaintips.py --srcdir "${BUILDDIR}/src"
${BUILDDIR}/qa/rpc-tests/rest.py --srcdir "${BUILDDIR}/src"
+ ${BUILDDIR}/qa/rpc-tests/mempool_spendcoinbase.py --srcdir "${BUILDDIR}/src"
#${BUILDDIR}/qa/rpc-tests/forknotify.py --srcdir "${BUILDDIR}/src"
else
echo "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled"
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py
new file mode 100755
index 0000000000..0fc7c8577e
--- /dev/null
+++ b/qa/rpc-tests/mempool_spendcoinbase.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 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 spending coinbase transactions.
+# The coinbase transaction in block N can appear in block
+# N+100... so is valid in the mempool when the best block
+# height is N+99.
+# This test makes sure coinbase spends that will be mature
+# in the next block are accepted into the memory pool,
+# but less mature coinbase spends are NOT.
+#
+
+from test_framework import BitcoinTestFramework
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+import os
+import shutil
+
+# Create one-input, one-output, no-fee transaction:
+class MempoolSpendCoinbaseTest(BitcoinTestFramework):
+
+ def setup_network(self):
+ # Just need one node for this test
+ args = ["-checkmempool", "-debug=mempool"]
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, args))
+ self.is_network_split = False
+
+ def create_tx(self, from_txid, to_address, amount):
+ inputs = [{ "txid" : from_txid, "vout" : 0}]
+ outputs = { to_address : amount }
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ signresult = self.nodes[0].signrawtransaction(rawtx)
+ assert_equal(signresult["complete"], True)
+ return signresult["hex"]
+
+ def run_test(self):
+ chain_height = self.nodes[0].getblockcount()
+ assert_equal(chain_height, 200)
+ node0_address = self.nodes[0].getnewaddress()
+
+ # Coinbase at height chain_height-100+1 ok in mempool, should
+ # get mined. Coinbase at height chain_height-100+2 is
+ # is too immature to spend.
+ b = [ self.nodes[0].getblockhash(n) for n in range(101, 103) ]
+ coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
+ spends_raw = [ self.create_tx(txid, node0_address, 50) for txid in coinbase_txids ]
+
+ spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])
+
+ # coinbase at height 102 should be too immature to spend
+ assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1])
+
+ # mempool should have just spend_101:
+ assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])
+
+ # mine a block, spend_101 should get confirmed
+ self.nodes[0].setgenerate(True, 1)
+ assert_equal(set(self.nodes[0].getrawmempool()), set())
+
+ # ... and now height 102 can be spent:
+ spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1])
+ assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ])
+
+if __name__ == '__main__':
+ MempoolSpendCoinbaseTest().main()
diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py
index 6b66bfd8f6..ec65f783e8 100644
--- a/qa/rpc-tests/util.py
+++ b/qa/rpc-tests/util.py
@@ -330,4 +330,14 @@ def assert_equal(thing1, thing2):
def assert_greater_than(thing1, thing2):
if thing1 <= thing2:
- raise AssertionError("%s <= %s"%(str(thing1),str(thing2))) \ No newline at end of file
+ raise AssertionError("%s <= %s"%(str(thing1),str(thing2)))
+
+def assert_raises(exc, fun, *args, **kwds):
+ try:
+ fun(*args, **kwds)
+ except exc:
+ pass
+ except Exception as e:
+ raise AssertionError("Unexpected exception raised: "+type(e).__name__)
+ else:
+ raise AssertionError("No exception raised")
diff --git a/src/init.cpp b/src/init.cpp
index 7b6ebb1b30..11329c16aa 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
@@ -60,7 +60,7 @@ bool fFeeEstimatesInitialized = false;
#define MIN_CORE_FILEDESCRIPTORS 150
#endif
-// Used to pass flags to the Bind() function
+/** Used to pass flags to the Bind() function */
enum BindFlags {
BF_NONE = 0,
BF_EXPLICIT = (1U << 0),
@@ -175,9 +175,9 @@ void Shutdown()
LogPrintf("%s: done\n", __func__);
}
-//
-// Signal handlers are very limited in what they are allowed to do, so:
-//
+/**
+ * Signal handlers are very limited in what they are allowed to do, so:
+ */
void HandleSIGTERM(int)
{
fRequestShutdown = true;
diff --git a/src/init.h b/src/init.h
index aaf8c07e6e..f2f7ac6747 100644
--- a/src/init.h
+++ b/src/init.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_INIT_H
@@ -22,7 +22,7 @@ bool ShutdownRequested();
void Shutdown();
bool AppInit2(boost::thread_group& threadGroup);
-/* The help message mode determines what help message to show */
+/** The help message mode determines what help message to show */
enum HelpMessageMode {
HMM_BITCOIND,
HMM_BITCOIN_QT
diff --git a/src/main.cpp b/src/main.cpp
index 0515eeb156..451d6c8cd9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
@@ -33,9 +33,9 @@ using namespace std;
# error "Bitcoin cannot be compiled without assertions."
#endif
-//
-// Global state
-//
+/**
+ * Global state
+ */
CCriticalSection cs_main;
@@ -66,7 +66,7 @@ map<uint256, COrphanTx> mapOrphanTransactions;
map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
void EraseOrphansFor(NodeId peer);
-// Constant stuff for coinbase transactions we create:
+/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
const string strMessageMagic = "Bitcoin Signed Message:\n";
@@ -97,44 +97,49 @@ namespace {
CBlockIndex *pindexBestInvalid;
- // The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS or better that are at least
- // as good as our current tip. Entries may be failed, though.
+ /**
+ * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS or better that are at least
+ * as good as our current tip. Entries may be failed, though.
+ */
set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
- // Number of nodes with fSyncStarted.
+ /** Number of nodes with fSyncStarted. */
int nSyncStarted = 0;
- // All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions.
+ /** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions. */
multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
int nLastBlockFile = 0;
- // Every received block is assigned a unique and increasing identifier, so we
- // know which one to give priority in case of a fork.
+ /**
+ * Every received block is assigned a unique and increasing identifier, so we
+ * know which one to give priority in case of a fork.
+ */
CCriticalSection cs_nBlockSequenceId;
- // Blocks loaded from disk are assigned id 0, so start the counter at 1.
+ /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
uint32_t nBlockSequenceId = 1;
- // Sources of received blocks, to be able to send them reject messages or ban
- // them, if processing happens afterwards. Protected by cs_main.
+ /**
+ * Sources of received blocks, to be able to send them reject messages or ban
+ * them, if processing happens afterwards. Protected by cs_main.
+ */
map<uint256, NodeId> mapBlockSource;
- // Blocks that are in flight, and that are in the queue to be downloaded.
- // Protected by cs_main.
+ /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
uint256 hash;
- CBlockIndex *pindex; // Optional.
- int64_t nTime; // Time of "getdata" request in microseconds.
+ CBlockIndex *pindex; //! Optional.
+ int64_t nTime; //! Time of "getdata" request in microseconds.
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
- // Number of preferrable block download peers.
+ /** Number of preferable block download peers. */
int nPreferredDownload = 0;
- // Dirty block index entries.
+ /** Dirty block index entries. */
set<CBlockIndex*> setDirtyBlockIndex;
- // Dirty block file entries.
+ /** Dirty block file entries. */
set<int> setDirtyFileInfo;
} // anon namespace
@@ -148,19 +153,19 @@ namespace {
namespace {
struct CMainSignals {
- // Notifies listeners of updated transaction data (transaction, and optionally the block it is found in.
+ /** 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).
+ /** 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).
+ /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
- // Notifies listeners of a new active block chain.
+ /** Notifies listeners of a new active block chain. */
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
- // Notifies listeners about an inventory item being seen on the network.
+ /** Notifies listeners about an inventory item being seen on the network. */
boost::signals2::signal<void (const uint256 &)> Inventory;
- // Tells listeners to broadcast their data.
+ /** Tells listeners to broadcast their data. */
boost::signals2::signal<void ()> Broadcast;
- // Notifies listeners of a block validation result
+ /** Notifies listeners of a block validation result */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
} g_signals;
@@ -213,32 +218,34 @@ struct CBlockReject {
uint256 hashBlock;
};
-// Maintain validation-specific state about nodes, protected by cs_main, instead
-// by CNode's own locks. This simplifies asynchronous operation, where
-// processing of incoming data is done after the ProcessMessage call returns,
-// and we're no longer holding the node's locks.
+/**
+ * Maintain validation-specific state about nodes, protected by cs_main, instead
+ * by CNode's own locks. This simplifies asynchronous operation, where
+ * processing of incoming data is done after the ProcessMessage call returns,
+ * and we're no longer holding the node's locks.
+ */
struct CNodeState {
- // Accumulated misbehaviour score for this peer.
+ //! Accumulated misbehaviour score for this peer.
int nMisbehavior;
- // Whether this peer should be disconnected and banned (unless whitelisted).
+ //! Whether this peer should be disconnected and banned (unless whitelisted).
bool fShouldBan;
- // String name of this peer (debugging/logging purposes).
+ //! String name of this peer (debugging/logging purposes).
std::string name;
- // List of asynchronously-determined block rejections to notify this peer about.
+ //! List of asynchronously-determined block rejections to notify this peer about.
std::vector<CBlockReject> rejects;
- // The best known block we know this peer has announced.
+ //! The best known block we know this peer has announced.
CBlockIndex *pindexBestKnownBlock;
- // The hash of the last unknown block this peer has announced.
+ //! The hash of the last unknown block this peer has announced.
uint256 hashLastUnknownBlock;
- // The last full block we both have.
+ //! The last full block we both have.
CBlockIndex *pindexLastCommonBlock;
- // Whether we've started headers synchronization with this peer.
+ //! Whether we've started headers synchronization with this peer.
bool fSyncStarted;
- // Since when we're stalling block download progress (in microseconds), or 0.
+ //! Since when we're stalling block download progress (in microseconds), or 0.
int64_t nStallingSince;
list<QueuedBlock> vBlocksInFlight;
int nBlocksInFlight;
- // Whether we consider this a preferred download peer.
+ //! Whether we consider this a preferred download peer.
bool fPreferredDownload;
CNodeState() {
@@ -254,7 +261,7 @@ struct CNodeState {
}
};
-// Map maintaining per-node state. Requires cs_main.
+/** Map maintaining per-node state. Requires cs_main. */
map<NodeId, CNodeState> mapNodeState;
// Requires cs_main.
@@ -708,15 +715,15 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
return true;
}
-//
-// Check transaction inputs to mitigate two
-// potential denial-of-service attacks:
-//
-// 1. scriptSigs with extra data stuffed into them,
-// not consumed by scriptPubKey (or P2SH script)
-// 2. P2SH scripts with a crazy number of expensive
-// CHECKSIG/CHECKMULTISIG operations
-//
+/**
+ * Check transaction inputs to mitigate two
+ * potential denial-of-service attacks:
+ *
+ * 1. scriptSigs with extra data stuffed into them,
+ * not consumed by scriptPubKey (or P2SH script)
+ * 2. P2SH scripts with a crazy number of expensive
+ * CHECKSIG/CHECKMULTISIG operations
+ */
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
@@ -1054,7 +1061,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return true;
}
-// Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock
+/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
{
CBlockIndex *pindexSlow = NULL;
@@ -1818,7 +1825,7 @@ void FlushStateToDisk() {
FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
}
-// Update chainActive and related internal data structures.
+/** Update chainActive and related internal data structures. */
void static UpdateTip(CBlockIndex *pindexNew) {
chainActive.SetTip(pindexNew);
@@ -1857,7 +1864,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
}
}
-// Disconnect chainActive's tip.
+/** Disconnect chainActive's tip. */
bool static DisconnectTip(CValidationState &state) {
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
@@ -1904,8 +1911,10 @@ static int64_t nTimeFlush = 0;
static int64_t nTimeChainState = 0;
static int64_t nTimePostConnect = 0;
-// Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
-// corresponding to pindexNew, to bypass loading it again from disk.
+/**
+ * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
+ * corresponding to pindexNew, to bypass loading it again from disk.
+ */
bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) {
assert(pindexNew->pprev == chainActive.Tip());
mempool.check(pcoinsTip);
@@ -1965,8 +1974,10 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
return true;
}
-// Return the tip of the chain with the most work in it, that isn't
-// known to be invalid (it's however far from certain to be valid).
+/**
+ * Return the tip of the chain with the most work in it, that isn't
+ * known to be invalid (it's however far from certain to be valid).
+ */
static CBlockIndex* FindMostWorkChain() {
do {
CBlockIndex *pindexNew = NULL;
@@ -2007,7 +2018,7 @@ static CBlockIndex* FindMostWorkChain() {
} while(true);
}
-// Delete all entries in setBlockIndexCandidates that are worse than the current tip.
+/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */
static void PruneBlockIndexCandidates() {
// Note that we can't delete the current block itself, as we may need to return to it later in case a
// reorganization to a better block fails.
@@ -2019,8 +2030,10 @@ static void PruneBlockIndexCandidates() {
assert(!setBlockIndexCandidates.empty());
}
-// Try to make some progress towards making pindexMostWork the active block.
-// pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
+/**
+ * Try to make some progress towards making pindexMostWork the active block.
+ * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
+ */
static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) {
AssertLockHeld(cs_main);
bool fInvalidFound = false;
@@ -2085,9 +2098,11 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
return true;
}
-// Make the best chain active, in multiple steps. The result is either failure
-// or an activated best chain. pblock is either NULL or a pointer to a block
-// that is already loaded (to avoid loading it again from disk).
+/**
+ * Make the best chain active, in multiple steps. The result is either failure
+ * or an activated best chain. pblock is either NULL or a pointer to a block
+ * that is already loaded (to avoid loading it again from disk).
+ */
bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
CBlockIndex *pindexNewTip = NULL;
CBlockIndex *pindexMostWork = NULL;
@@ -2236,7 +2251,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
return pindexNew;
}
-// Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS).
+/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
{
pindexNew->nTx = block.vtx.size();
@@ -2745,7 +2760,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 beyong the end of the array - copy left hash otherwise1
+ // calculate right hash if not beyond the end of the array - copy left hash otherwise1
if (pos*2+1 < CalcTreeWidth(height-1))
right = CalcHash(height-1, pos*2+1, vTxid);
else
diff --git a/src/main.h b/src/main.h
index 861a140efd..fc9913b7c6 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_MAIN_H
@@ -60,7 +60,7 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
-/** Maxiumum number of signature check operations in an IsStandard() P2SH script */
+/** Maximum number of signature check operations in an IsStandard() P2SH script */
static const unsigned int MAX_P2SH_SIGOPS = 15;
/** The maximum number of sigops we're willing to relay/mine in a single tx */
static const unsigned int MAX_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
@@ -97,7 +97,7 @@ static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
/** Time to wait (in seconds) between writing blockchain state to disk. */
static const unsigned int DATABASE_WRITE_INTERVAL = 3600;
-/** "reject" message codes **/
+/** "reject" message codes */
static const unsigned char REJECT_MALFORMED = 0x01;
static const unsigned char REJECT_INVALID = 0x10;
static const unsigned char REJECT_OBSOLETE = 0x11;
@@ -131,10 +131,10 @@ extern bool fIsBareMultisigStd;
extern unsigned int nCoinCacheSize;
extern CFeeRate minRelayTxFee;
-// Best header we've seen so far (used for getheaders queries' starting points).
+/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
-// Minimum disk space required - used in CheckDiskSpace()
+/** Minimum disk space required - used in CheckDiskSpace() */
static const uint64_t nMinDiskSpace = 52428800;
/** Register a wallet to receive updates from core */
@@ -151,15 +151,17 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
/** Unregister a network node */
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
-/** Process an incoming block. This only returns after the best known valid
- block is made active. Note that it does not, however, guarantee that the
- specific block passed to it has been checked for validity!
- @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state iff pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface - this will have its BlockChecked method called whenever *any* block completes validation.
- @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
- @param[in] pblock The block we want to process.
- @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
- @return True if state.IsValid()
-*/
+/**
+ * Process an incoming block. This only returns after the best known valid
+ * block is made active. Note that it does not, however, guarantee that the
+ * specific block passed to it has been checked for validity!
+ *
+ * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface - this will have its BlockChecked method called whenever *any* block completes validation.
+ * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
+ * @param[in] pblock The block we want to process.
+ * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
+ * @return True if state.IsValid()
+ */
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
@@ -245,54 +247,59 @@ struct CDiskTxPos : public CDiskBlockPos
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
-//
-// Check transaction inputs, and make sure any
-// pay-to-script-hash transactions are evaluating IsStandard scripts
-//
-// Why bother? To avoid denial-of-service attacks; an attacker
-// can submit a standard HASH... OP_EQUAL transaction,
-// which will get accepted into blocks. The redemption
-// script can be anything; an attacker could use a very
-// expensive-to-check-upon-redemption script like:
-// DUP CHECKSIG DROP ... repeated 100 times... OP_1
-//
+/**
+ * Check transaction inputs, and make sure any
+ * pay-to-script-hash transactions are evaluating IsStandard scripts
+ *
+ * Why bother? To avoid denial-of-service attacks; an attacker
+ * can submit a standard HASH... OP_EQUAL transaction,
+ * which will get accepted into blocks. The redemption
+ * script can be anything; an attacker could use a very
+ * expensive-to-check-upon-redemption script like:
+ * DUP CHECKSIG DROP ... repeated 100 times... OP_1
+ */
-/** Check for standard transaction types
- @param[in] mapInputs Map of previous transactions that have outputs we're spending
- @return True if all inputs (scriptSigs) use only standard transaction forms
-*/
+/**
+ * Check for standard transaction types
+ * @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ * @return True if all inputs (scriptSigs) use only standard transaction forms
+ */
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
-/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
- @return number of sigops this transaction's outputs will produce when spent
- @see CTransaction::FetchInputs
-*/
+/**
+ * Count ECDSA signature operations the old-fashioned (pre-0.6) way
+ * @return number of sigops this transaction's outputs will produce when spent
+ * @see CTransaction::FetchInputs
+ */
unsigned int GetLegacySigOpCount(const CTransaction& tx);
-/** Count ECDSA signature operations in pay-to-script-hash inputs.
-
- @param[in] mapInputs Map of previous transactions that have outputs we're spending
- @return maximum number of sigops required to validate this transaction's inputs
- @see CTransaction::FetchInputs
+/**
+ * Count ECDSA signature operations in pay-to-script-hash inputs.
+ *
+ * @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ * @return maximum number of sigops required to validate this transaction's inputs
+ * @see CTransaction::FetchInputs
*/
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
-// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
-// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
-// instead of being performed inline.
+/**
+ * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
+ * This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
+ * instead of being performed inline.
+ */
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
-// Apply the effects of this transaction on the UTXO set represented by view
+/** 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);
-// Context-independent validity checks
+/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
/** Check for standard transaction types
- @return True if all outputs (scriptPubKeys) use only standard transaction forms
-*/
+ * @return True if all outputs (scriptPubKeys) use only standard transaction forms
+ */
bool IsStandardTx(const CTransaction& tx, std::string& reason);
bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0);
@@ -315,8 +322,10 @@ public:
};
-/** Closure representing one script verification
- * Note that this stores references to the spending transaction */
+/**
+ * Closure representing one script verification
+ * Note that this stores references to the spending transaction
+ */
class CScriptCheck
{
private:
@@ -345,7 +354,7 @@ public:
/** Data structure that represents a partial merkle tree.
*
- * It respresents a subset of the txid's of a known block, in a way that
+ * It represents a subset of the txid's of a known block, in a way that
* allows recovery of the list of txid's and the merkle root, in an
* authenticated way.
*
@@ -380,36 +389,38 @@ public:
class CPartialMerkleTree
{
protected:
- // the total number of transactions in the block
+ /** the total number of transactions in the block */
unsigned int nTransactions;
- // node-is-parent-of-matched-txid bits
+ /** node-is-parent-of-matched-txid bits */
std::vector<bool> vBits;
- // txids and internal hashes
+ /** txids and internal hashes */
std::vector<uint256> vHash;
- // flag set when encountering invalid data
+ /** flag set when encountering invalid data */
bool fBad;
- // helper function to efficiently calculate the number of nodes at given height in the merkle tree
+ /** helper function to efficiently calculate the number of nodes at given height in the merkle tree */
unsigned int CalcTreeWidth(int height) {
return (nTransactions+(1 << height)-1) >> height;
}
- // calculate the hash of a node in the merkle tree (at leaf level: the txid's themself)
+ /** calculate the hash of a node in the merkle tree (at leaf level: the txid's themselves) */
uint256 CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid);
- // recursive function that traverses tree nodes, storing the data as bits and hashes
+ /** recursive function that traverses tree nodes, storing the data as bits and hashes */
void TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
- // recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
- // it returns the hash of the respective node.
+ /**
+ * recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
+ * it returns the hash of the respective node.
+ */
uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch);
public:
- // serialization implementation
+ /** serialization implementation */
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
@@ -432,13 +443,15 @@ public:
}
}
- // Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them
+ /** Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them */
CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
CPartialMerkleTree();
- // extract the matching txid's represented by this partial merkle tree.
- // returns the merkle root, or 0 in case of failure
+ /**
+ * extract the matching txid's represented by this partial merkle tree.
+ * returns the merkle root, or 0 in case of failure
+ */
uint256 ExtractMatches(std::vector<uint256> &vMatch);
};
@@ -458,22 +471,21 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
* of problems. Note that in any case, coins may be modified. */
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
-// Apply the effects of this block (with given index) on the UTXO set represented by coins
+/** Apply the effects of this block (with given index) on the UTXO set represented by coins */
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
-// Context-independent validity checks
+/** Context-independent validity checks */
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-// Context-dependent validity checks
+/** Context-dependent validity checks */
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev);
bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev);
-// Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held)
+/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-// Store block on disk
-// if dbp is provided, the file is known to already reside on disk
+/** Store block on disk. If dbp is provided, the file is known to already reside on disk */
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
@@ -482,13 +494,13 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
class CBlockFileInfo
{
public:
- unsigned int nBlocks; // number of blocks stored in file
- unsigned int nSize; // number of used bytes of block file
- unsigned int nUndoSize; // number of used bytes in the undo file
- unsigned int nHeightFirst; // lowest height of block in file
- unsigned int nHeightLast; // highest height of block in file
- uint64_t nTimeFirst; // earliest time of block in file
- uint64_t nTimeLast; // latest time of block in file
+ unsigned int nBlocks; //! number of blocks stored in file
+ unsigned int nSize; //! number of used bytes of block file
+ unsigned int nUndoSize; //! number of used bytes in the undo file
+ unsigned int nHeightFirst; //! lowest height of block in file
+ unsigned int nHeightLast; //! highest height of block in file
+ uint64_t nTimeFirst; //! earliest time of block in file
+ uint64_t nTimeLast; //! latest time of block in file
ADD_SERIALIZE_METHODS;
@@ -519,7 +531,7 @@ public:
std::string ToString() const;
- // update statistics (does not update nSize)
+ /** update statistics (does not update nSize) */
void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
if (nBlocks==0 || nHeightFirst > nHeightIn)
nHeightFirst = nHeightIn;
@@ -537,9 +549,9 @@ public:
class CValidationState {
private:
enum mode_state {
- MODE_VALID, // everything ok
- MODE_INVALID, // network rule violation (DoS value may be set)
- MODE_ERROR, // run-time error
+ MODE_VALID, //! everything ok
+ MODE_INVALID, //! network rule violation (DoS value may be set)
+ MODE_ERROR, //! run-time error
} mode;
int nDoS;
std::string strRejectReason;
@@ -634,24 +646,26 @@ struct CBlockTemplate
-/** Used to relay blocks as header + vector<merkle branch>
+/**
+ * Used to relay blocks as header + vector<merkle branch>
* to filtered nodes.
*/
class CMerkleBlock
{
public:
- // Public only for unit testing
+ /** Public only for unit testing */
CBlockHeader header;
CPartialMerkleTree txn;
public:
- // Public only for unit testing and relay testing
- // (not relayed)
+ /** Public only for unit testing and relay testing (not relayed) */
std::vector<std::pair<unsigned int, uint256> > vMatchedTxn;
- // Create from a CBlock, filtering transactions according to filter
- // Note that this will call IsRelevantAndUpdate on the filter for each transaction,
- // thus the filter will likely be modified.
+ /**
+ * Create from a CBlock, filtering transactions according to filter
+ * Note that this will call IsRelevantAndUpdate on the filter for each transaction,
+ * thus the filter will likely be modified.
+ */
CMerkleBlock(const CBlock& block, CBloomFilter& filter);
ADD_SERIALIZE_METHODS;
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 045cd90ef6..924f416904 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -505,6 +505,12 @@ Value getchaintips(const Array& params, bool fHelp)
" \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
" }\n"
"]\n"
+ "Possible values for status:\n"
+ "1. \"invalid\" This branch contains at least one invalid block\n"
+ "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
+ "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
+ "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
+ "5. \"active\" This is the tip of the active main chain, which is certainly valid\n"
"\nExamples:\n"
+ HelpExampleCli("getchaintips", "")
+ HelpExampleRpc("getchaintips", "")