Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b1dc2b795d |
@@ -1,4 +1,4 @@
|
||||
# Salvium One v1.1.1
|
||||
# Salvium One v1.0.7
|
||||
|
||||
Copyright (c) 2023-2025, Salvium
|
||||
Portions Copyright (c) 2014-2023, The Monero Project
|
||||
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
|
||||
|
||||
```bash
|
||||
cd salvium
|
||||
git checkout v1.1.1
|
||||
git checkout v1.0.7
|
||||
make
|
||||
```
|
||||
|
||||
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
|
||||
```bash
|
||||
git clone https://github.com/salvium/salvium
|
||||
cd salvium
|
||||
git checkout v1.1.1
|
||||
git checkout v1.0.7
|
||||
```
|
||||
|
||||
* Build:
|
||||
@@ -370,10 +370,10 @@ application.
|
||||
cd salvium
|
||||
```
|
||||
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v1.1.1'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v1.0.7'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v1.1.1
|
||||
git checkout v1.0.7
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
e032e42ebac862bf90d71f0a231d9f3ddb5583e321ec153ee05144d87629980b salvium-v1.1.0-macos-aarch64.zip
|
||||
0f31f09cf7be38b50a35510172bc94b7a4fb07c7107c79c4f055754c282c99f5 salvium-v1.1.0-macos-x86_64.zip
|
||||
4424fd93391daab7eee47c54ab7aad7810a16f4c866209d41ba016d984605ffb salvium-v1.1.0-ubuntu22.04-linux-aarch64.zip
|
||||
d1a5138f892189dfccc1d51d72ce24147fe6f1a2a5d465d350651426a71282a4 salvium-v1.1.0-ubuntu22.04-linux-x86_64.zip
|
||||
bb9c9175726b82e061a6a332a27a6845805be4779928df3abbbd5c0f54691c9a salvium-v1.1.0-win64.zip
|
||||
@@ -1,5 +0,0 @@
|
||||
d0a8b0515ae2ee79849cbc17b0639bb7859e30efcd50e5b058540874cd0919ce salvium-v1.1.0-rc4-ubuntu22.04-linux-x86_64.zip
|
||||
6528b8b23f09c574fc9383b48b88e87f99609ff5ce1b727872b5554505a69d77 salvium-v1.1.0-rc4-ubuntu22.04-linux-aarch64.zip
|
||||
00ca183c47f852b8b30e4b87ce3b3536a0e97866e6027bf25d389b4a1bc9c471 salvium-v1.1.0-rc4-macos-x86_64.zip
|
||||
50480b1043e9b5901576ab45f926b0b51a5d21237c6da549603ad1f13819e6ed salvium-v1.1.0-rc4-macos-aarch64.zip
|
||||
adf96eee17e16f318fc047721acb5bfa8ae7ed1c0ff8d022da8ab5df64d8ce3f salvium-v1.1.0-rc4-win64.zip
|
||||
@@ -1,5 +0,0 @@
|
||||
23a03277e922c3f41ba6ddb0efc7581c3287d9f3faa2ddd19cc2d018a6797701 salvium-v1.1.0-rc5-ubuntu22.04-linux-x86_64.zip
|
||||
94409b190eae890792b2d04cfffe148828dc23d658cd54a8d7802b12a9f274a4 salvium-v1.1.0-rc5-ubuntu22.04-linux-aarch64.zip
|
||||
76cc02603cb21cd0729f0e5c9a39bb32310428b15580458ec8d74dcba39c9319 salvium-v1.1.0-rc5-macos-x86_64.zip
|
||||
dc477718bfb370ecbafebf3e1736df5978200302f13542374f1b1fd43e07ab45 salvium-v1.1.0-rc5-macos-aarch64.zip
|
||||
0e9b81eeaa32a4709a1cbd4c198721455a3c8cc86c1f1915cfc74af7885f8fee salvium-v1.1.0-rc5-win64.zip
|
||||
@@ -1,5 +0,0 @@
|
||||
b712adec8fa6bbcbe461b0748649e4c9e4fb61934fc1adb064779afed28c0758 salvium-v1.1.0-rc6-macos-aarch64.zip
|
||||
8635955ff784f936a8b8de5be267e5dcdc0b55dfbf0b6f65ba24d098d8b8ab00 salvium-v1.1.0-rc6-macos-x86_64.zip
|
||||
79b65ba9a074aeba87f03d83a07c3a6c51815d376049b3136a38c1a33260bfac salvium-v1.1.0-rc6-ubuntu22.04-linux-aarch64.zip
|
||||
9031763ad60d1c8c572c76c5cb51a96b1680b9708c287264388f3d411bda464f salvium-v1.1.0-rc6-ubuntu22.04-linux-x86_64.zip
|
||||
e3a8e53e092041ed9ed32c98d5d0ecf548f42232402748f862371ba21e1f1f9f salvium-v1.1.0-rc6-win64.zip
|
||||
@@ -1501,55 +1501,38 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
tx.type == cryptonote::transaction_type::STAKE ||
|
||||
tx.type == cryptonote::transaction_type::AUDIT ||
|
||||
tx.type == cryptonote::transaction_type::TRANSFER ||
|
||||
tx.type == cryptonote::transaction_type::CREATE_TOKEN ||
|
||||
tx.type == cryptonote::transaction_type::ROLLUP)
|
||||
tx.type == cryptonote::transaction_type::CREATE_TOKEN)
|
||||
{
|
||||
|
||||
bool is_token = cryptonote::is_asset_type_token(tx.source_asset_type);
|
||||
if (!is_token) {
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
if (tx.version >= TRANSACTION_VERSION_ENABLE_TOKENS) {
|
||||
if (tx.source_asset_type != "SAL1") {
|
||||
// this must be a SAL BURN TX, so fee is paid for by ROLLUP
|
||||
final_source_tally = final_source_tally + tx.rct_signatures.txnFee;
|
||||
}
|
||||
}
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent underflow
|
||||
if (source_tally < final_source_tally)
|
||||
throw0(DB_ERROR("numeric underflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent underflow
|
||||
if (source_tally < final_source_tally)
|
||||
throw0(DB_ERROR("numeric underflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
if (tx.version >= TRANSACTION_VERSION_ENABLE_TOKENS) {
|
||||
if (tx.source_asset_type != "SAL1") {
|
||||
// this must be a SAL BURN TX, so fee is paid for by ROLLUP
|
||||
final_burn_tally = final_burn_tally - tx.rct_signatures.txnFee;
|
||||
}
|
||||
}
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally > final_burn_tally)
|
||||
throw0(DB_ERROR("burn overflow detected when adding tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally > final_burn_tally)
|
||||
throw0(DB_ERROR("burn overflow detected when adding tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
|
||||
// Iterate over all of the outputs for a PROTOCOL_TX since they're all MINTED
|
||||
std::map<uint32_t, uint64_t> minted_amounts;
|
||||
std::map<uint32_t, uint64_t> burned_amounts;
|
||||
for (const auto& out: tx.vout) {
|
||||
|
||||
// Fetch the amount and output_asset_type for this output
|
||||
@@ -1558,11 +1541,6 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
if (!ok)
|
||||
throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)"));
|
||||
minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount;
|
||||
|
||||
if (asset_type == "SAL" || asset_type == "SAL1") {
|
||||
uint32_t burned_asset_id = cryptonote::asset_id_from_type("BURN");
|
||||
burned_amounts[burned_asset_id] += out.amount;
|
||||
}
|
||||
}
|
||||
|
||||
// Now update the overall tally entries
|
||||
@@ -1589,23 +1567,23 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
// Log can be changed - not burning here
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before burn =" << source_tally.str() << "\n\tTally after burn =" << final_source_tally.str());
|
||||
}
|
||||
|
||||
// Update burned asset tallies (subtract what was burned, BUT NOT for tokens which are being created!)
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: there should only ever be one entry in this vector!!!
|
||||
for (const auto& asset: burned_amounts) {
|
||||
MDB_val_copy<uint64_t> burn_idx(asset.first);
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
if (burn_tally < asset.second)
|
||||
uint64_t burn_amount = 0;
|
||||
if (asset.first == 0x53414C00 || asset.first == 0x53414C31 || asset.first == 0x4255524E) { //BURN SAL and SAL1 // check
|
||||
burn_amount = asset.second;
|
||||
} else {
|
||||
burn_amount = asset.second / 200;
|
||||
}
|
||||
if (burn_tally < burn_amount)
|
||||
throw0(DB_ERROR("add_transaction_data() - burn underflow"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - asset.second;
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - burn_amount;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
// LAND AHOY!!!
|
||||
}
|
||||
|
||||
// Is there a rollup_tx to add?
|
||||
@@ -1920,60 +1898,37 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN ||
|
||||
tx.type == cryptonote::transaction_type::CONVERT ||
|
||||
tx.type == cryptonote::transaction_type::STAKE ||
|
||||
tx.type == cryptonote::transaction_type::AUDIT ||
|
||||
tx.type == cryptonote::transaction_type::TRANSFER ||
|
||||
tx.type == cryptonote::transaction_type::CREATE_TOKEN ||
|
||||
tx.type == cryptonote::transaction_type::ROLLUP)
|
||||
{
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
bool is_token = cryptonote::is_asset_type_token(tx.source_asset_type);
|
||||
if (!is_token) {
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
if (tx.version >= TRANSACTION_VERSION_ENABLE_TOKENS) {
|
||||
if (tx.source_asset_type != "SAL1") {
|
||||
// this must be a SAL BURN TX, so fee is paid for by ROLLUP
|
||||
final_source_tally = final_source_tally - tx.rct_signatures.txnFee;
|
||||
}
|
||||
}
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent overflow
|
||||
if (source_tally > final_source_tally)
|
||||
throw0(DB_ERROR("numeric overflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before remint =" << source_tally.str() << "\n\tTally after remint =" << final_source_tally.str());
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent overflow
|
||||
if (source_tally > final_source_tally)
|
||||
throw0(DB_ERROR("numeric overflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before remint =" << source_tally.str() << "\n\tTally after remint =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally < (tx.amount_burnt + tx.rct_signatures.txnFee))
|
||||
throw0(DB_ERROR("burn underflow detected when removing tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
if (tx.version >= TRANSACTION_VERSION_ENABLE_TOKENS) {
|
||||
if (tx.source_asset_type != "SAL1") {
|
||||
// this must be a SAL BURN TX, so fee is paid for by ROLLUP
|
||||
final_burn_tally = final_burn_tally + tx.rct_signatures.txnFee;
|
||||
}
|
||||
}
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally < (tx.amount_burnt + tx.rct_signatures.txnFee))
|
||||
throw0(DB_ERROR("burn underflow detected when removing tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
|
||||
// Iterate over all of the outputs for a PROTOCOL_TX since they're all MINTED
|
||||
std::map<uint32_t, uint64_t> minted_amounts;
|
||||
std::map<uint32_t, uint64_t> burned_amounts;
|
||||
for (const auto& out: tx.vout) {
|
||||
|
||||
// Fetch the amount and output_asset_type for this output
|
||||
@@ -1982,11 +1937,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
if (!ok)
|
||||
throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)"));
|
||||
minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount;
|
||||
|
||||
if (asset_type == "SAL" || asset_type == "SAL1") {
|
||||
uint32_t burned_asset_id = cryptonote::asset_id_from_type("BURN");
|
||||
burned_amounts[burned_asset_id] += out.amount;
|
||||
}
|
||||
}
|
||||
|
||||
// Now update the overall tally entries
|
||||
@@ -2005,13 +1955,8 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before undoing mint =" << source_tally.str() << "\n\tTally after undoing mint =" << final_source_tally.str());
|
||||
}
|
||||
|
||||
// Update burned asset tallies (add what was burned, BUT NOT for tokens which were being created!)
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: there should only ever be one entry in this vector!!!
|
||||
for (const auto& asset: burned_amounts) {
|
||||
MDB_val_copy<uint64_t> burn_idx(asset.first);
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result)
|
||||
@@ -2021,7 +1966,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
// LAND AHOY!!!
|
||||
}
|
||||
remove_tx_outputs(tip->data.tx_id, tx);
|
||||
|
||||
|
||||
Binary file not shown.
@@ -217,7 +217,6 @@ void make_carrot_transaction_proposal_v1(const std::vector<CarrotPaymentProposal
|
||||
}
|
||||
uint64_t fee = tx_proposal_out.fee;
|
||||
if (asset_type != "SAL1") {
|
||||
// check here
|
||||
if (tx_type != cryptonote::transaction_type::BURN || asset_type != "SAL") {
|
||||
CARROT_CHECK_AND_THROW(cryptonote::is_valid_custom_asset_type(asset_type),
|
||||
carrot_logic_error, "make_carrot_transaction_proposal_v1: invalid asset type in payment proposals: " << asset_type);
|
||||
|
||||
@@ -175,8 +175,7 @@ namespace cryptonote
|
||||
|
||||
uint64_t seed_height;
|
||||
crypto::hash seed_hash;
|
||||
crypto::public_key miner_reward_tx_key;
|
||||
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, seed_height, seed_hash, miner_reward_tx_key))
|
||||
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, seed_height, seed_hash))
|
||||
{
|
||||
LOG_ERROR("Failed to get_block_template(), stopping mining");
|
||||
m_forced_stop = true;
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace cryptonote
|
||||
struct i_miner_handler
|
||||
{
|
||||
virtual bool handle_block_found(block& b, block_verification_context &bvc) = 0;
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key) = 0;
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash) = 0;
|
||||
protected:
|
||||
~i_miner_handler(){};
|
||||
};
|
||||
|
||||
+3
-15
@@ -94,10 +94,6 @@
|
||||
|
||||
#define CREATE_TOKEN_LOCK_PERIOD 10
|
||||
|
||||
// HF11 block reward split
|
||||
#define BLOCK_REWARD_TREASURY_PCT 25 // to treasury, 21600-block unlock
|
||||
#define BLOCK_REWARD_STAKER_PCT 20 // to stakers via yield
|
||||
|
||||
#define DIFFICULTY_TARGET_V2 120 // seconds
|
||||
#define DIFFICULTY_TARGET_V1 60 // seconds - before first fork
|
||||
#define DIFFICULTY_WINDOW_V2 70 // blocks
|
||||
@@ -258,7 +254,7 @@
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
#define HF_VERSION_SLIPPAGE_YIELD 255
|
||||
|
||||
#define TESTNET_VERSION 18
|
||||
#define TESTNET_VERSION 15
|
||||
#define STAGENET_VERSION 1
|
||||
|
||||
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
|
||||
@@ -323,10 +319,9 @@ namespace config
|
||||
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
|
||||
const uint64_t TREASURY_SAL1_MINT_PERIOD = 30*24*30; // 1 month of blocks
|
||||
|
||||
std::string const TREASURY_ADDRESS_CARROT = "SC11ksHLFhy7H1yMk9bUZvADG1Z9ZkR1T5QMknm3RbGBbgdPkyanB2WBb5TER3MsiwJC5BnyoiYs2DBcvAfAm6JQ537iNKdtvm";
|
||||
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
|
||||
|
||||
// treasury payout {tx-key, output-key, anchor_enc, view_tag} tuples
|
||||
// treasury payout {tx-key, output-key, anchor_enc, vie_tag} tuples
|
||||
const std::map<uint64_t, std::tuple<std::string, std::string, std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_DATA = {
|
||||
{334750, {"1b2cd3ff56aa77c0cbab0473bfb96697ebdd0b25ad230136bfe41d5dc1ef265f","718cf02eabca157fd7ad7f8537db217624bfe1ca99dd09e758357e7000a5e57a","789cca3def51fb879eb7fbca271869b7","79bd0c"}},
|
||||
{356350, {"b51acbf35265d09f3cfb83dcabde2746991ddf0d30b5a4ecc34043b349a77031","9dc0d2e9534cdccf83494687c55c67c8c1b29834acf97cce53124a08a9549231","588ebc2918d06c009a18a28a8ab76694","ab8c23"}},
|
||||
@@ -428,11 +423,9 @@ namespace config
|
||||
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
|
||||
std::string const TREASURY_ADDRESS_CARROT = "SC1TouvX6e4HmkAqsU6AAXLRjgeZnnKHjSpVfMHepTXramNMT2P47AsDmteLH81wdPR2DwMg3cxKvgrhUBeDSUW6MhM3sQb92we";
|
||||
std::string const TREASURY_ADDRESS = "SaLvTyL2pN2SCAPRxwDQ7qjhdg46VbhZrGZTp2wHKJ5sK434a8ivEH35eWp2FTcmyW6LY6ExfBb9chmQ9xAL1eJyZ5FQjtQGTis3v";
|
||||
std::string const TREASURY_ADDRESS = "SaLvTyLFta9BiAXeUfFkKvViBkFt4ay5nEUBpWyDKewYggtsoxBbtCUVqaBjtcCDyY1euun8Giv7LLEgvztuurLo5a6Km1zskZn36";
|
||||
|
||||
// treasury payout {tx-key, output-key, anchor_enc, vie_tag} tuples
|
||||
// check address type before future development
|
||||
const std::map<uint64_t, std::tuple<std::string, std::string, std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_DATA = {
|
||||
{1100, {"71336a480440ed24a53b2cfd5a5292d1e618c3e843637227883ea2cc42fb346f","a135f59a05ea9e33539e4502b187b4789cc7fba79616c6902a902cc6601f0359","7f1c6970232254a9b13f7f063df2a853","62073c"}},
|
||||
{1120, {"2cc49b182addc0106b601c9876c01a4b06532c05f9dd9179b2c4f47e5c7c0d74","fd62e59324389f37d0bb628a39f413c11be34d572ec3a40f465e008b9dfd5e0c","fbf8584222e299bb748009eaf2177123","b76a8d"}},
|
||||
@@ -474,7 +467,6 @@ namespace config
|
||||
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
|
||||
std::string const TREASURY_ADDRESS_CARROT = ""; // TODO: generate stagenet Carrot treasury address ?
|
||||
std::string const TREASURY_ADDRESS = "fuLMowH85abK8nz9BBMEem7MAfUbQu4aSHHUV9j5Z86o6Go9Lv2U5ZQiJCWPY9R9HA8p5idburazjAhCqDngLo7fYPCD9ciM9ee1A";
|
||||
|
||||
// treasury payout {tx-key, output-key, anchor_enc, view_tag} tuples
|
||||
@@ -529,7 +521,6 @@ namespace cryptonote
|
||||
uint64_t TREASURY_SAL1_MINT_PERIOD;
|
||||
std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> const AUDIT_HARD_FORKS;
|
||||
std::string TREASURY_ADDRESS;
|
||||
std::string TREASURY_ADDRESS_CARROT;
|
||||
std::map<uint64_t, std::tuple<std::string, std::string, std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_DATA;
|
||||
};
|
||||
inline const config_t& get_config(network_type nettype)
|
||||
@@ -553,7 +544,6 @@ namespace cryptonote
|
||||
::config::TREASURY_SAL1_MINT_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::TREASURY_ADDRESS,
|
||||
::config::TREASURY_ADDRESS_CARROT,
|
||||
::config::TREASURY_SAL1_MINT_OUTPUT_DATA
|
||||
};
|
||||
static const config_t testnet = {
|
||||
@@ -575,7 +565,6 @@ namespace cryptonote
|
||||
::config::testnet::TREASURY_SAL1_MINT_PERIOD,
|
||||
::config::testnet::AUDIT_HARD_FORKS,
|
||||
::config::testnet::TREASURY_ADDRESS,
|
||||
::config::testnet::TREASURY_ADDRESS_CARROT,
|
||||
::config::testnet::TREASURY_SAL1_MINT_OUTPUT_DATA
|
||||
};
|
||||
static const config_t stagenet = {
|
||||
@@ -597,7 +586,6 @@ namespace cryptonote
|
||||
::config::stagenet::TREASURY_SAL1_MINT_PERIOD,
|
||||
::config::stagenet::AUDIT_HARD_FORKS,
|
||||
::config::stagenet::TREASURY_ADDRESS,
|
||||
::config::stagenet::TREASURY_ADDRESS_CARROT,
|
||||
::config::stagenet::TREASURY_SAL1_MINT_OUTPUT_DATA
|
||||
};
|
||||
switch (nettype)
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
@@ -58,8 +57,6 @@
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core.h"
|
||||
#include "ringct/rctSigs.h"
|
||||
#include "carrot_core/payment_proposal.h"
|
||||
#include "carrot_impl/format_utils.h"
|
||||
#include "common/perf_timer.h"
|
||||
#include "common/notify.h"
|
||||
#include "common/varint.h"
|
||||
@@ -1354,10 +1351,7 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height,
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "coinbase transaction in the block has the wrong type");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.version > 1, false, "Invalid coinbase transaction version");
|
||||
|
||||
if (hf_version >= HF_VERSION_ENABLE_TOKENS) {
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.version == TRANSACTION_VERSION_ENABLE_TOKENS, false, "miner transaction has wrong version");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.type == cryptonote::transaction_type::MINER, false, "miner transaction has wrong type");
|
||||
} else if (hf_version >= HF_VERSION_CARROT) {
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.version == TRANSACTION_VERSION_CARROT, false, "miner transaction has wrong version");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.type == cryptonote::transaction_type::MINER, false, "miner transaction has wrong type");
|
||||
}
|
||||
@@ -1416,10 +1410,7 @@ bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t heigh
|
||||
uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD;
|
||||
uint8_t hf_version_submitted = get_ideal_hard_fork_version(height - stake_lock_period - 1);
|
||||
|
||||
if (hf_version >= HF_VERSION_ENABLE_TOKENS) {
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.version == TRANSACTION_VERSION_ENABLE_TOKENS, false, "protocol transaction has wrong version");
|
||||
hf_version_submitted = hf_version;
|
||||
} else if (hf_version == HF_VERSION_CARROT) {
|
||||
if (hf_version == HF_VERSION_CARROT) {
|
||||
if (hf_version_submitted >= HF_VERSION_CARROT || b.protocol_tx.vout.size() == 0) {
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.version == TRANSACTION_VERSION_CARROT, false, "protocol transaction has wrong version");
|
||||
} else {
|
||||
@@ -1491,53 +1482,7 @@ std::tuple<bool, size_t> Blockchain::validate_treasury_payout(const transaction&
|
||||
return {false, 0};
|
||||
}
|
||||
|
||||
// Burning-bug guards: verify view_tag, anchor_enc, and D_e from the hardcoded config
|
||||
// so a miner cannot tamper with those fields while keeping K_o correct.
|
||||
|
||||
// Check view_tag
|
||||
carrot::view_tag_t expected_view_tag{};
|
||||
if (!epee::string_tools::hex_to_pod(viewtag, expected_view_tag)) {
|
||||
MERROR_VER("treasury payout: failed to deserialize expected view_tag");
|
||||
return {false, 0};
|
||||
}
|
||||
if (target.view_tag != expected_view_tag) {
|
||||
MERROR_VER("treasury payout view_tag mismatch (burning bug: K_o correct but view_tag tampered)");
|
||||
return {false, 0};
|
||||
}
|
||||
|
||||
// Check anchor_enc
|
||||
carrot::encrypted_janus_anchor_t expected_anchor_enc{};
|
||||
if (!epee::string_tools::hex_to_pod(anchor_enc, expected_anchor_enc)) {
|
||||
MERROR_VER("treasury payout: failed to deserialize expected anchor_enc");
|
||||
return {false, 0};
|
||||
}
|
||||
if (0 != memcmp(&target.encrypted_janus_anchor, &expected_anchor_enc, sizeof(expected_anchor_enc))) {
|
||||
MERROR_VER("treasury payout anchor_enc mismatch (burning bug: K_o correct but anchor tampered)");
|
||||
return {false, 0};
|
||||
}
|
||||
|
||||
// Check D_e (enote ephemeral pubkey)
|
||||
mx25519_pubkey expected_tx_key_raw{};
|
||||
if (!epee::string_tools::hex_to_pod(tx_key, expected_tx_key_raw)) {
|
||||
MERROR_VER("treasury payout: failed to deserialize expected tx_key");
|
||||
return {false, 0};
|
||||
}
|
||||
const crypto::public_key expected_De = carrot::raw_byte_convert<crypto::public_key>(expected_tx_key_raw);
|
||||
const size_t output_idx = output - tx.vout.begin();
|
||||
const crypto::public_key single_tx_pubkey = cryptonote::get_tx_pub_key_from_extra(tx);
|
||||
const std::vector<crypto::public_key> additional_tx_pubkeys = cryptonote::get_additional_tx_pub_keys_from_extra(tx);
|
||||
crypto::public_key actual_De{};
|
||||
if (!additional_tx_pubkeys.empty() && output_idx < additional_tx_pubkeys.size()) {
|
||||
actual_De = additional_tx_pubkeys[output_idx];
|
||||
} else if (single_tx_pubkey != crypto::null_pkey) {
|
||||
actual_De = single_tx_pubkey;
|
||||
}
|
||||
if (actual_De != expected_De) {
|
||||
MERROR_VER("treasury payout D_e mismatch (burning bug: K_o correct but ephemeral key tampered)");
|
||||
return {false, 0};
|
||||
}
|
||||
|
||||
return {true, output_idx};
|
||||
return {true, output - tx.vout.begin()};
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
// This function validates the miner transaction reward
|
||||
@@ -1560,23 +1505,42 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
treasury_index_in_tx_outputs = index_in_tx_outputs;
|
||||
}
|
||||
|
||||
// Calculate reward being issued
|
||||
//validate reward
|
||||
uint64_t money_in_use = 0;
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.amount_burnt > 0 || height == 0, false, "invalid tx.amount_burnt for miner_tx");
|
||||
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt >= money_in_use, false, "miner transaction is overflowed by amount_burnt");
|
||||
money_in_use += b.miner_tx.amount_burnt;
|
||||
for(size_t i = 0; i < b.miner_tx.vout.size(); i++)
|
||||
{
|
||||
// skip the treasury output
|
||||
if (treasury_payout_exists && (i == treasury_index_in_tx_outputs)) {
|
||||
continue;
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.vout[i].amount >= money_in_use, false, "miner transaction is overflowed by output amount");
|
||||
money_in_use += b.miner_tx.vout[i].amount;
|
||||
}
|
||||
partial_block_reward = false;
|
||||
|
||||
// Make sure the TOTAL REWARD is correct
|
||||
switch (version) {
|
||||
case HF_VERSION_BULLETPROOF_PLUS:
|
||||
case HF_VERSION_ENABLE_N_OUTS:
|
||||
case HF_VERSION_FULL_PROOFS:
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
case HF_VERSION_SHUTDOWN_USER_TXS:
|
||||
case HF_VERSION_SALVIUM_ONE_PROOFS:
|
||||
case HF_VERSION_AUDIT1_PAUSE:
|
||||
case HF_VERSION_AUDIT2:
|
||||
case HF_VERSION_AUDIT2_PAUSE:
|
||||
case HF_VERSION_CARROT:
|
||||
case HF_VERSION_ENABLE_TOKENS:
|
||||
if (b.miner_tx.amount_burnt > 0) {
|
||||
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt");
|
||||
money_in_use += b.miner_tx.amount_burnt;
|
||||
}
|
||||
if (already_generated_coins != 0)
|
||||
CHECK_AND_ASSERT_MES(money_in_use / 5 == b.miner_tx.amount_burnt, false, "miner_transaction has incorrect amount_burnt amount");
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t median_weight = m_current_block_cumul_weight_median;
|
||||
if (!get_block_reward(median_weight, cumulative_block_weight, already_generated_coins, base_reward, version))
|
||||
{
|
||||
@@ -1593,114 +1557,6 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
MDEBUG("coinbase transaction doesn't use full amount of block reward: spent: " << money_in_use << ", block reward " << base_reward + fee << "(" << base_reward << "+" << fee << ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
// HF-specific additional checks
|
||||
switch (version) {
|
||||
case HF_VERSION_BULLETPROOF_PLUS:
|
||||
case HF_VERSION_ENABLE_N_OUTS:
|
||||
case HF_VERSION_FULL_PROOFS:
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
case HF_VERSION_SHUTDOWN_USER_TXS:
|
||||
case HF_VERSION_SALVIUM_ONE_PROOFS:
|
||||
case HF_VERSION_AUDIT1_PAUSE:
|
||||
case HF_VERSION_AUDIT2:
|
||||
case HF_VERSION_AUDIT2_PAUSE:
|
||||
case HF_VERSION_CARROT:
|
||||
if (already_generated_coins != 0) {
|
||||
// HF1-10: block reward split is 80% miner + 20% staker (amount_burnt)
|
||||
CHECK_AND_ASSERT_MES(money_in_use / 5 == b.miner_tx.amount_burnt, false, "miner_transaction has incorrect amount_burnt amount");
|
||||
}
|
||||
break;
|
||||
case HF_VERSION_ENABLE_TOKENS:
|
||||
// HF11: block reward split is 60% miner + 25% treasury + 15% staker (amount_burnt)
|
||||
if (already_generated_coins != 0) {
|
||||
|
||||
// Validate treasury share: one output must equal block_reward * 25 / 100
|
||||
uint64_t expected_treasury_block_reward = money_in_use * BLOCK_REWARD_TREASURY_PCT / 100;
|
||||
// Validate staker share: amount_burnt == block_reward * 15 / 100
|
||||
uint64_t expected_staker_block_reward = (money_in_use - expected_treasury_block_reward) * BLOCK_REWARD_STAKER_PCT / 100;
|
||||
CHECK_AND_ASSERT_MES(expected_staker_block_reward == b.miner_tx.amount_burnt, false,
|
||||
"miner_transaction has incorrect amount_burnt for HF11 (expected " << expected_staker_block_reward << ", got " << b.miner_tx.amount_burnt << ")");
|
||||
uint64_t expected_miner_block_reward = money_in_use - b.miner_tx.amount_burnt - expected_treasury_block_reward;
|
||||
|
||||
// treasury_destination
|
||||
address_parse_info treasury_addr_info;
|
||||
bool addr_ok = cryptonote::get_account_address_from_str(treasury_addr_info, m_nettype, get_config(m_nettype).TREASURY_ADDRESS_CARROT);
|
||||
CHECK_AND_ASSERT_MES(addr_ok, false, "Failed to parse treasury address for validation");
|
||||
|
||||
carrot::CarrotDestinationV1 treasury_destination;
|
||||
carrot::make_carrot_main_address_v1(treasury_addr_info.address.m_spend_public_key,
|
||||
treasury_addr_info.address.m_view_public_key,
|
||||
treasury_destination);
|
||||
|
||||
// deterministic janus anchor
|
||||
const carrot::janus_anchor_t treasury_anchor = get_deterministic_treasury_anchor_from_height(height);
|
||||
const carrot::CarrotPaymentProposalV1 treasury_proposal{
|
||||
.destination = treasury_destination,
|
||||
.amount = expected_treasury_block_reward,
|
||||
.asset_type = "SAL1",
|
||||
.randomness = treasury_anchor
|
||||
};
|
||||
|
||||
carrot::CarrotCoinbaseEnoteV1 expected_enote;
|
||||
carrot::get_coinbase_output_proposal_v1(treasury_proposal, height, expected_enote);
|
||||
|
||||
// Get the ephemeral pubkeys from the TX
|
||||
crypto::public_key tx_pubkey = cryptonote::get_tx_pub_key_from_extra(b.miner_tx.extra);
|
||||
bool has_single = (tx_pubkey != crypto::null_pkey);
|
||||
std::vector<crypto::public_key> additional_tx_pubkeys = cryptonote::get_additional_tx_pub_keys_from_extra(b.miner_tx.extra);
|
||||
|
||||
bool found_treasury_block_reward = false;
|
||||
for (size_t i = 0; i < b.miner_tx.vout.size(); i++) {
|
||||
|
||||
// Get the output
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vout[i].target.type() == typeid(txout_to_carrot_v1), false, "Output of miner_tx is not txout_to_carrot_V1");
|
||||
const auto &output = boost::get<txout_to_carrot_v1>(b.miner_tx.vout[i].target);
|
||||
|
||||
// Check the output type is SAL1
|
||||
CHECK_AND_ASSERT_MES(output.asset_type == "SAL1", false, "Output of miner_tx is not SAL1");
|
||||
|
||||
// Skip the premine remint
|
||||
if (treasury_payout_exists && (i == treasury_index_in_tx_outputs)) continue;
|
||||
|
||||
// Could this be the treasury block reward?
|
||||
if (b.miner_tx.vout[i].amount == expected_treasury_block_reward) {
|
||||
|
||||
/// Check Ko
|
||||
if (output.key != expected_enote.onetime_address) continue;
|
||||
|
||||
// Check view_tag
|
||||
CHECK_AND_ASSERT_MES(output.view_tag == expected_enote.view_tag, false,
|
||||
"treasury output view_tag mismatch (burning bug: K_o correct but view_tag tampered)");
|
||||
|
||||
// Check anchor_enc
|
||||
CHECK_AND_ASSERT_MES(0 == memcmp(&output.encrypted_janus_anchor, &expected_enote.anchor_enc, sizeof(expected_enote.anchor_enc)), false,
|
||||
"treasury output anchor_enc mismatch (burning bug: K_o correct but anchor tampered)");
|
||||
|
||||
// Check D_e
|
||||
const crypto::public_key expected_De = carrot::raw_byte_convert<crypto::public_key>(expected_enote.enote_ephemeral_pubkey);
|
||||
crypto::public_key actual_De{};
|
||||
if (!additional_tx_pubkeys.empty() && i < additional_tx_pubkeys.size()) {
|
||||
actual_De = additional_tx_pubkeys[i];
|
||||
} else if (has_single) {
|
||||
actual_De = tx_pubkey;
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(actual_De == expected_De, false,
|
||||
"treasury output D_e mismatch"); //important
|
||||
|
||||
// Passed all checks
|
||||
found_treasury_block_reward = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(found_treasury_block_reward, false, "miner_tx missing treasury output with expected amount " << expected_treasury_block_reward);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CHECK_AND_ASSERT_MES(false, false, "invalid HF detected in miner_tx : " << version);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
@@ -2031,7 +1887,7 @@ uint64_t Blockchain::get_current_cumulative_block_weight_median() const
|
||||
// in a lot of places. That flag is not referenced in any of the code
|
||||
// nor any of the makefiles, howeve. Need to look into whether or not it's
|
||||
// necessary at all.
|
||||
bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key)
|
||||
bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
size_t median_weight;
|
||||
@@ -2060,7 +1916,6 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
expected_reward = m_btc_expected_reward;
|
||||
seed_height = m_btc_seed_height;
|
||||
seed_hash = m_btc_seed_hash;
|
||||
miner_reward_tx_key = m_btc_miner_reward_tx_key;
|
||||
return true;
|
||||
}
|
||||
MDEBUG("Not using cached template: address " << (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address))) << ", nonce " << (m_btc_nonce == ex_nonce) << ", cookie " << (m_btc_pool_cookie == m_tx_pool.cookie()) << ", from_block " << (!!from_block));
|
||||
@@ -2375,6 +2230,9 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
*/
|
||||
|
||||
// Time to construct the protocol_tx
|
||||
address_parse_info treasury_address_info;
|
||||
ok = cryptonote::get_account_address_from_str(treasury_address_info, m_nettype, get_config(m_nettype).TREASURY_ADDRESS);
|
||||
CHECK_AND_ASSERT_MES(ok, false, "Failed to obtain treasury address info");
|
||||
ok = construct_protocol_tx(height, b.protocol_tx, protocol_entries, b.major_version);
|
||||
CHECK_AND_ASSERT_MES(ok, false, "Failed to construct protocol tx");
|
||||
|
||||
@@ -2438,9 +2296,8 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
*/
|
||||
//make blocks coin-base tx looks close to real coinbase tx to get truthful blob weight
|
||||
uint8_t hf_version = b.major_version;
|
||||
size_t max_outs = hf_version >= HF_VERSION_ENABLE_TOKENS ? 3 : (hf_version >= 4 ? 1 : 11);
|
||||
|
||||
bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, miner_reward_tx_key, b.miner_tx, m_nettype, m_hardfork->get_hardforks(), ex_nonce, max_outs, hf_version);
|
||||
size_t max_outs = hf_version >= 4 ? 1 : 11;
|
||||
bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, m_nettype, m_hardfork->get_hardforks(), ex_nonce, max_outs, hf_version);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance");
|
||||
size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx);
|
||||
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
|
||||
@@ -2449,7 +2306,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
#endif
|
||||
for (size_t try_count = 0; try_count != 10; ++try_count)
|
||||
{
|
||||
r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, miner_reward_tx_key, b.miner_tx, m_nettype, m_hardfork->get_hardforks(), ex_nonce, max_outs, hf_version);
|
||||
r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, m_nettype, m_hardfork->get_hardforks(), ex_nonce, max_outs, hf_version);
|
||||
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance");
|
||||
size_t coinbase_weight = get_transaction_weight(b.miner_tx);
|
||||
@@ -2494,16 +2351,16 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
#endif
|
||||
|
||||
if (!from_block)
|
||||
cache_block_template(b, miner_address, ex_nonce, diffic, height, expected_reward, seed_height, seed_hash, pool_cookie, miner_reward_tx_key);
|
||||
cache_block_template(b, miner_address, ex_nonce, diffic, height, expected_reward, seed_height, seed_hash, pool_cookie);
|
||||
return true;
|
||||
}
|
||||
LOG_ERROR("Failed to create_block_template with " << 10 << " tries");
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key)
|
||||
bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
|
||||
{
|
||||
return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash, miner_reward_tx_key);
|
||||
return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog)
|
||||
@@ -4057,8 +3914,8 @@ bool Blockchain::check_tx_asset_types(const transaction& tx, tx_verification_con
|
||||
return false;
|
||||
}
|
||||
} else if (tx.type == cryptonote::transaction_type::BURN) {
|
||||
if ((tx.source_asset_type != "SAL" && tx.source_asset_type != "SAL1") || (tx.source_asset_type != tx.destination_asset_type)) {
|
||||
MERROR_VER("Invalid source/dest asset type for BURN - provided source asset: " << tx.source_asset_type << ", and destination asset: " << tx.destination_asset_type << ", expected SAL/SAL1 for both");
|
||||
if ((tx.source_asset_type != "SAL" && tx.source_asset_type != "SAL1") || tx.destination_asset_type != tx.source_asset_type) {
|
||||
MERROR_VER("Invalid source/dest asset type for BURN - provided source asset: " << tx.source_asset_type << ", and destination asset: " << tx.destination_asset_type << ", expected (matching) SAL/SAL1");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
@@ -4084,19 +3941,12 @@ bool Blockchain::check_tx_asset_types(const transaction& tx, tx_verification_con
|
||||
return false;
|
||||
}
|
||||
} else if (hf_version >= HF_VERSION_CARROT) {
|
||||
if (tx.type == cryptonote::transaction_type::BURN) {
|
||||
if (tx.source_asset_type != "SAL1" || tx.destination_asset_type != "BURN") {
|
||||
MERROR_VER("Invalid source/dest asset type for BURN - provided destination asset: " << tx.destination_asset_type << ", expected BURN" << ", provided source asset: " << tx.source_asset_type << ", expected SAL1");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (tx.source_asset_type != "SAL1" || tx.destination_asset_type != "SAL1") {
|
||||
MERROR_VER("Invalid destination/source asset type - provided destination asset: " << tx.destination_asset_type << ", expected SAL1" << ", provided source asset: " << tx.source_asset_type << ", expected SAL1");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
if (tx.source_asset_type != "SAL1" || tx.destination_asset_type != "SAL1") {
|
||||
MERROR_VER("Invalid destination/source asset type - provided destination asset: " << tx.destination_asset_type << ", expected SAL1" << ", provided source asset: " << tx.source_asset_type << ", expected SAL1");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
// }
|
||||
} else if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
// protocol and miner txs don't have source and destination asset types
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL || tx.type == cryptonote::transaction_type::MINER) {
|
||||
@@ -4104,8 +3954,8 @@ bool Blockchain::check_tx_asset_types(const transaction& tx, tx_verification_con
|
||||
} else if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL" && tx.destination_asset_type == "SAL", false, "wrong source/destination asset type: provided source asset " << tx.source_asset_type << " expected SAL and provided destination asset " << tx.destination_asset_type << " expected SAL");
|
||||
} else if (tx.type == cryptonote::transaction_type::BURN) {
|
||||
if ((tx.source_asset_type != "SAL" && tx.source_asset_type != "SAL1") || tx.destination_asset_type != "BURN") {
|
||||
MERROR_VER("Invalid source/dest asset type for BURN - provided source asset: " << tx.source_asset_type << ", and destination asset: " << tx.destination_asset_type << ", expected SAL/SAL1 and BURN respectively");
|
||||
if (tx.source_asset_type != "SAL1" || tx.destination_asset_type != "BURN") {
|
||||
MERROR_VER("Invalid source/dest asset type for BURN - provided source asset: " << tx.source_asset_type << ", and destination asset: " << tx.destination_asset_type << ", expected SAL1 and BURN respectively");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
@@ -4235,8 +4085,6 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
// Check that the ticker doesn't begin with the reserved chars `SAL`
|
||||
CHECK_AND_ASSERT_MES(tx.token_metadata.asset_type.substr(0,3) != "SAL", false, "Invalid CREATE_TOKEN ticker - SAL* is reserved");
|
||||
// Check that the specific asset_type being created isn't already in our list of tokens
|
||||
std::map<std::string, cryptonote::token_metadata_t> mapTokens = m_db->get_tokens();
|
||||
std::string asset_type = "sal" + tx.token_metadata.asset_type;
|
||||
@@ -4252,21 +4100,7 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
|
||||
// Validate the amount burnt matches the token creation price
|
||||
CHECK_AND_ASSERT_MES(tx.amount_burnt == cryptonote::get_token_creation_price(tx.token_metadata.asset_type), false, "Invalid fee paid for CREATE_TOKEN");
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::ROLLUP) {
|
||||
CHECK_AND_ASSERT_MES(tx.layer2_rollup_data.version == 1, false, "Invalid ROLLUP data version");
|
||||
CHECK_AND_ASSERT_MES(!tx.layer2_rollup_data.txs.empty(), false, "ROLLUP must include at least one paid TX entry");
|
||||
|
||||
uint64_t expected_amount_burnt = 0;
|
||||
for (const auto &rollup_tx : tx.layer2_rollup_data.txs) {
|
||||
CHECK_AND_ASSERT_MES(rollup_tx.tx_fee > 0, false, "ROLLUP contains a paid TX entry with zero fee");
|
||||
CHECK_AND_ASSERT_MES(expected_amount_burnt <= std::numeric_limits<uint64_t>::max() - rollup_tx.tx_fee, false, "Numeric overflow in ROLLUP fee total");
|
||||
expected_amount_burnt += rollup_tx.tx_fee;
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(tx.amount_burnt == expected_amount_burnt, false, "Invalid amount_burnt for ROLLUP");
|
||||
}
|
||||
|
||||
|
||||
// Check for invalid TX types
|
||||
if (tx.type == cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) {
|
||||
MERROR("TX type `" + std::to_string(tx.type) + "' is not supported");
|
||||
@@ -5750,6 +5584,7 @@ leave:
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Check the TX type
|
||||
tx_verification_context tvc;
|
||||
if (!check_tx_type_and_version(tx, tvc)) {
|
||||
@@ -5758,7 +5593,8 @@ leave:
|
||||
return_tx_to_pool(txs);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TIME_MEASURE_FINISH(cc);
|
||||
t_checktx += cc;
|
||||
fee_summary += fee;
|
||||
@@ -6943,7 +6779,7 @@ void Blockchain::cancel()
|
||||
}
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
static const char expected_block_hashes_hash[] = "f3bf12451890c9cbeb9f90b2762e4ee2756aaa726958e280e27b51ed9edf84b3";
|
||||
static const char expected_block_hashes_hash[] = "7e6c9efd949afb36bce062bbb720605f0dd67b03c0124e5167c527fa59c15ce3";
|
||||
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
|
||||
{
|
||||
if (get_checkpoints == nullptr || !m_fast_sync)
|
||||
@@ -7085,7 +6921,7 @@ void Blockchain::invalidate_block_template_cache()
|
||||
m_btc_valid = false;
|
||||
}
|
||||
|
||||
void Blockchain::cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie, crypto::public_key &miner_reward_tx_key)
|
||||
void Blockchain::cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie)
|
||||
{
|
||||
MDEBUG("Setting block template cache");
|
||||
m_btc = b;
|
||||
@@ -7097,7 +6933,6 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_
|
||||
m_btc_seed_hash = seed_hash;
|
||||
m_btc_seed_height = seed_height;
|
||||
m_btc_pool_cookie = pool_cookie;
|
||||
m_btc_miner_reward_tx_key = miner_reward_tx_key;
|
||||
m_btc_valid = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -394,8 +394,8 @@ namespace cryptonote
|
||||
*
|
||||
* @return true if block template filled in successfully, else false
|
||||
*/
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key);
|
||||
bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key);
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
|
||||
bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
|
||||
|
||||
/**
|
||||
* @brief gets data required to create a block template and start mining on it
|
||||
@@ -1333,7 +1333,7 @@ namespace cryptonote
|
||||
crypto::hash m_btc_seed_hash;
|
||||
uint64_t m_btc_seed_height;
|
||||
bool m_btc_valid;
|
||||
crypto::public_key m_btc_miner_reward_tx_key;
|
||||
|
||||
|
||||
bool m_batch_success;
|
||||
|
||||
@@ -1759,7 +1759,7 @@ namespace cryptonote
|
||||
*
|
||||
* At some point, may be used to push an update to miners
|
||||
*/
|
||||
void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie, crypto::public_key &miner_reward_tx_key);
|
||||
void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie);
|
||||
|
||||
/**
|
||||
* @brief sends new block notifications to ZMQ `miner_data` subscribers
|
||||
|
||||
@@ -1542,14 +1542,14 @@ namespace cryptonote
|
||||
notify_txpool_event(tx_blobs, epee::to_span(tx_hashes), epee::to_span(txs), just_broadcasted);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key)
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash, miner_reward_tx_key);
|
||||
return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key)
|
||||
bool core::get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash, miner_reward_tx_key);
|
||||
return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog)
|
||||
|
||||
@@ -231,8 +231,8 @@ namespace cryptonote
|
||||
*
|
||||
* @note see Blockchain::create_block_template
|
||||
*/
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key) override;
|
||||
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key);
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash) override;
|
||||
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
|
||||
|
||||
/**
|
||||
* @copydoc Blockchain::get_miner_data
|
||||
|
||||
@@ -392,7 +392,6 @@ namespace cryptonote
|
||||
}
|
||||
tx = store_carrot_to_coinbase_transaction_v1(enotes, std::string{}, cryptonote::transaction_type::PROTOCOL, height);
|
||||
tx.amount_burnt = 0;
|
||||
tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : TRANSACTION_VERSION_CARROT;
|
||||
tx.invalidate_hashes();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
@@ -459,17 +458,7 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
carrot::janus_anchor_t get_deterministic_treasury_anchor_from_height(uint64_t height)
|
||||
{
|
||||
carrot::janus_anchor_t treasury_anchor{};
|
||||
for (int i = 0; i < 8; ++i)
|
||||
treasury_anchor.bytes[i] = (height >> (8 * i)) & 0xff;
|
||||
for (int i = 8; i < 16; ++i)
|
||||
treasury_anchor.bytes[i] = 0;
|
||||
return treasury_anchor;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, crypto::public_key& miner_reward_tx_key, transaction& tx, network_type nettype, const std::vector<hardfork_t>& hardforks, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) {
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, network_type nettype, const std::vector<hardfork_t>& hardforks, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) {
|
||||
|
||||
// Clear the TX contents
|
||||
tx.set_null();
|
||||
@@ -497,70 +486,33 @@ namespace cryptonote
|
||||
{
|
||||
try
|
||||
{
|
||||
// miner destination
|
||||
carrot::CarrotDestinationV1 miner_destination;
|
||||
// Build the miner payout
|
||||
carrot::CarrotDestinationV1 destination;
|
||||
carrot::make_carrot_main_address_v1(miner_address.m_spend_public_key,
|
||||
miner_address.m_view_public_key,
|
||||
miner_destination);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(!miner_destination.is_subaddress,
|
||||
"construct_miner_tx: subaddresses are not allowed in miner transactions");
|
||||
CHECK_AND_ASSERT_THROW_MES(miner_destination.payment_id == carrot::null_payment_id,
|
||||
"construct_miner_tx: integrated addresses are not allowed in miner transactions");
|
||||
destination);
|
||||
|
||||
const bool do_new_split = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS);
|
||||
uint64_t treasury_reward = do_new_split ? (block_reward * BLOCK_REWARD_TREASURY_PCT / 100) : 0;
|
||||
uint64_t stake_reward = (block_reward - treasury_reward) * BLOCK_REWARD_STAKER_PCT / 100;
|
||||
uint64_t miner_reward = (block_reward - treasury_reward - stake_reward);
|
||||
CHECK_AND_ASSERT_THROW_MES(!destination.is_subaddress,
|
||||
"make_single_enote_carrot_coinbase_transaction_v1: subaddress are not allowed in miner transactions");
|
||||
CHECK_AND_ASSERT_THROW_MES(destination.payment_id == carrot::null_payment_id,
|
||||
"make_single_enote_carrot_coinbase_transaction_v1: integrated addresses are not allowed in miner transactions");
|
||||
|
||||
//miner enote
|
||||
const carrot::CarrotPaymentProposalV1 miner_proposal{
|
||||
.destination = miner_destination,
|
||||
.amount = miner_reward,
|
||||
uint64_t stake_reward = block_reward / 5;
|
||||
|
||||
const carrot::CarrotPaymentProposalV1 payment_proposal{
|
||||
.destination = destination,
|
||||
.amount = block_reward - stake_reward,
|
||||
.asset_type = "SAL1",
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
};
|
||||
|
||||
// Determine number of enotes: miner + optional treasury_reward + optional treasury_mint
|
||||
size_t num_enotes = 1;
|
||||
if (do_new_split) num_enotes++; // treasury reward output
|
||||
if (treasury_payout_exists) num_enotes++;
|
||||
std::vector<carrot::CarrotCoinbaseEnoteV1> enotes(num_enotes);
|
||||
carrot::get_coinbase_output_proposal_v1(miner_proposal, height, enotes[0]);
|
||||
std::vector<carrot::CarrotCoinbaseEnoteV1> enotes(treasury_payout_exists ? 2 : 1);
|
||||
carrot::get_coinbase_output_proposal_v1(payment_proposal, height, enotes.front());
|
||||
|
||||
// STORE THE MINER TX_PUB_KEY NOW
|
||||
miner_reward_tx_key = carrot::raw_byte_convert<crypto::public_key>(enotes[0].enote_ephemeral_pubkey);
|
||||
|
||||
size_t enote_idx = 1;
|
||||
|
||||
// Add the treasury reward enote (25% of block reward) for HF11+
|
||||
if (do_new_split) {
|
||||
|
||||
//treasury address for HF11+ block reward split
|
||||
address_parse_info treasury_addr_info;
|
||||
bool treasury_ok = cryptonote::get_account_address_from_str(treasury_addr_info, nettype, get_config(nettype).TREASURY_ADDRESS_CARROT);
|
||||
CHECK_AND_ASSERT_MES(treasury_ok, false, "Failed to parse treasury address for block reward split"); // maybe more check can be added here, but it's enough for now (bcs validation)
|
||||
|
||||
carrot::CarrotDestinationV1 treasury_destination;
|
||||
carrot::make_carrot_main_address_v1(treasury_addr_info.address.m_spend_public_key,
|
||||
treasury_addr_info.address.m_view_public_key,
|
||||
treasury_destination);
|
||||
|
||||
// Derive a deterministic janus anchor from height so validators can independently recompute the expected treasury K_o
|
||||
const carrot::janus_anchor_t treasury_anchor = get_deterministic_treasury_anchor_from_height(height);
|
||||
const carrot::CarrotPaymentProposalV1 treasury_proposal{
|
||||
.destination = treasury_destination,
|
||||
.amount = treasury_reward,
|
||||
.asset_type = "SAL1",
|
||||
.randomness = treasury_anchor
|
||||
};
|
||||
|
||||
carrot::get_coinbase_output_proposal_v1(treasury_proposal, height, enotes[enote_idx]);
|
||||
enote_idx++;
|
||||
}
|
||||
|
||||
//
|
||||
// Check to see if there needs to be a treasury payout
|
||||
if (treasury_payout_exists) {
|
||||
|
||||
// Convert the strings into meaningful data
|
||||
const auto [tx_public_key_str, onetime_address_str, anchor_enc_str, view_tag_str] = treasury_payout_data.at(height);
|
||||
mx25519_pubkey tx_public_key;
|
||||
CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(tx_public_key_str, tx_public_key), "fail to deserialize treasury tx public key");
|
||||
@@ -571,8 +523,8 @@ namespace cryptonote
|
||||
carrot::view_tag_t view_tag;
|
||||
CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(view_tag_str, view_tag), "fail to deserialize treasury tx view_tag");
|
||||
|
||||
//
|
||||
carrot::CarrotCoinbaseEnoteV1 &treasury_enote = enotes[enote_idx];
|
||||
// Manually produce an enote for the treasury payout using the hardcoded keys
|
||||
carrot::CarrotCoinbaseEnoteV1 &treasury_enote = enotes.back();
|
||||
treasury_enote.onetime_address = onetime_address;
|
||||
treasury_enote.amount = TREASURY_SAL1_MINT_AMOUNT;
|
||||
treasury_enote.asset_type = "SAL1";
|
||||
@@ -580,15 +532,15 @@ namespace cryptonote
|
||||
treasury_enote.view_tag = view_tag;
|
||||
treasury_enote.enote_ephemeral_pubkey = tx_public_key;
|
||||
treasury_enote.block_index = height;
|
||||
|
||||
// sort enotes by K_o
|
||||
if (enotes[0].onetime_address > enotes[1].onetime_address) {
|
||||
std::swap(enotes[0], enotes[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort enotes by K_o
|
||||
std::sort(enotes.begin(), enotes.end(), [](const carrot::CarrotCoinbaseEnoteV1 &a, const carrot::CarrotCoinbaseEnoteV1 &b) {
|
||||
return a.onetime_address < b.onetime_address;
|
||||
});
|
||||
|
||||
tx = carrot::store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER, height);
|
||||
tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : TRANSACTION_VERSION_CARROT;
|
||||
|
||||
tx.amount_burnt = stake_reward;
|
||||
tx.invalidate_hashes();
|
||||
}
|
||||
@@ -603,8 +555,6 @@ namespace cryptonote
|
||||
|
||||
keypair txkey = keypair::generate(hw::get_device("default"));
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
// STORE THE MINER TX_PUB_KEY NOW
|
||||
miner_reward_tx_key = txkey.pub;
|
||||
if(!extra_nonce.empty())
|
||||
if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
|
||||
return false;
|
||||
|
||||
@@ -77,9 +77,7 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------
|
||||
bool construct_protocol_tx(const size_t height, transaction& tx, std::vector<protocol_data_entry>& protocol_data, const uint8_t hf_version);
|
||||
//---------------------------------------------------------------
|
||||
carrot::janus_anchor_t get_deterministic_treasury_anchor_from_height(uint64_t height);
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, crypto::public_key& miner_reward_tx_key, transaction& tx, network_type nettype = network_type::FAKECHAIN, const std::vector<hardfork_t>& hardforks = {}, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, network_type nettype = network_type::FAKECHAIN, const std::vector<hardfork_t>& hardforks = {}, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
|
||||
|
||||
struct tx_source_entry
|
||||
{
|
||||
|
||||
@@ -275,13 +275,6 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
// HERE BE DRAGONS!!!
|
||||
// Check that CREATE_TOKEN txs are unique in the pool
|
||||
if (tx.type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
// TODO: ...scan the existing entries - requires either a registry of CREATE_TOKEN TXs, or to interatively process the pool
|
||||
}
|
||||
// LAND AHOY!!!
|
||||
|
||||
// assume failure during verification steps until success is certain
|
||||
tvc.m_verifivation_failed = true;
|
||||
|
||||
@@ -1656,17 +1649,11 @@ namespace cryptonote
|
||||
|
||||
LOG_PRINT_L2("Filling block template, median weight " << median_weight << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
|
||||
|
||||
LockedTXN lock(m_blockchain.get_db());
|
||||
|
||||
// Store list of tokens being created
|
||||
std::set<std::string> tokens;
|
||||
|
||||
// Get the list of already-created tokens that are in the DB
|
||||
std::map<std::string, cryptonote::token_metadata_t> mapTokens = m_blockchain.get_db().get_tokens();
|
||||
for (const auto &entry: mapTokens) {
|
||||
tokens.insert(entry.second.asset_type);
|
||||
}
|
||||
|
||||
LockedTXN lock(m_blockchain.get_db());
|
||||
|
||||
auto sorted_it = m_txs_by_fee_and_receive_time.begin();
|
||||
for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
|
||||
{
|
||||
|
||||
+1
-2
@@ -149,8 +149,7 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
|
||||
|
||||
//Prepare genesis_tx
|
||||
cryptonote::transaction tx_genesis;
|
||||
crypto::public_key miner_reward_tx_key = crypto::null_pkey;
|
||||
cryptonote::construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().m_account_address, miner_reward_tx_key, tx_genesis, (network_type)nettype, {}, blobdata(), 999, 1);
|
||||
cryptonote::construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().m_account_address, tx_genesis, (network_type)nettype, {}, blobdata(), 999, 1);
|
||||
std::cout << "Object:" << std::endl;
|
||||
std::cout << obj_to_json_str(tx_genesis) << std::endl << std::endl;
|
||||
|
||||
|
||||
@@ -61,9 +61,6 @@ const hardfork_t mainnet_hard_forks[] = {
|
||||
|
||||
// version 10 Carrot - including treasury mint - starts from block 334750, which is on or around the 13th of October, 2025. Fork time finalised on 2025-09-29. No fork voting occurs for the v10 fork.
|
||||
{10, 334750, 0, 1759142500 },
|
||||
|
||||
// version 11 Two Milestone 1 - starts from block 465000, which is on or around the 13th of April, 2026. Fork time finalised on 2026-03-20. No fork voting occurs for the v11 fork.
|
||||
{11, 465000, 0, 1774000000 },
|
||||
};
|
||||
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
|
||||
const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
|
||||
@@ -1871,22 +1871,40 @@ namespace cryptonote
|
||||
bool core_rpc_server::get_block_template(const account_public_address &address, const crypto::hash *prev_block, const cryptonote::blobdata &extra_nonce, size_t &reserved_offset, cryptonote::difficulty_type &difficulty, uint64_t &height, uint64_t &expected_reward, block &b, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, epee::json_rpc::error &error_resp)
|
||||
{
|
||||
b = boost::value_initialized<cryptonote::block>();
|
||||
crypto::public_key tx_pub_key = crypto::null_pkey;
|
||||
if(!m_core.get_block_template(b, prev_block, address, difficulty, height, expected_reward, extra_nonce, seed_height, seed_hash, tx_pub_key))
|
||||
if(!m_core.get_block_template(b, prev_block, address, difficulty, height, expected_reward, extra_nonce, seed_height, seed_hash))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: failed to create block template";
|
||||
LOG_ERROR("Failed to create block template");
|
||||
return false;
|
||||
}
|
||||
blobdata block_blob = t_serializable_object_to_blob(b);
|
||||
crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx);
|
||||
const std::vector<crypto::public_key> additional_tx_pub_keys = cryptonote::get_additional_tx_pub_keys_from_extra(b.miner_tx);
|
||||
if(tx_pub_key == crypto::null_pkey)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: failed to create block template";
|
||||
LOG_ERROR("Failed to get tx pub key in coinbase extra");
|
||||
return false;
|
||||
// Check for Carrot treasury payout
|
||||
const uint8_t hf_version = m_core.get_blockchain_storage().get_current_hard_fork_version();
|
||||
if (hf_version >= HF_VERSION_CARROT && b.miner_tx.vout.size() == 2) {
|
||||
|
||||
const auto treasury_payout_data = get_config(nettype()).TREASURY_SAL1_MINT_OUTPUT_DATA;
|
||||
const bool treasury_payout_exists = (treasury_payout_data.count(height) == 1);
|
||||
if (!treasury_payout_exists) {
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: failed to create block template (missing treasury payout)";
|
||||
LOG_ERROR("Failed to get tx pub key in coinbase extra (missing treasury payout)");
|
||||
return false;
|
||||
}
|
||||
tx_pub_key = additional_tx_pub_keys.back();
|
||||
|
||||
} else {
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: failed to create block template";
|
||||
LOG_ERROR("Failed to get tx pub key in coinbase extra");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
blobdata block_blob = t_serializable_object_to_blob(b);
|
||||
|
||||
uint64_t next_height;
|
||||
crypto::rx_seedheights(height, &seed_height, &next_height);
|
||||
if (next_height != seed_height)
|
||||
|
||||
@@ -8072,30 +8072,11 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
|
||||
std::string asset_type = (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) ? "SAL1" : "SAL";
|
||||
if (local_args.size() >= 2)
|
||||
{
|
||||
std::string strLastArg = local_args.back();
|
||||
if (strLastArg == "SAL" or strLastArg == "SAL1") {
|
||||
asset_type = strLastArg;
|
||||
} else {
|
||||
std::transform(strLastArg.begin() + 3, strLastArg.end(), strLastArg.begin() + 3, ::toupper);
|
||||
std::vector<std::string> asset_types = m_wallet->list_asset_types();
|
||||
|
||||
// check if the last argument is a known asset type
|
||||
bool found = false;
|
||||
for (const auto& asset : asset_types) {
|
||||
if (strLastArg == asset) {
|
||||
asset_type = strLastArg;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
fail_msg_writer() << tr("Unknown asset type: ") << strLastArg;
|
||||
return true;
|
||||
}
|
||||
std::string asset_type_check = local_args.back();
|
||||
if (cryptonote::is_valid_asset_type(asset_type_check)) {
|
||||
asset_type = asset_type_check;
|
||||
local_args.pop_back();
|
||||
}
|
||||
|
||||
local_args.pop_back();
|
||||
}
|
||||
|
||||
cryptonote::address_parse_info info;
|
||||
@@ -8774,15 +8755,9 @@ bool simple_wallet::burn(const std::vector<std::string> &args_)
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t hf_version = m_wallet->get_current_hard_fork();
|
||||
if (hf_version >= HF_VERSION_CARROT && hf_version < HF_VERSION_ENABLE_TOKENS) {
|
||||
fail_msg_writer() << tr("BURN command is disabled until hard fork ") << HF_VERSION_ENABLE_TOKENS;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> local_args;
|
||||
carrot::AddressDeriveType derive_type;
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
if (m_wallet->use_fork_rules(HF_VERSION_CARROT, 0)) {
|
||||
derive_type = carrot::AddressDeriveType::Carrot;
|
||||
} else {
|
||||
derive_type = carrot::AddressDeriveType::PreCarrot;
|
||||
@@ -8801,7 +8776,7 @@ bool simple_wallet::burn(const std::vector<std::string> &args_)
|
||||
asset_type = strLastArg;
|
||||
local_args.pop_back();
|
||||
|
||||
if (hf_version >= HF_VERSION_ENABLE_TOKENS) {
|
||||
if (m_wallet->get_current_hard_fork() >= HF_VERSION_ENABLE_TOKENS) {
|
||||
transfer_main(Burn, asset_type, asset_type, local_args, false);
|
||||
} else {
|
||||
transfer_main(Burn, asset_type, "BURN", local_args, false);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_SALVIUM_VERSION "1.1.1"
|
||||
#define DEF_SALVIUM_VERSION "1.1.0-rc3"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.4.0"
|
||||
#define DEF_MONERO_RELEASE_NAME "One"
|
||||
|
||||
@@ -178,8 +178,7 @@ void TransactionHistoryImpl::refresh()
|
||||
uint64_t amount = pd.m_amount_in - change - fee;
|
||||
if (pd.m_tx.type == cryptonote::transaction_type::AUDIT ||
|
||||
pd.m_tx.type == cryptonote::transaction_type::BURN ||
|
||||
pd.m_tx.type == cryptonote::transaction_type::STAKE ||
|
||||
pd.m_tx.type == cryptonote::transaction_type::ROLLUP) {
|
||||
pd.m_tx.type == cryptonote::transaction_type::STAKE) {
|
||||
amount = pd.m_tx.amount_burnt;
|
||||
if (fee > amount) fee -= amount;
|
||||
}
|
||||
@@ -224,8 +223,7 @@ void TransactionHistoryImpl::refresh()
|
||||
uint64_t amount = pd.m_amount_in - change - fee;
|
||||
if (pd.m_tx.type == cryptonote::transaction_type::AUDIT ||
|
||||
pd.m_tx.type == cryptonote::transaction_type::BURN ||
|
||||
pd.m_tx.type == cryptonote::transaction_type::STAKE ||
|
||||
pd.m_tx.type == cryptonote::transaction_type::ROLLUP) {
|
||||
pd.m_tx.type == cryptonote::transaction_type::STAKE) {
|
||||
amount = pd.m_tx.amount_burnt;
|
||||
if (fee > amount) fee -= amount;
|
||||
}
|
||||
|
||||
@@ -9574,7 +9574,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||
// check we're clear enough of rct start, to avoid corner cases below
|
||||
THROW_WALLET_EXCEPTION_IF(rct_offsets.size() <= CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE,
|
||||
error::get_output_distribution, "Not enough rct outputs");
|
||||
THROW_WALLET_EXCEPTION_IF(rct_offsets.back() < max_rct_index,
|
||||
THROW_WALLET_EXCEPTION_IF(rct_offsets.back() <= max_rct_index,
|
||||
error::get_output_distribution, "Daemon reports suspicious number of rct outputs");
|
||||
}
|
||||
|
||||
@@ -11089,7 +11089,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
|
||||
// Is this a BURN TX?
|
||||
if (hf_version >= HF_VERSION_ENABLE_TOKENS && tx_type == cryptonote::transaction_type::BURN) {
|
||||
THROW_WALLET_EXCEPTION_IF(source_asset != "SAL" && source_asset != "SAL1", error::wallet_internal_error, "Only SAL/SAL1 may be burnt");
|
||||
THROW_WALLET_EXCEPTION_IF(source_asset != "SAL" && source_asset != "SAL1", error::wallet_internal_error, "Only SAL and SAL1 may be burnt");
|
||||
THROW_WALLET_EXCEPTION_IF(dsts.size() != 1, error::wallet_internal_error, "Only 1 destination permitted for BURN");
|
||||
dsts[0].asset_type = source_asset;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user