Compare commits
14 Commits
v0.9.0
...
v0.9.4-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
| 5971f39e7a | |||
| 02ef77bbcc | |||
| aa64124c28 | |||
| bc7db51f03 | |||
| 6889321361 | |||
| 3cb473132e | |||
| b298f542a6 | |||
| eb9f799b8b | |||
| 8bf35db67e | |||
| aeef1a6677 | |||
| ee586a3fca | |||
| f4612357b2 | |||
| e9a2b6fbb7 | |||
| ca2069facc |
@@ -14,3 +14,6 @@
|
||||
[submodule "external/miniupnp"]
|
||||
path = external/miniupnp
|
||||
url = https://github.com/miniupnp/miniupnp
|
||||
[submodule "external/mx25519"]
|
||||
path = external/mx25519
|
||||
url = https://github.com/tevador/mx25519
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Salvium Zero v0.9.0
|
||||
# Salvium Zero v0.9.4
|
||||
|
||||
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.0
|
||||
git checkout v0.9.4
|
||||
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.0
|
||||
git checkout v0.9.4
|
||||
```
|
||||
|
||||
* 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.0'. 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.4'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.9.0
|
||||
git checkout v0.9.4
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
+1
Submodule external/mx25519 added at 84ca1290fa
@@ -215,7 +215,7 @@ namespace
|
||||
* yield_block_data block height {slippage_coins, locked_coins, lc_total, network_health}
|
||||
* yield_tx_data block height {txn hash, locked_coins, return_address}
|
||||
*
|
||||
* audit_data block height {locked_coins, lc_total}
|
||||
* audit_block_data block height {locked_coins, lc_total}
|
||||
* audit_tx_data block height {txn hash, locked_coins, return_address}
|
||||
*
|
||||
* Note: where the data items are of uniform size, DUPFIXED tables have
|
||||
@@ -3778,6 +3778,11 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
|
||||
//amount += m_coinbase;
|
||||
}
|
||||
|
||||
if (amount < 0) {
|
||||
// Negative number can't be converted to a 64-bit UINT, so return 0, but retain -ve number privately
|
||||
LOG_PRINT_L2("BlockchainLMDB::" << __func__ << " - supply of " << currency_label << " is negative (" << amount << ") but outputting zero");
|
||||
amount = 0;
|
||||
}
|
||||
circulating_supply[currency_label] = amount.convert_to<uint64_t>();
|
||||
}
|
||||
|
||||
|
||||
@@ -142,17 +142,23 @@ set(blockchain_scanner_private_headers)
|
||||
monero_private_headers(blockchain_scanner
|
||||
${blockchain_scanner_private_headers})
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
set(blockchain_audit_private_headers)
|
||||
|
||||
monero_private_headers(blockchain_audit
|
||||
${blockchain_audit_private_headers})
|
||||
if (BUILD_TAG)
|
||||
else()
|
||||
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
|
||||
threadpool_boost.cpp
|
||||
)
|
||||
|
||||
set(blockchain_audit_private_headers
|
||||
threadpool_boost.h
|
||||
)
|
||||
|
||||
monero_private_headers(blockchain_audit
|
||||
${blockchain_audit_private_headers})
|
||||
else()
|
||||
message(STATUS "blockchain_audit.cpp not found - not building the audit tool")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
monero_add_executable(blockchain_import
|
||||
@@ -324,30 +330,36 @@ set_property(TARGET blockchain_scanner
|
||||
OUTPUT_NAME "salvium-blockchain-scanner")
|
||||
install(TARGETS blockchain_scanner DESTINATION bin)
|
||||
|
||||
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}
|
||||
${blockchain_audit_private_headers})
|
||||
if (BUILD_TAG)
|
||||
else()
|
||||
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}
|
||||
${blockchain_audit_private_headers})
|
||||
|
||||
target_link_libraries(blockchain_audit
|
||||
PRIVATE
|
||||
wallet
|
||||
crypto
|
||||
cncrypto
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
version
|
||||
epee
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
target_include_directories(blockchain_audit PRIVATE /usr/include/mysql-cppconn/jdbc)
|
||||
|
||||
target_link_libraries(blockchain_audit
|
||||
PRIVATE
|
||||
wallet
|
||||
crypto
|
||||
cncrypto
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
version
|
||||
epee
|
||||
mysqlcppconn
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
set_property(TARGET blockchain_audit
|
||||
PROPERTY
|
||||
OUTPUT_NAME "salvium-blockchain-audit")
|
||||
install(TARGETS blockchain_audit DESTINATION bin)
|
||||
set_property(TARGET blockchain_audit
|
||||
PROPERTY
|
||||
OUTPUT_NAME "salvium-blockchain-audit")
|
||||
install(TARGETS blockchain_audit DESTINATION bin)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
monero_add_executable(blockchain_stats
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <iostream>
|
||||
#include "threadpool_boost.h"
|
||||
|
||||
ThreadPool::ThreadPool(size_t numThreads)
|
||||
: workGuard(boost::asio::make_work_guard(ioService)) {
|
||||
for (size_t i = 0; i < numThreads; ++i) {
|
||||
workers.emplace_back([this]() {
|
||||
std::cerr << "Thread started" << std::endl;
|
||||
ioService.run();
|
||||
std::cerr << "Thread finished" << std::endl;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::enqueue(std::function<void()> task) {
|
||||
ioService.post([task]() {
|
||||
try {
|
||||
task(); // Run the task
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception in thread pool task: " << e.what() << std::endl;
|
||||
} catch (...) {
|
||||
std::cerr << "Unknown exception in thread pool task!" << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ThreadPool::isStopping() const {
|
||||
return ioService.stopped(); // Check if io_context has stopped
|
||||
}
|
||||
|
||||
void ThreadPool::waitForCompletion() {
|
||||
std::cout << "Waiting for completion...\n";
|
||||
workGuard.reset(); // Allow ioService to stop when no more tasks
|
||||
ioService.run(); // Ensure no threads are left hanging
|
||||
|
||||
for (auto &worker : workers) {
|
||||
if (worker.joinable()) worker.join();
|
||||
}
|
||||
std::cout << "All threads joined.\n";
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool() {
|
||||
waitForCompletion();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef THREADPOOL_BOOST_H
|
||||
#define THREADPOOL_BOOST_H
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
explicit ThreadPool(size_t numThreads);
|
||||
~ThreadPool();
|
||||
|
||||
void enqueue(std::function<void()> task);
|
||||
bool isStopping() const;
|
||||
void waitForCompletion();
|
||||
|
||||
private:
|
||||
boost::asio::io_service ioService;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> workGuard;
|
||||
std::vector<boost::thread> workers;
|
||||
};
|
||||
|
||||
#endif // THREADPOOL_BOOST_H
|
||||
@@ -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;
|
||||
|
||||
+15
-11
@@ -231,6 +231,10 @@
|
||||
#define HF_VERSION_AUDIT1 6
|
||||
#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
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
@@ -287,10 +291,9 @@ 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"}}} };
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30*24*10;
|
||||
|
||||
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
|
||||
|
||||
@@ -363,8 +366,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"}};
|
||||
|
||||
@@ -390,8 +397,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"}};
|
||||
|
||||
@@ -428,8 +436,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)
|
||||
@@ -447,7 +454,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
|
||||
};
|
||||
@@ -464,8 +470,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 = {
|
||||
@@ -481,8 +486,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)
|
||||
|
||||
@@ -1505,6 +1505,9 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
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:
|
||||
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;
|
||||
@@ -1556,7 +1559,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
LOG_PRINT_L2("coinbase protocol transaction in the block has no outputs");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Can we have matured STAKE transactions yet?
|
||||
uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD;
|
||||
if (height <= stake_lock_period) {
|
||||
@@ -1583,10 +1586,36 @@ 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
/*
|
||||
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;
|
||||
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;
|
||||
@@ -1604,7 +1633,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
// Check we have the correct number of entries
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size() + audit_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting");
|
||||
|
||||
@@ -1980,12 +2009,13 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
|
||||
// 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);
|
||||
@@ -2002,7 +2032,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) {
|
||||
@@ -2019,6 +2049,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3951,6 +3982,20 @@ 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<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).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) {
|
||||
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL1", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size());
|
||||
std::vector < uint64_t > results;
|
||||
results.resize(tx.vin.size(), 0);
|
||||
@@ -4073,7 +4118,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
const rct::rctSig &rv = tx.rct_signatures;
|
||||
|
||||
// Check that after full proofs are enabled, the RCT version is set to enforce full proofs
|
||||
if (hf_version == HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) {
|
||||
MERROR_VER("Unsupported rct type (full proofs (with audit data) are required): " << rv.type);
|
||||
return false;
|
||||
@@ -4500,7 +4545,9 @@ bool Blockchain::calculate_audit_payouts(const uint64_t start_height, std::vecto
|
||||
}
|
||||
|
||||
// Build a blacklist of staking TXs _not_ to pay out for
|
||||
const std::set<std::string> txs_blacklist = {};
|
||||
const std::set<std::string> txs_blacklist = {
|
||||
"017a79539e69ce16e91d9aa2267c102f336678c41636567c1129e3e72149499a"
|
||||
};
|
||||
|
||||
// Get the ABI information for the 21,600 blocks that the matured TX(s), we can calculate audit
|
||||
for (const auto& entry: audit_entries) {
|
||||
|
||||
@@ -448,6 +448,9 @@ namespace cryptonote
|
||||
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:
|
||||
// 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;
|
||||
|
||||
@@ -49,6 +49,9 @@ const hardfork_t mainnet_hard_forks[] = {
|
||||
|
||||
// version 6 starts from block 154750, which is on or around the 4th of February, 2025. Fork time finalised on 2025-01-31. No fork voting occurs for the v6 fork.
|
||||
{ 6, 154750, 0, 1738336000 },
|
||||
|
||||
// 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 },
|
||||
};
|
||||
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);
|
||||
@@ -69,8 +72,17 @@ const hardfork_t testnet_hard_forks[] = {
|
||||
// version 5 (TX shutdown) starts from block 800
|
||||
{ 5, 800, 0, 1734607005 },
|
||||
|
||||
// version 6 (audit) starts from block 815
|
||||
// version 6 (audit 1) starts from block 815
|
||||
{ 6, 815, 0, 1734608000 },
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -6974,19 +6974,36 @@ 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
|
||||
if (unlocked_balance_per_subaddr.count(subaddr_index) == 0) continue;
|
||||
|
||||
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());
|
||||
|
||||
try {
|
||||
|
||||
std::set<uint32_t> subaddr_indices_single;
|
||||
subaddr_indices_single.insert(subaddr_index);
|
||||
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());
|
||||
|
||||
} 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) {
|
||||
fail_msg_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -8386,12 +8403,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
-1
@@ -1,5 +1,5 @@
|
||||
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_SALVIUM_VERSION "0.9.0"
|
||||
#define DEF_SALVIUM_VERSION "0.9.4-rc1"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.3.3"
|
||||
#define DEF_MONERO_RELEASE_NAME "Zero"
|
||||
|
||||
@@ -1444,6 +1444,34 @@ PendingTransaction *WalletImpl::createStakeTransaction(uint64_t amount, uint32_t
|
||||
return createTransactionMultDest(Monero::transaction_type::STAKE, std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {amount}) : (optional<std::vector<uint64_t>>()), mixin_count, asset_type, is_return, priority, subaddr_account, subaddr_indices);
|
||||
}
|
||||
|
||||
PendingTransaction *WalletImpl::createAuditTransaction(
|
||||
uint32_t mixin_count,
|
||||
PendingTransaction::Priority priority,
|
||||
uint32_t subaddr_account,
|
||||
std::set<uint32_t> subaddr_indices
|
||||
) {
|
||||
// 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 bool is_return = false;
|
||||
|
||||
LOG_ERROR("createAuditTransaction: called");
|
||||
|
||||
return createTransactionMultDest(
|
||||
Monero::transaction_type::AUDIT,
|
||||
std::vector<string> {dst_addr},
|
||||
payment_id,
|
||||
(optional<std::vector<uint64_t>>()),
|
||||
mixin_count,
|
||||
asset_type,
|
||||
is_return,
|
||||
priority,
|
||||
subaddr_account,
|
||||
subaddr_indices
|
||||
);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
|
||||
// 2 - check / design how "Transaction" can be single interface
|
||||
@@ -1536,11 +1564,11 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const Monero::transact
|
||||
fake_outs_count = m_wallet->adjust_mixin(mixin_count);
|
||||
|
||||
if (amount) {
|
||||
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, "SAL", "SAL", converted_tx_type, fake_outs_count, 0 /* unlock_time */,
|
||||
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, asset_type, asset_type, converted_tx_type, fake_outs_count, 0 /* unlock_time */,
|
||||
adjusted_priority,
|
||||
extra, subaddr_account, subaddr_indices);
|
||||
} else {
|
||||
transaction->m_pending_tx = m_wallet->create_transactions_all(0, converted_tx_type, "SAL", info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -158,6 +158,10 @@ public:
|
||||
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
||||
uint32_t subaddr_account = 0,
|
||||
std::set<uint32_t> subaddr_indices = {}) override;
|
||||
PendingTransaction * createAuditTransaction(uint32_t mixin_count,
|
||||
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
||||
uint32_t subaddr_account = 0,
|
||||
std::set<uint32_t> subaddr_indices = {}) override;
|
||||
PendingTransaction * createTransactionMultDest(const transaction_type &tx_type,
|
||||
const std::vector<std::string> &dst_addr, const std::string &payment_id,
|
||||
optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
|
||||
|
||||
@@ -58,7 +58,8 @@ enum transaction_type : uint8_t {
|
||||
BURN = 5,
|
||||
STAKE = 6,
|
||||
RETURN = 7,
|
||||
MAX = 7
|
||||
AUDIT = 8,
|
||||
MAX = 8
|
||||
};
|
||||
|
||||
namespace Utils {
|
||||
@@ -97,7 +98,7 @@ struct YieldInfo
|
||||
virtual uint64_t yield() const = 0;
|
||||
virtual uint64_t yield_per_stake() const = 0;
|
||||
virtual std::string period() const = 0;
|
||||
virtual std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> payouts() const = 0;
|
||||
virtual std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> payouts() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -878,6 +879,20 @@ struct Wallet
|
||||
uint32_t subaddr_account = 0,
|
||||
std::set<uint32_t> subaddr_indices = {}) = 0;
|
||||
|
||||
/*!
|
||||
* \brief createAuditTransaction creates audit transaction.
|
||||
* \param mixin_count mixin count. if 0 passed, wallet will use default value
|
||||
* \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices
|
||||
* \param priority
|
||||
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
|
||||
* after object returned
|
||||
*/
|
||||
|
||||
virtual PendingTransaction * createAuditTransaction(uint32_t mixin_count,
|
||||
PendingTransaction::Priority = PendingTransaction::Priority_Low,
|
||||
uint32_t subaddr_account = 0,
|
||||
std::set<uint32_t> subaddr_indices = {}) = 0;
|
||||
|
||||
/*!
|
||||
* \brief createTransactionMultDest creates transaction with multiple destinations. if dst_addr is an integrated address, payment_id is ignored
|
||||
* \param tx_type the type of transaction being created
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace Monero {
|
||||
return m_yield_per_stake;
|
||||
}
|
||||
|
||||
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> YieldInfoImpl::payouts() const
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> YieldInfoImpl::payouts() const
|
||||
{
|
||||
return m_payouts;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
uint64_t yield() const override;
|
||||
uint64_t yield_per_stake() const override;
|
||||
std::string period() const override;
|
||||
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> payouts() const override;
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> payouts() const override;
|
||||
|
||||
private:
|
||||
friend class WalletImpl;
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
uint64_t m_yield_per_stake;
|
||||
uint64_t m_num_entries;
|
||||
std::string m_period;
|
||||
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> m_payouts;
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> m_payouts;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -7076,6 +7076,8 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
|
||||
{
|
||||
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)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user