Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update develop with enforced value fixes #794

Merged
merged 14 commits into from
Jul 8, 2020
15 changes: 15 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ class CMainParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nTimeout = 1620324000; // UTC: Thu May 06 2021 18:00:00
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nOverrideRuleChangeActivationThreshold = 1714; // Approx 85% of 2016
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nOverrideMinerConfirmationWindow = 2016;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].bit = 9;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nStartTime = 1593453600; // UTC: Mon Jun 29 2020 18:00:00
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nTimeout = 1624989600; // UTC: Mon Jun 29 2021 18:00:00
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nOverrideRuleChangeActivationThreshold = 1411; // Approx 70% of 2016
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nOverrideMinerConfirmationWindow = 2016;

// The best chain should have at least this much work
consensus.nMinimumChainWork = uint256S("000000000000000000000000000000000000000000000020d4ac871fb7009b63"); // Block 1186833
Expand Down Expand Up @@ -302,6 +307,11 @@ class CTestNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nTimeout = 1618509600; // UTC: Thu Apr 15 2021 18:00:00
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nOverrideRuleChangeActivationThreshold = 1310;
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nOverrideMinerConfirmationWindow = 2016;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].bit = 9;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nStartTime = 1593453600; // UTC: Mon Jun 29 2020 18:00:00
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nTimeout = 1624989600; // UTC: Mon Jun 29 2021 18:00:00
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nOverrideRuleChangeActivationThreshold = 1411; // Approx 70% of 2016
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nOverrideMinerConfirmationWindow = 2016;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000168050db560b4");
Expand Down Expand Up @@ -512,6 +522,11 @@ class CRegTestParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nOverrideRuleChangeActivationThreshold = 208;
consensus.vDeployments[Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE].nOverrideMinerConfirmationWindow = 288;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].bit = 9;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nOverrideRuleChangeActivationThreshold = 108;
consensus.vDeployments[Consensus::DEPLOYMENT_ENFORCE_VALUE].nOverrideMinerConfirmationWindow = 144;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
Expand Down
1 change: 1 addition & 0 deletions src/consensus/consensus.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR *
UNUSED_VAR static bool fAssetsIsActive = false;
UNUSED_VAR static bool fRip5IsActive = false;
UNUSED_VAR static bool fTransferScriptIsActive = false;
UNUSED_VAR static bool fEnforcedValuesIsActive = false;

unsigned int GetMaxBlockWeight();
unsigned int GetMaxBlockSerializedSize();
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum DeploymentPos
DEPLOYMENT_ASSETS, // Deployment of RIP2
DEPLOYMENT_MSG_REST_ASSETS, // Delpoyment of RIP5 and Restricted assets
DEPLOYMENT_TRANSFER_SCRIPT_SIZE,
DEPLOYMENT_ENFORCE_VALUE,
// DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
// DEPLOYMENT_SEGWIT, // Deployment of BIP141, BIP143, and BIP147.
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
Expand Down
23 changes: 22 additions & 1 deletion src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
return nSigOps;
}

bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs, bool fMempoolCheck, bool fBlockCheck)
{
// Basic checks that don't depend on any context
if (tx.vin.empty())
Expand Down Expand Up @@ -308,6 +308,27 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
// Specific check and error message to go with to make sure the amount is 0
if (txout.nValue != 0)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-asset-issued-amount-isn't-zero");
} else if (nType == TX_REISSUE_ASSET) {
// Specific check and error message to go with to make sure the amount is 0
if (AreEnforcedValuesDeployed()) {
// We only want to not accept these txes when checking them from CheckBlock.
// We don't want to change the behavior when reading transactions from the database
// when AreEnforcedValuesDeployed return true
if (fBlockCheck) {
if (txout.nValue != 0) {
return state.DoS(0, false, REJECT_INVALID, "bad-txns-asset-reissued-amount-isn't-zero");
}
}
}

if (fMempoolCheck) {
// Don't accept to the mempool no matter what on these types of transactions
if (txout.nValue != 0) {
return state.DoS(0, false, REJECT_INVALID, "bad-mempool-txns-asset-reissued-amount-isn't-zero");
}
}
} else {
return state.DoS(0, false, REJECT_INVALID, "bad-asset-type-not-any-of-the-main-three");
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/consensus/tx_verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class CNullAssetTxData;
/** Transaction validation functions */

/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);
bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true, bool fMempoolCheck = false, bool fBlockCheck = false);

