123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- // ECOin - Copyright (c) - 2014/2022 - GPLv3 - epsylon@riseup.net (https://03c8.net)
- #include <boost/assign/list_of.hpp> // for 'map_list_of()'
- #include <boost/foreach.hpp>
- #include "checkpoints.h"
- #include "txdb.h"
- #include "main.h"
- #include "uint256.h"
- namespace Checkpoints
- {
- typedef std::map<int, std::pair<uint256, unsigned int> > MapCheckpoints;
- static MapCheckpoints mapCheckpoints =
- boost::assign::map_list_of
- ( 0, std::make_pair(hashGenesisBlock, 1610833657) )
- ;
- static MapCheckpoints mapCheckpointsTestnet =
- boost::assign::map_list_of
- ( 0, std::make_pair(hashGenesisBlockTestNet, 1610833657) )
- ;
- bool CheckHardened(int nHeight, const uint256& hash)
- {
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
- MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
- if (i == checkpoints.end()) return true;
- return hash == i->second.first;
- }
- int GetTotalBlocksEstimate()
- {
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
- return checkpoints.rbegin()->first;
- }
- int GetLastCheckpointTime()
- {
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
- return checkpoints.rbegin()->second.second;
- }
- CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
- {
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
- BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
- {
- const uint256& hash = i.second.first;
- std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
- if (t != mapBlockIndex.end())
- return t->second;
- }
- return NULL;
- }
- // ecoin: synchronized checkpoint (centrally broadcasted)
- uint256 hashSyncCheckpoint = 0;
- uint256 hashPendingCheckpoint = 0;
- CSyncCheckpoint checkpointMessage;
- CSyncCheckpoint checkpointMessagePending;
- uint256 hashInvalidCheckpoint = 0;
- CCriticalSection cs_hashSyncCheckpoint;
- // ecoin: get last synchronized checkpoint
- CBlockIndex* GetLastSyncCheckpoint()
- {
- LOCK(cs_hashSyncCheckpoint);
- if (!mapBlockIndex.count(hashSyncCheckpoint))
- error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
- else
- return mapBlockIndex[hashSyncCheckpoint];
- return NULL;
- }
- // ecoin: only descendant of current sync-checkpoint is allowed
- bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
- {
- if (!mapBlockIndex.count(hashSyncCheckpoint))
- return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
- if (!mapBlockIndex.count(hashCheckpoint))
- return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str());
- CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint];
- CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint];
- if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight)
- {
- CBlockIndex* pindex = pindexSyncCheckpoint;
- while (pindex->nHeight > pindexCheckpointRecv->nHeight)
- if (!(pindex = pindex->pprev))
- return error("ValidateSyncCheckpoint: pprev null - block index structure failure");
- if (pindex->GetBlockHash() != hashCheckpoint)
- {
- hashInvalidCheckpoint = hashCheckpoint;
- return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
- }
- return false; // ignore older checkpoint
- }
- CBlockIndex* pindex = pindexCheckpointRecv;
- while (pindex->nHeight > pindexSyncCheckpoint->nHeight)
- if (!(pindex = pindex->pprev))
- return error("ValidateSyncCheckpoint: pprev2 null - block index structure failure");
- if (pindex->GetBlockHash() != hashSyncCheckpoint)
- {
- hashInvalidCheckpoint = hashCheckpoint;
- return error("ValidateSyncCheckpoint: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
- }
- return true;
- }
- bool WriteSyncCheckpoint(const uint256& hashCheckpoint)
- {
- CTxDB txdb;
- txdb.TxnBegin();
- if (!txdb.WriteSyncCheckpoint(hashCheckpoint))
- {
- txdb.TxnAbort();
- return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
- }
- if (!txdb.TxnCommit())
- return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
- Checkpoints::hashSyncCheckpoint = hashCheckpoint;
- return true;
- }
- bool AcceptPendingSyncCheckpoint()
- {
- LOCK(cs_hashSyncCheckpoint);
- if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint))
- {
- if (!ValidateSyncCheckpoint(hashPendingCheckpoint))
- {
- hashPendingCheckpoint = 0;
- checkpointMessagePending.SetNull();
- return false;
- }
- CTxDB txdb;
- CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint];
- if (!pindexCheckpoint->IsInMainChain())
- {
- CBlock block;
- if (!block.ReadFromDisk(pindexCheckpoint))
- return error("AcceptPendingSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
- if (!block.SetBestChain(txdb, pindexCheckpoint))
- {
- hashInvalidCheckpoint = hashPendingCheckpoint;
- return error("AcceptPendingSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
- }
- }
- if (!WriteSyncCheckpoint(hashPendingCheckpoint))
- return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
- hashPendingCheckpoint = 0;
- checkpointMessage = checkpointMessagePending;
- checkpointMessagePending.SetNull();
- printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str());
- // relay the checkpoint
- if (!checkpointMessage.IsNull())
- {
- BOOST_FOREACH(CNode* pnode, vNodes)
- checkpointMessage.RelayTo(pnode);
- }
- return true;
- }
- return false;
- }
- // Automatically select a suitable sync-checkpoint
- uint256 AutoSelectSyncCheckpoint()
- {
- const CBlockIndex *pindex = pindexBest;
- // Search backward for a block within max span and maturity window
- while (pindex->pprev && (pindex->GetBlockTime() + CHECKPOINT_MAX_SPAN > pindexBest->GetBlockTime() || pindex->nHeight + 8 > pindexBest->nHeight))
- pindex = pindex->pprev;
- return pindex->GetBlockHash();
- }
- // Check against synchronized checkpoint
- bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev)
- {
- if (fTestNet) return true; // Testnet has no checkpoints
- int nHeight = pindexPrev->nHeight + 1;
- LOCK(cs_hashSyncCheckpoint);
- // sync-checkpoint should always be accepted block
- assert(mapBlockIndex.count(hashSyncCheckpoint));
- const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
- if (nHeight > pindexSync->nHeight)
- {
- // trace back to same height as sync-checkpoint
- const CBlockIndex* pindex = pindexPrev;
- while (pindex->nHeight > pindexSync->nHeight)
- if (!(pindex = pindex->pprev))
- return error("CheckSync: pprev null - block index structure failure");
- if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint)
- return false; // only descendant of sync-checkpoint can pass check
- }
- if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint)
- return false; // same height with sync-checkpoint
- if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
- return false; // lower height than sync-checkpoint
- return true;
- }
- bool WantedByPendingSyncCheckpoint(uint256 hashBlock)
- {
- LOCK(cs_hashSyncCheckpoint);
- if (hashPendingCheckpoint == 0)
- return false;
- if (hashBlock == hashPendingCheckpoint)
- return true;
- if (mapOrphanBlocks.count(hashPendingCheckpoint)
- && hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint]))
- return true;
- return false;
- }
- // ecoin: reset synchronized checkpoint to last hardened checkpoint
- bool ResetSyncCheckpoint()
- {
- LOCK(cs_hashSyncCheckpoint);
- const uint256& hash = mapCheckpoints.rbegin()->second.first;
- if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain())
- {
- // checkpoint block accepted but not yet in main chain
- printf("ResetSyncCheckpoint: SetBestChain to hardened checkpoint %s\n", hash.ToString().c_str());
- CTxDB txdb;
- CBlock block;
- if (!block.ReadFromDisk(mapBlockIndex[hash]))
- return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str());
- if (!block.SetBestChain(txdb, mapBlockIndex[hash]))
- {
- return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str());
- }
- }
- else if(!mapBlockIndex.count(hash))
- {
- // checkpoint block not yet accepted
- hashPendingCheckpoint = hash;
- checkpointMessagePending.SetNull();
- printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str());
- }
- BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
- {
- const uint256& hash = i.second.first;
- if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
- {
- if (!WriteSyncCheckpoint(hash))
- return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str());
- printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str());
- return true;
- }
- }
- return false;
- }
- void AskForPendingSyncCheckpoint(CNode* pfrom)
- {
- LOCK(cs_hashSyncCheckpoint);
- if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint)))
- pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint));
- }
- bool SetCheckpointPrivKey(std::string strPrivKey)
- {
- // Test signing a sync-checkpoint with genesis block
- CSyncCheckpoint checkpoint;
- checkpoint.hashCheckpoint = !fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet;
- CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
- sMsg << (CUnsignedSyncCheckpoint)checkpoint;
- checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
- std::vector<unsigned char> vchPrivKey = ParseHex(strPrivKey);
- CKey key;
- key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
- if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
- return false;
- // Test signing successful, proceed
- CSyncCheckpoint::strMasterPrivKey = strPrivKey;
- return true;
- }
- bool SendSyncCheckpoint(uint256 hashCheckpoint)
- {
- CSyncCheckpoint checkpoint;
- checkpoint.hashCheckpoint = hashCheckpoint;
- CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
- sMsg << (CUnsignedSyncCheckpoint)checkpoint;
- checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
- if (CSyncCheckpoint::strMasterPrivKey.empty())
- return error("SendSyncCheckpoint: Checkpoint master key unavailable.");
- std::vector<unsigned char> vchPrivKey = ParseHex(CSyncCheckpoint::strMasterPrivKey);
- CKey key;
- key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
- if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
- return error("SendSyncCheckpoint: Unable to sign checkpoint, check private key?");
- if(!checkpoint.ProcessSyncCheckpoint(NULL))
- {
- printf("WARNING: SendSyncCheckpoint: Failed to process checkpoint.\n");
- return false;
- }
- // Relay checkpoint
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- checkpoint.RelayTo(pnode);
- }
- return true;
- }
- // Is the sync-checkpoint outside maturity window?
- bool IsMatureSyncCheckpoint()
- {
- LOCK(cs_hashSyncCheckpoint);
- // sync-checkpoint should always be accepted block
- assert(mapBlockIndex.count(hashSyncCheckpoint));
- const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
- return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity ||
- pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime());
- }
- }
- // ecoin: sync-checkpoint master key
- const std::string CSyncCheckpoint::strMasterPubKey = "045d0773e7224ee40c6e69755c0343022b8f125f218a5ec5f6e57b31c00e182e048807d7e66548148795c1dfa4c972b6792ad41efea33111c5fc0d6c86fc0383f1";
- std::string CSyncCheckpoint::strMasterPrivKey = "";
- // ecoin: verify signature of sync-checkpoint message
- bool CSyncCheckpoint::CheckSignature()
- {
- CKey key;
- if (!key.SetPubKey(ParseHex(CSyncCheckpoint::strMasterPubKey)))
- return error("CSyncCheckpoint::CheckSignature() : SetPubKey failed");
- if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
- return error("CSyncCheckpoint::CheckSignature() : verify signature failed");
- // Now unserialize the data
- CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
- sMsg >> *(CUnsignedSyncCheckpoint*)this;
- return true;
- }
- // ecoin: process synchronized checkpoint
- bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom)
- {
- if (!CheckSignature())
- return false;
- LOCK(Checkpoints::cs_hashSyncCheckpoint);
- if (!mapBlockIndex.count(hashCheckpoint))
- {
- // We haven't received the checkpoint chain, keep the checkpoint as pending
- Checkpoints::hashPendingCheckpoint = hashCheckpoint;
- Checkpoints::checkpointMessagePending = *this;
- printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str());
- // Ask this guy to fill in what we're missing
- if (pfrom)
- {
- pfrom->PushGetBlocks(pindexBest, hashCheckpoint);
- // ask directly as well in case rejected earlier by duplicate
- // proof-of-stake because getblocks may not get it this time
- pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
- }
- return false;
- }
- if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint))
- return false;
- CTxDB txdb;
- CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint];
- if (!pindexCheckpoint->IsInMainChain())
- {
- // checkpoint chain received but not yet main chain
- CBlock block;
- if (!block.ReadFromDisk(pindexCheckpoint))
- return error("ProcessSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
- if (!block.SetBestChain(txdb, pindexCheckpoint))
- {
- Checkpoints::hashInvalidCheckpoint = hashCheckpoint;
- return error("ProcessSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
- }
- }
- if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint))
- return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str());
- Checkpoints::checkpointMessage = *this;
- Checkpoints::hashPendingCheckpoint = 0;
- Checkpoints::checkpointMessagePending.SetNull();
- printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str());
- return true;
- }
|