Skip to content

Commit 37e0d97

Browse files
committed
[BDAP] Add fee enforcement checking
1 parent b2b6406 commit 37e0d97

File tree

10 files changed

+211
-71
lines changed

10 files changed

+211
-71
lines changed

src/bdap/bdap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ static constexpr unsigned int MAX_BDAP_SIGNATURE_PROOF = 90; // TODO (bdap):
5555
static constexpr unsigned int MAX_BDAP_LINK_DATA_SIZE = 1592;
5656
static constexpr uint64_t DEFAULT_LINK_EXPIRE_TIME = 1861920000;
5757
static constexpr int32_t DEFAULT_REGISTRATION_MONTHS = 12; // 1 year
58+
static constexpr bool ENFORCE_BDAP_FEES = false; // ********** TODO (BDAP): Update to true after a new testnet.
5859
static const std::string DEFAULT_PUBLIC_DOMAIN = "bdap.io";
5960
static const std::string DEFAULT_PUBLIC_OU = "public";
6061
static const std::string DEFAULT_ADMIN_OU = "admin";

src/bdap/domainentrydb.cpp

Lines changed: 138 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
#include "bdap/domainentrydb.h"
66

7+
#include "amount.h"
78
#include "base58.h"
9+
#include "bdap/fees.h"
810
#include "coins.h"
911
#include "bdap/utils.h"
1012
#include "validation.h"
@@ -351,12 +353,30 @@ static bool CommonDataCheck(const CDomainEntry& entry, const vchCharString& vvch
351353
return false;
352354
}
353355

356+
if (vvchOpParameters.size() != 3)
357+
{
358+
errorMessage = "CommonDataCheck failed! Not enough parameters.";
359+
return false;
360+
}
361+
354362
if (entry.GetFullObjectPath() != stringFromVch(vvchOpParameters[0]))
355363
{
356364
errorMessage = "CommonDataCheck failed! Script operation parameter does not match entry entry object.";
357365
return false;
358366
}
359367

368+
if (entry.DHTPublicKey != vvchOpParameters[1])
369+
{
370+
errorMessage = "CommonDataCheck failed! DHT public key mismatch.";
371+
return false;
372+
}
373+
374+
if (vvchOpParameters[2].size() > 10)
375+
{
376+
errorMessage = "CommonDataCheck failed! Expire date or expire months invalid.";
377+
return false;
378+
}
379+
360380
if (entry.DomainComponent != vchDefaultDomainName)
361381
{
362382
errorMessage = "CommonDataCheck failed! Must use default domain.";
@@ -378,7 +398,7 @@ static bool CommonDataCheck(const CDomainEntry& entry, const vchCharString& vvch
378398
return true;
379399
}
380400

381-
bool CheckNewDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash,
401+
static bool CheckNewDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash,
382402
std::string& errorMessage, bool fJustCheck)
383403
{
384404
if (!CommonDataCheck(entry, vvchOpParameters, errorMessage))
@@ -415,7 +435,7 @@ bool CheckNewDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scrip
415435
return FlushLevelDB();
416436
}
417437

