Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/configure.ac b/configure.ac
- index 1c004cf..03d8e16 100644
- --- a/configure.ac
- +++ b/configure.ac
- @@ -77,6 +77,15 @@ AC_ARG_ENABLE([comparison-tool-reorg-tests],
- [use_comparison_tool_reorg_tests=$enableval],
- [use_comparison_tool_reorg_tests=no])
- +AC_ARG_ENABLE([first-class-messaging],
- + AS_HELP_STRING([--enable-first-class-messaging],[put messaging tools in a tab rather than popup window (default no)]),
- + [use_first_class_messaging=$enableval],
- + [use_first_class_messaging=no])
- +
- +if test "x$use_first_class_messaging" = xyes; then
- + AC_DEFINE([FIRST_CLASS_MESSAGING],[1],[Define to 1 to use tabs instead of windows for messaging tools])
- +fi
- +
- AC_ARG_WITH([qrencode],
- [AS_HELP_STRING([--with-qrencode],
- [enable QR code support (default is yes if qt is enabled and libqrencode is found)])],
- @@ -381,10 +390,22 @@ AC_TRY_COMPILE([#include <sys/socket.h>],
- [ AC_MSG_RESULT(no)]
- )
- +dnl Check for leveldb, only if explicitly requested
- LEVELDB_CPPFLAGS=
- LIBLEVELDB=
- LIBMEMENV=
- -AM_CONDITIONAL([EMBEDDED_LEVELDB],[true])
- +AC_ARG_WITH([system-leveldb],
- + [AS_HELP_STRING([--with-system-leveldb],
- + [Build with system LevelDB (default is no; DANGEROUS; NOT SUPPORTED)])],
- + [system_leveldb=$withval],
- + [system_leveldb=no]
- +)
- +if test x$system_leveldb != xno; then
- + LEVELDB_CPPFLAGS=
- + LIBLEVELDB=-lleveldb
- + LIBMEMENV=-lmemenv
- +fi
- +AM_CONDITIONAL([EMBEDDED_LEVELDB],[test x$system_leveldb = xno])
- AC_SUBST(LEVELDB_CPPFLAGS)
- AC_SUBST(LIBLEVELDB)
- AC_SUBST(LIBMEMENV)
- diff --git a/src/init.cpp b/src/init.cpp
- index de66151..19ce851 100644
- --- a/src/init.cpp
- +++ b/src/init.cpp
- @@ -230,6 +230,7 @@ std::string HelpMessage(HelpMessageMode hmm)
- strUsage += " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)") + "\n";
- strUsage += " -onion=<ip:port> " + _("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)") + "\n";
- strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n";
- + strUsage += " -permitbaremultisig " + _("Relay non-P2SH multisig (default: 1)") + "\n";
- strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n";
- strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS proxy") + "\n";
- strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n";
- @@ -289,6 +290,7 @@ std::string HelpMessage(HelpMessageMode hmm)
- }
- strUsage += " -mintxfee=<amt> " + _("Fees smaller than this are considered zero fee (for transaction creation) (default:") + " " + FormatMoney(CTransaction::nMinTxFee) + ")" + "\n";
- strUsage += " -minrelaytxfee=<amt> " + _("Fees smaller than this are considered zero fee (for relaying) (default:") + " " + FormatMoney(CTransaction::nMinRelayTxFee) + ")" + "\n";
- + strUsage += " -permitbaremultisig " + _("Relay non-P2SH multisig (default: 0)") + "\n";
- strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n";
- if (GetBoolArg("-help-debug", false))
- {
- @@ -303,6 +305,10 @@ std::string HelpMessage(HelpMessageMode hmm)
- strUsage += " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n";
- strUsage += " -testnet " + _("Use the test network") + "\n";
- + strUsage += "\n" + _("Node relay options:") + "\n";
- + strUsage += " -acceptnonstdtxn " + _("Accept \"non-standard\" transactions for relay and blocks") + "\n";
- + strUsage += " -datacarrier " + _("Relay and mine data carrier transactions (default: 1)") + "\n";
- +
- strUsage += "\n" + _("Block creation options:") + "\n";
- strUsage += " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n";
- strUsage += " -blockmaxsize=<n> " + strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE) + "\n";
- @@ -604,9 +610,13 @@ bool AppInit2(boost::thread_group& threadGroup)
- InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
- }
- bSpendZeroConfChange = GetArg("-spendzeroconfchange", true);
- + fIsBareMultisigStd = GetArg("-permitbaremultisig", false);
- strWalletFile = GetArg("-wallet", "wallet.dat");
- -#endif
- +#endif // ENABLE_WALLET
- +
- + fIsBareMultisigStd = GetArg("-permitbaremultisig", true);
- +
- // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
- // Sanity check
- if (!InitSanityCheck())
- diff --git a/src/main.cpp b/src/main.cpp
- index d172690..987c563 100644
- --- a/src/main.cpp
- +++ b/src/main.cpp
- @@ -22,6 +22,9 @@
- #include <boost/algorithm/string/replace.hpp>
- #include <boost/filesystem.hpp>
- #include <boost/filesystem/fstream.hpp>
- +#include <boost/thread/condition_variable.hpp>
- +#include <boost/thread/locks.hpp>
- +#include <boost/thread/mutex.hpp>
- using namespace std;
- using namespace boost;
- @@ -42,6 +45,8 @@ map<uint256, CBlockIndex*> mapBlockIndex;
- CChain chainActive;
- CChain chainMostWork;
- int64_t nTimeBestReceived = 0;
- +boost::mutex csBestBlock;
- +boost::condition_variable cvBlockChange;
- int nScriptCheckThreads = 0;
- bool fImporting = false;
- bool fReindex = false;
- @@ -498,6 +503,18 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
- +bool IsPushCanonicalTx(const CTransaction& tx, string& reason)
- +{
- + BOOST_FOREACH(const CTxIn& txin, tx.vin)
- + {
- + if (!txin.scriptSig.HasCanonicalPushes()) {
- + reason = "scriptsig-non-canonical-push";
- + return false;
- + }
- + }
- + return true;
- +}
- +
- bool IsStandardTx(const CTransaction& tx, string& reason)
- {
- AssertLockHeld(cs_main);
- @@ -555,22 +572,27 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
- reason = "scriptsig-not-pushonly";
- return false;
- }
- - if (!txin.scriptSig.HasCanonicalPushes()) {
- - reason = "scriptsig-non-canonical-push";
- - return false;
- - }
- }
- + if (!IsPushCanonicalTx(tx, reason))
- + return false;
- + unsigned int verfFlags = 0;
- + if (fIsBareMultisigStd)
- + verfFlags |= SCRIPT_VERIFY_BARE_MSIG_OK;
- unsigned int nDataOut = 0;
- txnouttype whichType;
- BOOST_FOREACH(const CTxOut& txout, tx.vout) {
- - if (!::IsStandard(txout.scriptPubKey, whichType)) {
- + if (!::IsStandard(txout.scriptPubKey, whichType, verfFlags)) {
- reason = "scriptpubkey";
- return false;
- }
- +
- if (whichType == TX_NULL_DATA)
- nDataOut++;
- - else if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
- + else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
- + reason = "bare-multisig";
- + return false;
- + } else if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
- reason = "dust";
- return false;
- }
- @@ -810,6 +832,16 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
- int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode)
- {
- + {
- + LOCK(mempool.cs);
- + uint256 hash = tx.GetHash();
- + double dPriorityDelta = 0;
- + int64_t nFeeDelta = 0;
- + mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
- + if (dPriorityDelta > 0 || nFeeDelta > 0)
- + return 0;
- + }
- +
- // Base fee is either nMinTxFee or nMinRelayTxFee
- int64_t nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee;
- @@ -859,11 +891,24 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
- REJECT_INVALID, "coinbase");
- // Rather not work on nonstandard transactions (unless -testnet/-regtest)
- + bool fIsNonStandard = false;
- string reason;
- if (Params().NetworkID() == CChainParams::MAIN && !IsStandardTx(tx, reason))
- - return state.DoS(0,
- - error("AcceptToMemoryPool : nonstandard transaction: %s", reason),
- - REJECT_NONSTANDARD, reason);
- + {
- + fIsNonStandard = true;
- + if ((!GetBoolArg("-acceptnonstdtxn", false)) || !IsPushCanonicalTx(tx, reason))
- + return state.DoS(0,
- + error("AcceptToMemoryPool : nonstandard transaction: %s", reason),
- + REJECT_NONSTANDARD, reason);
- + }
- +
- + const char *blacklistname;
- + BOOST_FOREACH(const CTxOut& txout, tx.vout)
- + {
- + blacklistname = txout.scriptPubKey.IsBlacklisted();
- + if (blacklistname)
- + return error("AcceptToMemoryPool : ignoring transaction %s with blacklisted output (%s)", tx.GetHash().ToString().c_str(), blacklistname);
- + }
- // is it already in the memory pool?
- uint256 hash = tx.GetHash();
- @@ -920,13 +965,23 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
- view.SetBackend(dummy);
- }
- + BOOST_FOREACH(const CTxIn txin, tx.vin)
- + {
- + const COutPoint &outpoint = txin.prevout;
- + const CCoins &coins = view.GetCoins(outpoint.hash);
- + assert(coins.IsAvailable(outpoint.n));
- + blacklistname = coins.vout[outpoint.n].scriptPubKey.IsBlacklisted();
- + if (blacklistname)
- + return error("CTxMemPool::accept() : ignoring transaction %s with blacklisted input (%s)", tx.GetHash().ToString().c_str(), blacklistname);
- + }
- +
- // Check for non-standard pay-to-script-hash in inputs
- if (Params().NetworkID() == CChainParams::MAIN && !AreInputsStandard(tx, view))
- - return error("AcceptToMemoryPool: : nonstandard transaction input");
- -
- - // Note: if you modify this code to accept non-standard transactions, then
- - // you should add code here to check that the transaction does a
- - // reasonable number of ECDSA signature verifications.
- + {
- + fIsNonStandard = true;
- + if (!GetBoolArg("-acceptnonstdtxn", false))
- + return error("AcceptToMemoryPool: : nonstandard transaction input");
- + }
- int64_t nValueIn = view.GetValueIn(tx);
- int64_t nValueOut = tx.GetValueOut();
- @@ -936,6 +991,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
- CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height());
- unsigned int nSize = entry.GetTxSize();
- + if (fIsNonStandard)
- + {
- + // Unnecessary/implied for standard transactions
- + long nBytesPerSigOp = GetArg("-bytespersigop", 0);
- + int nSigOps = GetLegacySigOpCount(tx);
- + nSigOps += GetP2SHSigOpCount(tx, view);
- +
- + if (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp)
- + return error("AcceptToMemoryPool : transaction with out-of-bounds SigOpCount");
- + }
- +
- // Don't accept it if it can't get into a block
- int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
- if (fLimitFree && nFees < txMinFee)
- @@ -1316,18 +1382,18 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
- return bnNew.GetCompact();
- }
- -bool CheckProofOfWork(uint256 hash, unsigned int nBits)
- +bool CheckProofOfWork(uint256 hash, unsigned int nBits, bool fSilent)
- {
- CBigNum bnTarget;
- bnTarget.SetCompact(nBits);
- // Check range
- if (bnTarget <= 0 || bnTarget > Params().ProofOfWorkLimit())
- - return error("CheckProofOfWork() : nBits below minimum work");
- + return fSilent ? false : error("CheckProofOfWork() : nBits below minimum work");
- // Check proof of work matches claimed amount
- if (hash > bnTarget.getuint256())
- - return error("CheckProofOfWork() : hash doesn't match nBits");
- + return fSilent ? false : error("CheckProofOfWork() : hash doesn't match nBits");
- return true;
- }
- @@ -1943,11 +2009,14 @@ void static UpdateTip(CBlockIndex *pindexNew) {
- // New best block
- nTimeBestReceived = GetTime();
- mempool.AddTransactionsUpdated(1);
- +
- LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n",
- chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
- Checkpoints::GuessVerificationProgress(chainActive.Tip()));
- + cvBlockChange.notify_all();
- +
- // Check the version of the last 100 blocks to see if we need to upgrade:
- if (!fIsInitialDownload)
- {
- @@ -2041,6 +2110,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
- list<CTransaction> unused;
- mempool.remove(tx, unused);
- mempool.removeConflicts(tx, txConflicted);
- + mempool.ClearPrioritisation(tx.GetHash());
- }
- mempool.check(pcoinsTip);
- // Update chainActive & related variables.
- @@ -2378,7 +2448,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
- return true;
- }
- -bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
- +bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp, bool fWriteToDisk)
- {
- AssertLockHeld(cs_main);
- // Check for duplicate
- @@ -2448,6 +2518,9 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
- }
- }
- + if (!fWriteToDisk)
- + return true;
- +
- // Write block to history file
- try {
- unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
- @@ -2515,7 +2588,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
- pnode->PushMessage("getblocks", chainActive.GetLocator(pindexBegin), hashEnd);
- }
- -bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
- +bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp, bool fCheckPOW)
- {
- AssertLockHeld(cs_main);
- @@ -2527,9 +2600,16 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
- return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString()), 0, "duplicate");
- // Preliminary checks
- - if (!CheckBlock(*pblock, state))
- + if (!CheckBlock(*pblock, state, fCheckPOW))
- return error("ProcessBlock() : CheckBlock FAILED");
- + bool fHasPOW = fCheckPOW;
- + if (!fHasPOW)
- + {
- + CValidationState dummy;
- + fHasPOW = CheckProofOfWork(pblock->GetHash(), pblock->nBits, true);
- + }
- +
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
- if (pcheckpoint && pblock->hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
- {
- @@ -2574,13 +2654,27 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
- // Ask this guy to fill in what we're missing
- PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(hash));
- }
- - return true;
- + // The block is accepted, but not immediately processed
- + return state.Orphan();
- }
- // Store to disk
- - if (!AcceptBlock(*pblock, state, dbp))
- + if (!AcceptBlock(*pblock, state, dbp, fHasPOW))
- return error("ProcessBlock() : AcceptBlock FAILED");
- + if (!fHasPOW)
- + {
- + // The block isn't committed to disk since it was just a proposal, but we need to do connect checks still
- + CBlockIndex* pindexPrev = mapBlockIndex[pblock->hashPrevBlock];
- + if (pblock->hashPrevBlock != pcoinsTip->GetBestBlock())
- + return state.Invalid("stale-prevblk", error("ProcessBlock() : proposed block built on non-best %s", pblock->hashPrevBlock.ToString().c_str()));
- + CBlockIndex indexDummy(*pblock);
- + indexDummy.pprev = pindexPrev;
- + indexDummy.nHeight = pindexPrev->nHeight + 1;
- + CCoinsViewCache viewNew(*pcoinsTip, true);
- + return ConnectBlock(*pblock, state, &indexDummy, viewNew, true);
- + }
- +
- // Recursively process any orphan blocks that depended on this one
- vector<uint256> vWorkQueue;
- vWorkQueue.push_back(hash);
- @@ -3499,6 +3593,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
- }
- }
- + // Trigger download of remote node's memory pool
- + if (!IsInitialBlockDownload() && !pfrom->fInbound &&
- + pfrom->nVersion >= MEMPOOL_GD_VERSION)
- + pfrom->PushMessage("mempool");
- +
- // Relay alerts
- {
- LOCK(cs_mapAlerts);
- diff --git a/src/main.h b/src/main.h
- index dc50dff..4e7bf0f 100644
- --- a/src/main.h
- +++ b/src/main.h
- @@ -29,6 +29,9 @@
- #include <utility>
- #include <vector>
- +#include <boost/thread/condition_variable.hpp>
- +#include <boost/thread/mutex.hpp>
- +
- class CBlockIndex;
- class CBloomFilter;
- class CInv;
- @@ -92,11 +95,14 @@ extern uint64_t nLastBlockTx;
- extern uint64_t nLastBlockSize;
- extern const std::string strMessageMagic;
- extern int64_t nTimeBestReceived;
- +extern boost::mutex csBestBlock;
- +extern boost::condition_variable cvBlockChange;
- extern bool fImporting;
- extern bool fReindex;
- extern bool fBenchmark;
- extern int nScriptCheckThreads;
- extern bool fTxIndex;
- +extern bool fIsBareMultisigStd;
- extern unsigned int nCoinCacheSize;
- // Minimum disk space required - used in CheckDiskSpace()
- @@ -131,7 +137,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
- void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd);
- /** Process an incoming block */
- -bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
- +bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL, bool fCheckPOW = true);
- /** Check whether enough disk space is available for an incoming block */
- bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
- /** Open a block file (blk?????.dat) */
- @@ -157,7 +163,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle);
- /** Run an instance of the script checking thread */
- void ThreadScriptCheck();
- /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
- -bool CheckProofOfWork(uint256 hash, unsigned int nBits);
- +bool CheckProofOfWork(uint256 hash, unsigned int nBits, bool fSilent = false);
- /** Calculate the minimum amount of work a received block needs, without knowing its direct parent */
- unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime);
- /** Check whether we are doing an initial block download (synchronizing from disk or network) */
- @@ -316,6 +322,8 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
- // Context-independent validity checks
- bool CheckTransaction(const CTransaction& tx, CValidationState& state);
- +bool IsPushCanonicalTx(const CTransaction&, string& reason);
- +
- /** Check for standard transaction types
- @return True if all outputs (scriptPubKeys) use only standard transaction forms
- */
- @@ -605,7 +613,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = t
- // Store block on disk
- // if dbp is provided, the file is known to already reside on disk
- -bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL);
- +bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL, bool fWriteToDisk = true);
- @@ -941,6 +949,7 @@ private:
- MODE_VALID, // everything ok
- MODE_INVALID, // network rule violation (DoS value may be set)
- MODE_ERROR, // run-time error
- + MODE_ORPHAN, // orphan data, processing deferred
- } mode;
- int nDoS;
- std::string strRejectReason;
- @@ -974,8 +983,16 @@ public:
- AbortNode(msg);
- return Error(msg);
- }
- + bool Orphan() {
- + if (IsValid())
- + mode = MODE_ORPHAN;
- + return true;
- + }
- bool IsValid() const {
- - return mode == MODE_VALID;
- + return mode == MODE_VALID || mode == MODE_ORPHAN;
- + }
- + bool IsOrphan() const {
- + return mode == MODE_ORPHAN;
- }
- bool IsInvalid() const {
- return mode == MODE_INVALID;
- diff --git a/src/miner.cpp b/src/miner.cpp
- index e8abb8c..e980dc1 100644
- --- a/src/miner.cpp
- +++ b/src/miner.cpp
- @@ -3,6 +3,8 @@
- // Distributed under the MIT/X11 software license, see the accompanying
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
- +#include <inttypes.h>
- +
- #include "miner.h"
- #include "core.h"
- @@ -52,28 +54,170 @@ void SHA256Transform(void* pstate, void* pinput, const void* pinit)
- ((uint32_t*)pstate)[i] = ctx.h[i];
- }
- -// Some explaining would be appreciated
- -class COrphan
- +//
- +// Unconfirmed transactions in the memory pool often depend on other
- +// transactions in the memory pool. When we select transactions from the
- +// pool, we select by highest priority or fee rate, so we might consider
- +// transactions that depend on transactions that aren't yet in the block.
- +// CTxInfo represents a logical transaction to potentially be included in blocks
- +// It stores extra metadata such as the subjective priority of a transaction at
- +// the time of building the block. When there are unconfirmed transactions that
- +// depend on other unconfirmed transactions, these "child" transactions' CTxInfo
- +// object factors in its "parents" to its priority and effective size; this way,
- +// the "child" can cover the "cost" of its "parents", and the "parents" are
- +// included into the block as part of the "child".
- +//
- +class CTxInfo;
- +typedef std::map<uint256, CTxInfo> mapInfo_t;
- +
- +class CTxInfo
- {
- public:
- + mapInfo_t *pmapInfoById;
- const CTransaction* ptx;
- + uint256 hash;
- +private:
- set<uint256> setDependsOn;
- +public:
- + set<uint256> setDependents;
- double dPriority;
- - double dFeePerKb;
- + uint64_t nTxFee;
- + int nTxSigOps;
- + bool fInvalid;
- + unsigned int nSize;
- + unsigned int nEffectiveSizeCached;
- - COrphan(const CTransaction* ptxIn)
- + CTxInfo() : pmapInfoById(NULL), hash(0), fInvalid(false), nSize(0), nEffectiveSizeCached(0)
- {
- - ptx = ptxIn;
- - dPriority = dFeePerKb = 0;
- + ptx = NULL;
- + dPriority = nTxFee = 0;
- }
- void print() const
- {
- - LogPrintf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n",
- - ptx->GetHash().ToString(), dPriority, dFeePerKb);
- + LogPrintf("CTxInfo(hash=%s, dPriority=%.1f, nTxFee=%d)\n",
- + ptx->GetHash().ToString(), dPriority, nTxFee);
- BOOST_FOREACH(uint256 hash, setDependsOn)
- LogPrintf(" setDependsOn %s\n", hash.ToString());
- }
- +
- + void addDependsOn(const uint256& hashPrev)
- + {
- + setDependsOn.insert(hashPrev);
- + nEffectiveSizeCached = 0;
- + }
- +
- + void rmDependsOn(const uint256& hashPrev)
- + {
- + setDependsOn.erase(hashPrev);
- + nEffectiveSizeCached = 0;
- + }
- +
- + // effectiveSize handles inheriting the fInvalid flag as a side effect
- + unsigned int effectiveSize()
- + {
- + if (fInvalid)
- + return -1;
- +
- + if (nEffectiveSizeCached)
- + return nEffectiveSizeCached;
- +
- + assert(pmapInfoById);
- +
- + if (!nSize)
- + nSize = ::GetSerializeSize(*ptx, SER_NETWORK, PROTOCOL_VERSION);
- + unsigned int nEffectiveSize = nSize;
- + BOOST_FOREACH(const uint256& dephash, setDependsOn)
- + {
- + CTxInfo& depinfo = (*pmapInfoById)[dephash];
- + nEffectiveSize += depinfo.effectiveSize();
- +
- + if (depinfo.fInvalid)
- + {
- + fInvalid = true;
- + return -1;
- + }
- + }
- + nEffectiveSizeCached = nEffectiveSize;
- + return nEffectiveSize;
- + }
- +
- + unsigned int effectiveSizeMod()
- + {
- + unsigned int nTxSizeMod = effectiveSize();
- + const CTransaction &tx = *ptx;
- + // In order to avoid disincentivizing cleaning up the UTXO set we don't count
- + // the constant overhead for each txin and up to 110 bytes of scriptSig (which
- + // is enough to cover a compressed pubkey p2sh redemption) for priority.
- + // Providing any more cleanup incentive than making additional inputs free would
- + // risk encouraging people to create junk outputs to redeem later.
- + BOOST_FOREACH(const CTxIn& txin, tx.vin)
- + {
- + unsigned int offset = 41U + min(110U, (unsigned int)txin.scriptSig.size());
- + if (nTxSizeMod > offset)
- + nTxSizeMod -= offset;
- + }
- + return nTxSizeMod;
- + }
- +
- + double getPriority()
- + {
- + // Priority is sum(valuein * age) / modified_txsize
- + return dPriority / effectiveSizeMod();
- + }
- +
- + double getFeeRate()
- + {
- + return nTxFee / effectiveSize();
- + }
- +
- + unsigned int GetLegacySigOpCount()
- + {
- + assert(pmapInfoById);
- +
- + unsigned int n = ::GetLegacySigOpCount(*ptx);
- + BOOST_FOREACH(const uint256& dephash, setDependsOn)
- + {
- + CTxInfo& depinfo = (*pmapInfoById)[dephash];
- + n += depinfo.GetLegacySigOpCount();
- + }
- + return n;
- + }
- +
- + bool DoInputs(CCoinsViewCache& view, CBlockIndex*pindexPrev, std::vector<CTxInfo*>& vAdded, unsigned int& nSigOpCounter)
- + {
- + const CTransaction& tx = *ptx;
- +
- + if (view.HaveCoins(hash))
- + // Already included in block template
- + return true;
- +
- + assert(pmapInfoById);
- +
- + BOOST_FOREACH(const uint256& dephash, setDependsOn)
- + {
- + CTxInfo& depinfo = (*pmapInfoById)[dephash];
- + if (!depinfo.DoInputs(view, pindexPrev, vAdded, nSigOpCounter))
- + return false;
- + }
- +
- + if (!view.HaveInputs(tx))
- + return false;
- +
- + nTxSigOps = GetP2SHSigOpCount(tx, view);
- + nSigOpCounter += nTxSigOps;
- +
- + CValidationState state;
- + if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH))
- + return false;
- +
- + CTxUndo txundo;
- + UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash);
- +
- + vAdded.push_back(this);
- +
- + return true;
- + }
- };
- @@ -81,7 +225,7 @@ uint64_t nLastBlockTx = 0;
- uint64_t nLastBlockSize = 0;
- // We want to sort transactions by priority and fee, so:
- -typedef boost::tuple<double, double, const CTransaction*> TxPriority;
- +typedef CTxInfo* TxPriority;
- class TxPriorityCompare
- {
- bool byFee;
- @@ -91,15 +235,15 @@ public:
- {
- if (byFee)
- {
- - if (a.get<1>() == b.get<1>())
- - return a.get<0>() < b.get<0>();
- - return a.get<1>() < b.get<1>();
- + if (a->getFeeRate() == b->getFeeRate())
- + return a->getPriority() < b->getPriority();
- + return a->getFeeRate() < b->getFeeRate();
- }
- else
- {
- - if (a.get<0>() == b.get<0>())
- - return a.get<1>() < b.get<1>();
- - return a.get<0>() < b.get<0>();
- + if (a->getPriority() == b->getPriority())
- + return a->getFeeRate() < b->getFeeRate();
- + return a->getPriority() < b->getPriority();
- }
- }
- };
- @@ -147,81 +291,75 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
- CCoinsViewCache view(*pcoinsTip, true);
- // Priority order to process transactions
- - list<COrphan> vOrphan; // list memory doesn't move
- - map<uint256, vector<COrphan*> > mapDependers;
- + mapInfo_t mapInfoById;
- bool fPrintPriority = GetBoolArg("-printpriority", false);
- // This vector will be sorted into a priority queue:
- vector<TxPriority> vecPriority;
- vecPriority.reserve(mempool.mapTx.size());
- +
- for (map<uint256, CTxMemPoolEntry>::iterator mi = mempool.mapTx.begin();
- mi != mempool.mapTx.end(); ++mi)
- {
- const CTransaction& tx = mi->second.GetTx();
- +
- + const uint256& hash = tx.GetHash();
- + CTxInfo& txinfo = mapInfoById[hash];
- + txinfo.hash = hash;
- + txinfo.pmapInfoById = &mapInfoById;
- + txinfo.ptx = &tx;
- +
- if (tx.IsCoinBase() || !IsFinalTx(tx, pindexPrev->nHeight + 1))
- + {
- + txinfo.fInvalid = true;
- continue;
- + }
- - COrphan* porphan = NULL;
- - double dPriority = 0;
- + double& dPriority = txinfo.dPriority;
- + uint64_t& nTxFee = txinfo.nTxFee;
- int64_t nTotalIn = 0;
- - bool fMissingInputs = false;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- // Read prev transaction
- - if (!view.HaveCoins(txin.prevout.hash))
- + int64_t nValueIn;
- + int nConf;
- + if (view.HaveCoins(txin.prevout.hash))
- {
- - // This should never happen; all transactions in the memory
- - // pool should connect to either transactions in the chain
- - // or other transactions in the memory pool.
- - if (!mempool.mapTx.count(txin.prevout.hash))
- - {
- - LogPrintf("ERROR: mempool transaction missing input\n");
- - if (fDebug) assert("mempool transaction missing input" == 0);
- - fMissingInputs = true;
- - if (porphan)
- - vOrphan.pop_back();
- - break;
- - }
- -
- - // Has to wait for dependencies
- - if (!porphan)
- - {
- - // Use list for automatic deletion
- - vOrphan.push_back(COrphan(&tx));
- - porphan = &vOrphan.back();
- - }
- - mapDependers[txin.prevout.hash].push_back(porphan);
- - porphan->setDependsOn.insert(txin.prevout.hash);
- - nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
- - continue;
- + const CCoins &coins = view.GetCoins(txin.prevout.hash);
- + // Input is confirmed
- + nConf = pindexPrev->nHeight - coins.nHeight + 1;
- + nValueIn = coins.vout[txin.prevout.n].nValue;
- + dPriority += (double)nValueIn * nConf;
- + }
- + else
- + if (mempool.mapTx.count(txin.prevout.hash))
- + {
- + // Input is still unconfirmed
- + const uint256& hashPrev = txin.prevout.hash;
- + nValueIn = mempool.mapTx[hashPrev].GetTx().vout[txin.prevout.n].nValue;
- + txinfo.addDependsOn(hashPrev);
- + mapInfoById[hashPrev].setDependents.insert(hash);
- + nConf = 0;
- + }
- + else
- + {
- + // We don't know where the input is
- + // In this case, it's impossible to include this transaction in a block, so mark it invalid and move on
- + txinfo.fInvalid = true;
- + LogPrintf("priority %s invalid input %s\n", txinfo.hash.ToString().substr(0,10).c_str(), txin.prevout.hash.ToString().substr(0,10).c_str());
- + goto nexttxn;
- }
- - const CCoins &coins = view.GetCoins(txin.prevout.hash);
- - int64_t nValueIn = coins.vout[txin.prevout.n].nValue;
- nTotalIn += nValueIn;
- -
- - int nConf = pindexPrev->nHeight - coins.nHeight + 1;
- -
- - dPriority += (double)nValueIn * nConf;
- }
- - if (fMissingInputs) continue;
- - // Priority is sum(valuein * age) / modified_txsize
- - unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- - dPriority = tx.ComputePriority(dPriority, nTxSize);
- + nTxFee = nTotalIn - tx.GetValueOut();
- - // This is a more accurate fee-per-kilobyte than is used by the client code, because the
- - // client code rounds up the size to the nearest 1K. That's good, because it gives an
- - // incentive to create smaller transactions.
- - double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0);
- + mempool.ApplyDeltas(hash, dPriority, nTotalIn);
- - if (porphan)
- - {
- - porphan->dPriority = dPriority;
- - porphan->dFeePerKb = dFeePerKb;
- - }
- - else
- - vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &mi->second.GetTx()));
- + vecPriority.push_back(&txinfo);
- +
- +nexttxn: (void)1;
- }
- // Collect transactions into block
- @@ -236,28 +374,36 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
- while (!vecPriority.empty())
- {
- // Take highest priority transaction off the priority queue:
- - double dPriority = vecPriority.front().get<0>();
- - double dFeePerKb = vecPriority.front().get<1>();
- - const CTransaction& tx = *(vecPriority.front().get<2>());
- -
- + CTxInfo& txinfo = *(vecPriority.front());
- std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
- vecPriority.pop_back();
- + if (txinfo.fInvalid)
- + continue;
- +
- + const CTransaction& tx = *txinfo.ptx;
- + double dPriority = txinfo.getPriority();
- + double dFeePerKb = txinfo.getFeeRate();
- +
- // Size limits
- - unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- + unsigned int nTxSize = txinfo.effectiveSize();
- if (nBlockSize + nTxSize >= nBlockMaxSize)
- continue;
- // Legacy limits on sigOps:
- - unsigned int nTxSigOps = GetLegacySigOpCount(tx);
- + unsigned int nTxSigOps = txinfo.GetLegacySigOpCount();
- if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
- continue;
- // Skip free transactions if we're past the minimum block size:
- - if (fSortedByFee && (dFeePerKb < CTransaction::nMinRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
- + const uint256& hash = tx.GetHash();
- + double dPriorityDelta = 0;
- + int64_t nFeeDelta = 0;
- + mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
- + if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (dFeePerKb < CTransaction::nMinRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
- continue;
- - // Prioritize by fee once past the priority size or we run out of high-priority
- + // Prioritise by fee once past the priority size or we run out of high-priority
- // transactions:
- if (!fSortedByFee &&
- ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
- @@ -267,31 +413,23 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
- std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
- }
- - if (!view.HaveInputs(tx))
- - continue;
- + // second layer cached modifications just for this transaction
- + CCoinsViewCache viewTemp(view, true);
- - int64_t nTxFees = view.GetValueIn(tx)-tx.GetValueOut();
- -
- - nTxSigOps += GetP2SHSigOpCount(tx, view);
- - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
- + std::vector<CTxInfo*> vAdded;
- + if (!txinfo.DoInputs(viewTemp, pindexPrev, vAdded, nTxSigOps))
- continue;
- - CValidationState state;
- - if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH))
- + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
- continue;
- - CTxUndo txundo;
- - uint256 hash = tx.GetHash();
- - UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash);
- + // push changes from the second layer cache to the first one
- + viewTemp.Flush();
- // Added
- - pblock->vtx.push_back(tx);
- - pblocktemplate->vTxFees.push_back(nTxFees);
- - pblocktemplate->vTxSigOps.push_back(nTxSigOps);
- nBlockSize += nTxSize;
- - ++nBlockTx;
- + nBlockTx += vAdded.size();
- nBlockSigOps += nTxSigOps;
- - nFees += nTxFees;
- if (fPrintPriority)
- {
- @@ -299,22 +437,29 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
- dPriority, dFeePerKb, tx.GetHash().ToString());
- }
- - // Add transactions that depend on this one to the priority queue
- - if (mapDependers.count(hash))
- + bool fResort = false;
- + BOOST_FOREACH(CTxInfo* ptxinfo, vAdded)
- {
- - BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
- + pblock->vtx.push_back(*ptxinfo->ptx);
- + pblocktemplate->vTxFees.push_back(ptxinfo->nTxFee);
- + pblocktemplate->vTxSigOps.push_back(ptxinfo->nTxSigOps);
- + nFees += ptxinfo->nTxFee;
- +
- + ptxinfo->fInvalid = true;
- + if (!ptxinfo->setDependents.empty())
- {
- - if (!porphan->setDependsOn.empty())
- + fResort = true;
- + BOOST_FOREACH(const uint256& dhash, ptxinfo->setDependents)
- {
- - porphan->setDependsOn.erase(hash);
- - if (porphan->setDependsOn.empty())
- - {
- - vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx));
- - std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
- - }
- + CTxInfo& dtxinfo = mapInfoById[dhash];
- + dtxinfo.rmDependsOn(ptxinfo->hash);
- + fResort = true;
- }
- }
- }
- + if (fResort)
- + // Re-sort the priority queue to pick up on improved standing
- + std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
- }
- nLastBlockTx = nBlockTx;
- diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am
- index 648971b..cae0070 100644
- --- a/src/qt/Makefile.am
- +++ b/src/qt/Makefile.am
- @@ -201,6 +201,7 @@ BITCOIN_QT_H = \
- sendcoinsentry.h \
- signverifymessagedialog.h \
- splashscreen.h \
- + tonalutils.h \
- trafficgraphwidget.h \
- transactiondesc.h \
- transactiondescdialog.h \
- @@ -278,6 +279,7 @@ BITCOIN_QT_CPP = \
- qvaluecombobox.cpp \
- rpcconsole.cpp \
- splashscreen.cpp \
- + tonalutils.cpp \
- trafficgraphwidget.cpp \
- utilitydialog.cpp \
- winshutdownmonitor.cpp
- diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
- index 08fe3e7..5d57ac4 100644
- --- a/src/qt/bitcoin.cpp
- +++ b/src/qt/bitcoin.cpp
- @@ -520,7 +520,7 @@ int main(int argc, char *argv[])
- /// - Do not call GetDataDir(true) before this step finishes
- if (!boost::filesystem::is_directory(GetDataDir(false)))
- {
- - QMessageBox::critical(0, QObject::tr("Bitcoin"),
- + QMessageBox::critical(0, QObject::tr("Bitcoin Core"),
- QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"])));
- return 1;
- }
- diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
- index 25ad0c6..9b87eaa 100644
- --- a/src/qt/bitcoinamountfield.cpp
- +++ b/src/qt/bitcoinamountfield.cpp
- @@ -14,17 +14,67 @@
- #include <QKeyEvent>
- #include <qmath.h> // for qPow()
- +#include "tonalutils.h"
- +
- +BitcoinAmountSpinBox::BitcoinAmountSpinBox(QWidget *parent)
- + : QDoubleSpinBox(parent), currentUnit(-1)
- +{
- + setLocale(QLocale::c());
- + setDecimals(8);
- + installEventFilter(parent);
- + setMaximumWidth(170);
- + setMaximum(21e14);
- +}
- +
- +QValidator::State BitcoinAmountSpinBox::validate(QString&text, int&pos) const
- +{
- + switch (currentNumsys) {
- + default:
- + case BitcoinUnits::BTC:
- + return QDoubleSpinBox::validate(text, pos);
- + case BitcoinUnits::TBC:
- + return TonalUtils::validate(text, pos);
- + }
- +}
- +
- +QString BitcoinAmountSpinBox::textFromValue(double value) const
- +{
- + return BitcoinUnits::format(currentUnit, value);
- +}
- +
- +double BitcoinAmountSpinBox::valueFromText(const QString&text) const
- +{
- + qint64 val;
- + BitcoinUnits::parse(currentUnit, text, &val);
- + return val;
- +}
- +
- +void BitcoinAmountSpinBox::setUnit(int unit)
- +{
- + currentUnit = unit;
- + currentNumsys = BitcoinUnits::numsys(unit);
- + qint64 factor = BitcoinUnits::factor(unit);
- + switch (currentNumsys) {
- + default:
- + case BitcoinUnits::BTC:
- + if (currentUnit == BitcoinUnits::uBTC)
- + setSingleStep(0.01 * factor);
- + else
- + setSingleStep(0.001 * factor);
- + break;
- + case BitcoinUnits::TBC:
- + setSingleStep(factor / 0x400);
- + }
- +}
- +
- +
- BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
- QWidget(parent),
- amount(0),
- - currentUnit(-1)
- + currentUnit(-1),
- + nSingleStep(0)
- {
- - nSingleStep = 100000; // satoshis
- -
- - amount = new QDoubleSpinBox(this);
- - amount->setLocale(QLocale::c());
- - amount->installEventFilter(this);
- - amount->setMaximumWidth(170);
- + amount = new BitcoinAmountSpinBox(this);
- QHBoxLayout *layout = new QHBoxLayout(this);
- layout->addWidget(amount);
- @@ -52,7 +102,7 @@ void BitcoinAmountField::setText(const QString &text)
- if (text.isEmpty())
- amount->clear();
- else
- - amount->setValue(text.toDouble());
- + amount->setValue(amount->valueFromText(text));
- }
- void BitcoinAmountField::clear()
- @@ -61,16 +111,18 @@ void BitcoinAmountField::clear()
- unit->setCurrentIndex(0);
- }
- -bool BitcoinAmountField::validate()
- +bool BitcoinAmountField::_is_valid() const
- {
- - bool valid = true;
- if (amount->value() == 0.0)
- - valid = false;
- - else if (!BitcoinUnits::parse(currentUnit, text(), 0))
- - valid = false;
- - else if (amount->value() > BitcoinUnits::maxAmount(currentUnit))
- - valid = false;
- + return false;
- + if (amount->value() > BitcoinUnits::maxAmount(BitcoinUnits::uBTC))
- + return false;
- + return true;
- +}
- +bool BitcoinAmountField::validate()
- +{
- + bool valid = _is_valid();
- setValid(valid);
- return valid;
- @@ -122,8 +174,8 @@ QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
- qint64 BitcoinAmountField::value(bool *valid_out) const
- {
- - qint64 val_out = 0;
- - bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
- + qint64 val_out = amount->value();
- + bool valid = _is_valid();
- if (valid_out)
- {
- *valid_out = valid;
- @@ -133,7 +185,7 @@ qint64 BitcoinAmountField::value(bool *valid_out) const
- void BitcoinAmountField::setValue(qint64 value)
- {
- - setText(BitcoinUnits::format(currentUnit, value));
- + amount->setValue(value);
- }
- void BitcoinAmountField::setReadOnly(bool fReadOnly)
- @@ -154,12 +206,24 @@ void BitcoinAmountField::unitChanged(int idx)
- bool valid = false;
- qint64 currentValue = value(&valid);
- + amount->setUnit(newUnit);
- currentUnit = newUnit;
- - // Set max length after retrieving the value, to prevent truncation
- - amount->setDecimals(BitcoinUnits::decimals(currentUnit));
- - amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals()));
- - amount->setSingleStep((double)nSingleStep / (double)BitcoinUnits::factor(currentUnit));
- + qint64 nSS = nSingleStep;
- + if (!nSS)
- + {
- + int numsys = BitcoinUnits::numsys(newUnit);
- + switch (numsys)
- + {
- + case BitcoinUnits::BTC:
- + nSS = 100000;
- + break;
- + case BitcoinUnits::TBC:
- + nSS = 0x10000;
- + break;
- + }
- + }
- + amount->setSingleStep(nSS);
- if (valid)
- {
- diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
- index 521a9ed..8355c6d 100644
- --- a/src/qt/bitcoinamountfield.h
- +++ b/src/qt/bitcoinamountfield.h
- @@ -5,13 +5,30 @@
- #ifndef BITCOINAMOUNTFIELD_H
- #define BITCOINAMOUNTFIELD_H
- +#include <QDoubleSpinBox>
- #include <QWidget>
- QT_BEGIN_NAMESPACE
- -class QDoubleSpinBox;
- class QValueComboBox;
- QT_END_NAMESPACE
- +class BitcoinAmountSpinBox : public QDoubleSpinBox
- +{
- + Q_OBJECT
- +public:
- + BitcoinAmountSpinBox(QWidget *parent = 0);
- +
- + virtual QValidator::State validate(QString&text, int&pos) const;
- + virtual QString textFromValue(double) const;
- + virtual double valueFromText(const QString&) const;
- +
- + void setUnit(int unit);
- +
- +private:
- + int currentUnit;
- + int currentNumsys;
- +};
- +
- /** Widget for entering bitcoin amounts.
- */
- class BitcoinAmountField: public QWidget
- @@ -56,10 +73,11 @@ protected:
- bool eventFilter(QObject *object, QEvent *event);
- private:
- - QDoubleSpinBox *amount;
- + BitcoinAmountSpinBox *amount;
- QValueComboBox *unit;
- int currentUnit;
- qint64 nSingleStep;
- + bool _is_valid() const;
- void setText(const QString &text);
- QString text() const;
- diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
- index e6190ae..991a5cd 100644
- --- a/src/qt/bitcoingui.cpp
- +++ b/src/qt/bitcoingui.cpp
- @@ -276,7 +276,7 @@ void BitcoinGUI::createActions(bool fIsTestnet)
- aboutQtAction->setStatusTip(tr("Show information about Qt"));
- aboutQtAction->setMenuRole(QAction::AboutQtRole);
- optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
- - optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin"));
- + optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin Core"));
- optionsAction->setMenuRole(QAction::PreferencesRole);
- if (!fIsTestnet)
- toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
- @@ -327,6 +327,19 @@ void BitcoinGUI::createActions(bool fIsTestnet)
- connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses()));
- connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses()));
- connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked()));
- +
- +# ifdef FIRST_CLASS_MESSAGING
- + firstClassMessagingAction = new QAction(QIcon(":/icons/edit"), tr("S&ignatures"), this);
- + firstClassMessagingAction->setToolTip(signMessageAction->toolTip() + QString(". / ") + verifyMessageAction->toolTip() + QString("."));
- + firstClassMessagingAction->setCheckable(true);
- + tabGroup->addAction(firstClassMessagingAction);
- +
- + connect(signMessageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
- + connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
- + connect(firstClassMessagingAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
- + // Always start with the sign message tab for FIRST_CLASS_MESSAGING
- + connect(firstClassMessagingAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
- +# endif
- }
- #endif
- }
- @@ -347,8 +360,10 @@ void BitcoinGUI::createMenuBar()
- {
- file->addAction(openAction);
- file->addAction(backupWalletAction);
- +#ifndef FIRST_CLASS_MESSAGING
- file->addAction(signMessageAction);
- file->addAction(verifyMessageAction);
- +#endif
- file->addSeparator();
- file->addAction(usedSendingAddressesAction);
- file->addAction(usedReceivingAddressesAction);
- @@ -386,6 +401,9 @@ void BitcoinGUI::createToolBars()
- toolbar->addAction(sendCoinsAction);
- toolbar->addAction(receiveCoinsAction);
- toolbar->addAction(historyAction);
- +#ifdef FIRST_CLASS_MESSAGING
- + toolbar->addAction(firstClassMessagingAction);
- +#endif
- overviewAction->setChecked(true);
- }
- }
- @@ -467,12 +485,12 @@ void BitcoinGUI::createTrayIcon(bool fIsTestnet)
- if (!fIsTestnet)
- {
- - trayIcon->setToolTip(tr("Bitcoin client"));
- + trayIcon->setToolTip(tr("Bitcoin Core client"));
- trayIcon->setIcon(QIcon(":/icons/toolbar"));
- }
- else
- {
- - trayIcon->setToolTip(tr("Bitcoin client") + " " + tr("[testnet]"));
- + trayIcon->setToolTip(tr("Bitcoin Core client") + " " + tr("[testnet]"));
- trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
- }
- @@ -507,7 +525,9 @@ void BitcoinGUI::createTrayIconMenu()
- trayIconMenu->addSeparator();
- trayIconMenu->addAction(sendCoinsAction);
- trayIconMenu->addAction(receiveCoinsAction);
- +#ifndef FIRST_CLASS_MESSAGING
- trayIconMenu->addSeparator();
- +#endif
- trayIconMenu->addAction(signMessageAction);
- trayIconMenu->addAction(verifyMessageAction);
- trayIconMenu->addSeparator();
- @@ -726,7 +746,7 @@ void BitcoinGUI::setNumBlocks(int count)
- void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret)
- {
- - QString strTitle = tr("Bitcoin"); // default title
- + QString strTitle = tr("Bitcoin Core"); // default title
- // Default to information icon
- int nMBoxIcon = QMessageBox::Information;
- int nNotifyIcon = Notificator::Information;
- diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
- index b4675b9..eabfae1 100644
- --- a/src/qt/bitcoingui.h
- +++ b/src/qt/bitcoingui.h
- @@ -83,6 +83,7 @@ private:
- QAction *usedReceivingAddressesAction;
- QAction *signMessageAction;
- QAction *verifyMessageAction;
- + QAction *firstClassMessagingAction;
- QAction *aboutAction;
- QAction *receiveCoinsAction;
- QAction *optionsAction;
- diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
- index 2fed443..ab1cb07 100644
- --- a/src/qt/bitcoinunits.cpp
- +++ b/src/qt/bitcoinunits.cpp
- @@ -6,6 +6,8 @@
- #include <QStringList>
- +#include "tonalutils.h"
- +
- BitcoinUnits::BitcoinUnits(QObject *parent):
- QAbstractListModel(parent),
- unitlist(availableUnits())
- @@ -14,10 +16,19 @@ BitcoinUnits::BitcoinUnits(QObject *parent):
- QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits()
- {
- - QList<BitcoinUnits::Unit> unitlist;
- - unitlist.append(BTC);
- - unitlist.append(mBTC);
- - unitlist.append(uBTC);
- + static QList<BitcoinUnits::Unit> unitlist;
- + if (unitlist.empty())
- + {
- + unitlist.append(BTC);
- + unitlist.append(mBTC);
- + unitlist.append(uBTC);
- + if (TonalUtils::Supported())
- + {
- + unitlist.append(bTBC);
- + unitlist.append(sTBC);
- + unitlist.append(TBC);
- + }
- + }
- return unitlist;
- }
- @@ -28,6 +39,9 @@ bool BitcoinUnits::valid(int unit)
- case BTC:
- case mBTC:
- case uBTC:
- + case bTBC:
- + case sTBC:
- + case TBC:
- return true;
- default:
- return false;
- @@ -41,6 +55,9 @@ QString BitcoinUnits::name(int unit)
- case BTC: return QString("BTC");
- case mBTC: return QString("mBTC");
- case uBTC: return QString::fromUtf8("μBTC");
- + case bTBC: return QString::fromUtf8("ᵇTBC");
- + case sTBC: return QString::fromUtf8("Ë¢TBC");
- + case TBC: return QString("TBC");
- default: return QString("???");
- }
- }
- @@ -49,9 +66,12 @@ QString BitcoinUnits::description(int unit)
- {
- switch(unit)
- {
- - case BTC: return QString("Bitcoins");
- + case BTC: return QString("Bitcoins (decimal)");
- case mBTC: return QString("Milli-Bitcoins (1 / 1,000)");
- case uBTC: return QString("Micro-Bitcoins (1 / 1,000,000)");
- + case bTBC: return QString("Bong-Bitcoins (1,0000 tonal)");
- + case sTBC: return QString("San-Bitcoins (100 tonal)");
- + case TBC: return QString("Bitcoins (tonal)");
- default: return QString("???");
- }
- }
- @@ -63,6 +83,9 @@ qint64 BitcoinUnits::factor(int unit)
- case BTC: return 100000000;
- case mBTC: return 100000;
- case uBTC: return 100;
- + case bTBC: return 0x100000000LL;
- + case sTBC: return 0x1000000;
- + case TBC: return 0x10000;
- default: return 100000000;
- }
- }
- @@ -85,6 +108,9 @@ int BitcoinUnits::amountDigits(int unit)
- case BTC: return 8; // 21,000,000 (# digits, without commas)
- case mBTC: return 11; // 21,000,000,000
- case uBTC: return 14; // 21,000,000,000,000
- + case bTBC: return 6; // 49,63
- + case sTBC: return 8; // 49,6384
- + case TBC: return 10; // 49,63,8448
- default: return 0;
- }
- }
- @@ -96,10 +122,52 @@ int BitcoinUnits::decimals(int unit)
- case BTC: return 8;
- case mBTC: return 5;
- case uBTC: return 2;
- + case bTBC: return 8;
- + case sTBC: return 6;
- + case TBC: return 4;
- default: return 0;
- }
- }
- +int BitcoinUnits::minPlaces(int unit)
- +{
- + switch(unit)
- + {
- + case bTBC:
- + case sTBC:
- + case TBC:
- + return -1;
- + default:
- + return 2;
- + }
- +}
- +
- +int BitcoinUnits::radix(int unit)
- +{
- + switch(unit)
- + {
- + case bTBC:
- + case sTBC:
- + case TBC:
- + return 0x10;
- + default:
- + return 10;
- + }
- +}
- +
- +int BitcoinUnits::numsys(int unit)
- +{
- + switch(unit)
- + {
- + case bTBC:
- + case sTBC:
- + case TBC:
- + return TBC;
- + default:
- + return BTC;
- + }
- +}
- +
- QString BitcoinUnits::format(int unit, qint64 n, bool fPlus)
- {
- // Note: not using straight sprintf here because we do NOT want
- @@ -111,20 +179,31 @@ QString BitcoinUnits::format(int unit, qint64 n, bool fPlus)
- qint64 n_abs = (n > 0 ? n : -n);
- qint64 quotient = n_abs / coin;
- qint64 remainder = n_abs % coin;
- - QString quotient_str = QString::number(quotient);
- - QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0');
- + int uradix = radix(unit);
- + QString s = QString::number(quotient, uradix) + "." + QString::number(remainder, uradix).rightJustified(num_decimals, '0');
- // Right-trim excess zeros after the decimal point
- - int nTrim = 0;
- - for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i)
- - ++nTrim;
- - remainder_str.chop(nTrim);
- + int nTrim = num_decimals - minPlaces(unit);
- + if (nTrim > 0)
- + {
- + int nTrimStop = s.size() - nTrim;
- + nTrim = 0;
- + for (int i = s.size()-1; i>=nTrimStop && (s.at(i) == '0'); --i)
- + ++nTrim;
- + if (s.at(nTrimStop) == '.' && nTrimStop + nTrim + 1 == s.size())
- + ++nTrim;
- + s.chop(nTrim);
- + }
- +
- + int unumsys = numsys(unit);
- + if (unumsys == TBC)
- + TonalUtils::ConvertFromHex(s);
- if (n < 0)
- - quotient_str.insert(0, '-');
- + s.insert(0, '-');
- else if (fPlus && n > 0)
- - quotient_str.insert(0, '+');
- - return quotient_str + QString(".") + remainder_str;
- + s.insert(0, '+');
- + return s;
- }
- QString BitcoinUnits::formatWithUnit(int unit, qint64 amount, bool plussign)
- @@ -157,11 +236,22 @@ bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out)
- bool ok = false;
- QString str = whole + decimals.leftJustified(num_decimals, '0');
- + int unumsys = numsys(unit);
- + if (unumsys == TBC)
- + {
- + if (str.size() > 15)
- + return false; // Longer numbers may exceed 63 bits
- + TonalUtils::ConvertToHex(str);
- + }
- + else
- + {
- if(str.size() > 18)
- {
- return false; // Longer numbers will exceed 63 bits
- }
- - qint64 retvalue = str.toLongLong(&ok);
- + }
- +
- + qint64 retvalue = str.toLongLong(&ok, radix(unit));
- if(val_out)
- {
- *val_out = retvalue;
- diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
- index 46517fc..f3019b0 100644
- --- a/src/qt/bitcoinunits.h
- +++ b/src/qt/bitcoinunits.h
- @@ -25,7 +25,10 @@ public:
- {
- BTC,
- mBTC,
- - uBTC
- + uBTC,
- + bTBC,
- + sTBC,
- + TBC,
- };
- //! @name Static API
- @@ -46,8 +49,14 @@ public:
- static qint64 maxAmount(int unit);
- //! Number of amount digits (to represent max number of coins)
- static int amountDigits(int unit);
- - //! Number of decimals left
- + //! Number of fractional places
- static int decimals(int unit);
- + //! Minimum number of fractional places to show
- + static int minPlaces(int unit);
- + //! Radix
- + static int radix(int unit);
- + //! Number system
- + static int numsys(int unit);
- //! Format as string
- static QString format(int unit, qint64 amount, bool plussign=false);
- //! Format as string (with unit)
- diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui
- index bc49214..bed0f4a 100644
- --- a/src/qt/forms/askpassphrasedialog.ui
- +++ b/src/qt/forms/askpassphrasedialog.ui
- @@ -23,7 +23,7 @@
- </size>
- </property>
- <property name="windowTitle">
- - <string>Passphrase Dialog</string>
- + <string>Bitcoin Core - Passphrase Dialog</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui
- index c1aea36..13a630e 100644
- --- a/src/qt/forms/editaddressdialog.ui
- +++ b/src/qt/forms/editaddressdialog.ui
- @@ -11,7 +11,7 @@
- </rect>
- </property>
- <property name="windowTitle">
- - <string>Edit Address</string>
- + <string>Bitcoin Core - Edit Address</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
- index 0103842..572bb32 100644
- --- a/src/qt/forms/optionsdialog.ui
- +++ b/src/qt/forms/optionsdialog.ui
- @@ -11,7 +11,7 @@
- </rect>
- </property>
- <property name="windowTitle">
- - <string>Options</string>
- + <string>Bitcoin Core - Options</string>
- </property>
- <property name="modal">
- <bool>true</bool>
- diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
- index fcb6bb6..aeabf42 100644
- --- a/src/qt/forms/rpcconsole.ui
- +++ b/src/qt/forms/rpcconsole.ui
- @@ -11,7 +11,7 @@
- </rect>
- </property>
- <property name="windowTitle">
- - <string>Debug window</string>
- + <string>Bitcoin Core - Debug window</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- @@ -305,7 +305,7 @@
- <item row="14" column="0">
- <widget class="QPushButton" name="openDebugLogfileButton">
- <property name="toolTip">
- - <string>Open the Bitcoin debug log file from the current data directory. This can take a few seconds for large log files.</string>
- + <string>Open the client debug log file from the current data directory. This can take a few seconds for large log files.</string>
- </property>
- <property name="text">
- <string>&Open</string>
- diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
- index 4cb1670..531efab 100644
- --- a/src/qt/forms/sendcoinsdialog.ui
- +++ b/src/qt/forms/sendcoinsdialog.ui
- @@ -11,7 +11,7 @@
- </rect>
- </property>
- <property name="windowTitle">
- - <string>Send Coins</string>
- + <string>Bitcoin Core - Send Coins</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0">
- <property name="bottomMargin">
- diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui
- index aa271b4..fd23777 100644
- --- a/src/qt/forms/signverifymessagedialog.ui
- +++ b/src/qt/forms/signverifymessagedialog.ui
- @@ -11,7 +11,7 @@
- </rect>
- </property>
- <property name="windowTitle">
- - <string>Signatures - Sign / Verify a Message</string>
- + <string>Bitcoin Core - Signatures</string>
- </property>
- <property name="modal">
- <bool>true</bool>
- diff --git a/src/qt/forms/transactiondescdialog.ui b/src/qt/forms/transactiondescdialog.ui
- index 5ae1e12..92306cd 100644
- --- a/src/qt/forms/transactiondescdialog.ui
- +++ b/src/qt/forms/transactiondescdialog.ui
- @@ -11,7 +11,7 @@
- </rect>
- </property>
- <property name="windowTitle">
- - <string>Transaction details</string>
- + <string>Bitcoin Core - Transaction Details</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
- index 004befe..da141e5 100644
- --- a/src/qt/guiutil.cpp
- +++ b/src/qt/guiutil.cpp
- @@ -2,6 +2,10 @@
- // Distributed under the MIT/X11 software license, see the accompanying
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
- +#include <sstream>
- +
- +#include <QApplication>
- +
- #include "guiutil.h"
- #include "bitcoinaddressvalidator.h"
- @@ -112,6 +116,52 @@ void setupAmountWidget(QLineEdit *widget, QWidget *parent)
- widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
- }
- +qint64 URIParseAmount(std::string strAmount)
- +{
- + bool ok;
- + qint64 nAmount = 0;
- + bool fHex = false;
- + if (strAmount[0] == 'x' || strAmount[0] == 'X')
- + {
- + fHex = true;
- + strAmount = strAmount.substr(1);
- + }
- + size_t nPosX = strAmount.find('X', 1);
- + if (nPosX == std::string::npos)
- + nPosX = strAmount.find('x', 1);
- + int nExponent = 0;
- + if (nPosX != std::string::npos)
- + {
- + nExponent = QString::fromStdString(strAmount.substr(nPosX + 1)).toInt(&ok, fHex ? 0x10 : 10);
- + if (!ok)
- + return -1;
- + }
- + else
- + {
- + // Non-compliant URI, assume standard units
- + nExponent = fHex ? 4 : 8;
- + nPosX = strAmount.size();
- + }
- + size_t nPosP = strAmount.find('.');
- + size_t nFractionLen = 0;
- + if (nPosP == std::string::npos)
- + nPosP = nPosX;
- + else
- + nFractionLen = (nPosX - nPosP) - 1;
- + nExponent -= nFractionLen;
- + strAmount = strAmount.substr(0, nPosP) + (nFractionLen ? strAmount.substr(nPosP + 1, nFractionLen) : "");
- + if (nExponent > 0)
- + strAmount.append(nExponent, '0');
- + else
- + if (nExponent < 0)
- + // WTF? truncate I guess
- + strAmount = strAmount.substr(0, strAmount.size() + nExponent);
- + nAmount = QString::fromStdString(strAmount).toLongLong(&ok, fHex ? 0x10 : 10);
- + if (!ok)
- + return -1;
- + return nAmount;
- +}
- +
- bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
- {
- // return if URI is not valid or is no bitcoin: URI
- @@ -151,10 +201,9 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
- {
- if(!i->second.isEmpty())
- {
- - if(!BitcoinUnits::parse(BitcoinUnits::BTC, i->second, &rv.amount))
- - {
- + rv.amount = URIParseAmount((i->second).toStdString());
- + if (rv.amount < 0)
- return false;
- - }
- }
- fShouldReturnFalse = false;
- }
- diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
- index 3e99e94..9bc67d0 100644
- --- a/src/qt/intro.cpp
- +++ b/src/qt/intro.cpp
- @@ -181,7 +181,7 @@ void Intro::pickDataDirectory()
- TryCreateDirectory(GUIUtil::qstringToBoostPath(dataDir));
- break;
- } catch(fs::filesystem_error &e) {
- - QMessageBox::critical(0, tr("Bitcoin"),
- + QMessageBox::critical(0, tr("Bitcoin Core"),
- tr("Error: Specified data directory \"%1\" can not be created.").arg(dataDir));
- /* fall through, back to choosing screen */
- }
- diff --git a/src/qt/tonalutils.cpp b/src/qt/tonalutils.cpp
- new file mode 100644
- index 0000000..969eaec
- --- /dev/null
- +++ b/src/qt/tonalutils.cpp
- @@ -0,0 +1,52 @@
- +#include <QFont>
- +#include <QFontMetrics>
- +#include <QRegExp>
- +#include <QRegExpValidator>
- +#include <QString>
- +
- +#include "tonalutils.h"
- +
- +bool TonalUtils::Supported()
- +{
- + QFontMetrics fm = QFontMetrics(QFont());
- + return fm.inFont(0xe9d9);
- +}
- +
- +static QRegExpValidator tv(QRegExp("-?(?:[\\d\\xe9d9-\\xe9df]+\\.?|[\\d\\xe9d9-\\xe9df]*\\.[\\d\\xe9d9-\\xe9df]*)"), NULL);
- +
- +QValidator::State TonalUtils::validate(QString&input, int&pos)
- +{
- + return tv.validate(input, pos);
- +}
- +
- +void TonalUtils::ConvertFromHex(QString&str)
- +{
- + for (int i = 0; i < str.size(); ++i)
- + {
- + ushort c = str[i].unicode();
- + if (c == '9')
- + str[i] = 0xe9d9;
- + else
- + if (c >= 'A' && c <= 'F')
- + str[i] = c + 0xe999;
- + else
- + if (c >= 'a' && c <= 'f')
- + str[i] = c + 0xe979;
- + }
- +}
- +
- +void TonalUtils::ConvertToHex(QString&str)
- +{
- + for (int i = 0; i < str.size(); ++i)
- + {
- + ushort c = str[i].unicode();
- + if (c == 0xe9d9)
- + str[i] = '9';
- + else
- + if (c == '9')
- + str[i] = 'a';
- + else
- + if (c >= 0xe9da && c <= 0xe9df)
- + str[i] = c - 0xe999;
- + }
- +}
- diff --git a/src/qt/tonalutils.h b/src/qt/tonalutils.h
- new file mode 100644
- index 0000000..426a312
- --- /dev/null
- +++ b/src/qt/tonalutils.h
- @@ -0,0 +1,21 @@
- +#ifndef TONALUTILS_H
- +#define TONALUTILS_H
- +
- +#include <QValidator>
- +
- +QT_BEGIN_NAMESPACE
- +class QString;
- +QT_END_NAMESPACE
- +
- +class TonalUtils
- +{
- +public:
- + static bool Supported();
- +
- + static QValidator::State validate(QString&input, int&pos);
- +
- + static void ConvertFromHex(QString&);
- + static void ConvertToHex(QString&);
- +};
- +
- +#endif
- diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
- index 1cef483..b5686e3 100644
- --- a/src/qt/walletview.cpp
- +++ b/src/qt/walletview.cpp
- @@ -58,6 +58,10 @@ WalletView::WalletView(QWidget *parent):
- addWidget(transactionsPage);
- addWidget(receiveCoinsPage);
- addWidget(sendCoinsPage);
- +#ifdef FIRST_CLASS_MESSAGING
- + signVerifyMessageDialog = new SignVerifyMessageDialog(NULL);
- + addWidget(signVerifyMessageDialog);
- +#endif
- // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page
- connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex)));
- @@ -112,6 +116,9 @@ void WalletView::setWalletModel(WalletModel *walletModel)
- overviewPage->setWalletModel(walletModel);
- receiveCoinsPage->setModel(walletModel);
- sendCoinsPage->setModel(walletModel);
- +#ifdef FIRST_CLASS_MESSAGING
- + signVerifyMessageDialog->setModel(walletModel);
- +#endif
- if (walletModel)
- {
- @@ -175,11 +182,17 @@ void WalletView::gotoSendCoinsPage(QString addr)
- void WalletView::gotoSignMessageTab(QString addr)
- {
- +#ifdef FIRST_CLASS_MESSAGING
- + setCurrentWidget(signVerifyMessageDialog);
- +
- + signVerifyMessageDialog->showTab_SM(false);
- +#else
- // calls show() in showTab_SM()
- SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this);
- signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
- signVerifyMessageDialog->setModel(walletModel);
- signVerifyMessageDialog->showTab_SM(true);
- +#endif
- if (!addr.isEmpty())
- signVerifyMessageDialog->setAddress_SM(addr);
- @@ -187,11 +200,17 @@ void WalletView::gotoSignMessageTab(QString addr)
- void WalletView::gotoVerifyMessageTab(QString addr)
- {
- +#ifdef FIRST_CLASS_MESSAGING
- + setCurrentWidget(signVerifyMessageDialog);
- +
- + signVerifyMessageDialog->showTab_VM(false);
- +#else
- // calls show() in showTab_VM()
- SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this);
- signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
- signVerifyMessageDialog->setModel(walletModel);
- signVerifyMessageDialog->showTab_VM(true);
- +#endif
- if (!addr.isEmpty())
- signVerifyMessageDialog->setAddress_VM(addr);
- diff --git a/src/qt/walletview.h b/src/qt/walletview.h
- index 9cfa8d6..566578f 100644
- --- a/src/qt/walletview.h
- +++ b/src/qt/walletview.h
- @@ -13,6 +13,7 @@ class OverviewPage;
- class ReceiveCoinsDialog;
- class SendCoinsDialog;
- class SendCoinsRecipient;
- +class SignVerifyMessageDialog;
- class TransactionView;
- class WalletModel;
- @@ -58,6 +59,7 @@ private:
- QWidget *transactionsPage;
- ReceiveCoinsDialog *receiveCoinsPage;
- SendCoinsDialog *sendCoinsPage;
- + SignVerifyMessageDialog *signVerifyMessageDialog;
- TransactionView *transactionView;
- diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
- index 4f3c39c..ec28830 100644
- --- a/src/rpcclient.cpp
- +++ b/src/rpcclient.cpp
- @@ -149,6 +149,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
- if (strMethod == "listtransactions" && n > 2) ConvertTo<int64_t>(params[2]);
- if (strMethod == "listaccounts" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "walletpassphrase" && n > 1) ConvertTo<int64_t>(params[1]);
- + if (strMethod == "prioritisetransaction" && n > 1) ConvertTo<double>(params[1]);
- + if (strMethod == "prioritisetransaction" && n > 2) ConvertTo<int64_t>(params[2]);
- if (strMethod == "getblocktemplate" && n > 0) ConvertTo<Object>(params[0]);
- if (strMethod == "listsinceblock" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "sendmany" && n > 1) ConvertTo<Object>(params[1]);
- diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
- index ef99cb3..a1dfde6 100644
- --- a/src/rpcmining.cpp
- +++ b/src/rpcmining.cpp
- @@ -3,12 +3,17 @@
- // Distributed under the MIT/X11 software license, see the accompanying
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
- +#include <boost/date_time/posix_time/posix_time.hpp>
- +#include <boost/thread/locks.hpp>
- +#include <boost/thread/thread_time.hpp>
- +
- #include "rpcserver.h"
- #include "chainparams.h"
- #include "init.h"
- #include "net.h"
- #include "main.h"
- #include "miner.h"
- +#include "util.h"
- #ifdef ENABLE_WALLET
- #include "db.h"
- #include "wallet.h"
- @@ -274,6 +279,20 @@ Value getmininginfo(const Array& params, bool fHelp)
- }
- +Value prioritisetransaction(const Array& params, bool fHelp)
- +{
- + if (fHelp || params.size() != 3)
- + throw runtime_error(
- + "prioritisetransaction <txid> <priority delta> <fee delta>\n"
- + "Accepts the transaction into mined blocks at a higher (or lower) priority");
- +
- + uint256 hash;
- + hash.SetHex(params[0].get_str());
- + mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), params[2].get_int64());
- + return true;
- +}
- +
- +
- #ifdef ENABLE_WALLET
- Value getwork(const Array& params, bool fHelp)
- {
- @@ -400,6 +419,8 @@ Value getwork(const Array& params, bool fHelp)
- }
- #endif
- +static Value TestBlock(const Value& valData, bool fCheckPOW);
- +
- Value getblocktemplate(const Array& params, bool fHelp)
- {
- if (fHelp || params.size() > 1)
- @@ -463,6 +484,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
- );
- std::string strMode = "template";
- + Value lpval = Value::null;
- if (params.size() > 0)
- {
- const Object& oparam = params[0].get_obj();
- @@ -475,6 +497,17 @@ Value getblocktemplate(const Array& params, bool fHelp)
- }
- else
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
- +
- + if (strMode == "proposal")
- + {
- + const Value& dataval = find_value(oparam, "data");
- + if (dataval.type() == str_type)
- + return TestBlock(dataval, false);
- + else
- + throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal");
- + }
- +
- + lpval = find_value(oparam, "longpollid");
- }
- if (strMode != "template")
- @@ -486,8 +519,62 @@ Value getblocktemplate(const Array& params, bool fHelp)
- if (IsInitialBlockDownload())
- throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks...");
- - // Update block
- static unsigned int nTransactionsUpdatedLast;
- +
- + if (lpval.type() != null_type)
- + {
- + // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
- + uint256 hashWatchedChain;
- + boost::system_time checktxtime;
- + unsigned int nTransactionsUpdatedLastLP;
- +
- + if (lpval.type() == str_type)
- + {
- + // Format: <hashBestChain><nTransactionsUpdatedLast>
- + std::string lpstr = lpval.get_str();
- +
- + hashWatchedChain.SetHex(lpstr.substr(0, 64));
- + nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64));
- + }
- + else
- + {
- + // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
- + hashWatchedChain = chainActive.Tip()->GetBlockHash();
- + nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
- + }
- +
- +#ifdef ENABLE_WALLET
- + if (pwalletMain)
- + LEAVE_CRITICAL_SECTION(pwalletMain->cs_wallet);
- +#endif
- + LEAVE_CRITICAL_SECTION(cs_main);
- + {
- + checktxtime = boost::get_system_time() + boost::posix_time::minutes(1);
- +
- + boost::unique_lock<boost::mutex> lock(csBestBlock);
- + while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && fRPCRunning)
- + {
- + if (!cvBlockChange.timed_wait(lock, checktxtime))
- + {
- + // Timeout: Check transactions for update
- + if (nTransactionsUpdatedLast != nTransactionsUpdatedLastLP)
- + break;
- + checktxtime += boost::posix_time::seconds(10);
- + }
- + }
- + }
- + ENTER_CRITICAL_SECTION(cs_main);
- +#ifdef ENABLE_WALLET
- + if (pwalletMain)
- + ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet);
- +#endif
- +
- + if (!fRPCRunning)
- + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
- + // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
- + }
- +
- + // Update block
- static CBlockIndex* pindexPrev;
- static int64_t nStart;
- static CBlockTemplate* pblocktemplate;
- @@ -522,6 +609,10 @@ Value getblocktemplate(const Array& params, bool fHelp)
- UpdateTime(*pblock, pindexPrev);
- pblock->nNonce = 0;
- + static Array aCaps;
- + if (aCaps.empty())
- + aCaps.push_back("proposal");
- +
- Array transactions;
- map<uint256, int64_t> setTxIndex;
- int i = 0;
- @@ -570,11 +661,13 @@ Value getblocktemplate(const Array& params, bool fHelp)
- }
- Object result;
- + result.push_back(Pair("capabilities", aCaps));
- result.push_back(Pair("version", pblock->nVersion));
- result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
- result.push_back(Pair("transactions", transactions));
- result.push_back(Pair("coinbaseaux", aux));
- result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
- + result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
- result.push_back(Pair("target", hashTarget.GetHex()));
- result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
- result.push_back(Pair("mutable", aMutable));
- @@ -588,6 +681,42 @@ Value getblocktemplate(const Array& params, bool fHelp)
- return result;
- }
- +static Value TestBlock(const Value& valData, bool fCheckPOW)
- +{
- + vector<unsigned char> blockData(ParseHex(valData.get_str()));
- + CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
- + CBlock pblock;
- + try {
- + ssBlock >> pblock;
- + }
- + catch (std::exception &e) {
- + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
- + }
- +
- + CValidationState state;
- + bool fAccepted = ProcessBlock(state, NULL, &pblock, NULL, fCheckPOW);
- + if (!fAccepted)
- + {
- + std::string strRejectReason = state.GetRejectReason();
- + if (state.IsError())
- + throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason);
- + if (state.IsInvalid())
- + {
- + if (strRejectReason.empty())
- + return "rejected";
- + return strRejectReason;
- + }
- + // Should be impossible
- + return "valid?";
- + }
- +
- + // NOTE: If we process an orphan, it is accepted yet not immediately processed
- + if (state.IsOrphan())
- + return "orphan";
- +
- + return Value::null;
- +}
- +
- Value submitblock(const Array& params, bool fHelp)
- {
- if (fHelp || params.size() < 1 || params.size() > 2)
- @@ -609,20 +738,5 @@ Value submitblock(const Array& params, bool fHelp)
- + HelpExampleRpc("submitblock", "\"mydata\"")
- );
- - vector<unsigned char> blockData(ParseHex(params[0].get_str()));
- - CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
- - CBlock pblock;
- - try {
- - ssBlock >> pblock;
- - }
- - catch (std::exception &e) {
- - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
- - }
- -
- - CValidationState state;
- - bool fAccepted = ProcessBlock(state, NULL, &pblock);
- - if (!fAccepted)
- - return "rejected"; // TODO: report validation state
- -
- - return Value::null;
- + return TestBlock(params[0], true);
- }
- diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h
- index 8b3df19..90aeec0 100644
- --- a/src/rpcprotocol.h
- +++ b/src/rpcprotocol.h
- @@ -49,9 +49,14 @@ enum RPCErrorCode
- RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter
- RPC_DATABASE_ERROR = -20, // Database error
- RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format
- - RPC_TRANSACTION_ERROR = -25, // General error during transaction submission
- - RPC_TRANSACTION_REJECTED = -26, // Transaction was rejected by network rules
- - RPC_TRANSACTION_ALREADY_IN_CHAIN= -27, // Transaction already in chain
- + RPC_VERIFY_ERROR = -25, // General error during transaction or block submission
- + RPC_VERIFY_REJECTED = -26, // Transaction or block was rejected by network rules
- + RPC_VERIFY_ALREADY_IN_CHAIN = -27, // Transaction already in chain
- +
- + // Aliases for backward compatibility
- + RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
- + RPC_TRANSACTION_REJECTED = RPC_VERIFY_REJECTED,
- + RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN,
- // P2P client errors
- RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected
- diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
- index f43acf4..9f83785 100644
- --- a/src/rpcserver.cpp
- +++ b/src/rpcserver.cpp
- @@ -33,6 +33,7 @@ using namespace json_spirit;
- static std::string strRPCUserColonPass;
- // These are created by StartRPCThreads, destroyed in StopRPCThreads
- +bool fRPCRunning = false;
- static asio::io_service* rpc_io_service = NULL;
- static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
- static ssl::context* rpc_ssl_context = NULL;
- @@ -253,6 +254,7 @@ static const CRPCCommand vRPCCommands[] =
- { "getblocktemplate", &getblocktemplate, true, false, false },
- { "getmininginfo", &getmininginfo, true, false, false },
- { "getnetworkhashps", &getnetworkhashps, true, false, false },
- + { "prioritisetransaction", &prioritisetransaction, true, false, false },
- { "submitblock", &submitblock, false, false, false },
- /* Raw transactions */
- @@ -614,6 +616,8 @@ void StartRPCThreads()
- return;
- }
- + fRPCRunning = true;
- +
- rpc_worker_group = new boost::thread_group();
- for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
- rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service));
- @@ -636,6 +640,7 @@ void StopRPCThreads()
- {
- if (rpc_io_service == NULL) return;
- + fRPCRunning = false;
- // First, cancel all timers and acceptors
- // This is not done automatically by ->stop(), and in some cases the destructor of
- // asio::io_service can hang if this is skipped.
- @@ -656,6 +661,7 @@ void StopRPCThreads()
- deadlineTimers.clear();
- rpc_io_service->stop();
- + cvBlockChange.notify_all();
- if (rpc_worker_group != NULL)
- rpc_worker_group->join_all();
- delete rpc_dummy_work; rpc_dummy_work = NULL;
- diff --git a/src/rpcserver.h b/src/rpcserver.h
- index 1092c69..c5f4609 100644
- --- a/src/rpcserver.h
- +++ b/src/rpcserver.h
- @@ -19,6 +19,7 @@
- #include "json/json_spirit_writer_template.h"
- class CBlockIndex;
- +extern bool fRPCRunning;
- /* Start RPC threads */
- void StartRPCThreads();
- @@ -126,6 +127,7 @@ extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHe
- extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp);
- extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp);
- extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp);
- +extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp);
- extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp);
- extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp);
- extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
- diff --git a/src/script.cpp b/src/script.cpp
- index 81d2754..24bbbad 100644
- --- a/src/script.cpp
- +++ b/src/script.cpp
- @@ -3,6 +3,9 @@
- // Distributed under the MIT/X11 software license, see the accompanying
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
- +#include <stdint.h>
- +
- +#include "compat.h"
- #include "script.h"
- #include "core.h"
- @@ -1199,7 +1202,8 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
- mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
- // Empty, provably prunable, data-carrying output
- - mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
- + if (GetBoolArg("-datacarrier", true))
- + mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
- mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
- }
- @@ -1400,7 +1404,8 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
- return -1;
- }
- -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
- +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType,
- + unsigned int flags)
- {
- vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- @@ -1408,6 +1413,8 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
- if (whichType == TX_MULTISIG)
- {
- + if (!(flags & SCRIPT_VERIFY_BARE_MSIG_OK))
- + return false;
- unsigned char m = vSolutions.front()[0];
- unsigned char n = vSolutions.back()[0];
- // Support up to x-of-3 multisig txns as standard
- @@ -1843,6 +1850,49 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
- return subscript.GetSigOpCount(true);
- }
- +struct BlacklistEntry {
- + uint32_t begin;
- + uint32_t end;
- + const char *name;
- +};
- +
- +static struct BlacklistEntry BlacklistedPrefixes[] = {
- + {0x946cb2e0, 0x946cb2e0, "Mastercoin"},
- + {0x06f1b600, 0x06f1b6ff, "SatoshiDice"},
- + {0x74db3700, 0x74db59ff, "BetCoin Dice"},
- + {0xc4c5d791, 0xc4c5d791, "CHBS"}, // 1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T
- + {0x434e5452, 0x434e5452, "Counterparty"},
- + {0x069532d8, 0x069532da, "SatoshiBones"},
- + {0xda5dde84, 0xda5dde94, "Lucky Bit"},
- +};
- +
- +bool fIsBareMultisigStd = false;
- +
- +const char *CScript::IsBlacklisted() const
- +{
- + if (this->size() >= 7 && this->at(0) == OP_DUP)
- + {
- + // pay-to-pubkeyhash
- + uint32_t pfx = ntohl(*(uint32_t*)&this->data()[3]);
- + unsigned i;
- +
- + for (i = 0; i < (sizeof(BlacklistedPrefixes) / sizeof(BlacklistedPrefixes[0])); ++i)
- + if (pfx >= BlacklistedPrefixes[i].begin && pfx <= BlacklistedPrefixes[i].end)
- + return BlacklistedPrefixes[i].name;
- + }
- + else
- + if (!fIsBareMultisigStd)
- + {
- + txnouttype type;
- + vector<vector<unsigned char> > vSolutions;
- + Solver(*this, type, vSolutions);
- + if (type == TX_MULTISIG)
- + return "bare multisig";
- + }
- +
- + return NULL;
- +}
- +
- bool CScript::IsPayToScriptHash() const
- {
- // Extra-fast test for pay-to-script-hash CScripts:
- diff --git a/src/script.h b/src/script.h
- index 1742ce8..20514c0 100644
- --- a/src/script.h
- +++ b/src/script.h
- @@ -190,6 +190,7 @@ enum
- SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
- SCRIPT_VERIFY_EVEN_S = (1U << 2), // enforce even S values in signatures (depends on STRICTENC)
- SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
- + SCRIPT_VERIFY_BARE_MSIG_OK = (1U << 4), // are bare msig outputs permitted?
- };
- enum txnouttype
- @@ -652,6 +653,8 @@ public:
- // pay-to-script-hash transactions:
- unsigned int GetSigOpCount(const CScript& scriptSig) const;
- + const char *IsBlacklisted() const;
- +
- bool IsPayToScriptHash() const;
- // Called by IsStandardTx and P2SH VerifyScript (which makes it consensus-critical).
- @@ -790,7 +793,8 @@ bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int
- bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
- bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
- int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
- -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
- +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType,
- + unsigned int flags);
- bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
- bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
- void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
- diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
- index 3775abd..8e6f7d2 100644
- --- a/src/test/multisig_tests.cpp
- +++ b/src/test/multisig_tests.cpp
- @@ -131,23 +131,30 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
- for (int i = 0; i < 4; i++)
- key[i].MakeNewKey(true);
- + unsigned int verfFlags = SCRIPT_VERIFY_BARE_MSIG_OK;
- txnouttype whichType;
- CScript a_and_b;
- a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
- - BOOST_CHECK(::IsStandard(a_and_b, whichType));
- + BOOST_CHECK(::IsStandard(a_and_b, whichType, verfFlags));
- + BOOST_CHECK(!::IsStandard(a_and_b, whichType,
- + verfFlags & ~SCRIPT_VERIFY_BARE_MSIG_OK));
- CScript a_or_b;
- a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
- - BOOST_CHECK(::IsStandard(a_or_b, whichType));
- + BOOST_CHECK(::IsStandard(a_or_b, whichType, verfFlags));
- + BOOST_CHECK(!::IsStandard(a_or_b, whichType,
- + verfFlags & ~SCRIPT_VERIFY_BARE_MSIG_OK));
- CScript escrow;
- escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
- - BOOST_CHECK(::IsStandard(escrow, whichType));
- + BOOST_CHECK(::IsStandard(escrow, whichType, verfFlags));
- + BOOST_CHECK(!::IsStandard(escrow, whichType,
- + verfFlags & ~SCRIPT_VERIFY_BARE_MSIG_OK));
- CScript one_of_four;
- one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG;
- - BOOST_CHECK(!::IsStandard(one_of_four, whichType));
- + BOOST_CHECK(!::IsStandard(one_of_four, whichType, verfFlags));
- CScript malformed[6];
- malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
- @@ -158,7 +165,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
- malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey();
- for (int i = 0; i < 6; i++)
- - BOOST_CHECK(!::IsStandard(malformed[i], whichType));
- + BOOST_CHECK(!::IsStandard(malformed[i], whichType, verfFlags));
- }
- BOOST_AUTO_TEST_CASE(multisig_Solver1)
- diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
- index 9b1290e..9bf8dc8 100644
- --- a/src/test/script_P2SH_tests.cpp
- +++ b/src/test/script_P2SH_tests.cpp
- @@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE(set)
- txTo[i].vin[0].prevout.n = i;
- txTo[i].vin[0].prevout.hash = txFrom.GetHash();
- txTo[i].vout[0].nValue = 1*CENT;
- - txTo[i].vout[0].scriptPubKey = inner[i];
- + txTo[i].vout[0].scriptPubKey = outer[i];
- BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
- }
- for (int i = 0; i < 4; i++)
- diff --git a/src/txmempool.cpp b/src/txmempool.cpp
- index 64c9eac..9713422 100644
- --- a/src/txmempool.cpp
- +++ b/src/txmempool.cpp
- @@ -195,6 +195,35 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
- return true;
- }
- +void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, int64_t nFeeDelta)
- +{
- + {
- + LOCK(cs);
- + std::pair<double, int64_t> &deltas = mapDeltas[hash];
- + deltas.first += dPriorityDelta;
- + deltas.second += nFeeDelta;
- + }
- + LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash.c_str(), dPriorityDelta, nFeeDelta);
- +}
- +
- +void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta)
- +{
- + LOCK(cs);
- + std::map<uint256, std::pair<double, int64_t> >::iterator pos = mapDeltas.find(hash);
- + if (pos == mapDeltas.end())
- + return;
- + const std::pair<double, int64_t> &deltas = pos->second;
- + dPriorityDelta += deltas.first;
- + nFeeDelta += deltas.second;
- +}
- +
- +void CTxMemPool::ClearPrioritisation(const uint256 hash)
- +{
- + LOCK(cs);
- + mapDeltas.erase(hash);
- +}
- +
- +
- CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
- bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) {
- diff --git a/src/txmempool.h b/src/txmempool.h
- index 4509e95..2d46816 100644
- --- a/src/txmempool.h
- +++ b/src/txmempool.h
- @@ -61,6 +61,7 @@ public:
- mutable CCriticalSection cs;
- std::map<uint256, CTxMemPoolEntry> mapTx;
- std::map<COutPoint, CInPoint> mapNextTx;
- + std::map<uint256, std::pair<double, int64_t> > mapDeltas;
- CTxMemPool();
- @@ -82,6 +83,11 @@ public:
- unsigned int GetTransactionsUpdated() const;
- void AddTransactionsUpdated(unsigned int n);
- + /** Affect CreateNewBlock prioritisation of transactions */
- + void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, int64_t nFeeDelta);
- + void ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta);
- + void ClearPrioritisation(const uint256 hash);
- +
- unsigned long size()
- {
- LOCK(cs);
- diff --git a/src/util.cpp b/src/util.cpp
- index b8036a3..88af740 100644
- --- a/src/util.cpp
- +++ b/src/util.cpp
- @@ -1336,6 +1336,8 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const
- if (!comments.empty())
- ss << "(" << boost::algorithm::join(comments, "; ") << ")";
- ss << "/";
- + ss << "ljr" << ":" << "20141002";
- + ss << "/";
- return ss.str();
- }
- diff --git a/src/wallet.cpp b/src/wallet.cpp
- index 80f011e..6f80fda 100644
- --- a/src/wallet.cpp
- +++ b/src/wallet.cpp
- @@ -1246,6 +1246,25 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
- wtxNew.BindWallet(this);
- + // Discourage fee sniping.
- + //
- + // However because of a off-by-one-error in previous versions we need to
- + // neuter it by setting nLockTime to at least one less than nBestHeight.
- + // Secondly currently propagation of transactions created for block heights
- + // corresponding to blocks that were just mined may be iffy - transactions
- + // aren't re-accepted into the mempool - we additionally neuter the code by
- + // going ten blocks back. Doesn't yet do anything for sniping, but does act
- + // to shake out wallet bugs like not showing nLockTime'd transactions at
- + // all.
- + wtxNew.nLockTime = chainActive.Height() - 10;
- +
- + // Secondly occasionally randomly pick a nLockTime even further back, so
- + // that transactions that are delayed after signing for whatever reason,
- + // e.g. high-latency mix networks and some CoinJoin implementations, have
- + // better privacy.
- + if (GetRandInt(10) == 0)
- + wtxNew.nLockTime -= GetRandInt(100);
- +
- {
- LOCK2(cs_main, cs_wallet);
- {
- @@ -1349,8 +1368,12 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
- reservekey.ReturnKey();
- // Fill vin
- + //
- + // Note how the sequence number is set to max()-1 so that the
- + // nLockTime set above actually works.
- BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- - wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
- + wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
- + std::numeric_limits<unsigned int>::max()-1));
- // Sign
- int nIn = 0;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement