unsigned int nMinerSleep;
bool fUseFastIndex;
bool fUseFastStakeMiner;
+bool fConfChange;
+bool fEnforceCanonical;
enum Checkpoints::CPMode CheckpointsMode;
//////////////////////////////////////////////////////////////////////////////
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
" -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" +
" -upgradewallet " + _("Upgrade wallet to latest format") + "\n" +
+ " -confchange " + _("Require a confirmations for change (default: 0)") + "\n" +
+ " -enforcecanonical " + _("Enforce transaction scripts to use canonical PUSH operators (default: 1)") + "\n" +
" -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" +
" -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" +
InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
}
+ fConfChange = GetBoolArg("-confchange", false);
+ fEnforceCanonical = GetBoolArg("-enforcecanonical", true);
+
if (mapArgs.count("-mininput"))
{
if (!ParseMoney(mapArgs["-mininput"], nMinimumInputValue))
bool CTransaction::IsStandard() const
{
- if (nVersion > CTransaction::CURRENT_VERSION)
+ if (nVersion > CTransaction::CURRENT_VERSION) {
return false;
+ }
BOOST_FOREACH(const CTxIn& txin, vin)
{
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
// ~65-byte public keys, plus a few script ops.
- if (txin.scriptSig.size() > 500)
+ if (txin.scriptSig.size() > 500) {
+ return false;
+ }
+ if (!txin.scriptSig.IsPushOnly()) {
return false;
- if (!txin.scriptSig.IsPushOnly())
+ }
+ if (fEnforceCanonical && !txin.scriptSig.HasCanonicalPushes()) {
return false;
+ }
}
+
BOOST_FOREACH(const CTxOut& txout, vout) {
- if (!::IsStandard(txout.scriptPubKey))
+ if (!::IsStandard(txout.scriptPubKey)) {
return false;
- if (txout.nValue == 0)
+ }
+ if (txout.nValue == 0) {
+ return false;
+ }
+ if (fEnforceCanonical && !txout.scriptPubKey.HasCanonicalPushes()) {
return false;
+ }
}
+
return true;
}
extern int64 nMinimumInputValue;
extern bool fUseFastIndex;
extern unsigned int nDerivationMethodIndex;
+extern bool fEnforceCanonical;
// Minimum disk space required - used in CheckDiskSpace()
static const uint64 nMinDiskSpace = 52428800;
(wtx.IsCoinBase() ? 1 : 0),
wtx.nTimeReceived,
idx);
- status.confirmed = wtx.IsConfirmed();
+ status.confirmed = wtx.IsTrusted();
status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = nBestHeight;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (!wtx.IsConfirmed())
+ if (!wtx.IsTrusted())
continue;
int64 allGeneratedImmature, allGeneratedMature, allFee;
this->at(22) == OP_EQUAL);
}
+bool CScript::HasCanonicalPushes() const
+{
+ const_iterator pc = begin();
+ while (pc < end())
+ {
+ opcodetype opcode;
+ std::vector<unsigned char> data;
+ if (!GetOp(pc, opcode, data))
+ return false;
+ if (opcode > OP_16)
+ continue;
+ if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16))
+ // Could have used an OP_n code, rather than a 1-byte push.
+ return false;
+ if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1)
+ // Could have used a normal n-byte push, rather than OP_PUSHDATA1.
+ return false;
+ if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF)
+ // Could have used an OP_PUSHDATA1.
+ return false;
+ if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF)
+ // Could have used an OP_PUSHDATA2.
+ return false;
+ }
+ return true;
+}
+
class CScriptVisitor : public boost::static_visitor<bool>
{
private:
return true;
}
+ // Called by CTransaction::IsStandard.
+ bool HasCanonicalPushes() const;
void SetDestination(const CTxDestination& address);
void SetMultisig(int nRequired, const std::vector<CKey>& keys);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (pcoin->IsConfirmed())
+ if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableCredit();
}
}
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ if (!pcoin->IsFinal() || !pcoin->IsTrusted())
nTotal += pcoin->GetAvailableCredit();
}
}
if (!pcoin->IsFinal())
continue;
- if (fOnlyConfirmed && !pcoin->IsConfirmed())
+ if (fOnlyConfirmed && !pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
{
CWalletTx *pcoin = &walletEntry.second;
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ if (!pcoin->IsFinal() || !pcoin->IsTrusted())
continue;
if ((pcoin->IsCoinBase() || pcoin->IsCoinStake()) && pcoin->GetBlocksToMaturity() > 0)
#include "walletdb.h"
extern bool fWalletUnlockMintOnly;
+extern bool fConfChange;
+
class CAccountingEntry;
class CWalletTx;
class CReserveKey;
return (GetDebit() > 0);
}
- bool IsConfirmed() const
+ bool IsTrusted() const
{
// Quick answer in most cases
if (!IsFinal())
return false;
if (GetDepthInMainChain() >= 1)
return true;
- if (!IsFromMe()) // using wtx's cached debit
+ if (fConfChange || !IsFromMe()) // using wtx's cached debit
return false;
// If no confirmations but it's from us, we can still