Skip to content
Merged

Hf3 #14

Show file tree
Hide file tree
Changes from all commits
Commits
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/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ struct Params {
uint32_t exploit_fix_2_height = 0;
/** Exploit fix 3 */
uint32_t exploit_fix_3_time = 0xffffffff;
/** Time dev fund is removed and inflation reduced */
uint32_t inflation_adjust_time = 0xffffffff;
/** Last prefork anonoutput index */
int64_t m_frozen_anon_index = 0;
/** Last block height of prefork blinded txns */
Expand Down
3 changes: 2 additions & 1 deletion src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
if (nRingCTOutputs > 0 || nCTOutputs > 0) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-frozen-blinded-out");
}
if (spends_tainted_blinded && nPlainValueOut + txfee > state.m_consensus_params->m_max_tainted_value_out) {
if (spends_tainted_blinded &&
(state.m_exploit_fix_3 || nPlainValueOut + txfee > state.m_consensus_params->m_max_tainted_value_out)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-frozen-blinded-too-large");
}
/* TODO? Limit to spending one frozen output at a time
Expand Down
3 changes: 3 additions & 0 deletions src/consensus/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class ValidationState
bool m_clamp_tx_version = false;
bool m_exploit_fix_1 = false;
bool m_exploit_fix_2 = false;
bool m_exploit_fix_3{false}; // inflation_adjust_time
bool m_in_block = false;
bool m_check_equal_rct_txid = true;
bool m_punish_for_duplicates = false;
Expand All @@ -204,6 +205,7 @@ class ValidationState
m_clamp_tx_version = time >= consensusParams.clamp_tx_version_time;
m_exploit_fix_1 = time >= consensusParams.exploit_fix_1_time;
m_exploit_fix_2 = time >= consensusParams.exploit_fix_2_time;
m_exploit_fix_3 = time >= consensusParams.inflation_adjust_time;
if (m_in_block && m_time < 1632177542) {
m_check_equal_rct_txid = false;
}
Expand All @@ -229,6 +231,7 @@ class ValidationState
m_clamp_tx_version = state_from.m_clamp_tx_version;
m_exploit_fix_1 = state_from.m_exploit_fix_1;
m_exploit_fix_2 = state_from.m_exploit_fix_2;
m_exploit_fix_3 = state_from.m_exploit_fix_3;
m_check_equal_rct_txid = state_from.m_check_equal_rct_txid;
m_punish_for_duplicates = state_from.m_punish_for_duplicates;
}
Expand Down
14 changes: 12 additions & 2 deletions src/kernel/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,16 @@ int64_t CChainParams::GetCoinYearReward(int64_t nTime) const
static const int64_t nSecondsInYear = 365 * 24 * 60 * 60;

if (GetChainType() != ChainType::REGTEST) {
// After HF2: 8%, 8%, 7%, 7%, 6%
if (nTime >= consensus.inflation_adjust_time) {
// After HF3: 3.5, 3.0 .. 1.5, 1.0
int64_t nPeriodsSinceHF3 = (nTime - consensus.inflation_adjust_time) / nSecondsInYear;
if (nPeriodsSinceHF3 >= 0 && nPeriodsSinceHF3 < 6) {
return (7 - nPeriodsSinceHF3) * (CENT / 2);
}
return 1 * CENT;
}
if (nTime >= consensus.exploit_fix_2_time) {
// After HF2: 8%, 8%, 7%, 7%, 6%
int64_t nPeriodsSinceHF2 = (nTime - consensus.exploit_fix_2_time) / (nSecondsInYear * 2);
if (nPeriodsSinceHF2 >= 0 && nPeriodsSinceHF2 < 2) {
return (8 - nPeriodsSinceHF2) * CENT;
Expand Down Expand Up @@ -526,6 +534,7 @@ class CMainParams : public CChainParams {
consensus.clamp_tx_version_time = 1643734800; // 2022-02-01 17:00:00 UTC
consensus.exploit_fix_3_time = 1643734800; // 2022-02-01 17:00:00 UTC
consensus.m_taproot_time = 1643734800; // 2022-02-01 17:00:00 UTC
consensus.inflation_adjust_time = 1769947200; // 2026-02-01 12:00:00 UTC

consensus.m_frozen_anon_index = 27340;
consensus.m_frozen_blinded_height = 884433;
Expand Down Expand Up @@ -610,7 +619,8 @@ class CMainParams : public CChainParams {
particl::TreasuryFundSettings("RBiiQBnQsVPPQkUaJVQTjsZM9K2xMKozST", 10, 60));
vTreasuryFundSettings.emplace_back(consensus.exploit_fix_2_time,
particl::TreasuryFundSettings("RQYUDd3EJohpjq62So4ftcV5XZfxZxJPe9", 50, 650));

vTreasuryFundSettings.emplace_back(consensus.inflation_adjust_time,
particl::TreasuryFundSettings("RQYUDd3EJohpjq62So4ftcV5XZfxZxJPe9", 0, 650, 1 * COIN));

base58Prefixes[PUBKEY_ADDRESS] = {0x38}; // P
base58Prefixes[SCRIPT_ADDRESS] = {0x3c};
Expand Down
3 changes: 3 additions & 0 deletions src/kernel/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ class TreasuryFundSettings
public:
TreasuryFundSettings(std::string sAddrTo, int nMinTreasuryStakePercent_, int nTreasuryOutputPeriod_)
: sTreasuryFundAddresses(sAddrTo), nMinTreasuryStakePercent(nMinTreasuryStakePercent_), nTreasuryOutputPeriod(nTreasuryOutputPeriod_) {};
TreasuryFundSettings(std::string sAddrTo, int nMinTreasuryStakePercent_, int nTreasuryOutputPeriod_, CAmount nMinPayoutAmount_)
: sTreasuryFundAddresses(sAddrTo), nMinTreasuryStakePercent(nMinTreasuryStakePercent_), nTreasuryOutputPeriod(nTreasuryOutputPeriod_), nMinPayoutAmount(nMinPayoutAmount_) {};

std::string sTreasuryFundAddresses;
int nMinTreasuryStakePercent; // [0, 100]
int nTreasuryOutputPeriod; // treasury fund output is created every n blocks
CAmount nMinPayoutAmount{0};
};
} // namespace particl

Expand Down
20 changes: 13 additions & 7 deletions src/rpc/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ static RPCHelpMan pushtreasuryfundsetting()
{"fundaddress", RPCArg::Type::STR, RPCArg::Optional::NO, "Address accumulated treasury fund coin is paid out to"},
{"minstakepercent", RPCArg::Type::NUM, RPCArg::Optional::NO, "Minimum percentage of the block reward allocated to treasury fund"},
{"outputperiod", RPCArg::Type::NUM, RPCArg::Optional::NO, "Blocks between treasury fund outputs"},
{"minpayoutvalue", RPCArg::Type::AMOUNT, RPCArg::Default{0}, "Minimum payment output value. Skip payment if treasury amount is less than."},
},
},
},
Expand All @@ -107,22 +108,27 @@ static RPCHelpMan pushtreasuryfundsetting()
if (!Params().IsMockableChain()) {
throw std::runtime_error("pushtreasuryfundsetting is for regression testing (-regtest mode) only");
}
const UniValue &setting = request.params[0].get_obj();
RPCTypeCheckObj(setting,
const UniValue &options = request.params[0].get_obj();
RPCTypeCheckObj(options,
{
{"timefrom", UniValueType(UniValue::VNUM)},
{"fundaddress", UniValueType(UniValue::VSTR)},
{"minstakepercent", UniValueType(UniValue::VNUM)},
{"outputperiod", UniValueType(UniValue::VNUM)},
});
}, false /* allow null */, false /* strict */);