418-
bool CheckDeleteDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
438+
static bool CheckDeleteDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
419439
std::string& errorMessage, bool fJustCheck)
420440
{
421441
if (vvchOpParameters.size() == 0) {
@@ -473,7 +493,7 @@ bool CheckDeleteDomainEntryTxInputs(const CDomainEntry& entry, const CScript& sc
473493
return FlushLevelDB();
474494
}
475495

476-
bool CheckUpdateDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash,
496+
static bool CheckUpdateDomainEntryTxInputs(CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash, const int& nMonths, const uint32_t& nBlockTime,
477497
std::string& errorMessage, bool fJustCheck)
478498
{
479499
//if exists, check for owner's signature
@@ -523,7 +543,12 @@ bool CheckUpdateDomainEntryTxInputs(const CDomainEntry& entry, const CScript& sc
523543
return error(errorMessage.c_str());
524544
}
525545
}
526-
546+
if (nMonths < 10000) {
547+
entry.nExpireTime = prevDomainEntry.nExpireTime + AddMonthsToBlockTime(nBlockTime, nMonths);
548+
}
549+
else {
550+
entry.nExpireTime = nMonths;
551+
}
527552
if (!pDomainEntryDB->UpdateDomainEntry(entry.vchFullObjectPath(), entry))
528553
{
529554
errorMessage = "CheckUpdateDomainEntryTxInputs: - Error updating entry in LevelDB; this update operation failed!";
@@ -533,7 +558,7 @@ bool CheckUpdateDomainEntryTxInputs(const CDomainEntry& entry, const CScript& sc
533558
return FlushLevelDB();
534559
}
535560

536-
bool CheckMoveDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
561+
static bool CheckMoveDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
537562
std::string& errorMessage, bool fJustCheck)
538563
{
539564
//check name in operation matches entry data in leveldb
@@ -542,45 +567,17 @@ bool CheckMoveDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scri
542567
return false;
543568
}
544569

545-
bool CheckExecuteDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
546-
std::string& errorMessage, bool fJustCheck)
547-
{
548-
//check name in operation matches entry data in leveldb
549-
//check if exists already
550-
//if exists, check for owner's signature
551-
return false;
552-
}
553-
554-
bool CheckBindDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
555-
std::string& errorMessage, bool fJustCheck)
556-
{
557-
//check names in operation matches entry data in leveldb
558-
//check if request or accept response
559-
//check if names exists already
560-
//if exists, check for owner's signature
561-
return false;
562-
}
563-
564-
bool CheckRevokeDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
565-
std::string& errorMessage, bool fJustCheck)
566-
{
567-
//check name in operation matches entry data in leveldb
568-
//check if names exists already
569-
//if exists, check for fluid signature
570-
return false;
571-
}
572-
573570
bool CheckDomainEntryTx(const CTransactionRef& tx, const CScript& scriptOp, const int& op1, const int& op2, const std::vector<std::vector<unsigned char> >& vvchArgs,
574-
bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck)
571+
const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage)
575572
{
576573
if (tx->IsCoinBase() && !fJustCheck && !bSanityCheck)
577574
{
578575
LogPrintf("*Trying to add BDAP entry in coinbase transaction, skipping...");
579576
return true;
580577
}
581578

582-
LogPrint("bdap", "%s -- *** BDAP nHeight=%d, chainActive.Tip()=%d, op1=%s, op2=%s, hash=%s justcheck=%s\n", __func__, nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op1).c_str(), BDAPFromOp(op2).c_str(), tx->GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK");
583-
579+
LogPrintf("%s -- *** BDAP nHeight=%d, chainActive.Tip()=%d, op1=%s, op2=%s, hash=%s justcheck=%s\n", __func__, nHeight, chainActive.Tip()->nHeight, BDAPFromOp(op1).c_str(), BDAPFromOp(op2).c_str(), tx->GetHash().ToString().c_str(), fJustCheck ? "JUSTCHECK" : "BLOCK");
580+
584581
// unserialize BDAP from txn, check if the entry is valid and does not conflict with a previous entry
585582
CDomainEntry entry;
586583
std::vector<unsigned char> vchData;
@@ -606,16 +603,114 @@ bool CheckDomainEntryTx(const CTransactionRef& tx, const CScript& scriptOp, cons
606603
entry.txHash = tx->GetHash();
607604
entry.nHeight = nHeight;
608605
}
609-
if (strOperationType == "bdap_new_account")
606+
607+
CAmount monthlyFee, oneTimeFee, depositFee;
608+
if (strOperationType == "bdap_new_account") {
609+
if (vvchArgs.size() != 3) {
610+
errorMessage = "Failed to get fees to add a new BDAP account";
611+
return false;
612+
}
613+
int nMonths = CScriptNum(vvchArgs[2], false, 10).getint();
614+
if (nMonths >= 10000)
615+
nMonths = 24;
616+
if (nMonths < 10000 && !GetBDAPFees(OP_BDAP_NEW, OP_BDAP_ACCOUNT_ENTRY, entry.ObjectType(), nMonths, monthlyFee, oneTimeFee, depositFee)) {
617+
errorMessage = "Failed to get fees to add a new BDAP account";
618+
return false;
619+
}
620+
// extract amounts from tx.
621+
CAmount dataAmount, opAmount;
622+
if (!ExtractAmountsFromTx(tx, dataAmount, opAmount)) {
623+
errorMessage = "Unable to extract BDAP amounts from transaction";
624+
return false;
625+
}
626+
// check if fees equal or exceed tx amounts. Use ENFORCE_BDAP_FEES for now. If ENFORCE_BDAP_FEES = false, just print the error.
627+
if (monthlyFee > dataAmount) {
628+
if (ENFORCE_BDAP_FEES) {
629+
errorMessage = "Invalid BDAP monthly registration fee amount for new BDAP account";
630+
return false;
631+
}
632+
else {
633+
LogPrintf("%s -- Invalid BDAP monthly registration fee amount for new BDAP account. Monthly paid %d but should be %d. Fees not enforced.\n", __func__, dataAmount, monthlyFee);
634+
}
635+
}
636+
else {
637+
LogPrintf("%s -- *** Valid BDAP monthly registration fee amount for new BDAP account. Monthly paid %d, should be %d.\n", __func__, dataAmount, monthlyFee);
638+
}
639+
if (depositFee > opAmount) {
640+
if (ENFORCE_BDAP_FEES) {
641+
errorMessage = "Invalid BDAP deposit fee amount for new BDAP account";
642+
return false;
643+
}
644+
else {
645+
LogPrintf("%s -- Invalid BDAP deposit fee amount for new BDAP account. Deposit paid %d but should be %d. Fees not enforced.\n", __func__, opAmount, depositFee);
646+
}
647+
}
648+
else {
649+
LogPrintf("%s -- *** Valid BDAP deposit fee amount for new BDAP account. Deposit paid %d, should be %d\n", __func__, opAmount, depositFee);
650+
}
651+
if (nMonths < 10000) {
652+
entry.nExpireTime = AddMonthsToBlockTime(nBlockTime, nMonths);
653+
}
654+
else {
655+
entry.nExpireTime = nMonths;
656+
}
657+
610658
return CheckNewDomainEntryTxInputs(entry, scriptOp, vvchArgs, tx->GetHash(), errorMessage, fJustCheck);
611-
else if (strOperationType == "bdap_delete_account")
659+
}
660+
else if (strOperationType == "bdap_delete_account") {
661+
uint16_t nMonths = 0;
662+
if (!GetBDAPFees(OP_BDAP_DELETE, OP_BDAP_ACCOUNT_ENTRY, entry.ObjectType(), nMonths, monthlyFee, oneTimeFee, depositFee)) {
663+
errorMessage = "Failed to get fees to delete a BDAP account";
664+
return false;
665+
}
666+
612667
return CheckDeleteDomainEntryTxInputs(entry, scriptOp, vvchArgs, errorMessage, fJustCheck);
613-
else if (strOperationType == "bdap_update_account")
614-
return CheckUpdateDomainEntryTxInputs(entry, scriptOp, vvchArgs, tx->GetHash(), errorMessage, fJustCheck);
615-
else if (strOperationType == "bdap_move_account")
668+
}
669+
else if (strOperationType == "bdap_update_account") {
670+
if (vvchArgs.size() != 3) {
671+
errorMessage = "Failed to get fees to add a new BDAP account";
672+
return false;
673+
}
674+
int nMonths = CScriptNum(vvchArgs[2], false, 10).getint();
675+
if (nMonths >= 10000)
676+
nMonths = 24;
677+
if (!GetBDAPFees(OP_BDAP_MODIFY, OP_BDAP_ACCOUNT_ENTRY, entry.ObjectType(), nMonths, monthlyFee, oneTimeFee, depositFee)) {
678+
errorMessage = "Failed to get fees to add a new BDAP account";
679+
return false;
680+
}
681+
// extract amounts from tx.
682+
CAmount dataAmount, opAmount;
683+
if (!ExtractAmountsFromTx(tx, dataAmount, opAmount)) {
684+
errorMessage = "Unable to extract BDAP amounts from transaction";
685+
return false;
686+
}
687+
// check if fees equal or exceed tx amounts. Use ENFORCE_BDAP_FEES for now. If ENFORCE_BDAP_FEES = false, just print the error.
688+
if (monthlyFee + oneTimeFee + depositFee > dataAmount + opAmount) {
689+
if (ENFORCE_BDAP_FEES) {
690+
errorMessage = "Invalid BDAP deposit fee amount for updated BDAP account";
691+
return false;
692+
}
693+
else {
694+
LogPrintf("%s -- Invalid BDAP deposit fee amount for updated BDAP account. Total paid %d but should be %d. Fees not enforced.\n", __func__,
695+
(dataAmount + opAmount), (monthlyFee + oneTimeFee + depositFee));
696+
}
697+
}
698+
else {
699+
LogPrintf("%s -- *** Valid BDAP deposit fee amount for updated BDAP account. Total paid %d, should be %d\n", __func__,
700+
(dataAmount + opAmount), (monthlyFee + oneTimeFee + depositFee));
701+
}
702+
// Add previous expire date plus additional months
703+
return CheckUpdateDomainEntryTxInputs(entry, scriptOp, vvchArgs, tx->GetHash(), nMonths, nBlockTime, errorMessage, fJustCheck);
704+
}
705+
else if (strOperationType == "bdap_move_account") {
706+
uint16_t nMonths = 0;
707+
if (!GetBDAPFees(OP_BDAP_MODIFY_RDN, OP_BDAP_ACCOUNT_ENTRY, entry.ObjectType(), nMonths, monthlyFee, oneTimeFee, depositFee)) {
708+
errorMessage = "Failed to get fees to move a BDAP account to another domain";
709+
return false;
710+
}
711+
616712
return CheckMoveDomainEntryTxInputs(entry, scriptOp, vvchArgs, errorMessage, fJustCheck);
617-
else if (strOperationType == "bdap_revoke_account")
618-
return CheckRevokeDomainEntryTxInputs(entry, scriptOp, vvchArgs, errorMessage, fJustCheck);
713+
}
619714

620715
return false;
621716
}

