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

Better handling of account history #128

Merged
merged 10 commits into from
Dec 15, 2020
Merged
28 changes: 22 additions & 6 deletions src/flushablestorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,29 @@ class CFlushableStorageKV : public CStorageKV {
MapKV changed;
};

template<typename T>
struct CLazySerialize
{
CStorageKVIterator& it;

operator T()
{
return get();
}

T get()
{
T value;
BytesToDbType(it.Value(), value);
return value;
}
};

class CStorageView {
public:
CStorageView() = default;
CStorageView(CStorageKV * st) : storage(st) {}
CStorageView() {}
virtual ~CStorageView() = default;

template<typename KeyType>
bool Exists(const KeyType& key) const {
Expand Down Expand Up @@ -374,18 +393,15 @@ class CStorageView {
}

template<typename By, typename KeyType, typename ValueType>
bool ForEach(std::function<bool(KeyType const &, ValueType &)> callback, KeyType const & start = KeyType()) const {
bool ForEach(std::function<bool(KeyType const &, CLazySerialize<ValueType>)> callback, KeyType const & start = KeyType()) const {
auto& self = const_cast<CStorageView&>(*this);
auto key = std::make_pair(By::prefix, start);

auto it = self.DB().NewIterator();
for(it->Seek(DbTypeToBytes(key)); it->Valid() && (BytesToDbType(it->Key(), key), key.first == By::prefix); it->Next()) {
boost::this_thread::interruption_point();

ValueType value;
BytesToDbType(it->Value(), value);

if (!callback(key.second, value))
if (!callback(key.second, CLazySerialize<ValueType>{*it}))
break;
}
return true;
Expand Down
23 changes: 22 additions & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ void SetupServerArgs()
hidden_args.emplace_back("-sysperms");
#endif
gArgs.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-acindex", strprintf("Maintain a full account history index, tracking all accounts balances changes. Used by the listaccounthistory rpc call (default: %u)", false), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-acindex", strprintf("Maintain a full account history index, tracking all accounts balances changes. Used by the listaccounthistory and accounthistorycount rpc calls (default: %u)", false), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-blockfilterindex=<type>",
strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) +
" If <type> is not supplied or if <type> = 1, indexes for all known types are enabled.",
Expand Down Expand Up @@ -1585,6 +1585,27 @@ bool AppInitMain(InitInterfaces& interfaces)
pcustomcsDB = MakeUnique<CStorageLevelDB>(GetDataDir() / "enhancedcs", nMinDbCache << 20, false, fReset || fReindexChainState);
pcustomcsview.reset();
pcustomcsview = MakeUnique<CCustomCSView>(*pcustomcsDB.get());
if (!fReset && gArgs.GetBoolArg("-acindex", false)) {
bool hasRewardHistory = false;
pcustomcsview->ForEachRewardHistory([&](RewardHistoryKey const &, CLazySerialize<RewardHistoryValue>) {
hasRewardHistory = true;
return false;
});
if (!hasRewardHistory) {
bool hasOldAccountHistory = false;
pcustomcsview->ForEachAccountHistory([&](AccountHistoryKey const & key, CLazySerialize<AccountHistoryValue>) {
if (key.txn == std::numeric_limits<uint32_t>::max()) {
hasOldAccountHistory = true;
return false;
}
return true;
}, { {}, 0, std::numeric_limits<uint32_t>::max() });
if (hasOldAccountHistory) {
strLoadError = _("Account history needs rebuild").translated;
break;
}
}
}

panchorauths.reset();
panchorauths = MakeUnique<CAnchorAuthIndex>();
Expand Down
4 changes: 2 additions & 2 deletions src/masternodes/accounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
/// @attention make sure that it does not overlap with those in masternodes.cpp/tokens.cpp/undos.cpp/accounts.cpp !!!
const unsigned char CAccountsView::ByBalanceKey::prefix = 'a';

void CAccountsView::ForEachBalance(std::function<bool(CScript const & owner, CTokenAmount const & amount)> callback, BalanceKey start) const
void CAccountsView::ForEachBalance(std::function<bool(CScript const &, CTokenAmount const &)> callback, BalanceKey const & start) const
{
ForEach<ByBalanceKey, BalanceKey, CAmount>([&callback] (BalanceKey const & key, CAmount const & val) {
ForEach<ByBalanceKey, BalanceKey, CAmount>([&callback] (BalanceKey const & key, CAmount val) {
return callback(key.owner, CTokenAmount{key.tokenID, val});
}, start);
}
Expand Down
7 changes: 4 additions & 3 deletions src/masternodes/accounts.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
class CAccountsView : public virtual CStorageView
{
public:
void ForEachBalance(std::function<bool(CScript const & owner, CTokenAmount const & amount)> callback, BalanceKey start = {}) const;
void ForEachBalance(std::function<bool(CScript const &, CTokenAmount const &)> callback, BalanceKey const & start = {}) const;
CTokenAmount GetBalance(CScript const & owner, DCT_ID tokenID) const;

Res AddBalance(CScript const & owner, CTokenAmount amount);
virtual Res AddBalance(CScript const & owner, CTokenAmount amount);
virtual Res SubBalance(CScript const & owner, CTokenAmount amount);

Res AddBalances(CScript const & owner, CBalances const & balances);
Res SubBalance(CScript const & owner, CTokenAmount amount);
Res SubBalances(CScript const & owner, CBalances const & balances);

// tags
Expand Down
53 changes: 13 additions & 40 deletions src/masternodes/accountshistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,53 +10,26 @@

/// @attention make sure that it does not overlap with those in masternodes.cpp/tokens.cpp/undos.cpp/accounts.cpp !!!
const unsigned char CAccountsHistoryView::ByAccountHistoryKey::prefix = 'h'; // don't intersects with CMintedHeadersView::MintedHeaders::prefix due to different DB
const unsigned char CRewardsHistoryView::ByRewardHistoryKey::prefix = 'R'; // don't intersects with CMintedHeadersView::MintedHeaders::prefix due to different DB

void CAccountsHistoryView::ForEachAccountHistory(std::function<bool(CScript const & owner, uint32_t height, uint32_t txn, uint256 const & txid, unsigned char category, TAmounts const & diffs)> callback, AccountHistoryKey start) const
void CAccountsHistoryView::ForEachAccountHistory(std::function<bool(AccountHistoryKey const &, CLazySerialize<AccountHistoryValue>)> callback, AccountHistoryKey const & start) const
{
ForEach<ByAccountHistoryKey, AccountHistoryKey, AccountHistoryValue>([&callback] (AccountHistoryKey const & key, AccountHistoryValue const & val) {
return callback(key.owner,key.blockHeight, key.txn, val.txid, val.category, val.diff);
}, start);
ForEach<ByAccountHistoryKey, AccountHistoryKey, AccountHistoryValue>(callback, start);
}

Res CAccountsHistoryView::SetAccountHistory(const CScript & owner, uint32_t height, uint32_t txn, const uint256 & txid, unsigned char category, TAmounts const & diff)
Res CAccountsHistoryView::SetAccountHistory(const AccountHistoryKey& key, const AccountHistoryValue& value)
{
//// left for debug:
// std::string ownerStr;
// CTxDestination dest;
// if (!ExtractDestination(owner, dest)) {
// ownerStr = owner.GetHex();
// } else
// ownerStr = EncodeDestination(dest);
// LogPrintf("DEBUG: SetAccountHistory: owner: %s, ownerStr: %s, block: %i, txn: %d, txid: %s, diffs: %ld\n", owner.GetHex().c_str(), ownerStr.c_str(), height, txn, txid.ToString().c_str(), diff.size());

WriteBy<ByAccountHistoryKey>(AccountHistoryKey{owner, height, txn}, AccountHistoryValue{txid, category, diff});
WriteBy<ByAccountHistoryKey>(key, value);
return Res::Ok();
}

bool CAccountsHistoryView::TrackAffectedAccounts(CStorageKV const & before, MapKV const & diff, uint32_t height, uint32_t txn, const uint256 & txid, unsigned char category) {
// txn set to max if called from CreateNewBlock to check account balances, do not track here.
if (!gArgs.GetBoolArg("-acindex", false) || txn == std::numeric_limits<uint32_t>::max())
return false;

std::map<CScript, TAmounts> balancesDiff;
using TKey = std::pair<unsigned char, BalanceKey>;

for (auto it = diff.lower_bound({CAccountsView::ByBalanceKey::prefix}); it != diff.end() && it->first.at(0) == CAccountsView::ByBalanceKey::prefix; ++it) {
CAmount oldAmount = 0, newAmount = 0;
void CRewardsHistoryView::ForEachRewardHistory(std::function<bool(RewardHistoryKey const &, CLazySerialize<RewardHistoryValue>)> callback, RewardHistoryKey const & start) const
{
ForEach<ByRewardHistoryKey, RewardHistoryKey, RewardHistoryValue>(callback, start);
}

if (it->second) {
BytesToDbType(*it->second, newAmount);
}
TBytes beforeVal;
if (before.Read(it->first, beforeVal)) {
BytesToDbType(beforeVal, oldAmount);
}
TKey balanceKey;
BytesToDbType(it->first, balanceKey);
balancesDiff[balanceKey.second.owner][balanceKey.second.tokenID] = newAmount - oldAmount;
}
for (auto const & kv : balancesDiff) {
SetAccountHistory(kv.first, height, txn, txid, category, kv.second);
}
return true;
Res CRewardsHistoryView::SetRewardHistory(const RewardHistoryKey& key, const RewardHistoryValue& value)
{
WriteBy<ByRewardHistoryKey>(key, value);
return Res::Ok();
}
52 changes: 49 additions & 3 deletions src/masternodes/accountshistory.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,61 @@ struct AccountHistoryValue {
}
};

struct RewardHistoryKey {
CScript owner;
uint32_t blockHeight;
DCT_ID poolID; // for order in block

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(owner);

if (ser_action.ForRead()) {
READWRITE(WrapBigEndian(blockHeight));
blockHeight = ~blockHeight;
}
else {
uint32_t blockHeight_ = ~blockHeight;
READWRITE(WrapBigEndian(blockHeight_));
}

READWRITE(VARINT(poolID.v));
}
};

struct RewardHistoryValue {
unsigned char category;
TAmounts diff;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(category);
READWRITE(diff);
}
};

class CAccountsHistoryView : public virtual CStorageView
{
public:
Res SetAccountHistory(CScript const & owner, uint32_t height, uint32_t txn, uint256 const & txid, unsigned char category, TAmounts const & diff);
void ForEachAccountHistory(std::function<bool(CScript const & owner, uint32_t height, uint32_t txn, uint256 const & txid, unsigned char category, TAmounts const & diff)> callback, AccountHistoryKey start) const;
bool TrackAffectedAccounts(CStorageKV const & before, MapKV const & diff, uint32_t height, uint32_t txn, const uint256 & txid, unsigned char category);
Res SetAccountHistory(AccountHistoryKey const & key, AccountHistoryValue const & value);
void ForEachAccountHistory(std::function<bool(AccountHistoryKey const &, CLazySerialize<AccountHistoryValue>)> callback, AccountHistoryKey const & start = {}) const;

// tags
struct ByAccountHistoryKey { static const unsigned char prefix; };
};

class CRewardsHistoryView : public virtual CStorageView
{
public:
Res SetRewardHistory(RewardHistoryKey const & key, RewardHistoryValue const & value);
void ForEachRewardHistory(std::function<bool(RewardHistoryKey const &, CLazySerialize<RewardHistoryValue>)> callback, RewardHistoryKey const & start = {}) const;

// tags
struct ByRewardHistoryKey { static const unsigned char prefix; };
};

#endif //DEFI_MASTERNODES_ACCOUNTSHISTORY_H
8 changes: 4 additions & 4 deletions src/masternodes/criminals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ bool CMintedHeadersView::FetchMintedHeaders(const uint256 & txid, const uint64_t
}

blockHeaders.clear();
ForEach<MintedHeaders,DBMNBlockHeadersKey,CBlockHeader>([&txid, &mintedBlocks, &blockHeaders] (DBMNBlockHeadersKey const & key, CBlockHeader & blockHeader) {
ForEach<MintedHeaders,DBMNBlockHeadersKey,CBlockHeader>([&txid, &mintedBlocks, &blockHeaders] (DBMNBlockHeadersKey const & key, CLazySerialize<CBlockHeader> blockHeader) {
if (key.masternodeID == txid &&
key.mintedBlocks == mintedBlocks) {

blockHeaders.emplace(key.blockHash, std::move(blockHeader));
blockHeaders.emplace(key.blockHash, blockHeader.get());
return true; // continue
}
return false; // break!
Expand Down Expand Up @@ -76,12 +76,12 @@ void CCriminalProofsView::RemoveCriminalProofs(const uint256 & mnId) {
CCriminalProofsView::CMnCriminals CCriminalProofsView::GetUnpunishedCriminals() {

CMnCriminals result;
ForEach<Proofs, uint256, CDoubleSignFact>([&result] (uint256 const & id, CDoubleSignFact & proof) {
ForEach<Proofs, uint256, CDoubleSignFact>([&result] (uint256 const & id, CLazySerialize<CDoubleSignFact> proof) {

// matching with already punished. and this is the ONLY measure!
auto node = pcustomcsview->GetMasternode(id); // assert?
if (node && node->banTx.IsNull()) {
result.emplace(id, std::move(proof));
result.emplace(id, proof.get());
}
return true; // continue
});
Expand Down
6 changes: 3 additions & 3 deletions src/masternodes/govvariables/lp_splits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ Res LP_SPLITS::Validate(const CCustomCSView & mnview) const {
}

Res LP_SPLITS::Apply(CCustomCSView & mnview) {
mnview.ForEachPoolPair([&] (const DCT_ID poolId, const CPoolPair & pool) {
mnview.ForEachPoolPair([&] (const DCT_ID poolId, CPoolPair pool) {
// we ought to reset previous value:
const_cast<CPoolPair &>(pool).rewardPct = 0;
pool.rewardPct = 0;
auto it = splits.find(poolId);
if (it != splits.end()) {
const_cast<CPoolPair &>(pool).rewardPct = it->second;
pool.rewardPct = it->second;
}

mnview.SetPoolPair(poolId, pool);
Expand Down
4 changes: 2 additions & 2 deletions src/masternodes/incentivefunding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ Res CCommunityBalancesView::SetCommunityBalance(CommunityAccountType account, CA
return Res::Ok();
}

void CCommunityBalancesView::ForEachCommunityBalance(std::function<bool (CommunityAccountType, CAmount)> callback) const
void CCommunityBalancesView::ForEachCommunityBalance(std::function<bool (CommunityAccountType, CLazySerialize<CAmount>)> callback) const
{
ForEach<ById, unsigned char, CAmount>([&callback] (unsigned char const & key, CAmount const & val) {
ForEach<ById, unsigned char, CAmount>([&callback] (unsigned char const & key, CLazySerialize<CAmount> val) {
return callback(CommunityAccountCodeToType(key), val);
}, '\0');

Expand Down
2 changes: 1 addition & 1 deletion src/masternodes/incentivefunding.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class CCommunityBalancesView : public virtual CStorageView
CAmount GetCommunityBalance(CommunityAccountType account) const;
Res SetCommunityBalance(CommunityAccountType account, CAmount amount);

void ForEachCommunityBalance(std::function<bool(CommunityAccountType account, CAmount amount)> callback) const;
void ForEachCommunityBalance(std::function<bool(CommunityAccountType, CLazySerialize<CAmount>)> callback) const;

Res AddCommunityBalance(CommunityAccountType account, CAmount amount);
Res SubCommunityBalance(CommunityAccountType account, CAmount amount);
Expand Down
Loading