Browse Source

[raw] reject insanely high fees by default in sendrawtransaction

There have been several incidents where mainnet experimentation with
 raw transactions  resulted in insane fees.  This is hard to prevent
 in the raw transaction api because the inputs may not be known.
 Since sending doesn't work if the inputs aren't known, we can catch
 it there.

This rejects fees > than 10000 * nMinRelayTxFee or 1 BTC with the
 defaults and can be overridden with a bool at the rpc.

Conflicts:
	src/main.cpp
	src/main.h
	src/rpcrawtransaction.cpp

Rebased-from: 6349de20f90f046aefa9eaae0de8e3faf11527fa 0.8.x
0.8
Gregory Maxwell 11 years ago committed by Warren Togami
parent
commit
6a51fcf1bd
  1. 1
      src/bitcoinrpc.cpp
  2. 11
      src/main.cpp
  3. 4
      src/main.h
  4. 10
      src/rpcrawtransaction.cpp

1
src/bitcoinrpc.cpp

@ -1188,6 +1188,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri @@ -1188,6 +1188,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true);
if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
if (strMethod == "sendrawtransaction" && n > 1) ConvertTo<bool>(params[1], true);
if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]);
if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);

11
src/main.cpp

@ -649,7 +649,7 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) @@ -649,7 +649,7 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
}
bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckInputs, bool fLimitFree,
bool* pfMissingInputs)
bool* pfMissingInputs, bool fRejectInsaneFee)
{
if (pfMissingInputs)
*pfMissingInputs = false;
@ -784,6 +784,11 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn @@ -784,6 +784,11 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
dFreeCount += nSize;
}
if (fRejectInsaneFee && nFees > CTransaction::nMinRelayTxFee * 10000)
return error("CTxMemPool::accept() : insane fees %s, %"PRI64d" > %"PRI64d,
hash.ToString().c_str(),
nFees, CTransaction::nMinRelayTxFee * 10000);
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC))
@ -812,10 +817,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn @@ -812,10 +817,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
return true;
}
bool CTransaction::AcceptToMemoryPool(CValidationState &state, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs)
bool CTransaction::AcceptToMemoryPool(CValidationState &state, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee)
{
try {
return mempool.accept(state, *this, fCheckInputs, fLimitFree, pfMissingInputs);
return mempool.accept(state, *this, fCheckInputs, fLimitFree, pfMissingInputs, fRejectInsaneFee);
} catch(std::runtime_error &e) {
return state.Abort(_("System error: ") + e.what());
}

4
src/main.h

@ -682,7 +682,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach @@ -682,7 +682,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
bool CheckTransaction(CValidationState &state) const;
// Try to accept this transaction into the memory pool
bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL);
bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL, bool fRejectInsaneFee = false);
protected:
static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs);
@ -2099,7 +2099,7 @@ public: @@ -2099,7 +2099,7 @@ public:
std::map<uint256, CTransaction> mapTx;
std::map<COutPoint, CInPoint> mapNextTx;
bool accept(CValidationState &state, CTransaction &tx, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs);
bool accept(CValidationState &state, CTransaction &tx, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee = false);
bool addUnchecked(const uint256& hash, const CTransaction &tx);
bool remove(const CTransaction &tx, bool fRecursive = false);
bool removeConflicts(const CTransaction &tx);

10
src/rpcrawtransaction.cpp

@ -529,9 +529,9 @@ Value signrawtransaction(const Array& params, bool fHelp) @@ -529,9 +529,9 @@ Value signrawtransaction(const Array& params, bool fHelp)
Value sendrawtransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 1)
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"sendrawtransaction <hex string>\n"
"sendrawtransaction <hex string> [allowhighfees=false]\n"
"Submits raw transaction (serialized, hex-encoded) to local node and network.");
// parse hex string from parameter
@ -539,6 +539,10 @@ Value sendrawtransaction(const Array& params, bool fHelp) @@ -539,6 +539,10 @@ Value sendrawtransaction(const Array& params, bool fHelp)
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
bool fOverrideFees = false;
if (params.size() > 1)
fOverrideFees = params[1].get_bool();
// deserialize binary data stream
try {
ssData >> tx;
@ -556,7 +560,7 @@ Value sendrawtransaction(const Array& params, bool fHelp) @@ -556,7 +560,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
if (!fHave) {
// push to local node
CValidationState state;
if (!tx.AcceptToMemoryPool(state, true, false))
if (!tx.AcceptToMemoryPool(state, true, false, NULL, !fOverrideFees))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
}
}

Loading…
Cancel
Save