diff --git a/src/init.cpp b/src/init.cpp
index b62b7e3c947..b71933530c5 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -459,6 +459,7 @@ void SetupServerArgs()
gArgs.AddArg("-masternode_operator=
", "Masternode operator address (default: empty)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-dummypos", "Flag to skip PoS-related checks (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-txnotokens", "Flag to force old tx serialization (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
+ gArgs.AddArg("-subsidytest", "Flag to enable new subsidy rules (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-anchorquorum", "Min quorum size (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-spv", "Enable SPV to bitcoin blockchain (default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-criminals", "punishment of criminal nodes (default: 0, regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
diff --git a/src/masternodes/govvariables/lp_daily_dfi_reward.cpp b/src/masternodes/govvariables/lp_daily_dfi_reward.cpp
index cc382ad6fa6..2a3c603439a 100644
--- a/src/masternodes/govvariables/lp_daily_dfi_reward.cpp
+++ b/src/masternodes/govvariables/lp_daily_dfi_reward.cpp
@@ -18,8 +18,12 @@ UniValue LP_DAILY_DFI_REWARD::Export() const {
return ValueFromAmount(dailyReward);
}
-Res LP_DAILY_DFI_REWARD::Validate(const CCustomCSView &) const
+Res LP_DAILY_DFI_REWARD::Validate(const CCustomCSView & view) const
{
+ if (view.GetLastHeight() >= static_cast(Params().GetConsensus().EunosHeight)) {
+ return Res::Err("Cannot be set manually after Eunos hard fork");
+ }
+
// nothing to do
return Res::Ok();
}
diff --git a/src/validation.cpp b/src/validation.cpp
index d30e1ad34cd..7464fa446e7 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1131,14 +1131,15 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
CAmount nSubsidy = consensusParams.baseBlockSubsidy;
- if (Params().NetworkIDString() != CBaseChainParams::REGTEST || consensusParams.EunosHeight == 1)
+ if (Params().NetworkIDString() != CBaseChainParams::REGTEST ||
+ (Params().NetworkIDString() == CBaseChainParams::REGTEST && gArgs.GetBoolArg("-subsidytest", false)))
{
if (nHeight >= consensusParams.EunosHeight)
{
nSubsidy = consensusParams.newBaseBlockSubsidy;
const size_t reductions = (nHeight - consensusParams.EunosHeight) / consensusParams.emissionReductionPeriod;
- // See if we already have thie reduction calculated and return if found.
+ // See if we already have this reduction calculated and return if found.
if (subsidyReductions.find(reductions) != subsidyReductions.end())
{
return subsidyReductions[reductions];
@@ -2085,7 +2086,18 @@ void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height)
for (const auto& kv : Params().GetConsensus().newNonUTXOSubsidies)
{
CAmount subsidy = CalculateCoinbaseReward(blockReward, kv.second);
- mnview.SubCommunityBalance(kv.first, subsidy);
+
+ // Remove Swap, Futures and Options balances from Unallocated
+ if (kv.first == CommunityAccountType::Swap ||
+ kv.first == CommunityAccountType::Futures ||
+ kv.first == CommunityAccountType::Options)
+ {
+ mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy);
+ }
+ else
+ {
+ mnview.SubCommunityBalance(kv.first, subsidy);
+ }
}
}
else
@@ -2571,6 +2583,27 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// make all changes to the new cache/snapshot to make it possible to take a diff later:
CCustomCSView cache(mnview);
+ // Hard coded LP_DAILY_DFI_REWARD change
+ if (pindex->nHeight >= chainparams.GetConsensus().EunosHeight)
+ {
+ const auto& incentivePair = chainparams.GetConsensus().newNonUTXOSubsidies.find(CommunityAccountType::IncentiveFunding);
+ if (incentivePair != chainparams.GetConsensus().newNonUTXOSubsidies.end())
+ {
+ CAmount subsidy = CalculateCoinbaseReward(GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()), incentivePair->second);
+ // Change daily LP reward if it has changed
+ auto var = cache.GetVariable(LP_DAILY_DFI_REWARD::TypeName());
+ if (var) {
+ // Cast to avoid UniValue in GovVariable Export/Import
+ auto lpVar = dynamic_cast(var.get());
+ if (lpVar && lpVar->dailyReward != subsidy) {
+ lpVar->dailyReward = subsidy;
+ lpVar->Apply(cache, pindex->nHeight);
+ cache.SetVariable(*lpVar);
+ }
+ }
+ }
+ }
+
// hardfork commissions update
CAmount distributed = cache.UpdatePoolRewards(
[&](CScript const & owner, DCT_ID tokenID) {
diff --git a/test/functional/feature_burn_address.py b/test/functional/feature_burn_address.py
index 0e3432022f6..21fb7f1ab6b 100755
--- a/test/functional/feature_burn_address.py
+++ b/test/functional/feature_burn_address.py
@@ -106,10 +106,8 @@ def run_test(self):
assert_equal(result[0]['type'], 'AccountToAccount')
assert_equal(result[0]['amounts'][0], '1.00000000@DFI')
- # Auto auth from failed accounttoaccount
- assert_equal(result[1]['owner'], 'mfburnZSAM7Gs1hpDeNaMotJXSGA7edosG')
- assert_equal(result[1]['type'], 'None')
- assert_equal(result[1]['amounts'][0], '0.99988640@DFI')
+ # Auto auth burnt amount
+ auth_burn_amount = result[1]['amounts'][0][0:10]
# Send to burn address with accounttoutxos
self.nodes[0].accounttoutxos(funded_address, {burn_address:"2@0"})
@@ -150,7 +148,7 @@ def run_test(self):
# Test output of getburninfo
result = self.nodes[0].getburninfo()
assert_equal(result['address'], burn_address)
- assert_equal(result['amount'], Decimal('12.99988640'))
+ assert_equal(result['amount'], Decimal('12.00000000') + Decimal(auth_burn_amount))
assert_equal(result['tokens'][0], '1.00000000@DFI')
assert_equal(result['tokens'][1], '100.00000000@GOLD#128')
assert_equal(result['feeburn'], Decimal('2.00000000'))
diff --git a/test/functional/feature_dfip8_communitybalances.py b/test/functional/feature_dfip8_communitybalances.py
index 51518dc0af6..d6dc703dca7 100644
--- a/test/functional/feature_dfip8_communitybalances.py
+++ b/test/functional/feature_dfip8_communitybalances.py
@@ -14,10 +14,9 @@ class Dfip8Test(DefiTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
- self.extra_args = [['-txnotokens=0', '-amkheight=1', '-eunosheight=1']]
+ self.extra_args = [['-txnotokens=0', '-amkheight=1', '-eunosheight=1', '-subsidytest=1']]
def run_test(self):
-
self.nodes[0].generate(1)
result = self.nodes[0].listcommunitybalances()
@@ -76,6 +75,35 @@ def run_test(self):
assert_equal(getblock['nonutxo'][0]['IncentiveFunding'], Decimal('101.37356916'))
assert_equal(getblock['nonutxo'][0]['Burnt'], Decimal('144.55193810'))
+ # Invalidate a block and test rollback
+ self.nodes[0].invalidateblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))
+ result = self.nodes[0].listcommunitybalances()
+
+ assert_equal(result['AnchorReward'], Decimal('12.23086488'))
+ assert_equal(result['IncentiveFunding'], Decimal('15563.77556916'))
+ assert_equal(result['Burnt'], Decimal('22192.90433810'))
+
+ getblock = self.nodes[0].getblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))
+
+ assert_equal(getblock['nonutxo'][0]['AnchorReward'], Decimal('0.07966488'))
+ assert_equal(getblock['nonutxo'][0]['IncentiveFunding'], Decimal('101.37356916'))
+ assert_equal(getblock['nonutxo'][0]['Burnt'], Decimal('144.55193810'))
+
+ #Go forward again to first reduction
+ self.nodes[0].generate(1)
+
+ result = self.nodes[0].listcommunitybalances()
+
+ assert_equal(result['AnchorReward'], Decimal('12.31052976'))
+ assert_equal(result['IncentiveFunding'], Decimal('15665.14913832'))
+ assert_equal(result['Burnt'], Decimal('22337.45627620'))
+
+ getblock = self.nodes[0].getblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))
+
+ assert_equal(getblock['nonutxo'][0]['AnchorReward'], Decimal('0.07966488'))
+ assert_equal(getblock['nonutxo'][0]['IncentiveFunding'], Decimal('101.37356916'))
+ assert_equal(getblock['nonutxo'][0]['Burnt'], Decimal('144.55193810'))
+
# Ten reductions plus one
self.nodes[0].generate(1502 - self.nodes[0].getblockcount())
diff --git a/test/functional/feature_poolswap_mechanism.py b/test/functional/feature_poolswap_mechanism.py
index d6158e0dd2e..937ff26dcc2 100755
--- a/test/functional/feature_poolswap_mechanism.py
+++ b/test/functional/feature_poolswap_mechanism.py
@@ -25,9 +25,9 @@ def set_test_params(self):
# node2: revert create (all)
self.setup_clean_chain = True
self.extra_args = [
- ['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120'],
- ['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120'],
- ['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120']
+ ['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120', '-subsidytest=1'],
+ ['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120', '-subsidytest=1'],
+ ['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120', '-subsidytest=1']
]
# SET parameters for create tokens and pools
@@ -71,6 +71,7 @@ def create_token(self, symbol, address):
"collateralAddress": address
}, [])
self.nodes[0].generate(1)
+ self.sync_blocks()
self.tokens.append(symbol)
def create_pool(self, tokenA, tokenB, owner):
@@ -82,6 +83,7 @@ def create_pool(self, tokenA, tokenB, owner):
"ownerAddress": owner
}, []))
self.nodes[0].generate(1)
+ self.sync_blocks()
def create_pools(self, owner):
for i in range(self.COUNT_POOLS):
@@ -100,6 +102,7 @@ def mint_tokens(self, owner):
self.nodes[0].generate(1)
self.nodes[0].minttokens(mint_amount + "@" + self.get_id_token(item), [])
self.nodes[0].generate(1)
+ self.sync_blocks()
return mint_amount
def send_tokens(self, owner):
@@ -117,6 +120,7 @@ def send_tokens(self, owner):
self.nodes[0].generate(1)
self.nodes[0].accounttoaccount(owner, outputs, [])
self.nodes[0].generate(1)
+ self.sync_blocks()
def add_pools_liquidity(self, owner):
for item in range(self.COUNT_POOLS):
@@ -143,6 +147,7 @@ def add_pools_liquidity(self, owner):
self.accounts[idx]: [amountA, amountB]
}, self.accounts[idx], [])
self.nodes[0].generate(1)
+ self.sync_blocks()
def slope_swap(self, unswapped, poolFrom, poolTo):
swapped = poolTo - (poolTo * poolFrom / (poolFrom + unswapped))
@@ -151,7 +156,7 @@ def slope_swap(self, unswapped, poolFrom, poolTo):
return (poolFrom, poolTo)
- def poolswap(self):
+ def poolswap(self, nodes):
for item in range(self.COUNT_POOLS):
tokenA = "GOLD" + str(item)
tokenB = "SILVER" + str(item)
@@ -165,6 +170,7 @@ def poolswap(self):
for idx in range(start, end):
self.nodes[0].sendmany("", { self.accounts[idx] : 0.02 })
self.nodes[0].generate(1)
+ self.sync_blocks(nodes)
amount = random.randint(1, self.AMOUNT_TOKEN // 2)
amountsB = {}
@@ -187,6 +193,7 @@ def poolswap(self):
"tokenTo": str(self.get_id_token(tokenA)),
}, [])
self.nodes[0].generate(1)
+ self.sync_blocks(nodes)
for idx in range(start, end):
liquidity = self.nodes[0].getaccount(self.accounts[idx], {}, True)[idPool]
@@ -222,10 +229,9 @@ def run_test(self):
print("Generating initial chain...")
self.nodes[0].generate(100)
- self.sync_all()
-
owner = self.nodes[0].getnewaddress("", "legacy")
self.nodes[0].generate(1)
+ self.sync_blocks()
# START
#========================
@@ -280,6 +286,7 @@ def run_test(self):
self.nodes[0].setgov({ "LP_SPLITS": obj })
self.nodes[0].setgov({ "LP_DAILY_DFI_REWARD": self.LP_DAILY_DFI_REWARD })
self.nodes[0].generate(1)
+ self.sync_blocks()
g1 = self.nodes[0].getgov("LP_SPLITS")
for i in range(self.COUNT_POOLS):
@@ -294,7 +301,8 @@ def run_test(self):
print("Swapping tokens...")
start_time = time.time()
- self.poolswap()
+ nodes = self.nodes[0:2]
+ self.poolswap(nodes)
end_time = time.time() - start_time
print("Tokens exchanged")
print("Elapsed time: {} s".format(end_time))
@@ -309,8 +317,12 @@ def run_test(self):
self.sync_blocks()
assert(self.nodes[0].getblockcount() == 120) # eunos
+
+ self.LP_DAILY_DFI_REWARD = self.nodes[0].getgov("LP_DAILY_DFI_REWARD")['LP_DAILY_DFI_REWARD']
+ assert_equal(self.LP_DAILY_DFI_REWARD, Decimal('103.08268000'))
+
print("Swapping tokens after eunos height...")
- self.poolswap()
+ self.poolswap(self.nodes)
if __name__ == '__main__':
diff --git a/test/functional/feature_setgov.py b/test/functional/feature_setgov.py
index f85334ff3f8..0345ea263a3 100755
--- a/test/functional/feature_setgov.py
+++ b/test/functional/feature_setgov.py
@@ -12,7 +12,7 @@
from test_framework.authproxy import JSONRPCException
from test_framework.util import \
- connect_nodes, disconnect_nodes
+ connect_nodes, disconnect_nodes, assert_equal
from decimal import Decimal
@@ -21,16 +21,11 @@ def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
self.extra_args = [
- ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50'],
- ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50']]
+ ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-eunosheight=200', '-subsidytest=1'],
+ ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-eunosheight=200', '-subsidytest=1']]
def run_test(self):
- # fast check for debug
- print (self.nodes[0].getgov("LP_SPLITS"))
- print (self.nodes[0].getgov("LP_DAILY_DFI_REWARD"))
- # return
-
print("Generating initial chain...")
self.setup_tokens()
@@ -200,6 +195,35 @@ def run_test(self):
and pool2['rewardPct'] == Decimal('0.40000000')
and pool3['rewardPct'] == Decimal('0.10000000'))
+ # Generate to Eunos hard fork
+ self.nodes[0].clearmempool()
+ self.nodes[0].generate(200 - self.nodes[0].getblockcount())
+
+ # Try and set LP_DAILY_DFI_REWARD manually
+ try:
+ self.nodes[0].setgov({ "LP_DAILY_DFI_REWARD": 100})
+ except JSONRPCException as e:
+ errorString = e.error['message']
+ assert("Cannot be set manually after Eunos hard fork" in errorString)
+
+ # Check new subsidy
+ assert_equal(self.nodes[0].getgov('LP_DAILY_DFI_REWARD')['LP_DAILY_DFI_REWARD'], Decimal('103.08268000'))
+
+ # Roll back
+ self.nodes[0].invalidateblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))
+
+ # Check subsidy restored
+ assert_equal(self.nodes[0].getgov('LP_DAILY_DFI_REWARD')['LP_DAILY_DFI_REWARD'], Decimal('35.50000000'))
+
+ # Move to second reduction and check reward
+ self.nodes[0].generate(151)
+ assert_equal(self.nodes[0].getgov('LP_DAILY_DFI_REWARD')['LP_DAILY_DFI_REWARD'], Decimal('101.37356916'))
+
+ # Rollback from second reduction
+ self.nodes[0].invalidateblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))
+
+ # Check subsidy restored
+ assert_equal(self.nodes[0].getgov('LP_DAILY_DFI_REWARD')['LP_DAILY_DFI_REWARD'], Decimal('103.08268000'))
if __name__ == '__main__':
GovsetTest ().main ()