Compare commits

...

31 Commits

Author SHA1 Message Date
Some Random Crypto Guy aa64124c28 fix for supply_info command with SAL supply going negative 2025-02-14 13:28:22 +00:00
Some Random Crypto Guy bc7db51f03 various fixes ready for next HF 2025-02-11 14:35:57 +00:00
Some Random Crypto Guy 6889321361 fixed possible throw() when dust in index=0; bumped version number 2025-02-11 12:18:08 +00:00
Some Random Crypto Guy 3cb473132e Merge branch 'main' of https://github.com/salvium/salvium 2025-02-10 13:21:47 +00:00
akildemir b298f542a6 add audit tx support for wallet api (#14) 2025-02-10 13:20:42 +00:00
Some Random Crypto Guy eb9f799b8b fixed syncing message error level; added thread library for auditing 2025-02-10 13:11:52 +00:00
Some Random Crypto Guy 8bf35db67e fixed submodules that got merged incorrectly 2025-02-04 10:40:49 +00:00
Some Random Crypto Guy aeef1a6677 Merge branch 'main' of https://github.com/somerandomcryptoguy/salvium-private 2025-02-04 10:16:10 +00:00
Some Random Crypto Guy ee586a3fca added asset_type check - sorry, sneaky hackers, but you have a spy in your midst ;) 2025-02-04 10:09:49 +00:00
Some Random Crypto Guy 19be3a6146 fixed gitignore issue with CMake and audit tool 2025-01-31 17:20:52 +00:00
Some Random Crypto Guy 64a69268fe set hard fork 6 height; bumped version number 2025-01-31 15:10:13 +00:00
Some Random Crypto Guy 7312652540 Merge branch 'develop' 2025-01-31 15:07:59 +00:00
Some Random Crypto Guy 8cd587ec54 added building of (private) audit tool; improved help text for AUDIT command in CLI 2025-01-30 13:56:17 +00:00
Some Random Crypto Guy 62c43a4ed2 added audit index=all command; added audit RPC command; bumped version 2025-01-30 12:59:33 +00:00
Some Random Crypto Guy 0180051a8c fixed #23 : If multiple inputs get sent on a single transaction, then return_payment will not return all those inputs
fixed #20 : Audit transaction is showing in yield_info, but says 0 yield
fixed #19 : if you send SAL1, while the tx is pending it shows in the sal balance
fixed #18 : yield_info display is showing the wrong unlock time (TESTNET)
fixed #17 : SAL appears to be accrued during audit
2025-01-29 22:32:41 +00:00
Some Random Crypto Guy a7c1ba652b interim checkin of changes for audit; bumped version number 2025-01-29 15:39:08 +00:00
Some Random Crypto Guy 2a4d08b67f Merge branch 'main' into develop 2025-01-29 12:38:05 +00:00
Some Random Crypto Guy 3fc5ea3543 set fork height; updated fast-sync checkpoints 2025-01-08 18:44:12 +00:00
Some Random Crypto Guy 3b72dc0555 added code to skip user TXs in v5 when filling block template 2025-01-07 23:23:44 +00:00
Some Random Crypto Guy b48c86afe0 added user tx verification 2025-01-07 22:53:58 +00:00
Some Random Crypto Guy 0f88d91fa0 bumped version 2025-01-07 16:57:19 +00:00
Some Random Crypto Guy 4b594142ca updated block fast sync checksums; disabled spend authority proof due to multisig; fixed issue in protocol_tx; bumped version 2024-12-17 20:06:54 +00:00
Some Random Crypto Guy 29e435bd39 added belt and braces to prevent CONVERT TXs from being attempted; integrated spend authority proof support into wallet; bumped version number 2024-12-16 14:07:37 +00:00
Some Random Crypto Guy 4abde92c1a bumped RC version 2024-12-16 09:18:47 +00:00
Some Random Crypto Guy dd23331df9 switched to single spend authority proof - the dummy proofs don't work as intended, so dropping them 2024-12-16 09:16:34 +00:00
Some Random Crypto Guy 7d2025bc19 interim checkin 2024-12-16 07:48:16 +00:00
Some Random Crypto Guy a01422a5e0 partial working serialisation 2024-12-15 22:28:14 +00:00
Some Random Crypto Guy e68f7f46ed fixed check on miner-staker split 2024-12-15 11:50:14 +00:00
Some Random Crypto Guy b87c243da1 fixed unit tests; fixed core tests; fixed performance tests; added fix to prevent change in block reward split (thanks Akil); added prelim code for spend authority proof - not complete / working 2024-12-15 11:09:46 +00:00
Some Random Crypto Guy 49fd907073 Merge branch 'main' into develop 2024-12-12 21:08:33 +00:00
Some Random Crypto Guy 8f5111aeda Merge branch 'main' into develop 2024-11-05 12:39:42 +00:00
62 changed files with 2042 additions and 565 deletions
+3
View File
@@ -30,6 +30,9 @@ contrib/gitian/builder/
contrib/gitian/docker/
contrib/gitian/sigs/
# Audit tool
src/blockchain_utilities/blockchain_audit.cpp
# Created by https://www.gitignore.io
### C++ ###
+3
View File
@@ -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
+5 -5
View File
@@ -1,4 +1,4 @@
# Salvium Zero v0.7.2
# Salvium Zero v0.9.3
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.7.0
git checkout v0.9.3
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.7.0
git checkout v0.9.3
```
* 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.7.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.3'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.7.0
git checkout v0.9.3
```
* If you are on a 64-bit system, run:
+9 -3
View File
@@ -269,6 +269,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
, const std::vector<std::pair<transaction, blobdata>>& txs
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
)
{
const block &blk = blck.first;
@@ -309,7 +310,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
}
std::map<std::string, int64_t> slippage_counts;
uint64_t yield_total = 0;
uint64_t audit_total = 0, yield_total = 0;
if (blk.protocol_tx.version == 2)
{
num_rct_outs += blk.protocol_tx.vout.size();
@@ -356,7 +357,12 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
slippage_counts[asset_type] += tx.first.amount_burnt;
}
// Is this a YIELD TX?
// Is this an AUDIT TX?
if (tx.first.type == cryptonote::transaction_type::AUDIT) {
audit_total += tx.first.amount_burnt;
}
// Is this a STAKE TX?
if (tx.first.type == cryptonote::transaction_type::STAKE) {
yield_total += tx.first.amount_burnt;
}
@@ -410,7 +416,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
// call out to subclass implementation to add the block & metadata
time1 = epee::misc_utils::get_tick_count();
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, num_rct_outs_by_asset_type, blk_hash, slippage_total, yield_total, nettype, ybi);
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, num_rct_outs_by_asset_type, blk_hash, slippage_total, yield_total, audit_total, nettype, ybi, abi);
TIME_MEASURE_FINISH(time1);
time_add_block1 += time1;
+7 -1
View File
@@ -430,8 +430,10 @@ private:
const crypto::hash& blk_hash,
uint64_t slippage_total,
uint64_t yield_total,
uint64_t audit_total,
const cryptonote::network_type nettype,
cryptonote::yield_block_info& ybi
cryptonote::yield_block_info& ybi,
cryptonote::audit_block_info& abi
) = 0;
/**
@@ -886,6 +888,7 @@ public:
, const std::vector<std::pair<transaction, blobdata>>& txs
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
);
/**
@@ -1915,6 +1918,9 @@ public:
*/
virtual uint64_t get_database_size() const = 0;
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const = 0;
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const = 0;
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const = 0;
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const = 0;
+326 -31
View File
@@ -215,6 +215,9 @@ 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_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
* been used to save space. In most of these cases, a dummy "zerokval"
* key is used when accessing the table; the Key listed above will be
@@ -289,6 +292,8 @@ const char* const LMDB_CIRC_SUPPLY_TALLY = "circ_supply_tally";
*/
const char* const LMDB_YIELD_TXS = "yield_txs";
const char* const LMDB_YIELD_BLOCKS = "yield_blocks";
const char* const LMDB_AUDIT_TXS = "audit_txs";
const char* const LMDB_AUDIT_BLOCKS = "audit_blocks";
const char zerokey[8] = {0};
const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey };
@@ -800,6 +805,75 @@ estim:
return threshold_size;
}
int BlockchainLMDB::get_audit_block_info(const uint64_t height, audit_block_info& abi) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
// Clear the ABI, just in case
std::memset(&abi, 0, sizeof(struct audit_block_info));
// Query for the matured AUDIT_BLOCK_INFO information
TXN_PREFIX_RDONLY();
RCURSOR(audit_blocks);
MDB_val v;
MDB_val_set(k, height);
int ret = mdb_cursor_get(m_cur_audit_blocks, &k, &v, MDB_SET);
if (ret == MDB_NOTFOUND) {
LOG_ERROR("Failed to locate ABI for block height " << height);
return ret;
}
if (ret)
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit block info: ", ret).c_str()));
audit_block_info *p = (audit_block_info*)v.mv_data;
abi = *p;
TXN_POSTFIX_RDONLY();
// Return success to caller
return ret;
}
int BlockchainLMDB::get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
// Clear the container
ati_container.clear();
// Query for the (presumably matured) AUDIT_TX_INFO information (we actually reuse YIELD_TX_INFO for this)
TXN_PREFIX_RDONLY();
RCURSOR(audit_txs);
MDB_val v;
MDB_val_set(k, height);
MDB_cursor_op op = MDB_SET;
while (1)
{
int ret = mdb_cursor_get(m_cur_audit_txs, &k, &v, op);
op = MDB_NEXT_DUP;
if (ret == MDB_NOTFOUND)
break;
if (ret)
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit TX info: ", ret).c_str()));
// Get the data
yield_tx_info *p = (yield_tx_info*)v.mv_data;
// Push result back into the container
ati_container.emplace_back(*p);
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
ati_container.back().block_height = height;
}
TXN_POSTFIX_RDONLY();
// Return success to caller
return 0;
}
int BlockchainLMDB::get_yield_block_info(const uint64_t height, yield_block_info& ybi) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -855,9 +929,12 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
if (ret)
throw0(DB_ERROR(lmdb_error("Failed to enumerate yield TX info: ", ret).c_str()));
// Push result back into the container
// Get the data
yield_tx_info *p = (yield_tx_info*)v.mv_data;
// Push result back into the container
yti_container.emplace_back(*p);
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
yti_container.back().block_height = height;
}
TXN_POSTFIX_RDONLY();
@@ -866,7 +943,7 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
return 0;
}
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi)
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, uint64_t audit_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -896,6 +973,18 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
int result = 0;
// Create the AUDIT_BLOCK_INFO instance for this block
CURSOR(audit_blocks)
abi.block_height = m_height;
abi.locked_coins_this_block = audit_total;
// Put the YBI into the table
MDB_val_set(key, m_height);
MDB_val_set(abi_val, abi);
result = mdb_cursor_put(m_cur_audit_blocks, &key, &abi_val, MDB_APPEND);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add ABI to db: ", result).c_str()));
CURSOR(yield_blocks)
yield_block_info ybi_matured, ybi_prev;
uint64_t yield_lock_period = cryptonote::get_config(nettype).STAKE_LOCK_PERIOD;
@@ -932,7 +1021,6 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
ybi.network_health_percentage = 100;
// Put the YBI into the table
MDB_val_set(key, m_height);
MDB_val_set(ybi_val, ybi);
result = mdb_cursor_put(m_cur_yield_blocks, &key, &ybi_val, MDB_APPEND);
if (result)
@@ -1004,6 +1092,7 @@ void BlockchainLMDB::remove_block()
CURSOR(blocks)
CURSOR(circ_supply_tally)
CURSOR(yield_blocks)
CURSOR(audit_blocks)
MDB_val_copy<uint64_t> k(m_height - 1);
MDB_val h = k;
if ((result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &h, MDB_GET_BOTH)))
@@ -1031,6 +1120,11 @@ void BlockchainLMDB::remove_block()
throw1(BLOCK_DNE(lmdb_error("Attempting to remove yield block info that's not in the db: ", result).c_str()));
if ((result = mdb_cursor_del(m_cur_yield_blocks, 0)))
throw1(DB_ERROR(lmdb_error("Failed to add removal of yield block info to db transaction: ", result).c_str()));
// Is the block within an audit window?
if ((result = mdb_cursor_get(m_cur_audit_blocks, &k2, NULL, MDB_SET)) == 0)
if ((result = mdb_cursor_del(m_cur_audit_blocks, 0)))
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit block info to db transaction: ", result).c_str()));
}
boost::multiprecision::int128_t
@@ -1116,6 +1210,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
CURSOR(circ_supply)
CURSOR(circ_supply_tally)
CURSOR(yield_txs)
CURSOR(audit_txs)
MDB_val_set(val_tx_id, tx_id);
MDB_val_set(val_h, tx_hash);
@@ -1183,13 +1278,19 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
throw0(DB_ERROR(lmdb_error("Failed to add prunable tx prunable hash to db transaction: ", result).c_str()));
}
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
if (tx.type == cryptonote::transaction_type::MINER) {
// Update the circulating supply tally because of potentially burnt block_reward proportion
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
std::string miner_asset_type = "SAL";
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
miner_asset_type = "SAL1";
}
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result && (m_height>0 || result != MDB_NOTFOUND))
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
boost::multiprecision::int128_t final_source_tally = source_tally;
for (const auto& out: tx.vout) {
@@ -1203,20 +1304,44 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
}
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
// Sanity check - prevent overflow
if (burn_tally > burn_tally + tx.amount_burnt)
throw0(DB_ERROR("burn overflow detected when adding miner_tx for db transaction"));
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt;
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
// Get the current tally value for the source currency type
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
boost::multiprecision::int128_t final_source_tally = source_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
// Sanity check - prevent underflow
if (source_tally < final_source_tally)
throw0(DB_ERROR("numeric underflow detected when processing C/B/S/A/T for db transaction"));
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
// Sanity check - prevent underflow
if (burn_tally > final_burn_tally)
throw0(DB_ERROR("burn overflow detected when adding tx for db transaction"));
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
@@ -1240,17 +1365,25 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
MDB_val_copy<uint64_t> source_idx(asset.first);
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result)
if (result == MDB_NOTFOUND)
throw0(DB_ERROR("minted asset not found"));
else if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
if (source_tally > source_tally + asset.second)
throw0(DB_ERROR("add_transaction_data() - mint overflow"));
boost::multiprecision::int128_t final_source_tally = source_tally + asset.second;
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
if (source_tally == 0 && result == MDB_NOTFOUND) {
if (tx.source_asset_type == "SAL") {
final_source_tally += coinbase;
}
}
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before burn =" << source_tally.str() << "\n\tTally after burn =" << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
if (burn_tally < asset.second)
throw0(DB_ERROR("add_transaction_data() - burn underflow"));
boost::multiprecision::int128_t final_burn_tally = burn_tally - asset.second;
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
}
@@ -1308,6 +1441,60 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
throw0(DB_ERROR( lmdb_error("Failed to add tx yield data to db transaction: ", result).c_str() ));
}
// Is there audit_tx data to add?
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Create the object we are going to write to the database
yield_tx_info audit_data;
audit_data.block_height = m_height;
audit_data.tx_hash = tx_hash;
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
if (tx.return_address == crypto::null_pkey)
throw0(DB_ERROR("missing return_address entry (needed to create audit data for PROTOCOL_TX) - v2 STAKE"));
audit_data.return_address = tx.return_address;
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
if (tx.return_address_list.empty())
throw0(DB_ERROR("no return_address_list entry (needed to create audit data for the PROTOCOL_TX)"));
else if (tx.return_address_list.size() > 1)
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create audit data for the PROTOCOL_TX)"));
audit_data.return_address = tx.return_address_list[0];
}
audit_data.locked_coins = tx.amount_burnt;
if (tx.vin.empty())
throw0(DB_ERROR("tx.vin is empty (needed to create audit data for the PROTOCOL_TX)"));
if (tx.vin[0].type() != typeid(cryptonote::txin_to_key))
throw0(DB_ERROR("tx.vin[0] is wrong type (needed to create audit data for the PROTOCOL_TX)"));
audit_data.return_pubkey = tx.return_pubkey;
if (tx.vout.size() != 1)
throw0(DB_ERROR("tx.vout is wrong size (needed to create audit data for the PROTOCOL_TX)"));
if (!cryptonote::get_output_public_key(tx.vout[0], audit_data.P_change))
throw0(DB_ERROR("failed to get P_change from tx.vout[0] (needed to create audit data for the PROTOCOL_TX)"));
// Because LMDB is shockingly bad at handling duplicates, we have resorted to using a counter of elements
// in the first element of the struct.
MDB_val data;
MDB_val_set(val_height, m_height);
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &data, MDB_SET);
if (!result)
{
mdb_size_t num_elems = 0;
result = mdb_cursor_count(m_cur_audit_txs, &num_elems);
if (result)
throw0(DB_ERROR(std::string("Failed to get number of audit TXs for height: ").append(mdb_strerror(result)).c_str()));
audit_data.block_height = num_elems;
}
else if (result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str()));
else
audit_data.block_height = 0;
// Now we know how many there are, write out the data to the DB
MDB_val_set(val_audit_tx_data, audit_data);
result = mdb_cursor_put(m_cur_audit_txs, &val_height, &val_audit_tx_data, MDB_APPENDDUP);
if (result)
throw0(DB_ERROR( lmdb_error("Failed to add tx audit data to db transaction: ", result).c_str() ));
}
return tx_id;
}
@@ -1330,6 +1517,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
CURSOR(tx_outputs)
CURSOR(circ_supply_tally)
CURSOR(yield_txs)
CURSOR(audit_txs)
MDB_val_set(val_h, tx_hash);
@@ -1373,42 +1561,70 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
throw1(DB_ERROR(lmdb_error("Failed to add removal of prunable hash tx to db transaction: ", result).c_str()));
}
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
if (tx.type == cryptonote::transaction_type::MINER) {
// Update the circulating supply tally because of potentially burnt block_reward proportion
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
std::string miner_asset_type = "SAL";
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
miner_asset_type = "SAL1";
}
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result && (m_height>0 || result != MDB_NOTFOUND))
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("remove_transaction_data() - Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
boost::multiprecision::int128_t final_source_tally = source_tally;
for (const auto& out: tx.vout) {
// Sanity check - prevent underflow
if (final_source_tally < final_source_tally - out.amount)
throw0(DB_ERROR("remove_transaction_data() - numeric underflow detected when removing miner_tx for db transaction"));
throw0(DB_ERROR("numeric underflow detected when removing miner_tx for db transaction"));
// Fetch the amount for this output
final_source_tally -= out.amount;
}
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
// Sanity check - prevent underflow
if (burn_tally < tx.amount_burnt)
throw0(DB_ERROR("burn underflow detected when removing miner_tx for db transaction"));
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt;
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
// Get the current tally value for the source currency type
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result == MDB_NOTFOUND)
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
// Sanity check - prevent overflow
if (source_tally > source_tally + tx.amount_burnt + tx.rct_signatures.txnFee)
throw0(DB_ERROR("remove_transaction_data() - numeric overflow detected when processing C/B/S for db transaction"));
boost::multiprecision::int128_t final_source_tally = source_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
// Sanity check - prevent overflow
if (source_tally > final_source_tally)
throw0(DB_ERROR("numeric overflow detected when processing C/B/S/A/T for db transaction"));
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before remint =" << source_tally.str() << "\n\tTally after remint =" << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
// Sanity check - prevent underflow
if (burn_tally < (tx.amount_burnt + tx.rct_signatures.txnFee))
throw0(DB_ERROR("burn underflow detected when removing tx for db transaction"));
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
@@ -1422,7 +1638,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
bool ok = cryptonote::get_output_asset_type(out, asset_type);
if (!ok)
throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)"));
minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount;
}
@@ -1434,12 +1649,24 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result == MDB_NOTFOUND)
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
throw0(DB_ERROR("minted asset not found"));
else if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
if (source_tally < asset.second)
throw0(DB_ERROR("remove_transaction_data() - mint underflow"));
boost::multiprecision::int128_t final_source_tally = source_tally - asset.second;
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before undoing mint =" << source_tally.str() << "\n\tTally after undoing mint =" << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
if (burn_tally > burn_tally + asset.second)
throw0(DB_ERROR("remove_transaction_data() - burn overflow"));
boost::multiprecision::int128_t final_burn_tally = burn_tally + asset.second;
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
}
remove_tx_outputs(tip->data.tx_id, tx);
@@ -1456,7 +1683,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str()));
}
// SRCG: The following code is designed to clean up the STAKE transactions, but it is very poorly written
// SRCG: The following code is designed to clean up AUDIT+STAKE transactions, but it is very poorly written
// Since transactions are ALWAYS supposed to be created in order, it stands that they should ALWAYS be
// removed in REVERSE ORDER. Yet the following loop starts from the beginning - this is the worst possible
// implementation in performance terms, since it will ALWAYS take the longest possible time to remove the
@@ -1464,6 +1691,30 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
// RECODE TO START FROM THE END OF THE DATABASE TABLE, AND THROW AN EXCEPTION IF YOU DO NOT MATCH FIRST TIME!
// Is there audit_tx data to remove?
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Remove any yield_tx data for this transaction
MDB_val_set(val_height, m_height);
MDB_val v;
MDB_cursor_op op = MDB_SET;
while (1) {
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &v, op);
if (result == MDB_NOTFOUND) {
throw1(DB_ERROR("Failed to locate audit tx for removal from db transaction"));
} else if (result) {
throw1(DB_ERROR(lmdb_error("Failed to locate audit_tx data for removal: ", result).c_str()));
}
op = MDB_NEXT_DUP;
const yield_tx_info ati = *(const yield_tx_info*)v.mv_data;
if (ati.tx_hash == tx_hash) {
result = mdb_cursor_del(m_cur_audit_txs, 0);
if (result)
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit_tx data to db transaction: ", result).c_str()));
break;
}
}
}
// Is there yield_tx data to remove?
if (tx.type == cryptonote::transaction_type::STAKE) {
// Remove any yield_tx data for this transaction
@@ -1970,6 +2221,9 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
lmdb_db_open(txn, LMDB_YIELD_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_yield_txs, "Failed to open db handle for m_yield_txs");
lmdb_db_open(txn, LMDB_YIELD_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_yield_blocks, "Failed to open db handle for m_yield_blocks");
lmdb_db_open(txn, LMDB_AUDIT_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_audit_txs, "Failed to open db handle for m_audit_txs");
lmdb_db_open(txn, LMDB_AUDIT_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_audit_blocks, "Failed to open db handle for m_audit_blocks");
mdb_set_dupsort(txn, m_spent_keys, compare_hash32);
mdb_set_dupsort(txn, m_block_heights, compare_hash32);
mdb_set_dupsort(txn, m_tx_indices, compare_hash32);
@@ -1993,6 +2247,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
mdb_set_compare(txn, m_circ_supply_tally, compare_uint64);
mdb_set_dupsort(txn, m_yield_txs, compare_uint64);
mdb_set_dupsort(txn, m_audit_txs, compare_uint64);
if (!(mdb_flags & MDB_RDONLY))
{
@@ -2174,6 +2429,10 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_txs: ", result).c_str()));
if (auto result = mdb_drop(txn, m_yield_blocks, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_blocks: ", result).c_str()));
if (auto result = mdb_drop(txn, m_audit_txs, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_txs: ", result).c_str()));
if (auto result = mdb_drop(txn, m_audit_blocks, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_blocks: ", result).c_str()));
// init with current version
MDB_val_str(k, "version");
@@ -3516,9 +3775,14 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
// Check for SAL - we need to adjust the total for them
if (currency_type == 0) {
// Get the current circulating supply for SAL
amount += m_coinbase;
//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>();
}
@@ -3527,12 +3791,13 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
// NEAC: check for empty supply tally - only happens prior to first conversion on chain
if (circulating_supply.empty()) {
circulating_supply["SAL"] = m_coinbase;
circulating_supply["SAL1"] = 0;
circulating_supply["BURN"] = 0;
}
// Adjust the supply to account for the staked coins
circulating_supply["STAKE"] = staked_coins;
circulating_supply["BURN"] = m_coinbase - circulating_supply["SAL"] - circulating_supply["STAKE"];
return circulating_supply;
}
@@ -4724,7 +4989,7 @@ void BlockchainLMDB::block_rtxn_abort() const
}
uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated,
const std::vector<std::pair<transaction, blobdata>>& txs, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi)
const std::vector<std::pair<transaction, blobdata>>& txs, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -4742,7 +5007,7 @@ uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t
try
{
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi);
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi, abi);
}
catch (const DB_ERROR_TXN_START& e)
{
@@ -5239,8 +5504,38 @@ uint64_t BlockchainLMDB::get_database_size() const
#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global"))
void BlockchainLMDB::migrate_2_3()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
uint64_t i;
int result;
mdb_txn_safe txn(false);
MDB_val k, v;
char *ptr;
MGINFO_YELLOW("Migrating blockchain from DB version 2 to 3 - this may take a while:");
// Create the missing (and empty) "audit_block_info" records for all blocks
do {
} while(0);
uint32_t version = VERSION;
v.mv_data = (void *)&version;
v.mv_size = sizeof(version);
MDB_val_str(vk, "version");
result = mdb_txn_begin(m_env, NULL, 0, txn);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
result = mdb_put(txn, m_properties, &vk, &v, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to update version for the db: ", result).c_str()));
txn.commit();
}
void BlockchainLMDB::migrate(const uint32_t oldversion)
{
//if (oldversion < 3)
// migrate_2_3();
}
} // namespace cryptonote
+19 -3
View File
@@ -78,6 +78,8 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_circ_supply_tally;
MDB_cursor *m_txc_yield_txs;
MDB_cursor *m_txc_yield_blocks;
MDB_cursor *m_txc_audit_txs;
MDB_cursor *m_txc_audit_blocks;
} mdb_txn_cursors;
@@ -104,6 +106,8 @@ typedef struct mdb_txn_cursors
#define m_cur_circ_supply_tally m_cursors->m_txc_circ_supply_tally
#define m_cur_yield_txs m_cursors->m_txc_yield_txs
#define m_cur_yield_blocks m_cursors->m_txc_yield_blocks
#define m_cur_audit_txs m_cursors->m_txc_audit_txs
#define m_cur_audit_blocks m_cursors->m_txc_audit_blocks
typedef struct mdb_rflags
{
@@ -131,6 +135,8 @@ typedef struct mdb_rflags
bool m_rf_circ_supply_tally;
bool m_rf_yield_txs;
bool m_rf_yield_blocks;
bool m_rf_audit_txs;
bool m_rf_audit_blocks;
} mdb_rflags;
typedef struct mdb_threadinfo
@@ -343,6 +349,7 @@ public:
, const std::vector<std::pair<transaction, blobdata>>& txs
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
);
virtual void set_batch_transactions(bool batch_transactions);
@@ -400,8 +407,10 @@ private:
const crypto::hash& blk_hash,
uint64_t slippage_total,
uint64_t yield_total,
uint64_t audit_total,
const cryptonote::network_type nettype,
cryptonote::yield_block_info& ybi
cryptonote::yield_block_info& ybi,
cryptonote::audit_block_info& abi
);
virtual void remove_block();
@@ -455,10 +464,14 @@ private:
// migrate from older DB version to current
void migrate(const uint32_t oldversion);
// migrate from DB version 0 to 1
//void migrate_0_1();
// migrate from DB version 2 to 3
void migrate_2_3();
void cleanup_batch();
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const;
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const;
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const;
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const;
@@ -499,6 +512,9 @@ private:
MDB_dbi m_yield_txs;
MDB_dbi m_yield_blocks;
MDB_dbi m_audit_txs;
MDB_dbi m_audit_blocks;
mutable uint64_t m_cum_size; // used in batch size estimation
mutable unsigned int m_cum_count;
std::string m_folder;
+6 -1
View File
@@ -140,6 +140,9 @@ public:
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const override { return false; }
virtual uint64_t get_database_size() const override { return 0; }
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const override { return 0; }
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const override { return 0; }
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const override { return 0; }
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const override { return 0; }
@@ -156,8 +159,10 @@ public:
const crypto::hash& blk_hash,
uint64_t slippage_total,
uint64_t yield_total,
uint64_t audit_total,
const cryptonote::network_type nettype,
cryptonote::yield_block_info& ybi
cryptonote::yield_block_info& ybi,
cryptonote::audit_block_info& abi
) override { }
virtual cryptonote::block get_block_from_height(const uint64_t& height) const override { return cryptonote::block(); }
virtual void set_hard_fork_version(uint64_t height, uint8_t version) override {}
+50
View File
@@ -142,6 +142,24 @@ set(blockchain_scanner_private_headers)
monero_private_headers(blockchain_scanner
${blockchain_scanner_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
${blockchain_import_sources}
@@ -312,6 +330,38 @@ set_property(TARGET blockchain_scanner
OUTPUT_NAME "salvium-blockchain-scanner")
install(TARGETS blockchain_scanner DESTINATION bin)
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_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)
endif()
endif()
monero_add_executable(blockchain_stats
${blockchain_stats_sources}
${blockchain_stats_private_headers})
@@ -488,8 +488,9 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
try
{
cryptonote::yield_block_info ybi; // This just gets discarded because we aren't looking to maintain a cache of YBI data in the import utility
cryptonote::audit_block_info abi; // This just gets discarded because we aren't looking to maintain a cache of ABI data in the import utility
uint64_t long_term_block_weight = core.get_blockchain_storage().get_next_long_term_block_weight(block_weight);
core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, ybi);
core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, ybi, abi);
}
catch (const std::exception& e)
{
+85 -197
View File
@@ -29,6 +29,8 @@
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include "common/command_line.h"
#include "common/i18n.h"
#include "common/password.h"
#include "common/varint.h"
#include "cryptonote_basic/cryptonote_boost_serialization.h"
#include "cryptonote_core/tx_pool.h"
@@ -43,11 +45,20 @@
#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
#define DELIM "|"
#define DEF_STAKE_MODE "all"
namespace po = boost::program_options;
using namespace epee;
using namespace cryptonote;
namespace scanner
{
const char* tr(const char* str)
{
return i18n_translate(str, "tools::scanner");
}
}
static bool stop_requested = false;
int main(int argc, char* argv[])
@@ -70,6 +81,8 @@ int main(int argc, char* argv[])
const command_line::arg_descriptor<uint64_t> arg_block_start = {"block-start", "start at block number", block_start};
const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
const command_line::arg_descriptor<std::string> arg_delimiter = {"delimiter", "\"<string>\"", DELIM};
const command_line::arg_descriptor<std::string> arg_stake_mode = {"stake", "\"<string>\"", DEF_STAKE_MODE};
const command_line::arg_descriptor<bool> arg_check_asset_types = {"check-asset-types", "Scan for asset-type issues", false};
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
@@ -78,6 +91,8 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, arg_block_start);
command_line::add_arg(desc_cmd_sett, arg_block_stop);
command_line::add_arg(desc_cmd_sett, arg_delimiter);
command_line::add_arg(desc_cmd_sett, arg_stake_mode);
command_line::add_arg(desc_cmd_sett, arg_check_asset_types);
command_line::add_arg(desc_cmd_only, command_line::arg_help);
po::options_description desc_options("Allowed options");
@@ -116,6 +131,8 @@ int main(int argc, char* argv[])
block_start = command_line::get_arg(vm, arg_block_start);
block_stop = command_line::get_arg(vm, arg_block_stop);
std::string delimiter = command_line::get_arg(vm, arg_delimiter);
std::string stake_mode = command_line::get_arg(vm, arg_stake_mode);
bool opt_check_asset_types = command_line::get_arg(vm, arg_check_asset_types);
// If we wanted to use the memory pool, we would set up a fake_core.
@@ -158,7 +175,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->blockchain.init(db, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET);
r = core_storage->blockchain.init(db, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");
@@ -203,6 +220,9 @@ 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;
for (uint64_t h = block_start; h < block_stop; ++h)
{
cryptonote::blobdata bd = db->get_block_blob_from_height(h);
@@ -234,34 +254,60 @@ skip:
std::map<size_t, std::vector<std::string>> used_tx_versions;
used_assets.insert("SAL");
uint8_t hf_version = blk.major_version;
// Check TX versions
if (blk.miner_tx.version != 2) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX version detected" << delimiter << "version:" << blk.miner_tx.version << std::endl;
}
if (blk.protocol_tx.version != 2) {
if (blk.protocol_tx.version != 2 && h>0) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX version detected" << delimiter << "version:" << blk.protocol_tx.version << std::endl;
}
// Get the miner_tx assets
std::set<crypto::public_key> used_keys;
for (const auto& miner_tx_vout : blk.miner_tx.vout) {
std::string asset_type;
if (!cryptonote::get_output_asset_type(miner_tx_vout, asset_type)) {
throw std::runtime_error("Aborting: failed to get output asset type from miner_tx");
} else if (asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from miner_tx");
} else if (blk.major_version >= HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL1") {
throw std::runtime_error("Aborting: invalid output asset type from miner_tx: " + asset_type);
} else if (blk.major_version < HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from miner_tx: " + asset_type + ", HF:" + std::to_string(blk.major_version));
}
miner_tx_assets.insert(asset_type);
if (miner_tx_vout.amount > 13500000000 && h>0) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX amount detected" << delimiter << "amount:" << miner_tx_vout.amount << std::endl;
}
crypto::public_key key;
cryptonote::get_output_public_key(miner_tx_vout, key);
if (used_keys.count(key)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX - duplicate output detected" << delimiter << "pubkey:" << key << std::endl;
}
used_keys.insert(key);
}
// Get the protocol_tx assets
used_keys.clear();
for (const auto& protocol_tx_vout : blk.protocol_tx.vout) {
std::string asset_type;
if (!cryptonote::get_output_asset_type(protocol_tx_vout, asset_type)) {
throw std::runtime_error("Aborting: failed to get output asset type from protocol_tx");
} else if (asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx");
} else if (blk.major_version >= HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL1") {
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx: " + asset_type);
} else if (blk.major_version < HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx: " + asset_type + ", HF:" + std::to_string(blk.major_version));
}
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;
}
crypto::public_key key;
cryptonote::get_output_public_key(protocol_tx_vout, key);
if (used_keys.count(key)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX - duplicate output detected" << delimiter << "pubkey:" << key << std::endl;
}
used_keys.insert(key);
}
for (const auto& tx_id : blk.tx_hashes)
@@ -285,207 +331,49 @@ skip:
currsz += bd.size();
currtxs++;
if (tx.version != 2) {
if (tx.type != cryptonote::transaction_type::TRANSFER &&
tx.type != cryptonote::transaction_type::BURN &&
tx.type != cryptonote::transaction_type::STAKE &&
tx.type != cryptonote::transaction_type::AUDIT) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX type detected" << delimiter << "type:" << (uint8_t)tx.type << std::endl;
}
if ((tx.version != 2 && hf_version < HF_VERSION_ENABLE_N_OUTS) || (tx.version != 3 && hf_version < HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX version detected" << delimiter << "version:" << tx.version << std::endl;
}
/*
std::string source;
std::string dest;
offshore::pricing_record pr;
if (!cryptonote::get_tx_asset_types(tx, source, dest, false)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "At least 1 input or 1 output of the tx was invalid" << delimiter << "get_tx_asset_types() failed : ";
if (source.empty()) {
std::cout << "source is empty" << std::endl;
}
if (dest.empty()) {
std::cout << "dest is empty" << std::endl;
if (tx.type == cryptonote::transaction_type::STAKE && stake_mode.compare("off")) {
if (stake_mode.compare("all") == 0) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "STAKE TX detected" << delimiter << "amount:" << (tx.amount_burnt / 100000000) << std::endl;
} else if (stake_mode.compare("large") == 0 && tx.amount_burnt > 25000000000000llu) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "large STAKE TX detected" << delimiter << "amount:" << (tx.amount_burnt / 100000000) << std::endl;
}
}
if (!cryptonote::get_tx_type(source, dest, offshore, onshore, offshore_transfer, xusd_to_xasset, xasset_to_xusd, xasset_transfer)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "At least 1 input or 1 output of the tx was invalid" << delimiter << "get_tx_type() failed" << std::endl;
}
*/
// Add the source currency to the list of expected ones
used_assets.insert(tx.source_asset_type);
/*
if ((offshore && !tx.rct_signatures.txnOffshoreFee) ||
(onshore && !tx.rct_signatures.txnOffshoreFee_usd) ||
(xusd_to_xasset && !tx.rct_signatures.txnOffshoreFee_usd) ||
(xasset_to_xusd && !tx.rct_signatures.txnOffshoreFee_xasset)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "Missing conversion fee." << delimiter << "" <<
"Source:" << source << ", dest:" << dest <<
", XHV fees:" << tx.rct_signatures.txnFee << "," << tx.rct_signatures.txnOffshoreFee <<
", XUSD fees:" << tx.rct_signatures.txnFee_usd << "," << tx.rct_signatures.txnOffshoreFee_usd <<
", burnt:" << tx.amount_burnt << ", minted:" << tx.amount_minted << std::endl;
} else if ((offshore || onshore || xusd_to_xasset || xasset_to_xusd) && (!tx.amount_burnt || !tx.amount_minted)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "Missing burnt/minted value." << std::endl;
}
*/
/*
// Only run these checks for conversions
if (source != dest) {
// Check PR record is not too old
if (h > (tx.pricing_record_height + 10)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "pricing record used by tx was too old" <<
delimiter << "tx.pricing_record_height = " << tx.pricing_record_height << std::endl;
}
// Get the PR used by the TX
cryptonote::blobdata bd_pr = db->get_block_blob_from_height(tx.pricing_record_height);
cryptonote::block blk_pr;
if (!cryptonote::parse_and_validate_block_from_blob(bd_pr, blk_pr)) {
LOG_PRINT_L0("Bad block from db");
return 1;
}
// Get a more convenient handle on the conversion PR
pr = blk_pr.pricing_record;
// Verify the fees in 128-bit space
boost::multiprecision::uint128_t burnt_128 = tx.amount_burnt;
boost::multiprecision::uint128_t minted_128 = tx.amount_minted;
// calculate conversion fees
uint32_t fees_version = (h >= 831700) ? 2 : (h >= 653565) ? 2 : 1;
uint64_t blocks_to_unlock = tx.unlock_time - h + 1;
boost::multiprecision::uint128_t fee;
if (offshore) {
if (fees_version >= 3) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid fee version " << fees_version << "" << delimiter << "..." << std::endl;
} else if (fees_version == 2) {
fee =
(blocks_to_unlock >= 5030) ? (tx.amount_burnt / 500) :
(blocks_to_unlock >= 1430) ? (tx.amount_burnt / 20) :
(blocks_to_unlock >= 710) ? (tx.amount_burnt / 10) :
tx.amount_burnt / 5;
if (opt_check_asset_types) {
if (tx.source_asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid source asset type found in tx");
} else if (tx.destination_asset_type != "SAL") {
if (tx.destination_asset_type == "BURN") {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "BURN TX detected" << delimiter << "amount:" << tx.amount_burnt << std::endl;
} else {
// Calculate the priority based on the unlock time
uint64_t priority =
(blocks_to_unlock >= 5030) ? 1 :
(blocks_to_unlock >= 1430) ? 2 :
(blocks_to_unlock >= 710) ? 3 :
4;
uint64_t unlock_time = 60 * pow(3, 4-priority);
// abs() implementation for uint64_t's
uint64_t delta = (pr.unused1 > pr.xUSD) ? pr.unused1 - pr.xUSD : pr.xUSD - pr.unused1;
// Estimate the fee
double scale = exp((M_PI / -1000.0) * (unlock_time - 60) * 1.2);
scale *= delta;
scale *= tx.amount_burnt;
scale /= 1000000000000;
fee = (boost::multiprecision::uint128_t)(scale);
}
if ((h >= 658500) && (fee != tx.rct_signatures.txnOffshoreFee)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid fee " << tx.rct_signatures.txnOffshoreFee << "" << delimiter << "check:" << fee << std::endl;
}
} else if (onshore) {
if (fees_version >= 3) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid fee version " << fees_version << "" << delimiter << "..." << std::endl;
} else if (fees_version == 2) {
fee =
(blocks_to_unlock >= 5030) ? (tx.amount_burnt / 500) :
(blocks_to_unlock >= 1430) ? (tx.amount_burnt / 20) :
(blocks_to_unlock >= 710) ? (tx.amount_burnt / 10) :
tx.amount_burnt / 5;
} else {
// Calculate the priority based on the unlock time
uint64_t priority =
(blocks_to_unlock >= 5030) ? 1 :
(blocks_to_unlock >= 1430) ? 2 :
(blocks_to_unlock >= 710) ? 3 :
4;
uint64_t unlock_time = 60 * pow(3, 4-priority);
// abs() implementation for uint64_t's
uint64_t delta = (pr.unused1 > pr.xUSD) ? pr.unused1 - pr.xUSD : pr.xUSD - pr.unused1;
// Estimate the fee
double scale = exp((M_PI / -1000.0) * (unlock_time - 60) * 1.2);
scale *= delta;
scale *= tx.amount_burnt;
scale /= 1000000000000;
fee = (boost::multiprecision::uint128_t)(scale);
}
if ((h >= 658500) && (fee != tx.rct_signatures.txnOffshoreFee_usd)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid offshore fee " << tx.rct_signatures.txnOffshoreFee_usd << "" << delimiter << "check:" << fee << std::endl;
}
} else if (xusd_to_xasset) {
fee = tx.amount_burnt;
fee *= 3;
fee /= 1000;
if (fee != tx.rct_signatures.txnOffshoreFee_usd) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid xusd_to_xasset fee " << tx.rct_signatures.txnOffshoreFee_usd << "" << delimiter << "check:" << fee << std::endl;
}
} else if (xasset_to_xusd) {
fee = tx.amount_burnt;
fee *= 3;
fee /= 1000;
if (fee != tx.rct_signatures.txnOffshoreFee_xasset) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
<< "invalid xasset_to_xusd fee " << tx.rct_signatures.txnOffshoreFee_xasset << "" << delimiter << "check:" << fee << std::endl;
}
}
// Check for 0 price in the source or destination currency
if (offshore|| xusd_to_xasset) {
if (!pr[dest]) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "0 exchange rate used for dest " << dest << "" << delimiter << "..." << std::endl;
} else if (pr[dest] == 1000000000000) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "1.0000 exchange rate used for dest " << dest << "" << delimiter << "..." << std::endl;
}
} else if (onshore || xasset_to_xusd) {
if (!pr[source]) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "0 exchange rate used for source " << source << "" << delimiter << "..." << std::endl;
} else if (pr[source] == 1000000000000) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "1.0000 exchange rate used for source " << source << "" << delimiter << "..." << std::endl;
throw std::runtime_error("Aborting: invalid destination asset type found in tx");
}
}
for (const auto& tx_vout : tx.vout) {
std::string asset_type;
if (!cryptonote::get_output_asset_type(tx_vout, asset_type)) {
throw std::runtime_error("Aborting: failed to get output asset type from tx");
} else if (asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from tx");
}
}
// Add the source currency to the list of expected ones
used_assets.insert(tx.source_asset_type);
}
*/
}
/*
// compare the asset sets
if (used_assets == miner_tx_assets) {
} else if (used_assets.empty() && (miner_tx_assets.size() == 1) && (miner_tx_assets.count("XHV") == 1)) {
} else {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "Mismatch in miner reward assets detected" << delimiter << "Used assets = { ";
for (auto const &i: used_assets)
std::cout << i << " ";
std::cout << "}, miner_tx claimed { ";
for (auto const &i: miner_tx_assets)
std::cout << i << " ";
std::cout << "}" << std::endl;
}
*/
currblks++;
@@ -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
+12
View File
@@ -510,6 +510,18 @@ namespace cryptonote
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
}
struct audit_block_info {
uint64_t block_height;
uint64_t locked_coins_this_block;
uint64_t locked_coins_tally;
BEGIN_SERIALIZE()
VARINT_FIELD(block_height)
VARINT_FIELD(locked_coins_this_block)
VARINT_FIELD(locked_coins_tally)
END_SERIALIZE()
};
struct yield_block_info {
uint64_t block_height;
uint64_t slippage_total_this_block;
@@ -358,6 +358,28 @@ namespace boost
a & x.z2;
}
template <class Archive>
inline void serialize(Archive &a, rct::salvium_input_data_t &x, const boost::serialization::version_type ver)
{
a & x.aR;
a & x.i;
}
template <class Archive>
inline void serialize(Archive &a, rct::salvium_data_t &x, const boost::serialization::version_type ver)
{
a & x.salvium_data_type;
a & x.pr_proof;
a & x.sa_proof;
if (x.salvium_data_type == rct::SalviumAudit)
{
a & x.cz_proof;
a & x.input_verification_data;
a & x.spend_pubkey;
a & x.enc_view_privkey_str;
}
}
template <class Archive>
inline void serialize(Archive &a, rct::ecdhTuple &x, const boost::serialization::version_type ver)
{
@@ -411,7 +433,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs)
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumOne)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -421,9 +443,11 @@ namespace boost
serializeOutPk(a, x.outPk, ver);
a & x.txnFee;
a & x.p_r;
if (x.type == rct::RCTTypeFullProofs) {
a & x.pr_proof;
a & x.sa_proof;
if (x.type == rct::RCTTypeSalviumOne) {
a & x.salvium_data;
} else if (x.type == rct::RCTTypeFullProofs) {
a & x.salvium_data.pr_proof;
a & x.salvium_data.sa_proof;
}
}
@@ -450,7 +474,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs)
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumOne)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -460,9 +484,11 @@ namespace boost
serializeOutPk(a, x.outPk, ver);
a & x.txnFee;
a & x.p_r;
if (x.type == rct::RCTTypeFullProofs) {
a & x.pr_proof;
a & x.sa_proof;
if (x.type == rct::RCTTypeSalviumOne) {
a & x.salvium_data;
} else if (x.type == rct::RCTTypeFullProofs) {
a & x.salvium_data.pr_proof;
a & x.salvium_data.sa_proof;
}
//--------------
a & x.p.rangeSigs;
@@ -475,7 +501,7 @@ namespace boost
a & x.p.MGs;
if (ver >= 1u)
a & x.p.CLSAGs;
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus || x.type == rct::RCTTypeFullProofs)
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus || x.type == rct::RCTTypeFullProofs || x.type == rct::RCTTypeSalviumOne)
a & x.p.pseudoOuts;
}
@@ -517,5 +543,5 @@ namespace boost
}
BOOST_CLASS_VERSION(rct::rctSigPrunable, 2)
BOOST_CLASS_VERSION(rct::rctSig, 3)
BOOST_CLASS_VERSION(rct::rctSig, 4)
BOOST_CLASS_VERSION(rct::multisig_out, 1)
@@ -290,7 +290,7 @@ namespace cryptonote
return is_v1_tx(blobdata_ref{tx_blob.data(), tx_blob.size()});
}
//---------------------------------------------------------------
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od)
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od, rct::salvium_input_data_t& sid)
{
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
@@ -317,11 +317,13 @@ namespace cryptonote
boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev);
CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address");
return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev, use_origin_data, od);
sid.aR = subaddr_recv_info->derivation;
sid.i = real_output_index;
return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev, use_origin_data, od, sid);
}
//---------------------------------------------------------------
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od)
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od, rct::salvium_input_data_t& sid)
{
if (hwdev.compute_key_image(ack, out_key, recv_derivation, real_output_index, received_index, in_ephemeral, ki))
{
@@ -400,7 +402,7 @@ namespace cryptonote
// SRCG: This is a confusing one - for some reason I was using the line below, and it _seemed_ to work...
// ... but I think it was luck! the "od.output_index" would only work for the TD_ORIGIN data, of course...
//hwdev.derive_subaddress_public_key(out_key, recv_derivation, od.output_index, P_change);
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE) {
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE || od.tx_type == cryptonote::transaction_type::AUDIT) {
hwdev.derive_subaddress_public_key(out_key, recv_derivation, 0, P_change);
} else {
hwdev.derive_subaddress_public_key(out_key, recv_derivation, real_output_index, P_change);
@@ -415,13 +417,20 @@ namespace cryptonote
crypto::secret_key sk_spend = crypto::null_skey;
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation_P_change_tx, od.output_index, spend_skey, sk_spend), false, "Failed to derive secret key for P_change");
// 3.5 Handle subaddresses
if (!received_index.is_zero()) {
crypto::secret_key scalar_step3;
hwdev.sc_secret_add(scalar_step3, sk_spend, subaddr_sk);
sk_spend = scalar_step3;
}
// 4. Derive the public key from the secret key for verification purposes
crypto::public_key change_pk;
CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(sk_spend, change_pk), false, "Failed to derive public key for P_change");
CHECK_AND_ASSERT_MES(P_change == change_pk, false, "derived P_change public key does not match P_change");
// 5. Calculate the secret spend key "x_return"
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE) {
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE || od.tx_type == cryptonote::transaction_type::AUDIT) {
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, 0, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'");
} else {
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, real_output_index, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'");
@@ -433,7 +442,11 @@ namespace cryptonote
// 6. Create the key_image needed to be able to spend the output
hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
// Update the SID to have the correct derivation for P_change as well
sid.aR_stake = derivation_P_change_tx;
sid.i_stake = od.output_index;
return true;
} else {
@@ -967,8 +980,8 @@ namespace cryptonote
switch (asset_type_id) {
case 0x53414C00:
return "SAL";
case 0x56534400:
return "VSD";
case 0x53414C31:
return "SAL1";
case 0x4255524E:
return "BURN";
case 0x00000000:
@@ -984,8 +997,8 @@ namespace cryptonote
{
if (asset_type == "SAL") {
return 0x53414C00;
} else if (asset_type == "VSD") {
return 0x56534400;
} else if (asset_type == "SAL1") {
return 0x53414C31;
} else if (asset_type == "BURN") {
return 0x4255524E;
} else if (asset_type == "") {
@@ -1260,7 +1273,24 @@ namespace cryptonote
// Verify the asset type
std::string asset_type;
CHECK_AND_ASSERT_MES(cryptonote::get_output_asset_type(o, asset_type), false, "failed to get asset type");
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
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) {
if (tx.type == cryptonote::transaction_type::AUDIT) {
// 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);
} 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);
} else {
// 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;
}
@@ -1338,15 +1368,13 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations");
if (out_can_be_to_acc(view_tag_opt, additional_derivations[output_index], output_index, &hwdev))
{
// HERE BE DRAGONS!!!
// SRCG: This is NOT going to work for PROTOCOL_TX except where there is only a single output
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
// LAND AHOY!!!
auto found = subaddresses.find(subaddress_spendkey);
if (found != subaddresses.end())
return subaddress_receive_info{ found->second, additional_derivations[output_index] };
// If we get here, odds are that it is a PROTOCOL_TX (rare for other TX types to have additional derivations!)
// If we get here, odds are that it is a PROTOCOL_TX
if (output_index != 0) {
// Try the derivation with a 0 index as an override - CONVERT / YIELD TXs cannot know their index in the PROTOCOL_TX, so they use 0 in all cases
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], 0, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
@@ -104,8 +104,8 @@ namespace cryptonote
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
bool get_tx_fee(const transaction& tx, uint64_t & fee);
uint64_t get_tx_fee(const transaction& tx);
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od);
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od);
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od, rct::salvium_input_data_t& sid);
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od, rct::salvium_input_data_t& sid);
void get_blob_hash(const blobdata& blob, crypto::hash& res);
void get_blob_hash(const blobdata_ref& blob, crypto::hash& res);
crypto::hash get_blob_hash(const blobdata& blob);
+27 -3
View File
@@ -31,6 +31,7 @@
#pragma once
#include <array>
#include <map>
#include <stdexcept>
#include <string>
#include <boost/uuid/uuid.hpp>
@@ -177,6 +178,9 @@
#define THREAD_STACK_SIZE 5 * 1024 * 1024
#define SECRET_ENCRYPTION_PK_STR "5e860406bf9221dba6409faa6eb8fecd6f34acc4935634e76b64b90bf2b6d6a6"
/*
#define HF_VERSION_DYNAMIC_FEE 4
#define HF_VERSION_MIN_MIXIN_4 6
@@ -222,12 +226,19 @@
#define HF_VERSION_ENFORCE_FULL_PROOFS 4
#define HF_VERSION_SHUTDOWN_USER_TXS 5
#define HF_VERSION_AUDIT1 6
#define HF_VERSION_SALVIUM_ONE_PROOFS 6
#define HF_VERSION_AUDIT1_PAUSE 7
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
#define HF_VERSION_ENABLE_CONVERT 255
#define HF_VERSION_ENABLE_ORACLE 255
#define HF_VERSION_SLIPPAGE_YIELD 255
#define TESTNET_VERSION 12
#define TESTNET_VERSION 14
#define STAGENET_VERSION 1
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
@@ -278,10 +289,13 @@ 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 uint64_t STAKE_LOCK_PERIOD = 30*24*30;
const uint64_t AUDIT_LOCK_PERIOD = 30*24*10;
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
// Hash domain separators
const char HASH_KEY_BULLETPROOF_EXPONENT[] = "bulletproof";
const char HASH_KEY_BULLETPROOF_PLUS_EXPONENT[] = "bulletproof_plus";
@@ -352,6 +366,7 @@ namespace config
uint32_t const GENESIS_NONCE = 10001;
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"}};
@@ -378,6 +393,7 @@ namespace config
uint32_t const GENESIS_NONCE = 10002;
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"}};
@@ -413,7 +429,9 @@ namespace cryptonote
uint32_t const GENESIS_NONCE;
std::array<std::string, 3> const ORACLE_URLS;
std::string const ORACLE_PUBLIC_KEY;
uint64_t STAKE_LOCK_PERIOD;
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::string TREASURY_ADDRESS;
};
inline const config_t& get_config(network_type nettype)
@@ -431,6 +449,8 @@ namespace cryptonote
::config::ORACLE_URLS,
::config::ORACLE_PUBLIC_KEY,
::config::STAKE_LOCK_PERIOD,
::config::AUDIT_LOCK_PERIOD,
::config::AUDIT_HARD_FORKS,
::config::TREASURY_ADDRESS
};
static const config_t testnet = {
@@ -446,6 +466,8 @@ 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::TREASURY_ADDRESS
};
static const config_t stagenet = {
@@ -461,6 +483,8 @@ 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::TREASURY_ADDRESS
};
switch (nettype)
+251 -34
View File
@@ -155,12 +155,13 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke
// outputs list. that is to say that absolute offset #2 is absolute offset
// #1 plus relative offset #2.
// TODO: Investigate if this is necessary / why this is done.
std::vector<uint64_t> absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets);
//std::vector<uint64_t> absolute_offsets;
//m_db->get_output_id_from_asset_type_output_index(tx_in_to_key.asset_type, asset_offsets, absolute_offsets);
std::vector<uint64_t> asset_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets);
std::vector<uint64_t> absolute_offsets;
m_db->get_output_id_from_asset_type_output_index(tx_in_to_key.asset_type, asset_offsets, absolute_offsets);
std::vector<output_data_t> outputs;
bool found = false;
/*
auto it = m_scan_table.find(tx_prefix_hash);
if (it != m_scan_table.end())
{
@@ -171,6 +172,7 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke
found = true;
}
}
*/
if (!found)
{
@@ -233,7 +235,7 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke
output_index = m_db->get_output_key(tx_in_to_key.amount, i);
// call to the passed boost visitor to grab the public key for the output
if (!vis.handle_output(output_index.unlock_time, tx_in_to_key.asset_type, output_index.pubkey, output_index.commitment))
if (!vis.handle_output(output_index.unlock_time, cryptonote::asset_type_from_id(output_index.asset_type), output_index.pubkey, output_index.commitment))
{
MERROR_VER("Failed to handle_output for output no = " << count << ", with absolute offset " << i);
return false;
@@ -1501,6 +1503,9 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
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:
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;
@@ -1546,10 +1551,13 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
}
// if nothing is created by this TX - check no money is included
size_t vout_size = b.protocol_tx.vout.size();
CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs");
CHECK_AND_ASSERT_MES(vout_size != 0, true, "coinbase protocol transaction in the block has no outputs");
size_t vout_size = b.protocol_tx.vout.size();
if (vout_size == 0) {
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) {
@@ -1558,22 +1566,48 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
// Get the staking data for the block that matured this time
cryptonote::yield_block_info ybi_matured;
std::vector<std::pair<yield_tx_info, uint64_t>> yield_payouts;
uint64_t matured_height = height - stake_lock_period - 1;
bool ok = get_ybi_entry(matured_height, ybi_matured);
if (!ok || ybi_matured.locked_coins_this_block == 0) {
if (!ok) {
LOG_ERROR("Block at height: " << height << " - Failed to obtain yield block information - aborting");
return false;
} else if (ybi_matured.locked_coins_this_block == 0) {
LOG_PRINT_L1("Block at height: " << height << " - no yield payouts due - skipping");
} else {
// Iterate over the cached data for block yield, calculating the yield payouts due
if (!calculate_yield_payouts(matured_height, yield_payouts)) {
LOG_ERROR("Block at height: " << height << " - Failed to obtain yield payout information - aborting");
return false;
}
}
// Iterate over the cached data for block yield, calculating the yield payouts due
std::vector<std::pair<yield_tx_info, uint64_t>> yield_payouts;
if (!calculate_yield_payouts(matured_height, yield_payouts)) {
LOG_ERROR("Block at height: " << height << " - Failed to obtain yield payout information - aborting");
return false;
// 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");
return false;
}
}
}
// Check we have the correct number of entries
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting");
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;
@@ -1609,19 +1643,43 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
// Add key to list of already-seen
used_keys.insert(out_key);
// check if there is entry in the yield payouts for this output
auto found = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
// 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;
});
if (found == yield_payouts.end()) {
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()) {
// 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";
} 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(out_asset_type == "SAL", false, "Incorrect output asset type for protocol TX");
CHECK_AND_ASSERT_MES(out_amount == found->second, false, "Incorrect output amount for protocol TX");
CHECK_AND_ASSERT_MES(expected_output_asset_type == out_asset_type, false, "Incorrect asset type detected for protocol TX ouput - rejecting block");
}
// Everything checks out
@@ -1897,14 +1955,22 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
return false;
}
// Work out what the asset_type should be based on height of submission
uint8_t hf_submitted = m_hardfork->get_ideal_version(start_height);
// Create the protocol_metadata entries here
for (const auto& yield_entry: yield_payouts) {
cryptonote::protocol_data_entry entry;
entry.amount_burnt = yield_entry.second;
entry.amount_minted = 0;
entry.amount_slippage_limit = 0;
entry.source_asset = "SAL";
entry.destination_asset = "SAL";
if (hf_submitted >= HF_VERSION_SALVIUM_ONE_PROOFS) {
entry.source_asset = "SAL1";
entry.destination_asset = "SAL1";
} else {
entry.source_asset = "SAL";
entry.destination_asset = "SAL";
}
entry.return_address = yield_entry.first.return_address;
entry.type = cryptonote::transaction_type::STAKE;
entry.P_change = yield_entry.first.P_change;
@@ -1912,6 +1978,50 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
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) {
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");
return false;
}
// Get the asset types
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf);
// Create the protocol_metadata entries here
for (const auto& audit_entry: audit_payouts) {
cryptonote::protocol_data_entry entry;
entry.amount_burnt = audit_entry.second;
entry.amount_minted = 0;
entry.amount_slippage_limit = 0;
entry.source_asset = audit_asset_types.first;
entry.destination_asset = audit_asset_types.second;
entry.return_address = audit_entry.first.return_address;
entry.type = cryptonote::transaction_type::AUDIT;
entry.P_change = audit_entry.first.P_change;
entry.return_pubkey = audit_entry.first.return_pubkey;
protocol_entries.push_back(entry);
}
}
}
}
// Time to construct the protocol_tx
uint64_t protocol_fee = 0;
@@ -3513,8 +3623,24 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
*/
// from v4, only allow bulletproofs plus _with_ full proofs on RCT transactions
if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
// for v5, force the audit and the new SalviumOne RCT data
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::AUDIT) {
if (tx.rct_signatures.type != rct::RCTTypeSalviumOne) {
MERROR_VER("FullProofs plus Audit data required after v" + std::to_string(HF_VERSION_SALVIUM_ONE_PROOFS));
tvc.m_invalid_output = true;
return false;
}
} else {
if (tx.rct_signatures.type != rct::RCTTypeNull) {
MERROR_VER("NULL RCT required for coinbase TXs after v" + std::to_string(HF_VERSION_SALVIUM_ONE_PROOFS));
tvc.m_invalid_output = true;
return false;
}
}
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
// from v4, only allow bulletproofs plus _with_ full proofs on RCT transactions
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT) {
if (tx.rct_signatures.type != rct::RCTTypeFullProofs) {
MERROR_VER("FullProofs required after v" + std::to_string(HF_VERSION_FULL_PROOFS));
@@ -3623,7 +3749,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
}
}
}
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs)
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne)
{
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys.size());
@@ -3664,7 +3790,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
}
}
}
else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs)
else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne)
{
if (!tx.pruned)
{
@@ -3805,8 +3931,8 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
// from v7, sorted ins
if (hf_version >= 7) {
// from v1, sorted ins
if (hf_version >= 1) {
const crypto::key_image *last_key_image = NULL;
for (size_t n = 0; n < tx.vin.size(); ++n)
{
@@ -3818,6 +3944,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
{
MERROR_VER("transaction has unsorted inputs");
tvc.m_verifivation_failed = true;
assert(false);
return false;
}
last_key_image = &in_to_key.k_image;
@@ -3825,6 +3952,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<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;
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);
@@ -3846,6 +3987,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
// Make sure the user isn't trying to spend BURNt coins
CHECK_AND_ASSERT_MES(in_to_key.asset_type not_eq "BURN", false, "trying to spend BURNt coins");
// Make sure only a single asset_type is being spent, and that is the one set on the TX
CHECK_AND_ASSERT_MES(in_to_key.asset_type == tx.source_asset_type, false, "trying to spend " << in_to_key.asset_type << " coins in a TX with " << tx.source_asset_type << " source asset type");
// make sure tx output has key offset(s) (is signed to be used)
CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "empty in_to_key.key_offsets in transaction with id " << get_transaction_hash(tx));
@@ -3911,7 +4055,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
false, "Transaction spends at least one output which is too young");
// Warn that new RCT types are present, and thus the cache is not being used effectively
static constexpr const std::uint8_t RCT_CACHE_TYPE = rct::RCTTypeFullProofs;
static constexpr const std::uint8_t RCT_CACHE_TYPE = rct::RCTTypeSalviumOne;
if (tx.rct_signatures.type > RCT_CACHE_TYPE)
{
MWARNING("RCT cache is not caching new verification results. Please update RCT_CACHE_TYPE!");
@@ -3944,10 +4088,13 @@ 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_ENFORCE_FULL_PROOFS)
{
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs)
{
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;
}
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs) {
MERROR_VER("Unsupported rct type (full proofs are required): " << rv.type);
return false;
}
@@ -3966,6 +4113,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
case rct::RCTTypeCLSAG:
case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeFullProofs:
case rct::RCTTypeSalviumOne:
{
if (!ver_rct_non_semantics_simple_cached(tx, pubkeys, m_rct_ver_cache, RCT_CACHE_TYPE, hf_version))
{
@@ -4348,6 +4496,59 @@ uint64_t Blockchain::get_adjusted_time(uint64_t height) const
return (adjusted_current_block_ts < median_ts ? adjusted_current_block_ts : median_ts);
}
//------------------------------------------------------------------
bool Blockchain::calculate_audit_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& audit_container)
{
LOG_PRINT_L3("Blockchain::" << __func__);
// Clear the audit payout amounts
audit_container.clear();
// Get the AUDIT TX information for matured staked coins
std::vector<cryptonote::yield_tx_info> audit_entries;
// We get the audit_tx_info from the block where they entered the chain
int audit_tx_result = m_db->get_audit_tx_info(start_height, audit_entries);
if (!audit_entries.size()) {
// Report error and abort
LOG_ERROR("calculate_audit_payouts() called, but no audit TXs found at height " << start_height << " - aborting");
return false;
}
// Build a blacklist of staking TXs _not_ to pay out for
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) {
// Check to see if this entry is in the blacklist
if (txs_blacklist.find(epee::string_tools::pod_to_hex(entry.tx_hash)) != txs_blacklist.end()) {
LOG_ERROR("calculate_audit_payouts() found blacklisted TX at height " << start_height << " - skipping payout");
continue;
}
audit_container.emplace_back(std::make_pair(entry, entry.locked_coins));
}
// Return success to caller
return true;
}
//------------------------------------------------------------------
bool Blockchain::get_abi_entry(const uint64_t height, cryptonote::audit_block_info& abi)
{
LOG_PRINT_L3("Blockchain::" << __func__);
// Clear the provided container
std::memset(&abi, 0, sizeof(struct cryptonote::audit_block_info));
int result = m_db->get_audit_block_info(height, abi);
if (result) {
// Request failed - report error and bail out
LOG_ERROR("failed to retrieve ABI entry for height " << height << " - aborting");
return false;
}
return true;
}
//------------------------------------------------------------------
bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_container)
{
LOG_PRINT_L3("Blockchain::" << __func__);
@@ -4365,9 +4566,17 @@ bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vecto
LOG_ERROR("calculate_yield_payouts() called, but no yield TXs found at height " << start_height << " - aborting");
return false;
}
// Build a blacklist of staking TXs _not_ to pay out for
const std::set<std::string> txs_blacklist = {};
// Get the YBI information for the 21,600 blocks that the matured TX(s), we can calculate yield
for (const auto& entry: yield_entries) {
// Check to see if this entry is in the blacklist
if (txs_blacklist.find(epee::string_tools::pod_to_hex(entry.tx_hash)) != txs_blacklist.end()) {
LOG_ERROR("calculate_yield_payouts() found blacklisted TX at height " << start_height << " - skipping payout");
continue;
}
yield_container.emplace_back(std::make_pair(entry, entry.locked_coins));
}
@@ -4955,8 +5164,10 @@ leave:
uint64_t long_term_block_weight = get_next_long_term_block_weight(block_weight);
cryptonote::blobdata bd = cryptonote::block_to_blob(bl);
yield_block_info new_ybi;
audit_block_info new_abi;
std::memset(&new_ybi, 0, sizeof(struct yield_block_info));
new_height = m_db->add_block(std::make_pair(std::move(bl), std::move(bd)), block_weight, long_term_block_weight, cumulative_difficulty, already_generated_coins, txs, m_nettype, new_ybi);
std::memset(&new_abi, 0, sizeof(struct audit_block_info));
new_height = m_db->add_block(std::make_pair(std::move(bl), std::move(bd)), block_weight, long_term_block_weight, cumulative_difficulty, already_generated_coins, txs, m_nettype, new_ybi, new_abi);
// Update the YBI cache data
uint64_t yield_lock_period = cryptonote::get_config(m_nettype).STAKE_LOCK_PERIOD;
@@ -5784,7 +5995,13 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
{
const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
// no need to check for duplicate here.
// HERE BE DRAGONS!!!
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
auto absolute_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets);
//std::vector<uint64_t> asset_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets);
//std::vector<uint64_t> absolute_offsets;
//m_db->get_output_id_from_asset_type_output_index(in_to_key.asset_type, asset_offsets, absolute_offsets);
// LAND AHOY!!!
for (const auto & offset : absolute_offsets)
offset_map[in_to_key.amount].push_back(offset);
+16
View File
@@ -1160,6 +1160,13 @@ namespace cryptonote
*/
uint64_t get_adjusted_time(uint64_t height) const;
/**
* calculate the audit payouts
*
* @return TRUE if the payouts were calculated successfully, FALSE otherwise
*/
bool calculate_audit_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& audit_payouts);
/**
* calculate the yield payouts
*
@@ -1167,6 +1174,15 @@ namespace cryptonote
*/
bool calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_payouts);
/**
* @brief get the ABI entry for a particular height from the cache
*
* Retrieve the ABI entry for the specified height from the local cache.
*
* @return TRUE if the entry was located and returned, FALSE otherwise
*/
bool get_abi_entry(const uint64_t height, cryptonote::audit_block_info& ybi);
/**
* @brief get the complete YBI cache
*
+13 -2
View File
@@ -924,7 +924,15 @@ namespace cryptonote
continue;
const rct::rctSig &rv = tx_info[n].tx->rct_signatures;
const uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) {
MERROR_VER("Invalid RCT type provided");
set_semantics_failed(tx_info[n].tx_hash);
tx_info[n].tvc.m_verifivation_failed = true;
tx_info[n].result = false;
return false;
}
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs) {
MERROR_VER("Invalid RCT type provided");
set_semantics_failed(tx_info[n].tx_hash);
@@ -946,6 +954,7 @@ namespace cryptonote
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
0
))
{
@@ -981,6 +990,7 @@ namespace cryptonote
break;
case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeFullProofs:
case rct::RCTTypeSalviumOne:
if (!is_canonical_bulletproof_plus_layout(rv.p.bulletproofs_plus))
{
MERROR_VER("Bulletproof_plus does not have canonical form");
@@ -1007,12 +1017,13 @@ namespace cryptonote
{
if (!tx_info[n].result)
continue;
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs)
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs && tx_info[n].tx->rct_signatures.type != rct::RCTTypeSalviumOne)
continue;
if (!rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures,
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
0
))
{
+152 -11
View File
@@ -208,7 +208,7 @@ namespace cryptonote
// We are done here - return to caller
return true;
} else if (tx_type == cryptonote::transaction_type::STAKE) {
} else if (tx_type == cryptonote::transaction_type::STAKE || tx_type == cryptonote::transaction_type::AUDIT) {
// CONVERT / YIELD Semantics
// From this point forward, we are departing from the original "return address" scheme
@@ -259,6 +259,7 @@ namespace cryptonote
// Not implemented yet
return false;
}
/*
//---------------------------------------------------------------
bool get_conversion_rate(const oracle::pricing_record& pr, const std::string& from_asset, const std::string& to_asset, uint64_t& rate) {
// Check for burns
@@ -332,6 +333,7 @@ namespace cryptonote
return true;
}
*/
//---------------------------------------------------------------
bool construct_protocol_tx(
const size_t height,
@@ -361,7 +363,16 @@ namespace cryptonote
// Create the TX output for this refund
tx_out out;
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
} else if (entry.type == cryptonote::transaction_type::AUDIT) {
// PAYOUT
LOG_PRINT_L2("Audit TX payout submitted " << entry.amount_burnt << entry.source_asset);
// Create the TX output for this refund
tx_out out;
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
}
@@ -435,6 +446,9 @@ namespace cryptonote
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:
// 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;
@@ -445,7 +459,10 @@ namespace cryptonote
}
tx_out out;
cryptonote::set_tx_out(amount, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
std::string asset_type = "SAL";
if (hard_fork_version >= HF_VERSION_SALVIUM_ONE_PROOFS)
asset_type = "SAL1";
cryptonote::set_tx_out(amount, asset_type, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
tx.vout.push_back(out);
} else {
@@ -491,6 +508,83 @@ namespace cryptonote
return addr.m_view_public_key;
}
//---------------------------------------------------------------
// Encrypt function
std::string encrypt_pvk(const crypto::secret_key &pvk, const crypto::public_key &PK) {
// Step 1: Generate ephemeral keypair
crypto::secret_key ephemeral_sk;
crypto::public_key ephemeral_pk;
crypto::generate_keys(ephemeral_pk, ephemeral_sk);
// Step 2: Derive shared secret
crypto::ec_scalar shared_secret;
crypto::key_derivation derivation;
if (!crypto::generate_key_derivation(PK, ephemeral_sk, derivation)) {
throw std::runtime_error("Failed to generate key derivation");
}
crypto::derivation_to_scalar(derivation, 0, shared_secret);
// Step 3: Symmetric key generation (using Keccak hash)
crypto::hash symmetric_key_hash;
crypto::cn_fast_hash(&shared_secret, sizeof(shared_secret), symmetric_key_hash);
// Step 4: Encrypt the data (AES-256-CBC or ChaCha20)
std::string ciphertext(sizeof(crypto::secret_key), '\0');
crypto::chacha_key symmetric_key;
memcpy(&symmetric_key, &symmetric_key_hash, sizeof(symmetric_key));
crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>();
crypto::chacha20(pvk.data, sizeof(crypto::secret_key), symmetric_key, iv, &ciphertext[0]);
// Step 5: Package ephemeral_pk and ciphertext together
std::string encrypted_data = std::string(reinterpret_cast<char*>(&ephemeral_pk), sizeof(ephemeral_pk)) +
std::string(reinterpret_cast<char*>(&iv), sizeof(iv)) +
ciphertext;
return epee::string_tools::buff_to_hex_nodelimer(encrypted_data);
}
//---------------------------------------------------------------
// Decrypt function
bool decrypt_pvk(const std::string &encrypted_data_hex, const crypto::secret_key &SK, crypto::secret_key &pvk) {
//std::string decrypt_pvk(const std::string &encrypted_data, const crypto::secret_key &SK) {
// Step 1: Extract ephemeral_pk, iv, and ciphertext from encrypted_data
std::string encrypted_data;
for (size_t i = 0; i < encrypted_data_hex.length(); i += 2) {
std::istringstream iss(encrypted_data_hex.substr(i, 2));
int byte;
iss >> std::hex >> byte;
encrypted_data += static_cast<char>(byte);
}
const char *data_ptr = encrypted_data.data();
crypto::public_key ephemeral_pk;
memcpy(&ephemeral_pk, data_ptr, sizeof(ephemeral_pk));
data_ptr += sizeof(ephemeral_pk);
crypto::chacha_iv iv;
memcpy(&iv, data_ptr, sizeof(iv));
data_ptr += sizeof(iv);
std::string ciphertext(data_ptr, encrypted_data.size() - sizeof(ephemeral_pk) - sizeof(iv));
// Step 2: Derive shared secret
crypto::ec_scalar shared_secret;
crypto::key_derivation derivation;
if (!crypto::generate_key_derivation(ephemeral_pk, SK, derivation)) {
throw std::runtime_error("Failed to generate key derivation");
}
crypto::derivation_to_scalar(derivation, 0, shared_secret);
// Step 3: Symmetric key generation (using Keccak hash)
crypto::hash symmetric_key_hash;
crypto::cn_fast_hash(&shared_secret, sizeof(shared_secret), symmetric_key_hash);
// Step 4: Decrypt the data
std::string plaintext(ciphertext.size(), '\0');
crypto::chacha_key symmetric_key;
memcpy(&symmetric_key, &symmetric_key_hash, sizeof(symmetric_key));
crypto::chacha20(ciphertext.data(), ciphertext.size(), symmetric_key, iv, &plaintext[0]);
memcpy(pvk.data, &plaintext[0], sizeof(crypto::secret_key));
return true;
}
//---------------------------------------------------------------
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags)
{
hw::device &hwdev = sender_account_keys.get_device();
@@ -602,6 +696,23 @@ namespace cryptonote
};
std::vector<input_generation_context_data> in_contexts;
bool audit = (tx_type == cryptonote::transaction_type::AUDIT);
rct::salvium_data_t salvium_data;
if (audit) {
// Generate the encrypted private view key
crypto::public_key PK;
epee::string_tools::hex_to_pod(SECRET_ENCRYPTION_PK_STR, PK);
salvium_data.enc_view_privkey_str = encrypt_pvk(sender_account_keys.m_view_secret_key, PK);
// And now the rest of the structure
salvium_data.salvium_data_type = rct::SalviumAudit;
salvium_data.input_verification_data.reserve(sources.size());
salvium_data.spend_pubkey = sender_account_keys.m_account_address.m_spend_public_key;
} else {
salvium_data.salvium_data_type = rct::SalviumNormal;
}
uint64_t summary_inputs_money = 0;
//fill inputs
int idx = -1;
@@ -619,14 +730,26 @@ namespace cryptonote
in_contexts.push_back(input_generation_context_data());
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
crypto::key_image img;
rct::salvium_input_data_t sid;
const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
bool use_origin_data = (src_entr.origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev, use_origin_data, src_entr.origin_tx_data))
sid.origin_tx_type = src_entr.origin_tx_data.tx_type;
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev, use_origin_data, src_entr.origin_tx_data, sid))
{
LOG_ERROR("Key image generation failed!");
return false;
}
// SRCG: store the audit data for the source here
if (audit) {
sid.amount = src_entr.amount;
if (sid.origin_tx_type == cryptonote::transaction_type::STAKE) {
// STAKE TXs have to use "output_index 0" because they don't know what the actual output_index value will be ahead of time
sid.i = 0;
}
salvium_data.input_verification_data.push_back(sid);
}
//check that derivated key is equal with real output key
if(!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) )
{
@@ -652,6 +775,14 @@ namespace cryptonote
tx.vin.push_back(input_to_key);
}
// Sanity check the size of the verification data
if (audit) {
if (salvium_data.input_verification_data.size() != sources.size()) {
LOG_ERROR("Missing input verification data");
return false;
}
}
if (shuffle_outs)
{
std::shuffle(destinations.begin(), destinations.end(), crypto::random_device{});
@@ -670,6 +801,7 @@ namespace cryptonote
std::swap(tx.vin[i0], tx.vin[i1]);
std::swap(in_contexts[i0], in_contexts[i1]);
std::swap(sources[i0], sources[i1]);
if (audit) std::swap(salvium_data.input_verification_data[i0], salvium_data.input_verification_data[i1]);
});
// figure out if we need to make additional tx pubkeys
@@ -705,6 +837,7 @@ namespace cryptonote
crypto::secret_key x_change = crypto::null_skey;
rct::key key_yF;
uint8_t change_index = 0;
bool found_change = false;
for(const tx_destination_entry& dst_entr: destinations)
{
CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount);
@@ -725,11 +858,19 @@ namespace cryptonote
tx.amount_burnt += dst_entr.amount;
continue;
}
} else if (tx_type == cryptonote::transaction_type::AUDIT) {
// Do not create outputs that are staked for yield - discard them as unused
if (!dst_entr.is_change) {
tx.amount_burnt += dst_entr.amount;
continue;
}
}
// Check to see if this is the change output
if (dst_entr.is_change) {
CHECK_AND_ASSERT_MES(!found_change, false, "Too many change outputs!!!");
change_index = output_index;
found_change = true;
}
LOG_ERROR("*****************************************************************************");
@@ -746,7 +887,7 @@ namespace cryptonote
need_additional_txkeys, additional_tx_keys,
additional_tx_public_keys, amount_keys, out_eph_public_key,
use_view_tags, view_tag);
tx_out out;
cryptonote::set_tx_out(dst_entr.amount, dst_entr.asset_type, dst_entr.is_change ? 0 : unlock_time, out_eph_public_key, use_view_tags, view_tag, out);
tx.vout.push_back(out);
@@ -836,14 +977,14 @@ namespace cryptonote
tx.return_address_change_mask.push_back(eci_data);
}
} else if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE) {
} else if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
if (tx.type == cryptonote::transaction_type::TRANSFER)
CHECK_AND_ASSERT_MES(tx.vout.size() == 2, false, "Internal error - incorrect number of outputs (!=2) for TRANSFER tx");
else if (tx.type == cryptonote::transaction_type::STAKE)
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for YIELD tx");
else if (tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT)
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for STAKE/AUDIT tx");
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
@@ -1031,11 +1172,10 @@ namespace cryptonote
fee = summary_inputs_money - summary_outs_money - tx.amount_burnt;
// zero out all amounts to mask rct outputs, real amounts are now encrypted
for (size_t i = 0; i < tx.vin.size(); ++i)
{
for (size_t i = 0; i < tx.vin.size(); ++i) {
if (sources[i].rct)
boost::get<txin_to_key>(tx.vin[i]).amount = 0;
}
}
for (size_t i = 0; i < tx.vout.size(); ++i) {
tx.vout[i].amount = 0;
}
@@ -1060,6 +1200,7 @@ namespace cryptonote
outSk,
rct_config,
hwdev,
salvium_data,
rct::sk2rct(x_change),
change_index,
key_yF
@@ -39,9 +39,11 @@
namespace cryptonote
{
/*
bool get_conversion_rate(const oracle::pricing_record& pr, const std::string& from_asset, const std::string& to_asset, uint64_t& rate);
bool get_converted_amount(const uint64_t& conversion_rate, const uint64_t& source_amount, uint64_t& dest_amount);
bool calculate_conversion(const std::string& source_asset, const std::string& dest_asset, const uint64_t amount_burnt, const uint64_t amount_slippage_limit, uint64_t& amount_minted, uint64_t& amount_slippage, const std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const uint8_t hf_version);
*/
//---------------------------------------------------------------
/**
* Construct the protocol_tx
@@ -171,6 +173,9 @@ namespace cryptonote
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& asset_type, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time);
std::string encrypt_pvk(const crypto::secret_key &pvk, const crypto::public_key &PK);
bool decrypt_pvk(const std::string &encrypted_data, const crypto::secret_key &SK, crypto::secret_key &pvk);
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false);
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false);
+15
View File
@@ -167,6 +167,15 @@ namespace cryptonote
return false;
}
// Reject ALL TXs except miner + protocol for v5
if (version == HF_VERSION_SHUTDOWN_USER_TXS) {
if (tx.type != cryptonote::transaction_type::MINER && tx.type != cryptonote::transaction_type::PROTOCOL) {
LOG_PRINT_L1("User TXs are not permitted for v" + std::to_string(HF_VERSION_SHUTDOWN_USER_TXS));
tvc.m_verifivation_failed = true;
return false;
}
}
if(!check_inputs_types_supported(tx))
{
tvc.m_verifivation_failed = true;
@@ -1653,6 +1662,12 @@ namespace cryptonote
continue;
}
// SRCG: skip all user TXs for HF 5 - when the node restarts, it'll discard them fully in `tx_memory_pool::validate()`
if (version == HF_VERSION_SHUTDOWN_USER_TXS) {
LOG_PRINT_L2(" User TXs forbidden by consensus for HF 5 - skipping");
continue;
}
LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method());
if (!meta.matches(relay_category::legacy) && !(m_mine_stem_txes && meta.get_relay_method() == relay_method::stem))
@@ -130,7 +130,7 @@ bool ver_rct_non_semantics_simple_cached
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions
// holds true in the future, enable the verification hash by modifying the `untested_tx`
// condition below.
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeFullProofs;
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeSalviumOne;
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
// Don't cache older (or newer) rctSig types
+2 -1
View File
@@ -53,6 +53,7 @@ namespace cryptonote
BURN = 5,
STAKE = 6,
RETURN = 7,
MAX = 7
AUDIT = 8,
MAX = 8
};
}
+21
View File
@@ -43,6 +43,15 @@ const hardfork_t mainnet_hard_forks[] = {
// version 4 starts from block 121100, which is on or around the 20th of December, 2024. Fork time finalised on 2024-12-19. No fork voting occurs for the v4 fork.
{ 4, 121800, 0, 1734607000 },
// version 5 starts from block 136100, which is on or around the 9th of January, 2025. Fork time finalised on 2025-01-08. No fork voting occurs for the v5 fork.
{ 5, 136100, 0, 1736265945 },
// 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);
@@ -56,6 +65,18 @@ const hardfork_t testnet_hard_forks[] = {
// version 3 starts from block 500
{ 3, 500, 0, 1729518000 },
// version 4 (full proofs) starts from block 600
{ 4, 600, 0, 1734607000 },
// version 5 (TX shutdown) starts from block 800
{ 5, 800, 0, 1734607005 },
// version 6 (audit 1) starts from block 815
{ 6, 815, 0, 1734608000 },
// version 7 (audit 1 pause) starts from block 900
{ 7, 900, 0, 1739264400 },
};
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);
+3 -2
View File
@@ -92,7 +92,8 @@ namespace multisig
const std::vector<crypto::key_image> &pkis,
crypto::key_image &ki,
const bool use_origin_data,
const cryptonote::origin_data& origin_tx_data)
const cryptonote::origin_data& origin_tx_data,
rct::salvium_input_data_t& sid)
{
// create a multisig partial key image
// KI_partial = ([view key component] + [subaddress component] + [multisig privkeys]) * Hp(output one-time address)
@@ -100,7 +101,7 @@ namespace multisig
// - later, we add in the components held by other participants
cryptonote::keypair in_ephemeral;
if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki, keys.get_device(), use_origin_data, origin_tx_data))
if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki, keys.get_device(), use_origin_data, origin_tx_data, sid))
return false;
std::unordered_set<crypto::key_image> used;
+2 -1
View File
@@ -67,6 +67,7 @@ namespace multisig
const std::vector<crypto::key_image> &pkis,
crypto::key_image &ki,
const bool use_origin_data,
const cryptonote::origin_data& origin_tx_data
const cryptonote::origin_data& origin_tx_data,
rct::salvium_input_data_t& sid
);
} //namespace multisig
+14 -12
View File
@@ -175,6 +175,7 @@ static bool compute_keys_for_sources(
cryptonote::origin_data origin_tx_data;
*/
bool use_origin_data = (src.origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
rct::salvium_input_data_t sid;
if (not cryptonote::generate_key_image_helper(
account_keys,
@@ -187,7 +188,8 @@ static bool compute_keys_for_sources(
tmp_key_image,
hwdev,
use_origin_data,
src.origin_tx_data
src.origin_tx_data,
sid
)) {
return false;
}
@@ -932,19 +934,19 @@ static bool set_tx_rct_signatures(
}
sc_sub(difference.bytes, sumpouts.bytes, sumouts.bytes);
rct::genC(rv.p_r, difference, 0);
if (rv.type == rct::RCTTypeFullProofs) {
rv.pr_proof = rct::PRProof_Gen(difference);
if (rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne) {
rv.salvium_data.pr_proof = rct::PRProof_Gen(difference);
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(rct::PRProof_Ver(rv.p_r, rv.pr_proof), "PRProof_Ver() failed on recently created proof");
CHECK_AND_ASSERT_THROW_MES(rct::PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), "PRProof_Ver() failed on recently created proof");
#endif
}
/*
// Check if spend authority proof is needed (only for TRANSFER TXs)
if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) {
rv.sa_proof = rct::SAProof_Gen(output_public_keys[change_index], x_change, hs_yF);
if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER && rv.type >= rct::RCTTypeFullProofs) {
rv.salvium_data.sa_proof = rct::SAProof_Gen(output_public_keys[change_index], x_change, hs_yF);
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(rct::SAProof_Ver(rv.sa_proof, output_public_keys[change_index], hs_yF), "SAProof_Ver() failed on recently created proof");
CHECK_AND_ASSERT_THROW_MES(rct::SAProof_Ver(rv.salvium_data.sa_proof, output_public_keys[change_index], hs_yF), "SAProof_Ver() failed on recently created proof");
#endif
}
*/
@@ -952,15 +954,15 @@ static bool set_tx_rct_signatures(
// check balance if reconstructing the tx
else {
rv.p.pseudoOuts = unsigned_tx.rct_signatures.p.pseudoOuts;
if (rv.type == rct::RCTTypeFullProofs) {
if (!rct::PRProof_Ver(unsigned_tx.rct_signatures.p_r, unsigned_tx.rct_signatures.pr_proof))
if (rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne) {
if (!rct::PRProof_Ver(unsigned_tx.rct_signatures.p_r, unsigned_tx.rct_signatures.salvium_data.pr_proof))
return false;
rv.p_r = unsigned_tx.rct_signatures.p_r;
rv.pr_proof = unsigned_tx.rct_signatures.pr_proof;
rv.salvium_data.pr_proof = unsigned_tx.rct_signatures.salvium_data.pr_proof;
/*
if (!rct::SAProof_Ver(unsigned_tx.rct_signatures.sa_proof, output_public_keys[change_index], hs_yF))
if (!rct::SAProof_Ver(unsigned_tx.rct_signatures.salvium_data.sa_proof, output_public_keys[change_index], hs_yF))
return false;
rv.sa_proof = unsigned_tx.rct_signatures.sa_proof; // should verify this during reconstruction
rv.salvium_data.sa_proof = unsigned_tx.rct_signatures.salvium_data.sa_proof; // should verify this during reconstruction
*/
} else {
rv.p_r = unsigned_tx.rct_signatures.p_r;
+7 -7
View File
@@ -31,7 +31,7 @@
namespace oracle {
const std::vector<std::string> ASSET_TYPES = {"SAL", "VSD", "BURN"};
const std::vector<std::string> ASSET_TYPES = {"SAL", "SAL1", "BURN"};
class asset_type_counts
{
@@ -40,12 +40,12 @@ namespace oracle {
// Fields
uint64_t SAL;
uint64_t VSD;
uint64_t SAL1;
uint64_t BURN;
asset_type_counts() noexcept
: SAL(0)
, VSD(0)
, SAL1(0)
, BURN(0)
{
}
@@ -54,8 +54,8 @@ namespace oracle {
{
if (asset_type == "SAL") {
return SAL;
} else if (asset_type == "VSD") {
return VSD;
} else if (asset_type == "SAL1") {
return SAL1;
} else if (asset_type == "BURN") {
return BURN;
}
@@ -67,8 +67,8 @@ namespace oracle {
{
if (asset_type == "SAL") {
SAL += val;
} else if (asset_type == "VSD") {
VSD += val;
} else if (asset_type == "SAL1") {
SAL1 += val;
} else if (asset_type == "BURN") {
BURN += val;
}
+79 -21
View File
@@ -1,5 +1,5 @@
// Copyright (c) 2016, Monero Research Labs
// Portions Copyright (c) 2023-2024, Salvium (author: SRCG)
// Portions Copyright (c) 2023-2025, Salvium (author: SRCG)
//
// Author: Shen Noether <shen.noether@gmx.com>
//
@@ -677,7 +677,7 @@ namespace rct {
kv.push_back(p.t);
}
}
else if (rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs)
else if (rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne)
{
kv.reserve((6*2+6) * rv.p.bulletproofs_plus.size());
for (const auto &p: rv.p.bulletproofs_plus)
@@ -1161,7 +1161,7 @@ namespace rct {
//mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(amounts[i]);
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne);
}
//set txn fee
@@ -1206,6 +1206,7 @@ namespace rct {
ctkeyV &outSk,
const RCTConfig &rct_config,
hw::device &hwdev,
const rct::salvium_data_t &salvium_data,
const key &x_change,
const size_t change_index,
const key &key_yF
@@ -1235,6 +1236,9 @@ namespace rct {
case 5:
rv.type = RCTTypeFullProofs;
break;
case 6:
rv.type = RCTTypeSalviumOne;
break;
default:
ASSERT_MES_AND_THROW("Unsupported BP version: " << rct_config.bp_version);
}
@@ -1289,6 +1293,7 @@ namespace rct {
rv.p.bulletproofs_plus.push_back(proveRangeBulletproofPlus(C, masks, outamounts, keys, hwdev));
else
rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts, keys, hwdev));
#ifdef DBG
if (plus)
CHECK_AND_ASSERT_THROW_MES(verBulletproofPlus(rv.p.bulletproofs_plus.back()), "verBulletproofPlus failed on newly created proof");
@@ -1351,7 +1356,7 @@ namespace rct {
//mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(outamounts[i]);
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne);
}
//set txn fee
@@ -1367,28 +1372,43 @@ namespace rct {
rv.p.MGs.resize(inamounts.size());
key sumpouts = zero(); //sum pseudoOut masks
keyV a(inamounts.size());
bool audit = (tx_type == cryptonote::transaction_type::AUDIT && rv.type == RCTTypeSalviumOne && salvium_data.salvium_data_type == rct::SalviumAudit);
for (i = 0 ; i < inamounts.size(); i++) {
if (audit)
a[i] = rct::zero();
else
skGen(a[i]);
sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes);
genC(pseudoOuts[i], a[i], inamounts[i]);
sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes);
genC(pseudoOuts[i], a[i], inamounts[i]);
}
key difference;
sc_sub(difference.bytes, sumpouts.bytes, sumout.bytes);
genC(rv.p_r, difference, 0);
DP(rv.p_r);
if (rv.type == RCTTypeFullProofs) {
rv.pr_proof = PRProof_Gen(difference);
if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne) {
rv.salvium_data.pr_proof = PRProof_Gen(difference);
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.p_r, rv.pr_proof), "PRProof_Ver() failed on recently created proof");
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), "PRProof_Ver() failed on recently created proof");
#endif
rv.salvium_data.salvium_data_type = salvium_data.salvium_data_type;
if (audit) {
// SRCG: populate the audit proof here
rv.salvium_data.input_verification_data = salvium_data.input_verification_data;
rv.salvium_data.spend_pubkey = salvium_data.spend_pubkey;
rv.salvium_data.enc_view_privkey_str = salvium_data.enc_view_privkey_str;
rv.salvium_data.cz_proof = PRProof_Gen(outSk[0].mask);
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.outPk[0].mask, rv.salvium_data.cz_proof), "PRProof_Ver() failed on recently created change proof");
#endif
}
}
/*
// Check if spend authority proof is needed (only for TRANSFER TXs)
if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) {
rv.sa_proof = SAProof_Gen(destinations[change_index], x_change, key_yF);
if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeSalviumOne) {
rv.salvium_data.sa_proof = SAProof_Gen(destinations[change_index], x_change, key_yF);
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.sa_proof, destinations[change_index], key_yF), "SAProof_Ver() failed on recently created proof");
CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.salvium_data.sa_proof, destinations[change_index], key_yF), "SAProof_Ver() failed on recently created proof");
#endif
}
*/
@@ -1428,6 +1448,7 @@ namespace rct {
unsigned int mixin,
const RCTConfig &rct_config,
hw::device &hwdev,
const rct::salvium_data_t &salvium_data,
const key &x_change,
const size_t change_index,
const key &key_yF
@@ -1441,7 +1462,7 @@ namespace rct {
mixRing[i].resize(mixin+1);
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
}
return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev, x_change, change_index, key_yF);
return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev, salvium_data, x_change, change_index, key_yF);
}
//RingCT protocol
@@ -1530,10 +1551,11 @@ namespace rct {
std::vector<const BulletproofPlus*> bpp_proofs;
size_t max_non_bp_proofs = 0, offset = 0;
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne,
false, "verRctSemanticsSimple called on non simple rctSig");
if (rv.type == RCTTypeFullProofs)
CHECK_AND_ASSERT_MES(PRProof_Ver(rv.p_r, rv.pr_proof), false, "Invalid p_r commitment to difference");
if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne)
CHECK_AND_ASSERT_MES(PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), false, "Invalid p_r commitment to difference");
const bool bulletproof = is_rct_bulletproof(rv.type);
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type);
if (bulletproof || bulletproof_plus)
@@ -1656,7 +1678,7 @@ namespace rct {
{
PERF_TIMER(verRctNonSemanticsSimple);
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne,
false, "verRctNonSemanticsSimple called on non simple rctSig");
const bool bulletproof = is_rct_bulletproof(rv.type);
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type);
@@ -1696,6 +1718,42 @@ namespace rct {
}
}
bool audit = (rv.type == RCTTypeSalviumOne && rv.salvium_data.salvium_data_type == rct::SalviumAudit);
if (audit) {
// Validate the Salvium audit data
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.outPk[0].mask, rv.salvium_data.cz_proof), "PRProof_Ver() failed on change proof");
CHECK_AND_ASSERT_THROW_MES(pseudoOuts.size() == rv.salvium_data.input_verification_data.size(), "incorrect number of input verification datasets");
CHECK_AND_ASSERT_THROW_MES(rv.salvium_data.spend_pubkey != crypto::null_pkey, "Invalid spend pubkey provided in audit data");
CHECK_AND_ASSERT_THROW_MES(rv.salvium_data.enc_view_privkey_str != "", "Invalid encrypted viewkey provided in audit data");
for (size_t i=0; i < rv.salvium_data.input_verification_data.size(); ++i) {
// Check for STAKE origin
crypto::public_key Ks = rv.salvium_data.spend_pubkey;
if (rv.salvium_data.input_verification_data[i].origin_tx_type != cryptonote::transaction_type::UNSET) {
// Verify the origin data provided
CHECK_AND_ASSERT_THROW_MES(crypto::derive_public_key(rv.salvium_data.input_verification_data[i].aR_stake, rv.salvium_data.input_verification_data[i].i_stake, rv.salvium_data.spend_pubkey, Ks),
"Failed to derive ephemeral public key from audit data");
}
// Recalculate the value of Ks from the Ko value
crypto::public_key ephemeral_pub = crypto::null_pkey;
CHECK_AND_ASSERT_THROW_MES(crypto::derive_public_key(rv.salvium_data.input_verification_data[i].aR, rv.salvium_data.input_verification_data[i].i, Ks, ephemeral_pub),
"Failed to derive ephemeral public key from audit data");
// Now find this in the list of mixring entries
bool found = false;
for (size_t n=0; n<rv.mixRing[i].size(); ++n) {
if (ephemeral_pub == rct::rct2pk(rv.mixRing[i][n].dest)) {
found = true;
break;
}
}
CHECK_AND_ASSERT_THROW_MES(found, "Failed to match ephemeral public key provided in audit data");
// Verify the individual input commitment
CHECK_AND_ASSERT_THROW_MES(equalKeys(scalarmultH(d2h(rv.salvium_data.input_verification_data[i].amount)), pseudoOuts[i]), "Invalid pseudoOuts entry");
}
}
return true;
}
// we can get deep throws from ge_frombytes_vartime if input isn't valid
@@ -1728,7 +1786,7 @@ namespace rct {
//mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i];
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne);
mask = ecdh_info.mask;
key amount = ecdh_info.amount;
key C = rv.outPk[i].mask;
@@ -1752,14 +1810,14 @@ namespace rct {
}
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) {
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne,
false, "decodeRct called on non simple rctSig");
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
//mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i];
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne);
mask = ecdh_info.mask;
key amount = ecdh_info.amount;
key C = rv.outPk[i].mask;
+2
View File
@@ -149,6 +149,7 @@ namespace rct {
unsigned int mixin,
const RCTConfig &rct_config,
hw::device &hwdev,
const rct::salvium_data_t &salvium_data,
const key &x_change = rct::zero(),
const size_t change_index = 0,
const key &key_yF = rct::zero()
@@ -169,6 +170,7 @@ namespace rct {
ctkeyV &outSk,
const RCTConfig &rct_config,
hw::device &hwdev,
const rct::salvium_data_t &salvium_data,
const key &x_change = rct::zero(),
const size_t change_index = 0,
const key &key_yF = rct::zero()
+3
View File
@@ -198,6 +198,7 @@ namespace rct {
case RCTTypeCLSAG:
case RCTTypeBulletproofPlus:
case RCTTypeFullProofs:
case RCTTypeSalviumOne:
return true;
default:
return false;
@@ -223,6 +224,7 @@ namespace rct {
{
case RCTTypeBulletproofPlus:
case RCTTypeFullProofs:
case RCTTypeSalviumOne:
return true;
default:
return false;
@@ -248,6 +250,7 @@ namespace rct {
case RCTTypeCLSAG:
case RCTTypeBulletproofPlus:
case RCTTypeFullProofs:
case RCTTypeSalviumOne:
return true;
default:
return false;
+78 -18
View File
@@ -55,6 +55,7 @@ extern "C" {
#include "serialization/binary_archive.h"
#include "serialization/json_archive.h"
#include "cryptonote_protocol/enums.h"
//Define this flag when debugging to get additional info on the console
#ifdef DBG
@@ -316,7 +317,8 @@ namespace rct {
RCTTypeBulletproof2 = 4,
RCTTypeCLSAG = 5,
RCTTypeBulletproofPlus = 6,
RCTTypeFullProofs = 7
RCTTypeFullProofs = 7,
RCTTypeSalviumOne = 8
};
enum RangeProofType { RangeProofBorromean, RangeProofBulletproof, RangeProofMultiOutputBulletproof, RangeProofPaddedBulletproof };
struct RCTConfig {
@@ -329,6 +331,50 @@ namespace rct {
VARINT_FIELD(bp_version)
END_SERIALIZE()
};
enum SalviumDataType { SalviumNormal=0, SalviumAudit=1 };
struct salvium_input_data_t {
crypto::key_derivation aR;
xmr_amount amount;
size_t i;
uint8_t origin_tx_type;
crypto::key_derivation aR_stake;
size_t i_stake;
BEGIN_SERIALIZE_OBJECT()
FIELD(aR)
VARINT_FIELD(amount)
VARINT_FIELD(i)
VARINT_FIELD(origin_tx_type)
if (origin_tx_type != cryptonote::transaction_type::UNSET) {
FIELD(aR_stake)
FIELD(i_stake)
}
END_SERIALIZE()
};
struct salvium_data_t {
uint8_t salvium_data_type; // flag to indicate what type of data is valid
zk_proof pr_proof; // p_r
zk_proof sa_proof; // spend authority proof
zk_proof cz_proof; // change is zero proof
std::vector<salvium_input_data_t> input_verification_data;
crypto::public_key spend_pubkey;
std::string enc_view_privkey_str;
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(salvium_data_type)
FIELD(pr_proof)
FIELD(sa_proof)
if (salvium_data_type == SalviumAudit)
{
FIELD(cz_proof)
FIELD(input_verification_data)
FIELD(spend_pubkey)
FIELD(enc_view_privkey_str)
}
END_SERIALIZE()
};
struct rctSigBase {
uint8_t type;
key message;
@@ -339,11 +385,10 @@ namespace rct {
ctkeyV outPk;
xmr_amount txnFee; // contains b
key p_r;
zk_proof pr_proof; // p_r
zk_proof sa_proof; // spend authority proof
salvium_data_t salvium_data;
rctSigBase() :
type(RCTTypeNull), message{}, mixRing{}, pseudoOuts{}, ecdhInfo{}, outPk{}, txnFee(0), p_r{}, pr_proof{}, sa_proof{}
type(RCTTypeNull), message{}, mixRing{}, pseudoOuts{}, ecdhInfo{}, outPk{}, txnFee(0), p_r{}, salvium_data{}
{}
template<bool W, template <bool> class Archive>
@@ -352,7 +397,7 @@ namespace rct {
FIELD(type)
if (type == RCTTypeNull)
return ar.good();
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs)
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs && type != RCTTypeSalviumOne)
return false;
VARINT_FIELD(txnFee)
// inputs/outputs not saved, only here for serialization help
@@ -381,7 +426,7 @@ namespace rct {
return false;
for (size_t i = 0; i < outputs; ++i)
{
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs)
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne)
{
// Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
// first 8 bytes of ecdhInfo[i].amount
@@ -418,10 +463,14 @@ namespace rct {
}
ar.end_array();
FIELD(p_r)
if (type == RCTTypeFullProofs)
if (type == RCTTypeSalviumOne)
{
FIELD(pr_proof)
FIELD(sa_proof)
FIELD(salvium_data)
}
else if (type == RCTTypeFullProofs)
{
FIELD(salvium_data.pr_proof)
FIELD(salvium_data.sa_proof)
}
return ar.good();
}
@@ -435,9 +484,14 @@ namespace rct {
FIELD(outPk)
VARINT_FIELD(txnFee)
FIELD(p_r)
if (type == RCTTypeFullProofs) {
FIELD(pr_proof)
FIELD(sa_proof)
if (type == RCTTypeSalviumOne)
{
FIELD(salvium_data)
}
else if (type == RCTTypeFullProofs)
{
FIELD(salvium_data.pr_proof)
FIELD(salvium_data.sa_proof)
}
END_SERIALIZE()
};
@@ -461,9 +515,9 @@ namespace rct {
return false;
if (type == RCTTypeNull)
return ar.good();
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs)
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs && type != RCTTypeSalviumOne)
return false;
if (type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs)
if (type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne)
{
uint32_t nbp = bulletproofs_plus.size();
VARINT_FIELD(nbp)
@@ -520,7 +574,7 @@ namespace rct {
ar.end_array();
}
if (type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs)
if (type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne)
{
ar.tag("CLSAGs");
ar.begin_array();
@@ -611,7 +665,7 @@ namespace rct {
}
ar.end_array();
}
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs)
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne)
{
ar.tag("pseudoOuts");
ar.begin_array();
@@ -643,12 +697,12 @@ namespace rct {
keyV& get_pseudo_outs()
{
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs ? p.pseudoOuts : pseudoOuts;
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne ? p.pseudoOuts : pseudoOuts;
}
keyV const& get_pseudo_outs() const
{
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs ? p.pseudoOuts : pseudoOuts;
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne ? p.pseudoOuts : pseudoOuts;
}
BEGIN_SERIALIZE_OBJECT()
@@ -820,6 +874,8 @@ VARIANT_TAG(debug_archive, rct::multisig_out, "rct::multisig_out");
VARIANT_TAG(debug_archive, rct::clsag, "rct::clsag");
VARIANT_TAG(debug_archive, rct::BulletproofPlus, "rct::bulletproof_plus");
VARIANT_TAG(debug_archive, rct::zk_proof, "rct::zk_proof");
VARIANT_TAG(debug_archive, rct::salvium_input_data_t, "rct::salvium_input_data");
VARIANT_TAG(debug_archive, rct::salvium_data_t, "rct::salvium_data");
VARIANT_TAG(binary_archive, rct::key, 0x90);
VARIANT_TAG(binary_archive, rct::key64, 0x91);
@@ -839,6 +895,8 @@ VARIANT_TAG(binary_archive, rct::multisig_out, 0x9e);
VARIANT_TAG(binary_archive, rct::clsag, 0x9f);
VARIANT_TAG(binary_archive, rct::BulletproofPlus, 0xa0);
VARIANT_TAG(binary_archive, rct::zk_proof, 0xa1);
VARIANT_TAG(binary_archive, rct::salvium_input_data_t, 0xa2);
VARIANT_TAG(binary_archive, rct::salvium_data_t, 0xa3);
VARIANT_TAG(json_archive, rct::key, "rct_key");
VARIANT_TAG(json_archive, rct::key64, "rct_key64");
@@ -858,5 +916,7 @@ VARIANT_TAG(json_archive, rct::multisig_out, "rct_multisig_out");
VARIANT_TAG(json_archive, rct::clsag, "rct_clsag");
VARIANT_TAG(json_archive, rct::BulletproofPlus, "rct_bulletproof_plus");
VARIANT_TAG(json_archive, rct::zk_proof, "rct_zk_proof");
VARIANT_TAG(json_archive, rct::salvium_input_data_t, "rct_salvium_input_data");
VARIANT_TAG(json_archive, rct::salvium_data_t, "rct_salvium_data");
#endif /* RCTTYPES_H */
+77 -6
View File
@@ -1173,9 +1173,11 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig&
INSERT_INTO_JSON_OBJECT(dest, commitments, transform(sig.outPk, just_mask));
INSERT_INTO_JSON_OBJECT(dest, fee, sig.txnFee);
INSERT_INTO_JSON_OBJECT(dest, p_r, sig.p_r);
if (sig.type == rct::RCTTypeFullProofs) {
INSERT_INTO_JSON_OBJECT(dest, pr_proof, sig.pr_proof);
INSERT_INTO_JSON_OBJECT(dest, sa_proof, sig.sa_proof);
if (sig.type == rct::RCTTypeSalviumOne) {
INSERT_INTO_JSON_OBJECT(dest, salvium_data, sig.salvium_data);
} else if (sig.type == rct::RCTTypeFullProofs) {
INSERT_INTO_JSON_OBJECT(dest, pr_proof, sig.salvium_data.pr_proof);
INSERT_INTO_JSON_OBJECT(dest, sa_proof, sig.salvium_data.sa_proof);
}
}
@@ -1214,9 +1216,11 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig)
GET_FROM_JSON_OBJECT(val, sig.outPk, commitments);
GET_FROM_JSON_OBJECT(val, sig.txnFee, fee);
GET_FROM_JSON_OBJECT(val, sig.p_r, p_r);
if (sig.type == rct::RCTTypeFullProofs) {
GET_FROM_JSON_OBJECT(val, sig.pr_proof, pr_proof);
GET_FROM_JSON_OBJECT(val, sig.sa_proof, sa_proof);
if (sig.type == rct::RCTTypeSalviumOne) {
GET_FROM_JSON_OBJECT(val, sig.salvium_data, salvium_data);
} else if (sig.type == rct::RCTTypeFullProofs) {
GET_FROM_JSON_OBJECT(val, sig.salvium_data.pr_proof, pr_proof);
GET_FROM_JSON_OBJECT(val, sig.salvium_data.sa_proof, sa_proof);
}
}
@@ -1496,6 +1500,73 @@ void fromJsonValue(const rapidjson::Value& val, rct::zk_proof& proof)
GET_FROM_JSON_OBJECT(val, proof.z2, z2);
}
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::salvium_input_data_t& salvium_input_data)
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, aR, salvium_input_data.aR);
INSERT_INTO_JSON_OBJECT(dest, i, salvium_input_data.i);
INSERT_INTO_JSON_OBJECT(dest, amount, salvium_input_data.amount);
INSERT_INTO_JSON_OBJECT(dest, origin_tx_type, salvium_input_data.origin_tx_type);
if (salvium_input_data.origin_tx_type != cryptonote::transaction_type::UNSET) {
INSERT_INTO_JSON_OBJECT(dest, aR_stake, salvium_input_data.aR_stake);
INSERT_INTO_JSON_OBJECT(dest, i_stake, salvium_input_data.i_stake);
}
dest.EndObject();
}
void fromJsonValue(const rapidjson::Value& val, rct::salvium_input_data_t& salvium_input_data)
{
if (!val.IsObject())
{
throw WRONG_TYPE("salvium_input_data_t (rct::salvium_input_data_t)");
}
GET_FROM_JSON_OBJECT(val, salvium_input_data.aR, aR);
GET_FROM_JSON_OBJECT(val, salvium_input_data.i, i);
GET_FROM_JSON_OBJECT(val, salvium_input_data.amount, amount);
GET_FROM_JSON_OBJECT(val, salvium_input_data.origin_tx_type, origin_tx_type);
if (salvium_input_data.origin_tx_type != cryptonote::transaction_type::UNSET) {
GET_FROM_JSON_OBJECT(val, salvium_input_data.aR_stake, aR_stake);
GET_FROM_JSON_OBJECT(val, salvium_input_data.i_stake, i_stake);
}
}
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::salvium_data_t& salvium_data)
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, salvium_data_type, salvium_data.salvium_data_type);
INSERT_INTO_JSON_OBJECT(dest, pr_proof, salvium_data.pr_proof);
INSERT_INTO_JSON_OBJECT(dest, sa_proof, salvium_data.sa_proof);
if (salvium_data.salvium_data_type == rct::SalviumAudit) {
INSERT_INTO_JSON_OBJECT(dest, cz_proof, salvium_data.cz_proof);
INSERT_INTO_JSON_OBJECT(dest, input_verification_data, salvium_data.input_verification_data);
INSERT_INTO_JSON_OBJECT(dest, spend_pubkey, salvium_data.spend_pubkey);
INSERT_INTO_JSON_OBJECT(dest, enc_view_privkey_str, salvium_data.enc_view_privkey_str);
}
dest.EndObject();
}
void fromJsonValue(const rapidjson::Value& val, rct::salvium_data_t& salvium_data)
{
if (!val.IsObject())
{
throw WRONG_TYPE("salvium_data_t (rct::salvium_data_t)");
}
GET_FROM_JSON_OBJECT(val, salvium_data.salvium_data_type, salvium_data_type);
GET_FROM_JSON_OBJECT(val, salvium_data.pr_proof, pr_proof);
GET_FROM_JSON_OBJECT(val, salvium_data.sa_proof, sa_proof);
if (salvium_data.salvium_data_type == rct::SalviumAudit) {
GET_FROM_JSON_OBJECT(val, salvium_data.cz_proof, cz_proof);
GET_FROM_JSON_OBJECT(val, salvium_data.input_verification_data, input_verification_data);
GET_FROM_JSON_OBJECT(val, salvium_data.spend_pubkey, spend_pubkey);
GET_FROM_JSON_OBJECT(val, salvium_data.enc_view_privkey_str, enc_view_privkey_str);
}
}
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::DaemonInfo& info)
{
dest.StartObject();
+6
View File
@@ -310,6 +310,12 @@ void fromJsonValue(const rapidjson::Value& val, rct::clsag& sig);
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::zk_proof& p);
void fromJsonValue(const rapidjson::Value& val, rct::zk_proof& p);
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::salvium_input_data_t& salvium_input_data);
void fromJsonValue(const rapidjson::Value& val, rct::salvium_input_data_t& salvium_input_data);
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::salvium_data_t& salvium_data);
void fromJsonValue(const rapidjson::Value& val, rct::salvium_data_t& salvium_data);
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::DaemonInfo& info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info);
+181 -59
View File
@@ -163,7 +163,8 @@ enum TransferType {
Convert,
Burn,
Stake,
Return
Return,
Audit
};
static std::string get_human_readable_timespan(std::chrono::seconds seconds);
@@ -213,6 +214,7 @@ namespace
const char* USAGE_BURN("burn <amount> <asset_type>");
const char* USAGE_CONVERT("convert <source_amount> <source_asset> <dest_asset> [<slippage_limit>]");
const char* USAGE_STAKE("stake <amount>");
const char* USAGE_AUDIT("audit [index=<N1>[,<N2>,...] | index=all]");
const char* USAGE_PRICE_INFO("price_info");
const char* USAGE_SUPPLY_INFO("supply_info");
const char* USAGE_YIELD_INFO("yield_info");
@@ -3219,6 +3221,7 @@ bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<st
message_writer() << tr("\"burn <amount> <asset_type>\" - destroy coins forever.");
message_writer() << tr("\"convert <amount> <source_asset> <dest_asset> [<slippage_limit>]\" - convert between coin types.");
message_writer() << tr("\"stake <amount>\" - stake SAL for 30 days to earn yield.");
message_writer() << tr("\"audit\" - audit your wallet main address (or subaddress(es) if specified).");
message_writer() << tr("\"price_info\" - Display current pricing information for supported assets.");
message_writer() << tr("\"supply_info\" - Display circulating supply information.");
message_writer() << tr("\"yield_info\" - Display current stats on Salvium staking / yield.");
@@ -3412,14 +3415,18 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::stake, this, _1),
tr(USAGE_STAKE),
tr("Locks <amount> of SAL as stake in order to earn yield"));
m_cmd_binder.set_handler("audit",
boost::bind(&simple_wallet::audit, this, _1),
tr(USAGE_AUDIT),
tr("Sends your wallet balance (or a single address or subaddress(es)) to audit (only available during AUDIT hard forks)"));
m_cmd_binder.set_handler("price_info",
boost::bind(&simple_wallet::price_info, this, _1),
tr(USAGE_PRICE_INFO),
tr("Displays the current exchange rate information for SAL <--> VSD conversions"));
tr("Displays the current exchange rate information for SAL <--> SAL1 conversions"));
m_cmd_binder.set_handler("supply_info",
boost::bind(&simple_wallet::supply_info, this, _1),
tr(USAGE_SUPPLY_INFO),
tr("Displays the current circulating supply information for SAL and VSD currencies"));
tr("Displays the current circulating supply information for SAL and SAL1 currencies"));
m_cmd_binder.set_handler("yield_info",
boost::bind(&simple_wallet::yield_info, this, _1),
tr(USAGE_YIELD_INFO),
@@ -5831,16 +5838,22 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
message_writer(console_color_red) << "\r" << "*** CONVERT ***";
} else if (td_origin.m_tx.type == cryptonote::transaction_type::STAKE) {
message_writer(console_color_magenta, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("stake returned ") << print_money(td_origin.m_tx.amount_burnt) << " " << td_origin.asset_type << " from height " << td_origin.m_block_height << ", " <<
tr("idx ") << subaddr_index;
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("stake returned ") << print_money(td_origin.m_tx.amount_burnt) << " " << td_origin.asset_type << " from height " << td_origin.m_block_height << ", " <<
tr("idx ") << subaddr_index;
message_writer(console_color_magenta, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("yield earned ") << print_money(amount - td_origin.m_tx.amount_burnt) << " " << asset_type << ", " <<
tr("idx ") << subaddr_index;
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("yield earned ") << print_money(amount - td_origin.m_tx.amount_burnt) << " " << asset_type << ", " <<
tr("idx ") << subaddr_index;
} else if (td_origin.m_tx.type == cryptonote::transaction_type::AUDIT) {
message_writer(console_color_red) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("audit returned ") << print_money(td_origin.m_tx.amount_burnt) << " " << asset_type << " from height " << td_origin.m_block_height << ", " <<
tr("idx ") << subaddr_index;
} else {
}
@@ -5848,19 +5861,28 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
if (tx.type == cryptonote::transaction_type::BURN) {
message_writer(console_color_yellow, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("burnt ") << print_money(tx.amount_burnt) << " " << asset_type;
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("burnt ") << print_money(tx.amount_burnt) << " " << asset_type << ", " <<
tr("idx ") << subaddr_index;
} else if (tx.type == cryptonote::transaction_type::CONVERT) {
message_writer(console_color_blue, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("converting ") << print_money(tx.amount_burnt) << " " << asset_type;
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("converting ") << print_money(tx.amount_burnt) << " " << asset_type << ", " <<
tr("idx ") << subaddr_index;
} else if (tx.type == cryptonote::transaction_type::STAKE) {
message_writer(console_color_cyan, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("staked ") << print_money(tx.amount_burnt) << " " << asset_type;
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("staked ") << print_money(tx.amount_burnt) << " " << asset_type << ", " <<
tr("idx ") << subaddr_index;
} else if (tx.type == cryptonote::transaction_type::AUDIT) {
message_writer(console_color_yellow, false) << "\r" <<
tr("Height ") << height << ", " <<
tr("txid ") << txid << ", " <<
tr("audited ") << print_money(tx.amount_burnt) << " " << asset_type << ", " <<
tr("idx ") << subaddr_index;
}
message_writer(asset_type == "SAL" ? console_color_green : console_color_blue, false) << "\r" <<
@@ -6719,14 +6741,20 @@ bool simple_wallet::transfer_main(
// "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"
if (!try_connect_to_daemon())
return false;
std::vector<std::string> local_args = args_;
std::set<uint32_t> subaddr_indices;
if (local_args.size() > 0 && local_args[0].substr(0, 6) == "index=")
{
if (!parse_subaddress_indices(local_args[0], subaddr_indices))
return false;
if (local_args[0] == "index=all")
{
for (uint32_t i = 0; i < m_wallet->get_num_subaddresses(m_current_subaddress_account); ++i)
subaddr_indices.insert(i);
}
else if (!parse_subaddress_indices(local_args[0], subaddr_indices))
{
return true;
}
local_args.erase(local_args.begin());
}
@@ -6766,7 +6794,7 @@ bool simple_wallet::transfer_main(
return false;
}
const size_t min_args = (transfer_type == TransferLocked) ? 2 : 1;
const size_t min_args = (transfer_type == Audit) ? 0 : (transfer_type == TransferLocked) ? 2 : 1;
if(local_args.size() < min_args)
{
fail_msg_writer() << tr("wrong number of arguments");
@@ -6944,30 +6972,58 @@ bool simple_wallet::transfer_main(
std::vector<tools::wallet2::pending_tx> ptx_vector;
uint64_t unlock_block = 0;
std::string err;
switch (transfer_type)
{
if (transfer_type == Audit) {
// 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;
try {
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());
} 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 {
switch (transfer_type) {
case Burn:
unlock_block = 0;
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::BURN, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
break;
break;
case Convert:
unlock_block = CONVERT_LOCK_PERIOD;
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::CONVERT, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
break;
break;
case Stake:
unlock_block = get_config(m_wallet->nettype()).STAKE_LOCK_PERIOD;
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::STAKE, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
break;
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::STAKE, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
break;
case TransferLocked:
unlock_block = locked_blocks;
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
break;
break;
default:
LOG_ERROR("Unknown transfer method, using default");
/* FALLTHRU */
case Transfer:
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
break;
break;
}
}
if (ptx_vector.empty())
@@ -7069,6 +7125,8 @@ bool simple_wallet::transfer_main(
prompt << boost::format(tr("Converting %s %s to %s. ")) % print_money(total_sent) % source_asset % dest_asset;
} else if (transfer_type == Stake) {
prompt << boost::format(tr("Staking %s %s for yield accrual. ")) % print_money(total_sent) % source_asset;
} else if (transfer_type == Audit) {
prompt << boost::format(tr("Auditing %s %s. ")) % print_money(total_sent) % source_asset;
} else {
prompt << boost::format(tr("Sending %s %s. ")) % print_money(total_sent) % source_asset;
}
@@ -7227,9 +7285,13 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
// Get the source asset type
std::string source_asset = "SAL";
if (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) {
// Default to "SAL1" post-HF
source_asset = "SAL1";
}
std::string strLastArg = local_args.back();
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
if (strLastArg == "SAL" or strLastArg == "VSD") {
if (strLastArg == "SAL" or strLastArg == "SAL1") {
source_asset = strLastArg;
local_args.pop_back();
}
@@ -7264,7 +7326,7 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
std::string source_asset = "SAL";
std::string strLastArg = local_args.back();
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
if (strLastArg == "SAL" or strLastArg == "VSD") {
if (strLastArg == "SAL" or strLastArg == "SAL1") {
source_asset = strLastArg;
local_args.pop_back();
}
@@ -7394,7 +7456,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_)
{
std::string asset_type = (args_.size() > 1) ? args_.back() : "SAL";
std::string asset_type = (args_.size() > 1) ? args_.back() : (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) ? "SAL1" : "SAL";
auto print_usage = [this, account, below]()
{
if (below)
@@ -8056,9 +8118,16 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
return true;
}
// We found the one we were looking for - take a copy of the key_image, etc.
// Verify that the correct asset type is being returned
if (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) {
if (td.asset_type != "SAL1") {
fail_msg_writer() << tr("Only SAL1 may be returned for txid ") << args_[0];
return true;
}
}
// We found the one(s) we were looking for - take a copy of the key_image, etc.
transfers_indices.push_back(idx);
break;
}
// Check we have a valid key_image
@@ -8083,21 +8152,32 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
fail_msg_writer() << tr("Multiple transactions are created, which is not supposed to happen");
return true;
}
if (ptx_vector[0].selected_transfers.size() != 1)
if (ptx_vector[0].selected_transfers.size() != transfers_indices.size())
{
fail_msg_writer() << tr("The transaction uses multiple or no inputs, which is not supposed to happen");
fail_msg_writer() << tr("The transaction uses incorrect number of inputs, which is not supposed to happen");
return true;
}
// give user total and fee, and prompt to confirm
uint64_t total_fee = ptx_vector[0].fee;
uint64_t total_sent = m_wallet->get_transfer_details(ptx_vector[0].selected_transfers.front()).amount();
uint64_t total_sent = 0;
std::string asset_type;
for (auto idx: ptx_vector[0].selected_transfers) {
const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(idx);
uint64_t sent = td.amount();
if (total_sent + sent < total_sent) {
fail_msg_writer() << tr("amount overflow detected");
return true;
}
total_sent += sent;
asset_type = td.asset_type;
}
std::ostringstream prompt;
if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
return true;
prompt << boost::format(tr("Returning %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
print_money(total_fee);
prompt << boost::format(tr("Returning %s %s for a total fee of %s %s. Is this okay?")) %
print_money(total_sent) % asset_type %
print_money(total_fee) % asset_type;
std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return true;
@@ -8200,7 +8280,7 @@ bool simple_wallet::burn(const std::vector<std::string> &args_)
std::string asset_type;
std::string strLastArg = local_args.back();
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
if (strLastArg not_eq "SAL" and strLastArg not_eq "VSD") {
if (strLastArg not_eq "SAL" and strLastArg not_eq "SAL1") {
PRINT_USAGE(USAGE_BURN);
return true;
}
@@ -8264,7 +8344,7 @@ bool simple_wallet::convert(const std::vector<std::string> &args_)
// Get the destination asset type
std::string source_asset, dest_asset;
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
if (strLastArg not_eq "SAL" and strLastArg not_eq "VSD") {
if (strLastArg not_eq "SAL" and strLastArg not_eq "SAL1") {
fail_msg_writer() << tr("invalid destination asset_type");
PRINT_USAGE(USAGE_CONVERT);
return true;
@@ -8274,7 +8354,7 @@ bool simple_wallet::convert(const std::vector<std::string> &args_)
// Get the source asset type
strLastArg = local_args.back();
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
if (strLastArg not_eq "SAL" and strLastArg not_eq "VSD") {
if (strLastArg not_eq "SAL" and strLastArg not_eq "SAL1") {
fail_msg_writer() << tr("invalid source asset_type");
PRINT_USAGE(USAGE_CONVERT);
return true;
@@ -8298,6 +8378,38 @@ bool simple_wallet::convert(const std::vector<std::string> &args_)
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::audit(const std::vector<std::string> &args_)
{
// TODO: add locked versions
std::vector<std::string> local_args = args_;
if (args_.size() == 0)
{
local_args.push_back("index=0");
} else if (args_.size() > 1) {
PRINT_USAGE(USAGE_AUDIT);
return true;
}
if(m_wallet->multisig())
{
fail_msg_writer() << tr("This is a multisig wallet, staking is not currently supported");
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 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);
transfer_main(Audit, audit_asset_types.first, audit_asset_types.first, local_args, false);
} else {
fail_msg_writer() << tr("Audit command is not available at this time.");
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::stake(const std::vector<std::string> &args_)
{
// TODO: add locked versions
@@ -8316,9 +8428,13 @@ bool simple_wallet::stake(const std::vector<std::string> &args_)
std::vector<std::string> local_args;
local_args.push_back(m_wallet->get_subaddress_as_str({m_current_subaddress_account,0}));
local_args.insert(local_args.end(), args_.begin(), args_.end());
transfer_main(Stake, "SAL", "SAL", local_args, false);
return true;
if (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) {
transfer_main(Stake, "SAL1", "SAL1", local_args, false);
} else {
transfer_main(Stake, "SAL", "SAL", local_args, false);
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::price_info(const std::vector<std::string> &args) {
@@ -8403,7 +8519,7 @@ bool simple_wallet::yield_info(const std::vector<std::string> &args) {
// EXPERIMENTAL - change to get_yield_summary_info() method
uint64_t t_burnt, t_supply, t_locked, t_yield, yps, ybi_size;
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> yield_payouts;
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> yield_payouts;
if (!m_wallet->get_yield_summary_info(t_burnt, t_supply, t_locked, t_yield, yps, ybi_size, yield_payouts)) {
fail_msg_writer() << "failed to get yield info. Make sure you are connected to a daemon.";
return false;
@@ -8411,29 +8527,35 @@ bool simple_wallet::yield_info(const std::vector<std::string> &args) {
// Get the chain height
const uint64_t blockchain_height = m_wallet->get_blockchain_current_height();
uint64_t stake_lock_period = get_config(m_wallet->nettype()).STAKE_LOCK_PERIOD;
message_writer(console_color_default, false) << boost::format(tr("\nSTAKED FUNDS:"));
for (auto &p: yield_payouts) {
uint64_t height, burnt, yield;
std::string txid;
std::tie(height, txid, burnt, yield) = p;
std::string txid, asset_type;
std::tie(height, txid, asset_type, burnt, yield) = p;
epee::console_colors asset_type_color = (asset_type == "SAL") ? console_color_green : (asset_type == "SAL1") ? console_color_blue : console_color_green;
if (blockchain_height > ybi_size + height)
message_writer(console_color_green, true) << boost::format(tr("Height %d, txid %s, staked %s SAL, earned %s SAL"))
message_writer(asset_type_color, true) << boost::format(tr("Height %d, txid %s, staked %s %s, earned %s %s"))
% height
% txid
% print_money(burnt)
% print_money(yield);
% asset_type
% print_money(yield)
% asset_type;
else
message_writer(console_color_green, false) << boost::format(tr("Height %d (matures %d), txid %s, staked %s SAL, %s SAL accrued so far"))
message_writer(asset_type_color, false) << boost::format(tr("Height %d (matures %d), txid %s, staked %s %s, %s %s accrued so far"))
% height
% (height + 21601)
% (height + stake_lock_period)
% txid
% print_money(burnt)
% print_money(yield);
}
% asset_type
% print_money(yield)
% asset_type;
}
// Output the necessary information about yield stats
message_writer(console_color_default, false) << boost::format(tr("\nYIELD INFO:\n\tSupply coins burnt over last %s: %d\n\tTotal coins locked: %d\n\tYield accrued over last %s: %d\n\tYield per SAL staked: %d"))
message_writer(console_color_default, false) << boost::format(tr("\nYIELD INFO:\n\tSupply coins burnt over last %s: %d\n\tTotal coins locked: %d\n\tYield accrued over last %s: %d\n\tYield per coin staked: %d"))
% get_human_readable_timespan((ybi_size-1) * DIFFICULTY_TARGET_V2)
% print_money(t_burnt)
% print_money(t_locked)
+1
View File
@@ -185,6 +185,7 @@ namespace cryptonote
bool return_payment(const std::vector<std::string> &args);
bool burn(const std::vector<std::string> &args);
bool convert(const std::vector<std::string> &args);
bool audit(const std::vector<std::string> &args);
bool stake(const std::vector<std::string> &args);
bool price_info(const std::vector<std::string> &args);
bool supply_info(const std::vector<std::string> &args);
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
#define DEF_SALVIUM_VERSION "0.7.2"
#define DEF_SALVIUM_VERSION "0.9.3"
#define DEF_MONERO_VERSION_TAG "release"
#define DEF_MONERO_VERSION "0.18.3.3"
#define DEF_MONERO_RELEASE_NAME "Zero"
+30 -2
View File
@@ -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);
}
+4
View File
@@ -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,
+17 -2
View File
@@ -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
+1 -1
View File
@@ -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;
}
+2 -2
View File
@@ -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;
};
}
+148 -53
View File
@@ -886,6 +886,11 @@ uint8_t get_full_proofs_fork()
return HF_VERSION_FULL_PROOFS;
}
uint8_t get_salvium_one_proofs_fork()
{
return HF_VERSION_SALVIUM_ONE_PROOFS;
}
uint64_t calculate_fee(bool use_per_byte_fee, const cryptonote::transaction &tx, size_t blob_size, uint64_t base_fee, uint64_t fee_quantization_mask)
{
if (use_per_byte_fee)
@@ -2148,6 +2153,7 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
case rct::RCTTypeCLSAG:
case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeFullProofs:
case rct::RCTTypeSalviumOne:
return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev);
case rct::RCTTypeFull:
return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev);
@@ -2198,6 +2204,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
// Flag to indicate this is a TX that uses a return_address
bool use_od = false;
cryptonote::origin_data od = AUTO_VAL_INIT(od);
rct::salvium_input_data_t sid;
auto search = m_salvium_txs.find(pk_change);
if (search != m_salvium_txs.end()) {
size_t idx = search->second;
@@ -2208,6 +2215,9 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
od.tx_pub_key = get_tx_pub_key_from_extra(td_origin.m_tx);
od.output_index = td_origin.m_internal_output_index;
od.tx_type = td_origin.m_tx.type;
// SRCG: this is necessary to be able to receive protocol_tx outputs to the correct wallet subaddress
tx_scan_info.received->index = td_origin.m_subaddr_index;
}
if (m_multisig)
@@ -2218,7 +2228,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
}
else
{
bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), output_public_key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device(), use_od, od);
bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), output_public_key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device(), use_od, od, sid);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != output_public_key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
@@ -2392,7 +2402,7 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
uint64_t &total_yield,
uint64_t &yield_per_stake,
uint64_t &ybi_data_size,
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> &payouts
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> &payouts
)
{
// Get the total circulating supply of SALs
@@ -2420,21 +2430,21 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
// Iterate over the transfers in our wallet
std::map<size_t, size_t> map_payouts;
std::map<std::string, std::pair<size_t, std::pair<uint64_t, uint64_t>>> payouts_active;
std::map<std::string, std::tuple<size_t, std::string, uint64_t, uint64_t>> payouts_active;
if (m_transfers.size() > 0) {
for (size_t idx = m_transfers.size()-1; idx>0; --idx) {
const tools::wallet2::transfer_details& td = m_transfers[idx];
//if (td.m_block_height < ybi_data[0].block_height) break;
if (td.m_tx.type == cryptonote::transaction_type::STAKE) {
if (map_payouts.count(idx)) {
payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt));
payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.asset_type, td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt));
} else {
//payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, 0));
payouts_active[epee::string_tools::pod_to_hex(td.m_txid)] = std::make_pair(td.m_block_height, std::make_pair(td.m_tx.amount_burnt, 0));
payouts_active[epee::string_tools::pod_to_hex(td.m_txid)] = std::make_tuple(td.m_block_height, td.asset_type, td.m_tx.amount_burnt, 0);
}
} else if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) {
// Store list of reverse-lookup indices to tell YIELD TXs how much they earned
if (m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::STAKE)
if (m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::STAKE || m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::AUDIT)
map_payouts[td.m_td_origin_idx] = idx;
}
}
@@ -2452,18 +2462,21 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
// EXPERIMENTAL - add up yield earned for active STAKE TXs
for (auto &payout: payouts_active) {
if (ybi_data[idx].block_height < payout.second.first) continue;
auto&[height,asset_type,total_burnt,total_accrued] = payout.second;
if (ybi_data[idx].block_height < height) continue;
boost::multiprecision::uint128_t amount_128 = ybi_data[idx].slippage_total_this_block;
amount_128 *= payout.second.second.first;
amount_128 *= total_burnt;
amount_128 /= ybi_data[idx].locked_coins_tally;
payout.second.second.second += amount_128.convert_to<uint64_t>();
total_accrued += amount_128.convert_to<uint64_t>();
}
}
}
for (auto &payout: payouts_active) {
// Copy to the list of payouts proper
payouts.push_back(std::make_tuple(payout.second.first, payout.first, payout.second.second.first, payout.second.second.second));
auto&[height,asset_type,total_burnt,total_accrued] = payout.second;
payouts.push_back(std::make_tuple(height, payout.first, asset_type, total_burnt, total_accrued));
}
// Get the total currently locked
@@ -2486,7 +2499,7 @@ bool wallet2::verify_spend_authority_proof(const cryptonote::transaction &tx, co
// Sanity checks
if (tx.type != cryptonote::transaction_type::TRANSFER) return true;
if (tx.version < TRANSACTION_VERSION_N_OUTS) return true;
if (tx.rct_signatures.type != rct::RCTTypeFullProofs) return true;
if (tx.rct_signatures.type != rct::RCTTypeFullProofs && tx.rct_signatures.type != rct::RCTTypeSalviumOne) return true;
// To verify the spend authority proof, we need to know the y value to process the F value
ec_scalar y;
@@ -2544,7 +2557,7 @@ bool wallet2::verify_spend_authority_proof(const cryptonote::transaction &tx, co
rct::key hs_yF = rct::hash_to_scalar(key_yF);
// Now we can verify the proof itself
if (!rct::SAProof_Ver(tx.rct_signatures.sa_proof, key_P_change, hs_yF)) {
if (!rct::SAProof_Ver(tx.rct_signatures.salvium_data.sa_proof, key_P_change, hs_yF)) {
return false;
}
@@ -2743,7 +2756,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
THROW_WALLET_EXCEPTION_IF(td_origin_idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol TX origin in m_transfers");
const transfer_details& td_origin = get_transfer_details(td_origin_idx);
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::STAKE, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers");
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::AUDIT && td_origin.m_tx.type != cryptonote::transaction_type::STAKE, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers");
// Get the output key for the change entry
crypto::public_key pk_locked_coins = crypto::null_pkey;
@@ -2877,7 +2890,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
total_received_1[asset_type] = amount;
notify = true;
if (tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
if (tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
// The CONVERT/YIELD TX was created by us - therefore we need to expect an output in the PROTOCOL_TX
// It could be a refund or a conversion
@@ -2887,14 +2900,15 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
crypto::public_key P_change = crypto::null_pkey;
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(tx.vout[0], P_change), error::wallet_internal_error, "Failed to get change output public key");
//m_subaddresses[P_change] = {0x50524F54,0x4F434F4C}; /* {PROT,OCOL} - seemed like a good idea at the time, but harder to implement! */
m_subaddresses[P_change] = {0,0};
m_subaddresses[P_change] = tx_scan_info[o].received->index;//{0,0};
//m_subaddresses[P_change] = {0,0};
m_salvium_txs.insert({P_change, m_transfers.size()-1});
if (tx.type == cryptonote::transaction_type::STAKE) {
// Additionally, with YIELD TXs, we need to update our "balance staked" subtotal, because otherwise our balance is out by the staked coins until they mature!
if (tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
// Additionally, with STAKE and AUDIT TXs, we need to update our "balance staked" subtotal, because otherwise our balance is out by the staked coins until they mature!
// SRCG: must remember to deduct the number of staked coins when they mature!!
LOG_PRINT_L1("***** STAKED COINS : " << tx.amount_burnt << " *****");
m_locked_coins.insert({P_change, {0, tx.amount_burnt}});
LOG_PRINT_L1("***** STAKED/AUDITED COINS : " << tx.amount_burnt << " *****");
m_locked_coins.insert({P_change, {0, tx.amount_burnt, tx.source_asset_type}});
}
} else if (tx.type == cryptonote::transaction_type::TRANSFER) {
@@ -7015,10 +7029,12 @@ uint64_t wallet2::balance(uint32_t index_major, const std::string& asset_type, b
uint64_t amount = 0;
for (const auto& i : balance_per_subaddress(index_major, asset_type, strict))
amount += i.second;
if (index_major == 0 && asset_type == "SAL") {
// Iterate over the locked coins, adding them to the _locked_ balance
for (const auto& i : m_locked_coins)
// Iterate over the locked coins, adding them to the _locked_ balance
for (const auto& i : m_locked_coins) {
if (index_major == 0 && asset_type == i.second.m_asset_type) {
amount += i.second.m_amount;
}
}
return amount;
}
@@ -7944,13 +7960,14 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
// SRCG: Calculate the correct uniqueness value here
assert(false);
cryptonote::origin_data origin_tx_data;
rct::salvium_input_data_t sid;
// if this output is back to this wallet, we can calculate its key image already
if (!is_out_to_acc_precomp(m_subaddresses, output_public_key, derivation, additional_derivations, i, hwdev, get_output_view_tag(tx.vout[i])))
continue;
crypto::key_image ki;
cryptonote::keypair in_ephemeral;
if (generate_key_image_helper(keys, m_subaddresses, output_public_key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev, false, origin_tx_data))
if (generate_key_image_helper(keys, m_subaddresses, output_public_key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev, false, origin_tx_data, sid))
signed_txes.tx_key_images[output_public_key] = ki;
else
MERROR("Failed to calculate key image");
@@ -9463,11 +9480,15 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (out < num_outs)
{
MINFO("Using it");
// HERE BE DRAGONS!!!
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
//req.outputs.push_back({amount, out, true}); // Rings are stored referencing global output IDs
add_output_to_lists({amount, out, true});
//add_output_to_lists({amount, out, true});
add_output_to_lists({amount, out, false});
// LAND AHOY!!!
++num_found;
seen_indices.emplace(out);
if (out == td.m_global_output_index)
if (out == td.m_asset_type_output_index)
{
MINFO("This is the real output");
own_found = true;
@@ -9725,7 +9746,11 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
"Daemon response did not include the requested real output");
// pick real out first (it will be sorted when done)
outs.back().push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), mask));
// HERE BE DRAGONS!!!
// SRCG: DO NOT COMMIT THIS CHANGE UNTIL VERIFIED AS WORKING
//outs.back().push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), mask));
outs.back().push_back(std::make_tuple(td.m_asset_type_output_index, td.get_public_key(), mask));
// LAND AHOY!!!
// then pick outs from an existing ring, if any
if (td.m_key_image_known && !td.m_key_image_partial)
@@ -9744,13 +9769,16 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
for (size_t o = 0; o < requested_outputs_count; ++o)
{
size_t i = base + o;
if (req.outputs[i].index == out && req.outputs[i].is_global_out)
// HERE BE DRAGONS!!!
// SRCG: DO NOT COMMIT THIS CHANGE UNTIL VERIFIED AS WORKING
if (req.outputs[i].index == out /*&& req.outputs[i].is_global_out*/)
{
LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key << " (from existing ring)");
tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache);
found = true;
break;
}
// LAND AHOY!!!
}
THROW_WALLET_EXCEPTION_IF(!found, error::wallet_internal_error, "Failed to find existing ring output in daemon out data");
}
@@ -9896,7 +9924,11 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
"real output not found");
tx_output_entry real_oe;
real_oe.first = td.m_global_output_index;
// HERE BE DRAGONS!!!
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
//real_oe.first = td.m_global_output_index;
real_oe.first = td.m_asset_type_output_index;
// LAND AHOY!!!
real_oe.second.dest = rct::pk2rct(td.get_public_key());
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
*it_to_replace = real_oe;
@@ -10101,9 +10133,13 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
uint32_t subaddr_index = m_transfers[*selected_transfers.begin()].m_subaddr_index.minor;
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i) {
THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts");
if (tx_type == cryptonote::transaction_type::AUDIT) {
THROW_WALLET_EXCEPTION_IF(subaddr_index != m_transfers[*i].m_subaddr_index.minor, error::wallet_internal_error, "the AUDIT tx uses funds from multiple subaddresses");
}
}
if (outs.empty())
get_outs(outs, selected_transfers, fake_outputs_count, all_rct, valid_public_keys_cache); // may throw
@@ -10152,13 +10188,21 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
//paste real transaction to the random index
auto it_to_replace = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a)
{
return a.first == td.m_global_output_index;
// HERE BE DRAGONS!!!
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
//return a.first == td.m_global_output_index;
return a.first == td.m_asset_type_output_index;
// LAND AHOY!!!
});
THROW_WALLET_EXCEPTION_IF(it_to_replace == src.outputs.end(), error::wallet_internal_error,
"real output not found");
tx_output_entry real_oe;
real_oe.first = td.m_global_output_index;
// HERE BE DRAGONS!!!
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
//real_oe.first = td.m_global_output_index;
real_oe.first = td.m_asset_type_output_index;
// LAND AHOY!!!
real_oe.second.dest = rct::pk2rct(td.get_public_key());
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
*it_to_replace = real_oe;
@@ -10182,11 +10226,18 @@ 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, 0});
change_dts.is_subaddress = subaddr_account != 0;
change_dts.addr = get_subaddress({subaddr_account, subaddr_index});
change_dts.is_subaddress = subaddr_account != 0 || subaddr_index != 0;
change_dts.is_change = true;
splitted_dsts.push_back(change_dts);
account_keys a_keys = m_account.get_keys();
// SRCG: add support for auditing of subaddresses
if (tx_type == cryptonote::transaction_type::AUDIT && (subaddr_account != 0 || subaddr_index != 0)) {
// Overwrite the public spend key and view key
a_keys.m_account_address = get_subaddress({subaddr_account, subaddr_index});
}
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
crypto::secret_key multisig_tx_key_entropy;
@@ -10230,7 +10281,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
std::vector<std::pair<std::string, std::string>> circ_amounts;
THROW_WALLET_EXCEPTION_IF(!get_circulating_supply(circ_amounts), error::wallet_internal_error, "Failed to get circulating supply");
// make a normal tx
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, tx_type, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
bool r = cryptonote::construct_tx_and_get_tx_key(a_keys/*m_account.get_keys()*/, m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, tx_type, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
LOG_PRINT_L2("constructed tx, r="<<r);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_nettype);
}
@@ -10652,7 +10703,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
const bool bulletproof_plus = true;
const bool clsag = true;
const bool use_fullproofs = use_fork_rules(get_full_proofs_fork(), 0);
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_fullproofs ? 5 : 4 };
const bool use_salviumone_proofs = use_fork_rules(get_salvium_one_proofs_fork(), 0);
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_salviumone_proofs ? 6 : use_fullproofs ? 5 : 4 };
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
std::unordered_set<crypto::public_key> valid_public_keys_cache;
@@ -10695,7 +10747,18 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
//THROW_WALLET_EXCEPTION_IF(!get_circulating_supply(circ_amounts), error::wallet_internal_error, "Failed to get circulating supply");
break;
case transaction_type::STAKE:
THROW_WALLET_EXCEPTION_IF(dest_asset != "SAL", error::wallet_internal_error, "Yield TX must specify 'SAL' destination asset type");
if (use_salviumone_proofs) {
THROW_WALLET_EXCEPTION_IF(source_asset != "SAL1", error::wallet_internal_error, "STAKE TX must specify 'SAL1' source asset type");
THROW_WALLET_EXCEPTION_IF(dest_asset != "SAL1", error::wallet_internal_error, "STAKE TX must specify 'SAL1' destination asset type");
} else {
THROW_WALLET_EXCEPTION_IF(source_asset != "SAL", error::wallet_internal_error, "STAKE TX must specify 'SAL' source asset type");
THROW_WALLET_EXCEPTION_IF(dest_asset != "SAL", error::wallet_internal_error, "STAKE TX must specify 'SAL' destination asset type");
}
THROW_WALLET_EXCEPTION_IF(subaddr_account != 0, error::wallet_internal_error, "Staking is only permitted from main account, not secondary accounts");
break;
case transaction_type::AUDIT:
THROW_WALLET_EXCEPTION_IF(source_asset != "SAL", error::wallet_internal_error, "AUDIT TX must specify 'SAL' source asset type");
THROW_WALLET_EXCEPTION_IF(dest_asset != "SAL", error::wallet_internal_error, "AUDIT TX must specify 'SAL' destination asset type");
THROW_WALLET_EXCEPTION_IF(subaddr_account != 0, error::wallet_internal_error, "Staking is only permitted from main account, not secondary accounts");
break;
default:
@@ -11327,6 +11390,8 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, c
received += ptx.tx.amount_burnt;
else if (ptx.tx.type == cryptonote::transaction_type::STAKE)
received += ptx.tx.amount_burnt;
else if (ptx.tx.type == cryptonote::transaction_type::AUDIT)
received += ptx.tx.amount_burnt;
total_received += received;
}
@@ -11351,11 +11416,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
const bool bulletproof_plus = true;
const bool clsag = true;
const bool use_fullproofs = use_fork_rules(get_full_proofs_fork(), 0);
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_fullproofs ? 5 : 4 };
const bool use_salviumone_proofs = use_fork_rules(get_salvium_one_proofs_fork(), 0);
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_salviumone_proofs ? 6 : use_fullproofs ? 5 : 4 };
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
const uint64_t base_fee = get_base_fee(priority);
const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags);
const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags);
// HERE BE DRAGONS!!!
// SRCG: the weight of the TX needs to account for the additional proofs
const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags/*, use_fullproofs, use_salviumone_proofs*/);
const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags/*, use_fullproofs, use_salviumone_proofs*/);
// LAND AHOY!!!
THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!");
const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring;
const uint64_t fractional_threshold = (base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
@@ -11413,7 +11482,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
}
}
return create_transactions_from(address, cryptonote::transaction_type::TRANSFER, "SAL", is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
return create_transactions_from(address, tx_type, asset_type, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
}
std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
@@ -11441,7 +11510,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector<size_t> transfers_indices)
{
// Get the asset_type and associated information
THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>1, error::wallet_internal_error, tr("Incorrect number of transfers_indices on return_payment"));
THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>15, error::wallet_internal_error, tr("Incorrect number of transfers_indices on return_payment"));
size_t idx = transfers_indices[0];
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers"));
const transfer_details& td_origin = get_transfer_details(idx);
@@ -11454,6 +11523,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
uint32_t priority = adjust_priority(0);
std::vector<uint8_t> extra; // No need for a TX extra beyond that which will be calculated herein
// Verify that all the indices share an origin
for (const auto &td_idx : transfers_indices) {
THROW_WALLET_EXCEPTION_IF(td_idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers"));
const transfer_details &td = get_transfer_details(td_idx);
THROW_WALLET_EXCEPTION_IF(td.m_txid != td_origin.m_txid, error::wallet_internal_error, tr("TX hashes do not match for inputs to return_payment"));
THROW_WALLET_EXCEPTION_IF(td.asset_type != td_origin.asset_type, error::wallet_internal_error, tr("TX asset_type values do not match for inputs to return_payment"));
}
// To return a payment, we need to know the y value to process the F value
// ...but the y value is calculated differently depending on the original TX
ec_scalar y;
@@ -11594,7 +11671,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
const bool bulletproof_plus = true;
const bool clsag = true;
const bool use_fullproofs = use_fork_rules(get_full_proofs_fork(), 0);
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_fullproofs ? 5 : 4 };
const bool use_salviumone_proofs = use_fork_rules(get_salvium_one_proofs_fork(), 0);
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_salviumone_proofs ? 6 : use_fullproofs ? 5 : 4 };
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
const uint64_t base_fee = get_base_fee(priority);
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
@@ -11666,7 +11744,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
// SRCG: should the subaddress be forced to TRUE for _RETURN_ TXs and FALSE for all others?!?!?
// add N - 1 outputs for correct initial fee estimation
for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i) {
tx.dsts.push_back(tx_destination_entry(1, address, tx_type == cryptonote::transaction_type::RETURN, tx_type == cryptonote::transaction_type::RETURN));
if (tx_type == cryptonote::transaction_type::AUDIT) {
tx.dsts.push_back(tx_destination_entry(1, address, tx_type == cryptonote::transaction_type::RETURN, tx_type == cryptonote::transaction_type::RETURN));
} else {
tx.dsts.push_back(tx_destination_entry(1, address, tx_type == cryptonote::transaction_type::RETURN, tx_type == cryptonote::transaction_type::RETURN));
}
tx.dsts.back().asset_type = asset_type;
}
@@ -12291,6 +12373,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
// SRCG: Calculate the correct uniqueness value here
assert(false);
cryptonote::origin_data origin_tx_data;
rct::salvium_input_data_t sid;
// derive the real output keypair
const transfer_details& in_td = m_transfers[found->second];
@@ -12299,7 +12382,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
const std::vector<crypto::public_key> in_additionakl_tx_pub_keys = get_additional_tx_pub_keys_from_extra(in_td.m_tx);
keypair in_ephemeral;
crypto::key_image in_img;
THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device(), false, origin_tx_data),
THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device(), false, origin_tx_data, sid),
error::wallet_internal_error, "failed to generate key image");
THROW_WALLET_EXCEPTION_IF(in_key->k_image != in_img, error::wallet_internal_error, "key image mismatch");
@@ -12515,7 +12598,7 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
crypto::secret_key scalar1;
crypto::derivation_to_scalar(found_derivation, n, scalar1);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs);
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs || tx.rct_signatures.type == rct::RCTTypeSalviumOne);
const rct::key C = tx.rct_signatures.outPk[n].mask;
rct::key Ctmp;
THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.mask.bytes) != 0, error::wallet_internal_error, "Bad ECDH input mask");
@@ -12529,6 +12612,12 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
received += amount;
}
}
// SRCG: if this returns 0 received, but it's an AUDIT TX, then that is EXPECTED
bool audit = (tx.rct_signatures.type == rct::RCTTypeSalviumOne && tx.rct_signatures.salvium_data.salvium_data_type == rct::SalviumAudit);
if (audit && received == 0) {
received += tx.amount_burnt;
}
}
void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations)
@@ -12782,8 +12871,9 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
uint64_t received;
check_tx_key_helper(tx, derivation, additional_derivations, address, received);
// SRCG: if this returns 0 received, but it's an AUDIT TX, then that is EXPECTED
THROW_WALLET_EXCEPTION_IF(!received, error::wallet_internal_error, tr("No funds received in this tx."));
// concatenate all signature strings
for (size_t i = 0; i < num_sigs; ++i)
sig_str +=
@@ -13032,11 +13122,12 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
// Populate this struct if you want to make use of "get_reserve_proof()" for Salvium!!!
assert(false);
origin_data od;
rct::salvium_input_data_t sid;
// derive ephemeral secret key
crypto::key_image ki;
cryptonote::keypair ephemeral;
const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki, m_account.get_device(), false, od);
const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki, m_account.get_device(), false, od, sid);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
THROW_WALLET_EXCEPTION_IF(ephemeral.pub != td.get_public_key(), error::wallet_internal_error, "Derived public key doesn't agree with the stored one");
@@ -13209,7 +13300,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
crypto::secret_key shared_secret;
crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx];
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs);
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs || tx.rct_signatures.type == rct::RCTTypeSalviumOne);
amount = rct::h2d(ecdh_info.amount);
}
total += amount;
@@ -13664,11 +13755,12 @@ std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>
// Populate this struct if you want to make use of "import_outputs" for Salvium!!!
assert(false);
origin_data od;
rct::salvium_input_data_t sid;
// generate ephemeral secret key
crypto::key_image ki;
cryptonote::keypair in_ephemeral;
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device(), false, od);
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device(), false, od, sid);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && !td.m_key_image_partial && ki != td.m_key_image,
@@ -14258,6 +14350,7 @@ process:
// Populate this struct if you want to make use of "import_outputs" for Salvium!!!
assert(false);
origin_data od;
rct::salvium_input_data_t sid;
THROW_WALLET_EXCEPTION_IF(td.m_tx.vout.empty(), error::wallet_internal_error, "tx with no outputs at index " + boost::lexical_cast<std::string>(i + offset));
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
@@ -14268,7 +14361,7 @@ process:
crypto::public_key out_key = td.get_public_key();
if (should_expand(td.m_subaddr_index))
create_one_off_subaddress(td.m_subaddr_index);
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), false, od);
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), false, od, sid);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
if (should_expand(td.m_subaddr_index))
expand_subaddresses(td.m_subaddr_index);
@@ -14367,6 +14460,7 @@ size_t wallet2::import_outputs(const std::tuple<uint64_t, uint64_t, std::vector<
// Populate this struct if you want to make use of "import_outputs" for Salvium!!!
assert(false);
origin_data od;
rct::salvium_input_data_t sid;
// the hot wallet wouldn't have known about key images (except if we already exported them)
cryptonote::keypair in_ephemeral;
@@ -14376,7 +14470,7 @@ size_t wallet2::import_outputs(const std::tuple<uint64_t, uint64_t, std::vector<
const crypto::public_key& out_key = etd.m_pubkey;
if (should_expand(td.m_subaddr_index))
create_one_off_subaddress(td.m_subaddr_index);
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), false, od);
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), false, od, sid);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
if (should_expand(td.m_subaddr_index))
expand_subaddresses(td.m_subaddr_index);
@@ -14585,6 +14679,7 @@ crypto::key_image wallet2::get_multisig_composite_key_image(size_t n) const
// SRCG: work out if we have origin data to use
bool use_origin_data = false;
cryptonote::origin_data origin_tx_data;
rct::salvium_input_data_t sid;
if (td.m_td_origin_idx != (uint64_t)-1) {
// Flag to indicate this is a TX that uses a return_address
@@ -14595,7 +14690,7 @@ crypto::key_image wallet2::get_multisig_composite_key_image(size_t n) const
use_origin_data = true;
}
bool r = multisig::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki, use_origin_data, origin_tx_data);
bool r = multisig::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki, use_origin_data, origin_tx_data, sid);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
return ki;
}
+4 -1
View File
@@ -486,11 +486,13 @@ private:
{
uint32_t m_index_major;
uint64_t m_amount;
std::string m_asset_type;
BEGIN_SERIALIZE_OBJECT()
VERSION_FIELD(0)
VARINT_FIELD(m_index_major)
VARINT_FIELD(m_amount)
FIELD(m_asset_type)
END_SERIALIZE()
};
@@ -1755,7 +1757,7 @@ private:
uint64_t &total_yield,
uint64_t &yield_per_stake,
uint64_t &ybi_data_size,
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> &payouts
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> &payouts
);
private:
@@ -2365,6 +2367,7 @@ namespace boost
{
a & x.m_index_major;
a & x.m_amount;
a & x.m_asset_type;
}
template <class Archive>
+71
View File
@@ -1093,6 +1093,77 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_audit(const wallet_rpc::COMMAND_RPC_AUDIT::request& req, wallet_rpc::COMMAND_RPC_AUDIT::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
std::vector<cryptonote::tx_destination_entry> dsts;
std::vector<uint8_t> extra;
if (!m_wallet) return not_open(er);
if (m_restricted)
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
CHECK_MULTISIG_ENABLED();
std::string asset_type = req.asset_type.empty() ? "SAL" : req.asset_type;
// validate the transfer requested and populate dsts & extra
std::list<wallet_rpc::transfer_destination> destinations;
destinations.push_back(wallet_rpc::transfer_destination());
destinations.back().amount = 0;
destinations.back().address = req.address;
destinations.back().asset_type = asset_type;
// validate the transfer requested and populate dsts & extra
if (!validate_transfer(destinations, asset_type, asset_type, cryptonote::transaction_type::AUDIT, req.payment_id, dsts, extra, true, er))
{
return false;
}
std::set<uint32_t> subaddr_indices;
if (req.subaddr_indices_all)
{
for (uint32_t i = 0; i < m_wallet->get_num_subaddresses(req.account_index); ++i)
subaddr_indices.insert(i);
}
else
{
subaddr_indices= req.subaddr_indices;
}
try
{
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);
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 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;
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());
}
return fill_response(ptx_vector_all, req.get_tx_keys, res.tx_key_list, res.amount_list, res.amounts_by_dest_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er);
}
catch (const std::exception& e)
{
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
+2
View File
@@ -87,6 +87,7 @@ namespace tools
MAP_JON_RPC_WE("freeze", on_freeze, wallet_rpc::COMMAND_RPC_FREEZE)
MAP_JON_RPC_WE("thaw", on_thaw, wallet_rpc::COMMAND_RPC_THAW)
MAP_JON_RPC_WE("frozen", on_frozen, wallet_rpc::COMMAND_RPC_FROZEN)
MAP_JON_RPC_WE("audit", on_audit, wallet_rpc::COMMAND_RPC_AUDIT)
MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
MAP_JON_RPC_WE("transfer_split", on_transfer_split, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT)
MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER)
@@ -180,6 +181,7 @@ namespace tools
bool on_freeze(const wallet_rpc::COMMAND_RPC_FREEZE::request& req, wallet_rpc::COMMAND_RPC_FREEZE::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_thaw(const wallet_rpc::COMMAND_RPC_THAW::request& req, wallet_rpc::COMMAND_RPC_THAW::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_frozen(const wallet_rpc::COMMAND_RPC_FROZEN::request& req, wallet_rpc::COMMAND_RPC_FROZEN::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_audit(const wallet_rpc::COMMAND_RPC_AUDIT::request& req, wallet_rpc::COMMAND_RPC_AUDIT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_sign_transfer(const wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
@@ -864,6 +864,42 @@ namespace wallet_rpc
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_AUDIT
{
struct request_t
{
std::string address;
uint32_t account_index;
std::set<uint32_t> subaddr_indices;
bool subaddr_indices_all;
uint64_t ring_size;
std::string payment_id;
bool get_tx_keys;
bool do_not_relay;
bool get_tx_hex;
bool get_tx_metadata;
std::string asset_type;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(account_index)
KV_SERIALIZE(subaddr_indices)
KV_SERIALIZE_OPT(subaddr_indices_all, false)
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
KV_SERIALIZE(payment_id)
KV_SERIALIZE(get_tx_keys)
KV_SERIALIZE_OPT(do_not_relay, false)
KV_SERIALIZE_OPT(get_tx_hex, false)
KV_SERIALIZE_OPT(get_tx_metadata, false)
KV_SERIALIZE(asset_type)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
typedef split_transfer_response response_t;
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_SWEEP_ALL
{
struct request_t
+6 -2
View File
@@ -69,8 +69,10 @@ public:
, const crypto::hash& blk_hash
, uint64_t slippage_total
, uint64_t yield_total
, uint64_t audit_total
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
) override {
blocks.push_back({block_weight, long_term_block_weight});
}
@@ -152,8 +154,9 @@ static void test(test_t t, uint64_t blocks)
cryptonote::block b;
b.major_version = 1;
b.minor_version = 1;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
bc->get_db().add_block(std::make_pair(b, ""), 300000, 300000, bc->get_db().height(), bc->get_db().height(), {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(b, ""), 300000, 300000, bc->get_db().height(), bc->get_db().height(), {}, cryptonote::FAKECHAIN, ybi, abi);
if (!bc->update_next_cumulative_weight_limit())
{
fprintf(stderr, "Failed to update cumulative weight limit 1\n");
@@ -187,8 +190,9 @@ static void test(test_t t, uint64_t blocks)
cryptonote::block b;
b.major_version = HF_VERSION_2021_SCALING;
b.minor_version = HF_VERSION_2021_SCALING;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
bc->get_db().add_block(std::make_pair(std::move(b), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(std::move(b), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {}, cryptonote::FAKECHAIN, ybi, abi);
if (!bc->update_next_cumulative_weight_limit())
{
+7 -3
View File
@@ -91,8 +91,10 @@ namespace
const crypto::hash& blk_hash,
uint64_t slippage_total,
uint64_t yield_total,
uint64_t audit_total,
const cryptonote::network_type nettype,
cryptonote::yield_block_info& ybi
cryptonote::yield_block_info& ybi,
cryptonote::audit_block_info& abi
) override
{
blocks.push_back({blk, blk_hash});
@@ -178,7 +180,8 @@ static std::unique_ptr<cryptonote::BlockchainAndPool> init_blockchain(const std:
auto blk_hash = get_block_hash(*blk);
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::yield_block_info ybi;
bdb->add_block(*blk, 1, 1, 1, 0, 0, num_rct_outs_by_asset_type, blk_hash, 0, 0, cryptonote::FAKECHAIN, ybi);
cryptonote::audit_block_info abi;
bdb->add_block(*blk, 1, 1, 1, 0, 0, num_rct_outs_by_asset_type, blk_hash, 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
}
bool r = bap->blockchain.init(bdb, nettype, true, test_options, 2, nullptr);
@@ -492,7 +495,8 @@ bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine,
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[from.get_keys().m_account_address.m_spend_public_key] = {0,0};
cryptonote::origin_data od{3, crypto::null_pkey, 0};
generate_key_image_helper(from.get_keys(), subaddresses, out_key, get_tx_pub_key_from_extra(*oi.p_tx), get_additional_tx_pub_keys_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, img, hw::get_device(("default")), false, od);
rct::salvium_input_data_t sid;
generate_key_image_helper(from.get_keys(), subaddresses, out_key, get_tx_pub_key_from_extra(*oi.p_tx), get_additional_tx_pub_keys_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, img, hw::get_device(("default")), false, od, sid);
// lookup for this key image in the events vector
BOOST_FOREACH(auto& tx_pair, mtx) {
+3 -2
View File
@@ -246,6 +246,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry
std::vector<rct::multisig_kLRki> kLRkis;
std::unordered_set<crypto::public_key> used_L;
const cryptonote::origin_data origin_tx_data{3,crypto::null_pkey, 0};
rct::salvium_input_data_t sid;
for (size_t tdidx = 0; tdidx < inputs; ++tdidx)
{
kLRkis.push_back(rct::multisig_kLRki());
@@ -254,13 +255,13 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry
for (size_t msidx = 0; msidx < total; ++msidx)
for (size_t n = 0; n < account_ki[msidx][tdidx].size(); ++n)
pkis.push_back(account_ki[msidx][tdidx][n]);
r = multisig::generate_multisig_composite_key_image(miner_account[0].get_keys(), subaddresses, output_pub_key[tdidx], tx_pub_key[tdidx], additional_tx_keys, 0, pkis, (crypto::key_image&)kLRki.ki, false, origin_tx_data);
r = multisig::generate_multisig_composite_key_image(miner_account[0].get_keys(), subaddresses, output_pub_key[tdidx], tx_pub_key[tdidx], additional_tx_keys, 0, pkis, (crypto::key_image&)kLRki.ki, false, origin_tx_data, sid);
CHECK_AND_ASSERT_MES(r, false, "Failed to generate composite key image");
MDEBUG("composite ki: " << kLRki.ki);
for (size_t n = 1; n < total; ++n)
{
rct::key ki;
r = multisig::generate_multisig_composite_key_image(miner_account[n].get_keys(), subaddresses, output_pub_key[tdidx], tx_pub_key[tdidx], additional_tx_keys, 0, pkis, (crypto::key_image&)ki, false, origin_tx_data);
r = multisig::generate_multisig_composite_key_image(miner_account[n].get_keys(), subaddresses, output_pub_key[tdidx], tx_pub_key[tdidx], additional_tx_keys, 0, pkis, (crypto::key_image&)ki, false, origin_tx_data, sid);
CHECK_AND_ASSERT_MES(r, false, "Failed to generate composite key image");
CHECK_AND_ASSERT_MES(kLRki.ki == ki, false, "Composite key images do not match");
}
+2 -1
View File
@@ -63,8 +63,9 @@ namespace
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
rct::salvium_input_data_t sid;
const cryptonote::origin_data od{3, crypto::null_pkey, src_entr.real_output};
generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img, hw::get_device(("default")), false, od);
generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img, hw::get_device(("default")), false, od, sid);
// put key image into tx input
txin_to_key input_to_key;
@@ -50,6 +50,7 @@ public:
subaddresses[m_bob.get_keys().m_account_address.m_spend_public_key] = {0,0};
crypto::public_key out_key = boost::get<cryptonote::txout_to_key>(m_tx.vout[0].target).key;
cryptonote::origin_data od{3,crypto::null_pkey,0};
return cryptonote::generate_key_image_helper(m_bob.get_keys(), subaddresses, out_key, m_tx_pub_key, m_additional_tx_pub_keys, 0, in_ephemeral, ki, hw::get_device("default"), false, od);
rct::salvium_input_data_t sid;
return cryptonote::generate_key_image_helper(m_bob.get_keys(), subaddresses, out_key, m_tx_pub_key, m_additional_tx_pub_keys, 0, in_ephemeral, ki, hw::get_device("default"), false, od, sid);
}
};
+7 -5
View File
@@ -274,9 +274,10 @@ TYPED_TEST(BlockchainDBTest, AddBlock)
// no blocks have been added yet (because genesis has no parent).
//ASSERT_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1]), BLOCK_PARENT_DNE);
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0], cryptonote::FAKECHAIN, ybi));
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1], cryptonote::FAKECHAIN, ybi));
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0], cryptonote::FAKECHAIN, ybi, abi));
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1], cryptonote::FAKECHAIN, ybi, abi));
block b;
ASSERT_TRUE(this->m_db->block_exists(get_block_hash(this->m_blocks[0].first)));
@@ -289,7 +290,7 @@ TYPED_TEST(BlockchainDBTest, AddBlock)
ASSERT_TRUE(compare_blocks(this->m_blocks[0].first, b));
// assert that we can't add the same block twice
ASSERT_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0], cryptonote::FAKECHAIN, ybi), TX_EXISTS);
ASSERT_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0], cryptonote::FAKECHAIN, ybi, abi), TX_EXISTS);
for (auto& h : this->m_blocks[0].first.tx_hashes)
{
@@ -315,15 +316,16 @@ TYPED_TEST(BlockchainDBTest, RetrieveBlockData)
db_wtxn_guard guard(this->m_db);
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0], cryptonote::FAKECHAIN, ybi));
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0], cryptonote::FAKECHAIN, ybi, abi));
ASSERT_EQ(t_sizes[0], this->m_db->get_block_weight(0));
ASSERT_EQ(t_diffs[0], this->m_db->get_block_cumulative_difficulty(0));
ASSERT_EQ(t_diffs[0], this->m_db->get_block_difficulty(0));
ASSERT_EQ(t_coins[0], this->m_db->get_block_already_generated_coins(0));
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1], cryptonote::FAKECHAIN, ybi));
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1], cryptonote::FAKECHAIN, ybi, abi));
ASSERT_EQ(t_diffs[1] - t_diffs[0], this->m_db->get_block_difficulty(1));
ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0].first), this->m_db->get_block_hash_from_height(0));
+2 -1
View File
@@ -138,7 +138,8 @@ TEST(bulletproofs, multi_splitting)
for (size_t i = 0; i < destinations.size(); ++i)
destination_asset_types.push_back("SAL");
rct::rctSig s = rct::genRctSimple(rct::zero(), sc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, available, mixRing, amount_keys, index, outSk, rct_config, hw::get_device("default"));
rct::salvium_data_t salvium_data;
rct::rctSig s = rct::genRctSimple(rct::zero(), sc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, available, mixRing, amount_keys, index, outSk, rct_config, hw::get_device("default"), salvium_data);
ASSERT_TRUE(rct::verRctSimple(s));
for (size_t i = 0; i < n_outputs; ++i)
{
+32 -18
View File
@@ -57,8 +57,10 @@ public:
, const crypto::hash& blk_hash
, uint64_t slippage_total
, uint64_t yield_total
, uint64_t audit_total
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
) override {
blocks.push_back(blk);
}
@@ -103,6 +105,7 @@ TEST(major, Only)
TestDB db;
HardFork hf(db, 1, 0, 0, 0, 1, 0); // no voting
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
// v h t
@@ -114,20 +117,20 @@ TEST(major, Only)
ASSERT_FALSE(hf.add(mkblock(0, 2), 0));
ASSERT_FALSE(hf.add(mkblock(2, 2), 0));
ASSERT_TRUE(hf.add(mkblock(1, 2), 0));
db.add_block(mkblock(1, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(1, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
// block height 1, only version 1 is accepted
ASSERT_FALSE(hf.add(mkblock(0, 2), 1));
ASSERT_FALSE(hf.add(mkblock(2, 2), 1));
ASSERT_TRUE(hf.add(mkblock(1, 2), 1));
db.add_block(mkblock(1, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(1, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
// block height 2, only version 2 is accepted
ASSERT_FALSE(hf.add(mkblock(0, 2), 2));
ASSERT_FALSE(hf.add(mkblock(1, 2), 2));
ASSERT_FALSE(hf.add(mkblock(3, 2), 2));
ASSERT_TRUE(hf.add(mkblock(2, 2), 2));
db.add_block(mkblock(2, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(2, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
}
TEST(empty_hardforks, Success)
@@ -135,6 +138,7 @@ TEST(empty_hardforks, Success)
TestDB db;
HardFork hf(db);
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
ASSERT_TRUE(hf.add_fork(1, 0, 0));
@@ -143,7 +147,7 @@ TEST(empty_hardforks, Success)
ASSERT_TRUE(hf.get_state(time(NULL) + 3600*24*400) == HardFork::Ready);
for (uint64_t h = 0; h <= 10; ++h) {
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
ASSERT_EQ(hf.get(0), 1);
@@ -170,6 +174,7 @@ TEST(check_for_height, Success)
TestDB db;
HardFork hf(db, 1, 0, 0, 0, 1, 0); // no voting
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
ASSERT_TRUE(hf.add_fork(1, 0, 0));
@@ -179,14 +184,14 @@ TEST(check_for_height, Success)
for (uint64_t h = 0; h <= 4; ++h) {
ASSERT_TRUE(hf.check_for_height(mkblock(1, 1), h));
ASSERT_FALSE(hf.check_for_height(mkblock(2, 2), h)); // block version is too high
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
for (uint64_t h = 5; h <= 10; ++h) {
ASSERT_FALSE(hf.check_for_height(mkblock(1, 1), h)); // block version is too low
ASSERT_TRUE(hf.check_for_height(mkblock(2, 2), h));
db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
}
@@ -196,6 +201,7 @@ TEST(get, next_version)
TestDB db;
HardFork hf(db);
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
ASSERT_TRUE(hf.add_fork(1, 0, 0));
@@ -205,19 +211,19 @@ TEST(get, next_version)
for (uint64_t h = 0; h <= 4; ++h) {
ASSERT_EQ(2, hf.get_next_version());
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
for (uint64_t h = 5; h <= 9; ++h) {
ASSERT_EQ(4, hf.get_next_version());
db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
for (uint64_t h = 10; h <= 15; ++h) {
ASSERT_EQ(4, hf.get_next_version());
db.add_block(mkblock(hf, h, 4), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, 4), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
}
@@ -251,6 +257,7 @@ TEST(steps_asap, Success)
TestDB db;
HardFork hf(db, 1,0,1,1,1);
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
// v h t
@@ -261,7 +268,7 @@ TEST(steps_asap, Success)
hf.init();
for (uint64_t h = 0; h < 10; ++h) {
db.add_block(mkblock(hf, h, 9), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, 9), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
@@ -282,6 +289,7 @@ TEST(steps_1, Success)
TestDB db;
HardFork hf(db, 1,0,1,1,1);
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
ASSERT_TRUE(hf.add_fork(1, 0, 0));
@@ -290,7 +298,7 @@ TEST(steps_1, Success)
hf.init();
for (uint64_t h = 0 ; h < 10; ++h) {
db.add_block(mkblock(hf, h, h+1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, h+1), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
@@ -305,6 +313,7 @@ TEST(reorganize, Same)
TestDB db;
HardFork hf(db, 1, 0, 1, 1, history, 100);
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
// v h t
@@ -317,7 +326,7 @@ TEST(reorganize, Same)
// index 0 1 2 3 4 5 6 7 8 9
static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
for (uint64_t h = 0; h < 20; ++h) {
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
@@ -336,6 +345,7 @@ TEST(reorganize, Changed)
TestDB db;
HardFork hf(db, 1, 0, 1, 1, 4, 100);
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
// v h t
@@ -350,7 +360,7 @@ TEST(reorganize, Changed)
static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9 };
for (uint64_t h = 0; h < 16; ++h) {
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE (hf.add(db.get_block_from_height(h), h));
}
@@ -370,7 +380,7 @@ TEST(reorganize, Changed)
ASSERT_EQ(db.height(), 3);
hf.reorganize_from_block_height(2);
for (uint64_t h = 3; h < 16; ++h) {
db.add_block(mkblock(hf, h, block_versions_new[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, block_versions_new[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
bool ret = hf.add(db.get_block_from_height(h), h);
ASSERT_EQ (ret, h < 15);
}
@@ -384,6 +394,7 @@ TEST(reorganize, Changed)
TEST(voting, threshold)
{
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
for (int threshold = 87; threshold <= 88; ++threshold) {
TestDB db;
@@ -396,7 +407,7 @@ TEST(voting, threshold)
for (uint64_t h = 0; h <= 8; ++h) {
uint8_t v = 1 + !!(h % 8);
db.add_block(mkblock(hf, h, v), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, v), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
bool ret = hf.add(db.get_block_from_height(h), h);
if (h >= 8 && threshold == 87) {
// for threshold 87, we reach the treshold at height 7, so from height 8, hard fork to version 2, but 8 tries to add 1
@@ -415,6 +426,7 @@ TEST(voting, threshold)
TEST(voting, different_thresholds)
{
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
for (int threshold = 87; threshold <= 88; ++threshold) {
TestDB db;
@@ -432,7 +444,7 @@ TEST(voting, different_thresholds)
static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
for (uint64_t h = 0; h < sizeof(block_versions) / sizeof(block_versions[0]); ++h) {
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
bool ret = hf.add(db.get_block_from_height(h), h);
ASSERT_EQ(ret, true);
}
@@ -447,6 +459,7 @@ TEST(voting, info)
TestDB db;
HardFork hf(db, 1, 0, 1, 1, 4, 50); // window size 4, default threshold 50%
oracle::asset_type_counts num_rct_outs_by_asset_type;
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
// v h ts
@@ -487,7 +500,7 @@ TEST(voting, info)
ASSERT_EQ(expected_thresholds[h], threshold);
ASSERT_EQ(4, voting);
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi);
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
}
}
@@ -551,8 +564,9 @@ TEST(reorganize, changed)
do { \
cryptonote::block b = mkblock(hf, h, v); \
oracle::asset_type_counts num_rct_outs_by_asset_type; \
cryptonote::audit_block_info abi; \
cryptonote::yield_block_info ybi; \
db.add_block(b, 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, cryptonote::FAKECHAIN, ybi); \
db.add_block(b, 0, 0, 0, 0, 0, num_rct_outs_by_asset_type, crypto::hash(), 0, 0, 0, cryptonote::FAKECHAIN, ybi, abi); \
ASSERT_##a(hf.add(b, h)); \
} while(0)
#define ADD_TRUE(v, h) ADD(v, h, TRUE)
+17 -14
View File
@@ -61,8 +61,10 @@ public:
, const crypto::hash& blk_hash
, uint64_t slippage_total
, uint64_t yield_total
, uint64_t audit_total
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
) override {
blocks.push_back({block_weight, long_term_block_weight});
}
@@ -114,6 +116,7 @@ static uint32_t lcg()
#define PREFIX_WINDOW(hf_version,window) \
cryptonote::BlockchainAndPool bap; \
cryptonote::Blockchain *bc = &bap.blockchain; \
cryptonote::audit_block_info abi; \
cryptonote::yield_block_info ybi; \
struct get_test_options { \
const std::pair<uint8_t, uint64_t> hard_forks[3]; \
@@ -146,7 +149,7 @@ TEST(long_term_block_weight, identical_before_fork)
{
size_t w = h < CRYPTONOTE_REWARD_BLOCKS_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
}
for (uint64_t h = 0; h < 10 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
@@ -163,7 +166,7 @@ TEST(long_term_block_weight, identical_after_fork_before_long_term_window)
{
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
}
for (uint64_t h = 0; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
@@ -180,7 +183,7 @@ TEST(long_term_block_weight, ceiling_at_30000000)
{
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
}
ASSERT_EQ(bc->get_current_cumulative_block_weight_median(), 15000000);
@@ -195,7 +198,7 @@ TEST(long_term_block_weight, multi_pop)
{
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
}
@@ -207,7 +210,7 @@ TEST(long_term_block_weight, multi_pop)
{
size_t w = bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
}
@@ -229,7 +232,7 @@ TEST(long_term_block_weight, multiple_updates)
{
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
@@ -253,7 +256,7 @@ TEST(long_term_block_weight, pop_invariant_max)
{
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
}
@@ -281,7 +284,7 @@ TEST(long_term_block_weight, pop_invariant_max)
{
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
}
@@ -303,7 +306,7 @@ TEST(long_term_block_weight, pop_invariant_random)
uint32_t r = lcg();
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : (r % bc->get_current_cumulative_block_weight_limit());
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
}
@@ -338,7 +341,7 @@ TEST(long_term_block_weight, pop_invariant_random)
uint32_t r = lcg();
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : (r % bc->get_current_cumulative_block_weight_limit());
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
@@ -366,7 +369,7 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
{
size_t w = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
}
ASSERT_EQ(long_term_effective_median_block_weight, 300000);
@@ -378,7 +381,7 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
float t = h / float(365 * 720 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW / 100000);
size_t w = 300000 + t * 30000;
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
}
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
@@ -389,7 +392,7 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
{
size_t w = bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
}
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
@@ -400,7 +403,7 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
{
size_t w = bc->get_current_cumulative_block_weight_median() * .25;
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {}, cryptonote::FAKECHAIN, ybi, abi);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
}
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
+3 -1
View File
@@ -433,6 +433,7 @@ TEST(cryptonote_protocol_handler, race_condition)
const block_t &block,
const stat::chain &stat
){
cryptonote::audit_block_info abi;
cryptonote::yield_block_info ybi;
core.get_blockchain_storage().get_db().batch_start({}, {});
core.get_blockchain_storage().get_db().add_block(
@@ -445,7 +446,8 @@ TEST(cryptonote_protocol_handler, race_condition)
stat.reward,
{},
cryptonote::FAKECHAIN,
ybi
ybi,
abi
);
core.get_blockchain_storage().get_db().batch_stop();
};
+10 -6
View File
@@ -351,7 +351,8 @@ TEST(ringct, range_proofs)
destination_asset_types.push_back("SAL");
//compute rct data with mixin 3
rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default"));
rct::salvium_data_t salvium_data;
rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default"), salvium_data);
//verify rct data
ASSERT_TRUE(verRctSimple(s));
@@ -368,7 +369,7 @@ TEST(ringct, range_proofs)
//compute rct data with mixin 3
s = genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default"));
s = genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default"), salvium_data);
//verify rct data
ASSERT_FALSE(verRctSimple(s));
@@ -422,7 +423,8 @@ TEST(ringct, range_proofs_with_fee)
destination_asset_types.push_back("SAL");
//compute rct data with mixin 3
rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 1, 3, rct_config, hw::get_device("default"));
rct::salvium_data_t salvium_data;
rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 1, 3, rct_config, hw::get_device("default"), salvium_data);
//verify rct data
ASSERT_TRUE(verRctSimple(s));
@@ -439,7 +441,7 @@ TEST(ringct, range_proofs_with_fee)
//compute rct data with mixin 3
s = genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 500, 3, rct_config, hw::get_device("default"));
s = genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 500, 3, rct_config, hw::get_device("default"), salvium_data);
//verify rct data
ASSERT_FALSE(verRctSimple(s));
@@ -504,7 +506,8 @@ TEST(ringct, simple)
for (size_t i = 0; i < destinations.size(); ++i)
destination_asset_types.push_back("SAL");
rctSig s = genRctSimple(message, sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, amount_keys, txnfee, 2, rct_config, hw::get_device("default"));
rct::salvium_data_t salvium_data;
rctSig s = genRctSimple(message, sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, amount_keys, txnfee, 2, rct_config, hw::get_device("default"), salvium_data);
//verify ring ct signature
ASSERT_TRUE(verRctSimple(s));
@@ -572,7 +575,8 @@ static rct::rctSig make_sample_simple_rct_sig(int n_inputs, const uint64_t input
for (size_t i = 0; i < destinations.size(); ++i)
destination_asset_types.push_back("SAL");
return genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, amount_keys, fee, 3, rct_config, hw::get_device("default"));
rct::salvium_data_t salvium_data;
return genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, amount_keys, fee, 3, rct_config, hw::get_device("default"), salvium_data);
}
static bool range_proof_test(bool expected_valid,
+3 -2
View File
@@ -613,7 +613,8 @@ TEST(Serialization, serializes_ringct_types)
for (size_t i = 0; i < destinations.size(); ++i)
destination_asset_types.push_back("SAL");
s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default"));
rct::salvium_data_t salvium_data;
s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 0, 3, rct_config, hw::get_device("default"), salvium_data);
ASSERT_FALSE(s0.p.MGs.empty());
ASSERT_TRUE(s0.p.CLSAGs.empty());
@@ -638,7 +639,7 @@ TEST(Serialization, serializes_ringct_types)
ASSERT_EQ(bp0, bp1);
const rct::RCTConfig rct_config_clsag{ rct::RangeProofPaddedBulletproof, 3 };
s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 0, 3, rct_config_clsag, hw::get_device("default"));
s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, amounts, amount_keys, 0, 3, rct_config_clsag, hw::get_device("default"), salvium_data);
ASSERT_FALSE(s0.p.CLSAGs.empty());
ASSERT_TRUE(s0.p.MGs.empty());