{
bool valid = true, timelocked = false;
CTxDestination firstDest;
-
+
// if time locks are on, ensure that this coin base is time locked exactly as it should be, or invalidate
- if (((uint64_t)tx.GetValueOut() >= ASSETCHAINS_TIMELOCKGTE) ||
- (((nHeight >= 31680) || !IsVerusMainnetActive()) && komodo_ac_block_subsidy(nHeight) >= ASSETCHAINS_TIMELOCKGTE))
+ if (((nHeight >= 31680 && nHeight <= 129600) && IsVerusMainnetActive()) &&
+ ((((uint64_t)tx.GetValueOut() >= ASSETCHAINS_TIMELOCKGTE) ||
+ (komodo_ac_block_subsidy(nHeight) >= ASSETCHAINS_TIMELOCKGTE))))
{
CScriptID scriptHash;
valid = false;
if (coins->IsCoinBase()) {
// ensure that output of coinbases are not still time locked, or are the outputs that are instant spend
- if ((uint64_t)coins->TotalTxValue() >= ASSETCHAINS_TIMELOCKGTE && !coins->vout[prevout.n].scriptPubKey.IsInstantSpend())
+ if ((uint64_t)coins->TotalTxValue() >= ASSETCHAINS_TIMELOCKGTE &&
+ !coins->vout[prevout.n].scriptPubKey.IsInstantSpend())
{
uint64_t unlockTime = komodo_block_unlocktime(coins->nHeight);
- if (nSpendHeight < unlockTime) {
- return state.DoS(10,
- error("CheckInputs(): tried to spend coinbase that is timelocked until block %d", unlockTime),
- REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
+ if ((coins->nHeight >= 31680 && coins->nHeight <= 129600) && IsVerusMainnetActive() && nSpendHeight < unlockTime)
+ {
+ if (CConstVerusSolutionVector::GetVersionByHeight(nSpendHeight) < CActivationHeight::ACTIVATE_IDENTITY)
+ {
+ printf("Questionable spend at height %u of coinbase at height %u\n", nSpendHeight, coins->nHeight);
+ }
+ else
+ {
+ return state.DoS(10,
+ error("CheckInputs(): tried to spend coinbase that is timelocked until block %d", unlockTime),
+ REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
+ }
+ }
+ else if (nSpendHeight < unlockTime)
+ {
+ printf("Potential version specific spend issue at height %u of coinbase at height %u\n", nSpendHeight, coins->nHeight);
}
}
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
}
- // As of solution version 3, we're done with the Zcash coinbase protection.
+ // As of solution version 5, we're done with the Zcash coinbase protection.
// After careful consideration, it seems that while there is no real privacy benefit to the
// coinbase protection beyond forcing the private address pool to be used at least a little by everyone, it does increase the size of the blockchain
// and often reduces privacy by mixing multiple coinbase payment addresses
} else if (state.GetRejectReason() != "already have coins" &&
!((missinginputs || state.GetRejectCode() == REJECT_DUPLICATE) && (!fCheckTxInputs || chainActive.Height() < height - 1)))
{
- //printf("Rejected transaction for %s, reject code %d\n", state.GetRejectReason().c_str(), state.GetRejectCode());
+ // printf("Rejected transaction for %s, reject code %d\n", state.GetRejectReason().c_str(), state.GetRejectCode());
//for (auto input : Tx.vin)
//{
// LogPrintf("input n: %d, hash: %s\n", input.prevout.n, input.prevout.hash.GetHex().c_str());
std::vector<CTxDestination> referrers;
bool valid = true;
+ bool extendedIDValidation = CConstVerusSolutionVector::GetVersionByHeight(height) >= CActivationHeight::ACTIVATE_EXTENDEDSTAKE;
+
AssertLockHeld(cs_main);
for (auto &txout : tx.vout)
CTxIn idTxIn;
uint32_t priorHeightOut;
CIdentity dupID = newIdentity.LookupIdentity(newIdentity.GetID(), height - 1, &priorHeightOut, &idTxIn);
- uint256 inputBlockHash;
- CCoinsViewCache view(pcoinsTip);
+ // CHECK #3a - if dupID is invalid, ensure we spend a matching name commitment
if (dupID.IsValid())
{
return state.Error("Identity already exists");
}
- // CHECK #3a - if dupID is invalid, ensure we spend a matching name commitment
- else
- {
- CCommitmentHash ch;
- int idx = -1;
- CTransaction txInput;
+ int commitmentHeight = 0;
+ const CCoins *coins;
+ CCoinsView dummy;
+ CCoinsViewCache view(&dummy);
+
+ LOCK(mempool.cs);
+ CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
+ view.SetBackend(viewMemPool);
+
+ CCommitmentHash ch;
+ int idx = -1;
+
+ CAmount nValueIn = 0;
+ {
// from here, we must spend a matching name commitment
+ std::map<uint256, const CCoins *> txMap;
for (auto &oneTxIn : tx.vin)
{
- if (!myGetTransaction(oneTxIn.prevout.hash, txInput, inputBlockHash))
+ coins = txMap[oneTxIn.prevout.hash];
+ if (!coins && !(coins = view.AccessCoins(oneTxIn.prevout.hash)))
{
+ //LogPrintf("Cannot access input from output %u of transaction %s in transaction %s\n", oneTxIn.prevout.n, oneTxIn.prevout.hash.GetHex().c_str(), tx.GetHash().GetHex().c_str());
+ //printf("Cannot access input from output %u of transaction %s in transaction %s\n", oneTxIn.prevout.n, oneTxIn.prevout.hash.GetHex().c_str(), tx.GetHash().GetHex().c_str());
return state.Error("Cannot access input");
}
+ txMap[oneTxIn.prevout.hash] = coins;
- if (oneTxIn.prevout.n >= txInput.vout.size())
+ if (oneTxIn.prevout.n >= coins->vout.size())
{
//extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
//UniValue uniTx;
}
COptCCParams p;
- if (txInput.vout[oneTxIn.prevout.n].scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.evalCode == EVAL_IDENTITY_COMMITMENT && p.vData.size())
+ if (idx == -1 &&
+ coins->vout[oneTxIn.prevout.n].scriptPubKey.IsPayToCryptoCondition(p) &&
+ p.IsValid() &&
+ p.evalCode == EVAL_IDENTITY_COMMITMENT &&
+ p.vData.size())
{
idx = oneTxIn.prevout.n;
::FromVector(p.vData[0], ch);
- break;
+ commitmentHeight = coins->nHeight;
+ // this needs to already be in a prior block, or we can't consider it valid
+ if (!commitmentHeight)
+ {
+ if (extendedIDValidation)
+ {
+ return state.Error("ID commitment was not already in blockchain");
+ }
+ printf("Identity commitment in tx: %s spends commitment in same block at height %d\n", tx.GetHash().GetHex().c_str(), height);
+ }
}
}
+ }
- if (idx == -1 || ch.hash.IsNull() || inputBlockHash.IsNull())
- {
- std::string specificMsg = "Invalid identity commitment in tx: " + tx.GetHash().GetHex();
- return state.Error(specificMsg);
- }
-
- auto priorIt = mapBlockIndex.find(inputBlockHash);
- if (priorIt == mapBlockIndex.end() || !chainActive.Contains(priorIt->second))
- {
- return state.Error("Identity commitment not in current chain");
- }
-
- priorHeightOut = priorIt->second->GetHeight();
+ if (idx == -1 || ch.hash.IsNull())
+ {
+ std::string specificMsg = "Invalid identity commitment in tx: " + tx.GetHash().GetHex();
+ return state.Error(specificMsg);
+ }
- // are we spending a matching name commitment?
- if (ch.hash != newName.GetCommitment().hash)
- {
- return state.Error("Mismatched identity commitment");
- }
+ // are we spending a matching name commitment?
+ if (ch.hash != newName.GetCommitment().hash)
+ {
+ return state.Error("Mismatched identity commitment");
+ }
- if (!newName.referral.IsNull() && issuingChain.IDReferralLevels() && !(CIdentity::LookupIdentity(newName.referral, priorHeightOut - 1).IsValid()))
- {
- // invalid referral identity
- return state.Error("Invalid referral identity specified");
- }
+ if (!newName.referral.IsNull() && issuingChain.IDReferralLevels() && !(CIdentity::LookupIdentity(newName.referral, commitmentHeight).IsValid()))
+ {
+ // invalid referral identity
+ return state.Error("Invalid referral identity specified");
}
CReserveTransactionDescriptor rtxd(tx, view, height);
for (auto &dest : dests)
{
uint160 oneDestID;
- if (dest.which() == COptCCParams::ADDRTYPE_ID && (oneDestID = GetDestinationID(dest)) != thisID && !CIdentity::LookupIdentity(CIdentityID(oneDestID)).IsValid())
+ if (dest.which() == COptCCParams::ADDRTYPE_ID &&
+ (oneDestID = GetDestinationID(dest)) != thisID &&
+ !CIdentity::LookupIdentity(CIdentityID(oneDestID)).IsValid())
{
return state.Error("Destination includes invalid identity");
}