LOCK(cs_main);

particl::TreasuryFundSettings settings(setting["fundaddress"].get_str(), setting["minstakepercent"].getInt<int>(), setting["outputperiod"].getInt<int>());
RegtestParams().PushTreasuryFundSettings(setting["timefrom"].getInt<int>(), settings);
CAmount minpayoutvalue{0};
if (options.exists("minpayoutvalue")) {
minpayoutvalue = AmountFromValue(options["minpayoutvalue"]);
}

particl::TreasuryFundSettings settings(options["fundaddress"].get_str(), options["minstakepercent"].getInt<int>(), options["outputperiod"].getInt<int>(), minpayoutvalue);
RegtestParams().PushTreasuryFundSettings(options["timefrom"].getInt<int>(), settings);

LogPrintf("Added treasury fund setting from %d: (%s, %d, %d)\n",
setting["timefrom"].getInt<int>(), setting["fundaddress"].get_str(), setting["minstakepercent"].getInt<int>(), setting["outputperiod"].getInt<int>());
LogPrintf("Added treasury fund setting from %d: (%s, %d, %d, %d)\n",
options["timefrom"].getInt<int>(), options["fundaddress"].get_str(), options["minstakepercent"].getInt<int>(), options["outputperiod"].getInt<int>(), minpayoutvalue);

