@@ -4635,40 +4635,69 @@ GRC::MintSummary CBlock::GetMint() const EXCLUSIVE_LOCKS_REQUIRED(cs_main)
4635
4635
}
4636
4636
4637
4637
// !
4638
- // ! \brief Used in GRC::MRCContractHandler::Validate
4639
- // ! \param tx The MRC request transaction
4640
- // ! \param mrc The MRC contract
4638
+ // ! \brief Used in GRC::MRCContractHandler::Validate (essentially AcceptToMemoryPool)
4639
+ // ! \param contract The contract that contains the MRC
4640
+ // ! \param tx The transaction that contains the contract
4641
4641
// ! \return true if successfully validated
4642
4642
// !
4643
- bool ValidateMRC (const CTransaction& tx , const GRC::MRC& mrc )
4643
+ bool ValidateMRC (const GRC::Contract& contract , const CTransaction& tx )
4644
4644
{
4645
- const int64_t & mrc_time = tx.nTime ;
4645
+ // The MRC transaction should only have one contract on it, and the contract type should be MRC (which we already
4646
+ // know to arrive at this virtual method implementation).
4647
+ if (tx.GetContracts ().size () != 1 ) {
4648
+ return error (" %s: Validation failed: The transaction, hash %s, that contains the MRC has more than one contract." ,
4649
+ __func__,
4650
+ tx.GetHash ().GetHex ());
4651
+ }
4646
4652
4647
- const GRC::CpidOption cpid = mrc.m_mining_id .TryCpid ();
4653
+ // Check that the burn in the contract is equal or greater than the required burn.
4654
+ CAmount burn_amount = 0 ;
4648
4655
4649
- // No Cpid, the MRC must be invalid.
4650
- if (!cpid) return error (" %s: Validation failed: MRC has no CPID." );
4651
-
4652
- // Check to ensure the beacon was active at the transaction time of the MRC and the MRC signature. This also
4653
- // checks the signature using the block hash in the mrc itself. This is done for the ContractHandler::Validate whereas
4654
- // the stronger form is done in the ConnectBlock using the overloaded version below.
4655
- // If this fails, no point in going further.
4656
- if (const GRC::BeaconOption beacon = GRC::GetBeaconRegistry ().TryActive (*cpid, mrc_time)) {
4657
- if (!mrc.VerifySignature (
4658
- beacon->m_public_key ,
4659
- mrc.m_last_block_hash )) {
4660
- return error (" %s: Validation failed: MRC signature validation failed for MRC for CPID %s." ,
4661
- __func__,
4662
- cpid->ToString ()
4663
- );
4656
+ for (const auto & output : tx.vout ) {
4657
+ if (output.scriptPubKey == (CScript () << OP_RETURN)) {
4658
+ burn_amount += output.nValue ;
4664
4659
}
4665
- } else {
4666
- return error (" %s: Validation failed: The beacon for the cpid %s referred to in the MRC is not active." ,
4660
+ }
4661
+
4662
+ GRC::MRC mrc = contract.CopyPayloadAs <GRC::MRC>();
4663
+
4664
+ LogPrintf (" INFO: %s: mrc m_client_version = %s, m_fee = %s, m_last_block_hash = %s, m_magnitude = %u, "
4665
+ " m_magnitude_unit = %f, m_mining_id = %s, m_organization = %s, m_research_subsidy = %s, "
4666
+ " m_version = %s" ,
4667
+ __func__,
4668
+ mrc.m_client_version ,
4669
+ FormatMoney (mrc.m_fee ),
4670
+ mrc.m_last_block_hash .GetHex (),
4671
+ mrc.m_magnitude ,
4672
+ mrc.m_magnitude_unit ,
4673
+ mrc.m_mining_id .ToString (),
4674
+ mrc.m_organization ,
4675
+ FormatMoney (mrc.m_research_subsidy ),
4676
+ mrc.m_version );
4677
+
4678
+ if (burn_amount < mrc.RequiredBurnAmount ()) {
4679
+ return error (" %s: Burn amount of %s in mrc contract is less than the required %s." ,
4667
4680
__func__,
4668
- cpid->ToString ()
4681
+ FormatMoney (mrc.m_fee ),
4682
+ FormatMoney (mrc.RequiredBurnAmount ())
4669
4683
);
4670
4684
}
4671
4685
4686
+ // If the mrc last block hash is not pindexBest's block hash return false, because MRC requests can only be valid
4687
+ // in the mempool if they refer to the head of the current chain.
4688
+ if (pindexBest->GetBlockHash () != mrc.m_last_block_hash ) {
4689
+ return error (" %s: Validation failed: MRC m_last_block_hash %s cannot be found in the chain." ,
4690
+ __func__,
4691
+ mrc.m_last_block_hash .GetHex ());
4692
+ }
4693
+
4694
+ const GRC::CpidOption cpid = mrc.m_mining_id .TryCpid ();
4695
+
4696
+ // No Cpid, the MRC must be invalid.
4697
+ if (!cpid) return error (" %s: Validation failed: MRC has no CPID." );
4698
+
4699
+ int64_t mrc_time = pindexBest->nTime ;
4700
+
4672
4701
// We are not going to even accept MRC transactions to the memory pool that have a payment interval less than
4673
4702
// MRCZeroPaymentInterval / 2. This is to prevent a rogue actor from trying to fill slots in a DoS to rightful
4674
4703
// MRC recipients.
@@ -4677,11 +4706,7 @@ bool ValidateMRC(const CTransaction& tx, const GRC::MRC& mrc)
4677
4706
const GRC::ResearchAccount& account = GRC::Tally::GetAccount (*cpid);
4678
4707
const int64_t last_reward_time = account.LastRewardTime ();
4679
4708
4680
- // Here we are using the nTime of the transaction here instead of the block time of the last block.
4681
- // Note that tx.nTime is > last_block.nTime, so this is a little looser than
4682
- // last_block.nTime - last_reward_time < reject_payment_interval, but that is ok, because we are using
4683
- // half of the MRCZeroPaymentInterval.
4684
- const int64_t payment_interval = tx.nTime - last_reward_time;
4709
+ const int64_t payment_interval = mrc_time - last_reward_time;
4685
4710
4686
4711
if (payment_interval < reject_payment_interval) {
4687
4712
return error (" %s: Validation failed: MRC payment interval by tx time, %" PRId64 " sec, is less than 1/2 of the MRC "
@@ -4691,6 +4716,10 @@ bool ValidateMRC(const CTransaction& tx, const GRC::MRC& mrc)
4691
4716
reject_payment_interval);
4692
4717
}
4693
4718
4719
+ // Note that the below overload of ValidateMRC repeats the check for a valid Cpid. It is low overhead and worth not
4720
+ // repeating a bunch of what would be common code to eliminate.
4721
+ ValidateMRC (pindexBest, mrc);
4722
+
4694
4723
// If we get here, return true.
4695
4724
return true ;
4696
4725
}
0 commit comments