Compare commits
31 Commits
v0.9.0-rc2
...
v0.9.3
| Author | SHA1 | Date | |
|---|---|---|---|
| aa64124c28 | |||
| bc7db51f03 | |||
| 6889321361 | |||
| 3cb473132e | |||
| b298f542a6 | |||
| eb9f799b8b | |||
| 8bf35db67e | |||
| aeef1a6677 | |||
| ee586a3fca | |||
| 19be3a6146 | |||
| 64a69268fe | |||
| 7312652540 | |||
| 8cd587ec54 | |||
| 62c43a4ed2 | |||
| 0180051a8c | |||
| a7c1ba652b | |||
| 2a4d08b67f | |||
| 3fc5ea3543 | |||
| 3b72dc0555 | |||
| b48c86afe0 | |||
| 0f88d91fa0 | |||
| 4b594142ca | |||
| 29e435bd39 | |||
| 4abde92c1a | |||
| dd23331df9 | |||
| 7d2025bc19 | |||
| a01422a5e0 | |||
| e68f7f46ed | |||
| b87c243da1 | |||
| 49fd907073 | |||
| 8f5111aeda |
@@ -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++ ###
|
||||
|
||||
@@ -14,3 +14,6 @@
|
||||
[submodule "external/miniupnp"]
|
||||
path = external/miniupnp
|
||||
url = https://github.com/miniupnp/miniupnp
|
||||
[submodule "external/mx25519"]
|
||||
path = external/mx25519
|
||||
url = https://github.com/tevador/mx25519
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Salvium Zero v0.7.2
|
||||
# Salvium Zero v0.9.3
|
||||
|
||||
Copyright (c) 2023-2024, Salvium
|
||||
Portions Copyright (c) 2014-2023, The Monero Project
|
||||
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
|
||||
|
||||
```bash
|
||||
cd salvium
|
||||
git checkout v0.7.0
|
||||
git checkout v0.9.3
|
||||
make
|
||||
```
|
||||
|
||||
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
|
||||
```bash
|
||||
git clone https://github.com/salvium/salvium
|
||||
cd salvium
|
||||
git checkout v0.7.0
|
||||
git checkout v0.9.3
|
||||
```
|
||||
|
||||
* Build:
|
||||
@@ -370,10 +370,10 @@ application.
|
||||
cd salvium
|
||||
```
|
||||
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.7.0'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.3'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.7.0
|
||||
git checkout v0.9.3
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -215,6 +215,9 @@ namespace
|
||||
* yield_block_data block height {slippage_coins, locked_coins, lc_total, network_health}
|
||||
* yield_tx_data block height {txn hash, locked_coins, return_address}
|
||||
*
|
||||
* audit_block_data block height {locked_coins, lc_total}
|
||||
* audit_tx_data block height {txn hash, locked_coins, return_address}
|
||||
*
|
||||
* Note: where the data items are of uniform size, DUPFIXED tables have
|
||||
* been used to save space. In most of these cases, a dummy "zerokval"
|
||||
* key is used when accessing the table; the Key listed above will be
|
||||
@@ -289,6 +292,8 @@ const char* const LMDB_CIRC_SUPPLY_TALLY = "circ_supply_tally";
|
||||
*/
|
||||
const char* const LMDB_YIELD_TXS = "yield_txs";
|
||||
const char* const LMDB_YIELD_BLOCKS = "yield_blocks";
|
||||
const char* const LMDB_AUDIT_TXS = "audit_txs";
|
||||
const char* const LMDB_AUDIT_BLOCKS = "audit_blocks";
|
||||
|
||||
const char zerokey[8] = {0};
|
||||
const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey };
|
||||
@@ -800,6 +805,75 @@ estim:
|
||||
return threshold_size;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_audit_block_info(const uint64_t height, audit_block_info& abi) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
// Clear the ABI, just in case
|
||||
std::memset(&abi, 0, sizeof(struct audit_block_info));
|
||||
|
||||
// Query for the matured AUDIT_BLOCK_INFO information
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(audit_blocks);
|
||||
|
||||
MDB_val v;
|
||||
MDB_val_set(k, height);
|
||||
int ret = mdb_cursor_get(m_cur_audit_blocks, &k, &v, MDB_SET);
|
||||
if (ret == MDB_NOTFOUND) {
|
||||
LOG_ERROR("Failed to locate ABI for block height " << height);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit block info: ", ret).c_str()));
|
||||
|
||||
audit_block_info *p = (audit_block_info*)v.mv_data;
|
||||
abi = *p;
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
// Return success to caller
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
// Clear the container
|
||||
ati_container.clear();
|
||||
|
||||
// Query for the (presumably matured) AUDIT_TX_INFO information (we actually reuse YIELD_TX_INFO for this)
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(audit_txs);
|
||||
|
||||
MDB_val v;
|
||||
MDB_val_set(k, height);
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
while (1)
|
||||
{
|
||||
int ret = mdb_cursor_get(m_cur_audit_txs, &k, &v, op);
|
||||
op = MDB_NEXT_DUP;
|
||||
if (ret == MDB_NOTFOUND)
|
||||
break;
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit TX info: ", ret).c_str()));
|
||||
|
||||
// Get the data
|
||||
yield_tx_info *p = (yield_tx_info*)v.mv_data;
|
||||
// Push result back into the container
|
||||
ati_container.emplace_back(*p);
|
||||
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
|
||||
ati_container.back().block_height = height;
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
// Return success to caller
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_yield_block_info(const uint64_t height, yield_block_info& ybi) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
@@ -855,9 +929,12 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate yield TX info: ", ret).c_str()));
|
||||
|
||||
// Push result back into the container
|
||||
// Get the data
|
||||
yield_tx_info *p = (yield_tx_info*)v.mv_data;
|
||||
// Push result back into the container
|
||||
yti_container.emplace_back(*p);
|
||||
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
|
||||
yti_container.back().block_height = height;
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
@@ -866,7 +943,7 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi)
|
||||
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, uint64_t audit_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
@@ -896,6 +973,18 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
|
||||
|
||||
int result = 0;
|
||||
|
||||
// Create the AUDIT_BLOCK_INFO instance for this block
|
||||
CURSOR(audit_blocks)
|
||||
abi.block_height = m_height;
|
||||
abi.locked_coins_this_block = audit_total;
|
||||
|
||||
// Put the YBI into the table
|
||||
MDB_val_set(key, m_height);
|
||||
MDB_val_set(abi_val, abi);
|
||||
result = mdb_cursor_put(m_cur_audit_blocks, &key, &abi_val, MDB_APPEND);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to add ABI to db: ", result).c_str()));
|
||||
|
||||
CURSOR(yield_blocks)
|
||||
yield_block_info ybi_matured, ybi_prev;
|
||||
uint64_t yield_lock_period = cryptonote::get_config(nettype).STAKE_LOCK_PERIOD;
|
||||
@@ -932,7 +1021,6 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
|
||||
ybi.network_health_percentage = 100;
|
||||
|
||||
// Put the YBI into the table
|
||||
MDB_val_set(key, m_height);
|
||||
MDB_val_set(ybi_val, ybi);
|
||||
result = mdb_cursor_put(m_cur_yield_blocks, &key, &ybi_val, MDB_APPEND);
|
||||
if (result)
|
||||
@@ -1004,6 +1092,7 @@ void BlockchainLMDB::remove_block()
|
||||
CURSOR(blocks)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_blocks)
|
||||
CURSOR(audit_blocks)
|
||||
MDB_val_copy<uint64_t> k(m_height - 1);
|
||||
MDB_val h = k;
|
||||
if ((result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &h, MDB_GET_BOTH)))
|
||||
@@ -1031,6 +1120,11 @@ void BlockchainLMDB::remove_block()
|
||||
throw1(BLOCK_DNE(lmdb_error("Attempting to remove yield block info that's not in the db: ", result).c_str()));
|
||||
if ((result = mdb_cursor_del(m_cur_yield_blocks, 0)))
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of yield block info to db transaction: ", result).c_str()));
|
||||
|
||||
// Is the block within an audit window?
|
||||
if ((result = mdb_cursor_get(m_cur_audit_blocks, &k2, NULL, MDB_SET)) == 0)
|
||||
if ((result = mdb_cursor_del(m_cur_audit_blocks, 0)))
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit block info to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
boost::multiprecision::int128_t
|
||||
@@ -1116,6 +1210,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
CURSOR(circ_supply)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_txs)
|
||||
CURSOR(audit_txs)
|
||||
|
||||
MDB_val_set(val_tx_id, tx_id);
|
||||
MDB_val_set(val_h, tx_hash);
|
||||
@@ -1183,13 +1278,19 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
throw0(DB_ERROR(lmdb_error("Failed to add prunable tx prunable hash to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
|
||||
if (tx.type == cryptonote::transaction_type::MINER) {
|
||||
|
||||
// Update the circulating supply tally because of potentially burnt block_reward proportion
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
|
||||
std::string miner_asset_type = "SAL";
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
miner_asset_type = "SAL1";
|
||||
}
|
||||
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result && (m_height>0 || result != MDB_NOTFOUND))
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally;
|
||||
for (const auto& out: tx.vout) {
|
||||
@@ -1203,20 +1304,44 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent overflow
|
||||
if (burn_tally > burn_tally + tx.amount_burnt)
|
||||
throw0(DB_ERROR("burn overflow detected when adding miner_tx for db transaction"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent underflow
|
||||
if (source_tally < final_source_tally)
|
||||
throw0(DB_ERROR("numeric underflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally > final_burn_tally)
|
||||
throw0(DB_ERROR("burn overflow detected when adding tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
@@ -1240,17 +1365,25 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
MDB_val_copy<uint64_t> source_idx(asset.first);
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result)
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("minted asset not found"));
|
||||
else if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
if (source_tally > source_tally + asset.second)
|
||||
throw0(DB_ERROR("add_transaction_data() - mint overflow"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally + asset.second;
|
||||
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
|
||||
if (source_tally == 0 && result == MDB_NOTFOUND) {
|
||||
if (tx.source_asset_type == "SAL") {
|
||||
final_source_tally += coinbase;
|
||||
}
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before burn =" << source_tally.str() << "\n\tTally after burn =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
if (burn_tally < asset.second)
|
||||
throw0(DB_ERROR("add_transaction_data() - burn underflow"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1308,6 +1441,60 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx yield data to db transaction: ", result).c_str() ));
|
||||
}
|
||||
|
||||
// Is there audit_tx data to add?
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// Create the object we are going to write to the database
|
||||
yield_tx_info audit_data;
|
||||
audit_data.block_height = m_height;
|
||||
audit_data.tx_hash = tx_hash;
|
||||
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
|
||||
if (tx.return_address == crypto::null_pkey)
|
||||
throw0(DB_ERROR("missing return_address entry (needed to create audit data for PROTOCOL_TX) - v2 STAKE"));
|
||||
audit_data.return_address = tx.return_address;
|
||||
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
if (tx.return_address_list.empty())
|
||||
throw0(DB_ERROR("no return_address_list entry (needed to create audit data for the PROTOCOL_TX)"));
|
||||
else if (tx.return_address_list.size() > 1)
|
||||
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create audit data for the PROTOCOL_TX)"));
|
||||
audit_data.return_address = tx.return_address_list[0];
|
||||
}
|
||||
audit_data.locked_coins = tx.amount_burnt;
|
||||
if (tx.vin.empty())
|
||||
throw0(DB_ERROR("tx.vin is empty (needed to create audit data for the PROTOCOL_TX)"));
|
||||
if (tx.vin[0].type() != typeid(cryptonote::txin_to_key))
|
||||
throw0(DB_ERROR("tx.vin[0] is wrong type (needed to create audit data for the PROTOCOL_TX)"));
|
||||
audit_data.return_pubkey = tx.return_pubkey;
|
||||
if (tx.vout.size() != 1)
|
||||
throw0(DB_ERROR("tx.vout is wrong size (needed to create audit data for the PROTOCOL_TX)"));
|
||||
if (!cryptonote::get_output_public_key(tx.vout[0], audit_data.P_change))
|
||||
throw0(DB_ERROR("failed to get P_change from tx.vout[0] (needed to create audit data for the PROTOCOL_TX)"));
|
||||
|
||||
// Because LMDB is shockingly bad at handling duplicates, we have resorted to using a counter of elements
|
||||
// in the first element of the struct.
|
||||
MDB_val data;
|
||||
MDB_val_set(val_height, m_height);
|
||||
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &data, MDB_SET);
|
||||
if (!result)
|
||||
{
|
||||
mdb_size_t num_elems = 0;
|
||||
result = mdb_cursor_count(m_cur_audit_txs, &num_elems);
|
||||
if (result)
|
||||
throw0(DB_ERROR(std::string("Failed to get number of audit TXs for height: ").append(mdb_strerror(result)).c_str()));
|
||||
audit_data.block_height = num_elems;
|
||||
}
|
||||
else if (result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str()));
|
||||
else
|
||||
audit_data.block_height = 0;
|
||||
|
||||
// Now we know how many there are, write out the data to the DB
|
||||
MDB_val_set(val_audit_tx_data, audit_data);
|
||||
result = mdb_cursor_put(m_cur_audit_txs, &val_height, &val_audit_tx_data, MDB_APPENDDUP);
|
||||
if (result)
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx audit data to db transaction: ", result).c_str() ));
|
||||
}
|
||||
|
||||
return tx_id;
|
||||
}
|
||||
|
||||
@@ -1330,6 +1517,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
CURSOR(tx_outputs)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_txs)
|
||||
CURSOR(audit_txs)
|
||||
|
||||
MDB_val_set(val_h, tx_hash);
|
||||
|
||||
@@ -1373,42 +1561,70 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of prunable hash tx to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
|
||||
if (tx.type == cryptonote::transaction_type::MINER) {
|
||||
|
||||
// Update the circulating supply tally because of potentially burnt block_reward proportion
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
|
||||
std::string miner_asset_type = "SAL";
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
miner_asset_type = "SAL1";
|
||||
}
|
||||
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result && (m_height>0 || result != MDB_NOTFOUND))
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("remove_transaction_data() - Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally;
|
||||
for (const auto& out: tx.vout) {
|
||||
|
||||
// Sanity check - prevent underflow
|
||||
if (final_source_tally < final_source_tally - out.amount)
|
||||
throw0(DB_ERROR("remove_transaction_data() - numeric underflow detected when removing miner_tx for db transaction"));
|
||||
throw0(DB_ERROR("numeric underflow detected when removing miner_tx for db transaction"));
|
||||
|
||||
// Fetch the amount for this output
|
||||
final_source_tally -= out.amount;
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally < tx.amount_burnt)
|
||||
throw0(DB_ERROR("burn underflow detected when removing miner_tx for db transaction"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
|
||||
// Sanity check - prevent overflow
|
||||
if (source_tally > source_tally + tx.amount_burnt + tx.rct_signatures.txnFee)
|
||||
throw0(DB_ERROR("remove_transaction_data() - numeric overflow detected when processing C/B/S for db transaction"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent overflow
|
||||
if (source_tally > final_source_tally)
|
||||
throw0(DB_ERROR("numeric overflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before remint =" << source_tally.str() << "\n\tTally after remint =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally < (tx.amount_burnt + tx.rct_signatures.txnFee))
|
||||
throw0(DB_ERROR("burn underflow detected when removing tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
@@ -1422,7 +1638,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
bool ok = cryptonote::get_output_asset_type(out, asset_type);
|
||||
if (!ok)
|
||||
throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)"));
|
||||
|
||||
minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount;
|
||||
}
|
||||
|
||||
@@ -1434,12 +1649,24 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
|
||||
throw0(DB_ERROR("minted asset not found"));
|
||||
else if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
if (source_tally < asset.second)
|
||||
throw0(DB_ERROR("remove_transaction_data() - mint underflow"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before undoing mint =" << source_tally.str() << "\n\tTally after undoing mint =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
if (burn_tally > burn_tally + asset.second)
|
||||
throw0(DB_ERROR("remove_transaction_data() - burn overflow"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
}
|
||||
remove_tx_outputs(tip->data.tx_id, tx);
|
||||
@@ -1456,7 +1683,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
// SRCG: The following code is designed to clean up the STAKE transactions, but it is very poorly written
|
||||
// SRCG: The following code is designed to clean up AUDIT+STAKE transactions, but it is very poorly written
|
||||
// Since transactions are ALWAYS supposed to be created in order, it stands that they should ALWAYS be
|
||||
// removed in REVERSE ORDER. Yet the following loop starts from the beginning - this is the worst possible
|
||||
// implementation in performance terms, since it will ALWAYS take the longest possible time to remove the
|
||||
@@ -1464,6 +1691,30 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
|
||||
// RECODE TO START FROM THE END OF THE DATABASE TABLE, AND THROW AN EXCEPTION IF YOU DO NOT MATCH FIRST TIME!
|
||||
|
||||
// Is there audit_tx data to remove?
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// Remove any yield_tx data for this transaction
|
||||
MDB_val_set(val_height, m_height);
|
||||
MDB_val v;
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
while (1) {
|
||||
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &v, op);
|
||||
if (result == MDB_NOTFOUND) {
|
||||
throw1(DB_ERROR("Failed to locate audit tx for removal from db transaction"));
|
||||
} else if (result) {
|
||||
throw1(DB_ERROR(lmdb_error("Failed to locate audit_tx data for removal: ", result).c_str()));
|
||||
}
|
||||
op = MDB_NEXT_DUP;
|
||||
const yield_tx_info ati = *(const yield_tx_info*)v.mv_data;
|
||||
if (ati.tx_hash == tx_hash) {
|
||||
result = mdb_cursor_del(m_cur_audit_txs, 0);
|
||||
if (result)
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit_tx data to db transaction: ", result).c_str()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is there yield_tx data to remove?
|
||||
if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
// Remove any yield_tx data for this transaction
|
||||
@@ -1970,6 +2221,9 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
lmdb_db_open(txn, LMDB_YIELD_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_yield_txs, "Failed to open db handle for m_yield_txs");
|
||||
lmdb_db_open(txn, LMDB_YIELD_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_yield_blocks, "Failed to open db handle for m_yield_blocks");
|
||||
|
||||
lmdb_db_open(txn, LMDB_AUDIT_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_audit_txs, "Failed to open db handle for m_audit_txs");
|
||||
lmdb_db_open(txn, LMDB_AUDIT_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_audit_blocks, "Failed to open db handle for m_audit_blocks");
|
||||
|
||||
mdb_set_dupsort(txn, m_spent_keys, compare_hash32);
|
||||
mdb_set_dupsort(txn, m_block_heights, compare_hash32);
|
||||
mdb_set_dupsort(txn, m_tx_indices, compare_hash32);
|
||||
@@ -1993,6 +2247,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
mdb_set_compare(txn, m_circ_supply_tally, compare_uint64);
|
||||
|
||||
mdb_set_dupsort(txn, m_yield_txs, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_audit_txs, compare_uint64);
|
||||
|
||||
if (!(mdb_flags & MDB_RDONLY))
|
||||
{
|
||||
@@ -2174,6 +2429,10 @@ void BlockchainLMDB::reset()
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_txs: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_yield_blocks, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_blocks: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_audit_txs, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_txs: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_audit_blocks, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_blocks: ", result).c_str()));
|
||||
|
||||
// init with current version
|
||||
MDB_val_str(k, "version");
|
||||
@@ -3516,9 +3775,14 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
|
||||
// Check for SAL - we need to adjust the total for them
|
||||
if (currency_type == 0) {
|
||||
// Get the current circulating supply for SAL
|
||||
amount += m_coinbase;
|
||||
//amount += m_coinbase;
|
||||
}
|
||||
|
||||
if (amount < 0) {
|
||||
// Negative number can't be converted to a 64-bit UINT, so return 0, but retain -ve number privately
|
||||
LOG_PRINT_L2("BlockchainLMDB::" << __func__ << " - supply of " << currency_label << " is negative (" << amount << ") but outputting zero");
|
||||
amount = 0;
|
||||
}
|
||||
circulating_supply[currency_label] = amount.convert_to<uint64_t>();
|
||||
}
|
||||
|
||||
@@ -3527,12 +3791,13 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
|
||||
// NEAC: check for empty supply tally - only happens prior to first conversion on chain
|
||||
if (circulating_supply.empty()) {
|
||||
circulating_supply["SAL"] = m_coinbase;
|
||||
circulating_supply["SAL1"] = 0;
|
||||
circulating_supply["BURN"] = 0;
|
||||
}
|
||||
|
||||
// Adjust the supply to account for the staked coins
|
||||
circulating_supply["STAKE"] = staked_coins;
|
||||
|
||||
circulating_supply["BURN"] = m_coinbase - circulating_supply["SAL"] - circulating_supply["STAKE"];
|
||||
|
||||
return circulating_supply;
|
||||
}
|
||||
|
||||
@@ -4724,7 +4989,7 @@ void BlockchainLMDB::block_rtxn_abort() const
|
||||
}
|
||||
|
||||
uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated,
|
||||
const std::vector<std::pair<transaction, blobdata>>& txs, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi)
|
||||
const std::vector<std::pair<transaction, blobdata>>& txs, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
@@ -4742,7 +5007,7 @@ uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t
|
||||
|
||||
try
|
||||
{
|
||||
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi);
|
||||
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi, abi);
|
||||
}
|
||||
catch (const DB_ERROR_TXN_START& e)
|
||||
{
|
||||
@@ -5239,8 +5504,38 @@ uint64_t BlockchainLMDB::get_database_size() const
|
||||
|
||||
#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global"))
|
||||
|
||||
void BlockchainLMDB::migrate_2_3()
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
uint64_t i;
|
||||
int result;
|
||||
mdb_txn_safe txn(false);
|
||||
MDB_val k, v;
|
||||
char *ptr;
|
||||
|
||||
MGINFO_YELLOW("Migrating blockchain from DB version 2 to 3 - this may take a while:");
|
||||
|
||||
// Create the missing (and empty) "audit_block_info" records for all blocks
|
||||
do {
|
||||
} while(0);
|
||||
|
||||
uint32_t version = VERSION;
|
||||
v.mv_data = (void *)&version;
|
||||
v.mv_size = sizeof(version);
|
||||
MDB_val_str(vk, "version");
|
||||
result = mdb_txn_begin(m_env, NULL, 0, txn);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
|
||||
result = mdb_put(txn, m_properties, &vk, &v, 0);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to update version for the db: ", result).c_str()));
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
void BlockchainLMDB::migrate(const uint32_t oldversion)
|
||||
{
|
||||
//if (oldversion < 3)
|
||||
// migrate_2_3();
|
||||
}
|
||||
|
||||
} // namespace cryptonote
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -142,6 +142,24 @@ set(blockchain_scanner_private_headers)
|
||||
monero_private_headers(blockchain_scanner
|
||||
${blockchain_scanner_private_headers})
|
||||
|
||||
if (BUILD_TAG)
|
||||
else()
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
|
||||
set(blockchain_audit_sources
|
||||
blockchain_audit.cpp
|
||||
threadpool_boost.cpp
|
||||
)
|
||||
|
||||
set(blockchain_audit_private_headers
|
||||
threadpool_boost.h
|
||||
)
|
||||
|
||||
monero_private_headers(blockchain_audit
|
||||
${blockchain_audit_private_headers})
|
||||
else()
|
||||
message(STATUS "blockchain_audit.cpp not found - not building the audit tool")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
monero_add_executable(blockchain_import
|
||||
${blockchain_import_sources}
|
||||
@@ -312,6 +330,38 @@ set_property(TARGET blockchain_scanner
|
||||
OUTPUT_NAME "salvium-blockchain-scanner")
|
||||
install(TARGETS blockchain_scanner DESTINATION bin)
|
||||
|
||||
if (BUILD_TAG)
|
||||
else()
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
|
||||
monero_add_executable(blockchain_audit
|
||||
${blockchain_audit_sources}
|
||||
${blockchain_audit_private_headers})
|
||||
|
||||
target_include_directories(blockchain_audit PRIVATE /usr/include/mysql-cppconn/jdbc)
|
||||
|
||||
target_link_libraries(blockchain_audit
|
||||
PRIVATE
|
||||
wallet
|
||||
crypto
|
||||
cncrypto
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
version
|
||||
epee
|
||||
mysqlcppconn
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
set_property(TARGET blockchain_audit
|
||||
PROPERTY
|
||||
OUTPUT_NAME "salvium-blockchain-audit")
|
||||
install(TARGETS blockchain_audit DESTINATION bin)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
monero_add_executable(blockchain_stats
|
||||
${blockchain_stats_sources}
|
||||
${blockchain_stats_private_headers})
|
||||
|
||||
@@ -488,8 +488,9 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
try
|
||||
{
|
||||
cryptonote::yield_block_info ybi; // This just gets discarded because we aren't looking to maintain a cache of YBI data in the import utility
|
||||
cryptonote::audit_block_info abi; // This just gets discarded because we aren't looking to maintain a cache of ABI data in the import utility
|
||||
uint64_t long_term_block_weight = core.get_blockchain_storage().get_next_long_term_block_weight(block_weight);
|
||||
core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, ybi);
|
||||
core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, ybi, abi);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "common/command_line.h"
|
||||
#include "common/i18n.h"
|
||||
#include "common/password.h"
|
||||
#include "common/varint.h"
|
||||
#include "cryptonote_basic/cryptonote_boost_serialization.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
@@ -43,11 +45,20 @@
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
|
||||
|
||||
#define DELIM "|"
|
||||
#define DEF_STAKE_MODE "all"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace epee;
|
||||
using namespace cryptonote;
|
||||
|
||||
namespace scanner
|
||||
{
|
||||
const char* tr(const char* str)
|
||||
{
|
||||
return i18n_translate(str, "tools::scanner");
|
||||
}
|
||||
}
|
||||
|
||||
static bool stop_requested = false;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@@ -70,6 +81,8 @@ int main(int argc, char* argv[])
|
||||
const command_line::arg_descriptor<uint64_t> arg_block_start = {"block-start", "start at block number", block_start};
|
||||
const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
|
||||
const command_line::arg_descriptor<std::string> arg_delimiter = {"delimiter", "\"<string>\"", DELIM};
|
||||
const command_line::arg_descriptor<std::string> arg_stake_mode = {"stake", "\"<string>\"", DEF_STAKE_MODE};
|
||||
const command_line::arg_descriptor<bool> arg_check_asset_types = {"check-asset-types", "Scan for asset-type issues", false};
|
||||
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
|
||||
@@ -78,6 +91,8 @@ int main(int argc, char* argv[])
|
||||
command_line::add_arg(desc_cmd_sett, arg_block_start);
|
||||
command_line::add_arg(desc_cmd_sett, arg_block_stop);
|
||||
command_line::add_arg(desc_cmd_sett, arg_delimiter);
|
||||
command_line::add_arg(desc_cmd_sett, arg_stake_mode);
|
||||
command_line::add_arg(desc_cmd_sett, arg_check_asset_types);
|
||||
command_line::add_arg(desc_cmd_only, command_line::arg_help);
|
||||
|
||||
po::options_description desc_options("Allowed options");
|
||||
@@ -116,6 +131,8 @@ int main(int argc, char* argv[])
|
||||
block_start = command_line::get_arg(vm, arg_block_start);
|
||||
block_stop = command_line::get_arg(vm, arg_block_stop);
|
||||
std::string delimiter = command_line::get_arg(vm, arg_delimiter);
|
||||
std::string stake_mode = command_line::get_arg(vm, arg_stake_mode);
|
||||
bool opt_check_asset_types = command_line::get_arg(vm, arg_check_asset_types);
|
||||
|
||||
// If we wanted to use the memory pool, we would set up a fake_core.
|
||||
|
||||
@@ -158,7 +175,7 @@ int main(int argc, char* argv[])
|
||||
LOG_PRINT_L0("Error opening database: " << e.what());
|
||||
return 1;
|
||||
}
|
||||
r = core_storage->blockchain.init(db, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET);
|
||||
r = core_storage->blockchain.init(db, net_type);
|
||||
|
||||
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
|
||||
LOG_PRINT_L0("Source blockchain storage initialized OK");
|
||||
@@ -203,6 +220,9 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
|
||||
uint32_t txhr[24] = {0};
|
||||
unsigned int i;
|
||||
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(net_type).AUDIT_HARD_FORKS;
|
||||
const uint64_t audit_lock_period = get_config(net_type).AUDIT_LOCK_PERIOD;
|
||||
|
||||
for (uint64_t h = block_start; h < block_stop; ++h)
|
||||
{
|
||||
cryptonote::blobdata bd = db->get_block_blob_from_height(h);
|
||||
@@ -234,34 +254,60 @@ skip:
|
||||
std::map<size_t, std::vector<std::string>> used_tx_versions;
|
||||
used_assets.insert("SAL");
|
||||
|
||||
uint8_t hf_version = blk.major_version;
|
||||
|
||||
// Check TX versions
|
||||
if (blk.miner_tx.version != 2) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX version detected" << delimiter << "version:" << blk.miner_tx.version << std::endl;
|
||||
}
|
||||
if (blk.protocol_tx.version != 2) {
|
||||
if (blk.protocol_tx.version != 2 && h>0) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX version detected" << delimiter << "version:" << blk.protocol_tx.version << std::endl;
|
||||
}
|
||||
|
||||
// Get the miner_tx assets
|
||||
std::set<crypto::public_key> used_keys;
|
||||
for (const auto& miner_tx_vout : blk.miner_tx.vout) {
|
||||
std::string asset_type;
|
||||
if (!cryptonote::get_output_asset_type(miner_tx_vout, asset_type)) {
|
||||
throw std::runtime_error("Aborting: failed to get output asset type from miner_tx");
|
||||
} else if (asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from miner_tx");
|
||||
} else if (blk.major_version >= HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL1") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from miner_tx: " + asset_type);
|
||||
} else if (blk.major_version < HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from miner_tx: " + asset_type + ", HF:" + std::to_string(blk.major_version));
|
||||
}
|
||||
miner_tx_assets.insert(asset_type);
|
||||
if (miner_tx_vout.amount > 13500000000 && h>0) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX amount detected" << delimiter << "amount:" << miner_tx_vout.amount << std::endl;
|
||||
}
|
||||
crypto::public_key key;
|
||||
cryptonote::get_output_public_key(miner_tx_vout, key);
|
||||
if (used_keys.count(key)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX - duplicate output detected" << delimiter << "pubkey:" << key << std::endl;
|
||||
}
|
||||
used_keys.insert(key);
|
||||
}
|
||||
|
||||
// Get the protocol_tx assets
|
||||
used_keys.clear();
|
||||
for (const auto& protocol_tx_vout : blk.protocol_tx.vout) {
|
||||
std::string asset_type;
|
||||
if (!cryptonote::get_output_asset_type(protocol_tx_vout, asset_type)) {
|
||||
throw std::runtime_error("Aborting: failed to get output asset type from protocol_tx");
|
||||
} else if (asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx");
|
||||
} else if (blk.major_version >= HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL1") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx: " + asset_type);
|
||||
} else if (blk.major_version < HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx: " + asset_type + ", HF:" + std::to_string(blk.major_version));
|
||||
}
|
||||
protocol_tx_assets.insert(asset_type);
|
||||
if (protocol_tx_vout.amount > 25000000000000) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "large protocol TX amount detected from height " << (h-audit_lock_period) << delimiter << "amount:" << protocol_tx_vout.amount << std::endl;
|
||||
}
|
||||
crypto::public_key key;
|
||||
cryptonote::get_output_public_key(protocol_tx_vout, key);
|
||||
if (used_keys.count(key)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX - duplicate output detected" << delimiter << "pubkey:" << key << std::endl;
|
||||
}
|
||||
used_keys.insert(key);
|
||||
}
|
||||
|
||||
for (const auto& tx_id : blk.tx_hashes)
|
||||
@@ -285,207 +331,49 @@ skip:
|
||||
currsz += bd.size();
|
||||
currtxs++;
|
||||
|
||||
if (tx.version != 2) {
|
||||
if (tx.type != cryptonote::transaction_type::TRANSFER &&
|
||||
tx.type != cryptonote::transaction_type::BURN &&
|
||||
tx.type != cryptonote::transaction_type::STAKE &&
|
||||
tx.type != cryptonote::transaction_type::AUDIT) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX type detected" << delimiter << "type:" << (uint8_t)tx.type << std::endl;
|
||||
}
|
||||
|
||||
if ((tx.version != 2 && hf_version < HF_VERSION_ENABLE_N_OUTS) || (tx.version != 3 && hf_version < HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX version detected" << delimiter << "version:" << tx.version << std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
std::string source;
|
||||
std::string dest;
|
||||
offshore::pricing_record pr;
|
||||
if (!cryptonote::get_tx_asset_types(tx, source, dest, false)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "At least 1 input or 1 output of the tx was invalid" << delimiter << "get_tx_asset_types() failed : ";
|
||||
if (source.empty()) {
|
||||
std::cout << "source is empty" << std::endl;
|
||||
}
|
||||
if (dest.empty()) {
|
||||
std::cout << "dest is empty" << std::endl;
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::STAKE && stake_mode.compare("off")) {
|
||||
if (stake_mode.compare("all") == 0) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "STAKE TX detected" << delimiter << "amount:" << (tx.amount_burnt / 100000000) << std::endl;
|
||||
} else if (stake_mode.compare("large") == 0 && tx.amount_burnt > 25000000000000llu) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "large STAKE TX detected" << delimiter << "amount:" << (tx.amount_burnt / 100000000) << std::endl;
|
||||
}
|
||||
}
|
||||
if (!cryptonote::get_tx_type(source, dest, offshore, onshore, offshore_transfer, xusd_to_xasset, xasset_to_xusd, xasset_transfer)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "At least 1 input or 1 output of the tx was invalid" << delimiter << "get_tx_type() failed" << std::endl;
|
||||
}
|
||||
*/
|
||||
|
||||
// Add the source currency to the list of expected ones
|
||||
used_assets.insert(tx.source_asset_type);
|
||||
/*
|
||||
if ((offshore && !tx.rct_signatures.txnOffshoreFee) ||
|
||||
(onshore && !tx.rct_signatures.txnOffshoreFee_usd) ||
|
||||
(xusd_to_xasset && !tx.rct_signatures.txnOffshoreFee_usd) ||
|
||||
(xasset_to_xusd && !tx.rct_signatures.txnOffshoreFee_xasset)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "Missing conversion fee." << delimiter << "" <<
|
||||
"Source:" << source << ", dest:" << dest <<
|
||||
", XHV fees:" << tx.rct_signatures.txnFee << "," << tx.rct_signatures.txnOffshoreFee <<
|
||||
", XUSD fees:" << tx.rct_signatures.txnFee_usd << "," << tx.rct_signatures.txnOffshoreFee_usd <<
|
||||
", burnt:" << tx.amount_burnt << ", minted:" << tx.amount_minted << std::endl;
|
||||
} else if ((offshore || onshore || xusd_to_xasset || xasset_to_xusd) && (!tx.amount_burnt || !tx.amount_minted)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "Missing burnt/minted value." << std::endl;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// Only run these checks for conversions
|
||||
if (source != dest) {
|
||||
|
||||
// Check PR record is not too old
|
||||
if (h > (tx.pricing_record_height + 10)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "pricing record used by tx was too old" <<
|
||||
delimiter << "tx.pricing_record_height = " << tx.pricing_record_height << std::endl;
|
||||
}
|
||||
|
||||
// Get the PR used by the TX
|
||||
cryptonote::blobdata bd_pr = db->get_block_blob_from_height(tx.pricing_record_height);
|
||||
cryptonote::block blk_pr;
|
||||
if (!cryptonote::parse_and_validate_block_from_blob(bd_pr, blk_pr)) {
|
||||
LOG_PRINT_L0("Bad block from db");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get a more convenient handle on the conversion PR
|
||||
pr = blk_pr.pricing_record;
|
||||
|
||||
// Verify the fees in 128-bit space
|
||||
boost::multiprecision::uint128_t burnt_128 = tx.amount_burnt;
|
||||
boost::multiprecision::uint128_t minted_128 = tx.amount_minted;
|
||||
|
||||
// calculate conversion fees
|
||||
uint32_t fees_version = (h >= 831700) ? 2 : (h >= 653565) ? 2 : 1;
|
||||
uint64_t blocks_to_unlock = tx.unlock_time - h + 1;
|
||||
|
||||
boost::multiprecision::uint128_t fee;
|
||||
if (offshore) {
|
||||
if (fees_version >= 3) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
|
||||
<< "invalid fee version " << fees_version << "" << delimiter << "..." << std::endl;
|
||||
} else if (fees_version == 2) {
|
||||
|
||||
fee =
|
||||
(blocks_to_unlock >= 5030) ? (tx.amount_burnt / 500) :
|
||||
(blocks_to_unlock >= 1430) ? (tx.amount_burnt / 20) :
|
||||
(blocks_to_unlock >= 710) ? (tx.amount_burnt / 10) :
|
||||
tx.amount_burnt / 5;
|
||||
|
||||
if (opt_check_asset_types) {
|
||||
if (tx.source_asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid source asset type found in tx");
|
||||
} else if (tx.destination_asset_type != "SAL") {
|
||||
if (tx.destination_asset_type == "BURN") {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "BURN TX detected" << delimiter << "amount:" << tx.amount_burnt << std::endl;
|
||||
} else {
|
||||
|
||||
// Calculate the priority based on the unlock time
|
||||
uint64_t priority =
|
||||
(blocks_to_unlock >= 5030) ? 1 :
|
||||
(blocks_to_unlock >= 1430) ? 2 :
|
||||
(blocks_to_unlock >= 710) ? 3 :
|
||||
4;
|
||||
uint64_t unlock_time = 60 * pow(3, 4-priority);
|
||||
|
||||
// abs() implementation for uint64_t's
|
||||
uint64_t delta = (pr.unused1 > pr.xUSD) ? pr.unused1 - pr.xUSD : pr.xUSD - pr.unused1;
|
||||
|
||||
// Estimate the fee
|
||||
double scale = exp((M_PI / -1000.0) * (unlock_time - 60) * 1.2);
|
||||
scale *= delta;
|
||||
scale *= tx.amount_burnt;
|
||||
scale /= 1000000000000;
|
||||
fee = (boost::multiprecision::uint128_t)(scale);
|
||||
}
|
||||
|
||||
if ((h >= 658500) && (fee != tx.rct_signatures.txnOffshoreFee)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
|
||||
<< "invalid fee " << tx.rct_signatures.txnOffshoreFee << "" << delimiter << "check:" << fee << std::endl;
|
||||
}
|
||||
|
||||
} else if (onshore) {
|
||||
|
||||
if (fees_version >= 3) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
|
||||
<< "invalid fee version " << fees_version << "" << delimiter << "..." << std::endl;
|
||||
} else if (fees_version == 2) {
|
||||
|
||||
fee =
|
||||
(blocks_to_unlock >= 5030) ? (tx.amount_burnt / 500) :
|
||||
(blocks_to_unlock >= 1430) ? (tx.amount_burnt / 20) :
|
||||
(blocks_to_unlock >= 710) ? (tx.amount_burnt / 10) :
|
||||
tx.amount_burnt / 5;
|
||||
|
||||
} else {
|
||||
|
||||
// Calculate the priority based on the unlock time
|
||||
uint64_t priority =
|
||||
(blocks_to_unlock >= 5030) ? 1 :
|
||||
(blocks_to_unlock >= 1430) ? 2 :
|
||||
(blocks_to_unlock >= 710) ? 3 :
|
||||
4;
|
||||
uint64_t unlock_time = 60 * pow(3, 4-priority);
|
||||
|
||||
// abs() implementation for uint64_t's
|
||||
uint64_t delta = (pr.unused1 > pr.xUSD) ? pr.unused1 - pr.xUSD : pr.xUSD - pr.unused1;
|
||||
|
||||
// Estimate the fee
|
||||
double scale = exp((M_PI / -1000.0) * (unlock_time - 60) * 1.2);
|
||||
scale *= delta;
|
||||
scale *= tx.amount_burnt;
|
||||
scale /= 1000000000000;
|
||||
fee = (boost::multiprecision::uint128_t)(scale);
|
||||
}
|
||||
|
||||
if ((h >= 658500) && (fee != tx.rct_signatures.txnOffshoreFee_usd)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
|
||||
<< "invalid offshore fee " << tx.rct_signatures.txnOffshoreFee_usd << "" << delimiter << "check:" << fee << std::endl;
|
||||
}
|
||||
|
||||
} else if (xusd_to_xasset) {
|
||||
|
||||
fee = tx.amount_burnt;
|
||||
fee *= 3;
|
||||
fee /= 1000;
|
||||
|
||||
if (fee != tx.rct_signatures.txnOffshoreFee_usd) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
|
||||
<< "invalid xusd_to_xasset fee " << tx.rct_signatures.txnOffshoreFee_usd << "" << delimiter << "check:" << fee << std::endl;
|
||||
}
|
||||
|
||||
} else if (xasset_to_xusd) {
|
||||
|
||||
fee = tx.amount_burnt;
|
||||
fee *= 3;
|
||||
fee /= 1000;
|
||||
|
||||
if (fee != tx.rct_signatures.txnOffshoreFee_xasset) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter
|
||||
<< "invalid xasset_to_xusd fee " << tx.rct_signatures.txnOffshoreFee_xasset << "" << delimiter << "check:" << fee << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check for 0 price in the source or destination currency
|
||||
if (offshore|| xusd_to_xasset) {
|
||||
if (!pr[dest]) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "0 exchange rate used for dest " << dest << "" << delimiter << "..." << std::endl;
|
||||
} else if (pr[dest] == 1000000000000) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "1.0000 exchange rate used for dest " << dest << "" << delimiter << "..." << std::endl;
|
||||
}
|
||||
} else if (onshore || xasset_to_xusd) {
|
||||
if (!pr[source]) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "0 exchange rate used for source " << source << "" << delimiter << "..." << std::endl;
|
||||
} else if (pr[source] == 1000000000000) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "1.0000 exchange rate used for source " << source << "" << delimiter << "..." << std::endl;
|
||||
throw std::runtime_error("Aborting: invalid destination asset type found in tx");
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& tx_vout : tx.vout) {
|
||||
std::string asset_type;
|
||||
if (!cryptonote::get_output_asset_type(tx_vout, asset_type)) {
|
||||
throw std::runtime_error("Aborting: failed to get output asset type from tx");
|
||||
} else if (asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from tx");
|
||||
}
|
||||
}
|
||||
|
||||
// Add the source currency to the list of expected ones
|
||||
used_assets.insert(tx.source_asset_type);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
// compare the asset sets
|
||||
if (used_assets == miner_tx_assets) {
|
||||
} else if (used_assets.empty() && (miner_tx_assets.size() == 1) && (miner_tx_assets.count("XHV") == 1)) {
|
||||
} else {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "Mismatch in miner reward assets detected" << delimiter << "Used assets = { ";
|
||||
for (auto const &i: used_assets)
|
||||
std::cout << i << " ";
|
||||
std::cout << "}, miner_tx claimed { ";
|
||||
for (auto const &i: miner_tx_assets)
|
||||
std::cout << i << " ";
|
||||
std::cout << "}" << std::endl;
|
||||
}
|
||||
*/
|
||||
|
||||
currblks++;
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <iostream>
|
||||
#include "threadpool_boost.h"
|
||||
|
||||
ThreadPool::ThreadPool(size_t numThreads)
|
||||
: workGuard(boost::asio::make_work_guard(ioService)) {
|
||||
for (size_t i = 0; i < numThreads; ++i) {
|
||||
workers.emplace_back([this]() {
|
||||
std::cerr << "Thread started" << std::endl;
|
||||
ioService.run();
|
||||
std::cerr << "Thread finished" << std::endl;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::enqueue(std::function<void()> task) {
|
||||
ioService.post([task]() {
|
||||
try {
|
||||
task(); // Run the task
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception in thread pool task: " << e.what() << std::endl;
|
||||
} catch (...) {
|
||||
std::cerr << "Unknown exception in thread pool task!" << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ThreadPool::isStopping() const {
|
||||
return ioService.stopped(); // Check if io_context has stopped
|
||||
}
|
||||
|
||||
void ThreadPool::waitForCompletion() {
|
||||
std::cout << "Waiting for completion...\n";
|
||||
workGuard.reset(); // Allow ioService to stop when no more tasks
|
||||
ioService.run(); // Ensure no threads are left hanging
|
||||
|
||||
for (auto &worker : workers) {
|
||||
if (worker.joinable()) worker.join();
|
||||
}
|
||||
std::cout << "All threads joined.\n";
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool() {
|
||||
waitForCompletion();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef THREADPOOL_BOOST_H
|
||||
#define THREADPOOL_BOOST_H
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
explicit ThreadPool(size_t numThreads);
|
||||
~ThreadPool();
|
||||
|
||||
void enqueue(std::function<void()> task);
|
||||
bool isStopping() const;
|
||||
void waitForCompletion();
|
||||
|
||||
private:
|
||||
boost::asio::io_service ioService;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> workGuard;
|
||||
std::vector<boost::thread> workers;
|
||||
};
|
||||
|
||||
#endif // THREADPOOL_BOOST_H
|
||||
@@ -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
@@ -31,6 +31,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
@@ -177,6 +178,9 @@
|
||||
|
||||
#define THREAD_STACK_SIZE 5 * 1024 * 1024
|
||||
|
||||
#define SECRET_ENCRYPTION_PK_STR "5e860406bf9221dba6409faa6eb8fecd6f34acc4935634e76b64b90bf2b6d6a6"
|
||||
|
||||
|
||||
/*
|
||||
#define HF_VERSION_DYNAMIC_FEE 4
|
||||
#define HF_VERSION_MIN_MIXIN_4 6
|
||||
@@ -222,12 +226,19 @@
|
||||
|
||||
#define HF_VERSION_ENFORCE_FULL_PROOFS 4
|
||||
|
||||
#define HF_VERSION_SHUTDOWN_USER_TXS 5
|
||||
|
||||
#define HF_VERSION_AUDIT1 6
|
||||
#define HF_VERSION_SALVIUM_ONE_PROOFS 6
|
||||
|
||||
#define HF_VERSION_AUDIT1_PAUSE 7
|
||||
|
||||
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
|
||||
#define HF_VERSION_ENABLE_CONVERT 255
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
#define HF_VERSION_SLIPPAGE_YIELD 255
|
||||
|
||||
#define TESTNET_VERSION 12
|
||||
#define TESTNET_VERSION 14
|
||||
#define STAGENET_VERSION 1
|
||||
|
||||
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
|
||||
@@ -278,10 +289,13 @@ namespace config
|
||||
|
||||
uint32_t const GENESIS_NONCE = 10000;
|
||||
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> AUDIT_HARD_FORKS = { {HF_VERSION_AUDIT1, {"SAL", "SAL1"}} };
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30*24*10;
|
||||
|
||||
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
|
||||
|
||||
|
||||
// Hash domain separators
|
||||
const char HASH_KEY_BULLETPROOF_EXPONENT[] = "bulletproof";
|
||||
const char HASH_KEY_BULLETPROOF_PLUS_EXPONENT[] = "bulletproof_plus";
|
||||
@@ -352,6 +366,7 @@ namespace config
|
||||
uint32_t const GENESIS_NONCE = 10001;
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 20;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30;
|
||||
|
||||
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
|
||||
|
||||
@@ -378,6 +393,7 @@ namespace config
|
||||
uint32_t const GENESIS_NONCE = 10002;
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 20;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30;
|
||||
|
||||
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
|
||||
|
||||
@@ -413,7 +429,9 @@ namespace cryptonote
|
||||
uint32_t const GENESIS_NONCE;
|
||||
std::array<std::string, 3> const ORACLE_URLS;
|
||||
std::string const ORACLE_PUBLIC_KEY;
|
||||
uint64_t STAKE_LOCK_PERIOD;
|
||||
uint64_t const STAKE_LOCK_PERIOD;
|
||||
uint64_t const AUDIT_LOCK_PERIOD;
|
||||
std::map<uint8_t, std::pair<std::string, std::string>> const AUDIT_HARD_FORKS;
|
||||
std::string TREASURY_ADDRESS;
|
||||
};
|
||||
inline const config_t& get_config(network_type nettype)
|
||||
@@ -431,6 +449,8 @@ namespace cryptonote
|
||||
::config::ORACLE_URLS,
|
||||
::config::ORACLE_PUBLIC_KEY,
|
||||
::config::STAKE_LOCK_PERIOD,
|
||||
::config::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::TREASURY_ADDRESS
|
||||
};
|
||||
static const config_t testnet = {
|
||||
@@ -446,6 +466,8 @@ namespace cryptonote
|
||||
::config::testnet::ORACLE_URLS,
|
||||
::config::testnet::ORACLE_PUBLIC_KEY,
|
||||
::config::testnet::STAKE_LOCK_PERIOD,
|
||||
::config::testnet::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::testnet::TREASURY_ADDRESS
|
||||
};
|
||||
static const config_t stagenet = {
|
||||
@@ -461,6 +483,8 @@ namespace cryptonote
|
||||
::config::stagenet::ORACLE_URLS,
|
||||
::config::stagenet::ORACLE_PUBLIC_KEY,
|
||||
::config::stagenet::STAKE_LOCK_PERIOD,
|
||||
::config::stagenet::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::stagenet::TREASURY_ADDRESS
|
||||
};
|
||||
switch (nettype)
|
||||
|
||||
@@ -155,12 +155,13 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke
|
||||
// outputs list. that is to say that absolute offset #2 is absolute offset
|
||||
// #1 plus relative offset #2.
|
||||
// TODO: Investigate if this is necessary / why this is done.
|
||||
std::vector<uint64_t> absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets);
|
||||
//std::vector<uint64_t> absolute_offsets;
|
||||
//m_db->get_output_id_from_asset_type_output_index(tx_in_to_key.asset_type, asset_offsets, absolute_offsets);
|
||||
std::vector<uint64_t> asset_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets);
|
||||
std::vector<uint64_t> absolute_offsets;
|
||||
m_db->get_output_id_from_asset_type_output_index(tx_in_to_key.asset_type, asset_offsets, absolute_offsets);
|
||||
std::vector<output_data_t> outputs;
|
||||
|
||||
bool found = false;
|
||||
/*
|
||||
auto it = m_scan_table.find(tx_prefix_hash);
|
||||
if (it != m_scan_table.end())
|
||||
{
|
||||
@@ -171,6 +172,7 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (!found)
|
||||
{
|
||||
@@ -233,7 +235,7 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke
|
||||
output_index = m_db->get_output_key(tx_in_to_key.amount, i);
|
||||
|
||||
// call to the passed boost visitor to grab the public key for the output
|
||||
if (!vis.handle_output(output_index.unlock_time, tx_in_to_key.asset_type, output_index.pubkey, output_index.commitment))
|
||||
if (!vis.handle_output(output_index.unlock_time, cryptonote::asset_type_from_id(output_index.asset_type), output_index.pubkey, output_index.commitment))
|
||||
{
|
||||
MERROR_VER("Failed to handle_output for output no = " << count << ", with absolute offset " << i);
|
||||
return false;
|
||||
@@ -1501,6 +1503,9 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
case HF_VERSION_ENABLE_N_OUTS:
|
||||
case HF_VERSION_FULL_PROOFS:
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
case HF_VERSION_SHUTDOWN_USER_TXS:
|
||||
case HF_VERSION_SALVIUM_ONE_PROOFS:
|
||||
case HF_VERSION_AUDIT1_PAUSE:
|
||||
if (b.miner_tx.amount_burnt > 0) {
|
||||
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt");
|
||||
money_in_use += b.miner_tx.amount_burnt;
|
||||
@@ -1546,10 +1551,13 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
}
|
||||
|
||||
// if nothing is created by this TX - check no money is included
|
||||
size_t vout_size = b.protocol_tx.vout.size();
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs");
|
||||
CHECK_AND_ASSERT_MES(vout_size != 0, true, "coinbase protocol transaction in the block has no outputs");
|
||||
|
||||
size_t vout_size = b.protocol_tx.vout.size();
|
||||
if (vout_size == 0) {
|
||||
LOG_PRINT_L2("coinbase protocol transaction in the block has no outputs");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Can we have matured STAKE transactions yet?
|
||||
uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD;
|
||||
if (height <= stake_lock_period) {
|
||||
@@ -1558,22 +1566,48 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
|
||||
// Get the staking data for the block that matured this time
|
||||
cryptonote::yield_block_info ybi_matured;
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> yield_payouts;
|
||||
uint64_t matured_height = height - stake_lock_period - 1;
|
||||
bool ok = get_ybi_entry(matured_height, ybi_matured);
|
||||
if (!ok || ybi_matured.locked_coins_this_block == 0) {
|
||||
if (!ok) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain yield block information - aborting");
|
||||
return false;
|
||||
} else if (ybi_matured.locked_coins_this_block == 0) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - no yield payouts due - skipping");
|
||||
} else {
|
||||
// Iterate over the cached data for block yield, calculating the yield payouts due
|
||||
if (!calculate_yield_payouts(matured_height, yield_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain yield payout information - aborting");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the cached data for block yield, calculating the yield payouts due
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> yield_payouts;
|
||||
if (!calculate_yield_payouts(matured_height, yield_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain yield payout information - aborting");
|
||||
return false;
|
||||
// Get the audit data for the block that matures at this height
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> audit_payouts;
|
||||
uint64_t audit_lock_period = get_config(m_nettype).AUDIT_LOCK_PERIOD;
|
||||
uint64_t matured_audit_height = height - audit_lock_period - 1;
|
||||
uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height);
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
if (audit_hard_forks.find(hf) != audit_hard_forks.end()) {
|
||||
// Maturing height was during an audit - process accordingly
|
||||
cryptonote::audit_block_info abi_matured;
|
||||
ok = get_abi_entry(matured_audit_height, abi_matured);
|
||||
if (!ok) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - failed to obtain audit block information - aborting");
|
||||
return false;
|
||||
} else if (abi_matured.locked_coins_this_block == 0) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - no audit payouts due - skipping");
|
||||
} else {
|
||||
// Iterate over the cached data for audits, calculating the audit payouts due
|
||||
if (!calculate_audit_payouts(matured_audit_height, audit_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain audit payout information - aborting");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check we have the correct number of entries
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting");
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size() + audit_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting");
|
||||
|
||||
// go through each vout and validate
|
||||
std::set<crypto::public_key> used_keys;
|
||||
@@ -1609,19 +1643,43 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
// Add key to list of already-seen
|
||||
used_keys.insert(out_key);
|
||||
|
||||
// check if there is entry in the yield payouts for this output
|
||||
auto found = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
|
||||
// check if there is entry in the yield payouts or audit payouts for this output
|
||||
std::string expected_output_asset_type = "SAL";
|
||||
auto found_yield = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
|
||||
return p.first.return_address == out_key;
|
||||
});
|
||||
if (found == yield_payouts.end()) {
|
||||
auto found_audit = std::find_if(audit_payouts.begin(), audit_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
|
||||
return p.first.return_address == out_key;
|
||||
});
|
||||
if (found_yield == yield_payouts.end() && found_audit == audit_payouts.end()) {
|
||||
MERROR("Block at height: " << height << " - Failed to locate output for protocol TX - rejecting block");
|
||||
return false;
|
||||
} else if (found_audit == audit_payouts.end()) {
|
||||
|
||||
// Found a YIELD entry
|
||||
CHECK_AND_ASSERT_MES(out_amount == found_yield->second, false, "Incorrect value for protocol TX YIELD amount");
|
||||
uint8_t hf_yield = m_hardfork->get_ideal_version(found_yield->first.block_height);
|
||||
if (hf_yield >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
expected_output_asset_type = "SAL1";
|
||||
|
||||
} else if (found_yield == yield_payouts.end()) {
|
||||
|
||||
// Found an AUDIT entry
|
||||
CHECK_AND_ASSERT_MES(out_amount == found_audit->second, false, "Incorrect value for protocol TX AUDIT amount");
|
||||
uint8_t hf_audit = m_hardfork->get_ideal_version(found_audit->first.block_height);
|
||||
if (hf_audit >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
expected_output_asset_type = "SAL1";
|
||||
|
||||
} else {
|
||||
|
||||
// Duplicate entry in yield + audit?!?!?
|
||||
MERROR("Block at height: " << height << " - Duplicated YIELD and AUDIT keys found for protocol TX - rejecting block");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check other fields
|
||||
CHECK_AND_ASSERT_MES(out_unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output");
|
||||
CHECK_AND_ASSERT_MES(out_asset_type == "SAL", false, "Incorrect output asset type for protocol TX");
|
||||
CHECK_AND_ASSERT_MES(out_amount == found->second, false, "Incorrect output amount for protocol TX");
|
||||
CHECK_AND_ASSERT_MES(expected_output_asset_type == out_asset_type, false, "Incorrect asset type detected for protocol TX ouput - rejecting block");
|
||||
}
|
||||
|
||||
// Everything checks out
|
||||
@@ -1897,14 +1955,22 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Work out what the asset_type should be based on height of submission
|
||||
uint8_t hf_submitted = m_hardfork->get_ideal_version(start_height);
|
||||
|
||||
// Create the protocol_metadata entries here
|
||||
for (const auto& yield_entry: yield_payouts) {
|
||||
cryptonote::protocol_data_entry entry;
|
||||
entry.amount_burnt = yield_entry.second;
|
||||
entry.amount_minted = 0;
|
||||
entry.amount_slippage_limit = 0;
|
||||
entry.source_asset = "SAL";
|
||||
entry.destination_asset = "SAL";
|
||||
if (hf_submitted >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
entry.source_asset = "SAL1";
|
||||
entry.destination_asset = "SAL1";
|
||||
} else {
|
||||
entry.source_asset = "SAL";
|
||||
entry.destination_asset = "SAL";
|
||||
}
|
||||
entry.return_address = yield_entry.first.return_address;
|
||||
entry.type = cryptonote::transaction_type::STAKE;
|
||||
entry.P_change = yield_entry.first.P_change;
|
||||
@@ -1912,6 +1978,50 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the audit data for the block that matures at this height
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> audit_payouts;
|
||||
uint64_t audit_lock_period = get_config(m_nettype).AUDIT_LOCK_PERIOD;
|
||||
uint64_t matured_audit_height = height - audit_lock_period - 1;
|
||||
if (height > audit_lock_period) {
|
||||
uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height);
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
if (audit_hard_forks.find(hf) != audit_hard_forks.end()) {
|
||||
// Maturing height was during an audit - process accordingly
|
||||
cryptonote::audit_block_info abi_matured;
|
||||
ok = get_abi_entry(matured_audit_height, abi_matured);
|
||||
if (!ok) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - failed to obtain audit block information - aborting");
|
||||
return false;
|
||||
} else if (abi_matured.locked_coins_this_block == 0) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - no audit payouts due - skipping");
|
||||
} else {
|
||||
// Iterate over the cached data for audits, calculating the audit payouts due
|
||||
if (!calculate_audit_payouts(matured_audit_height, audit_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain audit payout information - aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the asset types
|
||||
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf);
|
||||
|
||||
// Create the protocol_metadata entries here
|
||||
for (const auto& audit_entry: audit_payouts) {
|
||||
cryptonote::protocol_data_entry entry;
|
||||
entry.amount_burnt = audit_entry.second;
|
||||
entry.amount_minted = 0;
|
||||
entry.amount_slippage_limit = 0;
|
||||
entry.source_asset = audit_asset_types.first;
|
||||
entry.destination_asset = audit_asset_types.second;
|
||||
entry.return_address = audit_entry.first.return_address;
|
||||
entry.type = cryptonote::transaction_type::AUDIT;
|
||||
entry.P_change = audit_entry.first.P_change;
|
||||
entry.return_pubkey = audit_entry.first.return_pubkey;
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Time to construct the protocol_tx
|
||||
uint64_t protocol_fee = 0;
|
||||
@@ -3513,8 +3623,24 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
*/
|
||||
|
||||
// from v4, only allow bulletproofs plus _with_ full proofs on RCT transactions
|
||||
if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
// for v5, force the audit and the new SalviumOne RCT data
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
if (tx.rct_signatures.type != rct::RCTTypeSalviumOne) {
|
||||
MERROR_VER("FullProofs plus Audit data required after v" + std::to_string(HF_VERSION_SALVIUM_ONE_PROOFS));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (tx.rct_signatures.type != rct::RCTTypeNull) {
|
||||
MERROR_VER("NULL RCT required for coinbase TXs after v" + std::to_string(HF_VERSION_SALVIUM_ONE_PROOFS));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
// from v4, only allow bulletproofs plus _with_ full proofs on RCT transactions
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT) {
|
||||
if (tx.rct_signatures.type != rct::RCTTypeFullProofs) {
|
||||
MERROR_VER("FullProofs required after v" + std::to_string(HF_VERSION_FULL_PROOFS));
|
||||
@@ -3623,7 +3749,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs)
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
|
||||
rv.mixRing.resize(pubkeys.size());
|
||||
@@ -3664,7 +3790,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs)
|
||||
else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne)
|
||||
{
|
||||
if (!tx.pruned)
|
||||
{
|
||||
@@ -3805,8 +3931,8 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
}
|
||||
}
|
||||
|
||||
// from v7, sorted ins
|
||||
if (hf_version >= 7) {
|
||||
// from v1, sorted ins
|
||||
if (hf_version >= 1) {
|
||||
const crypto::key_image *last_key_image = NULL;
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
{
|
||||
@@ -3818,6 +3944,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
{
|
||||
MERROR_VER("transaction has unsorted inputs");
|
||||
tvc.m_verifivation_failed = true;
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
last_key_image = &in_to_key.k_image;
|
||||
@@ -3825,6 +3952,20 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
}
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// Make sure we are supposed to accept AUDIT txs at this point
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
CHECK_AND_ASSERT_MES(audit_hard_forks.find(hf_version) != audit_hard_forks.end(), false, "trying to audit outside an audit fork");
|
||||
std::string expected_asset_type = audit_hard_forks.at(hf_version).first;
|
||||
CHECK_AND_ASSERT_MES(tx.source_asset_type == expected_asset_type, false, "trying to spend " << tx.source_asset_type << " coins in an AUDIT TX");
|
||||
} else {
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL1", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size());
|
||||
std::vector < uint64_t > results;
|
||||
results.resize(tx.vin.size(), 0);
|
||||
@@ -3846,6 +3987,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
// Make sure the user isn't trying to spend BURNt coins
|
||||
CHECK_AND_ASSERT_MES(in_to_key.asset_type not_eq "BURN", false, "trying to spend BURNt coins");
|
||||
|
||||
// Make sure only a single asset_type is being spent, and that is the one set on the TX
|
||||
CHECK_AND_ASSERT_MES(in_to_key.asset_type == tx.source_asset_type, false, "trying to spend " << in_to_key.asset_type << " coins in a TX with " << tx.source_asset_type << " source asset type");
|
||||
|
||||
// make sure tx output has key offset(s) (is signed to be used)
|
||||
CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "empty in_to_key.key_offsets in transaction with id " << get_transaction_hash(tx));
|
||||
|
||||
@@ -3911,7 +4055,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
false, "Transaction spends at least one output which is too young");
|
||||
|
||||
// Warn that new RCT types are present, and thus the cache is not being used effectively
|
||||
static constexpr const std::uint8_t RCT_CACHE_TYPE = rct::RCTTypeFullProofs;
|
||||
static constexpr const std::uint8_t RCT_CACHE_TYPE = rct::RCTTypeSalviumOne;
|
||||
if (tx.rct_signatures.type > RCT_CACHE_TYPE)
|
||||
{
|
||||
MWARNING("RCT cache is not caching new verification results. Please update RCT_CACHE_TYPE!");
|
||||
@@ -3944,10 +4088,13 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
const rct::rctSig &rv = tx.rct_signatures;
|
||||
|
||||
// Check that after full proofs are enabled, the RCT version is set to enforce full proofs
|
||||
if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS)
|
||||
{
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs)
|
||||
{
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) {
|
||||
MERROR_VER("Unsupported rct type (full proofs (with audit data) are required): " << rv.type);
|
||||
return false;
|
||||
}
|
||||
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs) {
|
||||
MERROR_VER("Unsupported rct type (full proofs are required): " << rv.type);
|
||||
return false;
|
||||
}
|
||||
@@ -3966,6 +4113,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
case rct::RCTTypeCLSAG:
|
||||
case rct::RCTTypeBulletproofPlus:
|
||||
case rct::RCTTypeFullProofs:
|
||||
case rct::RCTTypeSalviumOne:
|
||||
{
|
||||
if (!ver_rct_non_semantics_simple_cached(tx, pubkeys, m_rct_ver_cache, RCT_CACHE_TYPE, hf_version))
|
||||
{
|
||||
@@ -4348,6 +4496,59 @@ uint64_t Blockchain::get_adjusted_time(uint64_t height) const
|
||||
return (adjusted_current_block_ts < median_ts ? adjusted_current_block_ts : median_ts);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::calculate_audit_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& audit_container)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
// Clear the audit payout amounts
|
||||
audit_container.clear();
|
||||
|
||||
// Get the AUDIT TX information for matured staked coins
|
||||
std::vector<cryptonote::yield_tx_info> audit_entries;
|
||||
// We get the audit_tx_info from the block where they entered the chain
|
||||
int audit_tx_result = m_db->get_audit_tx_info(start_height, audit_entries);
|
||||
if (!audit_entries.size()) {
|
||||
|
||||
// Report error and abort
|
||||
LOG_ERROR("calculate_audit_payouts() called, but no audit TXs found at height " << start_height << " - aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build a blacklist of staking TXs _not_ to pay out for
|
||||
const std::set<std::string> txs_blacklist = {
|
||||
"017a79539e69ce16e91d9aa2267c102f336678c41636567c1129e3e72149499a"
|
||||
};
|
||||
|
||||
// Get the ABI information for the 21,600 blocks that the matured TX(s), we can calculate audit
|
||||
for (const auto& entry: audit_entries) {
|
||||
// Check to see if this entry is in the blacklist
|
||||
if (txs_blacklist.find(epee::string_tools::pod_to_hex(entry.tx_hash)) != txs_blacklist.end()) {
|
||||
LOG_ERROR("calculate_audit_payouts() found blacklisted TX at height " << start_height << " - skipping payout");
|
||||
continue;
|
||||
}
|
||||
audit_container.emplace_back(std::make_pair(entry, entry.locked_coins));
|
||||
}
|
||||
|
||||
// Return success to caller
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::get_abi_entry(const uint64_t height, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
// Clear the provided container
|
||||
std::memset(&abi, 0, sizeof(struct cryptonote::audit_block_info));
|
||||
|
||||
int result = m_db->get_audit_block_info(height, abi);
|
||||
if (result) {
|
||||
// Request failed - report error and bail out
|
||||
LOG_ERROR("failed to retrieve ABI entry for height " << height << " - aborting");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_container)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
@@ -4365,9 +4566,17 @@ bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vecto
|
||||
LOG_ERROR("calculate_yield_payouts() called, but no yield TXs found at height " << start_height << " - aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Build a blacklist of staking TXs _not_ to pay out for
|
||||
const std::set<std::string> txs_blacklist = {};
|
||||
|
||||
// Get the YBI information for the 21,600 blocks that the matured TX(s), we can calculate yield
|
||||
for (const auto& entry: yield_entries) {
|
||||
// Check to see if this entry is in the blacklist
|
||||
if (txs_blacklist.find(epee::string_tools::pod_to_hex(entry.tx_hash)) != txs_blacklist.end()) {
|
||||
LOG_ERROR("calculate_yield_payouts() found blacklisted TX at height " << start_height << " - skipping payout");
|
||||
continue;
|
||||
}
|
||||
yield_container.emplace_back(std::make_pair(entry, entry.locked_coins));
|
||||
}
|
||||
|
||||
@@ -4955,8 +5164,10 @@ leave:
|
||||
uint64_t long_term_block_weight = get_next_long_term_block_weight(block_weight);
|
||||
cryptonote::blobdata bd = cryptonote::block_to_blob(bl);
|
||||
yield_block_info new_ybi;
|
||||
audit_block_info new_abi;
|
||||
std::memset(&new_ybi, 0, sizeof(struct yield_block_info));
|
||||
new_height = m_db->add_block(std::make_pair(std::move(bl), std::move(bd)), block_weight, long_term_block_weight, cumulative_difficulty, already_generated_coins, txs, m_nettype, new_ybi);
|
||||
std::memset(&new_abi, 0, sizeof(struct audit_block_info));
|
||||
new_height = m_db->add_block(std::make_pair(std::move(bl), std::move(bd)), block_weight, long_term_block_weight, cumulative_difficulty, already_generated_coins, txs, m_nettype, new_ybi, new_abi);
|
||||
|
||||
// Update the YBI cache data
|
||||
uint64_t yield_lock_period = cryptonote::get_config(m_nettype).STAKE_LOCK_PERIOD;
|
||||
@@ -5784,7 +5995,13 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
|
||||
{
|
||||
const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
|
||||
// no need to check for duplicate here.
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
|
||||
auto absolute_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets);
|
||||
//std::vector<uint64_t> asset_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets);
|
||||
//std::vector<uint64_t> absolute_offsets;
|
||||
//m_db->get_output_id_from_asset_type_output_index(in_to_key.asset_type, asset_offsets, absolute_offsets);
|
||||
// LAND AHOY!!!
|
||||
for (const auto & offset : absolute_offsets)
|
||||
offset_map[in_to_key.amount].push_back(offset);
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -924,7 +924,15 @@ namespace cryptonote
|
||||
continue;
|
||||
const rct::rctSig &rv = tx_info[n].tx->rct_signatures;
|
||||
const uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) {
|
||||
MERROR_VER("Invalid RCT type provided");
|
||||
set_semantics_failed(tx_info[n].tx_hash);
|
||||
tx_info[n].tvc.m_verifivation_failed = true;
|
||||
tx_info[n].result = false;
|
||||
return false;
|
||||
}
|
||||
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs) {
|
||||
MERROR_VER("Invalid RCT type provided");
|
||||
set_semantics_failed(tx_info[n].tx_hash);
|
||||
@@ -946,6 +954,7 @@ namespace cryptonote
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
|
||||
0
|
||||
))
|
||||
{
|
||||
@@ -981,6 +990,7 @@ namespace cryptonote
|
||||
break;
|
||||
case rct::RCTTypeBulletproofPlus:
|
||||
case rct::RCTTypeFullProofs:
|
||||
case rct::RCTTypeSalviumOne:
|
||||
if (!is_canonical_bulletproof_plus_layout(rv.p.bulletproofs_plus))
|
||||
{
|
||||
MERROR_VER("Bulletproof_plus does not have canonical form");
|
||||
@@ -1007,12 +1017,13 @@ namespace cryptonote
|
||||
{
|
||||
if (!tx_info[n].result)
|
||||
continue;
|
||||
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs)
|
||||
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs && tx_info[n].tx->rct_signatures.type != rct::RCTTypeSalviumOne)
|
||||
continue;
|
||||
if (!rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures,
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
|
||||
0
|
||||
))
|
||||
{
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace cryptonote
|
||||
// We are done here - return to caller
|
||||
return true;
|
||||
|
||||
} else if (tx_type == cryptonote::transaction_type::STAKE) {
|
||||
} else if (tx_type == cryptonote::transaction_type::STAKE || tx_type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// CONVERT / YIELD Semantics
|
||||
// From this point forward, we are departing from the original "return address" scheme
|
||||
@@ -259,6 +259,7 @@ namespace cryptonote
|
||||
// Not implemented yet
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
//---------------------------------------------------------------
|
||||
bool get_conversion_rate(const oracle::pricing_record& pr, const std::string& from_asset, const std::string& to_asset, uint64_t& rate) {
|
||||
// Check for burns
|
||||
@@ -332,6 +333,7 @@ namespace cryptonote
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
//---------------------------------------------------------------
|
||||
bool construct_protocol_tx(
|
||||
const size_t height,
|
||||
@@ -361,7 +363,16 @@ namespace cryptonote
|
||||
|
||||
// Create the TX output for this refund
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
} else if (entry.type == cryptonote::transaction_type::AUDIT) {
|
||||
// PAYOUT
|
||||
LOG_PRINT_L2("Audit TX payout submitted " << entry.amount_burnt << entry.source_asset);
|
||||
|
||||
// Create the TX output for this refund
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
@@ -435,6 +446,9 @@ namespace cryptonote
|
||||
case HF_VERSION_ENABLE_N_OUTS:
|
||||
case HF_VERSION_FULL_PROOFS:
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
case HF_VERSION_SHUTDOWN_USER_TXS:
|
||||
case HF_VERSION_SALVIUM_ONE_PROOFS:
|
||||
case HF_VERSION_AUDIT1_PAUSE:
|
||||
// SRCG: subtract 20% that will be rewarded to staking users
|
||||
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
|
||||
tx.amount_burnt = amount / 5;
|
||||
@@ -445,7 +459,10 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(amount, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
|
||||
std::string asset_type = "SAL";
|
||||
if (hard_fork_version >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
asset_type = "SAL1";
|
||||
cryptonote::set_tx_out(amount, asset_type, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
|
||||
tx.vout.push_back(out);
|
||||
|
||||
} else {
|
||||
@@ -491,6 +508,83 @@ namespace cryptonote
|
||||
return addr.m_view_public_key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// Encrypt function
|
||||
std::string encrypt_pvk(const crypto::secret_key &pvk, const crypto::public_key &PK) {
|
||||
// Step 1: Generate ephemeral keypair
|
||||
crypto::secret_key ephemeral_sk;
|
||||
crypto::public_key ephemeral_pk;
|
||||
crypto::generate_keys(ephemeral_pk, ephemeral_sk);
|
||||
|
||||
// Step 2: Derive shared secret
|
||||
crypto::ec_scalar shared_secret;
|
||||
crypto::key_derivation derivation;
|
||||
if (!crypto::generate_key_derivation(PK, ephemeral_sk, derivation)) {
|
||||
throw std::runtime_error("Failed to generate key derivation");
|
||||
}
|
||||
crypto::derivation_to_scalar(derivation, 0, shared_secret);
|
||||
|
||||
// Step 3: Symmetric key generation (using Keccak hash)
|
||||
crypto::hash symmetric_key_hash;
|
||||
crypto::cn_fast_hash(&shared_secret, sizeof(shared_secret), symmetric_key_hash);
|
||||
|
||||
// Step 4: Encrypt the data (AES-256-CBC or ChaCha20)
|
||||
std::string ciphertext(sizeof(crypto::secret_key), '\0');
|
||||
crypto::chacha_key symmetric_key;
|
||||
memcpy(&symmetric_key, &symmetric_key_hash, sizeof(symmetric_key));
|
||||
crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>();
|
||||
crypto::chacha20(pvk.data, sizeof(crypto::secret_key), symmetric_key, iv, &ciphertext[0]);
|
||||
|
||||
// Step 5: Package ephemeral_pk and ciphertext together
|
||||
std::string encrypted_data = std::string(reinterpret_cast<char*>(&ephemeral_pk), sizeof(ephemeral_pk)) +
|
||||
std::string(reinterpret_cast<char*>(&iv), sizeof(iv)) +
|
||||
ciphertext;
|
||||
return epee::string_tools::buff_to_hex_nodelimer(encrypted_data);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// Decrypt function
|
||||
bool decrypt_pvk(const std::string &encrypted_data_hex, const crypto::secret_key &SK, crypto::secret_key &pvk) {
|
||||
//std::string decrypt_pvk(const std::string &encrypted_data, const crypto::secret_key &SK) {
|
||||
// Step 1: Extract ephemeral_pk, iv, and ciphertext from encrypted_data
|
||||
std::string encrypted_data;
|
||||
for (size_t i = 0; i < encrypted_data_hex.length(); i += 2) {
|
||||
std::istringstream iss(encrypted_data_hex.substr(i, 2));
|
||||
int byte;
|
||||
iss >> std::hex >> byte;
|
||||
encrypted_data += static_cast<char>(byte);
|
||||
}
|
||||
const char *data_ptr = encrypted_data.data();
|
||||
crypto::public_key ephemeral_pk;
|
||||
memcpy(&ephemeral_pk, data_ptr, sizeof(ephemeral_pk));
|
||||
data_ptr += sizeof(ephemeral_pk);
|
||||
|
||||
crypto::chacha_iv iv;
|
||||
memcpy(&iv, data_ptr, sizeof(iv));
|
||||
data_ptr += sizeof(iv);
|
||||
|
||||
std::string ciphertext(data_ptr, encrypted_data.size() - sizeof(ephemeral_pk) - sizeof(iv));
|
||||
|
||||
// Step 2: Derive shared secret
|
||||
crypto::ec_scalar shared_secret;
|
||||
crypto::key_derivation derivation;
|
||||
if (!crypto::generate_key_derivation(ephemeral_pk, SK, derivation)) {
|
||||
throw std::runtime_error("Failed to generate key derivation");
|
||||
}
|
||||
crypto::derivation_to_scalar(derivation, 0, shared_secret);
|
||||
|
||||
// Step 3: Symmetric key generation (using Keccak hash)
|
||||
crypto::hash symmetric_key_hash;
|
||||
crypto::cn_fast_hash(&shared_secret, sizeof(shared_secret), symmetric_key_hash);
|
||||
|
||||
// Step 4: Decrypt the data
|
||||
std::string plaintext(ciphertext.size(), '\0');
|
||||
crypto::chacha_key symmetric_key;
|
||||
memcpy(&symmetric_key, &symmetric_key_hash, sizeof(symmetric_key));
|
||||
crypto::chacha20(ciphertext.data(), ciphertext.size(), symmetric_key, iv, &plaintext[0]);
|
||||
|
||||
memcpy(pvk.data, &plaintext[0], sizeof(crypto::secret_key));
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags)
|
||||
{
|
||||
hw::device &hwdev = sender_account_keys.get_device();
|
||||
@@ -602,6 +696,23 @@ namespace cryptonote
|
||||
};
|
||||
std::vector<input_generation_context_data> in_contexts;
|
||||
|
||||
bool audit = (tx_type == cryptonote::transaction_type::AUDIT);
|
||||
rct::salvium_data_t salvium_data;
|
||||
if (audit) {
|
||||
|
||||
// Generate the encrypted private view key
|
||||
crypto::public_key PK;
|
||||
epee::string_tools::hex_to_pod(SECRET_ENCRYPTION_PK_STR, PK);
|
||||
salvium_data.enc_view_privkey_str = encrypt_pvk(sender_account_keys.m_view_secret_key, PK);
|
||||
|
||||
// And now the rest of the structure
|
||||
salvium_data.salvium_data_type = rct::SalviumAudit;
|
||||
salvium_data.input_verification_data.reserve(sources.size());
|
||||
salvium_data.spend_pubkey = sender_account_keys.m_account_address.m_spend_public_key;
|
||||
|
||||
} else {
|
||||
salvium_data.salvium_data_type = rct::SalviumNormal;
|
||||
}
|
||||
uint64_t summary_inputs_money = 0;
|
||||
//fill inputs
|
||||
int idx = -1;
|
||||
@@ -619,14 +730,26 @@ namespace cryptonote
|
||||
in_contexts.push_back(input_generation_context_data());
|
||||
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
|
||||
crypto::key_image img;
|
||||
rct::salvium_input_data_t sid;
|
||||
const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
|
||||
bool use_origin_data = (src_entr.origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
|
||||
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev, use_origin_data, src_entr.origin_tx_data))
|
||||
sid.origin_tx_type = src_entr.origin_tx_data.tx_type;
|
||||
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev, use_origin_data, src_entr.origin_tx_data, sid))
|
||||
{
|
||||
LOG_ERROR("Key image generation failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// SRCG: store the audit data for the source here
|
||||
if (audit) {
|
||||
sid.amount = src_entr.amount;
|
||||
if (sid.origin_tx_type == cryptonote::transaction_type::STAKE) {
|
||||
// STAKE TXs have to use "output_index 0" because they don't know what the actual output_index value will be ahead of time
|
||||
sid.i = 0;
|
||||
}
|
||||
salvium_data.input_verification_data.push_back(sid);
|
||||
}
|
||||
|
||||
//check that derivated key is equal with real output key
|
||||
if(!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) )
|
||||
{
|
||||
@@ -652,6 +775,14 @@ namespace cryptonote
|
||||
tx.vin.push_back(input_to_key);
|
||||
}
|
||||
|
||||
// Sanity check the size of the verification data
|
||||
if (audit) {
|
||||
if (salvium_data.input_verification_data.size() != sources.size()) {
|
||||
LOG_ERROR("Missing input verification data");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shuffle_outs)
|
||||
{
|
||||
std::shuffle(destinations.begin(), destinations.end(), crypto::random_device{});
|
||||
@@ -670,6 +801,7 @@ namespace cryptonote
|
||||
std::swap(tx.vin[i0], tx.vin[i1]);
|
||||
std::swap(in_contexts[i0], in_contexts[i1]);
|
||||
std::swap(sources[i0], sources[i1]);
|
||||
if (audit) std::swap(salvium_data.input_verification_data[i0], salvium_data.input_verification_data[i1]);
|
||||
});
|
||||
|
||||
// figure out if we need to make additional tx pubkeys
|
||||
@@ -705,6 +837,7 @@ namespace cryptonote
|
||||
crypto::secret_key x_change = crypto::null_skey;
|
||||
rct::key key_yF;
|
||||
uint8_t change_index = 0;
|
||||
bool found_change = false;
|
||||
for(const tx_destination_entry& dst_entr: destinations)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount);
|
||||
@@ -725,11 +858,19 @@ namespace cryptonote
|
||||
tx.amount_burnt += dst_entr.amount;
|
||||
continue;
|
||||
}
|
||||
} else if (tx_type == cryptonote::transaction_type::AUDIT) {
|
||||
// Do not create outputs that are staked for yield - discard them as unused
|
||||
if (!dst_entr.is_change) {
|
||||
tx.amount_burnt += dst_entr.amount;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if this is the change output
|
||||
if (dst_entr.is_change) {
|
||||
CHECK_AND_ASSERT_MES(!found_change, false, "Too many change outputs!!!");
|
||||
change_index = output_index;
|
||||
found_change = true;
|
||||
}
|
||||
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
@@ -746,7 +887,7 @@ namespace cryptonote
|
||||
need_additional_txkeys, additional_tx_keys,
|
||||
additional_tx_public_keys, amount_keys, out_eph_public_key,
|
||||
use_view_tags, view_tag);
|
||||
|
||||
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(dst_entr.amount, dst_entr.asset_type, dst_entr.is_change ? 0 : unlock_time, out_eph_public_key, use_view_tags, view_tag, out);
|
||||
tx.vout.push_back(out);
|
||||
@@ -836,14 +977,14 @@ namespace cryptonote
|
||||
tx.return_address_change_mask.push_back(eci_data);
|
||||
}
|
||||
|
||||
} else if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
} else if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// Get the output public key for the change output
|
||||
crypto::public_key P_change = crypto::null_pkey;
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER)
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 2, false, "Internal error - incorrect number of outputs (!=2) for TRANSFER tx");
|
||||
else if (tx.type == cryptonote::transaction_type::STAKE)
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for YIELD tx");
|
||||
else if (tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT)
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for STAKE/AUDIT tx");
|
||||
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
|
||||
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
|
||||
|
||||
@@ -1031,11 +1172,10 @@ namespace cryptonote
|
||||
fee = summary_inputs_money - summary_outs_money - tx.amount_burnt;
|
||||
|
||||
// zero out all amounts to mask rct outputs, real amounts are now encrypted
|
||||
for (size_t i = 0; i < tx.vin.size(); ++i)
|
||||
{
|
||||
for (size_t i = 0; i < tx.vin.size(); ++i) {
|
||||
if (sources[i].rct)
|
||||
boost::get<txin_to_key>(tx.vin[i]).amount = 0;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i) {
|
||||
tx.vout[i].amount = 0;
|
||||
}
|
||||
@@ -1060,6 +1200,7 @@ namespace cryptonote
|
||||
outSk,
|
||||
rct_config,
|
||||
hwdev,
|
||||
salvium_data,
|
||||
rct::sk2rct(x_change),
|
||||
change_index,
|
||||
key_yF
|
||||
|
||||
@@ -39,9 +39,11 @@
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
/*
|
||||
bool get_conversion_rate(const oracle::pricing_record& pr, const std::string& from_asset, const std::string& to_asset, uint64_t& rate);
|
||||
bool get_converted_amount(const uint64_t& conversion_rate, const uint64_t& source_amount, uint64_t& dest_amount);
|
||||
bool calculate_conversion(const std::string& source_asset, const std::string& dest_asset, const uint64_t amount_burnt, const uint64_t amount_slippage_limit, uint64_t& amount_minted, uint64_t& amount_slippage, const std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const uint8_t hf_version);
|
||||
*/
|
||||
//---------------------------------------------------------------
|
||||
/**
|
||||
* Construct the protocol_tx
|
||||
@@ -171,6 +173,9 @@ namespace cryptonote
|
||||
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
|
||||
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& asset_type, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time);
|
||||
|
||||
std::string encrypt_pvk(const crypto::secret_key &pvk, const crypto::public_key &PK);
|
||||
bool decrypt_pvk(const std::string &encrypted_data, const crypto::secret_key &SK, crypto::secret_key &pvk);
|
||||
|
||||
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false);
|
||||
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false);
|
||||
|
||||
@@ -167,6 +167,15 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject ALL TXs except miner + protocol for v5
|
||||
if (version == HF_VERSION_SHUTDOWN_USER_TXS) {
|
||||
if (tx.type != cryptonote::transaction_type::MINER && tx.type != cryptonote::transaction_type::PROTOCOL) {
|
||||
LOG_PRINT_L1("User TXs are not permitted for v" + std::to_string(HF_VERSION_SHUTDOWN_USER_TXS));
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!check_inputs_types_supported(tx))
|
||||
{
|
||||
tvc.m_verifivation_failed = true;
|
||||
@@ -1653,6 +1662,12 @@ namespace cryptonote
|
||||
continue;
|
||||
}
|
||||
|
||||
// SRCG: skip all user TXs for HF 5 - when the node restarts, it'll discard them fully in `tx_memory_pool::validate()`
|
||||
if (version == HF_VERSION_SHUTDOWN_USER_TXS) {
|
||||
LOG_PRINT_L2(" User TXs forbidden by consensus for HF 5 - skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method());
|
||||
|
||||
if (!meta.matches(relay_category::legacy) && !(m_mine_stem_txes && meta.get_relay_method() == relay_method::stem))
|
||||
|
||||
@@ -130,7 +130,7 @@ bool ver_rct_non_semantics_simple_cached
|
||||
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions
|
||||
// holds true in the future, enable the verification hash by modifying the `untested_tx`
|
||||
// condition below.
|
||||
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeFullProofs;
|
||||
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeSalviumOne;
|
||||
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
|
||||
|
||||
// Don't cache older (or newer) rctSig types
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace cryptonote
|
||||
BURN = 5,
|
||||
STAKE = 6,
|
||||
RETURN = 7,
|
||||
MAX = 7
|
||||
AUDIT = 8,
|
||||
MAX = 8
|
||||
};
|
||||
}
|
||||
|
||||
@@ -43,6 +43,15 @@ const hardfork_t mainnet_hard_forks[] = {
|
||||
|
||||
// version 4 starts from block 121100, which is on or around the 20th of December, 2024. Fork time finalised on 2024-12-19. No fork voting occurs for the v4 fork.
|
||||
{ 4, 121800, 0, 1734607000 },
|
||||
|
||||
// version 5 starts from block 136100, which is on or around the 9th of January, 2025. Fork time finalised on 2025-01-08. No fork voting occurs for the v5 fork.
|
||||
{ 5, 136100, 0, 1736265945 },
|
||||
|
||||
// version 6 starts from block 154750, which is on or around the 4th of February, 2025. Fork time finalised on 2025-01-31. No fork voting occurs for the v6 fork.
|
||||
{ 6, 154750, 0, 1738336000 },
|
||||
|
||||
// version 7 starts from block 161900, which is on or around the 14th of February, 2025. Fork time finalised on 2025-02-04. No fork voting occurs for the v7 fork.
|
||||
{ 7, 161900, 0, 1739264400 },
|
||||
};
|
||||
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
|
||||
const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
@@ -56,6 +65,18 @@ const hardfork_t testnet_hard_forks[] = {
|
||||
|
||||
// version 3 starts from block 500
|
||||
{ 3, 500, 0, 1729518000 },
|
||||
|
||||
// version 4 (full proofs) starts from block 600
|
||||
{ 4, 600, 0, 1734607000 },
|
||||
|
||||
// version 5 (TX shutdown) starts from block 800
|
||||
{ 5, 800, 0, 1734607005 },
|
||||
|
||||
// version 6 (audit 1) starts from block 815
|
||||
{ 6, 815, 0, 1734608000 },
|
||||
|
||||
// version 7 (audit 1 pause) starts from block 900
|
||||
{ 7, 900, 0, 1739264400 },
|
||||
};
|
||||
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
|
||||
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -175,6 +175,7 @@ static bool compute_keys_for_sources(
|
||||
cryptonote::origin_data origin_tx_data;
|
||||
*/
|
||||
bool use_origin_data = (src.origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
|
||||
rct::salvium_input_data_t sid;
|
||||
|
||||
if (not cryptonote::generate_key_image_helper(
|
||||
account_keys,
|
||||
@@ -187,7 +188,8 @@ static bool compute_keys_for_sources(
|
||||
tmp_key_image,
|
||||
hwdev,
|
||||
use_origin_data,
|
||||
src.origin_tx_data
|
||||
src.origin_tx_data,
|
||||
sid
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
@@ -932,19 +934,19 @@ static bool set_tx_rct_signatures(
|
||||
}
|
||||
sc_sub(difference.bytes, sumpouts.bytes, sumouts.bytes);
|
||||
rct::genC(rv.p_r, difference, 0);
|
||||
if (rv.type == rct::RCTTypeFullProofs) {
|
||||
rv.pr_proof = rct::PRProof_Gen(difference);
|
||||
if (rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne) {
|
||||
rv.salvium_data.pr_proof = rct::PRProof_Gen(difference);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::PRProof_Ver(rv.p_r, rv.pr_proof), "PRProof_Ver() failed on recently created proof");
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), "PRProof_Ver() failed on recently created proof");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
// Check if spend authority proof is needed (only for TRANSFER TXs)
|
||||
if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) {
|
||||
rv.sa_proof = rct::SAProof_Gen(output_public_keys[change_index], x_change, hs_yF);
|
||||
if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER && rv.type >= rct::RCTTypeFullProofs) {
|
||||
rv.salvium_data.sa_proof = rct::SAProof_Gen(output_public_keys[change_index], x_change, hs_yF);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::SAProof_Ver(rv.sa_proof, output_public_keys[change_index], hs_yF), "SAProof_Ver() failed on recently created proof");
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::SAProof_Ver(rv.salvium_data.sa_proof, output_public_keys[change_index], hs_yF), "SAProof_Ver() failed on recently created proof");
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
@@ -952,15 +954,15 @@ static bool set_tx_rct_signatures(
|
||||
// check balance if reconstructing the tx
|
||||
else {
|
||||
rv.p.pseudoOuts = unsigned_tx.rct_signatures.p.pseudoOuts;
|
||||
if (rv.type == rct::RCTTypeFullProofs) {
|
||||
if (!rct::PRProof_Ver(unsigned_tx.rct_signatures.p_r, unsigned_tx.rct_signatures.pr_proof))
|
||||
if (rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne) {
|
||||
if (!rct::PRProof_Ver(unsigned_tx.rct_signatures.p_r, unsigned_tx.rct_signatures.salvium_data.pr_proof))
|
||||
return false;
|
||||
rv.p_r = unsigned_tx.rct_signatures.p_r;
|
||||
rv.pr_proof = unsigned_tx.rct_signatures.pr_proof;
|
||||
rv.salvium_data.pr_proof = unsigned_tx.rct_signatures.salvium_data.pr_proof;
|
||||
/*
|
||||
if (!rct::SAProof_Ver(unsigned_tx.rct_signatures.sa_proof, output_public_keys[change_index], hs_yF))
|
||||
if (!rct::SAProof_Ver(unsigned_tx.rct_signatures.salvium_data.sa_proof, output_public_keys[change_index], hs_yF))
|
||||
return false;
|
||||
rv.sa_proof = unsigned_tx.rct_signatures.sa_proof; // should verify this during reconstruction
|
||||
rv.salvium_data.sa_proof = unsigned_tx.rct_signatures.salvium_data.sa_proof; // should verify this during reconstruction
|
||||
*/
|
||||
} else {
|
||||
rv.p_r = unsigned_tx.rct_signatures.p_r;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
namespace oracle {
|
||||
|
||||
const std::vector<std::string> ASSET_TYPES = {"SAL", "VSD", "BURN"};
|
||||
const std::vector<std::string> ASSET_TYPES = {"SAL", "SAL1", "BURN"};
|
||||
|
||||
class asset_type_counts
|
||||
{
|
||||
@@ -40,12 +40,12 @@ namespace oracle {
|
||||
|
||||
// Fields
|
||||
uint64_t SAL;
|
||||
uint64_t VSD;
|
||||
uint64_t SAL1;
|
||||
uint64_t BURN;
|
||||
|
||||
asset_type_counts() noexcept
|
||||
: SAL(0)
|
||||
, VSD(0)
|
||||
, SAL1(0)
|
||||
, BURN(0)
|
||||
{
|
||||
}
|
||||
@@ -54,8 +54,8 @@ namespace oracle {
|
||||
{
|
||||
if (asset_type == "SAL") {
|
||||
return SAL;
|
||||
} else if (asset_type == "VSD") {
|
||||
return VSD;
|
||||
} else if (asset_type == "SAL1") {
|
||||
return SAL1;
|
||||
} else if (asset_type == "BURN") {
|
||||
return BURN;
|
||||
}
|
||||
@@ -67,8 +67,8 @@ namespace oracle {
|
||||
{
|
||||
if (asset_type == "SAL") {
|
||||
SAL += val;
|
||||
} else if (asset_type == "VSD") {
|
||||
VSD += val;
|
||||
} else if (asset_type == "SAL1") {
|
||||
SAL1 += val;
|
||||
} else if (asset_type == "BURN") {
|
||||
BURN += val;
|
||||
}
|
||||
|
||||
+79
-21
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2016, Monero Research Labs
|
||||
// Portions Copyright (c) 2023-2024, Salvium (author: SRCG)
|
||||
// Portions Copyright (c) 2023-2025, Salvium (author: SRCG)
|
||||
//
|
||||
// Author: Shen Noether <shen.noether@gmx.com>
|
||||
//
|
||||
@@ -677,7 +677,7 @@ namespace rct {
|
||||
kv.push_back(p.t);
|
||||
}
|
||||
}
|
||||
else if (rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs)
|
||||
else if (rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne)
|
||||
{
|
||||
kv.reserve((6*2+6) * rv.p.bulletproofs_plus.size());
|
||||
for (const auto &p: rv.p.bulletproofs_plus)
|
||||
@@ -1161,7 +1161,7 @@ namespace rct {
|
||||
//mask amount and mask
|
||||
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
|
||||
rv.ecdhInfo[i].amount = d2h(amounts[i]);
|
||||
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
|
||||
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne);
|
||||
}
|
||||
|
||||
//set txn fee
|
||||
@@ -1206,6 +1206,7 @@ namespace rct {
|
||||
ctkeyV &outSk,
|
||||
const RCTConfig &rct_config,
|
||||
hw::device &hwdev,
|
||||
const rct::salvium_data_t &salvium_data,
|
||||
const key &x_change,
|
||||
const size_t change_index,
|
||||
const key &key_yF
|
||||
@@ -1235,6 +1236,9 @@ namespace rct {
|
||||
case 5:
|
||||
rv.type = RCTTypeFullProofs;
|
||||
break;
|
||||
case 6:
|
||||
rv.type = RCTTypeSalviumOne;
|
||||
break;
|
||||
default:
|
||||
ASSERT_MES_AND_THROW("Unsupported BP version: " << rct_config.bp_version);
|
||||
}
|
||||
@@ -1289,6 +1293,7 @@ namespace rct {
|
||||
rv.p.bulletproofs_plus.push_back(proveRangeBulletproofPlus(C, masks, outamounts, keys, hwdev));
|
||||
else
|
||||
rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts, keys, hwdev));
|
||||
|
||||
#ifdef DBG
|
||||
if (plus)
|
||||
CHECK_AND_ASSERT_THROW_MES(verBulletproofPlus(rv.p.bulletproofs_plus.back()), "verBulletproofPlus failed on newly created proof");
|
||||
@@ -1351,7 +1356,7 @@ namespace rct {
|
||||
//mask amount and mask
|
||||
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
|
||||
rv.ecdhInfo[i].amount = d2h(outamounts[i]);
|
||||
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
|
||||
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne);
|
||||
}
|
||||
|
||||
//set txn fee
|
||||
@@ -1367,28 +1372,43 @@ namespace rct {
|
||||
rv.p.MGs.resize(inamounts.size());
|
||||
key sumpouts = zero(); //sum pseudoOut masks
|
||||
keyV a(inamounts.size());
|
||||
bool audit = (tx_type == cryptonote::transaction_type::AUDIT && rv.type == RCTTypeSalviumOne && salvium_data.salvium_data_type == rct::SalviumAudit);
|
||||
for (i = 0 ; i < inamounts.size(); i++) {
|
||||
if (audit)
|
||||
a[i] = rct::zero();
|
||||
else
|
||||
skGen(a[i]);
|
||||
sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes);
|
||||
genC(pseudoOuts[i], a[i], inamounts[i]);
|
||||
sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes);
|
||||
genC(pseudoOuts[i], a[i], inamounts[i]);
|
||||
}
|
||||
key difference;
|
||||
sc_sub(difference.bytes, sumpouts.bytes, sumout.bytes);
|
||||
genC(rv.p_r, difference, 0);
|
||||
DP(rv.p_r);
|
||||
if (rv.type == RCTTypeFullProofs) {
|
||||
rv.pr_proof = PRProof_Gen(difference);
|
||||
if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne) {
|
||||
rv.salvium_data.pr_proof = PRProof_Gen(difference);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.p_r, rv.pr_proof), "PRProof_Ver() failed on recently created proof");
|
||||
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), "PRProof_Ver() failed on recently created proof");
|
||||
#endif
|
||||
rv.salvium_data.salvium_data_type = salvium_data.salvium_data_type;
|
||||
if (audit) {
|
||||
// SRCG: populate the audit proof here
|
||||
rv.salvium_data.input_verification_data = salvium_data.input_verification_data;
|
||||
rv.salvium_data.spend_pubkey = salvium_data.spend_pubkey;
|
||||
rv.salvium_data.enc_view_privkey_str = salvium_data.enc_view_privkey_str;
|
||||
rv.salvium_data.cz_proof = PRProof_Gen(outSk[0].mask);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.outPk[0].mask, rv.salvium_data.cz_proof), "PRProof_Ver() failed on recently created change proof");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Check if spend authority proof is needed (only for TRANSFER TXs)
|
||||
if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) {
|
||||
rv.sa_proof = SAProof_Gen(destinations[change_index], x_change, key_yF);
|
||||
if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeSalviumOne) {
|
||||
rv.salvium_data.sa_proof = SAProof_Gen(destinations[change_index], x_change, key_yF);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.sa_proof, destinations[change_index], key_yF), "SAProof_Ver() failed on recently created proof");
|
||||
CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.salvium_data.sa_proof, destinations[change_index], key_yF), "SAProof_Ver() failed on recently created proof");
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
@@ -1428,6 +1448,7 @@ namespace rct {
|
||||
unsigned int mixin,
|
||||
const RCTConfig &rct_config,
|
||||
hw::device &hwdev,
|
||||
const rct::salvium_data_t &salvium_data,
|
||||
const key &x_change,
|
||||
const size_t change_index,
|
||||
const key &key_yF
|
||||
@@ -1441,7 +1462,7 @@ namespace rct {
|
||||
mixRing[i].resize(mixin+1);
|
||||
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
|
||||
}
|
||||
return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev, x_change, change_index, key_yF);
|
||||
return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev, salvium_data, x_change, change_index, key_yF);
|
||||
}
|
||||
|
||||
//RingCT protocol
|
||||
@@ -1530,10 +1551,11 @@ namespace rct {
|
||||
std::vector<const BulletproofPlus*> bpp_proofs;
|
||||
size_t max_non_bp_proofs = 0, offset = 0;
|
||||
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne,
|
||||
false, "verRctSemanticsSimple called on non simple rctSig");
|
||||
if (rv.type == RCTTypeFullProofs)
|
||||
CHECK_AND_ASSERT_MES(PRProof_Ver(rv.p_r, rv.pr_proof), false, "Invalid p_r commitment to difference");
|
||||
if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne)
|
||||
CHECK_AND_ASSERT_MES(PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), false, "Invalid p_r commitment to difference");
|
||||
|
||||
const bool bulletproof = is_rct_bulletproof(rv.type);
|
||||
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type);
|
||||
if (bulletproof || bulletproof_plus)
|
||||
@@ -1656,7 +1678,7 @@ namespace rct {
|
||||
{
|
||||
PERF_TIMER(verRctNonSemanticsSimple);
|
||||
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne,
|
||||
false, "verRctNonSemanticsSimple called on non simple rctSig");
|
||||
const bool bulletproof = is_rct_bulletproof(rv.type);
|
||||
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type);
|
||||
@@ -1696,6 +1718,42 @@ namespace rct {
|
||||
}
|
||||
}
|
||||
|
||||
bool audit = (rv.type == RCTTypeSalviumOne && rv.salvium_data.salvium_data_type == rct::SalviumAudit);
|
||||
if (audit) {
|
||||
// Validate the Salvium audit data
|
||||
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.outPk[0].mask, rv.salvium_data.cz_proof), "PRProof_Ver() failed on change proof");
|
||||
CHECK_AND_ASSERT_THROW_MES(pseudoOuts.size() == rv.salvium_data.input_verification_data.size(), "incorrect number of input verification datasets");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.salvium_data.spend_pubkey != crypto::null_pkey, "Invalid spend pubkey provided in audit data");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.salvium_data.enc_view_privkey_str != "", "Invalid encrypted viewkey provided in audit data");
|
||||
for (size_t i=0; i < rv.salvium_data.input_verification_data.size(); ++i) {
|
||||
|
||||
// Check for STAKE origin
|
||||
crypto::public_key Ks = rv.salvium_data.spend_pubkey;
|
||||
if (rv.salvium_data.input_verification_data[i].origin_tx_type != cryptonote::transaction_type::UNSET) {
|
||||
// Verify the origin data provided
|
||||
CHECK_AND_ASSERT_THROW_MES(crypto::derive_public_key(rv.salvium_data.input_verification_data[i].aR_stake, rv.salvium_data.input_verification_data[i].i_stake, rv.salvium_data.spend_pubkey, Ks),
|
||||
"Failed to derive ephemeral public key from audit data");
|
||||
}
|
||||
|
||||
// Recalculate the value of Ks from the Ko value
|
||||
crypto::public_key ephemeral_pub = crypto::null_pkey;
|
||||
CHECK_AND_ASSERT_THROW_MES(crypto::derive_public_key(rv.salvium_data.input_verification_data[i].aR, rv.salvium_data.input_verification_data[i].i, Ks, ephemeral_pub),
|
||||
"Failed to derive ephemeral public key from audit data");
|
||||
// Now find this in the list of mixring entries
|
||||
bool found = false;
|
||||
for (size_t n=0; n<rv.mixRing[i].size(); ++n) {
|
||||
if (ephemeral_pub == rct::rct2pk(rv.mixRing[i][n].dest)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(found, "Failed to match ephemeral public key provided in audit data");
|
||||
|
||||
// Verify the individual input commitment
|
||||
CHECK_AND_ASSERT_THROW_MES(equalKeys(scalarmultH(d2h(rv.salvium_data.input_verification_data[i].amount)), pseudoOuts[i]), "Invalid pseudoOuts entry");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// we can get deep throws from ge_frombytes_vartime if input isn't valid
|
||||
@@ -1728,7 +1786,7 @@ namespace rct {
|
||||
|
||||
//mask amount and mask
|
||||
ecdhTuple ecdh_info = rv.ecdhInfo[i];
|
||||
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
|
||||
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne);
|
||||
mask = ecdh_info.mask;
|
||||
key amount = ecdh_info.amount;
|
||||
key C = rv.outPk[i].mask;
|
||||
@@ -1752,14 +1810,14 @@ namespace rct {
|
||||
}
|
||||
|
||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne,
|
||||
false, "decodeRct called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
|
||||
//mask amount and mask
|
||||
ecdhTuple ecdh_info = rv.ecdhInfo[i];
|
||||
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
|
||||
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne);
|
||||
mask = ecdh_info.mask;
|
||||
key amount = ecdh_info.amount;
|
||||
key C = rv.outPk[i].mask;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -163,7 +163,8 @@ enum TransferType {
|
||||
Convert,
|
||||
Burn,
|
||||
Stake,
|
||||
Return
|
||||
Return,
|
||||
Audit
|
||||
};
|
||||
|
||||
static std::string get_human_readable_timespan(std::chrono::seconds seconds);
|
||||
@@ -213,6 +214,7 @@ namespace
|
||||
const char* USAGE_BURN("burn <amount> <asset_type>");
|
||||
const char* USAGE_CONVERT("convert <source_amount> <source_asset> <dest_asset> [<slippage_limit>]");
|
||||
const char* USAGE_STAKE("stake <amount>");
|
||||
const char* USAGE_AUDIT("audit [index=<N1>[,<N2>,...] | index=all]");
|
||||
const char* USAGE_PRICE_INFO("price_info");
|
||||
const char* USAGE_SUPPLY_INFO("supply_info");
|
||||
const char* USAGE_YIELD_INFO("yield_info");
|
||||
@@ -3219,6 +3221,7 @@ bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<st
|
||||
message_writer() << tr("\"burn <amount> <asset_type>\" - destroy coins forever.");
|
||||
message_writer() << tr("\"convert <amount> <source_asset> <dest_asset> [<slippage_limit>]\" - convert between coin types.");
|
||||
message_writer() << tr("\"stake <amount>\" - stake SAL for 30 days to earn yield.");
|
||||
message_writer() << tr("\"audit\" - audit your wallet main address (or subaddress(es) if specified).");
|
||||
message_writer() << tr("\"price_info\" - Display current pricing information for supported assets.");
|
||||
message_writer() << tr("\"supply_info\" - Display circulating supply information.");
|
||||
message_writer() << tr("\"yield_info\" - Display current stats on Salvium staking / yield.");
|
||||
@@ -3412,14 +3415,18 @@ simple_wallet::simple_wallet()
|
||||
boost::bind(&simple_wallet::stake, this, _1),
|
||||
tr(USAGE_STAKE),
|
||||
tr("Locks <amount> of SAL as stake in order to earn yield"));
|
||||
m_cmd_binder.set_handler("audit",
|
||||
boost::bind(&simple_wallet::audit, this, _1),
|
||||
tr(USAGE_AUDIT),
|
||||
tr("Sends your wallet balance (or a single address or subaddress(es)) to audit (only available during AUDIT hard forks)"));
|
||||
m_cmd_binder.set_handler("price_info",
|
||||
boost::bind(&simple_wallet::price_info, this, _1),
|
||||
tr(USAGE_PRICE_INFO),
|
||||
tr("Displays the current exchange rate information for SAL <--> VSD conversions"));
|
||||
tr("Displays the current exchange rate information for SAL <--> SAL1 conversions"));
|
||||
m_cmd_binder.set_handler("supply_info",
|
||||
boost::bind(&simple_wallet::supply_info, this, _1),
|
||||
tr(USAGE_SUPPLY_INFO),
|
||||
tr("Displays the current circulating supply information for SAL and VSD currencies"));
|
||||
tr("Displays the current circulating supply information for SAL and SAL1 currencies"));
|
||||
m_cmd_binder.set_handler("yield_info",
|
||||
boost::bind(&simple_wallet::yield_info, this, _1),
|
||||
tr(USAGE_YIELD_INFO),
|
||||
@@ -5831,16 +5838,22 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
|
||||
message_writer(console_color_red) << "\r" << "*** CONVERT ***";
|
||||
} else if (td_origin.m_tx.type == cryptonote::transaction_type::STAKE) {
|
||||
message_writer(console_color_magenta, false) << "\r" <<
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("stake returned ") << print_money(td_origin.m_tx.amount_burnt) << " " << td_origin.asset_type << " from height " << td_origin.m_block_height << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("stake returned ") << print_money(td_origin.m_tx.amount_burnt) << " " << td_origin.asset_type << " from height " << td_origin.m_block_height << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
|
||||
message_writer(console_color_magenta, false) << "\r" <<
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("yield earned ") << print_money(amount - td_origin.m_tx.amount_burnt) << " " << asset_type << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("yield earned ") << print_money(amount - td_origin.m_tx.amount_burnt) << " " << asset_type << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
} else if (td_origin.m_tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
message_writer(console_color_red) << "\r" <<
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("audit returned ") << print_money(td_origin.m_tx.amount_burnt) << " " << asset_type << " from height " << td_origin.m_block_height << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
} else {
|
||||
}
|
||||
|
||||
@@ -5848,19 +5861,28 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN) {
|
||||
message_writer(console_color_yellow, false) << "\r" <<
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("burnt ") << print_money(tx.amount_burnt) << " " << asset_type;
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("burnt ") << print_money(tx.amount_burnt) << " " << asset_type << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
} else if (tx.type == cryptonote::transaction_type::CONVERT) {
|
||||
message_writer(console_color_blue, false) << "\r" <<
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("converting ") << print_money(tx.amount_burnt) << " " << asset_type;
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("converting ") << print_money(tx.amount_burnt) << " " << asset_type << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
} else if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
message_writer(console_color_cyan, false) << "\r" <<
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("staked ") << print_money(tx.amount_burnt) << " " << asset_type;
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("staked ") << print_money(tx.amount_burnt) << " " << asset_type << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
} else if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
message_writer(console_color_yellow, false) << "\r" <<
|
||||
tr("Height ") << height << ", " <<
|
||||
tr("txid ") << txid << ", " <<
|
||||
tr("audited ") << print_money(tx.amount_burnt) << " " << asset_type << ", " <<
|
||||
tr("idx ") << subaddr_index;
|
||||
}
|
||||
|
||||
message_writer(asset_type == "SAL" ? console_color_green : console_color_blue, false) << "\r" <<
|
||||
@@ -6719,14 +6741,20 @@ bool simple_wallet::transfer_main(
|
||||
// "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"
|
||||
if (!try_connect_to_daemon())
|
||||
return false;
|
||||
|
||||
std::vector<std::string> local_args = args_;
|
||||
|
||||
std::set<uint32_t> subaddr_indices;
|
||||
if (local_args.size() > 0 && local_args[0].substr(0, 6) == "index=")
|
||||
{
|
||||
if (!parse_subaddress_indices(local_args[0], subaddr_indices))
|
||||
return false;
|
||||
if (local_args[0] == "index=all")
|
||||
{
|
||||
for (uint32_t i = 0; i < m_wallet->get_num_subaddresses(m_current_subaddress_account); ++i)
|
||||
subaddr_indices.insert(i);
|
||||
}
|
||||
else if (!parse_subaddress_indices(local_args[0], subaddr_indices))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
local_args.erase(local_args.begin());
|
||||
}
|
||||
|
||||
@@ -6766,7 +6794,7 @@ bool simple_wallet::transfer_main(
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t min_args = (transfer_type == TransferLocked) ? 2 : 1;
|
||||
const size_t min_args = (transfer_type == Audit) ? 0 : (transfer_type == TransferLocked) ? 2 : 1;
|
||||
if(local_args.size() < min_args)
|
||||
{
|
||||
fail_msg_writer() << tr("wrong number of arguments");
|
||||
@@ -6944,30 +6972,58 @@ bool simple_wallet::transfer_main(
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector;
|
||||
uint64_t unlock_block = 0;
|
||||
std::string err;
|
||||
switch (transfer_type)
|
||||
{
|
||||
if (transfer_type == Audit) {
|
||||
|
||||
// Get the subaddress unlocked balances
|
||||
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddr = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, source_asset, true);
|
||||
unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD;
|
||||
for (const auto subaddr_index : subaddr_indices) {
|
||||
|
||||
// Skip this wallet if there is no balance unlocked to audit
|
||||
if (unlocked_balance_per_subaddr.count(subaddr_index) == 0) continue;
|
||||
|
||||
try {
|
||||
|
||||
std::set<uint32_t> subaddr_indices_single;
|
||||
subaddr_indices_single.insert(subaddr_index);
|
||||
uint64_t unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD;
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector_audit = m_wallet->create_transactions_all(0, cryptonote::transaction_type::AUDIT, source_asset, m_wallet->get_subaddress({m_current_subaddress_account, subaddr_index}), (subaddr_index>0), 1, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices_single);
|
||||
ptx_vector.insert(ptx_vector.end(), ptx_vector_audit.begin(), ptx_vector_audit.end());
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
|
||||
// Let's skip this wallet - we have already reported the error
|
||||
if (unlocked_balance_per_subaddr[subaddr_index].first < 250000000) {
|
||||
fail_msg_writer() << boost::format(tr("Subaddress index %u has insufficient funds (%s) to pay for audit")) % subaddr_index % print_money(unlocked_balance_per_subaddr[subaddr_index].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
switch (transfer_type) {
|
||||
case Burn:
|
||||
unlock_block = 0;
|
||||
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::BURN, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
|
||||
break;
|
||||
break;
|
||||
case Convert:
|
||||
unlock_block = CONVERT_LOCK_PERIOD;
|
||||
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::CONVERT, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
|
||||
break;
|
||||
break;
|
||||
case Stake:
|
||||
unlock_block = get_config(m_wallet->nettype()).STAKE_LOCK_PERIOD;
|
||||
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::STAKE, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
|
||||
break;
|
||||
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::STAKE, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
|
||||
break;
|
||||
case TransferLocked:
|
||||
unlock_block = locked_blocks;
|
||||
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown transfer method, using default");
|
||||
/* FALLTHRU */
|
||||
case Transfer:
|
||||
ptx_vector = m_wallet->create_transactions_2(dsts, source_asset, dest_asset, cryptonote::transaction_type::TRANSFER, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptx_vector.empty())
|
||||
@@ -7069,6 +7125,8 @@ bool simple_wallet::transfer_main(
|
||||
prompt << boost::format(tr("Converting %s %s to %s. ")) % print_money(total_sent) % source_asset % dest_asset;
|
||||
} else if (transfer_type == Stake) {
|
||||
prompt << boost::format(tr("Staking %s %s for yield accrual. ")) % print_money(total_sent) % source_asset;
|
||||
} else if (transfer_type == Audit) {
|
||||
prompt << boost::format(tr("Auditing %s %s. ")) % print_money(total_sent) % source_asset;
|
||||
} else {
|
||||
prompt << boost::format(tr("Sending %s %s. ")) % print_money(total_sent) % source_asset;
|
||||
}
|
||||
@@ -7227,9 +7285,13 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
||||
|
||||
// Get the source asset type
|
||||
std::string source_asset = "SAL";
|
||||
if (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
// Default to "SAL1" post-HF
|
||||
source_asset = "SAL1";
|
||||
}
|
||||
std::string strLastArg = local_args.back();
|
||||
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
|
||||
if (strLastArg == "SAL" or strLastArg == "VSD") {
|
||||
if (strLastArg == "SAL" or strLastArg == "SAL1") {
|
||||
source_asset = strLastArg;
|
||||
local_args.pop_back();
|
||||
}
|
||||
@@ -7264,7 +7326,7 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
|
||||
std::string source_asset = "SAL";
|
||||
std::string strLastArg = local_args.back();
|
||||
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
|
||||
if (strLastArg == "SAL" or strLastArg == "VSD") {
|
||||
if (strLastArg == "SAL" or strLastArg == "SAL1") {
|
||||
source_asset = strLastArg;
|
||||
local_args.pop_back();
|
||||
}
|
||||
@@ -7394,7 +7456,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_)
|
||||
{
|
||||
std::string asset_type = (args_.size() > 1) ? args_.back() : "SAL";
|
||||
std::string asset_type = (args_.size() > 1) ? args_.back() : (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) ? "SAL1" : "SAL";
|
||||
auto print_usage = [this, account, below]()
|
||||
{
|
||||
if (below)
|
||||
@@ -8056,9 +8118,16 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
|
||||
return true;
|
||||
}
|
||||
|
||||
// We found the one we were looking for - take a copy of the key_image, etc.
|
||||
// Verify that the correct asset type is being returned
|
||||
if (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (td.asset_type != "SAL1") {
|
||||
fail_msg_writer() << tr("Only SAL1 may be returned for txid ") << args_[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// We found the one(s) we were looking for - take a copy of the key_image, etc.
|
||||
transfers_indices.push_back(idx);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check we have a valid key_image
|
||||
@@ -8083,21 +8152,32 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
|
||||
fail_msg_writer() << tr("Multiple transactions are created, which is not supposed to happen");
|
||||
return true;
|
||||
}
|
||||
if (ptx_vector[0].selected_transfers.size() != 1)
|
||||
if (ptx_vector[0].selected_transfers.size() != transfers_indices.size())
|
||||
{
|
||||
fail_msg_writer() << tr("The transaction uses multiple or no inputs, which is not supposed to happen");
|
||||
fail_msg_writer() << tr("The transaction uses incorrect number of inputs, which is not supposed to happen");
|
||||
return true;
|
||||
}
|
||||
|
||||
// give user total and fee, and prompt to confirm
|
||||
uint64_t total_fee = ptx_vector[0].fee;
|
||||
uint64_t total_sent = m_wallet->get_transfer_details(ptx_vector[0].selected_transfers.front()).amount();
|
||||
uint64_t total_sent = 0;
|
||||
std::string asset_type;
|
||||
for (auto idx: ptx_vector[0].selected_transfers) {
|
||||
const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(idx);
|
||||
uint64_t sent = td.amount();
|
||||
if (total_sent + sent < total_sent) {
|
||||
fail_msg_writer() << tr("amount overflow detected");
|
||||
return true;
|
||||
}
|
||||
total_sent += sent;
|
||||
asset_type = td.asset_type;
|
||||
}
|
||||
std::ostringstream prompt;
|
||||
if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
|
||||
return true;
|
||||
prompt << boost::format(tr("Returning %s for a total fee of %s. Is this okay?")) %
|
||||
print_money(total_sent) %
|
||||
print_money(total_fee);
|
||||
prompt << boost::format(tr("Returning %s %s for a total fee of %s %s. Is this okay?")) %
|
||||
print_money(total_sent) % asset_type %
|
||||
print_money(total_fee) % asset_type;
|
||||
std::string accepted = input_line(prompt.str(), true);
|
||||
if (std::cin.eof())
|
||||
return true;
|
||||
@@ -8200,7 +8280,7 @@ bool simple_wallet::burn(const std::vector<std::string> &args_)
|
||||
std::string asset_type;
|
||||
std::string strLastArg = local_args.back();
|
||||
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
|
||||
if (strLastArg not_eq "SAL" and strLastArg not_eq "VSD") {
|
||||
if (strLastArg not_eq "SAL" and strLastArg not_eq "SAL1") {
|
||||
PRINT_USAGE(USAGE_BURN);
|
||||
return true;
|
||||
}
|
||||
@@ -8264,7 +8344,7 @@ bool simple_wallet::convert(const std::vector<std::string> &args_)
|
||||
// Get the destination asset type
|
||||
std::string source_asset, dest_asset;
|
||||
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
|
||||
if (strLastArg not_eq "SAL" and strLastArg not_eq "VSD") {
|
||||
if (strLastArg not_eq "SAL" and strLastArg not_eq "SAL1") {
|
||||
fail_msg_writer() << tr("invalid destination asset_type");
|
||||
PRINT_USAGE(USAGE_CONVERT);
|
||||
return true;
|
||||
@@ -8274,7 +8354,7 @@ bool simple_wallet::convert(const std::vector<std::string> &args_)
|
||||
// Get the source asset type
|
||||
strLastArg = local_args.back();
|
||||
std::transform(strLastArg.begin(), strLastArg.end(), strLastArg.begin(), ::toupper);
|
||||
if (strLastArg not_eq "SAL" and strLastArg not_eq "VSD") {
|
||||
if (strLastArg not_eq "SAL" and strLastArg not_eq "SAL1") {
|
||||
fail_msg_writer() << tr("invalid source asset_type");
|
||||
PRINT_USAGE(USAGE_CONVERT);
|
||||
return true;
|
||||
@@ -8298,6 +8378,38 @@ bool simple_wallet::convert(const std::vector<std::string> &args_)
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::audit(const std::vector<std::string> &args_)
|
||||
{
|
||||
// TODO: add locked versions
|
||||
std::vector<std::string> local_args = args_;
|
||||
if (args_.size() == 0)
|
||||
{
|
||||
local_args.push_back("index=0");
|
||||
} else if (args_.size() > 1) {
|
||||
PRINT_USAGE(USAGE_AUDIT);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(m_wallet->multisig())
|
||||
{
|
||||
fail_msg_writer() << tr("This is a multisig wallet, staking is not currently supported");
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_wallet->nettype()).AUDIT_HARD_FORKS;
|
||||
const uint8_t hf_version = m_wallet->get_current_hard_fork();
|
||||
if (audit_hard_forks.find(hf_version) != audit_hard_forks.end()) {
|
||||
|
||||
// Get the asset types
|
||||
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf_version);
|
||||
transfer_main(Audit, audit_asset_types.first, audit_asset_types.first, local_args, false);
|
||||
|
||||
} else {
|
||||
fail_msg_writer() << tr("Audit command is not available at this time.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::stake(const std::vector<std::string> &args_)
|
||||
{
|
||||
// TODO: add locked versions
|
||||
@@ -8316,9 +8428,13 @@ bool simple_wallet::stake(const std::vector<std::string> &args_)
|
||||
std::vector<std::string> local_args;
|
||||
local_args.push_back(m_wallet->get_subaddress_as_str({m_current_subaddress_account,0}));
|
||||
local_args.insert(local_args.end(), args_.begin(), args_.end());
|
||||
|
||||
transfer_main(Stake, "SAL", "SAL", local_args, false);
|
||||
return true;
|
||||
|
||||
if (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
transfer_main(Stake, "SAL1", "SAL1", local_args, false);
|
||||
} else {
|
||||
transfer_main(Stake, "SAL", "SAL", local_args, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::price_info(const std::vector<std::string> &args) {
|
||||
@@ -8403,7 +8519,7 @@ bool simple_wallet::yield_info(const std::vector<std::string> &args) {
|
||||
|
||||
// EXPERIMENTAL - change to get_yield_summary_info() method
|
||||
uint64_t t_burnt, t_supply, t_locked, t_yield, yps, ybi_size;
|
||||
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> yield_payouts;
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> yield_payouts;
|
||||
if (!m_wallet->get_yield_summary_info(t_burnt, t_supply, t_locked, t_yield, yps, ybi_size, yield_payouts)) {
|
||||
fail_msg_writer() << "failed to get yield info. Make sure you are connected to a daemon.";
|
||||
return false;
|
||||
@@ -8411,29 +8527,35 @@ bool simple_wallet::yield_info(const std::vector<std::string> &args) {
|
||||
|
||||
// Get the chain height
|
||||
const uint64_t blockchain_height = m_wallet->get_blockchain_current_height();
|
||||
uint64_t stake_lock_period = get_config(m_wallet->nettype()).STAKE_LOCK_PERIOD;
|
||||
|
||||
message_writer(console_color_default, false) << boost::format(tr("\nSTAKED FUNDS:"));
|
||||
for (auto &p: yield_payouts) {
|
||||
uint64_t height, burnt, yield;
|
||||
std::string txid;
|
||||
std::tie(height, txid, burnt, yield) = p;
|
||||
std::string txid, asset_type;
|
||||
std::tie(height, txid, asset_type, burnt, yield) = p;
|
||||
epee::console_colors asset_type_color = (asset_type == "SAL") ? console_color_green : (asset_type == "SAL1") ? console_color_blue : console_color_green;
|
||||
if (blockchain_height > ybi_size + height)
|
||||
message_writer(console_color_green, true) << boost::format(tr("Height %d, txid %s, staked %s SAL, earned %s SAL"))
|
||||
message_writer(asset_type_color, true) << boost::format(tr("Height %d, txid %s, staked %s %s, earned %s %s"))
|
||||
% height
|
||||
% txid
|
||||
% print_money(burnt)
|
||||
% print_money(yield);
|
||||
% asset_type
|
||||
% print_money(yield)
|
||||
% asset_type;
|
||||
else
|
||||
message_writer(console_color_green, false) << boost::format(tr("Height %d (matures %d), txid %s, staked %s SAL, %s SAL accrued so far"))
|
||||
message_writer(asset_type_color, false) << boost::format(tr("Height %d (matures %d), txid %s, staked %s %s, %s %s accrued so far"))
|
||||
% height
|
||||
% (height + 21601)
|
||||
% (height + stake_lock_period)
|
||||
% txid
|
||||
% print_money(burnt)
|
||||
% print_money(yield);
|
||||
}
|
||||
% asset_type
|
||||
% print_money(yield)
|
||||
% asset_type;
|
||||
}
|
||||
|
||||
// Output the necessary information about yield stats
|
||||
message_writer(console_color_default, false) << boost::format(tr("\nYIELD INFO:\n\tSupply coins burnt over last %s: %d\n\tTotal coins locked: %d\n\tYield accrued over last %s: %d\n\tYield per SAL staked: %d"))
|
||||
message_writer(console_color_default, false) << boost::format(tr("\nYIELD INFO:\n\tSupply coins burnt over last %s: %d\n\tTotal coins locked: %d\n\tYield accrued over last %s: %d\n\tYield per coin staked: %d"))
|
||||
% get_human_readable_timespan((ybi_size-1) * DIFFICULTY_TARGET_V2)
|
||||
% print_money(t_burnt)
|
||||
% print_money(t_locked)
|
||||
|
||||
@@ -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
@@ -1,5 +1,5 @@
|
||||
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_SALVIUM_VERSION "0.7.2"
|
||||
#define DEF_SALVIUM_VERSION "0.9.3"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.3.3"
|
||||
#define DEF_MONERO_RELEASE_NAME "Zero"
|
||||
|
||||
@@ -1444,6 +1444,34 @@ PendingTransaction *WalletImpl::createStakeTransaction(uint64_t amount, uint32_t
|
||||
return createTransactionMultDest(Monero::transaction_type::STAKE, std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {amount}) : (optional<std::vector<uint64_t>>()), mixin_count, asset_type, is_return, priority, subaddr_account, subaddr_indices);
|
||||
}
|
||||
|
||||
PendingTransaction *WalletImpl::createAuditTransaction(
|
||||
uint32_t mixin_count,
|
||||
PendingTransaction::Priority priority,
|
||||
uint32_t subaddr_account,
|
||||
std::set<uint32_t> subaddr_indices
|
||||
) {
|
||||
// Need to populate {dst_entr, payment_id, asset_type, is_return}
|
||||
const string dst_addr = m_wallet->get_subaddress_as_str({subaddr_account, 0});//MY LOCAL (SUB)ADDRESS
|
||||
const string payment_id = "";
|
||||
const string asset_type = "SAL";
|
||||
const bool is_return = false;
|
||||
|
||||
LOG_ERROR("createAuditTransaction: called");
|
||||
|
||||
return createTransactionMultDest(
|
||||
Monero::transaction_type::AUDIT,
|
||||
std::vector<string> {dst_addr},
|
||||
payment_id,
|
||||
(optional<std::vector<uint64_t>>()),
|
||||
mixin_count,
|
||||
asset_type,
|
||||
is_return,
|
||||
priority,
|
||||
subaddr_account,
|
||||
subaddr_indices
|
||||
);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
|
||||
// 2 - check / design how "Transaction" can be single interface
|
||||
@@ -1536,11 +1564,11 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const Monero::transact
|
||||
fake_outs_count = m_wallet->adjust_mixin(mixin_count);
|
||||
|
||||
if (amount) {
|
||||
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, "SAL", "SAL", converted_tx_type, fake_outs_count, 0 /* unlock_time */,
|
||||
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, asset_type, asset_type, converted_tx_type, fake_outs_count, 0 /* unlock_time */,
|
||||
adjusted_priority,
|
||||
extra, subaddr_account, subaddr_indices);
|
||||
} else {
|
||||
transaction->m_pending_tx = m_wallet->create_transactions_all(0, converted_tx_type, "SAL", info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */,
|
||||
transaction->m_pending_tx = m_wallet->create_transactions_all(0, converted_tx_type, asset_type, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */,
|
||||
adjusted_priority,
|
||||
extra, subaddr_account, subaddr_indices);
|
||||
}
|
||||
|
||||
@@ -158,6 +158,10 @@ public:
|
||||
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
||||
uint32_t subaddr_account = 0,
|
||||
std::set<uint32_t> subaddr_indices = {}) override;
|
||||
PendingTransaction * createAuditTransaction(uint32_t mixin_count,
|
||||
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
||||
uint32_t subaddr_account = 0,
|
||||
std::set<uint32_t> subaddr_indices = {}) override;
|
||||
PendingTransaction * createTransactionMultDest(const transaction_type &tx_type,
|
||||
const std::vector<std::string> &dst_addr, const std::string &payment_id,
|
||||
optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
|
||||
|
||||
@@ -58,7 +58,8 @@ enum transaction_type : uint8_t {
|
||||
BURN = 5,
|
||||
STAKE = 6,
|
||||
RETURN = 7,
|
||||
MAX = 7
|
||||
AUDIT = 8,
|
||||
MAX = 8
|
||||
};
|
||||
|
||||
namespace Utils {
|
||||
@@ -97,7 +98,7 @@ struct YieldInfo
|
||||
virtual uint64_t yield() const = 0;
|
||||
virtual uint64_t yield_per_stake() const = 0;
|
||||
virtual std::string period() const = 0;
|
||||
virtual std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> payouts() const = 0;
|
||||
virtual std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> payouts() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -878,6 +879,20 @@ struct Wallet
|
||||
uint32_t subaddr_account = 0,
|
||||
std::set<uint32_t> subaddr_indices = {}) = 0;
|
||||
|
||||
/*!
|
||||
* \brief createAuditTransaction creates audit transaction.
|
||||
* \param mixin_count mixin count. if 0 passed, wallet will use default value
|
||||
* \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices
|
||||
* \param priority
|
||||
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
|
||||
* after object returned
|
||||
*/
|
||||
|
||||
virtual PendingTransaction * createAuditTransaction(uint32_t mixin_count,
|
||||
PendingTransaction::Priority = PendingTransaction::Priority_Low,
|
||||
uint32_t subaddr_account = 0,
|
||||
std::set<uint32_t> subaddr_indices = {}) = 0;
|
||||
|
||||
/*!
|
||||
* \brief createTransactionMultDest creates transaction with multiple destinations. if dst_addr is an integrated address, payment_id is ignored
|
||||
* \param tx_type the type of transaction being created
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace Monero {
|
||||
return m_yield_per_stake;
|
||||
}
|
||||
|
||||
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> YieldInfoImpl::payouts() const
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> YieldInfoImpl::payouts() const
|
||||
{
|
||||
return m_payouts;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
uint64_t yield() const override;
|
||||
uint64_t yield_per_stake() const override;
|
||||
std::string period() const override;
|
||||
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> payouts() const override;
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> payouts() const override;
|
||||
|
||||
private:
|
||||
friend class WalletImpl;
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
uint64_t m_yield_per_stake;
|
||||
uint64_t m_num_entries;
|
||||
std::string m_period;
|
||||
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> m_payouts;
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> m_payouts;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+148
-53
@@ -886,6 +886,11 @@ uint8_t get_full_proofs_fork()
|
||||
return HF_VERSION_FULL_PROOFS;
|
||||
}
|
||||
|
||||
uint8_t get_salvium_one_proofs_fork()
|
||||
{
|
||||
return HF_VERSION_SALVIUM_ONE_PROOFS;
|
||||
}
|
||||
|
||||
uint64_t calculate_fee(bool use_per_byte_fee, const cryptonote::transaction &tx, size_t blob_size, uint64_t base_fee, uint64_t fee_quantization_mask)
|
||||
{
|
||||
if (use_per_byte_fee)
|
||||
@@ -2148,6 +2153,7 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
|
||||
case rct::RCTTypeCLSAG:
|
||||
case rct::RCTTypeBulletproofPlus:
|
||||
case rct::RCTTypeFullProofs:
|
||||
case rct::RCTTypeSalviumOne:
|
||||
return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev);
|
||||
case rct::RCTTypeFull:
|
||||
return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev);
|
||||
@@ -2198,6 +2204,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
|
||||
// Flag to indicate this is a TX that uses a return_address
|
||||
bool use_od = false;
|
||||
cryptonote::origin_data od = AUTO_VAL_INIT(od);
|
||||
rct::salvium_input_data_t sid;
|
||||
auto search = m_salvium_txs.find(pk_change);
|
||||
if (search != m_salvium_txs.end()) {
|
||||
size_t idx = search->second;
|
||||
@@ -2208,6 +2215,9 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
|
||||
od.tx_pub_key = get_tx_pub_key_from_extra(td_origin.m_tx);
|
||||
od.output_index = td_origin.m_internal_output_index;
|
||||
od.tx_type = td_origin.m_tx.type;
|
||||
|
||||
// SRCG: this is necessary to be able to receive protocol_tx outputs to the correct wallet subaddress
|
||||
tx_scan_info.received->index = td_origin.m_subaddr_index;
|
||||
}
|
||||
|
||||
if (m_multisig)
|
||||
@@ -2218,7 +2228,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
|
||||
}
|
||||
else
|
||||
{
|
||||
bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), output_public_key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device(), use_od, od);
|
||||
bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), output_public_key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device(), use_od, od, sid);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||
THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != output_public_key,
|
||||
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
|
||||
@@ -2392,7 +2402,7 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
|
||||
uint64_t &total_yield,
|
||||
uint64_t &yield_per_stake,
|
||||
uint64_t &ybi_data_size,
|
||||
std::vector<std::tuple<size_t, std::string, uint64_t, uint64_t>> &payouts
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> &payouts
|
||||
)
|
||||
{
|
||||
// Get the total circulating supply of SALs
|
||||
@@ -2420,21 +2430,21 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
|
||||
|
||||
// Iterate over the transfers in our wallet
|
||||
std::map<size_t, size_t> map_payouts;
|
||||
std::map<std::string, std::pair<size_t, std::pair<uint64_t, uint64_t>>> payouts_active;
|
||||
std::map<std::string, std::tuple<size_t, std::string, uint64_t, uint64_t>> payouts_active;
|
||||
if (m_transfers.size() > 0) {
|
||||
for (size_t idx = m_transfers.size()-1; idx>0; --idx) {
|
||||
const tools::wallet2::transfer_details& td = m_transfers[idx];
|
||||
//if (td.m_block_height < ybi_data[0].block_height) break;
|
||||
if (td.m_tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (map_payouts.count(idx)) {
|
||||
payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt));
|
||||
payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.asset_type, td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt));
|
||||
} else {
|
||||
//payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, 0));
|
||||
payouts_active[epee::string_tools::pod_to_hex(td.m_txid)] = std::make_pair(td.m_block_height, std::make_pair(td.m_tx.amount_burnt, 0));
|
||||
payouts_active[epee::string_tools::pod_to_hex(td.m_txid)] = std::make_tuple(td.m_block_height, td.asset_type, td.m_tx.amount_burnt, 0);
|
||||
}
|
||||
} else if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
// Store list of reverse-lookup indices to tell YIELD TXs how much they earned
|
||||
if (m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::STAKE)
|
||||
if (m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::STAKE || m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::AUDIT)
|
||||
map_payouts[td.m_td_origin_idx] = idx;
|
||||
}
|
||||
}
|
||||
@@ -2452,18 +2462,21 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
|
||||
|
||||
// EXPERIMENTAL - add up yield earned for active STAKE TXs
|
||||
for (auto &payout: payouts_active) {
|
||||
if (ybi_data[idx].block_height < payout.second.first) continue;
|
||||
|
||||
auto&[height,asset_type,total_burnt,total_accrued] = payout.second;
|
||||
if (ybi_data[idx].block_height < height) continue;
|
||||
boost::multiprecision::uint128_t amount_128 = ybi_data[idx].slippage_total_this_block;
|
||||
amount_128 *= payout.second.second.first;
|
||||
amount_128 *= total_burnt;
|
||||
amount_128 /= ybi_data[idx].locked_coins_tally;
|
||||
payout.second.second.second += amount_128.convert_to<uint64_t>();
|
||||
total_accrued += amount_128.convert_to<uint64_t>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &payout: payouts_active) {
|
||||
// Copy to the list of payouts proper
|
||||
payouts.push_back(std::make_tuple(payout.second.first, payout.first, payout.second.second.first, payout.second.second.second));
|
||||
auto&[height,asset_type,total_burnt,total_accrued] = payout.second;
|
||||
payouts.push_back(std::make_tuple(height, payout.first, asset_type, total_burnt, total_accrued));
|
||||
}
|
||||
|
||||
// Get the total currently locked
|
||||
@@ -2486,7 +2499,7 @@ bool wallet2::verify_spend_authority_proof(const cryptonote::transaction &tx, co
|
||||
// Sanity checks
|
||||
if (tx.type != cryptonote::transaction_type::TRANSFER) return true;
|
||||
if (tx.version < TRANSACTION_VERSION_N_OUTS) return true;
|
||||
if (tx.rct_signatures.type != rct::RCTTypeFullProofs) return true;
|
||||
if (tx.rct_signatures.type != rct::RCTTypeFullProofs && tx.rct_signatures.type != rct::RCTTypeSalviumOne) return true;
|
||||
|
||||
// To verify the spend authority proof, we need to know the y value to process the F value
|
||||
ec_scalar y;
|
||||
@@ -2544,7 +2557,7 @@ bool wallet2::verify_spend_authority_proof(const cryptonote::transaction &tx, co
|
||||
rct::key hs_yF = rct::hash_to_scalar(key_yF);
|
||||
|
||||
// Now we can verify the proof itself
|
||||
if (!rct::SAProof_Ver(tx.rct_signatures.sa_proof, key_P_change, hs_yF)) {
|
||||
if (!rct::SAProof_Ver(tx.rct_signatures.salvium_data.sa_proof, key_P_change, hs_yF)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2743,7 +2756,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin_idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol TX origin in m_transfers");
|
||||
const transfer_details& td_origin = get_transfer_details(td_origin_idx);
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::STAKE, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers");
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::AUDIT && td_origin.m_tx.type != cryptonote::transaction_type::STAKE, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers");
|
||||
|
||||
// Get the output key for the change entry
|
||||
crypto::public_key pk_locked_coins = crypto::null_pkey;
|
||||
@@ -2877,7 +2890,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
total_received_1[asset_type] = amount;
|
||||
notify = true;
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// The CONVERT/YIELD TX was created by us - therefore we need to expect an output in the PROTOCOL_TX
|
||||
// It could be a refund or a conversion
|
||||
@@ -2887,14 +2900,15 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
crypto::public_key P_change = crypto::null_pkey;
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(tx.vout[0], P_change), error::wallet_internal_error, "Failed to get change output public key");
|
||||
//m_subaddresses[P_change] = {0x50524F54,0x4F434F4C}; /* {PROT,OCOL} - seemed like a good idea at the time, but harder to implement! */
|
||||
m_subaddresses[P_change] = {0,0};
|
||||
m_subaddresses[P_change] = tx_scan_info[o].received->index;//{0,0};
|
||||
//m_subaddresses[P_change] = {0,0};
|
||||
m_salvium_txs.insert({P_change, m_transfers.size()-1});
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
// Additionally, with YIELD TXs, we need to update our "balance staked" subtotal, because otherwise our balance is out by the staked coins until they mature!
|
||||
if (tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// Additionally, with STAKE and AUDIT TXs, we need to update our "balance staked" subtotal, because otherwise our balance is out by the staked coins until they mature!
|
||||
// SRCG: must remember to deduct the number of staked coins when they mature!!
|
||||
LOG_PRINT_L1("***** STAKED COINS : " << tx.amount_burnt << " *****");
|
||||
m_locked_coins.insert({P_change, {0, tx.amount_burnt}});
|
||||
LOG_PRINT_L1("***** STAKED/AUDITED COINS : " << tx.amount_burnt << " *****");
|
||||
m_locked_coins.insert({P_change, {0, tx.amount_burnt, tx.source_asset_type}});
|
||||
}
|
||||
|
||||
} else if (tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
@@ -7015,10 +7029,12 @@ uint64_t wallet2::balance(uint32_t index_major, const std::string& asset_type, b
|
||||
uint64_t amount = 0;
|
||||
for (const auto& i : balance_per_subaddress(index_major, asset_type, strict))
|
||||
amount += i.second;
|
||||
if (index_major == 0 && asset_type == "SAL") {
|
||||
// Iterate over the locked coins, adding them to the _locked_ balance
|
||||
for (const auto& i : m_locked_coins)
|
||||
|
||||
// Iterate over the locked coins, adding them to the _locked_ balance
|
||||
for (const auto& i : m_locked_coins) {
|
||||
if (index_major == 0 && asset_type == i.second.m_asset_type) {
|
||||
amount += i.second.m_amount;
|
||||
}
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
@@ -7944,13 +7960,14 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
|
||||
// SRCG: Calculate the correct uniqueness value here
|
||||
assert(false);
|
||||
cryptonote::origin_data origin_tx_data;
|
||||
rct::salvium_input_data_t sid;
|
||||
|
||||
// if this output is back to this wallet, we can calculate its key image already
|
||||
if (!is_out_to_acc_precomp(m_subaddresses, output_public_key, derivation, additional_derivations, i, hwdev, get_output_view_tag(tx.vout[i])))
|
||||
continue;
|
||||
crypto::key_image ki;
|
||||
cryptonote::keypair in_ephemeral;
|
||||
if (generate_key_image_helper(keys, m_subaddresses, output_public_key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev, false, origin_tx_data))
|
||||
if (generate_key_image_helper(keys, m_subaddresses, output_public_key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev, false, origin_tx_data, sid))
|
||||
signed_txes.tx_key_images[output_public_key] = ki;
|
||||
else
|
||||
MERROR("Failed to calculate key image");
|
||||
@@ -9463,11 +9480,15 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||
if (out < num_outs)
|
||||
{
|
||||
MINFO("Using it");
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
|
||||
//req.outputs.push_back({amount, out, true}); // Rings are stored referencing global output IDs
|
||||
add_output_to_lists({amount, out, true});
|
||||
//add_output_to_lists({amount, out, true});
|
||||
add_output_to_lists({amount, out, false});
|
||||
// LAND AHOY!!!
|
||||
++num_found;
|
||||
seen_indices.emplace(out);
|
||||
if (out == td.m_global_output_index)
|
||||
if (out == td.m_asset_type_output_index)
|
||||
{
|
||||
MINFO("This is the real output");
|
||||
own_found = true;
|
||||
@@ -9725,7 +9746,11 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||
"Daemon response did not include the requested real output");
|
||||
|
||||
// pick real out first (it will be sorted when done)
|
||||
outs.back().push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), mask));
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: DO NOT COMMIT THIS CHANGE UNTIL VERIFIED AS WORKING
|
||||
//outs.back().push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), mask));
|
||||
outs.back().push_back(std::make_tuple(td.m_asset_type_output_index, td.get_public_key(), mask));
|
||||
// LAND AHOY!!!
|
||||
|
||||
// then pick outs from an existing ring, if any
|
||||
if (td.m_key_image_known && !td.m_key_image_partial)
|
||||
@@ -9744,13 +9769,16 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||
for (size_t o = 0; o < requested_outputs_count; ++o)
|
||||
{
|
||||
size_t i = base + o;
|
||||
if (req.outputs[i].index == out && req.outputs[i].is_global_out)
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: DO NOT COMMIT THIS CHANGE UNTIL VERIFIED AS WORKING
|
||||
if (req.outputs[i].index == out /*&& req.outputs[i].is_global_out*/)
|
||||
{
|
||||
LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key << " (from existing ring)");
|
||||
tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
// LAND AHOY!!!
|
||||
}
|
||||
THROW_WALLET_EXCEPTION_IF(!found, error::wallet_internal_error, "Failed to find existing ring output in daemon out data");
|
||||
}
|
||||
@@ -9896,7 +9924,11 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||
"real output not found");
|
||||
|
||||
tx_output_entry real_oe;
|
||||
real_oe.first = td.m_global_output_index;
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
|
||||
//real_oe.first = td.m_global_output_index;
|
||||
real_oe.first = td.m_asset_type_output_index;
|
||||
// LAND AHOY!!!
|
||||
real_oe.second.dest = rct::pk2rct(td.get_public_key());
|
||||
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
|
||||
*it_to_replace = real_oe;
|
||||
@@ -10101,9 +10133,13 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
|
||||
|
||||
uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
|
||||
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
|
||||
uint32_t subaddr_index = m_transfers[*selected_transfers.begin()].m_subaddr_index.minor;
|
||||
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i) {
|
||||
THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts");
|
||||
|
||||
if (tx_type == cryptonote::transaction_type::AUDIT) {
|
||||
THROW_WALLET_EXCEPTION_IF(subaddr_index != m_transfers[*i].m_subaddr_index.minor, error::wallet_internal_error, "the AUDIT tx uses funds from multiple subaddresses");
|
||||
}
|
||||
}
|
||||
if (outs.empty())
|
||||
get_outs(outs, selected_transfers, fake_outputs_count, all_rct, valid_public_keys_cache); // may throw
|
||||
|
||||
@@ -10152,13 +10188,21 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
//paste real transaction to the random index
|
||||
auto it_to_replace = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a)
|
||||
{
|
||||
return a.first == td.m_global_output_index;
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
|
||||
//return a.first == td.m_global_output_index;
|
||||
return a.first == td.m_asset_type_output_index;
|
||||
// LAND AHOY!!!
|
||||
});
|
||||
THROW_WALLET_EXCEPTION_IF(it_to_replace == src.outputs.end(), error::wallet_internal_error,
|
||||
"real output not found");
|
||||
|
||||
tx_output_entry real_oe;
|
||||
real_oe.first = td.m_global_output_index;
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: ring tweak to indexed per asset_type - DO NOT COMMIT UNTIL IT IS ALL WORKING
|
||||
//real_oe.first = td.m_global_output_index;
|
||||
real_oe.first = td.m_asset_type_output_index;
|
||||
// LAND AHOY!!!
|
||||
real_oe.second.dest = rct::pk2rct(td.get_public_key());
|
||||
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
|
||||
*it_to_replace = real_oe;
|
||||
@@ -10182,11 +10226,18 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
|
||||
change_dts.amount = found_money - needed_money;
|
||||
change_dts.asset_type = source_asset;
|
||||
change_dts.addr = get_subaddress({subaddr_account, 0});
|
||||
change_dts.is_subaddress = subaddr_account != 0;
|
||||
change_dts.addr = get_subaddress({subaddr_account, subaddr_index});
|
||||
change_dts.is_subaddress = subaddr_account != 0 || subaddr_index != 0;
|
||||
change_dts.is_change = true;
|
||||
splitted_dsts.push_back(change_dts);
|
||||
|
||||
account_keys a_keys = m_account.get_keys();
|
||||
// SRCG: add support for auditing of subaddresses
|
||||
if (tx_type == cryptonote::transaction_type::AUDIT && (subaddr_account != 0 || subaddr_index != 0)) {
|
||||
// Overwrite the public spend key and view key
|
||||
a_keys.m_account_address = get_subaddress({subaddr_account, subaddr_index});
|
||||
}
|
||||
|
||||
crypto::secret_key tx_key;
|
||||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
crypto::secret_key multisig_tx_key_entropy;
|
||||
@@ -10230,7 +10281,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
std::vector<std::pair<std::string, std::string>> circ_amounts;
|
||||
THROW_WALLET_EXCEPTION_IF(!get_circulating_supply(circ_amounts), error::wallet_internal_error, "Failed to get circulating supply");
|
||||
// make a normal tx
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, tx_type, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(a_keys/*m_account.get_keys()*/, m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, tx_type, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
|
||||
LOG_PRINT_L2("constructed tx, r="<<r);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_nettype);
|
||||
}
|
||||
@@ -10652,7 +10703,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
const bool bulletproof_plus = true;
|
||||
const bool clsag = true;
|
||||
const bool use_fullproofs = use_fork_rules(get_full_proofs_fork(), 0);
|
||||
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_fullproofs ? 5 : 4 };
|
||||
const bool use_salviumone_proofs = use_fork_rules(get_salvium_one_proofs_fork(), 0);
|
||||
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_salviumone_proofs ? 6 : use_fullproofs ? 5 : 4 };
|
||||
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
|
||||
std::unordered_set<crypto::public_key> valid_public_keys_cache;
|
||||
|
||||
@@ -10695,7 +10747,18 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
//THROW_WALLET_EXCEPTION_IF(!get_circulating_supply(circ_amounts), error::wallet_internal_error, "Failed to get circulating supply");
|
||||
break;
|
||||
case transaction_type::STAKE:
|
||||
THROW_WALLET_EXCEPTION_IF(dest_asset != "SAL", error::wallet_internal_error, "Yield TX must specify 'SAL' destination asset type");
|
||||
if (use_salviumone_proofs) {
|
||||
THROW_WALLET_EXCEPTION_IF(source_asset != "SAL1", error::wallet_internal_error, "STAKE TX must specify 'SAL1' source asset type");
|
||||
THROW_WALLET_EXCEPTION_IF(dest_asset != "SAL1", error::wallet_internal_error, "STAKE TX must specify 'SAL1' destination asset type");
|
||||
} else {
|
||||
THROW_WALLET_EXCEPTION_IF(source_asset != "SAL", error::wallet_internal_error, "STAKE TX must specify 'SAL' source asset type");
|
||||
THROW_WALLET_EXCEPTION_IF(dest_asset != "SAL", error::wallet_internal_error, "STAKE TX must specify 'SAL' destination asset type");
|
||||
}
|
||||
THROW_WALLET_EXCEPTION_IF(subaddr_account != 0, error::wallet_internal_error, "Staking is only permitted from main account, not secondary accounts");
|
||||
break;
|
||||
case transaction_type::AUDIT:
|
||||
THROW_WALLET_EXCEPTION_IF(source_asset != "SAL", error::wallet_internal_error, "AUDIT TX must specify 'SAL' source asset type");
|
||||
THROW_WALLET_EXCEPTION_IF(dest_asset != "SAL", error::wallet_internal_error, "AUDIT TX must specify 'SAL' destination asset type");
|
||||
THROW_WALLET_EXCEPTION_IF(subaddr_account != 0, error::wallet_internal_error, "Staking is only permitted from main account, not secondary accounts");
|
||||
break;
|
||||
default:
|
||||
@@ -11327,6 +11390,8 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, c
|
||||
received += ptx.tx.amount_burnt;
|
||||
else if (ptx.tx.type == cryptonote::transaction_type::STAKE)
|
||||
received += ptx.tx.amount_burnt;
|
||||
else if (ptx.tx.type == cryptonote::transaction_type::AUDIT)
|
||||
received += ptx.tx.amount_burnt;
|
||||
|
||||
total_received += received;
|
||||
}
|
||||
@@ -11351,11 +11416,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
const bool bulletproof_plus = true;
|
||||
const bool clsag = true;
|
||||
const bool use_fullproofs = use_fork_rules(get_full_proofs_fork(), 0);
|
||||
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_fullproofs ? 5 : 4 };
|
||||
const bool use_salviumone_proofs = use_fork_rules(get_salvium_one_proofs_fork(), 0);
|
||||
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_salviumone_proofs ? 6 : use_fullproofs ? 5 : 4 };
|
||||
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
|
||||
const uint64_t base_fee = get_base_fee(priority);
|
||||
const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags);
|
||||
const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags);
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: the weight of the TX needs to account for the additional proofs
|
||||
const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags/*, use_fullproofs, use_salviumone_proofs*/);
|
||||
const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags/*, use_fullproofs, use_salviumone_proofs*/);
|
||||
// LAND AHOY!!!
|
||||
THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!");
|
||||
const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring;
|
||||
const uint64_t fractional_threshold = (base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
|
||||
@@ -11413,7 +11482,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
}
|
||||
}
|
||||
|
||||
return create_transactions_from(address, cryptonote::transaction_type::TRANSFER, "SAL", is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
|
||||
return create_transactions_from(address, tx_type, asset_type, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
|
||||
}
|
||||
|
||||
std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
|
||||
@@ -11441,7 +11510,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
|
||||
std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector<size_t> transfers_indices)
|
||||
{
|
||||
// Get the asset_type and associated information
|
||||
THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>1, error::wallet_internal_error, tr("Incorrect number of transfers_indices on return_payment"));
|
||||
THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>15, error::wallet_internal_error, tr("Incorrect number of transfers_indices on return_payment"));
|
||||
size_t idx = transfers_indices[0];
|
||||
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers"));
|
||||
const transfer_details& td_origin = get_transfer_details(idx);
|
||||
@@ -11454,6 +11523,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
|
||||
uint32_t priority = adjust_priority(0);
|
||||
std::vector<uint8_t> extra; // No need for a TX extra beyond that which will be calculated herein
|
||||
|
||||
// Verify that all the indices share an origin
|
||||
for (const auto &td_idx : transfers_indices) {
|
||||
THROW_WALLET_EXCEPTION_IF(td_idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers"));
|
||||
const transfer_details &td = get_transfer_details(td_idx);
|
||||
THROW_WALLET_EXCEPTION_IF(td.m_txid != td_origin.m_txid, error::wallet_internal_error, tr("TX hashes do not match for inputs to return_payment"));
|
||||
THROW_WALLET_EXCEPTION_IF(td.asset_type != td_origin.asset_type, error::wallet_internal_error, tr("TX asset_type values do not match for inputs to return_payment"));
|
||||
}
|
||||
|
||||
// To return a payment, we need to know the y value to process the F value
|
||||
// ...but the y value is calculated differently depending on the original TX
|
||||
ec_scalar y;
|
||||
@@ -11594,7 +11671,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
const bool bulletproof_plus = true;
|
||||
const bool clsag = true;
|
||||
const bool use_fullproofs = use_fork_rules(get_full_proofs_fork(), 0);
|
||||
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_fullproofs ? 5 : 4 };
|
||||
const bool use_salviumone_proofs = use_fork_rules(get_salvium_one_proofs_fork(), 0);
|
||||
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, use_salviumone_proofs ? 6 : use_fullproofs ? 5 : 4 };
|
||||
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
|
||||
const uint64_t base_fee = get_base_fee(priority);
|
||||
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
|
||||
@@ -11666,7 +11744,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
// SRCG: should the subaddress be forced to TRUE for _RETURN_ TXs and FALSE for all others?!?!?
|
||||
// add N - 1 outputs for correct initial fee estimation
|
||||
for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i) {
|
||||
tx.dsts.push_back(tx_destination_entry(1, address, tx_type == cryptonote::transaction_type::RETURN, tx_type == cryptonote::transaction_type::RETURN));
|
||||
if (tx_type == cryptonote::transaction_type::AUDIT) {
|
||||
tx.dsts.push_back(tx_destination_entry(1, address, tx_type == cryptonote::transaction_type::RETURN, tx_type == cryptonote::transaction_type::RETURN));
|
||||
} else {
|
||||
tx.dsts.push_back(tx_destination_entry(1, address, tx_type == cryptonote::transaction_type::RETURN, tx_type == cryptonote::transaction_type::RETURN));
|
||||
}
|
||||
tx.dsts.back().asset_type = asset_type;
|
||||
}
|
||||
|
||||
@@ -12291,6 +12373,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
|
||||
// SRCG: Calculate the correct uniqueness value here
|
||||
assert(false);
|
||||
cryptonote::origin_data origin_tx_data;
|
||||
rct::salvium_input_data_t sid;
|
||||
|
||||
// derive the real output keypair
|
||||
const transfer_details& in_td = m_transfers[found->second];
|
||||
@@ -12299,7 +12382,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
|
||||
const std::vector<crypto::public_key> in_additionakl_tx_pub_keys = get_additional_tx_pub_keys_from_extra(in_td.m_tx);
|
||||
keypair in_ephemeral;
|
||||
crypto::key_image in_img;
|
||||
THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device(), false, origin_tx_data),
|
||||
THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device(), false, origin_tx_data, sid),
|
||||
error::wallet_internal_error, "failed to generate key image");
|
||||
THROW_WALLET_EXCEPTION_IF(in_key->k_image != in_img, error::wallet_internal_error, "key image mismatch");
|
||||
|
||||
@@ -12515,7 +12598,7 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
|
||||
crypto::secret_key scalar1;
|
||||
crypto::derivation_to_scalar(found_derivation, n, scalar1);
|
||||
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
|
||||
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs);
|
||||
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs || tx.rct_signatures.type == rct::RCTTypeSalviumOne);
|
||||
const rct::key C = tx.rct_signatures.outPk[n].mask;
|
||||
rct::key Ctmp;
|
||||
THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.mask.bytes) != 0, error::wallet_internal_error, "Bad ECDH input mask");
|
||||
@@ -12529,6 +12612,12 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
|
||||
received += amount;
|
||||
}
|
||||
}
|
||||
|
||||
// SRCG: if this returns 0 received, but it's an AUDIT TX, then that is EXPECTED
|
||||
bool audit = (tx.rct_signatures.type == rct::RCTTypeSalviumOne && tx.rct_signatures.salvium_data.salvium_data_type == rct::SalviumAudit);
|
||||
if (audit && received == 0) {
|
||||
received += tx.amount_burnt;
|
||||
}
|
||||
}
|
||||
|
||||
void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations)
|
||||
@@ -12782,8 +12871,9 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
uint64_t received;
|
||||
check_tx_key_helper(tx, derivation, additional_derivations, address, received);
|
||||
// SRCG: if this returns 0 received, but it's an AUDIT TX, then that is EXPECTED
|
||||
THROW_WALLET_EXCEPTION_IF(!received, error::wallet_internal_error, tr("No funds received in this tx."));
|
||||
|
||||
|
||||
// concatenate all signature strings
|
||||
for (size_t i = 0; i < num_sigs; ++i)
|
||||
sig_str +=
|
||||
@@ -13032,11 +13122,12 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
|
||||
// Populate this struct if you want to make use of "get_reserve_proof()" for Salvium!!!
|
||||
assert(false);
|
||||
origin_data od;
|
||||
rct::salvium_input_data_t sid;
|
||||
|
||||
// derive ephemeral secret key
|
||||
crypto::key_image ki;
|
||||
cryptonote::keypair ephemeral;
|
||||
const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki, m_account.get_device(), false, od);
|
||||
const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki, m_account.get_device(), false, od, sid);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||
THROW_WALLET_EXCEPTION_IF(ephemeral.pub != td.get_public_key(), error::wallet_internal_error, "Derived public key doesn't agree with the stored one");
|
||||
|
||||
@@ -13209,7 +13300,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
|
||||
crypto::secret_key shared_secret;
|
||||
crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret);
|
||||
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx];
|
||||
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs);
|
||||
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs || tx.rct_signatures.type == rct::RCTTypeSalviumOne);
|
||||
amount = rct::h2d(ecdh_info.amount);
|
||||
}
|
||||
total += amount;
|
||||
@@ -13664,11 +13755,12 @@ std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>
|
||||
// Populate this struct if you want to make use of "import_outputs" for Salvium!!!
|
||||
assert(false);
|
||||
origin_data od;
|
||||
rct::salvium_input_data_t sid;
|
||||
|
||||
// generate ephemeral secret key
|
||||
crypto::key_image ki;
|
||||
cryptonote::keypair in_ephemeral;
|
||||
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device(), false, od);
|
||||
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device(), false, od, sid);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && !td.m_key_image_partial && ki != td.m_key_image,
|
||||
@@ -14258,6 +14350,7 @@ process:
|
||||
// Populate this struct if you want to make use of "import_outputs" for Salvium!!!
|
||||
assert(false);
|
||||
origin_data od;
|
||||
rct::salvium_input_data_t sid;
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(td.m_tx.vout.empty(), error::wallet_internal_error, "tx with no outputs at index " + boost::lexical_cast<std::string>(i + offset));
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
|
||||
@@ -14268,7 +14361,7 @@ process:
|
||||
crypto::public_key out_key = td.get_public_key();
|
||||
if (should_expand(td.m_subaddr_index))
|
||||
create_one_off_subaddress(td.m_subaddr_index);
|
||||
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), false, od);
|
||||
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), false, od, sid);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||
if (should_expand(td.m_subaddr_index))
|
||||
expand_subaddresses(td.m_subaddr_index);
|
||||
@@ -14367,6 +14460,7 @@ size_t wallet2::import_outputs(const std::tuple<uint64_t, uint64_t, std::vector<
|
||||
// Populate this struct if you want to make use of "import_outputs" for Salvium!!!
|
||||
assert(false);
|
||||
origin_data od;
|
||||
rct::salvium_input_data_t sid;
|
||||
|
||||
// the hot wallet wouldn't have known about key images (except if we already exported them)
|
||||
cryptonote::keypair in_ephemeral;
|
||||
@@ -14376,7 +14470,7 @@ size_t wallet2::import_outputs(const std::tuple<uint64_t, uint64_t, std::vector<
|
||||
const crypto::public_key& out_key = etd.m_pubkey;
|
||||
if (should_expand(td.m_subaddr_index))
|
||||
create_one_off_subaddress(td.m_subaddr_index);
|
||||
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), false, od);
|
||||
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), false, od, sid);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||
if (should_expand(td.m_subaddr_index))
|
||||
expand_subaddresses(td.m_subaddr_index);
|
||||
@@ -14585,6 +14679,7 @@ crypto::key_image wallet2::get_multisig_composite_key_image(size_t n) const
|
||||
// SRCG: work out if we have origin data to use
|
||||
bool use_origin_data = false;
|
||||
cryptonote::origin_data origin_tx_data;
|
||||
rct::salvium_input_data_t sid;
|
||||
if (td.m_td_origin_idx != (uint64_t)-1) {
|
||||
|
||||
// Flag to indicate this is a TX that uses a return_address
|
||||
@@ -14595,7 +14690,7 @@ crypto::key_image wallet2::get_multisig_composite_key_image(size_t n) const
|
||||
use_origin_data = true;
|
||||
}
|
||||
|
||||
bool r = multisig::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki, use_origin_data, origin_tx_data);
|
||||
bool r = multisig::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki, use_origin_data, origin_tx_data, sid);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||
return ki;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user