return NullUniValue;
},
Expand Down
1 change: 1 addition & 0 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{RPCResult::Type::STR_HEX, "data_hex", /*optional=*/true, "Data component"},
{RPCResult::Type::STR_AMOUNT, "ct_fee", /*optional=*/true, "data - SMSG confidential transaction fee"},
{RPCResult::Type::STR_AMOUNT, "smsgfeerate", /*optional=*/true, "data - SMSG fee rate"},
{RPCResult::Type::STR_AMOUNT, "treasury_fund_cfwd", /*optional=*/true, "data - Treasury fund carried forward"},
{RPCResult::Type::STR_HEX, "smsgdifficulty", /*optional=*/true, "data - SMSG difficulty"},
{RPCResult::Type::STR, "vote", /*optional=*/true, "data - Voting entry"},
{RPCResult::Type::STR_HEX, "pubkey", /*optional=*/true, "pubkey for anon output"},
Expand Down
19 changes: 18 additions & 1 deletion src/test/particlchain_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,24 @@ BOOST_AUTO_TEST_CASE(coin_year_reward)
BOOST_CHECK(Params().GetCoinYearReward(1626109200 + seconds_in_year * 3) == 7 * CENT);
BOOST_CHECK(Params().GetCoinYearReward(1626109200 + seconds_in_year * 4 - 1) == 7 * CENT);
BOOST_CHECK(Params().GetCoinYearReward(1626109200 + seconds_in_year * 4) == 6 * CENT); // 2025-07-11 17:00:00 UTC
BOOST_CHECK(Params().GetCoinYearReward(1626109200 + seconds_in_year * 6) == 6 * CENT);

int64_t hf3_time = Params().GetConsensus().inflation_adjust_time;
BOOST_CHECK(Params().GetCoinYearReward(hf3_time - 1) == 6 * CENT);
auto check_rate_at_time = [&](int64_t time, CAmount expect_value, const char *expect_time_str = nullptr) {
BOOST_CHECK_EQUAL(Params().GetCoinYearReward(time), expect_value);
if (expect_time_str) {
BOOST_CHECK_EQUAL(FormatISO8601DateTime(time), expect_time_str);
}
};
check_rate_at_time(hf3_time - 1, 6 * CENT);
check_rate_at_time(hf3_time, 3.5 * CENT, "2026-02-01T12:00:00Z");
check_rate_at_time(hf3_time + seconds_in_year * 1 - 1, 3.5 * CENT);
check_rate_at_time(hf3_time + seconds_in_year * 1, 3 * CENT, "2027-02-01T12:00:00Z");
check_rate_at_time(hf3_time + seconds_in_year * 2, 2.5 * CENT, "2028-02-01T12:00:00Z");
check_rate_at_time(hf3_time + seconds_in_year * 3, 2 * CENT, "2029-01-31T12:00:00Z");
check_rate_at_time(hf3_time + seconds_in_year * 4, 1.5 * CENT, "2030-01-31T12:00:00Z");
check_rate_at_time(hf3_time + seconds_in_year * 5, 1 * CENT, "2031-01-31T12:00:00Z");
check_rate_at_time(hf3_time + seconds_in_year * 6, 1 * CENT, "2032-01-31T12:00:00Z");
}

