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

Add A Fee Caching/Distribution System #359

Merged
merged 22 commits into from
May 27, 2016
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c3309ae
Setup a fee cache and start adding helper functions
zathras-crypto Mar 2, 2016
0d30374
Commenting somehow got messed up, fix
zathras-crypto Mar 2, 2016
c9c7afd
Further works toward MetaDEx fees
zathras-crypto Mar 3, 2016
1de7eb5
Switch to integer math for fee handling
zathras-crypto Mar 5, 2016
cddad0d
Record trading fee in STOListDB and expose it over RPC.
zathras-crypto Mar 5, 2016
1a1393d
Add omni_getfeecache RPC call to get currently cached fee amounts
zathras-crypto Mar 5, 2016
6752729
Further works towards prototype for fees
zathras-crypto Mar 7, 2016
3283798
Reverse orientation of fee reduction (fee should come from liquidity …
zathras-crypto Mar 7, 2016
8306576
Commit first part of testing
zathras-crypto Mar 7, 2016
6f693ab
Latest updates to fees concept
zathras-crypto Mar 22, 2016
fd53175
Apply fees only to non-Omni pairs
zathras-crypto Apr 13, 2016
2a5671d
Remove Dev Omni bypass
zathras-crypto Apr 13, 2016
108278c
Add fees as feature ID 9 and require activation before fees are taken
zathras-crypto Apr 19, 2016
5164386
Update tests to include fees activation via feature ID 9
zathras-crypto Apr 19, 2016
8a3fe7e
Fix reorg protection for the fee cache
zathras-crypto May 2, 2016
24bb242
Add overflow protection to AddFee
zathras-crypto May 3, 2016
4d4883d
Add rollback for fee history DB in event of reorg
zathras-crypto May 3, 2016
a571e5c
Fix a few remaining TODOs
zathras-crypto May 3, 2016
93e7a72
Change INT64_MAX to std::numeric_limits (thanks @dexx7)
zathras-crypto May 17, 2016
5abe857
Pay fees from test property trading to Test Omni holders
zathras-crypto May 22, 2016
0527904
Remove dev msc bypass left in from testing
zathras-crypto May 22, 2016
c40b72b
Fix up minor nits and improve omni_getfeeshare param handling
zathras-crypto May 23, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.omnicore.include
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ OMNICORE_H = \
omnicore/dex.h \
omnicore/encoding.h \
omnicore/errors.h \
omnicore/fees.h \
omnicore/fetchwallettx.h \
omnicore/log.h \
omnicore/mbstring.h \
Expand Down Expand Up @@ -45,6 +46,7 @@ OMNICORE_CPP = \
omnicore/createtx.cpp \
omnicore/dex.cpp \
omnicore/encoding.cpp \
omnicore/fees.cpp \
omnicore/fetchwallettx.cpp \
omnicore/log.cpp \
omnicore/mbstring.cpp \
Expand Down
484 changes: 484 additions & 0 deletions src/omnicore/fees.cpp

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions src/omnicore/fees.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#ifndef OMNICORE_FEES_H
#define OMNICORE_FEES_H

#include "leveldb/db.h"

#include "omnicore/log.h"
#include "omnicore/persistence.h"

#include <set>
#include <stdint.h>
#include <boost/filesystem.hpp>

typedef std::pair<int, int64_t> feeCacheItem;
typedef std::pair<std::string, int64_t> feeHistoryItem;

/** LevelDB based storage for the MetaDEx fee cache
*/
class COmniFeeCache : public CDBBase
{
public:
COmniFeeCache(const boost::filesystem::path& path, bool fWipe)
{
leveldb::Status status = Open(path, fWipe);
PrintToConsole("Loading fee cache database: %s\n", status.ToString());
}

virtual ~COmniFeeCache()
{
if (msc_debug_fees) PrintToLog("COmniFeeCache closed\n");
}

// Show Fee Cache DB statistics
void printStats();
// Show Fee Cache DB records
void printAll();

// Sets the distribution thresholds to total tokens for a property / OMNI_FEE_THRESHOLD
void UpdateDistributionThresholds();
// Returns the distribution threshold for a property
int64_t GetDistributionThreshold(const uint32_t &propertyId);
// Return a set containing fee cache history items
std::set<feeCacheItem> GetCacheHistory(const uint32_t &propertyId);
// Gets the current amount of the fee cache for a property
int64_t GetCachedAmount(const uint32_t &propertyId);
// Prunes entries over 50 blocks old from the entry for a property
void PruneCache(const uint32_t &propertyId, int block);
// Rolls back the cache to an earlier state (eg in event of a reorg) - block is *inclusive* (ie entries=block will get deleted)
void RollBackCache(int block);
// Zeros a property in the fee cache
void ClearCache(const uint32_t &propertyId, int block);
// Adds a fee to the cache (eg on a completed trade)
void AddFee(const uint32_t &propertyId, int block, const int64_t &amount);
// Evaluates fee caches for all properties against threshold and executes distribution if threshold met
void EvalCache(const uint32_t &propertyId, int block);
// Performs distribution of fees
void DistributeCache(const uint32_t &propertyId, int block);
};

/** LevelDB based storage for the MetaDEx fee distributions
*/
class COmniFeeHistory : public CDBBase
{
public:
COmniFeeHistory(const boost::filesystem::path& path, bool fWipe)
{
leveldb::Status status = Open(path, fWipe);
PrintToConsole("Loading fee history database: %s\n", status.ToString());
}

virtual ~COmniFeeHistory()
{
if (msc_debug_fees) PrintToLog("COmniFeeHistory closed\n");
}

// Show Fee History DB statistics
void printStats();
// Show Fee History DB records
void printAll();

// Roll back history in event of reorg
void RollBackHistory(int block);
// Count Fee History DB records
int CountRecords();
// Record a fee distribution
void RecordFeeDistribution(const uint32_t &propertyId, int block, int64_t total, std::set<feeHistoryItem> feeRecipients);
// Retrieve the recipients for a fee distribution
std::set<feeHistoryItem> GetFeeDistribution(int id);
// Retrieve fee distributions for a property
std::set<int> GetDistributionsForProperty(const uint32_t &propertyId);
// Populate data about a fee distribution
bool GetDistributionData(int id, uint32_t *propertyId, int *block, int64_t *total);
// Retrieve fee distribution receipts for an address
};

namespace mastercore
{
extern COmniFeeCache *p_feecache;
extern COmniFeeHistory *p_feehistory;
}

#endif // OMNICORE_FEES_H
4 changes: 4 additions & 0 deletions src/omnicore/log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ bool msc_debug_consensus_hash_every_block = 0;
bool msc_debug_alerts = 1;
//! Print consensus hashes for each transaction when parsing
bool msc_debug_consensus_hash_every_transaction = 0;
//! Debug fees
bool msc_debug_fees = 1;

/**
* LogPrintf() has been broken a couple of times now
Expand Down Expand Up @@ -263,6 +265,7 @@ void InitDebugLogLevels()
if (*it == "consensus_hash_every_block") msc_debug_consensus_hash_every_block = true;
if (*it == "alerts") msc_debug_alerts = true;
if (*it == "consensus_hash_every_transaction") msc_debug_consensus_hash_every_transaction = true;
if (*it == "fees") msc_debug_fees = true;
if (*it == "none" || *it == "all") {
bool allDebugState = false;
if (*it == "all") allDebugState = true;
Expand Down Expand Up @@ -298,6 +301,7 @@ void InitDebugLogLevels()
msc_debug_consensus_hash_every_block = allDebugState;
msc_debug_alerts = allDebugState;
msc_debug_consensus_hash_every_transaction = allDebugState;
msc_debug_fees = allDebugState;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/omnicore/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extern bool msc_debug_consensus_hash;
extern bool msc_debug_consensus_hash_every_block;
extern bool msc_debug_alerts;
extern bool msc_debug_consensus_hash_every_transaction;
extern bool msc_debug_fees;

/* When we switch to C++11, this can be switched to variadic templates instead
* of this macro-based construction (see tinyformat.h).
Expand Down
25 changes: 23 additions & 2 deletions src/omnicore/mdex.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#include "omnicore/mdex.h"

#include "omnicore/errors.h"
#include "omnicore/fees.h"
#include "omnicore/log.h"
#include "omnicore/omnicore.h"
#include "omnicore/rules.h"
#include "omnicore/sp.h"
#include "omnicore/tx.h"
#include "omnicore/uint256_extensions.h"
Expand Down Expand Up @@ -256,13 +258,32 @@ static MatchReturnType x_Trade(CMPMetaDEx* const pnew)

///////////////////////////

int64_t buyer_amountGotAfterFee = buyer_amountGot;
int64_t tradingFee = 0;

// strip a 0.05% fee from non-OMNI pairs if fees are activated
if (IsFeatureActivated(FEATURE_FEES, pnew->getBlock())) {
if ( (pold->getProperty() != (OMNI_PROPERTY_MSC || OMNI_PROPERTY_TMSC)) || (pold->getDesProperty() != (OMNI_PROPERTY_MSC || OMNI_PROPERTY_TMSC)) ) {
int64_t feeDivider = 2000; // 0.05%
tradingFee = buyer_amountGot / feeDivider;

// subtract the fee from the amount the seller will receive
buyer_amountGotAfterFee = buyer_amountGot - tradingFee;

// add the fee to the fee cache
p_feecache->AddFee(pnew->getDesProperty(), pnew->getBlock(), tradingFee);
} else {
if (msc_debug_fees) PrintToLog("Skipping fee reduction for trade match %s:%s as one of the properties is Omni\n", pold->getHash().GetHex(), pnew->getHash().GetHex());
}
}

// transfer the payment property from buyer to seller
assert(update_tally_map(pnew->getAddr(), pnew->getProperty(), -seller_amountGot, BALANCE));
assert(update_tally_map(pold->getAddr(), pold->getDesProperty(), seller_amountGot, BALANCE));

// transfer the market (the one being sold) property from seller to buyer
assert(update_tally_map(pold->getAddr(), pold->getProperty(), -buyer_amountGot, METADEX_RESERVE));
assert(update_tally_map(pnew->getAddr(), pnew->getDesProperty(), buyer_amountGot, BALANCE));
assert(update_tally_map(pnew->getAddr(), pnew->getDesProperty(), buyer_amountGotAfterFee, BALANCE));

NewReturn = TRADED;

Expand All @@ -287,7 +308,7 @@ static MatchReturnType x_Trade(CMPMetaDEx* const pnew)

// record the trade in MPTradeList
t_tradelistdb->recordMatchedTrade(pold->getHash(), pnew->getHash(), // < might just pass pold, pnew
pold->getAddr(), pnew->getAddr(), pold->getDesProperty(), pnew->getDesProperty(), seller_amountGot, buyer_amountGot, pnew->getBlock());
pold->getAddr(), pnew->getAddr(), pold->getDesProperty(), pnew->getDesProperty(), seller_amountGot, buyer_amountGotAfterFee, pnew->getBlock(), tradingFee);

if (msc_debug_metadex1) PrintToLog("++ erased old: %s\n", offerIt->ToString());
// erase the old seller element
Expand Down
37 changes: 33 additions & 4 deletions src/omnicore/omnicore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "omnicore/dex.h"
#include "omnicore/encoding.h"
#include "omnicore/errors.h"
#include "omnicore/fees.h"
#include "omnicore/log.h"
#include "omnicore/mdex.h"
#include "omnicore/notifications.h"
Expand Down Expand Up @@ -135,6 +136,8 @@ CMPTxList *mastercore::p_txlistdb;
CMPTradeList *mastercore::t_tradelistdb;
CMPSTOList *mastercore::s_stolistdb;
COmniTransactionDB *mastercore::p_OmniTXDB;
COmniFeeCache *mastercore::p_feecache;
COmniFeeHistory *mastercore::p_feehistory;

// indicate whether persistence is enabled at this point, or not
// used to write/read files, for breakout mode, debugging, etc.
Expand Down Expand Up @@ -2044,6 +2047,8 @@ void clear_all_state()
s_stolistdb->Clear();
t_tradelistdb->Clear();
p_OmniTXDB->Clear();
p_feecache->Clear();
p_feehistory->Clear();
assert(p_txlistdb->setDBVersion() == DB_VERSION); // new set of databases, set DB version
exodus_prev = 0;
}
Expand Down Expand Up @@ -2093,12 +2098,16 @@ int mastercore_init()
boost::filesystem::path spPath = GetDataDir() / "MP_spinfo";
boost::filesystem::path stoPath = GetDataDir() / "MP_stolist";
boost::filesystem::path omniTXDBPath = GetDataDir() / "Omni_TXDB";
boost::filesystem::path feesPath = GetDataDir() / "OMNI_feecache";
boost::filesystem::path feeHistoryPath = GetDataDir() / "OMNI_feehistory";
if (boost::filesystem::exists(persistPath)) boost::filesystem::remove_all(persistPath);
if (boost::filesystem::exists(txlistPath)) boost::filesystem::remove_all(txlistPath);
if (boost::filesystem::exists(tradePath)) boost::filesystem::remove_all(tradePath);
if (boost::filesystem::exists(spPath)) boost::filesystem::remove_all(spPath);
if (boost::filesystem::exists(stoPath)) boost::filesystem::remove_all(stoPath);
if (boost::filesystem::exists(omniTXDBPath)) boost::filesystem::remove_all(omniTXDBPath);
if (boost::filesystem::exists(feesPath)) boost::filesystem::remove_all(feesPath);
if (boost::filesystem::exists(feeHistoryPath)) boost::filesystem::remove_all(feeHistoryPath);
PrintToLog("Success clearing persistence files in datadir %s\n", GetDataDir().string());
startClean = true;
} catch (const boost::filesystem::filesystem_error& e) {
Expand All @@ -2112,6 +2121,8 @@ int mastercore_init()
p_txlistdb = new CMPTxList(GetDataDir() / "MP_txlist", fReindex);
_my_sps = new CMPSPInfo(GetDataDir() / "MP_spinfo", fReindex);
p_OmniTXDB = new COmniTransactionDB(GetDataDir() / "Omni_TXDB", fReindex);
p_feecache = new COmniFeeCache(GetDataDir() / "OMNI_feecache", fReindex);
p_feehistory = new COmniFeeHistory(GetDataDir() / "OMNI_feehistory", fReindex);

MPPersistencePath = GetDataDir() / "MP_persist";
TryCreateDirectory(MPPersistencePath);
Expand Down Expand Up @@ -2213,6 +2224,14 @@ int mastercore_shutdown()
delete p_OmniTXDB;
p_OmniTXDB = NULL;
}
if (p_feecache) {
delete p_feecache;
p_feecache = NULL;
}
if (p_feehistory) {
delete p_feehistory;
p_feehistory = NULL;
}

PrintToLog("\nOmni Core shutdown completed\n");
PrintToLog("Shutdown time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
Expand Down Expand Up @@ -2373,6 +2392,7 @@ int mastercore::ClassAgnosticWalletTXBuilder(const std::string& senderAddress, c
#else
return MP_ERR_WALLET_ACCESS;
#endif

}

void COmniTransactionDB::RecordTransaction(const uint256& txid, uint32_t posInBlock)
Expand Down Expand Up @@ -3263,7 +3283,7 @@ bool CMPTradeList::getMatchingTrades(const uint256& txid, uint32_t propertyId, A

// ensure correct amount of tokens in value string
boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on);
if (vstr.size() != 7) {
if (vstr.size() != 8) {
PrintToLog("TRADEDB error - unexpected number of tokens in value (%s)\n", strValue);
continue;
}
Expand All @@ -3276,8 +3296,11 @@ bool CMPTradeList::getMatchingTrades(const uint256& txid, uint32_t propertyId, A
int64_t amount1 = boost::lexical_cast<int64_t>(vstr[4]);
int64_t amount2 = boost::lexical_cast<int64_t>(vstr[5]);
int blockNum = atoi(vstr[6]);
int64_t tradingFee = boost::lexical_cast<int64_t>(vstr[7]);

std::string strAmount1 = FormatMP(prop1, amount1);
std::string strAmount2 = FormatMP(prop2, amount2);
std::string strTradingFee = FormatMP(prop1, tradingFee);

// populate trade object and add to the trade array, correcting for orientation of trade
Object trade;
Expand All @@ -3293,6 +3316,7 @@ bool CMPTradeList::getMatchingTrades(const uint256& txid, uint32_t propertyId, A
trade.push_back(Pair("address", address2));
trade.push_back(Pair("amountsold", strAmount2));
trade.push_back(Pair("amountreceived", strAmount1));
trade.push_back(Pair("tradingfee", strTradingFee));
totalReceived += amount1;
totalSold += amount2;
}
Expand Down Expand Up @@ -3329,7 +3353,7 @@ void CMPTradeList::getTradesForPair(uint32_t propertyIdSideA, uint32_t propertyI
if (strKey.size() != 129) continue; // only interested in matches
boost::split(vecKeys, strKey, boost::is_any_of("+"), boost::token_compress_on);
boost::split(vecValues, strValue, boost::is_any_of(":"), boost::token_compress_on);
if (vecKeys.size() != 2 || vecValues.size() != 7) {
if (vecKeys.size() != 2 || vecValues.size() != 8) {
PrintToLog("TRADEDB error - unexpected number of tokens (%s:%s)\n", strKey, strValue);
continue;
}
Expand Down Expand Up @@ -3439,11 +3463,11 @@ void CMPTradeList::recordNewTrade(const uint256& txid, const std::string& addres
if (msc_debug_tradedb) PrintToLog("%s(): %s\n", __FUNCTION__, status.ToString());
}

void CMPTradeList::recordMatchedTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum)
void CMPTradeList::recordMatchedTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum, int64_t fee)
{
if (!pdb) return;
const string key = txid1.ToString() + "+" + txid2.ToString();
const string value = strprintf("%s:%s:%u:%u:%lu:%lu:%d", address1, address2, prop1, prop2, amount1, amount2, blockNum);
const string value = strprintf("%s:%s:%u:%u:%lu:%lu:%d:%d", address1, address2, prop1, prop2, amount1, amount2, blockNum, fee);
Status status;
if (pdb)
{
Expand Down Expand Up @@ -3596,6 +3620,8 @@ int mastercore_handler_block_begin(int nBlockPrev, CBlockIndex const * pBlockInd
p_txlistdb->isMPinBlockRange(pBlockIndex->nHeight, reorgRecoveryMaxHeight, true);
t_tradelistdb->deleteAboveBlock(pBlockIndex->nHeight);
s_stolistdb->deleteAboveBlock(pBlockIndex->nHeight);
p_feecache->RollBackCache(pBlockIndex->nHeight);
p_feehistory->RollBackHistory(pBlockIndex->nHeight);
reorgRecoveryMaxHeight = 0;

nWaterlineBlock = ConsensusParams().GENESIS_BLOCK - 1;
Expand Down Expand Up @@ -3666,6 +3692,9 @@ int mastercore_handler_block_end(int nBlockNow, CBlockIndex const * pBlockIndex,
// transactions were found in the block, signal the UI accordingly
if (countMP > 0) CheckWalletUpdate(true);

// total tokens for properties may have changed, recalculate distribution thresholds for MetaDEx fees
p_feecache->UpdateDistributionThresholds();

// calculate and print a consensus hash if required
if (msc_debug_consensus_hash_every_block) {
uint256 consensusHash = GetConsensusHash();
Expand Down
2 changes: 1 addition & 1 deletion src/omnicore/omnicore.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ class CMPTradeList : public CDBBase
if (msc_debug_persistence) PrintToLog("CMPTradeList closed\n");
}

void recordMatchedTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum);
void recordMatchedTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum, int64_t fee);
void recordNewTrade(const uint256& txid, const std::string& address, uint32_t propertyIdForSale, uint32_t propertyIdDesired, int blockNum, int blockIndex);
int deleteAboveBlock(int blockNum);
bool exists(const uint256 &txid);
Expand Down
Loading