Compare commits

...

13 Commits

Author SHA1 Message Date
Some Random Crypto Guy 9570c7a910 Merge branch 'hotfix-v0.9.5a' 2025-03-02 22:26:32 +00:00
Some Random Crypto Guy 23756691b7 Hotfix release to address 2 wallet issues:
1. new wallet "set" parameter "send-change-back-to-subaddress [1|0]"
   The change for a transaction can now be sent back to the main address for the wallet (default)
   or to the sending subaddress
   (* please note that for AUDIT TX type, it will ALWAYS be sent back to the subaddress)

2. fixed erroneous code setting "source_asset" in wallet2::process_new_transaction()
   This bug caused change entries to appear in all TXs when querying using "get_transfer_by_txid"
   RPC method as "in" output types. Whilst this is fully conformant to the Monero Docs that
   describe the method in question, it did not conform to the experience of the RPC method users
   or to traditional Monero RPC output.
2025-03-02 22:15:50 +00:00
Some Random Crypto Guy 3eb986fc51 fixed debug build without audit tool 2025-02-25 15:54:50 +00:00
Some Random Crypto Guy b713a08a81 bumped version, ready for fork; fixed up wallet API method for auditing 2025-02-25 13:04:29 +00:00
Some Random Crypto Guy 5bd079af4a updated HF9 block height 2025-02-24 11:50:08 +00:00
Some Random Crypto Guy cd2c7c939c added audit2 as phase 3 2025-02-24 10:57:18 +00:00
Some Random Crypto Guy 2f707e30c6 bumped version number in preparation for hardforks 2025-02-24 10:53:32 +00:00
Some Random Crypto Guy f9726354b8 Merge branch 'develop' 2025-02-24 10:52:28 +00:00
Some Random Crypto Guy fcd78eea7e merged SAL1 support into the wallet API functions 2025-02-24 10:40:13 +00:00
akildemir db740fa037 make a separate tx per subaddress 2025-02-24 13:30:31 +03:00
Some Random Crypto Guy 5971f39e7a added 2nd phase of audit; bumped version 2025-02-19 17:49:38 +00:00
akildemir 02f2eb5ee9 add SAL1 support to wallet api 2025-02-18 12:05:12 +03:00
Some Random Crypto Guy 02ef77bbcc Merge branch 'main' into develop 2025-02-17 23:48:42 +00:00
23 changed files with 324 additions and 172 deletions
+5 -5
View File
@@ -1,4 +1,4 @@
# Salvium Zero v0.9.3
# Salvium Zero v0.9.5
Copyright (c) 2023-2024, Salvium
Portions Copyright (c) 2014-2023, The Monero Project
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
```bash
cd salvium
git checkout v0.9.3
git checkout v0.9.5
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 v0.9.3
git checkout v0.9.5
```
* 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. 'v0.9.3'. 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. 'v0.9.5'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.9.3
git checkout v0.9.5
```
* If you are on a 64-bit system, run:
+2 -4
View File
@@ -142,8 +142,7 @@ set(blockchain_scanner_private_headers)
monero_private_headers(blockchain_scanner
${blockchain_scanner_private_headers})
if (BUILD_TAG)
else()
if (BUILD_AUDIT)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
set(blockchain_audit_sources
blockchain_audit.cpp
@@ -330,8 +329,7 @@ set_property(TARGET blockchain_scanner
OUTPUT_NAME "salvium-blockchain-scanner")
install(TARGETS blockchain_scanner DESTINATION bin)
if (BUILD_TAG)
else()
if (BUILD_AUDIT)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
monero_add_executable(blockchain_audit
${blockchain_audit_sources}
@@ -220,8 +220,7 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
uint32_t txhr[24] = {0};
unsigned int i;
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(net_type).AUDIT_HARD_FORKS;
const uint64_t audit_lock_period = get_config(net_type).AUDIT_LOCK_PERIOD;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(net_type).AUDIT_HARD_FORKS;
for (uint64_t h = block_start; h < block_stop; ++h)
{
@@ -300,7 +299,7 @@ skip:
}
protocol_tx_assets.insert(asset_type);
if (protocol_tx_vout.amount > 25000000000000) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "large protocol TX amount detected from height " << (h-audit_lock_period) << delimiter << "amount:" << protocol_tx_vout.amount << std::endl;
//std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "large protocol TX amount detected from height " << (h-audit_lock_period) << delimiter << "amount:" << protocol_tx_vout.amount << std::endl;
}
crypto::public_key key;
cryptonote::get_output_public_key(protocol_tx_vout, key);
Binary file not shown.
@@ -1276,10 +1276,13 @@ namespace cryptonote
if (hf_version < HF_VERSION_SALVIUM_ONE_PROOFS) {
// Prior to the first audit, ONLY SAL was supported
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
} else if (hf_version == HF_VERSION_SALVIUM_ONE_PROOFS) {
} else {
if (tx.type == cryptonote::transaction_type::AUDIT) {
// HERE BE DRAGONS!!!
// SRCG: This will NOT always be the case - when we add an audit for SALx it'll need to support that as well
// The CHANGE for an AUDIT TX must be SAL (and 0 value, and unspendable, and to the origin wallet, and ...)
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
// LAND AHOY!!!
} else if (tx.type == cryptonote::transaction_type::PROTOCOL) {
// PROTOCOL TXs are responsible for paying out SAL and SAL1 during the AUDIT
CHECK_AND_ASSERT_MES(asset_type == "SAL1" || asset_type == "SAL", false, "wrong output asset type:" << asset_type);
@@ -1287,9 +1290,6 @@ namespace cryptonote
// All other TX types must only spend + create SAL1 (MINER, TRANSFER)
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
}
} else {
// After the first AUDIT, only SAL1 is supported
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
}
}
return true;
+16 -11
View File
@@ -232,6 +232,8 @@
#define HF_VERSION_SALVIUM_ONE_PROOFS 6
#define HF_VERSION_AUDIT1_PAUSE 7
#define HF_VERSION_AUDIT2 8
#define HF_VERSION_AUDIT2_PAUSE 9
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
#define HF_VERSION_ENABLE_CONVERT 255
@@ -289,10 +291,12 @@ namespace config
uint32_t const GENESIS_NONCE = 10000;
const std::map<uint8_t, std::pair<std::string, std::string>> AUDIT_HARD_FORKS = { {HF_VERSION_AUDIT1, {"SAL", "SAL1"}} };
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = {
{HF_VERSION_AUDIT1, {30*24*10, {"SAL", "SAL1"}}},
{HF_VERSION_AUDIT2, {30*24*14, {"SAL", "SAL1"}}}
};
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
const uint64_t AUDIT_LOCK_PERIOD = 30*24*10;
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
@@ -365,8 +369,12 @@ namespace config
std::string const GENESIS_TX = "020001ff000180c0d0c7bbbff60302838f76f69b70bb0d0f1961a12f6082a033d22285c07d4f12ec93c28197ae2a600353414c3c2101009e8b0abce686c417a1b1344eb7337176bdca90cc928b0facec8a9516190645010000";
uint32_t const GENESIS_NONCE = 10001;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = {
{HF_VERSION_AUDIT1, {30, {"SAL", "SAL1"}}},
{HF_VERSION_AUDIT2, {40, {"SAL", "SAL1"}}},
};
const uint64_t STAKE_LOCK_PERIOD = 20;
const uint64_t AUDIT_LOCK_PERIOD = 30;
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
@@ -392,8 +400,9 @@ namespace config
std::string const GENESIS_TX = "013c01ff0001ffffffffffff0302df5d56da0c7d643ddd1ce61901c7bdc5fb1738bfe39fbe69c28a3a7032729c0f2101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b";
uint32_t const GENESIS_NONCE = 10002;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = { {HF_VERSION_AUDIT1, {30, {"SAL", "SAL1"}}} };
const uint64_t STAKE_LOCK_PERIOD = 20;
const uint64_t AUDIT_LOCK_PERIOD = 30;
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
@@ -430,8 +439,7 @@ namespace cryptonote
std::array<std::string, 3> const ORACLE_URLS;
std::string const ORACLE_PUBLIC_KEY;
uint64_t const STAKE_LOCK_PERIOD;
uint64_t const AUDIT_LOCK_PERIOD;
std::map<uint8_t, std::pair<std::string, std::string>> const AUDIT_HARD_FORKS;
std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> const AUDIT_HARD_FORKS;
std::string TREASURY_ADDRESS;
};
inline const config_t& get_config(network_type nettype)
@@ -449,7 +457,6 @@ namespace cryptonote
::config::ORACLE_URLS,
::config::ORACLE_PUBLIC_KEY,
::config::STAKE_LOCK_PERIOD,
::config::AUDIT_LOCK_PERIOD,
::config::AUDIT_HARD_FORKS,
::config::TREASURY_ADDRESS
};
@@ -466,8 +473,7 @@ namespace cryptonote
::config::testnet::ORACLE_URLS,
::config::testnet::ORACLE_PUBLIC_KEY,
::config::testnet::STAKE_LOCK_PERIOD,
::config::testnet::AUDIT_LOCK_PERIOD,
::config::AUDIT_HARD_FORKS,
::config::testnet::AUDIT_HARD_FORKS,
::config::testnet::TREASURY_ADDRESS
};
static const config_t stagenet = {
@@ -483,8 +489,7 @@ namespace cryptonote
::config::stagenet::ORACLE_URLS,
::config::stagenet::ORACLE_PUBLIC_KEY,
::config::stagenet::STAKE_LOCK_PERIOD,
::config::stagenet::AUDIT_LOCK_PERIOD,
::config::AUDIT_HARD_FORKS,
::config::stagenet::AUDIT_HARD_FORKS,
::config::stagenet::TREASURY_ADDRESS
};
switch (nettype)
+96 -92
View File
@@ -1506,6 +1506,8 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
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:
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;
@@ -1584,25 +1586,29 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
// Get the audit data for the block that matures at this height
std::vector<std::pair<yield_tx_info, uint64_t>> audit_payouts;
uint64_t audit_lock_period = get_config(m_nettype).AUDIT_LOCK_PERIOD;
uint64_t matured_audit_height = height - audit_lock_period - 1;
uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height);
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
if (audit_hard_forks.find(hf) != audit_hard_forks.end()) {
// Maturing height was during an audit - process accordingly
cryptonote::audit_block_info abi_matured;
ok = get_abi_entry(matured_audit_height, abi_matured);
if (!ok) {
LOG_PRINT_L1("Block at height: " << height << " - failed to obtain audit block information - aborting");
return false;
} else if (abi_matured.locked_coins_this_block == 0) {
LOG_PRINT_L1("Block at height: " << height << " - no audit payouts due - skipping");
} else {
// Iterate over the cached data for audits, calculating the audit payouts due
if (!calculate_audit_payouts(matured_audit_height, audit_payouts)) {
LOG_ERROR("Block at height: " << height << " - Failed to obtain audit payout information - aborting");
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
for (const auto &audit_hf : audit_hard_forks) {
uint64_t audit_lock_period = audit_hf.second.first;
uint64_t matured_audit_height = height - audit_lock_period - 1;
uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height);
if (hf == audit_hf.first) {
// Found a matching audit
// Maturing height was during an audit - process accordingly
cryptonote::audit_block_info abi_matured;
ok = get_abi_entry(matured_audit_height, abi_matured);
if (!ok) {
LOG_PRINT_L1("Block at height: " << height << " - failed to obtain audit block information - aborting");
return false;
} else if (abi_matured.locked_coins_this_block == 0) {
LOG_PRINT_L1("Block at height: " << height << " - no audit payouts due - skipping");
} else {
// Iterate over the cached data for audits, calculating the audit payouts due
if (!calculate_audit_payouts(matured_audit_height, audit_payouts)) {
LOG_ERROR("Block at height: " << height << " - Failed to obtain audit payout information - aborting");
return false;
}
}
break;
}
}
@@ -1610,76 +1616,52 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size() + audit_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting");
// go through each vout and validate
std::set<crypto::public_key> used_keys;
for (auto& o : b.protocol_tx.vout) {
// gather the output data
uint64_t out_amount;
uint64_t out_unlock_time;
std::string out_asset_type;
//std::set<crypto::public_key> used_keys;
// Merge the yield and audit payouts into an iterable vector
std::vector<std::pair<yield_tx_info, uint64_t>> payouts{yield_payouts};
payouts.insert(payouts.end(), audit_payouts.begin(), audit_payouts.end());
/*
if (hf_version >= HF_VERSION_AUDIT2) {
std::sort(payouts.begin(), payouts.end(), [](const auto& lhs, const auto& rhs) {
// If block heights are different (only possible with mixed AUDIT+STAKE) sort by them first
if (lhs.first.block_height < rhs.first.block_height) return true;
if (lhs.first.block_height > rhs.first.block_height) return false;
// If output keys are different, sort by them second
if (lhs.first.return_address < rhs.first.return_address) return true;
if (lhs.first.return_address > rhs.first.return_address) return false;
// If block heights _and_ output keys are same, sort by amount third
return lhs.second < rhs.second;
});
}
*/
size_t output_idx = 0;
for (auto it = payouts.begin(); it != payouts.end(); it++, output_idx++) {
// Verify the output key
crypto::public_key out_key;
if (o.target.type() == typeid(txout_to_key)) {
txout_to_key out = boost::get<txout_to_key>(o.target);
out_unlock_time = out.unlock_time;
out_asset_type = out.asset_type;
out_key = out.key;
out_amount = o.amount;
} else if (o.target.type() == typeid(txout_to_tagged_key)) {
txout_to_tagged_key out = boost::get<txout_to_tagged_key>(o.target);
out_unlock_time = out.unlock_time;
out_asset_type = out.asset_type;
out_key = out.key;
out_amount = o.amount;
} else {
MERROR("Block at height: " << height << " attempting to add protocol transaction with invalid type " << o.target.type().name());
return false;
}
cryptonote::get_output_public_key(b.protocol_tx.vout[output_idx], out_key);
CHECK_AND_ASSERT_MES(out_key == it->first.return_address, false, "Incorrect output key detected in protocol_tx");
// Check if key has already been seen
if (used_keys.count(out_key) != 0) {
LOG_ERROR("Block at height: " << height << " - Duplicated output key " << out_key << " for protocol TX - aborting");
return false;
}
// Add key to list of already-seen
used_keys.insert(out_key);
// check if there is entry in the yield payouts or audit payouts for this output
std::string expected_output_asset_type = "SAL";
auto found_yield = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
return p.first.return_address == out_key;
});
auto found_audit = std::find_if(audit_payouts.begin(), audit_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
return p.first.return_address == out_key;
});
if (found_yield == yield_payouts.end() && found_audit == audit_payouts.end()) {
MERROR("Block at height: " << height << " - Failed to locate output for protocol TX - rejecting block");
return false;
} else if (found_audit == audit_payouts.end()) {
// Verify the output amount
CHECK_AND_ASSERT_MES(b.protocol_tx.vout[output_idx].amount == it->second, false, "Incorrect output amount detected in protocol_tx");
// Found a YIELD entry
CHECK_AND_ASSERT_MES(out_amount == found_yield->second, false, "Incorrect value for protocol TX YIELD amount");
uint8_t hf_yield = m_hardfork->get_ideal_version(found_yield->first.block_height);
if (hf_yield >= HF_VERSION_SALVIUM_ONE_PROOFS)
expected_output_asset_type = "SAL1";
// Verify the output asset type
std::string out_asset_type;
cryptonote::get_output_asset_type(b.protocol_tx.vout[output_idx], out_asset_type);
uint8_t hf_yield = m_hardfork->get_ideal_version(it->first.block_height);
if (hf_yield >= HF_VERSION_SALVIUM_ONE_PROOFS)
CHECK_AND_ASSERT_MES(out_asset_type == "SAL1", false, "Incorrect output asset_type (!= SAL1) detected in protocol_tx");
else
CHECK_AND_ASSERT_MES(out_asset_type == "SAL", false, "Incorrect output asset_type (!= SAL) detected in protocol_tx");
} else if (found_yield == yield_payouts.end()) {
// Found an AUDIT entry
CHECK_AND_ASSERT_MES(out_amount == found_audit->second, false, "Incorrect value for protocol TX AUDIT amount");
uint8_t hf_audit = m_hardfork->get_ideal_version(found_audit->first.block_height);
if (hf_audit >= HF_VERSION_SALVIUM_ONE_PROOFS)
expected_output_asset_type = "SAL1";
} else {
// Duplicate entry in yield + audit?!?!?
MERROR("Block at height: " << height << " - Duplicated YIELD and AUDIT keys found for protocol TX - rejecting block");
return false;
}
// check other fields
CHECK_AND_ASSERT_MES(out_unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output");
CHECK_AND_ASSERT_MES(expected_output_asset_type == out_asset_type, false, "Incorrect asset type detected for protocol TX ouput - rejecting block");
// Verify the output unlock time
uint64_t out_unlock_time;
cryptonote::get_output_unlock_time(b.protocol_tx.vout[output_idx], out_unlock_time);
CHECK_AND_ASSERT_MES(out_unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid output unlock time on protocol_tx output");
}
// Everything checks out
@@ -1975,18 +1957,20 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
entry.type = cryptonote::transaction_type::STAKE;
entry.P_change = yield_entry.first.P_change;
entry.return_pubkey = yield_entry.first.return_pubkey;
entry.origin_height = start_height;
protocol_entries.push_back(entry);
}
}
// Get the audit data for the block that matures at this height
std::vector<std::pair<yield_tx_info, uint64_t>> audit_payouts;
uint64_t audit_lock_period = get_config(m_nettype).AUDIT_LOCK_PERIOD;
uint64_t matured_audit_height = height - audit_lock_period - 1;
if (height > audit_lock_period) {
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
for (const auto &audit_hf : audit_hard_forks) {
uint64_t audit_lock_period = audit_hf.second.first;
uint64_t matured_audit_height = height - audit_lock_period - 1;
uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height);
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
if (audit_hard_forks.find(hf) != audit_hard_forks.end()) {
if (hf == audit_hf.first) {
// Found a matching audit
// Maturing height was during an audit - process accordingly
cryptonote::audit_block_info abi_matured;
ok = get_abi_entry(matured_audit_height, abi_matured);
@@ -2003,7 +1987,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
}
// Get the asset types
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf);
const std::pair<std::string, std::string> audit_asset_types = audit_hf.second.second;
// Create the protocol_metadata entries here
for (const auto& audit_entry: audit_payouts) {
@@ -2017,11 +2001,31 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
entry.type = cryptonote::transaction_type::AUDIT;
entry.P_change = audit_entry.first.P_change;
entry.return_pubkey = audit_entry.first.return_pubkey;
entry.origin_height = matured_audit_height;
protocol_entries.push_back(entry);
}
}
break;
}
}
/*
// From v8, we sort the protocol_tx outputs by ORIGIN_HEIGHT, OUTPUT_KEY, AMOUNT
if (b.major_version >= HF_VERSION_AUDIT2) {
std::sort(protocol_entries.begin(), protocol_entries.end(), [](const auto& lhs, const auto& rhs) {
// If origin block heights are different (only possible with mixed AUDIT+STAKE) sort by them first
if (lhs.origin_height < rhs.origin_height) return true;
if (lhs.origin_height > rhs.origin_height) return false;
// If output keys are different, sort by them second
if (lhs.return_address < rhs.return_address) return true;
if (lhs.return_address > rhs.return_address) return false;
// If block heights _and_ output keys are same, sort by amount third
return lhs.amount_burnt < rhs.amount_burnt;
});
}
*/
// Time to construct the protocol_tx
uint64_t protocol_fee = 0;
@@ -3954,9 +3958,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Make sure we are supposed to accept AUDIT txs at this point
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
CHECK_AND_ASSERT_MES(audit_hard_forks.find(hf_version) != audit_hard_forks.end(), false, "trying to audit outside an audit fork");
std::string expected_asset_type = audit_hard_forks.at(hf_version).first;
std::string expected_asset_type = audit_hard_forks.at(hf_version).second.first;
CHECK_AND_ASSERT_MES(tx.source_asset_type == expected_asset_type, false, "trying to spend " << tx.source_asset_type << " coins in an AUDIT TX");
} else {
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
@@ -6279,7 +6283,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "5065d5361119a526b7a45e9e5bdf1d5be86f80e9eb43b0398bf0e47489c81c6d";
static const char expected_block_hashes_hash[] = "131b18108fb3382b4fa82d4eb6cca8f9e1e0ee2aa7893e572361ca0c2c4118e6";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
@@ -449,6 +449,8 @@ namespace cryptonote
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:
// SRCG: subtract 20% that will be rewarded to staking users
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
tx.amount_burnt = amount / 5;
@@ -66,6 +66,7 @@ namespace cryptonote
uint8_t type;
crypto::public_key P_change;
crypto::public_key return_pubkey;
uint64_t origin_height;
};
//---------------------------------------------------------------
+13 -1
View File
@@ -52,6 +52,12 @@ const hardfork_t mainnet_hard_forks[] = {
// version 7 starts from block 161900, which is on or around the 14th of February, 2025. Fork time finalised on 2025-02-04. No fork voting occurs for the v7 fork.
{ 7, 161900, 0, 1739264400 },
// version 8 starts from block 172000, which is on or around the 28th of February, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v8 fork.
{ 8, 172000, 0, 1740390000 },
// version 9 starts from block 179200, which is on or around the 10th of March, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v9 fork.
{ 9, 179200, 0, 1740393800 },
};
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);
@@ -75,8 +81,14 @@ const hardfork_t testnet_hard_forks[] = {
// version 6 (audit 1) starts from block 815
{ 6, 815, 0, 1734608000 },
// version 7 (audit 1 pause) starts from block 900
// version 7 (audit 1 pause, blacklist controlling payouts) starts from block 900
{ 7, 900, 0, 1739264400 },
// version 8 (audit 1 resume) starts from block 950
{ 8, 950, 0, 1739270000 },
// version 9 (audit 1 complete, whitelist controlling payouts) starts from block 1000
{ 9, 1000, 0, 1739280000 },
};
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
+35 -5
View File
@@ -3200,6 +3200,25 @@ bool simple_wallet::set_freeze_incoming_payments(const std::vector<std::string>
return true;
}
bool simple_wallet::set_send_change_back_to_subaddress(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if (args.size() < 2)
{
fail_msg_writer() << tr("Value not specified");
return true;
}
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
parse_bool_and_use(args[1], [&](bool r) {
m_wallet->send_change_back_to_subaddress(r);
m_wallet->rewrite(m_wallet_file, pwd_container->password());
});
}
return true;
}
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if(args.empty())
@@ -3562,7 +3581,9 @@ simple_wallet::simple_wallet()
"inactivity-lock-timeout <unsigned int>\n "
" How many seconds to wait before locking the wallet (0 to disable).\n"
"freeze-incoming-payments <1|0>\n "
" Whether to have incoming payments automatically frozen, so they cannot be spent erroneously."));
" Whether to have incoming payments automatically frozen, so they cannot be spent erroneously.\n"
"send-change-back-to-subaddress <1|0>\n "
" Whether to have change from transactions sent back subaddresses (1) or to main address (0) (ignored for AUDIT commands)."));
m_cmd_binder.set_handler("encrypted_seed",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::encrypted_seed, _1),
tr("Display the encrypted Electrum-style mnemonic seed."));
@@ -3979,6 +4000,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "load-deprecated-formats = " << m_wallet->load_deprecated_formats();
success_msg_writer() << "enable-multisig-experimental = " << m_wallet->is_multisig_enabled();
success_msg_writer() << "freeze-incoming-payments = " << m_wallet->is_freeze_incoming_payments_enabled();
success_msg_writer() << "send-change-back-to-subaddress = " << m_wallet->is_send_change_back_to_subaddress_enabled();
return true;
}
else
@@ -4047,6 +4069,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("credits-target", set_credits_target, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("enable-multisig-experimental", set_enable_multisig, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("freeze-incoming-payments", set_freeze_incoming_payments, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("send-change-back-to-subaddress", set_send_change_back_to_subaddress, tr("0 or 1"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
return true;
@@ -6974,9 +6997,17 @@ bool simple_wallet::transfer_main(
std::string err;
if (transfer_type == Audit) {
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_wallet->nettype()).AUDIT_HARD_FORKS;
uint8_t hf_version = m_wallet->get_current_hard_fork();
const auto audit_hf = audit_hard_forks.find(hf_version);
if (audit_hf == audit_hard_forks.end()) {
fail_msg_writer() << tr("failed to find audit hard fork");
return false;
}
unlock_block = audit_hf->second.first;
// Get the subaddress unlocked balances
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddr = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, source_asset, true);
unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD;
for (const auto subaddr_index : subaddr_indices) {
// Skip this wallet if there is no balance unlocked to audit
@@ -6986,7 +7017,6 @@ bool simple_wallet::transfer_main(
std::set<uint32_t> subaddr_indices_single;
subaddr_indices_single.insert(subaddr_index);
uint64_t unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD;
std::vector<tools::wallet2::pending_tx> ptx_vector_audit = m_wallet->create_transactions_all(0, cryptonote::transaction_type::AUDIT, source_asset, m_wallet->get_subaddress({m_current_subaddress_account, subaddr_index}), (subaddr_index>0), 1, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices_single);
ptx_vector.insert(ptx_vector.end(), ptx_vector_audit.begin(), ptx_vector_audit.end());
@@ -8396,12 +8426,12 @@ bool simple_wallet::audit(const std::vector<std::string> &args_)
return true;
}
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_wallet->nettype()).AUDIT_HARD_FORKS;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_wallet->nettype()).AUDIT_HARD_FORKS;
const uint8_t hf_version = m_wallet->get_current_hard_fork();
if (audit_hard_forks.find(hf_version) != audit_hard_forks.end()) {
// Get the asset types
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf_version);
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf_version).second;
transfer_main(Audit, audit_asset_types.first, audit_asset_types.first, local_args, false);
} else {
+1
View File
@@ -156,6 +156,7 @@ namespace cryptonote
bool set_load_deprecated_formats(const std::vector<std::string> &args = std::vector<std::string>());
bool set_enable_multisig(const std::vector<std::string> &args = std::vector<std::string>());
bool set_freeze_incoming_payments(const std::vector<std::string> &args = std::vector<std::string>());
bool set_send_change_back_to_subaddress(const std::vector<std::string> &args = std::vector<std::string>());
bool set_persistent_rpc_client_id(const std::vector<std::string> &args = std::vector<std::string>());
bool set_auto_mine_for_rpc_payment_threshold(const std::vector<std::string> &args = std::vector<std::string>());
bool set_credits_target(const std::vector<std::string> &args = std::vector<std::string>());
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
#define DEF_SALVIUM_VERSION "0.9.3"
#define DEF_SALVIUM_VERSION "0.9.5a"
#define DEF_MONERO_VERSION_TAG "release"
#define DEF_MONERO_VERSION "0.18.3.3"
#define DEF_MONERO_RELEASE_NAME "Zero"
+3 -1
View File
@@ -65,7 +65,9 @@ void SubaddressAccountImpl::refresh()
m_wallet->m_wallet->get_subaddress_as_str({i,0}),
m_wallet->m_wallet->get_subaddress_label({i,0}),
cryptonote::print_money(m_wallet->m_wallet->balance(i, "SAL", false)),
cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i, "SAL", false))
cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i, "SAL", false)),
cryptonote::print_money(m_wallet->m_wallet->balance(i, "SAL1", false)),
cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i, "SAL1", false))
));
}
}
+6 -2
View File
@@ -151,6 +151,7 @@ void TransactionHistoryImpl::refresh()
ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0;
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;
m_history.push_back(ti);
}
@@ -195,10 +196,11 @@ void TransactionHistoryImpl::refresh()
ti->m_timestamp = pd.m_timestamp;
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;
// single output transaction might contain multiple transfers
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)});
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id), d.asset_type});
}
m_history.push_back(ti);
@@ -232,9 +234,10 @@ void TransactionHistoryImpl::refresh()
ti->m_timestamp = pd.m_timestamp;
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;
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)});
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id), d.asset_type});
}
m_history.push_back(ti);
}
@@ -262,6 +265,7 @@ void TransactionHistoryImpl::refresh()
ti->m_timestamp = pd.m_timestamp;
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;
m_history.push_back(ti);
LOG_PRINT_L1(__FUNCTION__ << ": Unconfirmed payment found " << pd.m_amount);
+7 -2
View File
@@ -37,8 +37,8 @@ namespace Monero {
TransactionInfo::~TransactionInfo() {}
TransactionInfo::Transfer::Transfer(uint64_t _amount, const string &_address)
: amount(_amount), address(_address) {}
TransactionInfo::Transfer::Transfer(uint64_t _amount, const string &_address, const string &_asset)
: amount(_amount), address(_address), asset(_asset) {}
TransactionInfoImpl::TransactionInfoImpl()
@@ -153,5 +153,10 @@ Monero::transaction_type TransactionInfoImpl::type() const
{
return m_type;
}
string TransactionInfoImpl::asset() const
{
return m_asset;
}
} // namespace
+2
View File
@@ -55,6 +55,7 @@ public:
virtual std::set<uint32_t> subaddrIndex() const override;
virtual uint32_t subaddrAccount() const override;
virtual std::string label() const override;
virtual std::string asset() const override;
virtual std::string hash() const override;
virtual std::time_t timestamp() const override;
@@ -73,6 +74,7 @@ private:
uint64_t m_fee;
uint64_t m_blockheight;
std::string m_description;
std::string m_asset;
std::set<uint32_t> m_subaddrIndex; // always unique index for incoming transfers; can be multiple indices for outgoing transfers
uint32_t m_subaddrAccount;
std::string m_label;
+40 -8
View File
@@ -946,14 +946,14 @@ void WalletImpl::setSubaddressLookahead(uint32_t major, uint32_t minor)
m_wallet->set_subaddress_lookahead(major, minor);
}
uint64_t WalletImpl::balance(uint32_t accountIndex) const
uint64_t WalletImpl::balance(const std::string& asset, uint32_t accountIndex) const
{
return m_wallet->balance(accountIndex, "SAL", false);
return m_wallet->balance(accountIndex, asset, false);
}
uint64_t WalletImpl::unlockedBalance(uint32_t accountIndex) const
uint64_t WalletImpl::unlockedBalance(const std::string& asset, uint32_t accountIndex) const
{
return m_wallet->unlocked_balance(accountIndex, "SAL", false);
return m_wallet->unlocked_balance(accountIndex, asset, false);
}
uint64_t WalletImpl::blockChainHeight() const
@@ -1436,7 +1436,7 @@ PendingTransaction *WalletImpl::createStakeTransaction(uint64_t amount, uint32_t
// Need to populate {dst_entr, payment_id, asset_type, is_return}
const string dst_addr = m_wallet->get_subaddress_as_str({subaddr_account, 0});//MY LOCAL (SUB)ADDRESS
const string payment_id = "";
const string asset_type = "SAL";
const string asset_type = "SAL1";
const bool is_return = false;
LOG_ERROR("createStakeTransaction: called");
@@ -1568,9 +1568,41 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const Monero::transact
adjusted_priority,
extra, subaddr_account, subaddr_indices);
} else {
transaction->m_pending_tx = m_wallet->create_transactions_all(0, converted_tx_type, asset_type, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */,
adjusted_priority,
extra, subaddr_account, subaddr_indices);
std::vector<tools::wallet2::pending_tx> m_pending_txs;
for (const auto subaddr_index : subaddr_indices) {
// Skip this wallet if there is no balance unlocked to audit
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddr = m_wallet->unlocked_balance_per_subaddress(subaddr_account, asset_type, true);
if (unlocked_balance_per_subaddr.count(subaddr_index) == 0) continue;
try {
const auto result = m_wallet->create_transactions_all(0,
converted_tx_type,
asset_type,
m_wallet->get_subaddress({subaddr_account, subaddr_index}),
(subaddr_index > 0),
1,
fake_outs_count,
0 /* unlock_time */,
adjusted_priority,
extra,
subaddr_account,
std::set<uint32_t> {subaddr_index}
);
m_pending_txs.insert(m_pending_txs.end(), result.begin(), result.end());
} catch (const std::exception &e) {
// Let's skip this wallet - we have already reported the error
if (unlocked_balance_per_subaddr[subaddr_index].first < 250000000) {
std::ostringstream writer;
writer << boost::format(tr("Subaddress index %u has insufficient funds (%s) to pay for audit")) % subaddr_index % print_money(unlocked_balance_per_subaddr[subaddr_index].first);
setStatusError(writer.str());
}
}
}
transaction->m_pending_tx = m_pending_txs;
}
pendingTxPostProcess(transaction);
+2 -2
View File
@@ -111,8 +111,8 @@ public:
void setTrustedDaemon(bool arg) override;
bool trustedDaemon() const override;
bool setProxy(const std::string &address) override;
uint64_t balance(uint32_t accountIndex = 0) const override;
uint64_t unlockedBalance(uint32_t accountIndex = 0) const override;
uint64_t balance(const std::string& asset, uint32_t accountIndex = 0) const override;
uint64_t unlockedBalance(const std::string& asset, uint32_t accountIndex = 0) const override;
uint64_t blockChainHeight() const override;
uint64_t approximateBlockChainHeight() const override;
uint64_t estimateBlockChainHeight() const override;
+26 -14
View File
@@ -209,9 +209,10 @@ struct TransactionInfo
};
struct Transfer {
Transfer(uint64_t _amount, const std::string &address);
Transfer(uint64_t _amount, const std::string &address, const std::string &asset);
const uint64_t amount;
const std::string address;
const std::string asset;
};
virtual ~TransactionInfo() = 0;
@@ -228,6 +229,7 @@ struct TransactionInfo
virtual std::string label() const = 0;
virtual uint64_t confirmations() const = 0;
virtual uint64_t unlockTime() const = 0;
virtual std::string asset() const = 0;
//! transaction_id
virtual std::string hash() const = 0;
virtual std::time_t timestamp() const = 0;
@@ -326,25 +328,35 @@ struct Subaddress
struct SubaddressAccountRow {
public:
SubaddressAccountRow(std::size_t _rowId, const std::string &_address, const std::string &_label, const std::string &_balance, const std::string &_unlockedBalance):
SubaddressAccountRow(std::size_t _rowId, const std::string &_address, const std::string &_label, const std::string &_balance, const std::string &_unlockedBalance, const std::string &_balance_sal1, const std::string &_unlockedBalance_sal1):
m_rowId(_rowId),
m_address(_address),
m_label(_label),
m_balance(_balance),
m_unlockedBalance(_unlockedBalance) {}
m_balance_sal(_balance),
m_unlockedBalance_sal(_unlockedBalance),
m_balance_sal1(_balance_sal1),
m_unlockedBalance_sal1(_unlockedBalance_sal1) {}
private:
std::size_t m_rowId;
std::string m_address;
std::string m_label;
std::string m_balance;
std::string m_unlockedBalance;
std::string m_balance_sal;
std::string m_balance_sal1;
std::string m_unlockedBalance_sal;
std::string m_unlockedBalance_sal1;
public:
std::string extra;
std::string getAddress() const {return m_address;}
std::string getLabel() const {return m_label;}
std::string getBalance() const {return m_balance;}
std::string getUnlockedBalance() const {return m_unlockedBalance;}
std::string getBalance(const std::string& asset) const {
if (asset == "SAL") return m_balance_sal;
else return m_balance_sal1;
}
std::string getUnlockedBalance(const std::string& asset) const {
if (asset == "SAL") return m_unlockedBalance_sal;
else return m_unlockedBalance_sal1;
}
std::size_t getRowId() const {return m_rowId;}
};
@@ -642,18 +654,18 @@ struct Wallet
virtual void setTrustedDaemon(bool arg) = 0;
virtual bool trustedDaemon() const = 0;
virtual bool setProxy(const std::string &address) = 0;
virtual uint64_t balance(uint32_t accountIndex = 0) const = 0;
uint64_t balanceAll() const {
virtual uint64_t balance(const std::string &asset, uint32_t accountIndex = 0) const = 0;
uint64_t balanceAll(const std::string &asset) const {
uint64_t result = 0;
for (uint32_t i = 0; i < numSubaddressAccounts(); ++i)
result += balance(i);
result += balance(asset, i);
return result;
}
virtual uint64_t unlockedBalance(uint32_t accountIndex = 0) const = 0;
uint64_t unlockedBalanceAll() const {
virtual uint64_t unlockedBalance(const std::string &asset, uint32_t accountIndex = 0) const = 0;
uint64_t unlockedBalanceAll(const std::string &asset) const {
uint64_t result = 0;
for (uint32_t i = 0; i < numSubaddressAccounts(); ++i)
result += unlockedBalance(i);
result += unlockedBalance(asset, i);
return result;
}
+49 -16
View File
@@ -1252,6 +1252,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std
m_credits_target(0),
m_enable_multisig(false),
m_freeze_incoming_payments(false),
m_send_change_back_to_subaddress(false),
m_pool_info_query_time(0),
m_has_ever_refreshed_from_node(false),
m_allow_mismatched_daemon_version(false)
@@ -2573,10 +2574,16 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
if (!miner_tx && !pool)
process_unconfirmed(txid, tx, height);
std::string source_asset =
(tx.type == cryptonote::transaction_type::MINER) ? "SAL" :
(tx.type == cryptonote::transaction_type::PROTOCOL) ? "SAL" :
tx.source_asset_type;
std::string source_asset;
if (tx.type == cryptonote::transaction_type::MINER || tx.type == cryptonote::transaction_type::PROTOCOL) {
if (use_fork_rules(get_salvium_one_proofs_fork(), 0)) {
source_asset = "SAL1";
} else {
source_asset = "SAL";
}
} else {
source_asset = tx.source_asset_type;
}
// per receiving subaddress index
std::unordered_map<cryptonote::subaddress_index, std::map<std::string, uint64_t>> tx_money_got_in_outs;
@@ -2762,7 +2769,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
crypto::public_key pk_locked_coins = crypto::null_pkey;
THROW_WALLET_EXCEPTION_IF(!get_output_public_key(td_origin.m_tx.vout[td_origin.m_internal_output_index], pk_locked_coins), error::wallet_internal_error, "Failed to get output public key for locked coins");
// At this point, we need to clear the "locked coins" count, because otherwise we will be counting yield stakes twice in our balance
THROW_WALLET_EXCEPTION_IF(!m_locked_coins.erase(pk_locked_coins), error::wallet_internal_error, "Failed to remove protocol_tx entry from m_locked_coins");
//THROW_WALLET_EXCEPTION_IF(!m_locked_coins.erase(pk_locked_coins), error::wallet_internal_error, "Failed to remove protocol_tx entry from m_locked_coins");
if (!m_locked_coins.erase(pk_locked_coins)) {
LOG_ERROR("Failed to remove protocol_tx entry from m_locked_coins - possible duplicate output key detected");
}
}
}
}
@@ -5135,6 +5145,9 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
value2.SetInt(m_freeze_incoming_payments ? 1 : 0);
json.AddMember("freeze_incoming_payments", value2, json.GetAllocator());
value2.SetInt(m_send_change_back_to_subaddress ? 1 : 0);
json.AddMember("send_change_back_to_subaddress", value2, json.GetAllocator());
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -5282,6 +5295,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
m_credits_target = 0;
m_enable_multisig = false;
m_freeze_incoming_payments = false;
m_send_change_back_to_subaddress = false;
m_allow_mismatched_daemon_version = false;
}
else if(json.IsObject())
@@ -5521,6 +5535,8 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
m_enable_multisig = field_enable_multisig;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, freeze_incoming_payments, int, Int, false, false);
m_freeze_incoming_payments = field_freeze_incoming_payments;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, send_change_back_to_subaddress, int, Int, false, false);
m_send_change_back_to_subaddress = field_send_change_back_to_subaddress;
}
else
{
@@ -7060,22 +7076,27 @@ uint64_t wallet2::unlocked_balance(uint32_t index_major, const std::string& asse
std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_major, const std::string& asset_type, bool strict) const
{
std::map<uint32_t, uint64_t> amount_per_subaddr;
for (const auto& idx: m_transfers_indices.at(asset_type))
{
const transfer_details& td = m_transfers[idx];
if (td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
if (m_transfers_indices.count(asset_type) > 0) {
for (const auto& idx: m_transfers_indices.at(asset_type))
{
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
amount_per_subaddr[td.m_subaddr_index.minor] = td.amount();
else
found->second += td.amount();
const transfer_details& td = m_transfers[idx];
if (td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
{
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
amount_per_subaddr[td.m_subaddr_index.minor] = td.amount();
else
found->second += td.amount();
}
}
}
if (!strict)
{
for (const auto& utx: m_unconfirmed_txs)
{
// Skip UTXs that have the wrong asset type
if (utx.second.m_tx.source_asset_type != asset_type) continue;
if (utx.second.m_subaddr_account == index_major && utx.second.m_state != wallet2::unconfirmed_transfer_details::failed)
{
// all changes go to 0-th subaddress (in the current subaddress account)
@@ -7116,6 +7137,10 @@ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> amount_per_subaddr;
const uint64_t blockchain_height = get_blockchain_current_height();
const uint64_t now = time(NULL);
if (m_transfers_indices.count(asset_type) == 0) {
return amount_per_subaddr;
}
for(const auto& idx: m_transfers_indices[asset_type])
{
transfer_details& td = m_transfers[idx];
@@ -10226,8 +10251,16 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
change_dts.amount = found_money - needed_money;
change_dts.asset_type = source_asset;
change_dts.addr = get_subaddress({subaddr_account, subaddr_index});
change_dts.is_subaddress = subaddr_account != 0 || subaddr_index != 0;
// Lazy devs can't be bothered to code a proper solution for get_transfer_by_txid,
// so we have to provide a hack for them and their poor code.
if (m_send_change_back_to_subaddress || tx_type == cryptonote::transaction_type::AUDIT) {
change_dts.addr = get_subaddress({subaddr_account, subaddr_index});
change_dts.is_subaddress = subaddr_account != 0 || subaddr_index != 0;
} else {
change_dts.addr = get_subaddress({subaddr_account, 0});
change_dts.is_subaddress = subaddr_account != 0;
}
change_dts.is_change = true;
splitted_dsts.push_back(change_dts);
+3
View File
@@ -1450,6 +1450,8 @@ private:
void enable_multisig(bool enable) { m_enable_multisig = enable; }
bool is_freeze_incoming_payments_enabled() const { return m_freeze_incoming_payments; }
void freeze_incoming_payments(bool enable) { m_freeze_incoming_payments = enable; }
bool is_send_change_back_to_subaddress_enabled() const { return m_send_change_back_to_subaddress; }
void send_change_back_to_subaddress(bool enable) { m_send_change_back_to_subaddress = enable; }
bool is_mismatched_daemon_version_allowed() const { return m_allow_mismatched_daemon_version; }
void allow_mismatched_daemon_version(bool allow_mismatch) { m_allow_mismatched_daemon_version = allow_mismatch; }
@@ -1982,6 +1984,7 @@ private:
uint64_t m_credits_target;
bool m_enable_multisig;
bool m_freeze_incoming_payments;
bool m_send_change_back_to_subaddress;
bool m_allow_mismatched_daemon_version;
// Aux transaction data from device
+8 -1
View File
@@ -1136,6 +1136,13 @@ namespace tools
try
{
// Get the audit information
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_wallet->nettype()).AUDIT_HARD_FORKS;
const uint8_t hf_version = m_wallet->get_current_hard_fork();
if (audit_hard_forks.find(hf_version) == audit_hard_forks.end()) {
return false;
}
std::vector<wallet2::pending_tx> ptx_vector_all;
// Get the subaddress unlocked balances
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddr = m_wallet->unlocked_balance_per_subaddress(req.account_index, asset_type, true);
@@ -1148,7 +1155,7 @@ namespace tools
subaddr_indices_single.insert(subaddr_index);
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(0);
uint64_t unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD;
uint64_t unlock_block = audit_hard_forks.at(hf_version).first;
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(0, cryptonote::transaction_type::AUDIT, asset_type, m_wallet->get_subaddress({req.account_index, subaddr_index}), (subaddr_index > 0), 1, mixin, unlock_block, priority, extra, req.account_index, subaddr_indices_single);
ptx_vector_all.insert(ptx_vector_all.end(), ptx_vector.begin(), ptx_vector.end());
}