src/bdap/domainentrydb.h

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,8 @@ bool DeleteDomainEntry(const CDomainEntry& entry);
4646
bool CheckDomainEntryDB();
4747
bool FlushLevelDB();
4848
void CleanupLevelDB(int& nRemoved);
49-
bool CheckNewDomainEntryTxInputs(const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash,
50-
std::string& errorMessage, bool fJustCheck);
51-
bool CheckDeleteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
52-
std::string& errorMessage, bool fJustCheck);
53-
bool CheckUpdateDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters, const uint256& txHash,
54-
std::string& errorMessage, bool fJustCheck);
55-
bool CheckMoveDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
56-
std::string& errorMessage, bool fJustCheck);
57-
bool CheckExecuteDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
58-
std::string& errorMessage, bool fJustCheck);
59-
bool CheckBindDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
60-
std::string& errorMessage, bool fJustCheck);
61-
bool CheckRevokeDomainEntryTxInputs(const CTransaction& tx, const CDomainEntry& entry, const CScript& scriptOp, const vchCharString& vvchOpParameters,
62-
std::string& errorMessage, bool fJustCheck);
6349
bool CheckDomainEntryTx(const CTransactionRef& tx, const CScript& scriptOp, const int& op1, const int& op2, const std::vector<std::vector<unsigned char> >& vvchArgs,
64-
bool fJustCheck, int nHeight, std::string& errorMessage, bool bSanityCheck);
50+
const bool fJustCheck, const int& nHeight, const uint32_t& nBlockTime, const bool bSanityCheck, std::string& errorMessage);
6551

