30 #include <boost/algorithm/string.hpp> 31 #include <boost/range/adaptor/transformed.hpp> 32 #include <boost/filesystem.hpp> 39 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 40 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "wallet.ringdb" 42 static const char zerokey[8] = {0};
43 static const MDB_val zerokeyval = {
sizeof(zerokey), (
void *)zerokey };
49 for (
int n = 7; n >= 0; n--)
53 return va[n] < vb[n] ? -1 : 1;
63 return va < vb ? -1 : va > vb;
66 static std::string compress_ring(
const std::vector<uint64_t> &ring)
74 static std::vector<uint64_t> decompress_ring(
const std::string &s)
76 std::vector<uint64_t> ring;
78 for (std::string::const_iterator i = s.begin(); i != s.cend(); std::advance(i, read))
82 read = tools::read_varint(tmp.begin(), tmp.end(),
out);
91 if (!boost::filesystem::is_directory(filename))
92 filename.remove_filename();
93 return filename.string();
98 static const char salt[] =
"ringdsb";
106 static_assert(
sizeof(
hash) >=
CHACHA_IV_SIZE,
"Incompatible hash and chacha IV sizes");
107 crypto::chacha_iv iv;
116 ciphertext.resize(plaintext.size() +
sizeof(iv));
118 memcpy(&ciphertext[0], &iv,
sizeof(iv));
132 plaintext.resize(ciphertext.size() -
sizeof(iv));
133 crypto::chacha20(ciphertext.data() +
sizeof(iv), ciphertext.size() -
sizeof(iv),
key, iv, &plaintext[0]);
141 key.mv_data = (
void*)key_ciphertext.data();
142 key.mv_size = key_ciphertext.size();
143 std::string compressed_ring = compress_ring(relative_ring);
145 data.
mv_size = data_ciphertext.size();
146 data.
mv_data = (
void*)data_ciphertext.c_str();
151 static int resize_env(
MDB_env *env,
const char *db_path,
size_t needed)
157 needed = std::max(needed, (
size_t)(100ul * 1024 * 1024));
171 boost::filesystem::path path(db_path);
172 boost::filesystem::space_info si = boost::filesystem::space(path);
173 if(si.available < needed)
175 MERROR(
"!! WARNING: Insufficient free space to extend database !!: " << (si.available >> 20L) <<
" MB available");
182 MWARNING(
"Unable to query free disk space.");
190 static size_t get_ring_data_size(
size_t n_entries)
192 return n_entries * (32 + 1024);
205 bool tx_active =
false;
215 dbr =
mdb_env_open(env, actual_filename.c_str(), 0, 0664);
257 bool tx_active =
false;
259 dbr = resize_env(env, filename.c_str(), get_ring_data_size(tx.
vin.size()));
266 for (
const auto &in: tx.
vin)
270 const auto &txin = boost::get<cryptonote::txin_to_key>(in);
271 const uint32_t ring_size = txin.key_offsets.size();
275 store_relative_ring(txn, dbi_rings, txin.k_image, txin.key_offsets, chacha_key);
284 bool ringdb::remove_rings(
const crypto::chacha_key &chacha_key,
const std::vector<crypto::key_image> &key_images)
288 bool tx_active =
false;
290 dbr = resize_env(env, filename.c_str(), 0);
301 key.mv_data = (
void*)key_ciphertext.data();
302 key.mv_size = key_ciphertext.size();
323 std::vector<crypto::key_image> key_images;
324 key_images.reserve(tx.
vin.size());
325 for (
const auto &in: tx.
vin)
329 const auto &txin = boost::get<cryptonote::txin_to_key>(in);
330 const uint32_t ring_size = txin.key_offsets.size();
333 key_images.push_back(txin.k_image);
342 bool tx_active =
false;
344 dbr = resize_env(env, filename.c_str(), 0);
353 key.mv_data = (
void*)key_ciphertext.data();
354 key.mv_size = key_ciphertext.size();
362 outs = decompress_ring(data_plaintext);
378 bool tx_active =
false;
380 dbr = resize_env(env, filename.c_str(), outs.size() * 64);
395 bool ringdb::blackball_worker(
const std::vector<std::pair<uint64_t, uint64_t>> &outputs,
int op)
400 bool tx_active =
false;
405 dbr = resize_env(env, filename.c_str(), 32 * 2 * outputs.size());
416 for (
const std::pair<uint64_t, uint64_t> &output: outputs)
418 key.mv_data = (
void*)&output.first;
419 key.mv_size =
sizeof(output.first);
420 data.
mv_data = (
void*)&output.second;
421 data.
mv_size =
sizeof(output.second);
426 MDEBUG(
"Marking output " << output.first <<
"/" << output.second <<
" as spent");
432 MDEBUG(
"Marking output " << output.first <<
"/" << output.second <<
" as unspent");
456 dbr =
mdb_drop(txn, dbi_blackballs, 0);
473 std::vector<std::pair<uint64_t, uint64_t>> outputs(1, output);
479 std::vector<std::pair<uint64_t, uint64_t>> outputs(1, output);
485 std::vector<std::pair<uint64_t, uint64_t>> outputs(1, output);
491 return blackball_worker(std::vector<std::pair<uint64_t, uint64_t>>(),
BLACKBALL_CLEAR);
int mdb_env_set_mapsize(MDB_env *env, mdb_size_t size)
Set the size of the memory map to use for this environment.
void mdb_cursor_close(MDB_cursor *cursor)
Close a cursor handle.
int mdb_del(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data)
Delete items from a database.
int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi)
Open a database in the environment.
Lightning memory-mapped database library.
std::string get_rings_filename(boost::filesystem::path filename)
int mdb_txn_commit(MDB_txn *txn)
Commit all the operations of a transaction into the database.
int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data, unsigned int flags)
Store by cursor.
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
void mdb_dbi_close(MDB_env *env, MDB_dbi dbi)
Close a database handle. Normally unnecessary. Use with care:
void chacha20(const void *data, size_t length, const uint8_t *key, const uint8_t *iv, char *cipher)
int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
Set a custom data comparison function for a MDB_DUPSORT database.
int mdb_env_info(MDB_env *env, MDB_envinfo *stat)
Return information about the LMDB environment.
int mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs)
Set the maximum number of named databases for the environment.
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
struct MDB_env MDB_env
Opaque structure for a database environment.
struct MDB_txn MDB_txn
Opaque structure for a transaction handle.
int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
Empty or delete+close a database.
std::vector< txin_v > vin
int mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode)
Open an environment handle.
Statistics for a database in the environment.
Information about the environment.
std::vector< uint64_t > absolute_output_offsets_to_relative(const std::vector< uint64_t > &off)
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
unsigned __int64 uint64_t
int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
Set a custom key comparison function for a database.
unsigned int MDB_dbi
A handle for an individual database in the DB environment.
int mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn)
Create a transaction for use with the environment.
void cn_fast_hash(const void *data, size_t length, char *hash)
int mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op op)
Retrieve by cursor.
int mdb_env_create(MDB_env **env)
Create an LMDB environment handle.
void mdb_txn_abort(MDB_txn *txn)
Abandon all the operations of the transaction instead of saving them.
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
void decrypt(const void *ciphertext, size_t length, const uint8_t *key, const uint8_t *iv, char *plaintext, size_t *plaintext_len)
struct MDB_cursor MDB_cursor
Opaque structure for navigating through a database.
Generic structure used for passing keys and data in and out of the database.
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
void * memcpy(void *a, const void *b, size_t c)
int mdb_env_stat(MDB_env *env, MDB_stat *stat)
Return statistics about the LMDB environment.
char * mdb_strerror(int err)
Return a string describing a given error code.
int mdb_cursor_del(MDB_cursor *cursor, unsigned int flags)
Delete current key/data pair.
#define THROW_WALLET_EXCEPTION(err_type,...)
std::string to_string(t_connection_type type)
int compare_uint64(const MDB_val *a, const MDB_val *b)
int mdb_get(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data)
Get items from a database.
int mdb_put(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned int flags)
Store items into a database.
void mdb_env_close(MDB_env *env)
Close the environment and release the memory map.
int mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **cursor)
Create a cursor handle.