Skip to content

Commit

Permalink
Add interrupt-block, stop-block, refactor stats, explicit validity ch…
Browse files Browse the repository at this point in the history
…ecks (#1261)

* Token Lock

* Token Split

* Fix setting ATTRIBUTES by Gov height

* Move loan and collateral token to Gov var

* Move FCR to GW

* tests: remove redundant line

* Set time in attrs when applying by height

* Token split support multiple pool and pool created in the block

* Migrate all keys on token split

* Do not fail when vault has interest but no loan tokens

* Return false on error from get internal price

* tests: Update error text

* Add SetValue and EraseKey to attrs

* Add interrupt-block, refactor stats, explicit validity checks

* Add interrupt block to lint

* Add stop-block, refactor logic, fix lints

* Swap order of stop and interrupt

* Update init.cpp

Co-authored-by: Bushstar <[email protected]>
  • Loading branch information
prasannavl and Bushstar authored May 23, 2022
1 parent b012e65 commit f42eb25
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 67 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ src/univalue/gen
Makefile
!depends/Makefile
background.tiff*
configure~

# Qt Creator
Makefile.am.user
Expand Down
37 changes: 34 additions & 3 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ void SetupServerArgs()

// Hidden Options
std::vector<std::string> hidden_args = {
"-dbcrashratio", "-forcecompactdb",
"-dbcrashratio", "-forcecompactdb", "-interrupt-block=<hash|height>", "-stop-block=<hash|height>",
// GUI args. These will be overwritten by SetupUIArgs for the GUI
"-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-splash"};

Expand Down Expand Up @@ -809,6 +809,8 @@ static bool InitSanityCheck()

static bool AppInitServers()
{
if (!gArgs.GetBoolArg("-rpcstats", DEFAULT_RPC_STATS))
statsRPC.setActive(false);
RPCServer::OnStarted(&OnRPCStarted);
RPCServer::OnStopped(&OnRPCStopped);
if (!InitHTTPServer())
Expand Down Expand Up @@ -1285,6 +1287,34 @@ void SetupAnchorSPVDatabases(bool resync) {
}
}

bool SetupInterruptArg(const std::string &argName, std::string &hashStore, int &heightStore) {
// Experimental: Block height or hash to invalidate on and stop sync
auto val = gArgs.GetArg(argName, "");
auto flagName = argName.substr(1);
if (val.empty())
return false;
if (val.size() == 64) {
hashStore = val;
LogPrintf("flag: %s hash: %s\n", flagName, hashStore);
} else {
std::stringstream ss(val);
ss >> heightStore;
if (heightStore) {
LogPrintf("flag: %s height: %d\n", flagName, heightStore);
} else {
LogPrintf("%s: invalid hash or height provided: %s\n", flagName, val);
}
}
return true;
}

void SetupInterrupts() {
auto isSet = false;
isSet = SetupInterruptArg("-interrupt-block", fInterruptBlockHash, fInterruptBlockHeight) || isSet;
isSet = SetupInterruptArg("-stop-block", fStopBlockHash, fStopBlockHeight) || isSet;
fStopOrInterrupt = isSet;
}

bool AppInitMain(InitInterfaces& interfaces)
{
const CChainParams& chainparams = Params();
Expand Down Expand Up @@ -1500,6 +1530,9 @@ bool AppInitMain(InitInterfaces& interfaces)
nMaxOutboundLimit = gArgs.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024;
}

// Setup interrupts
SetupInterrupts();

// ********************************************************* Step 7: load block chain

fReindex = gArgs.GetBoolArg("-reindex", false);
Expand Down Expand Up @@ -2069,7 +2102,5 @@ bool AppInitMain(InitInterfaces& interfaces)
));
}

if (!gArgs.GetBoolArg("-rpcstats", DEFAULT_RPC_STATS)) statsRPC.setActive(false);

