Skip to content

Commit

Permalink
Classes and basic validation of ProUpServTx
Browse files Browse the repository at this point in the history
  • Loading branch information
codablock committed Aug 31, 2018
1 parent 255403e commit 6ec0d7a
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 29 deletions.
58 changes: 58 additions & 0 deletions src/evo/providertx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,42 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid

if (!CheckInputsHashAndSig(tx, ptx, ptx.keyIDOwner, state))
return false;
return true;
}

bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
{
AssertLockHeld(cs_main);

CProUpServTx ptx;
if (!GetTxPayload(tx, ptx))
return state.DoS(100, false, REJECT_INVALID, "bad-tx-payload");

if (ptx.nVersion > CProRegTx::CURRENT_VERSION)
return state.DoS(100, false, REJECT_INVALID, "bad-protx-version");

if (!CheckService(ptx.proTxHash, ptx, pindexPrev, state))
return false;

if (pindexPrev) {
auto mn = deterministicMNManager->GetMN(pindexPrev->GetBlockHash(), ptx.proTxHash);
if (!mn)
return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");

if (ptx.scriptOperatorPayout != CScript()) {
if (mn->nOperatorReward == 0) {
// don't allow to set operator reward payee in case no operatorReward was set
return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-payee");
}
// we may support P2SH later, but restrict it for now (while in transitioning phase from old MN list to deterministic list)
if (!ptx.scriptOperatorPayout.IsPayToPublicKeyHash())
return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-payee");
}

// we can only check the signature if pindexPrev != NULL and the MN is known
if (!CheckInputsHashAndSig(tx, ptx, mn->pdmnState->keyIDOperator, state))
return false;
}

return true;
}
Expand Down Expand Up @@ -152,6 +188,28 @@ void CProRegTx::ToJson(UniValue& obj) const
obj.push_back(Pair("inputsHash", inputsHash.ToString()));
}

std::string CProUpServTx::ToString() const
{
return strprintf("CProUpServTx(nVersion=%d, proTxHash=%s, nProtocolVersion=%d, addr=%s)",
nVersion, proTxHash.ToString(), nProtocolVersion, addr.ToString());
}

void CProUpServTx::ToJson(UniValue& obj) const
{
obj.clear();
obj.setObject();
obj.push_back(Pair("version", nVersion));
obj.push_back(Pair("proTxHash", proTxHash.ToString()));
obj.push_back(Pair("protocolVersion", nProtocolVersion));
obj.push_back(Pair("service", addr.ToString(false)));
CTxDestination dest;
if (ExtractDestination(scriptOperatorPayout, dest)) {
CBitcoinAddress bitcoinAddress(dest);
obj.push_back(Pair("operatorPayoutAddress", bitcoinAddress.ToString()));
}
obj.push_back(Pair("inputsHash", inputsHash.ToString()));
}

bool IsProTxCollateral(const CTransaction& tx, uint32_t n)
{
return GetProTxCollateralIndex(tx) == n;
Expand Down
37 changes: 37 additions & 0 deletions src/evo/providertx.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,44 @@ class CProRegTx
void ToJson(UniValue& obj) const;
};

class CProUpServTx
{
public:
static const uint16_t CURRENT_VERSION = 1;

public:
uint16_t nVersion{CURRENT_VERSION}; // message version
uint256 proTxHash;
int32_t nProtocolVersion{0};
CService addr;
CScript scriptOperatorPayout;
uint256 inputsHash; // replay protection
std::vector<unsigned char> vchSig;

public:
ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(nVersion);
READWRITE(proTxHash);
READWRITE(nProtocolVersion);
READWRITE(addr);
READWRITE(*(CScriptBase*)(&scriptOperatorPayout));
READWRITE(inputsHash);
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(vchSig);
}
}

public:
std::string ToString() const;
void ToJson(UniValue& obj) const;
};

bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state);
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state);

bool IsProTxCollateral(const CTransaction& tx, uint32_t n);
uint32_t GetProTxCollateralIndex(const CTransaction& tx);
Expand Down
4 changes: 4 additions & 0 deletions src/evo/specialtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
switch (tx.nType) {
case TRANSACTION_PROVIDER_REGISTER:
return CheckProRegTx(tx, pindexPrev, state);
case TRANSACTION_PROVIDER_UPDATE_SERVICE:
return CheckProUpServTx(tx, pindexPrev, state);
}

return state.DoS(10, false, REJECT_INVALID, "bad-tx-type");
Expand All @@ -39,6 +41,7 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida

switch (tx.nType) {
case TRANSACTION_PROVIDER_REGISTER:
case TRANSACTION_PROVIDER_UPDATE_SERVICE:
return true; // handled in batches per block
}

Expand All @@ -52,6 +55,7 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)

switch (tx.nType) {
case TRANSACTION_PROVIDER_REGISTER:
case TRANSACTION_PROVIDER_UPDATE_SERVICE:
return true; // handled in batches per block
}

Expand Down
1 change: 1 addition & 0 deletions src/primitives/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
enum {
TRANSACTION_NORMAL = 0,
TRANSACTION_PROVIDER_REGISTER = 1,
TRANSACTION_PROVIDER_UPDATE_SERVICE = 2,
};

/** An outpoint - a combination of a transaction hash and an index n into its vout */
Expand Down
9 changes: 8 additions & 1 deletion src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,20 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
entry.push_back(Pair("extraPayload", HexStr(tx.vExtraPayload)));
}

