Skip to content

Commit 4b6e34b

Browse files
committed
Cache witness signing key for block producing bitshares#125
1 parent 10a2b43 commit 4b6e34b

File tree

6 files changed

+94
-10
lines changed

6 files changed

+94
-10
lines changed

libraries/chain/db_block.cpp

+59-4
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,19 @@ signed_block database::_generate_block(
352352
witness_id_type scheduled_witness = get_scheduled_witness( slot_num );
353353
FC_ASSERT( scheduled_witness == witness_id );
354354

355-
const auto& witness_obj = witness_id(*this);
356-
357355
if( !(skip & skip_witness_signature) )
358-
FC_ASSERT( witness_obj.signing_key == block_signing_private_key.get_public_key() );
356+
{
357+
auto signing_key = find_witness_key_from_cache( witness_id );
358+
if( signing_key.valid() ) // witness in cache
359+
{
360+
FC_ASSERT( *signing_key == block_signing_private_key.get_public_key() );
361+
}
362+
else // witness not in cache
363+
{
364+
const auto& witness_obj = witness_id(*this);
365+
FC_ASSERT( witness_obj.signing_key == block_signing_private_key.get_public_key() );
366+
}
367+
}
359368

360369
static const size_t max_block_header_size = fc::raw::pack_size( signed_block_header() ) + 4;
361370
auto maximum_block_size = get_global_properties().parameters.maximum_block_size;
@@ -374,11 +383,12 @@ signed_block database::_generate_block(
374383
// the value of the "when" variable is known, which means we need to
375384
// re-apply pending transactions in this method.
376385
//
386+
387+
// pop pending state (reset to head block state)
377388
_pending_tx_session.reset();
378389
_pending_tx_session = _undo_db.start_undo_session();
379390

380391
uint64_t postponed_tx_count = 0;
381-
// pop pending state (reset to head block state)
382392
for( const processed_transaction& tx : _pending_tx )
383393
{
384394
size_t new_total_size = total_block_size + fc::raw::pack_size( tx );
@@ -457,6 +467,9 @@ void database::pop_block()
457467

458468
_popped_tx.insert( _popped_tx.begin(), head_block->transactions.begin(), head_block->transactions.end() );
459469

470+
// Note: for better performance, can move this to where calls pop_block();
471+
refresh_witness_key_cache();
472+
460473
} FC_CAPTURE_AND_RETHROW() }
461474

462475
void database::clear_pending()
@@ -532,6 +545,9 @@ void database::_apply_block( const signed_block& next_block )
532545

533546
_issue_453_affected_assets.clear();
534547

548+
if( !(skip&skip_witness_key_cache_update) )
549+
skip |= force_witness_key_cache_update;
550+
535551
for( const auto& trx : next_block.transactions )
536552
{
537553
/* We do not need to push the undo state for each transaction
@@ -720,4 +736,43 @@ bool database::before_last_checkpoint()const
720736
return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
721737
}
722738

739+
void database::init_witness_key_cache( std::set<witness_id_type>& witnesses )
740+
{
741+
for( const witness_id_type& wit : witnesses )
742+
_witness_key_cache[wit]; // add it
743+
}
744+
745+
void database::update_witness_key_cache( witness_id_type wit, const public_key_type& pub_key )
746+
{
747+
if( _witness_key_cache.empty() )
748+
return;
749+
uint32_t skip = get_node_properties().skip_flags;
750+
if( (skip&force_witness_key_cache_update) )
751+
{
752+
auto itr = _witness_key_cache.find( wit );
753+
if( itr != _witness_key_cache.end() )
754+
itr->second = pub_key;
755+
}
756+
}
757+
758+
void database::refresh_witness_key_cache()
759+
{
760+
for( auto& wit_key : _witness_key_cache )
761+
{
762+
const witness_object* wit_obj = find( wit_key.first );
763+
if( wit_obj )
764+
wit_key.second = wit_obj->signing_key;
765+
else
766+
wit_key.second.reset();
767+
}
768+
}
769+
770+
optional<public_key_type> database::find_witness_key_from_cache( witness_id_type wit ) const
771+
{
772+
auto itr = _witness_key_cache.find( wit );
773+
if( itr != _witness_key_cache.end() )
774+
return itr->second;
775+
return optional<public_key_type>();
776+
}
777+
723778
} }

libraries/chain/db_management.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ void database::reindex( fc::path data_dir )
108108
skip_transaction_dupe_check |
109109
skip_tapos_check |
110110
skip_witness_schedule_check |
111+
skip_witness_key_cache_update |
111112
skip_authority_check);
112113
else
113114
{
@@ -185,6 +186,7 @@ void database::open(
185186
("last_block->id", last_block)("head_block_id",head_block_num()) );
186187
reindex( data_dir );
187188
}
189+
refresh_witness_key_cache();
188190
_opened = true;
189191
}
190192
FC_CAPTURE_LOG_AND_RETHROW( (data_dir) )

libraries/chain/include/graphene/chain/database.hpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ namespace graphene { namespace chain {
7575
skip_merkle_check = 1 << 7, ///< used while reindexing
7676
skip_assert_evaluation = 1 << 8, ///< used while reindexing
7777
skip_undo_history_check = 1 << 9, ///< used while reindexing
78-
skip_witness_schedule_check = 1 << 10, ///< used while reindexing
79-
skip_validate = 1 << 11 ///< used prior to checkpoint, skips validate() call on transaction
78+
skip_witness_schedule_check = 1 << 10, ///< used while reindexing
79+
skip_validate = 1 << 11, ///< used prior to checkpoint, skips validate() call on transaction
80+
skip_witness_key_cache_update = 1 << 12, ///< used while reindexing -- do not update cache
81+
force_witness_key_cache_update = 1 << 13 ///< used while applying a block but not applying pending transactions
8082
};
8183

8284
/**
@@ -439,11 +441,19 @@ namespace graphene { namespace chain {
439441
void apply_block( const signed_block& next_block, uint32_t skip = skip_nothing );
440442
processed_transaction apply_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing );
441443
operation_result apply_operation( transaction_evaluation_state& eval_state, const operation& op );
444+
445+
void init_witness_key_cache( std::set<witness_id_type>& witnesses );
446+
void update_witness_key_cache( witness_id_type wit, const public_key_type& pub_key );
447+
void refresh_witness_key_cache();
448+
optional<public_key_type> find_witness_key_from_cache( witness_id_type wit ) const;
449+
442450
private:
443451
void _apply_block( const signed_block& next_block );
444452
processed_transaction _apply_transaction( const signed_transaction& trx );
445453
void _cancel_bids_and_revive_mpa( const asset_object& bitasset, const asset_bitasset_data_object& bad );
446454

455+
flat_map< witness_id_type, optional<public_key_type> > _witness_key_cache;
456+
447457
///Steps involved in applying a new block
448458
///@{
449459

libraries/chain/witness_evaluator.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,21 @@ void_result witness_create_evaluator::do_evaluate( const witness_create_operatio
3838

3939
object_id_type witness_create_evaluator::do_apply( const witness_create_operation& op )
4040
{ try {
41+
database& _db = db();
4142
vote_id_type vote_id;
42-
db().modify(db().get_global_properties(), [&vote_id](global_property_object& p) {
43+
_db.modify( _db.get_global_properties(), [&vote_id](global_property_object& p) {
4344
vote_id = get_next_vote_id(p, vote_id_type::witness);
4445
});
4546

46-
const auto& new_witness_object = db().create<witness_object>( [&]( witness_object& obj ){
47+
const auto& new_witness_object = _db.create<witness_object>( [&op,&vote_id]( witness_object& obj ){
4748
obj.witness_account = op.witness_account;
4849
obj.signing_key = op.block_signing_key;
4950
obj.vote_id = vote_id;
5051
obj.url = op.url;
5152
});
53+
54+
_db.update_witness_key_cache( new_witness_object.id, op.block_signing_key );
55+
5256
return new_witness_object.id;
5357
} FC_CAPTURE_AND_RETHROW( (op) ) }
5458

@@ -63,13 +67,17 @@ void_result witness_update_evaluator::do_apply( const witness_update_operation&
6367
database& _db = db();
6468
_db.modify(
6569
_db.get(op.witness),
66-
[&]( witness_object& wit )
70+
[&op]( witness_object& wit )
6771
{
6872
if( op.new_url.valid() )
6973
wit.url = *op.new_url;
7074
if( op.new_signing_key.valid() )
7175
wit.signing_key = *op.new_signing_key;
7276
});
77+
78+
if( op.new_signing_key.valid() )
79+
_db.update_witness_key_cache( op.witness, *op.new_signing_key );
80+
7381
return void_result();
7482
} FC_CAPTURE_AND_RETHROW( (op) ) }
7583

libraries/plugins/witness/witness.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ void witness_plugin::plugin_startup()
130130
new_chain_banner(d);
131131
_production_skip_flags |= graphene::chain::database::skip_undo_history_check;
132132
}
133+
134+
d.init_witness_key_cache( _witnesses );
135+
133136
schedule_production_loop();
134137
} else
135138
elog("No witnesses configured! Please add witness IDs and private keys to configuration.");
@@ -250,7 +253,7 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb
250253
}
251254

252255
fc::time_point_sec scheduled_time = db.get_slot_time( slot );
253-
graphene::chain::public_key_type scheduled_key = scheduled_witness( db ).signing_key;
256+
graphene::chain::public_key_type scheduled_key = *db.find_witness_key_from_cache( scheduled_witness ); // should be valid
254257
auto private_key_itr = _private_keys.find( scheduled_key );
255258

256259
if( private_key_itr == _private_keys.end() )

tests/tests/block_tests.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,12 @@ BOOST_AUTO_TEST_CASE( change_signing_key )
264264
PUSH_TX( db, wu_trx, 0 );
265265
};
266266

267+
// Initialize witness key cache
268+
std::set< witness_id_type > witnesses;
269+
for( uint32_t i = 0; i <= 11; ++i ) // 11 init witnesses and 0 is reserved
270+
witnesses.insert( witness_id_type(i) );
271+
db.init_witness_key_cache( witnesses );
272+
267273
// open database
268274
db.open(data_dir.path(), make_genesis, "TEST");
269275

0 commit comments

Comments
 (0)