namespace Consensus {
/**
Expand Down
71 changes: 71 additions & 0 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,36 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
return result;
}

UniValue decodeblockToJSON(const CBlock& block)
{
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", block.GetHash().GetHex()));

result.push_back(Pair("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("weight", (int)::GetBlockWeight(block)));
result.push_back(Pair("height", (int)block.nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion)));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
UniValue txs(UniValue::VARR);
for(const auto& tx : block.vtx)
{
UniValue objTx(UniValue::VOBJ);
TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags());
txs.push_back(objTx);
}
result.push_back(Pair("tx", txs));
result.push_back(Pair("time", block.GetBlockTime()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
result.push_back(Pair("headerhash", block.GetKAWPOWHeaderHash().GetHex()));
result.push_back(Pair("mixhash", block.mix_hash.GetHex()));
result.push_back(Pair("nonce64", (uint64_t)block.nNonce64));

return result;
}

UniValue getblockcount(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
Expand Down Expand Up @@ -990,6 +1020,45 @@ UniValue getblock(const JSONRPCRequest& request)
return blockToJSON(block, pblockindex, verbosity >= 2);
}

UniValue decodeblock(const JSONRPCRequest& request)
blondfrogs marked this conversation as resolved.
Show resolved Hide resolved
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"decodeblock \"blockhex\"\n"
"\nArguments:\n"
"1. \"blockhex\" (string, required) The block hex\n"
"\nResult:\n"
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
" \"size\" : n, (numeric) The block size\n"
" \"strippedsize\" : n, (numeric) The block size excluding witness data\n"
" \"weight\" : n (numeric) The block weight as defined in BIP 141\n"
" \"height\" : n, (numeric) The block height or index\n"
" \"version\" : n, (numeric) The block version\n"
" \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n"
" \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
" \"tx\" : [ (array of string) The transaction ids\n"
" \"transactionid\" (string) The transaction id\n"
" ,...\n"
" ],\n"
" \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"nonce\" : n, (numeric) The nonce\n"
" \"bits\" : \"1d00ffff\", (string) The bits\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("decodeblock", "\"xxxx\"")
+ HelpExampleRpc("decodeblock", "\"xxxx\"")
);

std::string strHex = request.params[0].get_str();
CBlock block;
DecodeHexBlk(block, strHex);

return decodeblockToJSON(block);
}



struct CCoinsStats
{
int nHeight;
Expand Down Expand Up @@ -1433,6 +1502,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
BIP9SoftForkDescPushBack(bip9_softforks, "assets", consensusParams, Consensus::DEPLOYMENT_ASSETS);
BIP9SoftForkDescPushBack(bip9_softforks, "messaging_restricted", consensusParams, Consensus::DEPLOYMENT_MSG_REST_ASSETS);
BIP9SoftForkDescPushBack(bip9_softforks, "transfer_script", consensusParams, Consensus::DEPLOYMENT_TRANSFER_SCRIPT_SIZE);
BIP9SoftForkDescPushBack(bip9_softforks, "enforce", consensusParams, Consensus::DEPLOYMENT_ENFORCE_VALUE);
obj.push_back(Pair("softforks", softforks));
obj.push_back(Pair("bip9_softforks", bip9_softforks));

Expand Down Expand Up @@ -1832,6 +1902,7 @@ static const CRPCCommand commands[] =
{ "blockchain", "getbestblockhash", &getbestblockhash, {} },
{ "blockchain", "getblockcount", &getblockcount, {} },
{ "blockchain", "getblock", &getblock, {"blockhash","verbosity|verbose"} },
{ "blockchain", "decodeblock", &decodeblock, {"blockhex"} },
{ "blockchain", "getblockdeltas", &getblockdeltas, {} },
{ "blockchain", "getblockhashes", &getblockhashes, {} },
{ "blockchain", "getblockhash", &getblockhash, {"height"} },
Expand Down
1 change: 1 addition & 0 deletions src/rpc/blockchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);

/** Block description to JSON */
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
UniValue decodeblockToJSON(const CBlock& block);

/** Mempool information to JSON */
UniValue mempoolInfoToJSON();
Expand Down
63 changes: 63 additions & 0 deletions src/test/assets/asset_tx_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <base58.h>
#include <consensus/validation.h>
#include <consensus/tx_verify.h>
#include <validation.h>

BOOST_FIXTURE_TEST_SUITE(asset_tx_tests, BasicTestingSetup)

Expand Down Expand Up @@ -477,4 +478,66 @@ BOOST_FIXTURE_TEST_SUITE(asset_tx_tests, BasicTestingSetup)
BOOST_CHECK_MESSAGE(!CheckNewAsset(asset, error), "Test13: " + error);
}