if (tx.nVersion >= 3 && tx.nType == TRANSACTION_PROVIDER_REGISTER) {
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
CProRegTx proTx;
if (GetTxPayload(tx, proTx)) {
UniValue proTxObj;
proTx.ToJson(proTxObj);
entry.push_back(Pair("proTx", proTxObj));
}
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx;
if (GetTxPayload(tx, proTx)) {
UniValue proTxObj;
proTx.ToJson(proTxObj);
entry.push_back(Pair("proUpServTx", proTxObj));
}
}

if (!hashBlock.IsNull()) {
Expand Down
75 changes: 49 additions & 26 deletions src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,15 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
if (!GetTxPayload(tx, proTx)) {
assert(false);
}
mapProTxRegisterAddresses.emplace(proTx.addr, tx.GetHash());
mapProTxAddresses.emplace(proTx.addr, tx.GetHash());
mapProTxPubKeyIDs.emplace(proTx.keyIDOwner, tx.GetHash());
mapProTxPubKeyIDs.emplace(proTx.keyIDOperator, tx.GetHash());
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx;
if (!GetTxPayload(tx, proTx)) {
assert(false);
}
mapProTxAddresses.emplace(proTx.addr, tx.GetHash());
}

return true;
Expand Down Expand Up @@ -626,14 +632,20 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
} else
vTxHashes.clear();

if (it->GetTx().nVersion >= 3 && it->GetTx().nType == TRANSACTION_PROVIDER_REGISTER) {
if (it->GetTx().nType == TRANSACTION_PROVIDER_REGISTER) {
CProRegTx proTx;
if (!GetTxPayload(it->GetTx(), proTx)) {
assert(false);
}
mapProTxRegisterAddresses.erase(proTx.addr);
mapProTxAddresses.erase(proTx.addr);
mapProTxPubKeyIDs.erase(proTx.keyIDOwner);
mapProTxPubKeyIDs.erase(proTx.keyIDOperator);
} else if (it->GetTx().nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx;
if (!GetTxPayload(it->GetTx(), proTx)) {
assert(false);
}
mapProTxAddresses.erase(proTx.addr);
}

totalTxSize -= it->GetTxSize();
Expand Down Expand Up @@ -764,30 +776,41 @@ void CTxMemPool::removeConflicts(const CTransaction &tx)

void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
{
if (tx.nType != TRANSACTION_PROVIDER_REGISTER)
return;

CProRegTx proTx;
if (!GetTxPayload(tx, proTx)) {
assert(false);
}
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
CProRegTx proTx;
if (!GetTxPayload(tx, proTx)) {
assert(false);
}

if (mapProTxRegisterAddresses.count(proTx.addr)) {
uint256 conflictHash = mapProTxRegisterAddresses[proTx.addr];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
if (mapProTxAddresses.count(proTx.addr)) {
uint256 conflictHash = mapProTxAddresses[proTx.addr];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
}
}
}
if (mapProTxPubKeyIDs.count(proTx.keyIDOwner)) {
uint256 conflictHash = mapProTxPubKeyIDs[proTx.keyIDOwner];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
if (mapProTxPubKeyIDs.count(proTx.keyIDOwner)) {
uint256 conflictHash = mapProTxPubKeyIDs[proTx.keyIDOwner];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
}
}
}
if (mapProTxPubKeyIDs.count(proTx.keyIDOperator)) {
uint256 conflictHash = mapProTxPubKeyIDs[proTx.keyIDOperator];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
if (mapProTxPubKeyIDs.count(proTx.keyIDOperator)) {
uint256 conflictHash = mapProTxPubKeyIDs[proTx.keyIDOperator];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
}
}
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx;
if (!GetTxPayload(tx, proTx)) {
assert(false);
}

if (mapProTxAddresses.count(proTx.addr)) {
uint256 conflictHash = mapProTxAddresses[proTx.addr];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
}
}
}
}
Expand Down Expand Up @@ -830,7 +853,7 @@ void CTxMemPool::_clear()
mapLinks.clear();
mapTx.clear();
mapNextTx.clear();
mapProTxRegisterAddresses.clear();
mapProTxAddresses.clear();
mapProTxPubKeyIDs.clear();
totalTxSize = 0;
cachedInnerUsage = 0;
Expand Down Expand Up @@ -1076,7 +1099,7 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
CProRegTx proTx;
if (!GetTxPayload(tx, proTx))
assert(false);
return mapProTxRegisterAddresses.count(proTx.addr) || mapProTxPubKeyIDs.count(proTx.keyIDOwner) || mapProTxPubKeyIDs.count(proTx.keyIDOperator);
return mapProTxAddresses.count(proTx.addr) || mapProTxPubKeyIDs.count(proTx.keyIDOwner) || mapProTxPubKeyIDs.count(proTx.keyIDOperator);
}

CFeeRate CTxMemPool::estimateFee(int nBlocks) const
Expand Down
2 changes: 1 addition & 1 deletion src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ class CTxMemPool
typedef std::map<uint256, std::vector<CSpentIndexKey> > mapSpentIndexInserted;
mapSpentIndexInserted mapSpentInserted;

std::map<CService, uint256> mapProTxRegisterAddresses;
std::map<CService, uint256> mapProTxAddresses;
std::map<CKeyID, uint256> mapProTxPubKeyIDs;

void UpdateParent(txiter entry, txiter parent, bool add);
Expand Down
3 changes: 2 additions & 1 deletion src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,8 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
// check version 3 transaction types
if (tx.nVersion >= 3) {
if (tx.nType != TRANSACTION_NORMAL &&
tx.nType != TRANSACTION_PROVIDER_REGISTER) {
tx.nType != TRANSACTION_PROVIDER_REGISTER &&
tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
}
if (tx.IsCoinBase() && tx.nType != TRANSACTION_NORMAL)
Expand Down

0 comments on commit 6ec0d7a

Please sign in to comment.