Compare commits

..

16 Commits

Author SHA1 Message Date
Codex Bot 1998d79c3e Keep tx info sync without polyseed API drift
ci/gh-actions/depends / Cross-Mac aarch64 (push) Failing after 7m38s
ci/gh-actions/depends / ARM v7 (push) Has been cancelled
ci/gh-actions/depends / i686 Linux (push) Has been cancelled
ci/gh-actions/depends / i686 Win (push) Has been cancelled
ci/gh-actions/depends / RISCV 64bit (push) Has been cancelled
ci/gh-actions/depends / Cross-Mac x86_64 (push) Has been cancelled
ci/gh-actions/depends / x86_64 Freebsd (push) Has been cancelled
ci/gh-actions/depends / x86_64 Linux (push) Has been cancelled
ci/gh-actions/depends / Win64 (push) Has been cancelled
ci/gh-actions/depends / ARM v8 (push) Has been cancelled
2026-04-06 18:40:08 +02:00
Codex Bot ea4d5a9132 Fix subdirectory linker flag checks
ci/gh-actions/depends / Cross-Mac aarch64 (push) Has been cancelled
ci/gh-actions/depends / ARM v8 (push) Has been cancelled
ci/gh-actions/depends / ARM v7 (push) Has been cancelled
ci/gh-actions/depends / i686 Linux (push) Has been cancelled
ci/gh-actions/depends / i686 Win (push) Has been cancelled
ci/gh-actions/depends / RISCV 64bit (push) Has been cancelled
ci/gh-actions/depends / Cross-Mac x86_64 (push) Has been cancelled
ci/gh-actions/depends / x86_64 Freebsd (push) Has been cancelled
ci/gh-actions/depends / x86_64 Linux (push) Has been cancelled
ci/gh-actions/depends / Win64 (push) Has been cancelled
2026-04-06 18:38:28 +02:00
Codex Bot 585f7b9d05 Add store tx info and return addresses API
ci/gh-actions/depends / Cross-Mac aarch64 (push) Has been cancelled
ci/gh-actions/depends / ARM v8 (push) Has been cancelled
ci/gh-actions/depends / ARM v7 (push) Has been cancelled
ci/gh-actions/depends / i686 Linux (push) Has been cancelled
ci/gh-actions/depends / i686 Win (push) Has been cancelled
ci/gh-actions/depends / RISCV 64bit (push) Has been cancelled
ci/gh-actions/depends / Cross-Mac x86_64 (push) Has been cancelled
ci/gh-actions/depends / x86_64 Freebsd (push) Has been cancelled
ci/gh-actions/depends / x86_64 Linux (push) Has been cancelled
ci/gh-actions/depends / Win64 (push) Has been cancelled
2026-04-06 18:36:27 +02:00
Some Random Crypto Guy b7c707bd4e added hashes file for v1.1.1 2026-04-02 11:02:12 +01:00
Some Random Crypto Guy b57d2c338c bumped version to v1.1.1 2026-04-02 08:48:00 +01:00
Some Random Crypto Guy 28069fc84b Merge branch 'display-rollup-tx-amount-burnt' 2026-04-02 08:44:47 +01:00
Some Random Crypto Guy d7ec62cdbe fixed RPC-based mining issues with block cache template for some miners 2026-04-02 08:43:48 +01:00
auruya 244fc7acaa display amount_burnt for rollup txs 2026-04-01 13:24:10 +03:00
Some Random Crypto Guy 3716330ac7 added hashes file for mainnet release 2026-03-30 14:42:23 +01:00
Some Random Crypto Guy c4e7f6e0f0 implementation of treasury block reward; various fixes for P2Pool and solo-xmrig miners 2026-03-30 12:50:49 +01:00
Some Random Crypto Guy c0862ea66e bumped testnet to (hopefully) final version for Milestone-1 2026-03-27 11:09:25 +00:00
Some Random Crypto Guy 67b41240d2 improved miner_tx security relating to treasury block reward; updated fast-sync checkpoints to block 450000 2026-03-27 11:01:13 +00:00
Some Random Crypto Guy 16110603a1 updated 'fork date set' timestamp to correct value 2026-03-26 08:57:52 +00:00
Some Random Crypto Guy 83934efaad treasury reward payout added for HF11 2026-03-25 19:55:35 +00:00
Some Random Crypto Guy 6fb167308c fixed small asset_type issue for sweep; added HF11 block height 2026-03-23 10:16:26 +00:00
Some Random Crypto Guy d6f95156bc added 1.1.0-rc6 hashes; added consensus block on SAL* tokens 2026-03-19 16:34:50 +00:00
26 changed files with 427 additions and 119 deletions
+5 -5
View File
@@ -1,4 +1,4 @@
# Salvium One v1.0.7
# Salvium One v1.1.1
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.0.7
git checkout v1.1.1
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.0.7
git checkout v1.1.1
```
* 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.0.7'. 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.1.1'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v1.0.7
git checkout v1.1.1
```
* If you are on a 64-bit system, run:
+1 -1
View File
@@ -6,7 +6,7 @@ macro(CHECK_LINKER_FLAG flag VARIABLE)
message(STATUS "Looking for ${flag} linker flag")
endif()
set(_cle_source ${CMAKE_SOURCE_DIR}/cmake/CheckLinkerFlag.c)
set(_cle_source ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckLinkerFlag.c)
set(saved_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
set(CMAKE_C_FLAGS "${flag}")
+5
View File
@@ -0,0 +1,5 @@
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
+5
View File
@@ -0,0 +1,5 @@
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
+5
View File
@@ -0,0 +1,5 @@
d22bbe19fa5e7eb7ebaf95eee336d73cbd59ded7b5e737213e89a8b84d5791eb salvium-v1.1.1-macos-aarch64.zip
262e2bdffc3c4fee89ec79451a6181175671db5874726d359077c4479754076e salvium-v1.1.1-macos-x86_64.zip
72b37fa30df6b136dba380b88e9ccc4d66804d8286a221a87e944e337f4ba593 salvium-v1.1.1-ubuntu22.04-linux-aarch64.zip
33321419bb426507de0f5de7c1977e436ca34bf4db620fa00eede1fa318b7994 salvium-v1.1.1-ubuntu22.04-linux-x86_64.zip
33e7c1e1bc4e5a1f9c40482eba993a5efb97a8feedfb36dca863bbb5bd9e794f salvium-v1.1.1-win64.zip
Binary file not shown.
+2 -1
View File
@@ -175,7 +175,8 @@ namespace cryptonote
uint64_t seed_height;
crypto::hash seed_hash;
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, seed_height, 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))
{
LOG_ERROR("Failed to get_block_template(), stopping mining");
m_forced_stop = true;
+1 -1
View File
@@ -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) = 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;
protected:
~i_miner_handler(){};
};
+15 -3
View File
@@ -94,6 +94,10 @@
#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
@@ -254,7 +258,7 @@
#define HF_VERSION_ENABLE_ORACLE 255
#define HF_VERSION_SLIPPAGE_YIELD 255
#define TESTNET_VERSION 17
#define TESTNET_VERSION 18
#define STAGENET_VERSION 1
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
@@ -319,9 +323,10 @@ 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, vie_tag} tuples
// treasury payout {tx-key, output-key, anchor_enc, view_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"}},
@@ -423,9 +428,11 @@ namespace config
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
"-----END PUBLIC KEY-----\n";
std::string const TREASURY_ADDRESS = "SaLvTyLFta9BiAXeUfFkKvViBkFt4ay5nEUBpWyDKewYggtsoxBbtCUVqaBjtcCDyY1euun8Giv7LLEgvztuurLo5a6Km1zskZn36";
std::string const TREASURY_ADDRESS_CARROT = "SC1TouvX6e4HmkAqsU6AAXLRjgeZnnKHjSpVfMHepTXramNMT2P47AsDmteLH81wdPR2DwMg3cxKvgrhUBeDSUW6MhM3sQb92we";
std::string const TREASURY_ADDRESS = "SaLvTyL2pN2SCAPRxwDQ7qjhdg46VbhZrGZTp2wHKJ5sK434a8ivEH35eWp2FTcmyW6LY6ExfBb9chmQ9xAL1eJyZ5FQjtQGTis3v";
// 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"}},
@@ -467,6 +474,7 @@ 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
@@ -521,6 +529,7 @@ 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)
@@ -544,6 +553,7 @@ 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 = {
@@ -565,6 +575,7 @@ 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 = {
@@ -586,6 +597,7 @@ 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)
+177 -38
View File
@@ -58,6 +58,8 @@
#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"
@@ -1489,7 +1491,53 @@ std::tuple<bool, size_t> Blockchain::validate_treasury_payout(const transaction&
return {false, 0};
}
return {true, output - tx.vout.begin()};
// 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};
}
//------------------------------------------------------------------
// This function validates the miner transaction reward
@@ -1512,42 +1560,23 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
treasury_index_in_tx_outputs = index_in_tx_outputs;
}
//validate reward
// Calculate reward being issued
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;
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;
}
// Make sure the TOTAL REWARD is correct
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))
{
@@ -1564,6 +1593,114 @@ 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;
}
//------------------------------------------------------------------
@@ -1894,7 +2031,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)
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)
{
LOG_PRINT_L3("Blockchain::" << __func__);
size_t median_weight;
@@ -1923,6 +2060,7 @@ 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));
@@ -2237,9 +2375,6 @@ 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");
@@ -2303,8 +2438,9 @@ 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 >= 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);
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);
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)
@@ -2313,7 +2449,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, 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, miner_reward_tx_key, 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);
@@ -2358,16 +2494,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);
cache_block_template(b, miner_address, ex_nonce, diffic, height, expected_reward, seed_height, seed_hash, pool_cookie, miner_reward_tx_key);
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)
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)
{
return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash, miner_reward_tx_key);
}
//------------------------------------------------------------------
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)
@@ -4099,6 +4235,8 @@ 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;
@@ -6805,7 +6943,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "7e6c9efd949afb36bce062bbb720605f0dd67b03c0124e5167c527fa59c15ce3";
static const char expected_block_hashes_hash[] = "f3bf12451890c9cbeb9f90b2762e4ee2756aaa726958e280e27b51ed9edf84b3";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
@@ -6947,7 +7085,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)
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)
{
MDEBUG("Setting block template cache");
m_btc = b;
@@ -6959,6 +7097,7 @@ 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;
}
+4 -4
View File
@@ -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);
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);
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);
/**
* @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);
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);
/**
* @brief sends new block notifications to ZMQ `miner_data` subscribers
+4 -4
View File
@@ -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)
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)
{
return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce, seed_height, 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);
}
//-----------------------------------------------------------------------------------------------
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)
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)
{
return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce, seed_height, 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);
}
//-----------------------------------------------------------------------------------------------
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)
+2 -2
View File
@@ -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) 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);
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);
/**
* @copydoc Blockchain::get_miner_data
+74 -25
View File
@@ -459,7 +459,17 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
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) {
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) {
// Clear the TX contents
tx.set_null();
@@ -487,33 +497,70 @@ namespace cryptonote
{
try
{
// Build the miner payout
carrot::CarrotDestinationV1 destination;
// miner destination
carrot::CarrotDestinationV1 miner_destination;
carrot::make_carrot_main_address_v1(miner_address.m_spend_public_key,
miner_address.m_view_public_key,
destination);
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");
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");
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);
uint64_t stake_reward = block_reward / 5;
const carrot::CarrotPaymentProposalV1 payment_proposal{
.destination = destination,
.amount = block_reward - stake_reward,
//miner enote
const carrot::CarrotPaymentProposalV1 miner_proposal{
.destination = miner_destination,
.amount = miner_reward,
.asset_type = "SAL1",
.randomness = carrot::gen_janus_anchor()
};
std::vector<carrot::CarrotCoinbaseEnoteV1> enotes(treasury_payout_exists ? 2 : 1);
carrot::get_coinbase_output_proposal_v1(payment_proposal, height, enotes.front());
// 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]);
// Check to see if there needs to be a treasury payout
// 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++;
}
//
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");
@@ -524,8 +571,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");
// Manually produce an enote for the treasury payout using the hardcoded keys
carrot::CarrotCoinbaseEnoteV1 &treasury_enote = enotes.back();
//
carrot::CarrotCoinbaseEnoteV1 &treasury_enote = enotes[enote_idx];
treasury_enote.onetime_address = onetime_address;
treasury_enote.amount = TREASURY_SAL1_MINT_AMOUNT;
treasury_enote.asset_type = "SAL1";
@@ -533,13 +580,13 @@ 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;
@@ -556,6 +603,8 @@ 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;
+3 -1
View File
@@ -77,7 +77,9 @@ namespace cryptonote
//---------------------------------------------------------------
bool construct_protocol_tx(const size_t height, transaction& tx, std::vector<protocol_data_entry>& protocol_data, const uint8_t hf_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 = 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);
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);
struct tx_source_entry
{
+2 -1
View File
@@ -149,7 +149,8 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
//Prepare genesis_tx
cryptonote::transaction tx_genesis;
cryptonote::construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().m_account_address, tx_genesis, (network_type)nettype, {}, blobdata(), 999, 1);
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);
std::cout << "Object:" << std::endl;
std::cout << obj_to_json_str(tx_genesis) << std::endl << std::endl;
+3
View File
@@ -61,6 +61,9 @@ 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);
+7 -25
View File
@@ -1871,40 +1871,22 @@ 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>();
if(!m_core.get_block_template(b, prev_block, address, difficulty, height, expected_reward, extra_nonce, seed_height, seed_hash))
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))
{
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)
{
// 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;
}
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)
+23 -4
View File
@@ -8072,11 +8072,30 @@ 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 asset_type_check = local_args.back();
if (cryptonote::is_valid_asset_type(asset_type_check)) {
asset_type = asset_type_check;
local_args.pop_back();
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;
}
}
local_args.pop_back();
}
cryptonote::address_parse_info info;
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
#define DEF_SALVIUM_VERSION "1.1.0-rc6"
#define DEF_SALVIUM_VERSION "1.1.1"
#define DEF_MONERO_VERSION_TAG "release"
#define DEF_MONERO_VERSION "0.18.4.0"
#define DEF_MONERO_RELEASE_NAME "One"
+66 -3
View File
@@ -34,16 +34,60 @@
#include "wallet.h"
#include "crypto/hash.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "wallet/wallet2.h"
#include <string>
#include <list>
#include <unordered_map>
#include <unordered_set>
using namespace epee;
namespace Monero {
namespace {
std::string to_hex_or_empty(const crypto::public_key &key)
{
if (key == crypto::null_pkey)
return {};
return string_tools::pod_to_hex(key);
}
std::vector<std::string> extract_return_addresses(const cryptonote::transaction_prefix &tx)
{
std::vector<std::string> addresses;
if (tx.type == cryptonote::transaction_type::STAKE)
{
auto hex = to_hex_or_empty(tx.protocol_tx_data.return_address);
if (hex.empty())
hex = to_hex_or_empty(tx.return_address);
if (!hex.empty())
addresses.push_back(hex);
return addresses;
}
if (tx.type != cryptonote::transaction_type::PROTOCOL)
return addresses;
std::unordered_set<std::string> seen;
for (const auto &out : tx.vout)
{
crypto::public_key output_key = crypto::null_pkey;
if (!cryptonote::get_output_public_key(out, output_key))
continue;
auto hex = to_hex_or_empty(output_key);
if (hex.empty())
continue;
if (seen.emplace(hex).second)
addresses.push_back(hex);
}
return addresses;
}
} // namespace
TransactionHistory::~TransactionHistory() {}
@@ -130,6 +174,7 @@ void TransactionHistoryImpl::refresh()
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> in_payments;
m_wallet->m_wallet->get_payments(in_payments, min_height, max_height);
std::unordered_map<crypto::hash, TransactionInfoImpl*> protocol_by_hash;
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = in_payments.begin(); i != in_payments.end(); ++i) {
const tools::wallet2::payment_details &pd = i->second;
std::string payment_id = string_tools::pod_to_hex(i->first);
@@ -152,6 +197,8 @@ void TransactionHistoryImpl::refresh()
ti->m_unlock_time = pd.m_unlock_time;
ti->m_type = static_cast<Monero::transaction_type>(static_cast<uint8_t>(pd.m_tx_type));
ti->m_asset = pd.m_asset_type;
if (pd.m_tx_type == cryptonote::transaction_type::PROTOCOL)
protocol_by_hash.emplace(pd.m_tx_hash, ti);
m_history.push_back(ti);
}
@@ -178,7 +225,8 @@ 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::STAKE ||
pd.m_tx.type == cryptonote::transaction_type::ROLLUP) {
amount = pd.m_tx.amount_burnt;
if (fee > amount) fee -= amount;
}
@@ -203,6 +251,7 @@ void TransactionHistoryImpl::refresh()
ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0;
ti->m_type = static_cast<Monero::transaction_type>(static_cast<uint8_t>(pd.m_tx.type));
ti->m_asset = pd.m_tx.source_asset_type;
ti->m_return_addresses = extract_return_addresses(pd.m_tx);
// single output transaction might contain multiple transfers
for (const auto &d: pd.m_dests) {
@@ -223,7 +272,8 @@ 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::STAKE ||
pd.m_tx.type == cryptonote::transaction_type::ROLLUP) {
amount = pd.m_tx.amount_burnt;
if (fee > amount) fee -= amount;
}
@@ -249,6 +299,7 @@ void TransactionHistoryImpl::refresh()
ti->m_confirmations = 0;
ti->m_type = static_cast<Monero::transaction_type>(static_cast<uint8_t>(pd.m_tx.type));
ti->m_asset = pd.m_tx.source_asset_type;
ti->m_return_addresses = extract_return_addresses(pd.m_tx);
for (const auto &d : pd.m_dests)
{
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id), d.asset_type});
@@ -280,11 +331,23 @@ void TransactionHistoryImpl::refresh()
ti->m_confirmations = 0;
ti->m_type = static_cast<Monero::transaction_type>(static_cast<uint8_t>(pd.m_tx_type));
ti->m_asset = pd.m_asset_type;
if (pd.m_tx_type == cryptonote::transaction_type::PROTOCOL)
protocol_by_hash.emplace(pd.m_tx_hash, ti);
m_history.push_back(ti);
LOG_PRINT_L1(__FUNCTION__ << ": Unconfirmed payment found " << pd.m_amount);
}
std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> confirmed_protocol_payments;
m_wallet->m_wallet->get_payments_out(confirmed_protocol_payments, min_height, max_height);
for (const auto &entry : confirmed_protocol_payments)
{
const auto it = protocol_by_hash.find(entry.first);
if (it == protocol_by_hash.end())
continue;
it->second->m_return_addresses = extract_return_addresses(entry.second.m_tx);
}
}
} // namespace
+5
View File
@@ -134,6 +134,11 @@ string TransactionInfoImpl::paymentId() const
return m_paymentid;
}
const std::vector<std::string> &TransactionInfoImpl::returnAddresses() const
{
return m_return_addresses;
}
const std::vector<TransactionInfo::Transfer> &TransactionInfoImpl::transfers() const
{
return m_transfers;
+2
View File
@@ -60,6 +60,7 @@ public:
virtual std::string hash() const override;
virtual std::time_t timestamp() const override;
virtual std::string paymentId() const override;
virtual const std::vector<std::string> &returnAddresses() const override;
virtual const std::vector<Transfer> &transfers() const override;
virtual uint64_t confirmations() const override;
virtual uint64_t unlockTime() const override;
@@ -81,6 +82,7 @@ private:
std::string m_hash;
std::time_t m_timestamp;
std::string m_paymentid;
std::vector<std::string> m_return_addresses;
std::vector<Transfer> m_transfers;
uint64_t m_confirmations;
uint64_t m_unlock_time;
+10
View File
@@ -806,6 +806,16 @@ std::string WalletImpl::seed(const std::string& seed_offset) const
return std::string(seed.data(), seed.size()); // TODO
}
void WalletImpl::setStoreTxInfo(bool store)
{
m_wallet->store_tx_info(store);
}
bool WalletImpl::storeTxInfo() const
{
return m_wallet->store_tx_info();
}
std::string WalletImpl::getSeedLanguage() const
{
return m_wallet->get_seed_language();
+2
View File
@@ -83,6 +83,8 @@ public:
Device getDeviceType() const override;
bool close(bool store = true);
std::string seed(const std::string& seed_offset = "") const override;
void setStoreTxInfo(bool store) override;
bool storeTxInfo() const override;
std::string getSeedLanguage() const override;
void setSeedLanguage(const std::string &arg) override;
// void setListener(Listener *) {}
+3
View File
@@ -236,6 +236,7 @@ struct TransactionInfo
virtual std::string hash() const = 0;
virtual std::time_t timestamp() const = 0;
virtual std::string paymentId() const = 0;
virtual const std::vector<std::string> & returnAddresses() const = 0;
//! only applicable for output transactions
virtual const std::vector<Transfer> & transfers() const = 0;
virtual Monero::transaction_type type() const = 0;
@@ -503,6 +504,8 @@ struct Wallet
virtual ~Wallet() = 0;
virtual std::string seed(const std::string& seed_offset = "") const = 0;
virtual void setStoreTxInfo(bool store) = 0;
virtual bool storeTxInfo() const = 0;
virtual std::string getSeedLanguage() const = 0;
virtual void setSeedLanguage(const std::string &arg) = 0;
//! returns wallet status (Status_Ok | Status_Error)