Auto merge of #1566 - daira:1557.make-v2-txns-standard, r=ageis
1557.make v2 txns standard Make v2 transactions standard. This also corrects a rule about admitting large orphan transactions into the mempool, to account for v2-specific fields. ref #1557
This commit is contained in:
commit
c99a1c7e4f
|
@ -157,7 +157,7 @@ static void RegisterLoad(const string& strInput)
|
|||
static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
|
||||
{
|
||||
int64_t newVersion = atoi64(cmdVal);
|
||||
if (newVersion < 1 || newVersion > CTransaction::CURRENT_VERSION)
|
||||
if (newVersion < CTransaction::MIN_CURRENT_VERSION || newVersion > CTransaction::MAX_CURRENT_VERSION)
|
||||
throw runtime_error("Invalid TX version requested");
|
||||
|
||||
tx.nVersion = (int) newVersion;
|
||||
|
|
|
@ -564,7 +564,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer)
|
|||
// have been mined or received.
|
||||
// 10,000 orphans, each of which is at most 5,000 bytes big is
|
||||
// at most 500 megabytes of orphans:
|
||||
unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
|
||||
unsigned int sz = tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
|
||||
if (sz > 5000)
|
||||
{
|
||||
LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
|
||||
|
@ -639,7 +639,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
|
|||
|
||||
bool IsStandardTx(const CTransaction& tx, string& reason)
|
||||
{
|
||||
if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
|
||||
if (tx.nVersion > CTransaction::MAX_CURRENT_VERSION || tx.nVersion < CTransaction::MIN_CURRENT_VERSION) {
|
||||
reason = "version";
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ std::string CTxOut::ToString() const
|
|||
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
|
||||
}
|
||||
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::MIN_CURRENT_VERSION), nLockTime(0) {}
|
||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
|
||||
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
|
||||
{
|
||||
|
@ -154,7 +154,7 @@ void CTransaction::UpdateHash() const
|
|||
*const_cast<uint256*>(&hash) = SerializeHash(*this);
|
||||
}
|
||||
|
||||
CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), vjoinsplit(), joinSplitPubKey(), joinSplitSig() { }
|
||||
CTransaction::CTransaction() : nVersion(CTransaction::MIN_CURRENT_VERSION), vin(), vout(), nLockTime(0), vjoinsplit(), joinSplitPubKey(), joinSplitSig() { }
|
||||
|
||||
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vjoinsplit(tx.vjoinsplit),
|
||||
joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
|
||||
|
|
|
@ -309,7 +309,9 @@ private:
|
|||
public:
|
||||
typedef boost::array<unsigned char, 64> joinsplit_sig_t;
|
||||
|
||||
static const int32_t CURRENT_VERSION=1;
|
||||
// Transactions that include a list of JoinSplits are version 2.
|
||||
static const int32_t MIN_CURRENT_VERSION = 1;
|
||||
static const int32_t MAX_CURRENT_VERSION = 2;
|
||||
|
||||
// The local variables are made const to prevent unintended modification
|
||||
// without updating the cached hash value. However, CTransaction is not
|
||||
|
|
|
@ -590,4 +590,55 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
|||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_IsStandardV2)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CBasicKeyStore keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
|
||||
|
||||
CMutableTransaction t;
|
||||
t.vin.resize(1);
|
||||
t.vin[0].prevout.hash = dummyTransactions[0].GetHash();
|
||||
t.vin[0].prevout.n = 1;
|
||||
t.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
|
||||
t.vout.resize(1);
|
||||
t.vout[0].nValue = 90*CENT;
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
|
||||
|
||||
string reason;
|
||||
// A v2 transaction with no JoinSplits is still standard.
|
||||
t.nVersion = 2;
|
||||
BOOST_CHECK(IsStandardTx(t, reason));
|
||||
|
||||
// ... and with one JoinSplit.
|
||||
t.vjoinsplit.push_back(JSDescription());
|
||||
BOOST_CHECK(IsStandardTx(t, reason));
|
||||
|
||||
// ... and when that JoinSplit takes from a transparent input.
|
||||
JSDescription *jsdesc = &t.vjoinsplit[0];
|
||||
jsdesc->vpub_old = 10*CENT;
|
||||
t.vout[0].nValue -= 10*CENT;
|
||||
BOOST_CHECK(IsStandardTx(t, reason));
|
||||
|
||||
// A v2 transaction with JoinSplits but no transparent inputs is standard.
|
||||
jsdesc->vpub_old = 0;
|
||||
jsdesc->vpub_new = 100*CENT;
|
||||
t.vout[0].nValue = 90*CENT;
|
||||
t.vin.resize(0);
|
||||
BOOST_CHECK(IsStandardTx(t, reason));
|
||||
|
||||
// v2 transactions can still be non-standard for the same reasons as v1.
|
||||
t.vout[0].nValue = 501; // dust
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
|
||||
// v3 is not standard.
|
||||
t.nVersion = 3;
|
||||
t.vout[0].nValue = 90*CENT;
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Reference in New Issue