Skip to content

Commit

Permalink
5.2.2.0, 2021-03-14, leisure
Browse files Browse the repository at this point in the history
Fixed
- beacon, contracts: Fix sync from zero issue due to ApplyContracts problem in 5.2.1.0 #2047 (@jamescowens)
  • Loading branch information
jamescowens committed Mar 14, 2021
2 parents 90d00b6 + 174f5dd commit 50b3067
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 65 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [5.2.2.0] 2021-03-14, leisure
### Fixed
- beacon, contracts: Fix sync from zero issue due to ApplyContracts problem in 5.2.1.0 #2047 (@jamescowens)

## [5.2.1.0] 2021-03-07, leisure
### Added
- voting: Add wait warning to voting tab loading message #2039 (@cyrossignol)
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 5)
define(_CLIENT_VERSION_MINOR, 2)
define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_REVISION, 2)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2021)
Expand Down
115 changes: 84 additions & 31 deletions src/gridcoin/beacon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,9 @@ bool BeaconRegistry::TryRenewal(Beacon_ptr& current_beacon_ptr, int& height, con
// Put the renewal beacon into the db.
if (!m_beacon_db.insert(renewal.m_hash, height, renewal))
{
LogPrint(LogFlags::BEACON, "WARNING: %s: In renewal of beacon for cpid %s, address %s, hash %s, beacon db record "
"already exists.",
LogPrint(LogFlags::BEACON, "INFO: %s: In renewal of beacon for cpid %s, address %s, hash %s, beacon db record "
"already exists. This can be expected on a restart of the wallet to ensure multiple "
"contracts in the same block get stored/replayed.",
__func__,
renewal.m_cpid.ToString(),
renewal.GetAddress().ToString(),
Expand Down Expand Up @@ -435,7 +436,16 @@ void BeaconRegistry::Add(const ContractContext& ctx)
historical.m_cpid = payload.m_cpid;
historical.m_status = BeaconStatusForStorage::ACTIVE;

m_beacon_db.insert(ctx.m_tx.GetHash(), height, historical);
if (!m_beacon_db.insert(ctx.m_tx.GetHash(), height, historical))
{
LogPrint(LogFlags::BEACON, "INFO: %s: In activation of v1 beacon for cpid %s, address %s, hash %s, beacon db record "
"already exists. This can be expected on a restart of the wallet to ensure multiple "
"contracts in the same block get stored/replayed.",
__func__,
historical.m_cpid.ToString(),
historical.GetAddress().ToString(),
historical.m_hash.GetHex());
}
m_beacons[payload.m_cpid] = std::make_shared<Beacon>(m_beacon_db[ctx.m_tx.GetHash()]);
return;
}
Expand All @@ -458,7 +468,16 @@ void BeaconRegistry::Add(const ContractContext& ctx)
pending.m_status = BeaconStatusForStorage::PENDING;

// Insert the entry into the db.
m_beacon_db.insert(ctx.m_tx.GetHash(), height, static_cast<Beacon>(pending));
if (!m_beacon_db.insert(ctx.m_tx.GetHash(), height, static_cast<Beacon>(pending)))
{
LogPrint(LogFlags::BEACON, "INFO: %s: In advertisement of beacon for cpid %s, address %s, hash %s, beacon db record "
"already exists. This can be expected on a restart of the wallet to ensure multiple "
"contracts in the same block get stored/replayed.",
__func__,
pending.m_cpid.ToString(),
pending.GetAddress().ToString(),
pending.m_hash.GetHex());
}

// Insert a pointer to the entry in the m_pending map.
m_pending[pending.GetId()] = std::make_shared<Beacon>(m_beacon_db[ctx.m_tx.GetHash()]);
Expand Down Expand Up @@ -723,6 +742,16 @@ int BeaconRegistry::GetDBHeight()
return height;
}

bool BeaconRegistry::NeedsIsContractCorrection()
{
return m_beacon_db.NeedsIsContractCorrection();
}

bool BeaconRegistry::SetNeedsIsContractCorrection(bool flag)
{
return m_beacon_db.SetNeedsIsContractCorrection(flag);
}

bool BeaconRegistry::Validate(const Contract& contract, const CTransaction& tx) const
{
if (contract.m_version <= 1) {
Expand Down Expand Up @@ -998,6 +1027,7 @@ int BeaconRegistry::BeaconDB::Initialize(PendingBeaconMap& m_pending, BeaconMap&
bool status = true;
int height = 0;
uint32_t version = 0;
bool needs_IsContract_correction = false;

// First load the beacon db version from leveldb and check it against the constant in the class.
{
Expand All @@ -1019,8 +1049,22 @@ int BeaconRegistry::BeaconDB::Initialize(PendingBeaconMap& m_pending, BeaconMap&
version,
CURRENT_VERSION);

// Version 1, which corresponds to the 5.2.1.0 release contained a bug in ApplyContracts which prevented the
// application of multiple beacon contracts contained in a block under certain circumstances. In particular,
// the case with superblock 2053368, which contained beacon activations AND two beacon contracts was affected
// and once recorded in CBlockIndex, IsContract() returns the incorrect value. This flag will be used by
// ApplyContracts to check every block during the ContractReplay to correct the situation.
if (version == 1)
{
needs_IsContract_correction = true;
}

clear_leveldb();

// After clearing the leveldb state, set the needs IsContract correction to the proper state. If the version that
// was on disk was 1, then this will be set to true.
SetNeedsIsContractCorrection(needs_IsContract_correction);

LogPrint(LogFlags::BEACON, "INFO: %s: Leveldb beacon area cleared. Version level set to %u.",
__func__,
CURRENT_VERSION);
Expand All @@ -1038,6 +1082,21 @@ int BeaconRegistry::BeaconDB::Initialize(PendingBeaconMap& m_pending, BeaconMap&
// Set m_database_init to true. This will cause LoadDBHeight hereinafter to simply report
// the value of m_height_stored rather than loading the stored height from leveldb.
m_database_init = true;

// We are in a restart where at least some of a rescan was completed during a prior run. It is possible
// that the rescan may have not been completed before a shutdown was issued. In that case the
// needs_IsContract_correction flag will be set to true in leveldb, so restore that state for this run
// to ensure the correction finishes. When ReplayContracts finishes the corrections, it will mark the flag
// false.
CTxDB txdb("r");

std::pair<std::string, std::string> key = std::make_pair("beacon_db", "needs_IsContract_correction");

bool status = txdb.ReadGenericSerializable(key, needs_IsContract_correction);

if (!status) needs_IsContract_correction = false;

m_needs_IsContract_correction = needs_IsContract_correction;
}

LogPrint(LogFlags::BEACON, "INFO: %s: db stored height at block %i.",
Expand Down Expand Up @@ -1246,6 +1305,7 @@ bool BeaconRegistry::BeaconDB::clear_leveldb()
m_height_stored = 0;
m_recnum_stored = 0;
m_database_init = false;
m_needs_IsContract_correction = false;

return status;
}
Expand All @@ -1262,6 +1322,24 @@ size_t BeaconRegistry::BeaconDB::size()
return m_historical.size();
}

bool BeaconRegistry::BeaconDB::NeedsIsContractCorrection()
{
return m_needs_IsContract_correction;
}

bool BeaconRegistry::BeaconDB::SetNeedsIsContractCorrection(bool flag)
{
// Update the in-memory flag.
m_needs_IsContract_correction = flag;

// Update leveldb
CTxDB txdb("rw");

std::pair<std::string, std::string> key = std::make_pair("beacon_db", "needs_IsContract_correction");

return txdb.WriteGenericSerializable(key, m_needs_IsContract_correction);
}

bool BeaconRegistry::BeaconDB::StoreDBHeight(const int& height_stored)
{
// Update the in-memory bookmark variable.
Expand Down Expand Up @@ -1313,11 +1391,12 @@ bool BeaconRegistry::BeaconDB::insert(const uint256 &hash, const int& height, co
}
else
{
LogPrint(LogFlags::BEACON, "INFO %s - store beacon: cpid %s, address %s, timestamp %" PRId64
LogPrint(LogFlags::BEACON, "INFO %s - store beacon: cpid %s, address %s, height %i, timestamp %" PRId64
", hash %s, prev_beacon_hash %s, status = %u.",
__func__,
beacon.m_cpid.ToString(), // cpid
beacon.GetAddress().ToString(), // address
height, // height
beacon.m_timestamp, // timestamp
beacon.m_hash.GetHex(), // transaction hash
beacon.m_prev_beacon_hash.GetHex(), // prev beacon transaction hash
Expand All @@ -1334,32 +1413,6 @@ bool BeaconRegistry::BeaconDB::insert(const uint256 &hash, const int& height, co
}
}

bool BeaconRegistry::BeaconDB::update(const uint256 &hash, const int& height, const Beacon &beacon)
{
bool status = false;

LogPrint(LogFlags::BEACON, "INFO %s - store beacon: cpid %s, address %s, timestamp %" PRId64
", hash %s, prev_beacon_hash %s, status = %u.",
__func__,
beacon.m_cpid.ToString(), // cpid
beacon.GetAddress().ToString(), // address
beacon.m_timestamp, // timestamp
beacon.m_hash.GetHex(), // transaction hash
beacon.m_prev_beacon_hash.GetHex(), // prev beacon transaction hash
beacon.m_status.Raw() // status
);

// update m_historical entry
m_historical[hash] = beacon;

// update leveldb
status = Store(hash, static_cast<StorageBeacon>(beacon));

if (height) status &= StoreDBHeight(height);

return status;
}

bool BeaconRegistry::BeaconDB::erase(uint256 hash)
{
auto iter = m_historical.find(hash);
Expand Down
53 changes: 36 additions & 17 deletions src/gridcoin/beacon.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,19 @@ class BeaconRegistry : public IContractHandler
//!
void ResetInMemoryOnly();

//!
//! \brief Returns whether IsContract correction is needed in ReplayContracts during initialization
//! \return
//!
bool NeedsIsContractCorrection();

//!
//! \brief Sets the state of the IsContract needs correction flag in memory and leveldb
//! \param flag The state to set
//! \return
//!
bool SetNeedsIsContractCorrection(bool flag);

private:
BeaconMap m_beacons; //!< Contains the active registered beacons.
PendingBeaconMap m_pending; //!< Contains beacons awaiting verification.
Expand All @@ -714,7 +727,11 @@ class BeaconRegistry : public IContractHandler
//! will ensure that when the wallet is restarted, the level db beacon storage will be cleared and
//! reloaded from the contract replay with the correct lookback scope.
//!
static constexpr uint32_t CURRENT_VERSION = 1;
//! Version 0: <= 5.2.0.0
//! Version 1: = 5.2.1.0
//! Version 2: 5.2.1.0 with hotfix and > 5.2.1.0
//!
static constexpr uint32_t CURRENT_VERSION = 2;

//!
//! \brief Initializes the Beacon Registry map structures from the replay of the beacon states stored
Expand Down Expand Up @@ -753,6 +770,19 @@ class BeaconRegistry : public IContractHandler
//!
size_t size();

//!
//! \brief Returns whether IsContract correction is needed in ReplayContracts during initialization
//! \return
//!
bool NeedsIsContractCorrection();

//!
//! \brief Sets the state of the IsContract needs correction flag in memory and leveldb
//! \param flag The state to set
//! \return
//!
bool SetNeedsIsContractCorrection(bool flag);

//!
//! \brief This stores the height to which the database entries are valid (the db scope). Note that it
//! is not desired to expose this function as a public function, but currently the Revert function
Expand Down Expand Up @@ -791,22 +821,6 @@ class BeaconRegistry : public IContractHandler
//!
bool insert(const uint256& hash, const int& height, const Beacon& beacon);

//!
//! \brief Update a beacon state record into the historical database.
//!
//! \param hash The hash for the key to the historical record. (This must be unique. It is usually
//! the transaction hash that of the transaction that contains the beacon contract, but also can be
//! a synthetic hash created from the hash of the superblock hash and the cpid hash if recording
//! beacon activations or expired pendings, which are handled in ActivatePending.
//! \param height The height of the block from which the beacon state record originates.
//! \param beacon The beacon state record to insert (which includes the appropriate status).
//!
//! \return Success or Failure. This is just like insert but it always succeeds (unless there is a
//! problem with the storage layer). If a record already exists it will be replaced. If it is new,
//! it will be inserted.
//!
bool update(const uint256& hash, const int& height, const Beacon& beacon);

//!
//! \brief Erase a record from the database.
//!
Expand Down Expand Up @@ -896,6 +910,11 @@ class BeaconRegistry : public IContractHandler
//!
uint64_t m_recnum_stored = 0;

//!
//! \brief The flag that indicates whether IsContract correction is needed in ReplayContracts during initialization.
//!
bool m_needs_IsContract_correction = false;

//!
//! \brief Store a beacon object in leveldb with the provided key value.
//!
Expand Down
Loading

0 comments on commit 50b3067

Please sign in to comment.