Primitive, context-free consensus changes for CPourTx

* PourTxs cannot appear in coinbase transactions.
* Transactions can only contain empty vin/vouts if they contain a PourTx.
* PourTx public values must be well-formed (not negative or too large).
* Transactions cannot have the same serial twice throughout all PourTxs.
This commit is contained in:
Sean Bowe
2015-12-29 20:20:30 -07:00
parent 5884044ba9
commit 69761d8269
2 changed files with 162 additions and 2 deletions

View File

@@ -847,12 +847,16 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
{
// Basic checks that don't depend on any context
if (tx.vin.empty())
// Transactions can contain empty `vin` and `vout` so long as
// `vpour` is non-empty.
if (tx.vin.empty() && tx.vpour.empty())
return state.DoS(10, error("CheckTransaction(): vin empty"),
REJECT_INVALID, "bad-txns-vin-empty");
if (tx.vout.empty())
if (tx.vout.empty() && tx.vpour.empty())
return state.DoS(10, error("CheckTransaction(): vout empty"),
REJECT_INVALID, "bad-txns-vout-empty");
// Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckTransaction(): size limits failed"),
@@ -874,6 +878,32 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
}
// Ensure that pour values are well-formed
BOOST_FOREACH(const CPourTx& pour, tx.vpour)
{
if (pour.vpub_old < 0)
return state.DoS(100, error("CheckTransaction(): pour.vpub_old negative"),
REJECT_INVALID, "bad-txns-vpub_old-negative");
if (pour.vpub_new < 0)
return state.DoS(100, error("CheckTransaction(): pour.vpub_new negative"),
REJECT_INVALID, "bad-txns-vpub_new-negative");
if (pour.vpub_old > MAX_MONEY)
return state.DoS(100, error("CheckTransaction(): pour.vpub_old too high"),
REJECT_INVALID, "bad-txns-vpub_old-toolarge");
if (pour.vpub_new > MAX_MONEY)
return state.DoS(100, error("CheckTransaction(): pour.vpub_new too high"),
REJECT_INVALID, "bad-txns-vpub_new-toolarge");
nValueOut += pour.vpub_new;
if (!MoneyRange(nValueOut))
return state.DoS(100, error("CheckTransaction(): txout total out of range"),
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
}
// Check for duplicate inputs
set<COutPoint> vInOutPoints;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
@@ -884,8 +914,27 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
vInOutPoints.insert(txin.prevout);
}
// Check for duplicate pour serials in this transaction
set<uint256> vPourSerials;
BOOST_FOREACH(const CPourTx& pour, tx.vpour)
{
BOOST_FOREACH(const uint256& serial, pour.serials)
{
if (vPourSerials.count(serial))
return state.DoS(100, error("CheckTransaction(): duplicate serials"),
REJECT_INVALID, "bad-pours-serials-duplicate");
vPourSerials.insert(serial);
}
}
if (tx.IsCoinBase())
{
// There should be no pours in a coinbase transaction
if (tx.vpour.size() > 0)
return state.DoS(100, error("CheckTransaction(): coinbase has pours"),
REJECT_INVALID, "bad-cb-has-pours");
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
return state.DoS(100, error("CheckTransaction(): coinbase script size"),
REJECT_INVALID, "bad-cb-length");