2015-06-17 16:33:38 +00:00
/*
2015-10-12 17:48:40 +00:00
* Copyright ( c ) 2015 Cryptonomex , Inc . , and contributors .
*
2016-01-06 09:51:18 +00:00
* The MIT License
2015-10-12 17:48:40 +00:00
*
2016-01-06 09:51:18 +00:00
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
2015-10-12 17:48:40 +00:00
*
2016-01-06 09:51:18 +00:00
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
2015-10-12 17:02:59 +00:00
*
2016-01-06 09:51:18 +00:00
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
2015-06-17 16:33:38 +00:00
*/
2015-06-16 19:56:13 +00:00
# include <graphene/chain/block_database.hpp>
2015-07-08 20:39:23 +00:00
# include <graphene/chain/protocol/fee_schedule.hpp>
# include <fc/io/raw.hpp>
2015-06-16 19:56:13 +00:00
namespace graphene { namespace chain {
struct index_entry
{
uint64_t block_pos = 0 ;
uint32_t block_size = 0 ;
block_id_type block_id ;
} ;
2015-06-17 16:33:38 +00:00
} }
2015-06-16 22:45:33 +00:00
FC_REFLECT ( graphene : : chain : : index_entry , ( block_pos ) ( block_size ) ( block_id ) ) ;
namespace graphene { namespace chain {
2015-06-16 19:56:13 +00:00
void block_database : : open ( const fc : : path & dbdir )
2015-06-16 22:45:33 +00:00
{ try {
fc : : create_directories ( dbdir ) ;
_block_num_to_pos . exceptions ( std : : ios_base : : failbit | std : : ios_base : : badbit ) ;
_blocks . exceptions ( std : : ios_base : : failbit | std : : ios_base : : badbit ) ;
2017-08-04 23:39:42 +00:00
_index_filename = dbdir / " index " ;
if ( ! fc : : exists ( _index_filename ) )
2015-06-16 22:45:33 +00:00
{
2017-08-04 23:39:42 +00:00
_block_num_to_pos . open ( _index_filename . generic_string ( ) . c_str ( ) , std : : fstream : : binary | std : : fstream : : in | std : : fstream : : out | std : : fstream : : trunc ) ;
2015-06-16 22:45:33 +00:00
_blocks . open ( ( dbdir / " blocks " ) . generic_string ( ) . c_str ( ) , std : : fstream : : binary | std : : fstream : : in | std : : fstream : : out | std : : fstream : : trunc ) ;
}
else
{
2017-08-04 23:39:42 +00:00
_block_num_to_pos . open ( _index_filename . generic_string ( ) . c_str ( ) , std : : fstream : : binary | std : : fstream : : in | std : : fstream : : out ) ;
2015-06-16 22:45:33 +00:00
_blocks . open ( ( dbdir / " blocks " ) . generic_string ( ) . c_str ( ) , std : : fstream : : binary | std : : fstream : : in | std : : fstream : : out ) ;
}
} FC_CAPTURE_AND_RETHROW ( ( dbdir ) ) }
2015-06-16 19:56:13 +00:00
bool block_database : : is_open ( ) const
{
return _blocks . is_open ( ) ;
}
void block_database : : close ( )
{
_blocks . close ( ) ;
_block_num_to_pos . close ( ) ;
}
void block_database : : flush ( )
{
_blocks . flush ( ) ;
_block_num_to_pos . flush ( ) ;
}
2015-08-21 17:16:17 +00:00
void block_database : : store ( const block_id_type & _id , const signed_block & b )
2015-06-16 19:56:13 +00:00
{
2021-12-01 21:57:46 +00:00
if ( true = = replay_mode ) {
return ;
}
2015-08-21 17:16:17 +00:00
block_id_type id = _id ;
if ( id = = block_id_type ( ) )
{
id = b . id ( ) ;
elog ( " id argument of block_database::store() was not initialized for block ${id} " , ( " id " , id ) ) ;
}
2015-06-16 19:56:13 +00:00
auto num = block_header : : num_from_id ( id ) ;
_block_num_to_pos . seekp ( sizeof ( index_entry ) * num ) ;
index_entry e ;
_blocks . seekp ( 0 , _blocks . end ) ;
auto vec = fc : : raw : : pack ( b ) ;
e . block_pos = _blocks . tellp ( ) ;
e . block_size = vec . size ( ) ;
e . block_id = id ;
_blocks . write ( vec . data ( ) , vec . size ( ) ) ;
_block_num_to_pos . write ( ( char * ) & e , sizeof ( e ) ) ;
}
void block_database : : remove ( const block_id_type & id )
2015-06-16 22:45:33 +00:00
{ try {
2015-06-16 19:56:13 +00:00
index_entry e ;
auto index_pos = sizeof ( e ) * block_header : : num_from_id ( id ) ;
_block_num_to_pos . seekg ( 0 , _block_num_to_pos . end ) ;
2021-12-08 17:07:41 +00:00
std : : streampos s_pos = _block_num_to_pos . tellg ( ) ;
if ( - 1 = = s_pos ) {
FC_THROW_EXCEPTION ( fc : : key_not_found_exception , " Block ${id} not contained in block database, _block_num_to_pos.tellg failed " , ( " id " , id ) ) ;
}
if ( static_cast < uint32_t > ( s_pos ) < = index_pos ) {
2015-06-25 14:33:39 +00:00
FC_THROW_EXCEPTION ( fc : : key_not_found_exception , " Block ${id} not contained in block database " , ( " id " , id ) ) ;
2021-12-08 17:07:41 +00:00
}
2015-06-16 19:56:13 +00:00
_block_num_to_pos . seekg ( index_pos ) ;
_block_num_to_pos . read ( ( char * ) & e , sizeof ( e ) ) ;
2015-06-16 22:45:33 +00:00
if ( e . block_id = = id )
{
e . block_size = 0 ;
_block_num_to_pos . seekp ( sizeof ( e ) * block_header : : num_from_id ( id ) ) ;
_block_num_to_pos . write ( ( char * ) & e , sizeof ( e ) ) ;
}
} FC_CAPTURE_AND_RETHROW ( ( id ) ) }
2015-06-16 19:56:13 +00:00
2015-06-30 20:42:41 +00:00
bool block_database : : contains ( const block_id_type & id ) const
2021-12-08 17:07:41 +00:00
{ try {
2015-08-21 17:18:47 +00:00
if ( id = = block_id_type ( ) )
return false ;
2015-06-16 19:56:13 +00:00
index_entry e ;
auto index_pos = sizeof ( e ) * block_header : : num_from_id ( id ) ;
_block_num_to_pos . seekg ( 0 , _block_num_to_pos . end ) ;
2021-12-08 17:07:41 +00:00
std : : streampos s_pos = _block_num_to_pos . tellg ( ) ;
if ( - 1 = = s_pos ) {
FC_THROW_EXCEPTION ( fc : : key_not_found_exception , " Block ${id} not contained in block database, _block_num_to_pos.tellg failed " , ( " id " , id ) ) ;
}
if ( static_cast < uint32_t > ( s_pos ) < index_pos + sizeof ( e ) )
2015-06-30 20:42:41 +00:00
return false ;
2021-12-08 17:07:41 +00:00
2015-06-16 19:56:13 +00:00
_block_num_to_pos . seekg ( index_pos ) ;
_block_num_to_pos . read ( ( char * ) & e , sizeof ( e ) ) ;
2015-09-04 19:22:12 +00:00
return e . block_id = = id & & e . block_size > 0 ;
2021-12-08 17:07:41 +00:00
} FC_CAPTURE_AND_RETHROW ( ( id ) ) }
2015-06-16 19:56:13 +00:00
2015-06-30 20:42:41 +00:00
block_id_type block_database : : fetch_block_id ( uint32_t block_num ) const
2015-06-16 19:56:13 +00:00
{
2015-08-21 17:16:17 +00:00
assert ( block_num ! = 0 ) ;
2015-06-16 19:56:13 +00:00
index_entry e ;
auto index_pos = sizeof ( e ) * block_num ;
_block_num_to_pos . seekg ( 0 , _block_num_to_pos . end ) ;
2015-09-21 12:46:55 +00:00
if ( _block_num_to_pos . tellg ( ) < = int64_t ( index_pos ) )
2015-06-25 14:33:39 +00:00
FC_THROW_EXCEPTION ( fc : : key_not_found_exception , " Block number ${block_num} not contained in block database " , ( " block_num " , block_num ) ) ;
2015-06-16 19:56:13 +00:00
_block_num_to_pos . seekg ( index_pos ) ;
_block_num_to_pos . read ( ( char * ) & e , sizeof ( e ) ) ;
2015-08-21 17:16:17 +00:00
FC_ASSERT ( e . block_id ! = block_id_type ( ) , " Empty block_id in block_database (maybe corrupt on disk?) " ) ;
2015-06-16 19:56:13 +00:00
return e . block_id ;
}
optional < signed_block > block_database : : fetch_optional ( const block_id_type & id ) const
2015-06-18 18:47:53 +00:00
{
2015-06-30 20:42:41 +00:00
try
2015-06-18 18:47:53 +00:00
{
index_entry e ;
auto index_pos = sizeof ( e ) * block_header : : num_from_id ( id ) ;
_block_num_to_pos . seekg ( 0 , _block_num_to_pos . end ) ;
2021-12-08 17:07:41 +00:00
std : : streampos s_pos = _block_num_to_pos . tellg ( ) ;
if ( - 1 = = s_pos ) {
FC_THROW_EXCEPTION ( fc : : key_not_found_exception , " Block ${id} not contained in block database, _block_num_to_pos.tellg failed " , ( " id " , id ) ) ;
}
if ( static_cast < uint32_t > ( s_pos ) < = index_pos )
2015-06-30 20:42:41 +00:00
return { } ;
2015-06-18 18:47:53 +00:00
_block_num_to_pos . seekg ( index_pos ) ;
_block_num_to_pos . read ( ( char * ) & e , sizeof ( e ) ) ;
2015-06-30 20:42:41 +00:00
2015-06-18 18:47:53 +00:00
if ( e . block_id ! = id ) return optional < signed_block > ( ) ;
2015-06-30 20:42:41 +00:00
2015-06-18 18:47:53 +00:00
vector < char > data ( e . block_size ) ;
_blocks . seekg ( e . block_pos ) ;
2015-08-21 23:53:35 +00:00
if ( e . block_size )
_blocks . read ( data . data ( ) , e . block_size ) ;
2015-06-18 18:47:53 +00:00
auto result = fc : : raw : : unpack < signed_block > ( data ) ;
FC_ASSERT ( result . id ( ) = = e . block_id ) ;
return result ;
}
catch ( const fc : : exception & )
{
}
catch ( const std : : exception & )
{
}
return optional < signed_block > ( ) ;
}
2015-06-16 19:56:13 +00:00
optional < signed_block > block_database : : fetch_by_number ( uint32_t block_num ) const
2015-06-18 18:47:53 +00:00
{
2015-06-30 20:42:41 +00:00
try
2015-06-18 18:47:53 +00:00
{
index_entry e ;
auto index_pos = sizeof ( e ) * block_num ;
_block_num_to_pos . seekg ( 0 , _block_num_to_pos . end ) ;
2021-12-08 17:07:41 +00:00
std : : streampos s_pos = _block_num_to_pos . tellg ( ) ;
if ( - 1 = = s_pos ) {
FC_THROW_EXCEPTION ( fc : : key_not_found_exception , " Block ${block_num} not contained in block database, _block_num_to_pos.tellg failed " , ( " block_num " , block_num ) ) ;
}
if ( static_cast < uint32_t > ( s_pos ) < = index_pos )
2015-06-30 20:42:41 +00:00
return { } ;
2015-06-16 19:56:13 +00:00
2015-06-18 18:47:53 +00:00
_block_num_to_pos . seekg ( index_pos , _block_num_to_pos . beg ) ;
_block_num_to_pos . read ( ( char * ) & e , sizeof ( e ) ) ;
2015-06-16 19:56:13 +00:00
2015-06-18 18:47:53 +00:00
vector < char > data ( e . block_size ) ;
_blocks . seekg ( e . block_pos ) ;
_blocks . read ( data . data ( ) , e . block_size ) ;
auto result = fc : : raw : : unpack < signed_block > ( data ) ;
FC_ASSERT ( result . id ( ) = = e . block_id ) ;
return result ;
}
catch ( const fc : : exception & )
{
}
catch ( const std : : exception & )
{
}
return optional < signed_block > ( ) ;
}
2015-06-16 19:56:13 +00:00
2017-07-12 19:13:26 +00:00
optional < index_entry > block_database : : last_index_entry ( ) const {
2015-06-30 20:42:41 +00:00
try
2015-06-18 18:47:53 +00:00
{
index_entry e ;
2017-07-12 19:13:26 +00:00
2015-06-18 18:47:53 +00:00
_block_num_to_pos . seekg ( 0 , _block_num_to_pos . end ) ;
2017-07-12 19:13:26 +00:00
std : : streampos pos = _block_num_to_pos . tellg ( ) ;
2021-12-08 17:07:41 +00:00
if ( - 1 = = pos ) {
FC_THROW_EXCEPTION ( fc : : key_not_found_exception , " last_index_entry tellg failed " ) ;
}
if ( static_cast < size_t > ( pos ) < sizeof ( index_entry ) )
2017-07-12 19:13:26 +00:00
return optional < index_entry > ( ) ;
2015-06-16 19:56:13 +00:00
2017-08-04 19:44:56 +00:00
pos - = pos % sizeof ( index_entry ) ;
2015-06-16 19:56:13 +00:00
2017-08-04 19:44:56 +00:00
_blocks . seekg ( 0 , _block_num_to_pos . end ) ;
const std : : streampos blocks_size = _blocks . tellg ( ) ;
2017-08-04 23:39:42 +00:00
while ( pos > 0 )
2015-06-18 18:47:53 +00:00
{
2015-09-03 21:42:52 +00:00
pos - = sizeof ( index_entry ) ;
_block_num_to_pos . seekg ( pos ) ;
2015-06-18 18:47:53 +00:00
_block_num_to_pos . read ( ( char * ) & e , sizeof ( e ) ) ;
2017-08-04 19:44:56 +00:00
if ( _block_num_to_pos . gcount ( ) = = sizeof ( e ) & & e . block_size > 0
2021-12-08 17:07:41 +00:00
& & e . block_pos + static_cast < uint64_t > ( e . block_size ) < = static_cast < uint64_t > ( blocks_size ) )
2017-07-12 19:13:26 +00:00
try
{
vector < char > data ( e . block_size ) ;
_blocks . seekg ( e . block_pos ) ;
_blocks . read ( data . data ( ) , e . block_size ) ;
2017-08-04 19:44:56 +00:00
if ( _blocks . gcount ( ) = = e . block_size )
{
const signed_block block = fc : : raw : : unpack < signed_block > ( data ) ;
if ( block . id ( ) = = e . block_id )
return e ;
}
2017-07-12 19:13:26 +00:00
}
catch ( const fc : : exception & )
{
}
catch ( const std : : exception & )
{
}
2017-08-04 23:39:42 +00:00
fc : : resize_file ( _index_filename , pos ) ;
2017-07-12 19:13:26 +00:00
}
2015-06-16 22:45:33 +00:00
}
2015-06-18 18:47:53 +00:00
catch ( const fc : : exception & )
{
}
catch ( const std : : exception & )
{
}
2017-07-12 19:13:26 +00:00
return optional < index_entry > ( ) ;
}
optional < signed_block > block_database : : last ( ) const
{
optional < index_entry > entry = last_index_entry ( ) ;
if ( entry . valid ( ) ) return fetch_by_number ( block_header : : num_from_id ( entry - > block_id ) ) ;
2015-06-18 18:47:53 +00:00
return optional < signed_block > ( ) ;
2015-06-16 19:56:13 +00:00
}
2015-09-09 18:44:31 +00:00
optional < block_id_type > block_database : : last_id ( ) const
{
2017-07-12 19:13:26 +00:00
optional < index_entry > entry = last_index_entry ( ) ;
if ( entry . valid ( ) ) return entry - > block_id ;
2015-09-09 18:44:31 +00:00
return optional < block_id_type > ( ) ;
}
2021-12-01 21:57:46 +00:00
void block_database : : set_replay_mode ( bool mode )
{
replay_mode = mode ;
}
2015-06-16 19:56:13 +00:00
} }