return true;
}
31 changes: 24 additions & 7 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4239,21 +4239,38 @@ Res SwapToDFIOverUSD(CCustomCSView & mnview, DCT_ID tokenId, CAmount amount, CS
bool IsVaultPriceValid(CCustomCSView& mnview, const CVaultId& vaultId, uint32_t height)
{
if (auto collaterals = mnview.GetVaultCollaterals(vaultId))
for (const auto& collateral : collaterals->balances)
if (auto collateralToken = mnview.HasLoanCollateralToken({collateral.first, height}))
if (auto fixedIntervalPrice = mnview.GetFixedIntervalPrice(collateralToken->fixedIntervalPriceId))
if (!fixedIntervalPrice.val->isLive(mnview.GetPriceDeviation()))
for (const auto& collateral : collaterals->balances) {
if (auto collateralToken = mnview.HasLoanCollateralToken({collateral.first, height})) {
if (auto fixedIntervalPrice = mnview.GetFixedIntervalPrice(collateralToken->fixedIntervalPriceId)) {
if (!fixedIntervalPrice.val->isLive(mnview.GetPriceDeviation())) {
return false;
}
} else {
// No fixed interval prices available. Should not have happened.
return false;
}
} else {
// Not a collateral token. Should not have happened.
return false;
}
}

if (auto loans = mnview.GetLoanTokens(vaultId))
for (const auto& loan : loans->balances)
if (auto loanToken = mnview.GetLoanTokenByID(loan.first))
for (const auto& loan : loans->balances) {
if (auto loanToken = mnview.GetLoanTokenByID(loan.first)) {
if (auto fixedIntervalPrice = mnview.GetFixedIntervalPrice(loanToken->fixedIntervalPriceId)) {
if (!fixedIntervalPrice.val->isLive(mnview.GetPriceDeviation()))
if (!fixedIntervalPrice.val->isLive(mnview.GetPriceDeviation())) {
return false;
}
} else {
// No fixed interval prices available. Should not have happened.
return false;
}
} else {
// Not a loan token. Should not have happened.
return false;
}
}
return true;
}

Expand Down
48 changes: 47 additions & 1 deletion src/rpc/stats.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,54 @@
#include <rpc/stats.h>

#include <rpc/server.h>
#include <rpc/util.h>

bool CRPCStats::isActive() { return active.load(); }
void CRPCStats::setActive(bool isActive) { active.store(isActive); }

std::optional<RPCStats> CRPCStats::get(const std::string& name) {
CLockFreeGuard lock(lock_stats);

auto it = map.find(name);
if (it == map.end()) {
return {};
}
return it->second;
}

std::map<std::string, RPCStats> CRPCStats::getMap() {
CLockFreeGuard lock(lock_stats);
return map;
}

void CRPCStats::save() {
fs::path statsPath = GetDataDir() / DEFAULT_STATSFILE;
fsbridge::ofstream file(statsPath);

file << toJSON().write() << '\n';
file.close();
}

void CRPCStats::load() {
fs::path statsPath = GetDataDir() / DEFAULT_STATSFILE;
fsbridge::ifstream file(statsPath);
if (!file.is_open()) return;

std::string line;
file >> line;

if (!line.size()) return;

UniValue arr(UniValue::VARR);
arr.read((const std::string)line);

CLockFreeGuard lock(lock_stats);
for (const auto &val : arr.getValues()) {
auto name = val["name"].get_str();
map[name] = RPCStats::fromJSON(val);
}
file.close();
}

UniValue RPCStats::toJSON() {
UniValue stats(UniValue::VOBJ),
latencyObj(UniValue::VOBJ),
Expand Down
65 changes: 11 additions & 54 deletions src/rpc/stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <univalue.h>
#include <util/time.h>
#include <util/system.h>

#include <optional>
#include <boost/circular_buffer.hpp>

const char * const DEFAULT_STATSFILE = "stats.log";
Expand Down Expand Up @@ -39,9 +39,10 @@ struct RPCStats {

RPCStats() : history(RPC_STATS_HISTORY_SIZE) {}

RPCStats(const std::string& name, int64_t latency, int64_t payload) : name(name), latency(latency), payload(payload), history(RPC_STATS_HISTORY_SIZE) {
lastUsedTime = GetSystemTimeInSeconds();
count = 1;
RPCStats(const std::string& name, int64_t latency, int64_t payload) :
name(name), latency(latency), payload(payload), history(RPC_STATS_HISTORY_SIZE) {
lastUsedTime = GetSystemTimeInSeconds();
count = 1;
};

UniValue toJSON();
Expand All @@ -59,58 +60,14 @@ class CRPCStats
std::atomic_bool active{DEFAULT_RPC_STATS};

public:
bool isActive() {
return active.load();
}
void setActive(bool isActive) {
active.store(isActive);
}

bool isActive();
void setActive(bool isActive);
void add(const std::string& name, const int64_t latency, const int64_t payload);

std::optional<RPCStats> get(const std::string& name) {
CLockFreeGuard lock(lock_stats);

auto it = map.find(name);
if (it == map.end()) {
return {};
}
return it->second;
};
std::map<std::string, RPCStats> getMap() {
CLockFreeGuard lock(lock_stats);
return map;
};
std::optional<RPCStats> get(const std::string& name);
std::map<std::string, RPCStats> getMap();
UniValue toJSON();

void save() {
fs::path statsPath = GetDataDir() / DEFAULT_STATSFILE;
fsbridge::ofstream file(statsPath);

file << toJSON().write() << '\n';
file.close();
};

void load() {
fs::path statsPath = GetDataDir() / DEFAULT_STATSFILE;
fsbridge::ifstream file(statsPath);
if (!file.is_open()) return;

std::string line;
file >> line;

if (!line.size()) return;

UniValue arr(UniValue::VARR);
arr.read((const std::string)line);

CLockFreeGuard lock(lock_stats);
for (const auto &val : arr.getValues()) {
auto name = val["name"].get_str();
map[name] = RPCStats::fromJSON(val);
}
file.close();
};
void save();
void load();
};

extern CRPCStats statsRPC;
Expand Down
39 changes: 38 additions & 1 deletion src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ bool fHavePruned = false;
bool fPruneMode = false;
bool fRequireStandard = true;
bool fCheckBlockIndex = false;

bool fStopOrInterrupt = false;
std::string fInterruptBlockHash = "";
int fInterruptBlockHeight = 0;
std::string fStopBlockHash = "";
int fStopBlockHeight = 0;

size_t nCoinCacheUsage = 5000 * 300;
size_t nCustomMemUsage = nDefaultDbCache << 10;
uint64_t nPruneTarget = 0;
Expand Down Expand Up @@ -2304,6 +2311,33 @@ bool ApplyGovVars(CCustomCSView& cache, const CBlockIndex& pindex, const std::ma
return false;
}

bool StopOrInterruptConnect(const CBlockIndex *pIndex, CValidationState& state) {
if (!fStopOrInterrupt)
return false;

const auto checkMatch = [](const CBlockIndex *index, const int height, const std::string& hash) {
return height == index->nHeight || (!hash.empty() && hash == index->phashBlock->ToString());
};

// Stop is processed first. So, if a block has both stop and interrupt
// stop will take priority.
if (checkMatch(pIndex, fStopBlockHeight, fStopBlockHash)) {
StartShutdown();
return true;
}

if (checkMatch(pIndex, fInterruptBlockHeight, fInterruptBlockHash)) {
state.Invalid(
ValidationInvalidReason::CONSENSUS,
error("ConnectBlock(): user interrupt"),
REJECT_INVALID,
"user-interrupt-request");
return true;
}

return false;
}

/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
* can fail if those validity checks fail (among other reasons). */
Expand All @@ -2315,6 +2349,10 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
assert(*pindex->phashBlock == block.GetHash());
int64_t nTimeStart = GetTimeMicros();

// Interrupt on hash or height requested. Invalidate the block.
if (StopOrInterruptConnect(pindex, state))
return false;

// Reset phanton TX to block TX count
nPhantomBurnTx = block.vtx.size();

Expand Down Expand Up @@ -4218,7 +4256,6 @@ void CChainState::ProcessTokenSplits(const CBlock& block, const CBlockIndex* pin
}

view.SetVariable(*attributes);

view.Flush();
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ extern int nScriptCheckThreads;
extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;

extern bool fStopOrInterrupt;
extern std::string fInterruptBlockHash;
extern int fInterruptBlockHeight;
extern std::string fStopBlockHash;
extern int fStopBlockHeight;

extern size_t nCoinCacheUsage;
extern size_t nCustomMemUsage;
/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
Expand Down
2 changes: 1 addition & 1 deletion test/lint/check-doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
CMD_GREP_WALLET_HIDDEN_ARGS = r"git grep --function-context 'void DummyWalletInit::AddWalletOptions' -- {}".format(CMD_ROOT_DIR)
CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR)
# list unsupported, deprecated and duplicate args as they need no documentation
SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb'])
SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb', '-interrupt-block', '-stop-block'])


def lint_missing_argument_documentation():
Expand Down

0 comments on commit f42eb25

Please sign in to comment.