@ -145,9 +145,34 @@ int compare_string(const MDB_val *a, const MDB_val *b)
return strcmp ( va , vb ) ;
return strcmp ( va , vb ) ;
}
}
/* DB schema:
*
* Table Key Data
* - - - - - - - - - - - -
* blocks block ID block blob
* block_heights block hash block height
* block_info block ID { block metadata }
*
* txs txn ID txn blob
* tx_indices txn hash { txn ID , metadata }
* tx_outputs txn ID [ txn amount output indices ]
*
* output_txs output ID { txn hash , local index }
* output_amounts amount [ { amount output index , metadata } . . . ]
*
* spent_keys output hash -
*
* 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
* attached as a prefix on the Data to serve as the DUPSORT key .
* ( DUPFIXED saves 8 bytes per record . )
*
* The output_amounts table doesn ' t use a dummy key , but uses DUPSORT .
*/
const char * const LMDB_BLOCKS = " blocks " ;
const char * const LMDB_BLOCKS = " blocks " ;
const char * const LMDB_BLOCK_INFO = " block_info " ;
const char * const LMDB_BLOCK_HEIGHTS = " block_heights " ;
const char * const LMDB_BLOCK_HEIGHTS = " block_heights " ;
const char * const LMDB_BLOCK_INFO = " block_info " ;
const char * const LMDB_TXS = " txs " ;
const char * const LMDB_TXS = " txs " ;
const char * const LMDB_TX_INDICES = " tx_indices " ;
const char * const LMDB_TX_INDICES = " tx_indices " ;
@ -215,8 +240,8 @@ typedef struct mdb_block_info
} mdb_block_info ;
} mdb_block_info ;
typedef struct blk_height {
typedef struct blk_height {
crypto : : hash key ;
crypto : : hash bh_hash ;
uint64_t height;
uint64_t bh_ height;
} blk_height ;
} blk_height ;
typedef struct txindex {
typedef struct txindex {
@ -226,12 +251,12 @@ typedef struct txindex {
typedef struct outkey {
typedef struct outkey {
uint64_t amount_index ;
uint64_t amount_index ;
uint64_t tx _in dex ;
uint64_t outpu t_id;
output_data_t data ;
output_data_t data ;
} outkey ;
} outkey ;
typedef struct outtx {
typedef struct outtx {
uint64_t txnum ;
uint64_t output_id ;
crypto : : hash tx_hash ;
crypto : : hash tx_hash ;
uint64_t local_index ;
uint64_t local_index ;
} outtx ;
} outtx ;
@ -560,14 +585,13 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
CURSOR ( block_heights )
CURSOR ( block_heights )
blk_height bh = { blk_hash , m_height } ;
blk_height bh = { blk_hash , m_height } ;
MDB_val val_h = { sizeof ( bh ) , ( void * ) & bh } ;
MDB_val _set( val_h , bh ) ;
if ( mdb_cursor_get ( m_cur_block_heights , ( MDB_val * ) & zerokval , & val_h , MDB_GET_BOTH ) = = 0 )
if ( mdb_cursor_get ( m_cur_block_heights , ( MDB_val * ) & zerokval , & val_h , MDB_GET_BOTH ) = = 0 )
throw1 ( BLOCK_EXISTS ( " Attempting to add block that's already in the db " ) ) ;
throw1 ( BLOCK_EXISTS ( " Attempting to add block that's already in the db " ) ) ;
if ( m_height > 0 )
if ( m_height > 0 )
{
{
blk_height ph = { blk . prev_id , 0 } ;
MDB_val_set ( parent_key , blk . prev_id ) ;
MDB_val parent_key = { sizeof ( ph ) , ( void * ) & ph } ;
int result = mdb_cursor_get ( m_cur_block_heights , ( MDB_val * ) & zerokval , & parent_key , MDB_GET_BOTH ) ;
int result = mdb_cursor_get ( m_cur_block_heights , ( MDB_val * ) & zerokval , & parent_key , MDB_GET_BOTH ) ;
if ( result )
if ( result )
{
{
@ -576,13 +600,13 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
throw0 ( DB_ERROR ( lmdb_error ( " Failed to get top block hash to check for new block's parent: " , result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " Failed to get top block hash to check for new block's parent: " , result ) . c_str ( ) ) ) ;
}
}
blk_height * prev = ( blk_height * ) parent_key . mv_data ;
blk_height * prev = ( blk_height * ) parent_key . mv_data ;
if ( prev - > height ! = m_height - 1 )
if ( prev - > bh_ height ! = m_height - 1 )
throw0 ( BLOCK_PARENT_DNE ( " Top block is not new block's parent " ) ) ;
throw0 ( BLOCK_PARENT_DNE ( " Top block is not new block's parent " ) ) ;
}
}
int result = 0 ;
int result = 0 ;
MDB_val_ copy< uint64_t > key ( m_height ) ;
MDB_val_ set( key , m_height ) ;
CURSOR ( blocks )
CURSOR ( blocks )
CURSOR ( block_info )
CURSOR ( block_info )
@ -600,7 +624,7 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
bi . bi_diff = cumulative_difficulty ;
bi . bi_diff = cumulative_difficulty ;
bi . bi_hash = blk_hash ;
bi . bi_hash = blk_hash ;
MDB_val val = { sizeof ( bi ) , ( void * ) & bi } ;
MDB_val _set( val , bi ) ;
result = mdb_cursor_put ( m_cur_block_info , ( MDB_val * ) & zerokval , & val , MDB_APPENDDUP ) ;
result = mdb_cursor_put ( m_cur_block_info , ( MDB_val * ) & zerokval , & val , MDB_APPENDDUP ) ;
if ( result )
if ( result )
throw0 ( DB_ERROR ( lmdb_error ( " Failed to add block info to db transaction: " , result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " Failed to add block info to db transaction: " , result ) . c_str ( ) ) ) ;
@ -657,26 +681,27 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
check_open ( ) ;
check_open ( ) ;
mdb_txn_cursors * m_cursors = & m_wcursors ;
mdb_txn_cursors * m_cursors = & m_wcursors ;
int result = 0 ;
int result ;
uint64_t tx_i n dex = m_num_txs ;
uint64_t tx_i d = m_num_txs ;
CURSOR ( txs )
CURSOR ( txs )
CURSOR ( tx_indices )
CURSOR ( tx_indices )
txindex ti = { tx_hash } ;
MDB_val_set ( val_tx_id , tx_id ) ;
MDB_val_copy < uint64_t > val_tx_index ( tx_index ) ;
MDB_val_set ( val_h , tx_hash ) ;
MDB_val val_h = { sizeof ( ti ) , ( void * ) & ti } ;
result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & val_h , MDB_GET_BOTH ) ;
result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & val_h , MDB_GET_BOTH ) ;
if ( result = = 0 ) {
if ( result = = 0 ) {
txindex * tip = ( txindex * ) val_h . mv_data ;
txindex * tip = ( txindex * ) val_h . mv_data ;
throw1 ( TX_EXISTS ( std : : string ( " Attempting to add transaction that's already in the db (tx i n dex " ) . append ( boost : : lexical_cast < std : : string > ( tip - > data . tx_i n dex ) ) . append ( " ) " ) . c_str ( ) ) ) ;
throw1 ( TX_EXISTS ( std : : string ( " Attempting to add transaction that's already in the db (tx i d " ) . append ( boost : : lexical_cast < std : : string > ( tip - > data . tx_i d) ) . append ( " ) " ) . c_str ( ) ) ) ;
} else if ( result ! = MDB_NOTFOUND ) {
} else if ( result ! = MDB_NOTFOUND ) {
throw1 ( DB_ERROR ( lmdb_error ( std : : string ( " Error checking if tx index exists for tx hash " ) + epee : : string_tools : : pod_to_hex ( tx_hash ) + " : " , result ) . c_str ( ) ) ) ;
throw1 ( DB_ERROR ( lmdb_error ( std : : string ( " Error checking if tx index exists for tx hash " ) + epee : : string_tools : : pod_to_hex ( tx_hash ) + " : " , result ) . c_str ( ) ) ) ;
}
}
ti . data . tx_index = tx_index ;
txindex ti ;
ti . key = tx_hash ;
ti . data . tx_id = tx_id ;
ti . data . unlock_time = tx . unlock_time ;
ti . data . unlock_time = tx . unlock_time ;
ti . data . height = m_height ;
ti . data . block_id = m_height ; // we don't need blk_hash since we know m_height
val_h . mv_size = sizeof ( ti ) ;
val_h . mv_size = sizeof ( ti ) ;
val_h . mv_data = ( void * ) & ti ;
val_h . mv_data = ( void * ) & ti ;
@ -686,12 +711,12 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
throw0 ( DB_ERROR ( lmdb_error ( " Failed to add tx data to db transaction: " , result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " Failed to add tx data to db transaction: " , result ) . c_str ( ) ) ) ;
MDB_val_copy < blobdata > blob ( tx_to_blob ( tx ) ) ;
MDB_val_copy < blobdata > blob ( tx_to_blob ( tx ) ) ;
result = mdb_cursor_put ( m_cur_txs , & val_tx_i n dex , & blob , MDB_APPEND ) ;
result = mdb_cursor_put ( m_cur_txs , & val_tx_i d, & blob , MDB_APPEND ) ;
if ( result )
if ( result )
throw0 ( DB_ERROR ( lmdb_error ( " Failed to add tx blob to db transaction: " , result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " Failed to add tx blob to db transaction: " , result ) . c_str ( ) ) ) ;
m_num_txs + + ;
m_num_txs + + ;
return tx_i n dex ;
return tx_i d;
}
}
// TODO: compare pros and cons of looking up the tx hash's tx index once and
// TODO: compare pros and cons of looking up the tx hash's tx index once and
@ -708,24 +733,22 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
CURSOR ( txs )
CURSOR ( txs )
CURSOR ( tx_outputs )
CURSOR ( tx_outputs )
txindex ti = { tx_hash } ;
MDB_val_set ( val_h , tx_hash ) ;
MDB_val val_h = { sizeof ( ti ) , ( void * ) & ti } ;
if ( mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & val_h , MDB_GET_BOTH ) )
if ( mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & val_h , MDB_GET_BOTH ) )
throw1 ( TX_DNE ( " Attempting to remove transaction that isn't in the db " ) ) ;
throw1 ( TX_DNE ( " Attempting to remove transaction that isn't in the db " ) ) ;
txindex * tip = ( txindex * ) val_h . mv_data ;
txindex * tip = ( txindex * ) val_h . mv_data ;
uint64_t tx_index = tip - > data . tx_index ;
MDB_val_set ( val_tx_id , tip - > data . tx_id ) ;
MDB_val_copy < uint64_t > val_tx_index ( tx_index ) ;
if ( ( result = mdb_cursor_get ( m_cur_txs , & val_tx_i n dex , NULL , MDB_SET ) ) )
if ( ( result = mdb_cursor_get ( m_cur_txs , & val_tx_i d, NULL , MDB_SET ) ) )
throw1 ( DB_ERROR ( lmdb_error ( " Failed to locate tx for removal: " , result ) . c_str ( ) ) ) ;
throw1 ( DB_ERROR ( lmdb_error ( " Failed to locate tx for removal: " , result ) . c_str ( ) ) ) ;
result = mdb_cursor_del ( m_cur_txs , 0 ) ;
result = mdb_cursor_del ( m_cur_txs , 0 ) ;
if ( result )
if ( result )
throw1 ( DB_ERROR ( lmdb_error ( " Failed to add removal of tx to db transaction: " , result ) . c_str ( ) ) ) ;
throw1 ( DB_ERROR ( lmdb_error ( " Failed to add removal of tx to db transaction: " , result ) . c_str ( ) ) ) ;
remove_tx_outputs ( t x_in dex , tx ) ;
remove_tx_outputs ( t ip- > data . t x_id, tx ) ;
result = mdb_cursor_get ( m_cur_tx_outputs , & val_tx_i n dex , NULL , MDB_SET ) ;
result = mdb_cursor_get ( m_cur_tx_outputs , & val_tx_i d, NULL , MDB_SET ) ;
if ( result = = MDB_NOTFOUND )
if ( result = = MDB_NOTFOUND )
LOG_PRINT_L1 ( " tx has no outputs to remove: " < < tx_hash ) ;
LOG_PRINT_L1 ( " tx has no outputs to remove: " < < tx_hash ) ;
else if ( result )
else if ( result )
@ -737,24 +760,17 @@ 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 ( ) ) ) ;
throw1 ( DB_ERROR ( lmdb_error ( " Failed to add removal of tx outputs to db transaction: " , result ) . c_str ( ) ) ) ;
}
}
// Though other things could change, so long as earlier functions (like
// Don't delete the tx_indices entry until the end, after we're done with val_tx_id
// remove_tx_outputs) need to do the lookup of tx hash -> tx index, don't
// delete the tx_indices entry until the end.
if ( mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & val_h , MDB_GET_BOTH ) )
throw1 ( TX_DNE ( " Attempting to remove transaction that isn't in the db " ) ) ;
if ( mdb_cursor_del ( m_cur_tx_indices , 0 ) )
if ( mdb_cursor_del ( m_cur_tx_indices , 0 ) )
throw1 ( DB_ERROR ( " Failed to add removal of tx index to db transaction " ) ) ;
throw1 ( DB_ERROR ( " Failed to add removal of tx index to db transaction " ) ) ;
m_num_txs - - ;
m_num_txs - - ;
}
}
// global_output_index is no longer used for locating outputs
uint64_t BlockchainLMDB : : add_output ( const crypto : : hash & tx_hash ,
void BlockchainLMDB : : add_output ( const crypto : : hash & tx_hash ,
const tx_out & tx_output ,
const tx_out & tx_output ,
const uint64_t & local_index ,
const uint64_t & local_index ,
const uint64_t unlock_time ,
const uint64_t unlock_time )
uint64_t & amount_output_index ,
uint64_t & global_output_index )
{
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
check_open ( ) ;
@ -791,7 +807,7 @@ void BlockchainLMDB::add_output(const crypto::hash& tx_hash,
throw0 ( DB_ERROR ( lmdb_error ( " Failed to get output amount in db transaction: " , result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " Failed to get output amount in db transaction: " , result ) . c_str ( ) ) ) ;
else
else
ok . amount_index = 0 ;
ok . amount_index = 0 ;
ok . tx _in dex = m_num_outputs ;
ok . outpu t_id = m_num_outputs ;
ok . data . pubkey = boost : : get < txout_to_key > ( tx_output . target ) . key ;
ok . data . pubkey = boost : : get < txout_to_key > ( tx_output . target ) . key ;
ok . data . unlock_time = unlock_time ;
ok . data . unlock_time = unlock_time ;
ok . data . height = m_height ;
ok . data . height = m_height ;
@ -801,16 +817,12 @@ void BlockchainLMDB::add_output(const crypto::hash& tx_hash,
if ( ( result = mdb_cursor_put ( m_cur_output_amounts , & val_amount , & data , MDB_APPENDDUP ) ) )
if ( ( result = mdb_cursor_put ( m_cur_output_amounts , & val_amount , & data , MDB_APPENDDUP ) ) )
throw0 ( DB_ERROR ( lmdb_error ( " Failed to add output pubkey to db transaction: " , result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " Failed to add output pubkey to db transaction: " , result ) . c_str ( ) ) ) ;
amount_output_index = ok . amount_index ;
global_output_index = m_num_outputs ;
m_num_outputs + + ;
m_num_outputs + + ;
return ok . amount_index ;
}
}
// global_output_indices is now ignored
void BlockchainLMDB : : add_tx_amount_output_indices ( const uint64_t tx_id ,
void BlockchainLMDB : : add_amount_and_global_output_indices ( const uint64_t tx_index ,
const std : : vector < uint64_t > & amount_output_indices )
const std : : vector < uint64_t > & amount_output_indices ,
const std : : vector < uint64_t > & global_output_indices )
{
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
check_open ( ) ;
@ -821,24 +833,22 @@ void BlockchainLMDB::add_amount_and_global_output_indices(const uint64_t tx_inde
int num_outputs = amount_output_indices . size ( ) ;
int num_outputs = amount_output_indices . size ( ) ;
MDB_val_ copy< uint64_t > k_tx_index ( tx_index ) ;
MDB_val_ set( k_tx_id , tx_id ) ;
MDB_val v ;
MDB_val v ;
v . mv_data = ( void * ) amount_output_indices . data ( ) ;
v . mv_data = ( void * ) amount_output_indices . data ( ) ;
v . mv_size = sizeof ( uint64_t ) * num_outputs ;
v . mv_size = sizeof ( uint64_t ) * num_outputs ;
// LOG_PRINT_L1("tx_outputs[tx_hash] size: " << v.mv_size);
// LOG_PRINT_L1("tx_outputs[tx_hash] size: " << v.mv_size);
result = mdb_cursor_put ( m_cur_tx_outputs , & k_tx_i n dex , & v , MDB_APPEND ) ;
result = mdb_cursor_put ( m_cur_tx_outputs , & k_tx_i d, & v , MDB_APPEND ) ;
if ( result )
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add <tx hash, amount output index array> to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( std : : string ( " Failed to add <tx hash, amount output index array> to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
}
}
void BlockchainLMDB : : remove_tx_outputs ( const uint64_t tx_i n dex , const transaction & tx )
void BlockchainLMDB : : remove_tx_outputs ( const uint64_t tx_i d, const transaction & tx )
{
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
// only need amount_output_indices
std : : vector < uint64_t > amount_output_indices = get_tx_amount_output_indices ( tx_id ) ;
std : : vector < uint64_t > amount_output_indices , global_output_indices ;
get_amount_and_global_output_indices ( tx_index , amount_output_indices , global_output_indices ) ;
if ( amount_output_indices . empty ( ) )
if ( amount_output_indices . empty ( ) )
{
{
@ -880,7 +890,7 @@ void BlockchainLMDB::remove_output(const uint64_t& out_index, const uint64_t amo
throw0 ( DB_ERROR ( lmdb_error ( " DB error attempting to get an output " , result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " DB error attempting to get an output " , result ) . c_str ( ) ) ) ;
outkey * ok = ( outkey * ) v . mv_data ;
outkey * ok = ( outkey * ) v . mv_data ;
MDB_val_set ( otxk , ok - > tx _in dex ) ;
MDB_val_set ( otxk , ok - > outpu t_id) ;
result = mdb_cursor_get ( m_cur_output_txs , ( MDB_val * ) & zerokval , & otxk , MDB_GET_BOTH ) ;
result = mdb_cursor_get ( m_cur_output_txs , ( MDB_val * ) & zerokval , & otxk , MDB_GET_BOTH ) ;
if ( result = = MDB_NOTFOUND )
if ( result = = MDB_NOTFOUND )
{
{
@ -1333,8 +1343,7 @@ bool BlockchainLMDB::block_exists(const crypto::hash& h) const
RCURSOR ( block_heights ) ;
RCURSOR ( block_heights ) ;
bool ret = false ;
bool ret = false ;
blk_height bh = { h , 0 } ;
MDB_val_set ( key , h ) ;
MDB_val key = { sizeof ( bh ) , ( void * ) & bh } ;
auto get_result = mdb_cursor_get ( m_cur_block_heights , ( MDB_val * ) & zerokval , & key , MDB_GET_BOTH ) ;
auto get_result = mdb_cursor_get ( m_cur_block_heights , ( MDB_val * ) & zerokval , & key , MDB_GET_BOTH ) ;
if ( get_result = = MDB_NOTFOUND )
if ( get_result = = MDB_NOTFOUND )
{
{
@ -1365,8 +1374,7 @@ uint64_t BlockchainLMDB::get_block_height(const crypto::hash& h) const
TXN_PREFIX_RDONLY ( ) ;
TXN_PREFIX_RDONLY ( ) ;
RCURSOR ( block_heights ) ;
RCURSOR ( block_heights ) ;
blk_height bh = { h , 0 } ;
MDB_val_set ( key , h ) ;
MDB_val key = { sizeof ( bh ) , ( void * ) & bh } ;
auto get_result = mdb_cursor_get ( m_cur_block_heights , ( MDB_val * ) & zerokval , & key , MDB_GET_BOTH ) ;
auto get_result = mdb_cursor_get ( m_cur_block_heights , ( MDB_val * ) & zerokval , & key , MDB_GET_BOTH ) ;
if ( get_result = = MDB_NOTFOUND )
if ( get_result = = MDB_NOTFOUND )
throw1 ( BLOCK_DNE ( " Attempted to retrieve non-existent block height " ) ) ;
throw1 ( BLOCK_DNE ( " Attempted to retrieve non-existent block height " ) ) ;
@ -1374,7 +1382,7 @@ uint64_t BlockchainLMDB::get_block_height(const crypto::hash& h) const
throw0 ( DB_ERROR ( " Error attempting to retrieve a block height from the db " ) ) ;
throw0 ( DB_ERROR ( " Error attempting to retrieve a block height from the db " ) ) ;
blk_height * bhp = ( blk_height * ) key . mv_data ;
blk_height * bhp = ( blk_height * ) key . mv_data ;
uint64_t ret = bhp - > height;
uint64_t ret = bhp - > bh_ height;
TXN_POSTFIX_RDONLY ( ) ;
TXN_POSTFIX_RDONLY ( ) ;
return ret ;
return ret ;
}
}
@ -1635,7 +1643,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
RCURSOR ( tx_indices ) ;
RCURSOR ( tx_indices ) ;
RCURSOR ( txs ) ;
RCURSOR ( txs ) ;
MDB_val_ copy< crypto : : hash > key ( h ) ;
MDB_val_ set( key , h ) ;
bool tx_found = false ;
bool tx_found = false ;
TIME_MEASURE_START ( time1 ) ;
TIME_MEASURE_START ( time1 ) ;
@ -1666,7 +1674,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
return true ;
return true ;
}
}
bool BlockchainLMDB : : tx_exists ( const crypto : : hash & h , uint64_t & tx_i n dex ) const
bool BlockchainLMDB : : tx_exists ( const crypto : : hash & h , uint64_t & tx_i d) const
{
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
check_open ( ) ;
@ -1674,8 +1682,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_index) const
TXN_PREFIX_RDONLY ( ) ;
TXN_PREFIX_RDONLY ( ) ;
RCURSOR ( tx_indices ) ;
RCURSOR ( tx_indices ) ;
txindex ti = { h } ;
MDB_val_set ( v , h ) ;
MDB_val v = { sizeof ( ti ) , ( void * ) & ti } ;
TIME_MEASURE_START ( time1 ) ;
TIME_MEASURE_START ( time1 ) ;
auto get_result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
auto get_result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
@ -1683,7 +1690,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_index) const
time_tx_exists + = time1 ;
time_tx_exists + = time1 ;
if ( ! get_result ) {
if ( ! get_result ) {
txindex * tip = ( txindex * ) v . mv_data ;
txindex * tip = ( txindex * ) v . mv_data ;
tx_i n dex = tip - > data . tx_i n dex ;
tx_i d = tip - > data . tx_i d;
}
}
TXN_POSTFIX_RDONLY ( ) ;
TXN_POSTFIX_RDONLY ( ) ;
@ -1709,8 +1716,7 @@ uint64_t BlockchainLMDB::get_tx_unlock_time(const crypto::hash& h) const
TXN_PREFIX_RDONLY ( ) ;
TXN_PREFIX_RDONLY ( ) ;
RCURSOR ( tx_indices ) ;
RCURSOR ( tx_indices ) ;
txindex ti = { h } ;
MDB_val_set ( v , h ) ;
MDB_val v = { sizeof ( ti ) , ( void * ) & ti } ;
auto get_result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
auto get_result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
if ( get_result = = MDB_NOTFOUND )
if ( get_result = = MDB_NOTFOUND )
throw1 ( TX_DNE ( lmdb_error ( std : : string ( " tx data with hash " ) + epee : : string_tools : : pod_to_hex ( h ) + " not found in db: " , get_result ) . c_str ( ) ) ) ;
throw1 ( TX_DNE ( lmdb_error ( std : : string ( " tx data with hash " ) + epee : : string_tools : : pod_to_hex ( h ) + " not found in db: " , get_result ) . c_str ( ) ) ) ;
@ -1732,16 +1738,14 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
RCURSOR ( tx_indices ) ;
RCURSOR ( tx_indices ) ;
RCURSOR ( txs ) ;
RCURSOR ( txs ) ;
txindex ti = { h } ;
MDB_val_set ( v , h ) ;
MDB_val v = { sizeof ( ti ) , ( void * ) & ti } ;
MDB_val result ;
MDB_val result ;
auto get_result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
auto get_result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
if ( get_result = = 0 )
if ( get_result = = 0 )
{
{
txindex * tip = ( txindex * ) v . mv_data ;
txindex * tip = ( txindex * ) v . mv_data ;
uint64_t tx_index = tip - > data . tx_index ;
MDB_val_set ( val_tx_id , tip - > data . tx_id ) ;
MDB_val_copy < uint64_t > val_tx_index ( tx_index ) ;
get_result = mdb_cursor_get ( m_cur_txs , & val_tx_id , & result , MDB_SET ) ;
get_result = mdb_cursor_get ( m_cur_txs , & val_tx_index , & result , MDB_SET ) ;
}
}
if ( get_result = = MDB_NOTFOUND )
if ( get_result = = MDB_NOTFOUND )
throw1 ( TX_DNE ( std : : string ( " tx with hash " ) . append ( epee : : string_tools : : pod_to_hex ( h ) ) . append ( " not found in db " ) . c_str ( ) ) ) ;
throw1 ( TX_DNE ( std : : string ( " tx with hash " ) . append ( epee : : string_tools : : pod_to_hex ( h ) ) . append ( " not found in db " ) . c_str ( ) ) ) ;
@ -1798,8 +1802,7 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
TXN_PREFIX_RDONLY ( ) ;
TXN_PREFIX_RDONLY ( ) ;
RCURSOR ( tx_indices ) ;
RCURSOR ( tx_indices ) ;
txindex ti = { h } ;
MDB_val_set ( v , h ) ;
MDB_val v = { sizeof ( ti ) , ( void * ) & ti } ;
auto get_result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
auto get_result = mdb_cursor_get ( m_cur_tx_indices , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
if ( get_result = = MDB_NOTFOUND )
if ( get_result = = MDB_NOTFOUND )
{
{
@ -1809,7 +1812,7 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
throw0 ( DB_ERROR ( lmdb_error ( " DB error attempting to fetch tx height from hash " , get_result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " DB error attempting to fetch tx height from hash " , get_result ) . c_str ( ) ) ) ;
txindex * tip = ( txindex * ) v . mv_data ;
txindex * tip = ( txindex * ) v . mv_data ;
uint64_t ret = tip - > data . height ;
uint64_t ret = tip - > data . block_id ;
TXN_POSTFIX_RDONLY ( ) ;
TXN_POSTFIX_RDONLY ( ) ;
return ret ;
return ret ;
}
}
@ -1867,7 +1870,7 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint6
return ret ;
return ret ;
}
}
tx_out_index BlockchainLMDB : : get_output_tx_and_index_from_global ( const uint64_t & in dex ) const
tx_out_index BlockchainLMDB : : get_output_tx_and_index_from_global ( const uint64_t & output_ id) const
{
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
check_open ( ) ;
@ -1875,7 +1878,7 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
TXN_PREFIX_RDONLY ( ) ;
TXN_PREFIX_RDONLY ( ) ;
RCURSOR ( output_txs ) ;
RCURSOR ( output_txs ) ;
MDB_val_set ( v , in dex ) ;
MDB_val_set ( v , output_ id) ;
auto get_result = mdb_cursor_get ( m_cur_output_txs , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
auto get_result = mdb_cursor_get ( m_cur_output_txs , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
if ( get_result = = MDB_NOTFOUND )
if ( get_result = = MDB_NOTFOUND )
@ -1903,29 +1906,21 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, con
return indices [ 0 ] ;
return indices [ 0 ] ;
}
}
// we don't have global_output_indices
std : : vector < uint64_t > BlockchainLMDB : : get_tx_amount_output_indices ( const uint64_t tx_id ) const
void BlockchainLMDB : : get_amount_and_global_output_indices ( const uint64_t tx_index ,
std : : vector < uint64_t > & amount_output_indices ,
std : : vector < uint64_t > & global_output_indices ) const
{
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
check_open ( ) ;
// If a new txn is created, it only needs to read.
//
// This must existence of m_write_txn too (not only m_batch_active), as
// that's what remove_tx_outputs() expected to use instead of creating a new
// txn, regardless of batch mode. Otherwise, remove_tx_outputs() would now
// create a new read-only txn here, which is incorrect.
TXN_PREFIX_RDONLY ( ) ;
TXN_PREFIX_RDONLY ( ) ;
RCURSOR ( tx_outputs ) ;
RCURSOR ( tx_outputs ) ;
int result = 0 ;
int result = 0 ;
MDB_val_ copy< uint64_t > k_tx_index ( tx_index ) ;
MDB_val_set ( k_tx_id , tx_id ) ;
MDB_val v ;
MDB_val v ;
std : : vector < uint64_t > amount_output_indices ;
result = mdb_cursor_get ( m_cur_tx_outputs , & k_tx_i n dex , & v , MDB_SET ) ;
result = mdb_cursor_get ( m_cur_tx_outputs , & k_tx_i d, & v , MDB_SET ) ;
if ( result = = MDB_NOTFOUND )
if ( result = = MDB_NOTFOUND )
LOG_PRINT_L0 ( " WARNING: Unexpected: tx has no amount indices stored in "
LOG_PRINT_L0 ( " WARNING: Unexpected: tx has no amount indices stored in "
" tx_outputs, but it should have an empty entry even if it's a tx without "
" tx_outputs, but it should have an empty entry even if it's a tx without "
@ -1944,21 +1939,10 @@ void BlockchainLMDB::get_amount_and_global_output_indices(const uint64_t tx_inde
indices = nullptr ;
indices = nullptr ;
TXN_POSTFIX_RDONLY ( ) ;
TXN_POSTFIX_RDONLY ( ) ;
}
std : : vector < uint64_t > BlockchainLMDB : : get_tx_amount_output_indices ( const uint64_t tx_index ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
std : : vector < uint64_t > amount_output_indices , global_output_indices ;
// only need amount_output_indices
get_amount_and_global_output_indices ( tx_index , amount_output_indices , global_output_indices ) ;
return amount_output_indices ;
return amount_output_indices ;
}
}
bool BlockchainLMDB : : has_key_image ( const crypto : : key_image & img ) const
bool BlockchainLMDB : : has_key_image ( const crypto : : key_image & img ) const
{
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
@ -2110,7 +2094,7 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
throw0 ( DB_ERROR ( " Failed to enumerate outputs " ) ) ;
throw0 ( DB_ERROR ( " Failed to enumerate outputs " ) ) ;
uint64_t amount = * ( const uint64_t * ) k . mv_data ;
uint64_t amount = * ( const uint64_t * ) k . mv_data ;
outkey * ok = ( outkey * ) v . mv_data ;
outkey * ok = ( outkey * ) v . mv_data ;
tx_out_index toi = get_output_tx_and_index_from_global ( ok - > tx _in dex ) ;
tx_out_index toi = get_output_tx_and_index_from_global ( ok - > outpu t_id) ;
if ( ! f ( amount , toi . first , toi . second ) ) {
if ( ! f ( amount , toi . first , toi . second ) ) {
ret = false ;
ret = false ;
break ;
break ;
@ -2453,9 +2437,9 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
TXN_PREFIX_RDONLY ( ) ;
TXN_PREFIX_RDONLY ( ) ;
RCURSOR ( output_txs ) ;
RCURSOR ( output_txs ) ;
for ( const uint64_t & in dex : global_indices )
for ( const uint64_t & output_ id : global_indices )
{
{
MDB_val_set ( v , in dex ) ;
MDB_val_set ( v , output_ id) ;
auto get_result = mdb_cursor_get ( m_cur_output_txs , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
auto get_result = mdb_cursor_get ( m_cur_output_txs , ( MDB_val * ) & zerokval , & v , MDB_GET_BOTH ) ;
if ( get_result = = MDB_NOTFOUND )
if ( get_result = = MDB_NOTFOUND )
@ -2527,7 +2511,7 @@ void BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const std::
throw0 ( DB_ERROR ( lmdb_error ( " Error attempting to retrieve an output from the db " , get_result ) . c_str ( ) ) ) ;
throw0 ( DB_ERROR ( lmdb_error ( " Error attempting to retrieve an output from the db " , get_result ) . c_str ( ) ) ) ;
outkey * okp = ( outkey * ) v . mv_data ;
outkey * okp = ( outkey * ) v . mv_data ;
tx_indices . push_back ( okp - > tx _in dex ) ;
tx_indices . push_back ( okp - > outpu t_id) ;
}
}
TIME_MEASURE_START ( db3 ) ;
TIME_MEASURE_START ( db3 ) ;