Merge pull request #2264 from codablock/pr_dip3_unittests
DIP3 and DIP4 unit tests
This commit is contained in:
commit
1560b16775
@ -89,6 +89,8 @@ BITCOIN_TESTS =\
|
||||
test/crypto_tests.cpp \
|
||||
test/cuckoocache_tests.cpp \
|
||||
test/DoS_tests.cpp \
|
||||
test/evo_deterministicmns_tests.cpp \
|
||||
test/evo_simplifiedmns_tests.cpp \
|
||||
test/getarg_tests.cpp \
|
||||
test/governance_validators_tests.cpp \
|
||||
test/hash_tests.cpp \
|
||||
|
@ -45,6 +45,15 @@ void CSimplifiedMNListEntry::ToJson(UniValue& obj) const
|
||||
obj.push_back(Pair("isValid", isValid));
|
||||
}
|
||||
|
||||
CSimplifiedMNList::CSimplifiedMNList(const std::vector<CSimplifiedMNListEntry>& smlEntries)
|
||||
{
|
||||
mnList = smlEntries;
|
||||
|
||||
std::sort(mnList.begin(), mnList.end(), [&](const CSimplifiedMNListEntry& a, const CSimplifiedMNListEntry& b) {
|
||||
return a.proRegTxHash.Compare(b.proRegTxHash) < 0;
|
||||
});
|
||||
}
|
||||
|
||||
CSimplifiedMNList::CSimplifiedMNList(const CDeterministicMNList& dmnList)
|
||||
{
|
||||
mnList.reserve(dmnList.all_count());
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
|
||||
public:
|
||||
CSimplifiedMNList() {}
|
||||
CSimplifiedMNList(const std::vector<CSimplifiedMNListEntry>& smlEntries);
|
||||
CSimplifiedMNList(const CDeterministicMNList& dmnList);
|
||||
|
||||
uint256 CalcMerkleRoot(bool *pmutated = NULL) const;
|
||||
|
394
src/test/evo_deterministicmns_tests.cpp
Normal file
394
src/test/evo_deterministicmns_tests.cpp
Normal file
@ -0,0 +1,394 @@
|
||||
// Copyright (c) 2018 The Dash Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "test/test_dash.h"
|
||||
|
||||
#include "script/interpreter.h"
|
||||
#include "script/standard.h"
|
||||
#include "script/sign.h"
|
||||
#include "validation.h"
|
||||
#include "base58.h"
|
||||
#include "netbase.h"
|
||||
#include "messagesigner.h"
|
||||
#include "keystore.h"
|
||||
#include "spork.h"
|
||||
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/providertx.h"
|
||||
#include "evo/deterministicmns.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
static const CBitcoinAddress payoutAddress ("yRq1Ky1AfFmf597rnotj7QRxsDUKePVWNF");
|
||||
static const std::string payoutKey ("cV3qrPWzDcnhzRMV4MqtTH4LhNPqPo26ZntGvfJhc8nqCi8Ae5xR");
|
||||
|
||||
typedef std::map<COutPoint, std::pair<int, CAmount>> SimpleUTXOMap;
|
||||
|
||||
static SimpleUTXOMap BuildSimpleUtxoMap(const std::vector<CTransaction>& txs)
|
||||
{
|
||||
SimpleUTXOMap utxos;
|
||||
for (size_t i = 0; i < txs.size(); i++) {
|
||||
auto& tx = txs[i];
|
||||
for (size_t j = 0; j < tx.vout.size(); j++) {
|
||||
utxos.emplace(COutPoint(tx.GetHash(), j), std::make_pair((int)i + 1, tx.vout[j].nValue));
|
||||
}
|
||||
}
|
||||
return utxos;
|
||||
}
|
||||
|
||||
static std::vector<COutPoint> SelectUTXOs(SimpleUTXOMap& utoxs, CAmount amount, CAmount& changeRet)
|
||||
{
|
||||
changeRet = 0;
|
||||
|
||||
std::vector<COutPoint> selectedUtxos;
|
||||
CAmount selectedAmount = 0;
|
||||
while (!utoxs.empty()) {
|
||||
bool found = false;
|
||||
for (auto it = utoxs.begin(); it != utoxs.end(); ++it) {
|
||||
if (chainActive.Height() - it->second.first < 101) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
selectedAmount += it->second.second;
|
||||
selectedUtxos.emplace_back(it->first);
|
||||
utoxs.erase(it);
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT(found);
|
||||
if (selectedAmount >= amount) {
|
||||
changeRet = selectedAmount - amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return selectedUtxos;
|
||||
}
|
||||
|
||||
static void FundTransaction(CMutableTransaction& tx, SimpleUTXOMap& utoxs, const CScript& scriptPayout, CAmount amount, const CKey& coinbaseKey)
|
||||
{
|
||||
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
||||
|
||||
CAmount change;
|
||||
auto inputs = SelectUTXOs(utoxs, amount, change);
|
||||
for (size_t i = 0; i < inputs.size(); i++) {
|
||||
tx.vin.emplace_back(CTxIn(inputs[i]));
|
||||
}
|
||||
tx.vout.emplace_back(CTxOut(amount, scriptPayout));
|
||||
if (change != 0) {
|
||||
tx.vout.emplace_back(CTxOut(change, scriptPayout));
|
||||
}
|
||||
}
|
||||
|
||||
static void SignTransaction(CMutableTransaction& tx, const CKey& coinbaseKey)
|
||||
{
|
||||
CBasicKeyStore tempKeystore;
|
||||
tempKeystore.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
|
||||
for (size_t i = 0; i < tx.vin.size(); i++) {
|
||||
CTransactionRef txFrom;
|
||||
uint256 hashBlock;
|
||||
BOOST_ASSERT(GetTransaction(tx.vin[i].prevout.hash, txFrom, Params().GetConsensus(), hashBlock));
|
||||
BOOST_ASSERT(SignSignature(tempKeystore, *txFrom, tx, i));
|
||||
}
|
||||
}
|
||||
|
||||
static CMutableTransaction CreateProRegTx(SimpleUTXOMap& utxos, int port, const CScript& scriptPayout, const CKey& coinbaseKey, CKey& mnKeyRet)
|
||||
{
|
||||
mnKeyRet.MakeNewKey(true);
|
||||
|
||||
CAmount change;
|
||||
auto inputs = SelectUTXOs(utxos, 1000 * COIN, change);
|
||||
|
||||
CProRegTx proTx;
|
||||
proTx.nProtocolVersion = PROTOCOL_VERSION;
|
||||
proTx.nCollateralIndex = 0;
|
||||
proTx.addr = LookupNumeric("1.1.1.1", port);
|
||||
proTx.keyIDOwner = mnKeyRet.GetPubKey().GetID();
|
||||
proTx.keyIDOperator = mnKeyRet.GetPubKey().GetID();
|
||||
proTx.keyIDVoting = mnKeyRet.GetPubKey().GetID();
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 3;
|
||||
tx.nType = TRANSACTION_PROVIDER_REGISTER;
|
||||
FundTransaction(tx, utxos, scriptPayout, 1000 * COIN, coinbaseKey);
|
||||
proTx.inputsHash = CalcTxInputsHash(tx);
|
||||
CHashSigner::SignHash(::SerializeHash(proTx), mnKeyRet, proTx.vchSig);
|
||||
SetTxPayload(tx, proTx);
|
||||
SignTransaction(tx, coinbaseKey);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
static CMutableTransaction CreateProUpServTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CKey& mnKey, int port, const CScript& scriptOperatorPayout, const CKey& coinbaseKey)
|
||||
{
|
||||
CAmount change;
|
||||
auto inputs = SelectUTXOs(utxos, 1 * COIN, change);
|
||||
|
||||
CProUpServTx proTx;
|
||||
proTx.proTxHash = proTxHash;
|
||||
proTx.nProtocolVersion = PROTOCOL_VERSION;
|
||||
proTx.addr = LookupNumeric("1.1.1.1", port);
|
||||
proTx.scriptOperatorPayout = scriptOperatorPayout;
|
||||
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 3;
|
||||
tx.nType = TRANSACTION_PROVIDER_UPDATE_SERVICE;
|
||||
FundTransaction(tx, utxos, GetScriptForDestination(coinbaseKey.GetPubKey().GetID()), 1 * COIN, coinbaseKey);
|
||||
proTx.inputsHash = CalcTxInputsHash(tx);
|
||||
CHashSigner::SignHash(::SerializeHash(proTx), mnKey, proTx.vchSig);
|
||||
SetTxPayload(tx, proTx);
|
||||
SignTransaction(tx, coinbaseKey);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
static CMutableTransaction CreateProUpRegTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CKey& mnKey, const CKeyID& keyIDOperator, const CKeyID& keyIDVoting, const CScript& scriptPayout, const CKey& coinbaseKey)
|
||||
{
|
||||
CAmount change;
|
||||
auto inputs = SelectUTXOs(utxos, 1 * COIN, change);
|
||||
|
||||
CProUpRegTx proTx;
|
||||
proTx.proTxHash = proTxHash;
|
||||
proTx.keyIDOperator = keyIDOperator;
|
||||
proTx.keyIDVoting = keyIDVoting;
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 3;
|
||||
tx.nType = TRANSACTION_PROVIDER_UPDATE_REGISTRAR;
|
||||
FundTransaction(tx, utxos, GetScriptForDestination(coinbaseKey.GetPubKey().GetID()), 1 * COIN, coinbaseKey);
|
||||
proTx.inputsHash = CalcTxInputsHash(tx);
|
||||
CHashSigner::SignHash(::SerializeHash(proTx), mnKey, proTx.vchSig);
|
||||
SetTxPayload(tx, proTx);
|
||||
SignTransaction(tx, coinbaseKey);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
static CMutableTransaction CreateProUpRevTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CKey& mnKey, const CKey& coinbaseKey)
|
||||
{
|
||||
CAmount change;
|
||||
auto inputs = SelectUTXOs(utxos, 1 * COIN, change);
|
||||
|
||||
CProUpRevTx proTx;
|
||||
proTx.proTxHash = proTxHash;
|
||||
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 3;
|
||||
tx.nType = TRANSACTION_PROVIDER_UPDATE_REVOKE;
|
||||
FundTransaction(tx, utxos, GetScriptForDestination(coinbaseKey.GetPubKey().GetID()), 1 * COIN, coinbaseKey);
|
||||
proTx.inputsHash = CalcTxInputsHash(tx);
|
||||
CHashSigner::SignHash(::SerializeHash(proTx), mnKey, proTx.vchSig);
|
||||
SetTxPayload(tx, proTx);
|
||||
SignTransaction(tx, coinbaseKey);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
static CScript GenerateRandomAddress()
|
||||
{
|
||||
CKey key;
|
||||
key.MakeNewKey(false);
|
||||
return GetScriptForDestination(key.GetPubKey().GetID());
|
||||
}
|
||||
|
||||
static CDeterministicMNCPtr FindPayoutDmn(const CBlock& block)
|
||||
{
|
||||
auto dmnList = deterministicMNManager->GetListAtChainTip();
|
||||
|
||||
for (auto txout : block.vtx[0]->vout) {
|
||||
for (auto& dmn : dmnList.valid_range()) {
|
||||
if (txout.scriptPubKey == dmn->pdmnState->scriptPayout) {
|
||||
return dmn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(evo_dip3_activation_tests)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(dip3_activation, TestChainDIP3BeforeActivationSetup)
|
||||
{
|
||||
auto utxos = BuildSimpleUtxoMap(coinbaseTxns);
|
||||
CKey mnKey;
|
||||
auto tx = CreateProRegTx(utxos, 1, GetScriptForDestination(payoutAddress.Get()), coinbaseKey, mnKey);
|
||||
std::vector<CMutableTransaction> txns = {tx};
|
||||
|
||||
int nHeight = chainActive.Height();
|
||||
|
||||
// We start one block before DIP3 activation, so mining a block with a DIP3 transaction should fail
|
||||
auto block = std::make_shared<CBlock>(CreateBlock(txns, coinbaseKey));
|
||||
ProcessNewBlock(Params(), block, true, nullptr);
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight);
|
||||
BOOST_ASSERT(block->GetHash() != chainActive.Tip()->GetBlockHash());
|
||||
BOOST_ASSERT(!deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
|
||||
|
||||
// This block should activate DIP3
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
|
||||
|
||||
// Mining a block with a DIP3 transaction should succeed now
|
||||
block = std::make_shared<CBlock>(CreateBlock(txns, coinbaseKey));
|
||||
ProcessNewBlock(Params(), block, true, nullptr);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight + 2);
|
||||
BOOST_ASSERT(block->GetHash() == chainActive.Tip()->GetBlockHash());
|
||||
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup)
|
||||
{
|
||||
CKey sporkKey;
|
||||
sporkKey.MakeNewKey(false);
|
||||
CBitcoinSecret sporkSecret(sporkKey);
|
||||
CBitcoinAddress sporkAddress;
|
||||
sporkAddress.Set(sporkKey.GetPubKey().GetID());
|
||||
sporkManager.SetSporkAddress(sporkAddress.ToString());
|
||||
sporkManager.SetPrivKey(sporkSecret.ToString());
|
||||
|
||||
auto utxos = BuildSimpleUtxoMap(coinbaseTxns);
|
||||
|
||||
int nHeight = chainActive.Height();
|
||||
int port = 1;
|
||||
|
||||
std::vector<uint256> dmnHashes;
|
||||
std::map<uint256, CKey> mnKeys;
|
||||
|
||||
// register one MN per block
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
CKey mnKey;
|
||||
auto tx = CreateProRegTx(utxos, port++, GenerateRandomAddress(), coinbaseKey, mnKey);
|
||||
dmnHashes.emplace_back(tx.GetHash());
|
||||
mnKeys.emplace(tx.GetHash(), mnKey);
|
||||
CreateAndProcessBlock({tx}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
|
||||
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
|
||||
|
||||
nHeight++;
|
||||
}
|
||||
|
||||
// activate spork15
|
||||
sporkManager.UpdateSpork(SPORK_15_DETERMINISTIC_MNS_ENABLED, chainActive.Height() + 1, *g_connman);
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
nHeight++;
|
||||
|
||||
// check MN reward payments
|
||||
for (size_t i = 0; i < 20; i++) {
|
||||
auto dmnExpectedPayee = deterministicMNManager->GetListAtChainTip().GetMNPayee();
|
||||
|
||||
CBlock block = CreateAndProcessBlock({}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(!block.vtx.empty());
|
||||
|
||||
auto dmnPayout = FindPayoutDmn(block);
|
||||
BOOST_ASSERT(dmnPayout != nullptr);
|
||||
BOOST_CHECK_EQUAL(dmnPayout->proTxHash.ToString(), dmnExpectedPayee->proTxHash.ToString());
|
||||
|
||||
nHeight++;
|
||||
}
|
||||
|
||||
// register multiple MNs per block
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
std::vector<CMutableTransaction> txns;
|
||||
for (size_t j = 0; j < 3; j++) {
|
||||
CKey mnKey;
|
||||
auto tx = CreateProRegTx(utxos, port++, GenerateRandomAddress(), coinbaseKey, mnKey);
|
||||
dmnHashes.emplace_back(tx.GetHash());
|
||||
mnKeys.emplace(tx.GetHash(), mnKey);
|
||||
txns.emplace_back(tx);
|
||||
}
|
||||
CreateAndProcessBlock(txns, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
|
||||
|
||||
for (size_t j = 0; j < 3; j++) {
|
||||
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(txns[j].GetHash()));
|
||||
}
|
||||
|
||||
nHeight++;
|
||||
}
|
||||
|
||||
// test ProUpServTx
|
||||
auto tx = CreateProUpServTx(utxos, dmnHashes[0], mnKeys[dmnHashes[0]], 1000, CScript(), coinbaseKey);
|
||||
CreateAndProcessBlock({tx}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
|
||||
nHeight++;
|
||||
|
||||
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(dmnHashes[0]);
|
||||
BOOST_ASSERT(dmn != nullptr && dmn->pdmnState->addr.GetPort() == 1000);
|
||||
|
||||
// test ProUpRevTx
|
||||
tx = CreateProUpRevTx(utxos, dmnHashes[0], mnKeys[dmnHashes[0]], coinbaseKey);
|
||||
CreateAndProcessBlock({tx}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
|
||||
nHeight++;
|
||||
|
||||
dmn = deterministicMNManager->GetListAtChainTip().GetMN(dmnHashes[0]);
|
||||
BOOST_ASSERT(dmn != nullptr && dmn->pdmnState->nPoSeBanHeight == nHeight);
|
||||
|
||||
// test that the revoked MN does not get paid anymore
|
||||
for (size_t i = 0; i < 20; i++) {
|
||||
auto dmnExpectedPayee = deterministicMNManager->GetListAtChainTip().GetMNPayee();
|
||||
BOOST_ASSERT(dmnExpectedPayee->proTxHash != dmnHashes[0]);
|
||||
|
||||
CBlock block = CreateAndProcessBlock({}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(!block.vtx.empty());
|
||||
|
||||
auto dmnPayout = FindPayoutDmn(block);
|
||||
BOOST_ASSERT(dmnPayout != nullptr);
|
||||
BOOST_CHECK_EQUAL(dmnPayout->proTxHash.ToString(), dmnExpectedPayee->proTxHash.ToString());
|
||||
|
||||
nHeight++;
|
||||
}
|
||||
|
||||
// test reviving the MN
|
||||
CKey newOperatorKey;
|
||||
newOperatorKey.MakeNewKey(false);
|
||||
dmn = deterministicMNManager->GetListAtChainTip().GetMN(dmnHashes[0]);
|
||||
tx = CreateProUpRegTx(utxos, dmnHashes[0], mnKeys[dmnHashes[0]], newOperatorKey.GetPubKey().GetID(), newOperatorKey.GetPubKey().GetID(), dmn->pdmnState->scriptPayout, coinbaseKey);
|
||||
CreateAndProcessBlock({tx}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
|
||||
nHeight++;
|
||||
|
||||
tx = CreateProUpServTx(utxos, dmnHashes[0], newOperatorKey, 100, CScript(), coinbaseKey);
|
||||
CreateAndProcessBlock({tx}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
|
||||
nHeight++;
|
||||
|
||||
dmn = deterministicMNManager->GetListAtChainTip().GetMN(dmnHashes[0]);
|
||||
BOOST_ASSERT(dmn != nullptr && dmn->pdmnState->addr.GetPort() == 100);
|
||||
BOOST_ASSERT(dmn != nullptr && dmn->pdmnState->nPoSeBanHeight == -1);
|
||||
|
||||
// test that the revived MN gets payments again
|
||||
bool foundRevived = false;
|
||||
for (size_t i = 0; i < 20; i++) {
|
||||
auto dmnExpectedPayee = deterministicMNManager->GetListAtChainTip().GetMNPayee();
|
||||
if (dmnExpectedPayee->proTxHash == dmnHashes[0]) {
|
||||
foundRevived = true;
|
||||
}
|
||||
|
||||
CBlock block = CreateAndProcessBlock({}, coinbaseKey);
|
||||
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
|
||||
BOOST_ASSERT(!block.vtx.empty());
|
||||
|
||||
auto dmnPayout = FindPayoutDmn(block);
|
||||
BOOST_ASSERT(dmnPayout != nullptr);
|
||||
BOOST_CHECK_EQUAL(dmnPayout->proTxHash.ToString(), dmnExpectedPayee->proTxHash.ToString());
|
||||
|
||||
nHeight++;
|
||||
}
|
||||
BOOST_ASSERT(foundRevived);
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
64
src/test/evo_simplifiedmns_tests.cpp
Normal file
64
src/test/evo_simplifiedmns_tests.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2018 The Dash Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "test/test_dash.h"
|
||||
|
||||
#include "evo/simplifiedmns.h"
|
||||
#include "netbase.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(evo_simplifiedmns_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(simplifiedmns_merkleroots)
|
||||
{
|
||||
std::vector<CSimplifiedMNListEntry> entries;
|
||||
for (size_t i = 0; i < 15; i++) {
|
||||
CSimplifiedMNListEntry smle;
|
||||
smle.proRegTxHash.SetHex(strprintf("%064x", i));
|
||||
|
||||
std::string ip = strprintf("%d.%d.%d.%d", 0, 0, 0, i);
|
||||
Lookup(ip.c_str(), smle.service, i, false);
|
||||
|
||||
smle.keyIDOperator.SetHex(strprintf("%040x", i));
|
||||
smle.keyIDVoting.SetHex(strprintf("%040x", i));
|
||||
smle.isValid = true;
|
||||
|
||||
entries.emplace_back(smle);
|
||||
}
|
||||
|
||||
std::vector<std::string> expectedHashes = {
|
||||
"aa8bfb825f433bcd6f1039f27c77ed269386e05577b0fe9afc4e16b1af0076b2",
|
||||
"686a19dba9b515f77f11027cd1e92e6a8c650448bf4616101fd5ddbe6e2629e7",
|
||||
"c2efc1b08daa791c71e1d5887be3eaa136381f783fcc5b7efdc5909db38701bb",
|
||||
"ce394197d6e1684467fbf2e1619f71ae9d1a6cf6548b2235e4289f95d4bccbbd",
|
||||
"aeeaf7b498aa7d5fa92ee0028499b4f165c31662f5e9b0a80e6e13b38fd61f8d",
|
||||
"0c1c8dc9dc82eb5432a557580e5d3d930943ce0d0db5daebc51267afb46b6d48",
|
||||
"1c4add10ea844a46734473e48c2f781059b35382219d0cf67d6432b540e0bbbe",
|
||||
"1ae1ad5ff4dd4c09469d21d569a025d467dca1e407581a2815175528e139b7da",
|
||||
"d59b231cdc80ce7eda3a3f37608abda818659c189d31a7ef42024d496e290cbc",
|
||||
"2d5e6c87e3d4e5b3fdd600f561e8dec1ea720560569398006050480232f1257c",
|
||||
"3d6af35f08efeea22f3c8fcb78038e56dac221f3173ca4e2230ea8ae3cbd3c60",
|
||||
"ecf547077c37b79da954c4ef46a3c4fb136746366bfb81192ed01de96fd66348",
|
||||
"626af5fb8192ead7bbd79ad7bfe2c3ea82714fdfd9ac49b88d7a411aa6956853",
|
||||
"6c84a4485fb2ba35b4dcd4d89cbdd3d813446514bb7a2046b6b1b9813beaac0f",
|
||||
"453ca2a83140da73a37794fe6fddd701ea5066f21c2f1df8a33b6ff6134043c3",
|
||||
};
|
||||
std::vector<std::string> calculatedHashes;
|
||||
|
||||
for (auto& smle : entries) {
|
||||
calculatedHashes.emplace_back(smle.CalcHash().ToString());
|
||||
//printf("\"%s\",\n", calculatedHashes.back().c_str());
|
||||
}
|
||||
|
||||
BOOST_CHECK(expectedHashes == calculatedHashes);
|
||||
|
||||
CSimplifiedMNList sml(entries);
|
||||
|
||||
std::string expectedMerkleRoot = "926efc8dc7b5b060254b102670b918133fea67c5e1bc2703d596e49672878c22";
|
||||
std::string calculatedMerkleRoot = sml.CalcMerkleRoot(nullptr).ToString();
|
||||
|
||||
BOOST_CHECK(expectedMerkleRoot == calculatedMerkleRoot);
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
@ -24,7 +24,9 @@
|
||||
|
||||
#include "test/testutil.h"
|
||||
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/deterministicmns.h"
|
||||
#include "evo/cbtx.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -100,12 +102,12 @@ TestingSetup::~TestingSetup()
|
||||
boost::filesystem::remove_all(pathTemp);
|
||||
}
|
||||
|
||||
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
|
||||
TestChainSetup::TestChainSetup(int blockCount) : TestingSetup(CBaseChainParams::REGTEST)
|
||||
{
|
||||
// Generate a 100-block chain:
|
||||
coinbaseKey.MakeNewKey(true);
|
||||
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
||||
for (int i = 0; i < COINBASE_MATURITY; i++)
|
||||
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
||||
for (int i = 0; i < blockCount; i++)
|
||||
{
|
||||
std::vector<CMutableTransaction> noTxns;
|
||||
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
|
||||
@ -118,7 +120,25 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
|
||||
// scriptPubKey, and try to add it to the current chain.
|
||||
//
|
||||
CBlock
|
||||
TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
|
||||
TestChainSetup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
auto block = CreateBlock(txns, scriptPubKey);
|
||||
|
||||
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
|
||||
ProcessNewBlock(chainparams, shared_pblock, true, NULL);
|
||||
|
||||
CBlock result = block;
|
||||
return result;
|
||||
}
|
||||
|
||||
CBlock TestChainSetup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CKey& scriptKey)
|
||||
{
|
||||
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
||||
return CreateAndProcessBlock(txns, scriptPubKey);
|
||||
}
|
||||
|
||||
CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
|
||||
@ -128,20 +148,39 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
|
||||
block.vtx.resize(1);
|
||||
BOOST_FOREACH(const CMutableTransaction& tx, txns)
|
||||
block.vtx.push_back(MakeTransactionRef(tx));
|
||||
|
||||
// Manually update CbTx as we modified the block here
|
||||
if (block.vtx[0]->nType == TRANSACTION_COINBASE) {
|
||||
CCbTx cbTx;
|
||||
if (!GetTxPayload(*block.vtx[0], cbTx)) {
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
CValidationState state;
|
||||
if (!CalcCbTxMerkleRootMNList(block, chainActive.Tip(), cbTx.merkleRootMNList, state)) {
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
CMutableTransaction tmpTx = *block.vtx[0];
|
||||
SetTxPayload(tmpTx, cbTx);
|
||||
block.vtx[0] = MakeTransactionRef(tmpTx);
|
||||
}
|
||||
|
||||
// IncrementExtraNonce creates a valid coinbase and merkleRoot
|
||||
unsigned int extraNonce = 0;
|
||||
IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
|
||||
|
||||
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
|
||||
|
||||
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
|
||||
ProcessNewBlock(chainparams, shared_pblock, true, NULL);
|
||||
|
||||
CBlock result = block;
|
||||
return result;
|
||||
}
|
||||
|
||||
TestChain100Setup::~TestChain100Setup()
|
||||
CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns, const CKey& scriptKey)
|
||||
{
|
||||
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
||||
return CreateBlock(txns, scriptPubKey);
|
||||
}
|
||||
|
||||
TestChainSetup::~TestChainSetup()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -43,24 +43,44 @@ class CBlock;
|
||||
struct CMutableTransaction;
|
||||
class CScript;
|
||||
|
||||
//
|
||||
// Testing fixture that pre-creates a
|
||||
// 100-block REGTEST-mode block chain
|
||||
//
|
||||
struct TestChain100Setup : public TestingSetup {
|
||||
TestChain100Setup();
|
||||
struct TestChainSetup : public TestingSetup
|
||||
{
|
||||
TestChainSetup(int blockCount);
|
||||
~TestChainSetup();
|
||||
|
||||
// Create a new block with just given transactions, coinbase paying to
|
||||
// scriptPubKey, and try to add it to the current chain.
|
||||
CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns,
|
||||
const CScript& scriptPubKey);
|
||||
|
||||
~TestChain100Setup();
|
||||
CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns,
|
||||
const CKey& scriptKey);
|
||||
CBlock CreateBlock(const std::vector<CMutableTransaction>& txns,
|
||||
const CScript& scriptPubKey);
|
||||
CBlock CreateBlock(const std::vector<CMutableTransaction>& txns,
|
||||
const CKey& scriptKey);
|
||||
|
||||
std::vector<CTransaction> coinbaseTxns; // For convenience, coinbase transactions
|
||||
CKey coinbaseKey; // private/public key needed to spend coinbase transactions
|
||||
};
|
||||
|
||||
//
|
||||
// Testing fixture that pre-creates a
|
||||
// 100-block REGTEST-mode block chain
|
||||
//
|
||||
struct TestChain100Setup : public TestChainSetup {
|
||||
TestChain100Setup() : TestChainSetup(100) {}
|
||||
};
|
||||
|
||||
struct TestChainDIP3Setup : public TestChainSetup
|
||||
{
|
||||
TestChainDIP3Setup() : TestChainSetup(431) {}
|
||||
};
|
||||
|
||||
struct TestChainDIP3BeforeActivationSetup : public TestChainSetup
|
||||
{
|
||||
TestChainDIP3BeforeActivationSetup() : TestChainSetup(430) {}
|
||||
};
|
||||
|
||||
class CTxMemPoolEntry;
|
||||
class CTxMemPool;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user