Showing with 36 additions and 0 deletions.
  1. +2 −0 src/consensus/consensus.h
  2. +22 −0 src/primitives/transaction.cpp
  3. +3 −0 src/primitives/transaction.h
  4. +9 −0 src/validation.cpp
2 changes: 2 additions & 0 deletions src/consensus/consensus.h
Expand Up @@ -9,6 +9,8 @@
#include <stdlib.h>
#include <stdint.h>

/** The minimum allowed price, in USD per BTC (effective beginning with block 622370) */
static const unsigned int MIN_USDBTC_PRICE = 50000;
/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000;
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
Expand Down
22 changes: 22 additions & 0 deletions src/primitives/transaction.cpp
Expand Up @@ -80,6 +80,28 @@ CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VER
CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}

int64_t CTransaction::GetUSDPrice() const
{
if (vout.size() >= 1
&& vout[0].scriptPubKey.size() >= 7
&& vout[0].scriptPubKey[0] == OP_RETURN
&& vout[0].scriptPubKey[1] == 4 // push 4 bytes
&& vout[0].scriptPubKey[2] == 0x55
&& vout[0].scriptPubKey[3] == 0x53
&& vout[0].scriptPubKey[4] == 0x44
&& vout[0].scriptPubKey[5] == 0x24
&& vout[0].scriptPubKey[6] <= 5 // at most 5 bytes for the price
&& vout[0].scriptPubKey[6] == vout[0].scriptPubKey.size() - 7) {
try {
const CScriptNum usd_price(std::vector<unsigned char>(vout[0].scriptPubKey.begin() + 7, vout[0].scriptPubKey.end()), true, 5);
return usd_price.getint();
} catch (...) {
return -1;
}
}
return -1;
}

CAmount CTransaction::GetValueOut() const
{
CAmount nValueOut = 0;
Expand Down
3 changes: 3 additions & 0 deletions src/primitives/transaction.h
Expand Up @@ -321,6 +321,9 @@ class CTransaction
// GetValueIn() is a method on CCoinsViewCache, because
// inputs must be known to compute value in.

// Returns the USD/BTC exchange rate used for the transaction, or -1 if unknown
int64_t GetUSDPrice() const;

/**
* Get the total transaction size in bytes, including witness data.
* "Total Size" defined in BIP141 and BIP144.
Expand Down
9 changes: 9 additions & 0 deletions src/validation.cpp
Expand Up @@ -3301,6 +3301,15 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
}
}

if (nHeight >= 622370) { // Approx 2020 April 1
// Check that all transactions declare a price >= $50kUSD/BTC
for (const auto& tx : block.vtx) {
if (tx->GetUSDPrice() < MIN_USDBTC_PRICE) {
return state.DoS(0, false, REJECT_INVALID, "bad-txns-bear", false, "transaction USD price too low");
}
}
}

// Validation for witness commitments.
// * We compute the witness hash (which is the hash including witnesses) of all the block's transactions, except the
// coinbase (where 0x0000....0000 is used instead).
Expand Down