BOOST_AUTO_TEST_CASE(asset_tx_enforce_value_test)
{
BOOST_TEST_MESSAGE("Running Asset TX Enforce Value Test");

SelectParams(CBaseChainParams::MAIN);

// Create the reissue asset
CReissueAsset reissueAsset("ENFORCE_VALUE", 100, 8, true, "");
CScript scriptPubKey = GetScriptForDestination(DecodeDestination(GetParams().GlobalBurnAddress()));
reissueAsset.ConstructTransaction(scriptPubKey);

// Create an invalid reissue asset with nValue not equal to zero
CTxOut txOut;
txOut.nValue = 500;
txOut.scriptPubKey = scriptPubKey;

// Create views
CCoinsView view;
CCoinsViewCache coins(&view);
CAssetsCache assetCache;

// Create a random hash
uint256 hash = uint256S("BF50CB9A63BE0019171456252989A459A7D0A5F494735278290079D22AB704A2");

// Add the coin to the cache
COutPoint outpoint(hash, 1);
coins.AddCoin(outpoint, Coin(txOut, 10, 0), true);

// Create input
CTxIn in;
in.prevout = outpoint;

// Create transaction and input for the outpoint of the coin we just created
CMutableTransaction mutTx;

// Add the input, and an output into the transaction
mutTx.vin.emplace_back(in);
mutTx.vout.emplace_back(txOut);

CTransaction tx(mutTx);
CValidationState state;

bool fCheckMempool = true;
bool fCheckBlock = false;

// Check that the CheckTransaction will fail when trying to add it to the mempool
bool fCheck = !CheckTransaction(tx, state, true, fCheckMempool, fCheckBlock);

BOOST_CHECK(fCheck);
BOOST_CHECK(state.GetRejectReason() == "bad-mempool-txns-asset-reissued-amount-isn't-zero");

// Check that the CheckTransaction will fail when trying to add it to a block
fCheckMempool = false;
fCheckBlock = true;
// Turn on the BIP that enforces the block check
SetEnforcedValues(true);

fCheck = !CheckTransaction(tx, state, true, fCheckMempool, fCheckBlock);
BOOST_CHECK(fCheck);
BOOST_CHECK(state.GetRejectReason() == "bad-txns-asset-reissued-amount-isn't-zero");
}

BOOST_AUTO_TEST_SUITE_END()
52 changes: 45 additions & 7 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,10 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
AssertLockHeld(cs_main);
if (pfMissingInputs)
*pfMissingInputs = false;
if (!CheckTransaction(tx, state))

bool fCheckDuplicates = true;
bool fCheckMempool = true;
if (!CheckTransaction(tx, state, fCheckDuplicates, fCheckMempool))
return false; // state filled in by CheckTransaction

// Coinbase is only valid in a block, not as a loose transaction
Expand Down Expand Up @@ -3951,7 +3954,7 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state,
return true;
}

bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot)
bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot, bool fDBCheck)
{
// These are checks that are independent of context.

Expand Down Expand Up @@ -3996,10 +3999,23 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase");

// Check transactions
for (const auto& tx : block.vtx)
if (!CheckTransaction(*tx, state))
bool fCheckBlock = true;
bool fCheckDuplicates = true;
bool fCheckMempool = false;
for (const auto& tx : block.vtx) {
// We only want to check the blocks when they are added to our chain
// We want to make sure when nodes shutdown and restart that they still
// verify the blocks in the database correctly even if Enforce Value BIP is active
fCheckBlock = true;
if (fDBCheck){
fCheckBlock = false;
}

if (!CheckTransaction(*tx, state, fCheckDuplicates, fCheckMempool, fCheckBlock))
return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),
strprintf("Transaction check failed (tx hash %s) %s %s", tx->GetHash().ToString(), state.GetDebugMessage(), state.GetRejectReason()));
strprintf("Transaction check failed (tx hash %s) %s %s", tx->GetHash().ToString(),
state.GetDebugMessage(), state.GetRejectReason()));
}

unsigned int nSigOps = 0;
for (const auto& tx : block.vtx)
Expand Down Expand Up @@ -4878,7 +4894,10 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity
if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams.GetConsensus(), true, true)) // fCheckAssetDuplicate set to false, because we don't want to fail because the asset exists in our database, when loading blocks from our asset databse
bool fCheckPoW = true;
bool fCheckMerkleRoot = true;
bool fDBCheck = true;
if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams.GetConsensus(), fCheckPoW, fCheckMerkleRoot, fDBCheck)) // fCheckAssetDuplicate set to false, because we don't want to fail because the asset exists in our database, when loading blocks from our asset databse
return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__,
pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
// check level 2: verify undo validity
Expand Down Expand Up @@ -5703,7 +5722,26 @@ double GuessVerificationProgress(const ChainTxData& data, CBlockIndex *pindex) {
}

/** RVN START */
bool AreAssetsDeployed() {

// Only used by test framework
void SetEnforcedValues(bool value) {
fEnforcedValuesIsActive = value;
}

bool AreEnforcedValuesDeployed()
{
if (fEnforcedValuesIsActive)
return true;

const ThresholdState thresholdState = VersionBitsTipState(GetParams().GetConsensus(), Consensus::DEPLOYMENT_ENFORCE_VALUE);
if (thresholdState == THRESHOLD_ACTIVE || thresholdState == THRESHOLD_LOCKED_IN)
fEnforcedValuesIsActive = true;

return fEnforcedValuesIsActive;
}

bool AreAssetsDeployed()
{

if (fAssetsIsActive)
return true;
Expand Down
7 changes: 6 additions & 1 deletion src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus
/** Functions for validating blocks and updating the block tree */

/** Context-independent validity checks */
bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true, bool fDBCheck = false);

/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
Expand Down Expand Up @@ -595,6 +595,11 @@ bool AreMessagesDeployed();

bool AreRestrictedAssetsDeployed();

bool AreEnforcedValuesDeployed();

// Only used by test framework
void SetEnforcedValues(bool value);

bool IsRip5Active();


Expand Down
Loading