Skip to content

Commit

Permalink
Transfer burn address balances
Browse files Browse the repository at this point in the history
  • Loading branch information
Bushstar committed May 4, 2021
1 parent 41cf191 commit 89d0949
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ class CMainParams : public CChainParams {
}

consensus.burnAddress = GetScriptForDestination(DecodeDestination("8defichainBurnAddressXXXXXXXdRQkSm", *this));
consensus.retiredBurnAddress = GetScriptForDestination(DecodeDestination("8defichainDSTBurnAddressXXXXaCAuTq", *this));

genesis = CreateGenesisBlock(1587883831, 0x1d00ffff, 1, initdist, CreateGenesisMasternodes()); // old=1231006505
consensus.hashGenesisBlock = genesis.GetHash();
Expand Down Expand Up @@ -443,6 +444,7 @@ class CTestNetParams : public CChainParams {
initdist.push_back(CTxOut(100000000 * COIN, GetScriptForDestination(DecodeDestination("tahuMwb9eX83eJhf2vXL6NPzABy3Ca8DHi", *this))));

consensus.burnAddress = GetScriptForDestination(DecodeDestination("7DefichainBurnAddressXXXXXXXdMUE5n", *this));
consensus.retiredBurnAddress = GetScriptForDestination(DecodeDestination("7DefichainDSTBurnAddressXXXXXzS4Hi", *this));

genesis = CreateGenesisBlock(1586099762, 0x1d00ffff, 1, initdist, CreateGenesisMasternodes()); // old=1296688602
consensus.hashGenesisBlock = genesis.GetHash();
Expand Down Expand Up @@ -611,6 +613,7 @@ class CDevNetParams : public CChainParams {
initdist.push_back(CTxOut(100000000 * COIN, GetScriptForDestination(DecodeDestination("7LfqHbyh9dBQDjWB6MxcWvH2PBC5iY4wPa", *this))));

consensus.burnAddress = GetScriptForDestination(DecodeDestination("7DefichainBurnAddressXXXXXXXdMUE5n", *this));
consensus.retiredBurnAddress = GetScriptForDestination(DecodeDestination("7DefichainDSTBurnAddressXXXXXzS4Hi", *this));

genesis = CreateGenesisBlock(1585132338, 0x1d00ffff, 1, initdist, CreateGenesisMasternodes()); // old=1296688602
consensus.hashGenesisBlock = genesis.GetHash();
Expand Down Expand Up @@ -781,6 +784,7 @@ class CRegTestParams : public CChainParams {

// For testing send after Eunos: 93ViFmLeJVgKSPxWGQHmSdT5RbeGDtGW4bsiwQM2qnQyucChMqQ
consensus.burnAddress = GetScriptForDestination(DecodeDestination("mfburnZSAM7Gs1hpDeNaMotJXSGA7edosG", *this));
consensus.retiredBurnAddress = GetScriptForDestination(DecodeDestination("mfdefichainDSTBurnAddressXXXZcE1vs", *this));

genesis = CreateGenesisBlock(1579045065, 0x207fffff, 1, {
CTxOut(consensus.baseBlockSubsidy,
Expand Down
2 changes: 2 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ struct Params {
CAmount foundationShareDFIP1;
/** Trackable burn address */
CScript burnAddress;
/** Previous burn address to transfer tokens from */
CScript retiredBurnAddress;

/** Struct to hold percentages for coinbase distribution.
* Percentages are calculated out of 10000 */
Expand Down
63 changes: 62 additions & 1 deletion src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1791,6 +1791,41 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
}
}

// Remove burn balance transfers
if (pindex->nHeight == Params().GetConsensus().EunosHeight)
{
std::set<uint32_t> txOut;
auto shouldContinueToNextAccountHistory = [&txOut, block](AccountHistoryKey const & key, CLazySerialize<AccountHistoryValue> valueLazy) -> bool
{
if (key.owner != Params().GetConsensus().burnAddress) {
return false;
}

if (key.blockHeight != Params().GetConsensus().EunosHeight) {
return true;
}

const auto & value = valueLazy.get();

if (value.category != uint8_t(CustomTxType::AccountToAccount)) {
return true;
}

if (key.txn >= block.vtx.size()) {
txOut.insert(key.txn);
}

return true;
};

AccountHistoryKey startKey({Params().GetConsensus().burnAddress, static_cast<uint32_t>(Params().GetConsensus().EunosHeight), std::numeric_limits<uint32_t>::max()});
pburnHistoryDB->ForEachAccountHistory(shouldContinueToNextAccountHistory, startKey);

for (const auto& out : txOut) {
pburnHistoryDB->EraseAccountHistory({Params().GetConsensus().burnAddress, static_cast<uint32_t>(Params().GetConsensus().EunosHeight), out});
}
}

// Erase any UTXO burns
for (const auto& entries : eraseBurnEntries)
{
Expand Down Expand Up @@ -2461,7 +2496,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
{
if (tx.vout[j].scriptPubKey == Params().GetConsensus().burnAddress)
{
writeBurnEntries.push_back({{Params().GetConsensus().burnAddress, static_cast<uint32_t>(pindex->nHeight), i}, {block.vtx[i]->GetHash(), 0, {{DCT_ID{0}, tx.vout[j].nValue}}}});
writeBurnEntries.push_back({{Params().GetConsensus().burnAddress, static_cast<uint32_t>(pindex->nHeight), i},
{block.vtx[i]->GetHash(), static_cast<uint8_t>(CustomTxType::None), {{DCT_ID{0}, tx.vout[j].nValue}}}});
}
}

Expand Down Expand Up @@ -2561,6 +2597,31 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
cache.BayfrontFlagsCleanup();
}

// Move funds from old burn address to new one
if (pindex->nHeight == chainparams.GetConsensus().EunosHeight)
{
CBalances amounts;
cache.ForEachBalance([&amounts](CScript const & owner, CTokenAmount balance) {
if (owner != Params().GetConsensus().retiredBurnAddress) {
return false;
}

amounts.Add({balance.nTokenId, balance.nValue});

return true;
}, BalanceKey{chainparams.GetConsensus().retiredBurnAddress, DCT_ID{}});

cache.SubBalances(chainparams.GetConsensus().retiredBurnAddress, amounts);
cache.AddBalances(chainparams.GetConsensus().burnAddress, amounts);

// Add transfer as additional TX in block
size_t count{0};
for (const auto& entry : amounts.balances) {
pburnHistoryDB->WriteAccountHistory({Params().GetConsensus().burnAddress, static_cast<uint32_t>(pindex->nHeight), static_cast<uint32_t>(block.vtx.size() + count++)},
{uint256{}, static_cast<uint8_t>(CustomTxType::AccountToAccount), {{entry.first, entry.second}}});
}
}

// construct undo
auto& flushable = cache.GetStorage();
auto undo = CUndo::Construct(mnview.GetStorage(), flushable.GetRaw());
Expand Down
107 changes: 107 additions & 0 deletions test/functional/feature_eunos_balances.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2019 The Bitcoin Core developers
# Copyright (c) DeFi Blockchain Developers
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
"""Test burn address tracking"""

from test_framework.test_framework import DefiTestFramework

from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal

from decimal import Decimal

class TransferBurnTest(DefiTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
self.extra_args = [['-txnotokens=0', '-amkheight=1', '-eunosheight=200', '-dakotaheight=1']]

def run_test(self):

# Burn address
old_burn_address = "mfdefichainDSTBurnAddressXXXZcE1vs"
burn_address = "mfburnZSAM7Gs1hpDeNaMotJXSGA7edosG"

self.nodes[0].generate(101)

# Create funded account address
address = self.nodes[0].getnewaddress()
self.nodes[0].sendtoaddress(address, 1)
self.nodes[0].generate(1)

# Create tokens
self.nodes[0].createtoken({
"symbol": "GOLD",
"name": "shiny gold",
"collateralAddress": address
})
self.nodes[0].generate(1)

self.nodes[0].createtoken({
"symbol": "SILVER",
"name": "shiny silver",
"collateralAddress": address
})
self.nodes[0].generate(1)

# Mint tokens
self.nodes[0].minttokens(["100@128"])
self.nodes[0].generate(1)

self.nodes[0].minttokens(["100@129"])
self.nodes[0].generate(1)

# Send tokens to burn address
self.nodes[0].accounttoaccount(address, {old_burn_address:"100@128"})
self.nodes[0].generate(1)

self.nodes[0].accounttoaccount(address, {old_burn_address:"100@129"})
self.nodes[0].generate(1)

# Check balance
result = self.nodes[0].getaccount(old_burn_address)
assert_equal(result[0], "100.00000000@GOLD#128")
assert_equal(result[1], "100.00000000@SILVER#129")

# Move to fork height
self.nodes[0].generate(200 - self.nodes[0].getblockcount())

# Check funds have moved
assert_equal(len(self.nodes[0].getaccount(old_burn_address)), 0)
result = self.nodes[0].getaccount(burn_address)
assert_equal(result[0], "100.00000000@GOLD#128")
assert_equal(result[1], "100.00000000@SILVER#129")

result = self.nodes[0].listburnhistory()
assert_equal(result[0]['owner'], burn_address)
assert_equal(result[0]['type'], 'AccountToAccount')
assert_equal(result[0]['amounts'][0], '100.00000000@SILVER#129')
assert_equal(result[1]['owner'], burn_address)
assert_equal(result[1]['type'], 'AccountToAccount')
assert_equal(result[1]['amounts'][0], '100.00000000@GOLD#128')

result = self.nodes[0].getburnaddressinfo()
assert_equal(result['address'], burn_address)
assert_equal(result['amount'], Decimal('0.00000000'))
assert_equal(result['tokens'][0], '100.00000000@GOLD#128')
assert_equal(result['tokens'][1], '100.00000000@SILVER#129')

# Revert fork block
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(200))

assert_equal(len(self.nodes[0].getaccount(burn_address)), 0)
result = self.nodes[0].getaccount(old_burn_address)
assert_equal(result[0], "100.00000000@GOLD#128")
assert_equal(result[1], "100.00000000@SILVER#129")

assert_equal(len(self.nodes[0].listburnhistory()), 0)

result = self.nodes[0].getburnaddressinfo()
assert_equal(result['address'], burn_address)
assert_equal(result['amount'], Decimal('0.00000000'))
assert_equal(len(result['tokens']), 0)

if __name__ == '__main__':
TransferBurnTest().main()
1 change: 1 addition & 0 deletions test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@
'feature_oracles.py',
'rpc_getmininginfo.py',
'feature_burn_address.py',
'feature_eunos_balances.py',
# Don't append tests at the end to avoid merge conflicts
# Put them in a random line within the section that fits their approximate run-time
]
Expand Down

0 comments on commit 89d0949

Please sign in to comment.