Compare commits

...

27 Commits

Author SHA1 Message Date
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 114297d784 fixed switch values in validation; bumped version 2024-12-20 09:48:00 +00:00
Some Random Crypto Guy 6368aee05f bumped version for consensus rules hard fork 2024-12-19 11:31:05 +00:00
Some Random Crypto Guy 8599cdf95b Merge branch 'main' of https://github.com/salvium/salvium 2024-12-18 12:14:53 +00:00
Some Random Crypto Guy d39f2f180e set fork height 2024-12-18 12:04:32 +00:00
Some Random Crypto Guy c763febe98 bumped mainline version to v0.7.0 2024-12-18 12:04:32 +00:00
Some Random Crypto Guy cef01372b1 updated block fast sync checksums; disabled spend authority proof due to multisig; fixed issue with duplicate keys; bumped version 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy e15dbb5db2 added belt and braces to prevent CONVERT TXs from being attempted; integrated spend authority proof support into wallet; bumped version number 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 82d706aacb bumped RC version 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy f3522764a1 switched to single spend authority proof - the dummy proofs don't work as intended, so dropping them 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 0448a6bf9a interim checkin 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 2ce22c2508 partial working serialisation 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 1334bac45a fixed check on miner-staker split 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy e909e3eef1 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-18 12:04:02 +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
SomeRandomDevopsGuy 8c999520d1 add RPC (#11)
Co-authored-by: srdg <srdg@srdg.io>
2024-11-18 18:39:04 +00:00
57 changed files with 2064 additions and 930 deletions
+1 -1
View File
@@ -109,7 +109,7 @@ jobs:
with:
name: ${{ matrix.toolchain.name }}
path: |
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-cli*
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-*
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salviumd*
- name: zip daemon & cli
run: |
+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++ ###
+5 -5
View File
@@ -1,4 +1,4 @@
# Salvium Zero v0.7.0-rc3
# Salvium Zero v0.9.0
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.0
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.0
```
* 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.0'. 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.0
```
* 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;
+321 -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_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,7 +3775,7 @@ 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;
}
circulating_supply[currency_label] = amount.convert_to<uint64_t>();
@@ -3527,12 +3786,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 +4984,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 +5002,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 +5499,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 {}
+38
View File
@@ -142,6 +142,18 @@ set(blockchain_scanner_private_headers)
monero_private_headers(blockchain_scanner
${blockchain_scanner_private_headers})
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
set(blockchain_audit_sources
blockchain_audit.cpp
)
set(blockchain_audit_private_headers)
monero_private_headers(blockchain_audit
${blockchain_audit_private_headers})
else()
message(STATUS "blockchain_audit.cpp not found - not building the audit tool")
endif()
monero_add_executable(blockchain_import
${blockchain_import_sources}
@@ -312,6 +324,32 @@ set_property(TARGET blockchain_scanner
OUTPUT_NAME "salvium-blockchain-scanner")
install(TARGETS blockchain_scanner DESTINATION bin)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
monero_add_executable(blockchain_audit
${blockchain_audit_sources}
${blockchain_audit_private_headers})
target_link_libraries(blockchain_audit
PRIVATE
wallet
crypto
cncrypto
cryptonote_core
blockchain_db
version
epee
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
set_property(TARGET blockchain_audit
PROPERTY
OUTPUT_NAME "salvium-blockchain-audit")
install(TARGETS blockchain_audit DESTINATION bin)
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++;
Binary file not shown.
+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
@@ -220,12 +224,19 @@
#define HF_VERSION_FULL_PROOFS 3
#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_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
@@ -276,10 +287,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";
@@ -350,6 +364,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"}};
@@ -376,6 +391,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"}};
@@ -411,7 +427,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)
@@ -429,6 +447,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 = {
@@ -444,6 +464,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 = {
@@ -459,6 +481,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)
+323 -226
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;
@@ -1450,9 +1452,11 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height,
bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version)
{
LOG_PRINT_L3("Blockchain::" << __func__);
if (!b.protocol_tx.vin.size()) {
// Nothing is created by this TX - check no money is included
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "void protocol transaction in the block has outputs");
if (height == 0) {
// Genesis block exception
CHECK_AND_ASSERT_MES(b.protocol_tx.version == 1, false, "Invalid genesis protocol transaction version");
CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 0, false, "genesis protocol transaction in the block has inputs");
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "genesis protocol transaction in the block has outputs");
return true;
}
CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs");
@@ -1498,6 +1502,9 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
case HF_VERSION_FULL_PROOFS:
case HF_VERSION_ENFORCE_FULL_PROOFS:
case HF_VERSION_SHUTDOWN_USER_TXS:
case HF_VERSION_SALVIUM_ONE_PROOFS:
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;
@@ -1530,173 +1537,148 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
}
//------------------------------------------------------------------
// SRCG
bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, std::vector<std::pair<transaction, blobdata>>& txs, uint8_t hf_version)
bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version)
{
LOG_PRINT_L3("Blockchain::" << __func__);
CHECK_AND_ASSERT_MES(b.tx_hashes.size() == txs.size(), false, "Invalid number of TXs / hashes supplied");
if (!b.protocol_tx.vin.size()) {
// Nothing is created by this TX - check no money is included
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "void protocol transaction in the block has outputs");
if (height == 0) {
// Genesis block exception
CHECK_AND_ASSERT_MES(b.protocol_tx.version == 1, false, "Invalid genesis protocol transaction version");
CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 0, false, "genesis protocol transaction in the block has inputs");
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "genesis protocol transaction in the block has outputs");
return true;
}
if (!b.protocol_tx.vout.size()) {
// No money is minted, nothing to verify - bail out
// if nothing is created by this TX - check no money is included
CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs");
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;
}
// Get the circulating supply so we can verify
std::map<std::string, uint64_t> circ_supply;
if (hf_version >= HF_VERSION_ENABLE_CONVERT) {
circ_supply = get_db().get_circulating_supply();
}
// Build a map of outputs from the protocol_tx
std::map<crypto::public_key, std::tuple<std::string, uint64_t, uint64_t>> outputs;
for (auto& o : b.protocol_tx.vout) {
if (o.target.type() == typeid(txout_to_key)) {
txout_to_key out = boost::get<txout_to_key>(o.target);
CHECK_AND_ASSERT_MES(out.unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output");
outputs[out.key] = std::make_tuple(out.asset_type, o.amount, out.unlock_time);
} else if (o.target.type() == typeid(txout_to_tagged_key)) {
txout_to_tagged_key out = boost::get<txout_to_tagged_key>(o.target);
CHECK_AND_ASSERT_MES(out.unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output");
outputs[out.key] = std::make_tuple(out.asset_type, o.amount, out.unlock_time);
} else {
MERROR("Block at height: " << height << " attempting to add protocol transaction with invalid type " << o.target.type().name());
return false;
}
}
// Maintain a count of outputs that we have verified
std::vector<crypto::public_key> outputs_verified;
size_t tx_index = 0;
// Iterate over the block's transaction hashes, grabbing each
// from the tx_pool and validating them.
for (const auto& tx_tmp : txs)
{
// Get a ptr to the TX to simplify coding
const transaction* tx = &tx_tmp.first;
// Check to see if the TX exists in the DB - this probably duplicates the effort in our caller, but better to be sure
if (m_db->tx_exists(tx->hash))
{
MERROR("Block at height: " << height << " attempting to add transaction already in blockchain with id: " << tx->hash);
return false;
}
if (hf_version >= HF_VERSION_ENABLE_CONVERT) {
// Check to see if the TX is a conversion or not
if (tx->type != cryptonote::transaction_type::CONVERT) {
// Only conversion (and failed conversion, aka refund) TXs need to be verified - skip this TX
continue;
}
// Verify that the TX has an output in the protocol_tx to verify
if (outputs.count(tx->return_address) != 1) {
LOG_ERROR("Block at height: " << height << " - Failed to locate output for conversion TX id " << tx->hash << " - rejecting block");
return false;
}
// Get the output information
std::string output_asset_type;
uint64_t output_amount;
uint64_t output_unlock_time;
std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[tx->return_address];
// Verify the asset_type
if (tx->source_asset_type == output_asset_type) {
// Check the amount for REFUND
if (tx->amount_burnt != output_amount) {
LOG_ERROR("Block at height: " << height << " - Output amount does not match amount_burnt for refunded TX id " << tx->hash << " - rejecting block");
return false;
}
// Verified the refund successfully
outputs_verified.push_back(tx->return_address);
} else if (tx->destination_asset_type == output_asset_type) {
// Check the amount for CONVERT
// Verify the amount of the conversion
uint64_t amount_minted_check = 0, amount_slippage_check = 0;
bool ok = cryptonote::calculate_conversion(tx->source_asset_type, tx->destination_asset_type, tx->amount_burnt, tx->amount_slippage_limit, amount_minted_check, amount_slippage_check, circ_supply, b.pricing_record, hf_version);
if (!ok) {
LOG_ERROR("Block at height: " << height << " - Failed to calculate conversion for TX id " << tx->hash << " - rejecting block");
return false;
}
if (amount_minted_check != output_amount) {
LOG_ERROR("Block at height: " << height << " - Output amount does not match amount minted for converted TX id " << tx->hash << " - rejecting block");
return false;
}
// Verified the conversion successfully
outputs_verified.push_back(tx->return_address);
} else {
LOG_ERROR("Block at height: " << height << " - Output asset type incorrect: source " << tx->source_asset_type << ", dest " << tx->destination_asset_type << ", got " << output_asset_type << " - rejecting block");
return false;
}
}
}
// Can we have matured STAKE transactions yet?
uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD;
if (height > stake_lock_period) {
if (height <= stake_lock_period) {
return false;
}
// Yes - Get the staking data for the block that matured this time
cryptonote::yield_block_info ybi_matured;
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) {
// 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");
// 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) {
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;
}
}
// 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;
}
// Iterate the yield payouts, verifying as we go
for (const auto& payout: yield_payouts) {
// Do we have a singular matching output in tx.vout?
if (outputs.count(payout.first.return_address) != 1) {
LOG_ERROR("Block at height: " << height << " - Failed to locate output for matured TX id " << payout.first.tx_hash << " - rejecting block");
return false;
}
// Get the output information
std::string output_asset_type;
uint64_t output_amount;
uint64_t output_unlock_time;
std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[payout.first.return_address];
// Verify the asset type - must be SAL
if (output_asset_type != "SAL") {
LOG_ERROR("Block at height: " << height << " - Incorrect output asset type for matured TX id " << payout.first.tx_hash << " - rejecting block");
return false;
}
// Verify the amount
if (output_amount != payout.second) {
LOG_ERROR("Block at height: " << height << " - Incorrect output amount for matured TX id " << payout.first.tx_hash << " - rejecting block");
return false;
}
// Amount and return_address match our expectation
outputs_verified.push_back(payout.first.return_address);
}
}
}
// All candidates have been evaluated - make sure there are no other outputs that have not been catered for
if (outputs.size() != outputs_verified.size()) {
LOG_ERROR("Block at height: " << height << " - Incorrect number of outputs - expected " << outputs_verified.size() << " but received " << outputs.size() << " - rejecting block");
return false;
// Check we have the correct number of entries
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size() + audit_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting");
// go through each vout and validate
std::set<crypto::public_key> used_keys;
for (auto& o : b.protocol_tx.vout) {
// gather the output data
uint64_t out_amount;
uint64_t out_unlock_time;
std::string out_asset_type;
crypto::public_key out_key;
if (o.target.type() == typeid(txout_to_key)) {
txout_to_key out = boost::get<txout_to_key>(o.target);
out_unlock_time = out.unlock_time;
out_asset_type = out.asset_type;
out_key = out.key;
out_amount = o.amount;
} else if (o.target.type() == typeid(txout_to_tagged_key)) {
txout_to_tagged_key out = boost::get<txout_to_tagged_key>(o.target);
out_unlock_time = out.unlock_time;
out_asset_type = out.asset_type;
out_key = out.key;
out_amount = o.amount;
} else {
MERROR("Block at height: " << height << " attempting to add protocol transaction with invalid type " << o.target.type().name());
return false;
}
// Check if key has already been seen
if (used_keys.count(out_key) != 0) {
LOG_ERROR("Block at height: " << height << " - Duplicated output key " << out_key << " for protocol TX - aborting");
return false;
}
// Add key to list of already-seen
used_keys.insert(out_key);
// check if there is entry in the yield payouts or audit payouts for this output
std::string expected_output_asset_type = "SAL";
auto found_yield = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
return p.first.return_address == out_key;
});
auto found_audit = std::find_if(audit_payouts.begin(), audit_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
return p.first.return_address == out_key;
});
if (found_yield == yield_payouts.end() && found_audit == audit_payouts.end()) {
MERROR("Block at height: " << height << " - Failed to locate output for protocol TX - rejecting block");
return false;
} else if (found_audit == audit_payouts.end()) {
// 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(expected_output_asset_type == out_asset_type, false, "Incorrect asset type detected for protocol TX ouput - rejecting block");
}
// Everything checks out
@@ -1951,46 +1933,16 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
size_t txs_weight;
uint64_t fee;
/**
* Here is where the magic happens - determination of the payments for the protocol_tx
*
* We need to know the following:
* - address to send the funds to ("return_address")
* - asset_type being burnt
* - amount being burnt
* - asset_type being minted
*
* (All of this information should be provided by the txpool_tx_meta_t object)
*
* From that little lot, we can hopefully work out the slippage on all of the TXs, and
* therefore the amount to be minted for each TX, and who to pay it to, etc, etc.
*/
std::vector<txpool_tx_meta_t> protocol_metadata;
std::vector<cryptonote::protocol_data_entry> protocol_entries;
if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, b.major_version, b.pricing_record, circ_supply, protocol_metadata))
if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, b.major_version))
{
return false;
}
// Clone the txpool_tx_meta_t data into a more useable format
for (auto& meta: protocol_metadata) {
cryptonote::protocol_data_entry entry;
entry.amount_burnt = meta.amount_burnt;
entry.amount_minted = 0;
entry.amount_slippage_limit = meta.amount_slippage_limit;
entry.source_asset = asset_type_from_id(meta.source_asset_id);
entry.destination_asset = asset_type_from_id(meta.destination_asset_id);
entry.return_address = meta.return_address;
entry.type = meta.tx_type;
entry.P_change = meta.one_time_public_key;
entry.return_pubkey = meta.return_pubkey;
protocol_entries.push_back(entry);
}
// Check to see if there are any matured YIELD TXs
uint64_t yield_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD;
uint64_t start_height = (height > yield_lock_period) ? height - yield_lock_period - 1 : 0;
std::vector<cryptonote::protocol_data_entry> protocol_entries;
cryptonote::yield_block_info ybi_matured;
bool ok = get_ybi_entry(start_height, ybi_matured);
if (ok && ybi_matured.locked_coins_this_block > 0) {
@@ -2002,14 +1954,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;
@@ -2017,13 +1977,57 @@ 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;
address_parse_info treasury_address_info;
ok = cryptonote::get_account_address_from_str(treasury_address_info, m_nettype, get_config(m_nettype).TREASURY_ADDRESS);
CHECK_AND_ASSERT_MES(ok, false, "Failed to obtain treasury address info");
ok = construct_protocol_tx(height, protocol_fee, b.protocol_tx, protocol_entries, circ_supply, b.pricing_record, miner_address, treasury_address_info.address, b.major_version);
ok = construct_protocol_tx(height, b.protocol_tx, protocol_entries, b.major_version);
CHECK_AND_ASSERT_MES(ok, false, "Failed to construct protocol tx");
pool_cookie = m_tx_pool.cookie();
@@ -3489,9 +3493,9 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
}
*/
// from v4, forbid invalid pubkeys
if (hf_version >= 4) {
if (hf_version >= 1) {
for (const auto &o: tx.vout) {
crypto::public_key output_public_key;
if (!get_output_public_key(o, output_public_key)) {
@@ -3504,7 +3508,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
}
/*
// from v8, allow bulletproofs
if (hf_version < 8) {
if (tx.version >= 2) {
@@ -3603,10 +3607,9 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
}
*/
// from v16, forbid bulletproofs
if (hf_version > HF_VERSION_BULLETPROOF_PLUS) {
// from v1, forbid bulletproofs
if (hf_version >= HF_VERSION_BULLETPROOF_PLUS) {
if (tx.version >= 2) {
const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type);
if (bulletproof)
@@ -3617,11 +3620,35 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
}
*/
if (hf_version >= HF_VERSION_FULL_PROOFS) {
if (tx.type == cryptonote::transaction_type::TRANSFER) {
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 for TRANSFER TXs after v" + std::to_string(HF_VERSION_FULL_PROOFS));
MERROR_VER("FullProofs required after v" + std::to_string(HF_VERSION_FULL_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_FULL_PROOFS));
tvc.m_invalid_output = true;
return false;
}
@@ -3721,7 +3748,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());
@@ -3762,7 +3789,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)
{
@@ -3903,8 +3930,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)
{
@@ -3916,6 +3943,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;
@@ -3944,6 +3972,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));
@@ -4009,7 +4040,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!");
@@ -4040,6 +4071,20 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
// obviously, the original and simple rct APIs use a mixRing that's indexes
// in opposite orders, because it'd be too simple otherwise...
const rct::rctSig &rv = tx.rct_signatures;
// Check that after full proofs are enabled, the RCT version is set to enforce full proofs
if (hf_version == HF_VERSION_SALVIUM_ONE_PROOFS) {
if (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;
}
}
switch (rv.type)
{
case rct::RCTTypeNull: {
@@ -4053,6 +4098,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))
{
@@ -4130,22 +4176,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
MERROR_VER("Unsupported rct type: " << rv.type);
return false;
}
// for bulletproofs, check they're only multi-output after v8
if (rct::is_rct_bulletproof(rv.type))
{
if (hf_version < 8)
{
for (const rct::Bulletproof &proof: rv.p.bulletproofs)
{
if (proof.V.size() > 1)
{
MERROR_VER("Multi output bulletproofs are invalid before v8");
return false;
}
}
}
}
}
return true;
}
@@ -4451,6 +4481,57 @@ 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 = {};
// 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__);
@@ -4468,9 +4549,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));
}
@@ -5021,7 +5110,7 @@ leave:
TIME_MEASURE_FINISH(vmt);
TIME_MEASURE_START(vpt);
if(!validate_protocol_transaction(bl, blockchain_height, txs, m_hardfork->get_current_version()))
if(!validate_protocol_transaction(bl, blockchain_height, m_hardfork->get_current_version()))
{
MERROR_VER("Block with id: " << id << " has incorrect protocol transaction");
bvc.m_verifivation_failed = true;
@@ -5058,8 +5147,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;
@@ -5887,7 +5978,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);
+17 -2
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
*
@@ -1529,12 +1545,11 @@ namespace cryptonote
*
* @param b the block containing the miner transaction to be validated
* @param height the blockchain's weight
* @param txs a vector containing all the TXs and their blobs, needed to obtain tx_types, asset_types and burnt amounts
* @param version hard fork version for that transaction
*
* @return false if anything is found wrong with the protocol transaction, otherwise true
*/
bool validate_protocol_transaction(const block& b, uint64_t height, std::vector<std::pair<transaction, blobdata>>& txs, uint8_t hf_version);
bool validate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version);
/**
* @brief reverts the blockchain to its previous state following a failed switch
+22 -1
View File
@@ -923,6 +923,24 @@ namespace cryptonote
if (tx_info[n].tx->version < 2)
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_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);
tx_info[n].tvc.m_verifivation_failed = true;
tx_info[n].result = false;
return false;
}
}
switch (rv.type) {
case rct::RCTTypeNull:
// coinbase should not come here, so we reject for all other types
@@ -936,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
))
{
@@ -971,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");
@@ -997,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
))
{
+161 -176
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,19 +333,14 @@ namespace cryptonote
return true;
}
*/
//---------------------------------------------------------------
bool construct_protocol_tx(const size_t height,
uint64_t& protocol_fee,
transaction& tx,
std::vector<protocol_data_entry>& protocol_data,
std::map<std::string, uint64_t> circ_supply,
const oracle::pricing_record& pr,
const account_public_address &miner_address,
const account_public_address &treasury_address,
const uint8_t hf_version) {
// A vector to contain all of the additional _tx_secret_keys_
//std::vector<crypto::secret_key>& additional_tx_keys;
bool construct_protocol_tx(
const size_t height,
transaction& tx,
std::vector<protocol_data_entry>& protocol_data,
const uint8_t hf_version
) {
// Clear the TX contents
tx.set_null();
@@ -358,174 +354,33 @@ namespace cryptonote
if (!sort_tx_extra(tx.extra, tx.extra))
return false;
// Update the circulating_supply information, while keeping a count of amount to be created using txin_gen
std::map<std::string, uint64_t> txin_gen_totals;
uint64_t txin_gen_final = 0;
for (auto const& entry: protocol_data) {
if (!circ_supply.count(entry.source_asset)) {
LOG_ERROR("Circulating supply does not have " << entry.source_asset << " balance - invalid source_asset");
return false;
}
// Deduct the amount_burnt from the circulating_supply balance
circ_supply[entry.source_asset] -= entry.amount_burnt;
}
// Calculate the slippage for the output amounts
LOG_PRINT_L2("Creating protocol_tx...");
uint64_t slippage_total = 0;
std::vector<crypto::public_key> additional_tx_public_keys;
for (auto const& entry: protocol_data) {
if (entry.destination_asset == "BURN") {
// BURN TX - no slippage, no money minted - skip
continue;
}
// CONVERT TX
/*
// Create a secret TX key (= s)
crypto::secret_key s = keypair::generate(hw::get_device("default")).sec;
//additional_tx_keys.push_back(s);
// Now add the correct TX public key (= sP_change)
// This has to be done using smK() call because of g_k_d() performing a torsion clear
crypto::public_key txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(entry.P_change), rct::sk2rct(s)));
additional_tx_public_keys.push_back(txkey_pub);
// Calculate the actual return address, because the field we already have is actually the TX pubkey to use
// return address = Hs(syF || i)G + P_change = Hs(saP_change || i)G + P_change
// Generate the uniqueness for the input
size_t output_index = tx.vout.size();
// y = Hs(uniqueness)
ec_scalar y;
CHECK_AND_ASSERT_MES(cryptonote::calculate_uniqueness((cryptonote::transaction_type)(entry.type), entry.input_k_image, height, 0, y), false, "while creating protocol_tx outs: failed to calculate uniqueness");
rct::key key_y = (rct::key&)(y);
rct::key key_F = (rct::key&)(entry.return_address);
crypto::public_key syF = rct::rct2pk(rct::scalarmultKey(rct::scalarmultKey(key_F, key_y), rct::sk2rct(s)));
crypto::key_derivation derivation_syF = AUTO_VAL_INIT(derivation_syF);
std::memcpy(derivation_syF.data, syF.data, sizeof(crypto::key_derivation));
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
bool r = crypto::derive_public_key(derivation_syF, output_index, entry.P_change, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed to derive_public_key(" << derivation_syF << ", " << key_y << ", "<< entry.P_change << ")");
// Sanity checks
crypto::public_key P_change_verify = crypto::null_pkey;
r = crypto::derive_subaddress_public_key(out_eph_public_key, derivation_syF, output_index, P_change_verify);
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed sanity check calling derive_subaddress_public_key(" << out_eph_public_key << ", " << derivation_syF << ", " << key_y << ", " << P_change_verify << ")");
CHECK_AND_ASSERT_MES(entry.P_change == P_change_verify, false, "while creating protocol_tx outs: failed sanity check (keys do not match)");
*/
/*
LOG_ERROR("***************************************************************************************");
LOG_ERROR("output_index : " << output_index);
LOG_ERROR("P_change : " << entry.P_change);
LOG_ERROR("key_y : " << key_y);
LOG_ERROR("key_F : " << key_F);
LOG_ERROR("s : " << s);
LOG_ERROR("der. (syF) : " << derivation_syF);
LOG_ERROR("txkey_pub : " << txkey_pub);
LOG_ERROR("output_key : " << out_eph_public_key << " (derivation_syF, output_index, P_change)");
LOG_ERROR("P_change_ver : " << P_change_verify);
LOG_ERROR("***************************************************************************************");
*/
if (entry.type == cryptonote::transaction_type::CONVERT) {
// Now calculate the slippage, and decide if it is going to be converted or refunded
uint64_t amount_slippage = 0, amount_minted = 0;
bool ok = cryptonote::calculate_conversion(entry.source_asset, entry.destination_asset, entry.amount_burnt, entry.amount_slippage_limit, amount_minted, amount_slippage, circ_supply, pr, hf_version);
if (!ok) {
LOG_ERROR("failed to calculate slippage when trying to build protocol_tx");
return false;
}
if (amount_minted == 0) {
// REFUND
LOG_PRINT_L2("Conversion TX refunded - slippage too high");
txin_gen_totals[entry.source_asset] += entry.amount_burnt;
// Create the TX output for this refund
tx_out out;
//cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(entry.amount_burnt, entry.source_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 {
// CONVERTED
LOG_PRINT_L2("Conversion TX submitted - converted " << print_money(entry.amount_burnt) << " " << entry.source_asset << " to " << print_money(amount_minted) << " " << entry.destination_asset << "(slippage " << print_money(amount_slippage) << ")");
txin_gen_totals[entry.destination_asset] += amount_minted;
// Add the slippage to our total for the block
if (entry.source_asset == "SAL") {
slippage_total += amount_slippage;
} else {
// Convert the slippage into a SAL amount so we can pay a proportion to the miner
uint64_t conversion_rate = 0, amount_slippage_converted = 0;
ok = get_conversion_rate(pr, entry.source_asset, entry.destination_asset, conversion_rate);
CHECK_AND_ASSERT_MES(ok, false, "Failed to get conversion rate for miner payout");
ok = get_converted_amount(conversion_rate, amount_slippage, amount_slippage_converted);
CHECK_AND_ASSERT_MES(ok, false, "Failed to get converted slippage amount for miner payout");
slippage_total += amount_slippage_converted;
}
// Create the TX output for this conversion
tx_out out;
//cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(amount_minted, 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::STAKE) {
if (entry.type == cryptonote::transaction_type::STAKE) {
// PAYOUT
LOG_PRINT_L2("Yield TX payout submitted " << entry.amount_burnt << entry.source_asset);
txin_gen_totals[entry.source_asset] += entry.amount_burnt;
// Create the TX output for this refund
tx_out out;
//cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, 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);
}
}
// Add in all of the additional TX pubkeys we need to process the payments
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
if (slippage_total > 0) {
// Add a payout for the miner
uint64_t slippage_miner = slippage_total / 5;
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{txkey.sec} << ")");
r = crypto::derive_public_key(derivation, tx.vout.size(), miner_address.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
tx_out out_miner;
cryptonote::set_tx_out(slippage_miner, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, false, crypto::view_tag{}, out_miner);
tx.vout.push_back(out_miner);
// Add a payout for the treasury
crypto::key_derivation derivation_treasury = AUTO_VAL_INIT(derivation_treasury);
crypto::public_key out_eph_public_key_treasury = AUTO_VAL_INIT(out_eph_public_key_treasury);
r = crypto::generate_key_derivation(treasury_address.m_view_public_key, txkey.sec, derivation_treasury);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << treasury_address.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{txkey.sec} << ")");
r = crypto::derive_public_key(derivation_treasury, tx.vout.size(), treasury_address.m_spend_public_key, out_eph_public_key_treasury);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
uint64_t slippage_treasury = slippage_miner >> 1;
tx_out out_treasury;
cryptonote::set_tx_out(slippage_treasury, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key_treasury, false, crypto::view_tag{}, out_treasury);
tx.vout.push_back(out_treasury);
}
// Create the txin_gen now
txin_gen in;
in.height = height;
@@ -590,6 +445,9 @@ namespace cryptonote
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
case HF_VERSION_FULL_PROOFS:
case HF_VERSION_ENFORCE_FULL_PROOFS:
case HF_VERSION_SHUTDOWN_USER_TXS:
case HF_VERSION_SALVIUM_ONE_PROOFS:
// 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;
@@ -600,7 +458,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 {
@@ -646,6 +507,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();
@@ -757,6 +695,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;
@@ -774,14 +729,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) )
{
@@ -807,6 +774,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{});
@@ -825,6 +800,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
@@ -860,6 +836,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);
@@ -880,11 +857,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("*****************************************************************************");
@@ -901,7 +886,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);
@@ -991,14 +976,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");
@@ -1186,11 +1171,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;
}
@@ -1215,6 +1199,7 @@ namespace cryptonote
outSk,
rct_config,
hwdev,
salvium_data,
rct::sk2rct(x_change),
change_index,
key_yF
+6 -1
View File
@@ -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
@@ -67,7 +69,7 @@ namespace cryptonote
};
//---------------------------------------------------------------
bool construct_protocol_tx(const size_t height, uint64_t& protocol_fee, transaction& tx, std::vector<protocol_data_entry>& protocol_data, std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const account_public_address &miner_address, const account_public_address &treasury_address, const uint8_t hf_version);
bool construct_protocol_tx(const size_t height, transaction& tx, std::vector<protocol_data_entry>& protocol_data, const uint8_t hf_version);
//---------------------------------------------------------------
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
@@ -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);
+16 -9
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;
@@ -1614,7 +1623,7 @@ namespace cryptonote
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate
bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version, oracle::pricing_record& pr, std::map<std::string, uint64_t>& circ_supply, std::vector<txpool_tx_meta_t>& protocol_metadata)
bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
@@ -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))
@@ -1744,14 +1759,6 @@ namespace cryptonote
continue;
}
// Check what the TX type is - only CONVERT needs a cash_value
if (meta.source_asset_id == meta.destination_asset_id) {
// TRANSFER
} else {
// BURN OR CONVERT (both require inclusion in the protocol_tx calculation for circ_supply purposes)
protocol_metadata.push_back(meta);
}
bl.tx_hashes.push_back(sorted_it->second);
total_weight += meta.weight;
fee += meta.fee;
+1 -4
View File
@@ -227,13 +227,10 @@ namespace cryptonote
* @param fee return-by-reference the total of fees from the included transactions
* @param expected_reward return-by-reference the total reward awarded to the miner finding this block, including transaction fees
* @param version hard fork version to use for consensus rules
* @param pr the current pricing record
* @param circ_cupply the circulating supply information for all asset types
* @param protocol_metadata the TX-specific data needed to create conversion outputs in the protocol TX (including converted amounts and refunds)
*
* @return true
*/
bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version, oracle::pricing_record& pr, std::map<std::string, uint64_t>& circ_supply, std::vector<txpool_tx_meta_t>& protocol_metadata);
bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version);
/**
* @brief get a list of all transactions in the pool
@@ -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
};
}
+22 -1
View File
@@ -36,7 +36,19 @@ const hardfork_t mainnet_hard_forks[] = {
{ 1, 1, 0, 1341378000 },
// version 2 starts from block 89800, which is on or around the 4th of November, 2024. Fork time finalised on 2024-10-21. No fork voting occurs for the v2 fork.
{ 2, 89800, 0, 1729518000 },
{ 2, 89800, 0, 1729518000 },
// version 3 starts from block 121100, which is on or around the 19th of December, 2024. Fork time finalised on 2024-12-18. No fork voting occurs for the v3 fork.
{ 3, 121100, 0, 1734516900 },
// 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 },
};
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);
@@ -50,6 +62,15 @@ 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) starts from block 815
{ 6, 815, 0, 1734608000 },
};
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
+84 -8
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;
}
@@ -543,6 +545,9 @@ static bool compute_keys_for_destinations(
if (destinations[i].is_change) {
found_change = true;
change_index = output_index; // Store the change_index - we will need this
// Calculate the change spend key (x_change)
}
output_index++;
}
@@ -666,6 +671,8 @@ static void make_new_range_proofs(const int bp_version,
sigs.bulletproofs.push_back(rct::bulletproof_PROVE(output_amounts, output_amount_masks));
else if (bp_version == 4)
sigs.bulletproofs_plus.push_back(rct::bulletproof_plus_PROVE(output_amounts, output_amount_masks));
else if (bp_version == 5)
sigs.bulletproofs_plus.push_back(rct::bulletproof_plus_PROVE(output_amounts, output_amount_masks));
}
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
@@ -701,6 +708,12 @@ static bool try_reconstruct_range_proofs(const int bp_version,
return false;
return rct::bulletproof_plus_VERIFY(reconstructed_sigs.bulletproofs_plus);
}
else if (bp_version == 5)
{
if (not try_reconstruct_range_proofs(original_sigs.bulletproofs_plus, reconstructed_sigs.bulletproofs_plus))
return false;
return rct::bulletproof_plus_VERIFY(reconstructed_sigs.bulletproofs_plus);
}
return false;
}
@@ -818,7 +831,10 @@ static bool set_tx_rct_signatures(
const bool reconstruction,
cryptonote::transaction& unsigned_tx,
std::vector<CLSAG_context_t>& CLSAG_contexts,
rct::keyV& cached_w
rct::keyV& cached_w,
const uint8_t change_index,
const rct::key& x_change,
const rct::key& hs_yF
)
{
if (rct_config.bp_version != 3 &&
@@ -918,16 +934,39 @@ 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 = 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.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.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.salvium_data.sa_proof, output_public_keys[change_index], hs_yF), "SAProof_Ver() failed on recently created proof");
#endif
}
*/
}
// check balance if reconstructing the tx
else {
rv.p.pseudoOuts = unsigned_tx.rct_signatures.p.pseudoOuts;
rv.pr_proof = unsigned_tx.rct_signatures.pr_proof; // should verify this during reconstruction
rv.sa_proof = unsigned_tx.rct_signatures.sa_proof; // should verify this during reconstruction
rv.p_r = unsigned_tx.rct_signatures.p_r;
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.salvium_data.pr_proof = unsigned_tx.rct_signatures.salvium_data.pr_proof;
/*
if (!rct::SAProof_Ver(unsigned_tx.rct_signatures.salvium_data.sa_proof, output_public_keys[change_index], hs_yF))
return false;
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;
}
if (num_sources != rv.p.pseudoOuts.size())
return false;
rct::key balance_accumulator = rct::scalarmultH(rct::d2h(fee));
@@ -1172,6 +1211,8 @@ bool tx_builder_ringct_t::init(
// Check that the change element was found
if (!found_change)
return false;
//
// add inputs to tx
set_tx_inputs(sources, unsigned_tx);
@@ -1186,6 +1227,8 @@ bool tx_builder_ringct_t::init(
if (not set_tx_outputs_result)
return false;
rct::key hs_yF;
rct::key x_change;
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && unsigned_tx.type == cryptonote::transaction_type::TRANSFER) {
// Get the output public key for the change output
@@ -1221,6 +1264,7 @@ bool tx_builder_ringct_t::init(
rct::key key_F = rct::scalarmultKey(key_aP_change, key_inv_y);
rct::key key_verify = rct::scalarmultKey(key_F, key_y);
CHECK_AND_ASSERT_MES(key_verify == key_aP_change, false, "at get_return_address: failed to verify invert() function with smK() approach");
hs_yF = rct::hash_to_scalar(key_verify);
// Push the F point into the TX vector of F points
if (not reconstruction)
@@ -1241,6 +1285,38 @@ bool tx_builder_ringct_t::init(
unsigned_tx.return_address_change_mask.push_back(eci_data);
}
if (hf_version >= HF_VERSION_FULL_PROOFS) {
// Get the secret spend key for the change element
crypto::secret_key spend_skey = crypto::null_skey;
for (const auto &multisig_key : account_keys.m_multisig_keys) {
sc_add((unsigned char*)spend_skey.data,
(const unsigned char*)multisig_key.data,
(const unsigned char*)spend_skey.data);
}
// Calculate z_i (the shared secret between sender and ourselves for the original TX)
crypto::public_key txkey_pub = crypto::null_pkey; // R
const std::vector<crypto::public_key> in_additional_tx_pub_keys = cryptonote::get_additional_tx_pub_keys_from_extra(unsigned_tx);
if (in_additional_tx_pub_keys.size() != 0) {
CHECK_AND_ASSERT_MES(in_additional_tx_pub_keys.size() == unsigned_tx.vout.size(), false, "incorrect number of additional TX pubkeys in origin TX for return_payment");
txkey_pub = in_additional_tx_pub_keys[change_index];
} else {
txkey_pub = cryptonote::get_tx_pub_key_from_extra(unsigned_tx);
}
// Obtain a separate key_derivation for the P_change output
// (using the TX public key and the sender's private view key)
hw::device &hwdev = account_keys.get_device();
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(txkey_pub, account_keys.m_view_secret_key, derivation), false, "Failed to generate key_derivation for P_change");
// Calculate the secret spend key "x_change" for the P_change output
crypto::secret_key s_change = crypto::null_skey;
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation, change_index, spend_skey, s_change), false, "Failed to derive secret key for P_change");
x_change = rct::sk2rct(s_change);
}
} else if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER || unsigned_tx.type == cryptonote::transaction_type::STAKE) {
// Get the tx public key
@@ -1253,7 +1329,7 @@ bool tx_builder_ringct_t::init(
// prepare input signatures
if (not set_tx_rct_signatures(fee, sources, destination_amounts, input_secret_keys, output_public_keys, output_amount_secret_keys,
rct_config, reconstruction, unsigned_tx, CLSAG_contexts, cached_w))
rct_config, reconstruction, unsigned_tx, CLSAG_contexts, cached_w, change_index, x_change, hs_yF))
return false;
initialized = true;
+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;
}
+81 -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,29 +1372,46 @@ 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
}
*/
key full_message = get_pre_mlsag_hash(rv,hwdev);
@@ -1426,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
@@ -1439,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
@@ -1528,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)
@@ -1654,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);
@@ -1694,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
@@ -1726,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;
@@ -1750,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;
+3 -1
View File
@@ -88,7 +88,7 @@ namespace rct {
zk_proof PRProof_Gen(const rct::key &difference);
bool PRProof_Ver(const rct::key &C, const zk_proof &proof);
zk_proof SAProof_Gen(const keyV &P, const key &x_change, const key &key_yF);
zk_proof SAProof_Gen(const key &P, const key &x_change, const key &key_yF);
bool SAProof_Ver(const zk_proof &proof, const key &P, const key &key_yF);
//proveRange and verRange
@@ -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);
+171 -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,48 @@ 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;
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());
}
} 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 +7115,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 +7275,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 +7316,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 +7446,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 +8108,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 +8142,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 +8270,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 +8334,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 +8344,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 +8368,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 +8418,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 +8509,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 +8517,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.0-rc3"
#define DEF_SALVIUM_VERSION "0.9.0"
#define DEF_MONERO_VERSION_TAG "release"
#define DEF_MONERO_VERSION "0.18.3.3"
#define DEF_MONERO_RELEASE_NAME "Zero"
+153 -54
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;
@@ -2856,6 +2869,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
update_multisig_rescan_info(*m_multisig_rescan_k, *m_multisig_rescan_info, m_transfers.size() - 1);
}
/*
// Verify the spend authority proof
if (!verify_spend_authority_proof(tx, o, tx_scan_info[o])) {
// Freeze the output
@@ -2863,6 +2877,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
LOG_ERROR("Please review the transaction and verify that the sender is someone you trust before thawing this payment.");
td.m_frozen = true;
}
*/
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (!ignore_callbacks && 0 != m_callback)
@@ -2875,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
@@ -2885,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) {
@@ -2980,7 +2996,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
THROW_WALLET_EXCEPTION_IF(td.get_public_key() != tx_scan_info[o].in_ephemeral.pub, error::wallet_internal_error, "Inconsistent public keys");
THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status");
/*
// Verify the spend authority proof
if (!verify_spend_authority_proof(tx, o, tx_scan_info[o])) {
// Freeze the output
@@ -2988,6 +3005,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
LOG_ERROR("Please review the transaction and verify that the sender is someone you trust before thawing this payment.");
td.m_frozen = true;
}
*/
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (!ignore_callbacks && 0 != m_callback)
@@ -7011,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;
}
@@ -7940,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");
@@ -9459,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;
@@ -9721,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)
@@ -9740,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");
}
@@ -9892,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;
@@ -10097,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
@@ -10148,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;
@@ -10178,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;
@@ -10226,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);
}
@@ -10648,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;
@@ -10691,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:
@@ -11323,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;
}
@@ -11347,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);
@@ -11409,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)
@@ -11437,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);
@@ -11450,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;
@@ -11590,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();
@@ -11662,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;
}
@@ -12287,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];
@@ -12295,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");
@@ -12511,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");
@@ -12525,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)
@@ -12778,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 +=
@@ -13028,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");
@@ -13205,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;
@@ -13660,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,
@@ -14254,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);
@@ -14264,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);
@@ -14363,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;
@@ -14372,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);
@@ -14581,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
@@ -14591,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());