6652
extern CDomainEntryDB *pDomainEntryDB;
6753

src/bdap/fees.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ bool GetBDAPFees(const opcodetype& opCodeAction, const opcodetype& opCodeObject,
9090
oneTimeFee = 0;
9191
monthlyFee = 0;
9292
depositFee = BDAP_CREDIT;
93-
93+
} else if (objType == BDAP::ObjectType::BDAP_DEFAULT_TYPE) {
94+
// ********** TODO (BDAP): Remove this
95+
oneTimeFee = 0;
96+
monthlyFee = 0;
97+
depositFee = BDAP_CREDIT;
9498
}
9599
else {
96100
LogPrintf("%s -- BDAP operation code pair (%d and %d) for %s not found or unsupported.\n", __func__, opCodeAction, opCodeObject, strObjectType);
@@ -109,4 +113,41 @@ int64_t AddMonthsToCurrentEpoch(const short nMonths)
109113
boost::posix_time::time_duration dur = boost::posix_time::ptime(boost::gregorian::date(nYear, nMonth, nDay)) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1));
110114
//LogPrintf("%s -- nYear %d, nMonth %d, nDay %d\n", __func__, nYear, nMonth, nDay);
111115
return dur.total_seconds() + SECONDS_PER_DAY;
116+
}
117+
118+
int64_t AddMonthsToBlockTime(const uint32_t& nBlockTime, const short nMonths)
119+
{
120+
boost::gregorian::date dt = boost::posix_time::from_time_t(nBlockTime).date();
121+
short nYear = dt.year() + ((dt.month() + nMonths)/12);
122+
short nMonth = (dt.month() + nMonths) % 12;
123+
short nDay = dt.day();
124+
boost::posix_time::time_duration dur = boost::posix_time::ptime(boost::gregorian::date(nYear, nMonth, nDay)) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1));
125+
//LogPrintf("%s -- nYear %d, nMonth %d, nDay %d\n", __func__, nYear, nMonth, nDay);
126+
return dur.total_seconds() + SECONDS_PER_DAY;
127+
}
128+
129+
uint16_t MonthsFromBlockToExpire(const uint32_t& nBlockTime, const uint64_t& nExpireTime)
130+
{
131+
boost::gregorian::date dtBlock = boost::posix_time::from_time_t(nBlockTime).date();
132+
boost::gregorian::date dtExpire = boost::posix_time::from_time_t(nExpireTime).date();
133+
return (uint16_t)((dtExpire.year() - dtBlock.year())*12 + dtExpire.month() - dtBlock.month());
134+
}
135+
136+
bool ExtractAmountsFromTx(const CTransactionRef& ptx, CAmount& dataAmount, CAmount& opAmount)
137+
{
138+
bool fDataFound = false, fOpFound = false;
139+
for (const CTxOut& out : ptx->vout) {
140+
if (out.scriptPubKey.IsUnspendable() && out.scriptPubKey.size() > 40)
141+
{
142+
dataAmount = out.nValue;
143+
fDataFound = true;
144+
}
145+
int op1, op2;
146+
std::vector<std::vector<unsigned char>> vOpArgs;
147+
if (DecodeBDAPScript(out.scriptPubKey, op1, op2, vOpArgs)) {
148+
opAmount = out.nValue;
149+
fOpFound = true;
150+
}
151+
}
152+
return (fDataFound && fOpFound);
112153
}

src/bdap/fees.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "amount.h"
99
#include "bdap/bdap.h"
10+
#include "primitives/transaction.h"
1011
#include "script/script.h"
1112

1213
#include <map>
@@ -37,5 +38,8 @@ static const int32_t BDAP_NON_REFUNDABLE_SIDECHAIN_DEPOSIT = 7004;
3738

3839
bool GetBDAPFees(const opcodetype& opCodeAction, const opcodetype& opCodeObject, const BDAP::ObjectType objType, const uint16_t nMonths, CAmount& monthlyFee, CAmount& oneTimeFee, CAmount& depositFee);
3940
int64_t AddMonthsToCurrentEpoch(const short nMonths);
41+
int64_t AddMonthsToBlockTime(const uint32_t& nBlockTime, const short nMonths);
42+
uint16_t MonthsFromBlockToExpire(const uint32_t& nBlockTime, const uint64_t& nExpireTime);
43+
bool ExtractAmountsFromTx(const CTransactionRef& ptx, CAmount& dataAmount, CAmount& opAmount);
4044

4145
#endif // DYNAMIC_BDAP_FEES_H

0 commit comments

Comments
 (0)