Compare commits
19 Commits
v0.9.9-rc1
...
v0.9.0-rc6
| Author | SHA1 | Date | |
|---|---|---|---|
| ab6e23c7b8 | |||
| ac59a40c2d | |||
| 0bd1351750 | |||
| 5fde8021dc | |||
| f9b946e929 | |||
| fee5676d8c | |||
| 97685a0849 | |||
| fa5ec5f12e | |||
| d2a71984cf | |||
| 9f1721261f | |||
| e68841d306 | |||
| 6571df4c76 | |||
| 89180a6727 | |||
| 2ccd388153 | |||
| 5757c67e17 | |||
| 013011cde7 | |||
| 400ec099d1 | |||
| 60825ae753 | |||
| 0c5d6e92e6 |
@@ -1,6 +1,6 @@
|
||||
# Salvium Zero v0.7.2
|
||||
# Salvium Zero v0.9.0-rc6
|
||||
|
||||
Copyright (c) 2023-2024, Salvium
|
||||
Copyright (c) 2023-2025, Salvium
|
||||
Portions Copyright (c) 2014-2023, The Monero Project
|
||||
Portions Copyright (c) 2012-2013 The Cryptonote developers.
|
||||
|
||||
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
|
||||
|
||||
```bash
|
||||
cd salvium
|
||||
git checkout v0.7.0
|
||||
git checkout v0.9.0
|
||||
make
|
||||
```
|
||||
|
||||
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
|
||||
```bash
|
||||
git clone https://github.com/salvium/salvium
|
||||
cd salvium
|
||||
git checkout v0.7.0
|
||||
git checkout v0.9.0
|
||||
```
|
||||
|
||||
* Build:
|
||||
@@ -370,10 +370,10 @@ application.
|
||||
cd salvium
|
||||
```
|
||||
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.7.0'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.0'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.7.0
|
||||
git checkout v0.9.0
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -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_data block height {locked_coins, lc_total}
|
||||
* audit_tx_data block height {txn hash, locked_coins, return_address}
|
||||
*
|
||||
* Note: where the data items are of uniform size, DUPFIXED tables have
|
||||
* been used to save space. In most of these cases, a dummy "zerokval"
|
||||
* key is used when accessing the table; the Key listed above will be
|
||||
@@ -289,6 +292,8 @@ const char* const LMDB_CIRC_SUPPLY_TALLY = "circ_supply_tally";
|
||||
*/
|
||||
const char* const LMDB_YIELD_TXS = "yield_txs";
|
||||
const char* const LMDB_YIELD_BLOCKS = "yield_blocks";
|
||||
const char* const LMDB_AUDIT_TXS = "audit_txs";
|
||||
const char* const LMDB_AUDIT_BLOCKS = "audit_blocks";
|
||||
|
||||
const char zerokey[8] = {0};
|
||||
const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey };
|
||||
@@ -800,6 +805,75 @@ estim:
|
||||
return threshold_size;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_audit_block_info(const uint64_t height, audit_block_info& abi) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
// Clear the ABI, just in case
|
||||
std::memset(&abi, 0, sizeof(struct audit_block_info));
|
||||
|
||||
// Query for the matured AUDIT_BLOCK_INFO information
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(audit_blocks);
|
||||
|
||||
MDB_val v;
|
||||
MDB_val_set(k, height);
|
||||
int ret = mdb_cursor_get(m_cur_audit_blocks, &k, &v, MDB_SET);
|
||||
if (ret == MDB_NOTFOUND) {
|
||||
LOG_ERROR("Failed to locate ABI for block height " << height);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit block info: ", ret).c_str()));
|
||||
|
||||
audit_block_info *p = (audit_block_info*)v.mv_data;
|
||||
abi = *p;
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
// Return success to caller
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
// Clear the container
|
||||
ati_container.clear();
|
||||
|
||||
// Query for the (presumably matured) AUDIT_TX_INFO information (we actually reuse YIELD_TX_INFO for this)
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(audit_txs);
|
||||
|
||||
MDB_val v;
|
||||
MDB_val_set(k, height);
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
while (1)
|
||||
{
|
||||
int ret = mdb_cursor_get(m_cur_audit_txs, &k, &v, op);
|
||||
op = MDB_NEXT_DUP;
|
||||
if (ret == MDB_NOTFOUND)
|
||||
break;
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit TX info: ", ret).c_str()));
|
||||
|
||||
// Get the data
|
||||
yield_tx_info *p = (yield_tx_info*)v.mv_data;
|
||||
// Push result back into the container
|
||||
ati_container.emplace_back(*p);
|
||||
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
|
||||
ati_container.back().block_height = height;
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
// Return success to caller
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_yield_block_info(const uint64_t height, yield_block_info& ybi) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
@@ -855,9 +929,12 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate yield TX info: ", ret).c_str()));
|
||||
|
||||
// Push result back into the container
|
||||
// Get the data
|
||||
yield_tx_info *p = (yield_tx_info*)v.mv_data;
|
||||
// Push result back into the container
|
||||
yti_container.emplace_back(*p);
|
||||
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
|
||||
yti_container.back().block_height = height;
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
@@ -866,7 +943,7 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi)
|
||||
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, uint64_t audit_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
@@ -896,6 +973,18 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
|
||||
|
||||
int result = 0;
|
||||
|
||||
// Create the AUDIT_BLOCK_INFO instance for this block
|
||||
CURSOR(audit_blocks)
|
||||
abi.block_height = m_height;
|
||||
abi.locked_coins_this_block = audit_total;
|
||||
|
||||
// Put the YBI into the table
|
||||
MDB_val_set(key, m_height);
|
||||
MDB_val_set(abi_val, abi);
|
||||
result = mdb_cursor_put(m_cur_audit_blocks, &key, &abi_val, MDB_APPEND);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to add ABI to db: ", result).c_str()));
|
||||
|
||||
CURSOR(yield_blocks)
|
||||
yield_block_info ybi_matured, ybi_prev;
|
||||
uint64_t yield_lock_period = cryptonote::get_config(nettype).STAKE_LOCK_PERIOD;
|
||||
@@ -932,7 +1021,6 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
|
||||
ybi.network_health_percentage = 100;
|
||||
|
||||
// Put the YBI into the table
|
||||
MDB_val_set(key, m_height);
|
||||
MDB_val_set(ybi_val, ybi);
|
||||
result = mdb_cursor_put(m_cur_yield_blocks, &key, &ybi_val, MDB_APPEND);
|
||||
if (result)
|
||||
@@ -1004,6 +1092,7 @@ void BlockchainLMDB::remove_block()
|
||||
CURSOR(blocks)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_blocks)
|
||||
CURSOR(audit_blocks)
|
||||
MDB_val_copy<uint64_t> k(m_height - 1);
|
||||
MDB_val h = k;
|
||||
if ((result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &h, MDB_GET_BOTH)))
|
||||
@@ -1031,6 +1120,11 @@ void BlockchainLMDB::remove_block()
|
||||
throw1(BLOCK_DNE(lmdb_error("Attempting to remove yield block info that's not in the db: ", result).c_str()));
|
||||
if ((result = mdb_cursor_del(m_cur_yield_blocks, 0)))
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of yield block info to db transaction: ", result).c_str()));
|
||||
|
||||
// Is the block within an audit window?
|
||||
if ((result = mdb_cursor_get(m_cur_audit_blocks, &k2, NULL, MDB_SET)) == 0)
|
||||
if ((result = mdb_cursor_del(m_cur_audit_blocks, 0)))
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit block info to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
boost::multiprecision::int128_t
|
||||
@@ -1116,6 +1210,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
CURSOR(circ_supply)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_txs)
|
||||
CURSOR(audit_txs)
|
||||
|
||||
MDB_val_set(val_tx_id, tx_id);
|
||||
MDB_val_set(val_h, tx_hash);
|
||||
@@ -1183,13 +1278,19 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
throw0(DB_ERROR(lmdb_error("Failed to add prunable tx prunable hash to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
|
||||
if (tx.type == cryptonote::transaction_type::MINER) {
|
||||
|
||||
// Update the circulating supply tally because of potentially burnt block_reward proportion
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
|
||||
std::string miner_asset_type = "SAL";
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
miner_asset_type = "SAL1";
|
||||
}
|
||||
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result && (m_height>0 || result != MDB_NOTFOUND))
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally;
|
||||
for (const auto& out: tx.vout) {
|
||||
@@ -1203,20 +1304,44 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent overflow
|
||||
if (burn_tally > burn_tally + tx.amount_burnt)
|
||||
throw0(DB_ERROR("burn overflow detected when adding miner_tx for db transaction"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent underflow
|
||||
if (source_tally < final_source_tally)
|
||||
throw0(DB_ERROR("numeric underflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally > final_burn_tally)
|
||||
throw0(DB_ERROR("burn overflow detected when adding tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
@@ -1240,17 +1365,25 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
MDB_val_copy<uint64_t> source_idx(asset.first);
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result)
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("minted asset not found"));
|
||||
else if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
if (source_tally > source_tally + asset.second)
|
||||
throw0(DB_ERROR("add_transaction_data() - mint overflow"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally + asset.second;
|
||||
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
|
||||
if (source_tally == 0 && result == MDB_NOTFOUND) {
|
||||
if (tx.source_asset_type == "SAL") {
|
||||
final_source_tally += coinbase;
|
||||
}
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before burn =" << source_tally.str() << "\n\tTally after burn =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
if (burn_tally < asset.second)
|
||||
throw0(DB_ERROR("add_transaction_data() - burn underflow"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1308,6 +1441,60 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx yield data to db transaction: ", result).c_str() ));
|
||||
}
|
||||
|
||||
// Is there audit_tx data to add?
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// Create the object we are going to write to the database
|
||||
yield_tx_info audit_data;
|
||||
audit_data.block_height = m_height;
|
||||
audit_data.tx_hash = tx_hash;
|
||||
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
|
||||
if (tx.return_address == crypto::null_pkey)
|
||||
throw0(DB_ERROR("missing return_address entry (needed to create audit data for PROTOCOL_TX) - v2 STAKE"));
|
||||
audit_data.return_address = tx.return_address;
|
||||
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
if (tx.return_address_list.empty())
|
||||
throw0(DB_ERROR("no return_address_list entry (needed to create audit data for the PROTOCOL_TX)"));
|
||||
else if (tx.return_address_list.size() > 1)
|
||||
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create audit data for the PROTOCOL_TX)"));
|
||||
audit_data.return_address = tx.return_address_list[0];
|
||||
}
|
||||
audit_data.locked_coins = tx.amount_burnt;
|
||||
if (tx.vin.empty())
|
||||
throw0(DB_ERROR("tx.vin is empty (needed to create audit data for the PROTOCOL_TX)"));
|
||||
if (tx.vin[0].type() != typeid(cryptonote::txin_to_key))
|
||||
throw0(DB_ERROR("tx.vin[0] is wrong type (needed to create audit data for the PROTOCOL_TX)"));
|
||||
audit_data.return_pubkey = tx.return_pubkey;
|
||||
if (tx.vout.size() != 1)
|
||||
throw0(DB_ERROR("tx.vout is wrong size (needed to create audit data for the PROTOCOL_TX)"));
|
||||
if (!cryptonote::get_output_public_key(tx.vout[0], audit_data.P_change))
|
||||
throw0(DB_ERROR("failed to get P_change from tx.vout[0] (needed to create audit data for the PROTOCOL_TX)"));
|
||||
|
||||
// Because LMDB is shockingly bad at handling duplicates, we have resorted to using a counter of elements
|
||||
// in the first element of the struct.
|
||||
MDB_val data;
|
||||
MDB_val_set(val_height, m_height);
|
||||
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &data, MDB_SET);
|
||||
if (!result)
|
||||
{
|
||||
mdb_size_t num_elems = 0;
|
||||
result = mdb_cursor_count(m_cur_audit_txs, &num_elems);
|
||||
if (result)
|
||||
throw0(DB_ERROR(std::string("Failed to get number of audit TXs for height: ").append(mdb_strerror(result)).c_str()));
|
||||
audit_data.block_height = num_elems;
|
||||
}
|
||||
else if (result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str()));
|
||||
else
|
||||
audit_data.block_height = 0;
|
||||
|
||||
// Now we know how many there are, write out the data to the DB
|
||||
MDB_val_set(val_audit_tx_data, audit_data);
|
||||
result = mdb_cursor_put(m_cur_audit_txs, &val_height, &val_audit_tx_data, MDB_APPENDDUP);
|
||||
if (result)
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx audit data to db transaction: ", result).c_str() ));
|
||||
}
|
||||
|
||||
return tx_id;
|
||||
}
|
||||
|
||||
@@ -1330,6 +1517,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
CURSOR(tx_outputs)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_txs)
|
||||
CURSOR(audit_txs)
|
||||
|
||||
MDB_val_set(val_h, tx_hash);
|
||||
|
||||
@@ -1373,42 +1561,70 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of prunable hash tx to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
|
||||
if (tx.type == cryptonote::transaction_type::MINER) {
|
||||
|
||||
// Update the circulating supply tally because of potentially burnt block_reward proportion
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
|
||||
std::string miner_asset_type = "SAL";
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
miner_asset_type = "SAL1";
|
||||
}
|
||||
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result && (m_height>0 || result != MDB_NOTFOUND))
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("remove_transaction_data() - Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally;
|
||||
for (const auto& out: tx.vout) {
|
||||
|
||||
// Sanity check - prevent underflow
|
||||
if (final_source_tally < final_source_tally - out.amount)
|
||||
throw0(DB_ERROR("remove_transaction_data() - numeric underflow detected when removing miner_tx for db transaction"));
|
||||
throw0(DB_ERROR("numeric underflow detected when removing miner_tx for db transaction"));
|
||||
|
||||
// Fetch the amount for this output
|
||||
final_source_tally -= out.amount;
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally < tx.amount_burnt)
|
||||
throw0(DB_ERROR("burn underflow detected when removing miner_tx for db transaction"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
|
||||
// Sanity check - prevent overflow
|
||||
if (source_tally > source_tally + tx.amount_burnt + tx.rct_signatures.txnFee)
|
||||
throw0(DB_ERROR("remove_transaction_data() - numeric overflow detected when processing C/B/S for db transaction"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent overflow
|
||||
if (source_tally > final_source_tally)
|
||||
throw0(DB_ERROR("numeric overflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before remint =" << source_tally.str() << "\n\tTally after remint =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally < (tx.amount_burnt + tx.rct_signatures.txnFee))
|
||||
throw0(DB_ERROR("burn underflow detected when removing tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
@@ -1422,7 +1638,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
bool ok = cryptonote::get_output_asset_type(out, asset_type);
|
||||
if (!ok)
|
||||
throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)"));
|
||||
|
||||
minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount;
|
||||
}
|
||||
|
||||
@@ -1434,12 +1649,24 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
|
||||
throw0(DB_ERROR("minted asset not found"));
|
||||
else if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
if (source_tally < asset.second)
|
||||
throw0(DB_ERROR("remove_transaction_data() - mint underflow"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before undoing mint =" << source_tally.str() << "\n\tTally after undoing mint =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
if (burn_tally > burn_tally + asset.second)
|
||||
throw0(DB_ERROR("remove_transaction_data() - burn overflow"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
}
|
||||
remove_tx_outputs(tip->data.tx_id, tx);
|
||||
@@ -1456,7 +1683,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
// SRCG: The following code is designed to clean up the STAKE transactions, but it is very poorly written
|
||||
// SRCG: The following code is designed to clean up AUDIT+STAKE transactions, but it is very poorly written
|
||||
// Since transactions are ALWAYS supposed to be created in order, it stands that they should ALWAYS be
|
||||
// removed in REVERSE ORDER. Yet the following loop starts from the beginning - this is the worst possible
|
||||
// implementation in performance terms, since it will ALWAYS take the longest possible time to remove the
|
||||
@@ -1464,6 +1691,30 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
|
||||
// RECODE TO START FROM THE END OF THE DATABASE TABLE, AND THROW AN EXCEPTION IF YOU DO NOT MATCH FIRST TIME!
|
||||
|
||||
// Is there audit_tx data to remove?
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// Remove any yield_tx data for this transaction
|
||||
MDB_val_set(val_height, m_height);
|
||||
MDB_val v;
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
while (1) {
|
||||
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &v, op);
|
||||
if (result == MDB_NOTFOUND) {
|
||||
throw1(DB_ERROR("Failed to locate audit tx for removal from db transaction"));
|
||||
} else if (result) {
|
||||
throw1(DB_ERROR(lmdb_error("Failed to locate audit_tx data for removal: ", result).c_str()));
|
||||
}
|
||||
op = MDB_NEXT_DUP;
|
||||
const yield_tx_info ati = *(const yield_tx_info*)v.mv_data;
|
||||
if (ati.tx_hash == tx_hash) {
|
||||
result = mdb_cursor_del(m_cur_audit_txs, 0);
|
||||
if (result)
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit_tx data to db transaction: ", result).c_str()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is there yield_tx data to remove?
|
||||
if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
// Remove any yield_tx data for this transaction
|
||||
@@ -1970,6 +2221,9 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
lmdb_db_open(txn, LMDB_YIELD_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_yield_txs, "Failed to open db handle for m_yield_txs");
|
||||
lmdb_db_open(txn, LMDB_YIELD_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_yield_blocks, "Failed to open db handle for m_yield_blocks");
|
||||
|
||||
lmdb_db_open(txn, LMDB_AUDIT_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_audit_txs, "Failed to open db handle for m_audit_txs");
|
||||
lmdb_db_open(txn, LMDB_AUDIT_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_audit_blocks, "Failed to open db handle for m_audit_blocks");
|
||||
|
||||
mdb_set_dupsort(txn, m_spent_keys, compare_hash32);
|
||||
mdb_set_dupsort(txn, m_block_heights, compare_hash32);
|
||||
mdb_set_dupsort(txn, m_tx_indices, compare_hash32);
|
||||
@@ -1993,6 +2247,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
mdb_set_compare(txn, m_circ_supply_tally, compare_uint64);
|
||||
|
||||
mdb_set_dupsort(txn, m_yield_txs, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_audit_txs, compare_uint64);
|
||||
|
||||
if (!(mdb_flags & MDB_RDONLY))
|
||||
{
|
||||
@@ -2174,6 +2429,10 @@ void BlockchainLMDB::reset()
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_txs: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_yield_blocks, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_blocks: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_audit_txs, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_txs: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_audit_blocks, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_blocks: ", result).c_str()));
|
||||
|
||||
// init with current version
|
||||
MDB_val_str(k, "version");
|
||||
@@ -3516,7 +3775,7 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
|
||||
// Check for SAL - we need to adjust the total for them
|
||||
if (currency_type == 0) {
|
||||
// Get the current circulating supply for SAL
|
||||
amount += m_coinbase;
|
||||
//amount += m_coinbase;
|
||||
}
|
||||
|
||||
circulating_supply[currency_label] = amount.convert_to<uint64_t>();
|
||||
@@ -3527,12 +3786,13 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
|
||||
// NEAC: check for empty supply tally - only happens prior to first conversion on chain
|
||||
if (circulating_supply.empty()) {
|
||||
circulating_supply["SAL"] = m_coinbase;
|
||||
circulating_supply["SAL1"] = 0;
|
||||
circulating_supply["BURN"] = 0;
|
||||
}
|
||||
|
||||
// Adjust the supply to account for the staked coins
|
||||
circulating_supply["STAKE"] = staked_coins;
|
||||
|
||||
circulating_supply["BURN"] = m_coinbase - circulating_supply["SAL"] - circulating_supply["STAKE"];
|
||||
|
||||
return circulating_supply;
|
||||
}
|
||||
|
||||
@@ -4724,7 +4984,7 @@ void BlockchainLMDB::block_rtxn_abort() const
|
||||
}
|
||||
|
||||
uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated,
|
||||
const std::vector<std::pair<transaction, blobdata>>& txs, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi)
|
||||
const std::vector<std::pair<transaction, blobdata>>& txs, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
@@ -4742,7 +5002,7 @@ uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t
|
||||
|
||||
try
|
||||
{
|
||||
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi);
|
||||
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi, abi);
|
||||
}
|
||||
catch (const DB_ERROR_TXN_START& e)
|
||||
{
|
||||
@@ -5239,8 +5499,38 @@ uint64_t BlockchainLMDB::get_database_size() const
|
||||
|
||||
#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global"))
|
||||
|
||||
void BlockchainLMDB::migrate_2_3()
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
uint64_t i;
|
||||
int result;
|
||||
mdb_txn_safe txn(false);
|
||||
MDB_val k, v;
|
||||
char *ptr;
|
||||
|
||||
MGINFO_YELLOW("Migrating blockchain from DB version 2 to 3 - this may take a while:");
|
||||
|
||||
// Create the missing (and empty) "audit_block_info" records for all blocks
|
||||
do {
|
||||
} while(0);
|
||||
|
||||
uint32_t version = VERSION;
|
||||
v.mv_data = (void *)&version;
|
||||
v.mv_size = sizeof(version);
|
||||
MDB_val_str(vk, "version");
|
||||
result = mdb_txn_begin(m_env, NULL, 0, txn);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
|
||||
result = mdb_put(txn, m_properties, &vk, &v, 0);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to update version for the db: ", result).c_str()));
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
void BlockchainLMDB::migrate(const uint32_t oldversion)
|
||||
{
|
||||
//if (oldversion < 3)
|
||||
// migrate_2_3();
|
||||
}
|
||||
|
||||
} // namespace cryptonote
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -297,6 +297,9 @@ monero_add_executable(blockchain_scanner
|
||||
|
||||
target_link_libraries(blockchain_scanner
|
||||
PRIVATE
|
||||
wallet
|
||||
crypto
|
||||
cncrypto
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
version
|
||||
|
||||
@@ -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++;
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -315,13 +315,26 @@ namespace cryptonote
|
||||
}
|
||||
}
|
||||
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: This FAILS under certain circumstances to find the correct subaddress for STAKE returns, and this BREAKS AUDITING
|
||||
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);
|
||||
/*
|
||||
if (use_origin_data) {
|
||||
// Try something a little special to find the subaddress index
|
||||
crypto::key_derivation recv_derivation_od = AUTO_VAL_INIT(recv_derivation_od);
|
||||
r = hwdev.generate_key_derivation(od.tx_pub_key, ack.m_view_secret_key, recv_derivation_od);
|
||||
boost::optional<subaddress_receive_info> subaddr_recv_info_od = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation_od, additional_recv_derivations, od.output_index,hwdev);
|
||||
}
|
||||
*/
|
||||
// LAND AHOY!!!
|
||||
|
||||
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 +413,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 +428,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 +453,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 +991,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 +1008,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 +1284,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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+25
-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,17 @@
|
||||
|
||||
#define HF_VERSION_ENFORCE_FULL_PROOFS 4
|
||||
|
||||
#define HF_VERSION_SHUTDOWN_USER_TXS 5
|
||||
|
||||
#define HF_VERSION_AUDIT1 6
|
||||
#define HF_VERSION_SALVIUM_ONE_PROOFS 6
|
||||
|
||||
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
|
||||
#define HF_VERSION_ENABLE_CONVERT 255
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
#define HF_VERSION_SLIPPAGE_YIELD 255
|
||||
|
||||
#define TESTNET_VERSION 12
|
||||
#define TESTNET_VERSION 13
|
||||
#define STAGENET_VERSION 1
|
||||
|
||||
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
|
||||
@@ -278,10 +287,13 @@ namespace config
|
||||
|
||||
uint32_t const GENESIS_NONCE = 10000;
|
||||
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> AUDIT_HARD_FORKS = { {HF_VERSION_AUDIT1, {"SAL", "SAL1"}} };
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30*24*10;
|
||||
|
||||
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
|
||||
|
||||
|
||||
// Hash domain separators
|
||||
const char HASH_KEY_BULLETPROOF_EXPONENT[] = "bulletproof";
|
||||
const char HASH_KEY_BULLETPROOF_PLUS_EXPONENT[] = "bulletproof_plus";
|
||||
@@ -352,6 +364,7 @@ namespace config
|
||||
uint32_t const GENESIS_NONCE = 10001;
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 20;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30;
|
||||
|
||||
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
|
||||
|
||||
@@ -378,6 +391,7 @@ namespace config
|
||||
uint32_t const GENESIS_NONCE = 10002;
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 20;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30;
|
||||
|
||||
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
|
||||
|
||||
@@ -413,7 +427,9 @@ namespace cryptonote
|
||||
uint32_t const GENESIS_NONCE;
|
||||
std::array<std::string, 3> const ORACLE_URLS;
|
||||
std::string const ORACLE_PUBLIC_KEY;
|
||||
uint64_t STAKE_LOCK_PERIOD;
|
||||
uint64_t const STAKE_LOCK_PERIOD;
|
||||
uint64_t const AUDIT_LOCK_PERIOD;
|
||||
std::map<uint8_t, std::pair<std::string, std::string>> const AUDIT_HARD_FORKS;
|
||||
std::string TREASURY_ADDRESS;
|
||||
};
|
||||
inline const config_t& get_config(network_type nettype)
|
||||
@@ -431,6 +447,8 @@ namespace cryptonote
|
||||
::config::ORACLE_URLS,
|
||||
::config::ORACLE_PUBLIC_KEY,
|
||||
::config::STAKE_LOCK_PERIOD,
|
||||
::config::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::TREASURY_ADDRESS
|
||||
};
|
||||
static const config_t testnet = {
|
||||
@@ -446,6 +464,8 @@ namespace cryptonote
|
||||
::config::testnet::ORACLE_URLS,
|
||||
::config::testnet::ORACLE_PUBLIC_KEY,
|
||||
::config::testnet::STAKE_LOCK_PERIOD,
|
||||
::config::testnet::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::testnet::TREASURY_ADDRESS
|
||||
};
|
||||
static const config_t stagenet = {
|
||||
@@ -461,6 +481,8 @@ namespace cryptonote
|
||||
::config::stagenet::ORACLE_URLS,
|
||||
::config::stagenet::ORACLE_PUBLIC_KEY,
|
||||
::config::stagenet::STAKE_LOCK_PERIOD,
|
||||
::config::stagenet::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::stagenet::TREASURY_ADDRESS
|
||||
};
|
||||
switch (nettype)
|
||||
|
||||
@@ -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,8 @@ 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:
|
||||
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,9 +1550,12 @@ 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;
|
||||
@@ -1558,22 +1565,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 +1642,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
|
||||
@@ -1912,6 +1969,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 +3614,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 +3740,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 +3781,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 +3922,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 +3935,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;
|
||||
@@ -3846,6 +3964,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 +4032,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 +4065,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 +4090,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 +4473,57 @@ uint64_t Blockchain::get_adjusted_time(uint64_t height) const
|
||||
return (adjusted_current_block_ts < median_ts ? adjusted_current_block_ts : median_ts);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::calculate_audit_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& audit_container)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
// Clear the audit payout amounts
|
||||
audit_container.clear();
|
||||
|
||||
// Get the AUDIT TX information for matured staked coins
|
||||
std::vector<cryptonote::yield_tx_info> audit_entries;
|
||||
// We get the audit_tx_info from the block where they entered the chain
|
||||
int audit_tx_result = m_db->get_audit_tx_info(start_height, audit_entries);
|
||||
if (!audit_entries.size()) {
|
||||
|
||||
// Report error and abort
|
||||
LOG_ERROR("calculate_audit_payouts() called, but no audit TXs found at height " << start_height << " - aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build a blacklist of staking TXs _not_ to pay out for
|
||||
const std::set<std::string> txs_blacklist = {};
|
||||
|
||||
// Get the ABI information for the 21,600 blocks that the matured TX(s), we can calculate audit
|
||||
for (const auto& entry: audit_entries) {
|
||||
// Check to see if this entry is in the blacklist
|
||||
if (txs_blacklist.find(epee::string_tools::pod_to_hex(entry.tx_hash)) != txs_blacklist.end()) {
|
||||
LOG_ERROR("calculate_audit_payouts() found blacklisted TX at height " << start_height << " - skipping payout");
|
||||
continue;
|
||||
}
|
||||
audit_container.emplace_back(std::make_pair(entry, entry.locked_coins));
|
||||
}
|
||||
|
||||
// Return success to caller
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::get_abi_entry(const uint64_t height, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
// Clear the provided container
|
||||
std::memset(&abi, 0, sizeof(struct cryptonote::audit_block_info));
|
||||
|
||||
int result = m_db->get_audit_block_info(height, abi);
|
||||
if (result) {
|
||||
// Request failed - report error and bail out
|
||||
LOG_ERROR("failed to retrieve ABI entry for height " << height << " - aborting");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_container)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
@@ -4365,9 +4541,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 +5139,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 +5970,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,22 @@ 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);
|
||||
std::string asset_type = "SAL";
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
asset_type = "SAL1";
|
||||
cryptonote::set_tx_out(entry.amount_burnt, asset_type, 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;
|
||||
std::string asset_type = "SAL";
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
asset_type = "SAL1";
|
||||
cryptonote::set_tx_out(entry.amount_burnt, asset_type, 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 +452,8 @@ 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:
|
||||
// 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 +464,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 +513,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 +701,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 +735,22 @@ 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;
|
||||
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 +776,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 +802,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 +838,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 +859,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 +888,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 +978,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 +1173,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 +1201,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,14 @@ namespace cryptonote
|
||||
continue;
|
||||
}
|
||||
|
||||
// HERE BE DRAGONS!!!
|
||||
// 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;
|
||||
}
|
||||
// LAND AHOY!!!
|
||||
|
||||
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,9 @@ 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 },
|
||||
};
|
||||
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 +59,15 @@ const hardfork_t testnet_hard_forks[] = {
|
||||
|
||||
// version 3 starts from block 500
|
||||
{ 3, 500, 0, 1729518000 },
|
||||
|
||||
// version 4 (full proofs) starts from block 600
|
||||
{ 4, 600, 0, 1734607000 },
|
||||
|
||||
// version 5 (TX shutdown) starts from block 800
|
||||
{ 5, 800, 0, 1734607005 },
|
||||
|
||||
// version 6 (audit) starts from block 815
|
||||
{ 6, 815, 0, 1734608000 },
|
||||
};
|
||||
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
|
||||
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
|
||||
@@ -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");
|
||||
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.");
|
||||
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 for 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,24 @@ 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;
|
||||
} 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;
|
||||
} 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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
message_writer(asset_type == "SAL" ? console_color_green : console_color_blue, false) << "\r" <<
|
||||
@@ -6720,6 +6738,13 @@ bool simple_wallet::transfer_main(
|
||||
if (!try_connect_to_daemon())
|
||||
return false;
|
||||
|
||||
bool audit = false;
|
||||
if (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (transfer_type == Audit) {
|
||||
audit = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> local_args = args_;
|
||||
|
||||
std::set<uint32_t> subaddr_indices;
|
||||
@@ -6728,7 +6753,9 @@ bool simple_wallet::transfer_main(
|
||||
if (!parse_subaddress_indices(local_args[0], subaddr_indices))
|
||||
return false;
|
||||
local_args.erase(local_args.begin());
|
||||
}
|
||||
if (transfer_type == Audit)
|
||||
while (subaddr_indices.size() > 1)
|
||||
subaddr_indices.erase(std::prev(subaddr_indices.end())); }
|
||||
|
||||
uint32_t priority = m_wallet->get_default_priority();
|
||||
if (local_args.size() > 0 && parse_priority(local_args[0], priority))
|
||||
@@ -6766,7 +6793,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 +6971,35 @@ bool simple_wallet::transfer_main(
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector;
|
||||
uint64_t unlock_block = 0;
|
||||
std::string err;
|
||||
cryptonote::address_parse_info info;
|
||||
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 Audit:
|
||||
unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD;
|
||||
ptx_vector = m_wallet->create_transactions_all(0, cryptonote::transaction_type::AUDIT, source_asset, m_wallet->get_subaddress({m_current_subaddress_account, 0}), false, 1, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices);
|
||||
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 +7101,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 +7261,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 +7302,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();
|
||||
}
|
||||
@@ -8056,6 +8094,14 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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 we were looking for - take a copy of the key_image, etc.
|
||||
transfers_indices.push_back(idx);
|
||||
break;
|
||||
@@ -8200,7 +8246,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 +8310,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 +8320,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 +8344,36 @@ 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
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<std::string> local_args = args_;
|
||||
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 +8392,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) {
|
||||
|
||||
@@ -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.0-rc6"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.3.3"
|
||||
#define DEF_MONERO_RELEASE_NAME "Zero"
|
||||
|
||||
+131
-41
@@ -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,11 @@ 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;
|
||||
|
||||
// HERE BE DRAGONS!!!
|
||||
// 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;
|
||||
// LAND AHOY!!!
|
||||
}
|
||||
|
||||
if (m_multisig)
|
||||
@@ -2218,7 +2230,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");
|
||||
@@ -2425,7 +2437,7 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
|
||||
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 (td.m_tx.type == cryptonote::transaction_type::STAKE || td.m_tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
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));
|
||||
} else {
|
||||
@@ -2434,7 +2446,7 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@@ -2486,7 +2498,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 +2556,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 +2755,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 +2889,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,13 +2899,14 @@ 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 << " *****");
|
||||
LOG_PRINT_L1("***** STAKED/AUDITED COINS : " << tx.amount_burnt << " *****");
|
||||
m_locked_coins.insert({P_change, {0, tx.amount_burnt}});
|
||||
}
|
||||
|
||||
@@ -7944,13 +7957,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 +9477,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 +9743,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 +9766,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 +9921,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 +10130,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 +10185,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 +10223,20 @@ 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();
|
||||
// HERE BE DRAGONS!!!
|
||||
// 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});
|
||||
}
|
||||
// LAND AHOY!!!
|
||||
|
||||
crypto::secret_key tx_key;
|
||||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
crypto::secret_key multisig_tx_key_entropy;
|
||||
@@ -10230,7 +10280,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 +10702,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 +10746,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 +11389,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 +11415,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 +11481,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)
|
||||
@@ -11594,7 +11662,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 +11735,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 +12364,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 +12373,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 +12589,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 +12603,14 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
|
||||
received += amount;
|
||||
}
|
||||
}
|
||||
|
||||
// HERE BE DRAGONS!!!
|
||||
// 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;
|
||||
}
|
||||
// LAND AHOY!!!
|
||||
}
|
||||
|
||||
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 +12864,11 @@ 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);
|
||||
// HERE BE DRAGONS!!!
|
||||
// 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."));
|
||||
|
||||
// LAND AHOY!!!
|
||||
|
||||
// concatenate all signature strings
|
||||
for (size_t i = 0; i < num_sigs; ++i)
|
||||
sig_str +=
|
||||
@@ -13032,11 +13117,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 +13295,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 +13750,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 +14345,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 +14356,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 +14455,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 +14465,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 +14674,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 +14685,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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user