BOOST_AUTO_TEST_CASE(taproot)
Expand Down
10 changes: 5 additions & 5 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3327,7 +3327,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
}
}

if (!pTreasuryFundSettings || pTreasuryFundSettings->nMinTreasuryStakePercent <= 0) {
if (!pTreasuryFundSettings || pTreasuryFundSettings->nMinTreasuryStakePercent < 0) {
if (nStakeReward < 0 || nStakeReward > nCalculatedStakeReward) {
LogPrintf("ERROR: %s: Coinstake pays too much(actual=%d vs calculated=%d)\n", __func__, nStakeReward, nCalculatedStakeReward);
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cs-amount");
Expand Down Expand Up @@ -3356,7 +3356,8 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
}
}

if (pindex->nHeight % pTreasuryFundSettings->nTreasuryOutputPeriod == 0) {
if (pindex->nHeight % pTreasuryFundSettings->nTreasuryOutputPeriod == 0 &&
nTreasuryBfwd >= pTreasuryFundSettings->nMinPayoutAmount) {
// Fund output must exist and match cfwd, cfwd data output must be unset
// nStakeReward must == nTreasuryBfwd + nCalculatedStakeReward

Expand Down Expand Up @@ -3394,20 +3395,19 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// Ensure cfwd data output is correct and nStakeReward is <= nHolderPart
// cfwd must == nTreasuryBfwd + (nCalculatedStakeReward - nStakeReward) // Allowing users to set a higher split

CAmount nTreasuryCfwd = nTreasuryBfwd + nCalculatedStakeReward - nStakeReward;
if (nStakeReward < 0 || nStakeReward > nMaxHolderPart) {
LogPrintf("ERROR: %s: Bad stake-reward (actual=%d vs maxholderpart=%d)\n", __func__, nStakeReward, nMaxHolderPart);
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cs-amount");
}
CAmount nTreasuryCfwd = nTreasuryBfwd + nCalculatedStakeReward - nStakeReward;
if (!txCoinstake->GetTreasuryFundCfwd(nTreasuryCfwdCheck) ||
nTreasuryCfwdCheck != nTreasuryCfwd) {
LogPrintf("ERROR: %s: Coinstake treasury fund carried forward mismatch (actual=%d vs expected=%d)\n", __func__, nTreasuryCfwdCheck, nTreasuryCfwd);
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cs-cfwd");
}
}

particl::coinStakeCache.InsertCoinStake(blockHash, txCoinstake);
}
particl::coinStakeCache.InsertCoinStake(blockHash, txCoinstake);
} else {
if (blockHash != params.GetConsensus().hashGenesisBlock) {
LogPrintf("ERROR: %s: Block isn't coinstake or genesis.\n", __func__);
Expand Down
12 changes: 8 additions & 4 deletions src/wallet/hdwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11910,6 +11910,8 @@ void CHDWallet::AvailableBlindedCoins(std::vector<COutputR>& vCoins, const CCoin

vCoins.clear();

int64_t time_now = GetTime();

const int min_depth = {coinControl ? coinControl->m_min_depth : DEFAULT_MIN_DEPTH};
const int max_depth = {coinControl ? coinControl->m_max_depth : DEFAULT_MAX_DEPTH};
//const bool fIncludeImmature = {coinControl ? coinControl->m_include_immature : false}; // Blinded coins can't stake
Expand Down Expand Up @@ -12007,7 +12009,7 @@ void CHDWallet::AvailableBlindedCoins(std::vector<COutputR>& vCoins, const CCoin
}

if (spend_frozen && !include_tainted_frozen) {
if (r.nValue > consensusParams.m_max_tainted_value_out) {
if (time_now >= consensusParams.inflation_adjust_time || r.nValue > consensusParams.m_max_tainted_value_out) {
if (IsFrozenBlindOutput(txid)) {
continue;
}
Expand Down Expand Up @@ -12263,7 +12265,8 @@ void CHDWallet::AvailableAnonCoins(std::vector<COutputR> &vCoins, const CCoinCon
!stx.tx->vpout[r.n]->IsType(OUTPUT_RINGCT) ||
!chain().readRCTOutputLink(((CTxOutRingCT*)stx.tx->vpout[r.n].get())->pk, index) ||
IsBlacklistedAnonOutput(index) ||
(!IsWhitelistedAnonOutput(index, time_now, consensusParams) && r.nValue > consensusParams.m_max_tainted_value_out)) {
(!IsWhitelistedAnonOutput(index, time_now, consensusParams) &&
(time_now >= consensusParams.inflation_adjust_time || r.nValue > consensusParams.m_max_tainted_value_out))) {
continue;
}
}
Expand Down Expand Up @@ -13738,7 +13741,7 @@ bool CHDWallet::CreateCoinStake(unsigned int nBits, int64_t nTime, int nBlockHei
CTransactionRef txPrevCoinstake = nullptr;
CAmount nRewardOut;
const particl::TreasuryFundSettings *pTreasuryFundSettings = Params().GetTreasuryFundSettings(nTime);
if (!pTreasuryFundSettings || pTreasuryFundSettings->nMinTreasuryStakePercent <= 0) {
if (!pTreasuryFundSettings || pTreasuryFundSettings->nMinTreasuryStakePercent < 0) {
nRewardOut = nReward;
} else {
int64_t nStakeSplit = std::max(pTreasuryFundSettings->nMinTreasuryStakePercent, nWalletTreasuryFundCedePercent);
Expand All @@ -13759,7 +13762,8 @@ bool CHDWallet::CreateCoinStake(unsigned int nBits, int64_t nTime, int nBlockHei
}

CAmount nTreasuryCfwd = nTreasuryBfwd + nTreasuryPart;
if (nBlockHeight % pTreasuryFundSettings->nTreasuryOutputPeriod == 0) {
if (nBlockHeight % pTreasuryFundSettings->nTreasuryOutputPeriod == 0 &&
nTreasuryBfwd >= pTreasuryFundSettings->nMinPayoutAmount) {
// Place treasury fund output
OUTPUT_PTR<CTxOutStandard> outTreasurySplit = MAKE_OUTPUT<CTxOutStandard>();
outTreasurySplit->nValue = nTreasuryCfwd;
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/rpchdwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4490,6 +4490,7 @@ static RPCHelpMan getstakinginfo()
{RPCResult::Type::STR_AMOUNT, "reserve", /*optional=*/true, "The reserve balance of the wallet in " + CURRENCY_UNIT},
{RPCResult::Type::STR_AMOUNT, "wallettreasurydonationpercent", /*optional=*/true, "User set percentage of the block reward ceded to the treasury"},
{RPCResult::Type::STR_AMOUNT, "treasurydonationpercent", /*optional=*/true, "Network enforced percentage of the block reward ceded to the treasury"},
{RPCResult::Type::STR_AMOUNT, "treasurydonationminpayout", /*optional=*/true, "Minimum (brought forward) treasury amount to trigger payout."},
{RPCResult::Type::STR_AMOUNT, "minstakeablevalue", "The minimum value for an output to attempt staking in " + CURRENCY_UNIT},
{RPCResult::Type::NUM, "minstakeabledepth", "Minimum depth required in the chain for an output to stake"},
{RPCResult::Type::NUM, "currentblocksize", "The last approximate block size in bytes"},
Expand Down Expand Up @@ -4583,6 +4584,7 @@ static RPCHelpMan getstakinginfo()
const particl::TreasuryFundSettings *pTreasuryFundSettings = Params().GetTreasuryFundSettings(nTipTime);
if (pTreasuryFundSettings && pTreasuryFundSettings->nMinTreasuryStakePercent > 0) {
obj.pushKV("treasurydonationpercent", pTreasuryFundSettings->nMinTreasuryStakePercent);
obj.pushKV("treasurydonationminpayout", ValueFromAmount(pTreasuryFundSettings->nMinPayoutAmount));
}

obj.pushKV("minstakeablevalue", ValueFromAmount(pwallet->m_min_stakeable_value));
Expand Down
Loading
Loading