chain_controller.cpp 49.6 KB
Newer Older
A
Andrianto Lie 已提交
1 2 3
/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
N
Nathan Hourt 已提交
4
 */
N
Nathan Hourt 已提交
5

B
Bart Wyatt 已提交
6
#include <eosio/chain/chain_controller.hpp>
N
Nathan Hourt 已提交
7

B
Bart Wyatt 已提交
8 9 10 11 12 13 14 15 16
#include <eosio/chain/block_summary_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/key_value_object.hpp>
#include <eosio/chain/action_objects.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/transaction_object.hpp>
#include <eosio/chain/producer_object.hpp>
#include <eosio/chain/permission_link_object.hpp>
#include <eosio/chain/authority_checker.hpp>
D
Daniel Larimer 已提交
17
#include <eosio/chain/contracts/chain_initializer.hpp>
18
#include <eosio/chain/contracts/producer_objects.hpp>
19
#include <eosio/chain/scope_serial_object.hpp>
20
#include <eosio/chain/merkle.hpp>
N
Nathan Hourt 已提交
21

B
Bart Wyatt 已提交
22
#include <eosio/chain/wasm_interface.hpp>
23

24
#include <eos/utilities/rand.hpp>
25

N
Nathan Hourt 已提交
26
#include <fc/smart_ref_impl.hpp>
N
Nathan Hourt 已提交
27 28 29
#include <fc/uint128.hpp>
#include <fc/crypto/digest.hpp>

30
#include <boost/range/algorithm/copy.hpp>
N
Nathan Hourt 已提交
31
#include <boost/range/algorithm_ext/is_sorted.hpp>
32
#include <boost/range/adaptor/transformed.hpp>
N
Nathan Hourt 已提交
33
#include <boost/range/adaptor/map.hpp>
N
Nathan Hourt 已提交
34 35 36 37

#include <fstream>
#include <functional>
#include <iostream>
38
#include <chrono>
N
Nathan Hourt 已提交
39

P
Pravin 已提交
40
namespace eosio { namespace chain {
D
Daniel Larimer 已提交
41

42 43 44 45
bool is_start_of_round( block_num_type block_num ) {
  return (block_num % config::blocks_per_round) == 0; 
}

D
Daniel Larimer 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
chain_controller::chain_controller( const chain_controller::controller_config& cfg )
:_db( cfg.shared_memory_dir, 
      (cfg.read_only ? database::read_only : database::read_write), 
      cfg.shared_memory_size), 
 _block_log(cfg.block_log_dir) 
{
   _initialize_indexes();

   contracts::chain_initializer starter(cfg.genesis);
   starter.register_types(*this, _db);

   // Behave as though we are applying a block during chain initialization (it's the genesis block!)
   with_applying_block([&] {
      _initialize_chain(starter);
   });

   _spinup_db();
   _spinup_fork_db();

   if (_block_log.read_head() && head_block_num() < _block_log.read_head()->block_num())
      replay();
} /// chain_controller::chain_controller


chain_controller::~chain_controller() {
   clear_pending();
   _db.flush();
}

75
bool chain_controller::is_known_block(const block_id_type& id)const
N
Nathan Hourt 已提交
76
{
77
   return _fork_db.is_known_block(id) || _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
78 79 80 81 82 83
}
/**
 * Only return true *if* the transaction has not expired or been invalidated. If this
 * method is called with a VERY old transaction we will return false, they should
 * query things by blocks if they are that old.
 */
84
bool chain_controller::is_known_transaction(const transaction_id_type& id)const
N
Nathan Hourt 已提交
85
{
86
   const auto& trx_idx = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
87 88 89
   return trx_idx.find( id ) != trx_idx.end();
}

90
block_id_type chain_controller::get_block_id_for_num(uint32_t block_num)const
N
Nathan Hourt 已提交
91
{ try {
92 93
   if (const auto& block = fetch_block_by_number(block_num))
      return block->id();
N
Nathan Hourt 已提交
94

95 96 97
   FC_THROW_EXCEPTION(unknown_block_exception, "Could not find block");
} FC_CAPTURE_AND_RETHROW((block_num)) }

98
optional<signed_block> chain_controller::fetch_block_by_id(const block_id_type& id)const
N
Nathan Hourt 已提交
99
{
100 101
   auto b = _fork_db.fetch_block(id);
   if(b) return b->data;
102
   return _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
103 104
}

105
optional<signed_block> chain_controller::fetch_block_by_number(uint32_t num)const
N
Nathan Hourt 已提交
106
{
107
   if (const auto& block = _block_log.read_block_by_num(num))
108 109
      return *block;

N
Nathan Hourt 已提交
110
   // Not in _block_log, so it must be since the last irreversible block. Grab it from _fork_db instead
111 112 113 114 115 116 117 118
   if (num <= head_block_num()) {
      auto block = _fork_db.head();
      while (block && block->num > num)
         block = block->prev.lock();
      if (block && block->num == num)
         return block->data;
   }

N
Nathan Hourt 已提交
119 120 121
   return optional<signed_block>();
}

D
Daniel Larimer 已提交
122
/*
D
Daniel Larimer 已提交
123
const signed_transaction& chain_controller::get_recent_transaction(const transaction_id_type& trx_id) const
N
Nathan Hourt 已提交
124
{
125
   auto& index = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
126 127 128 129
   auto itr = index.find(trx_id);
   FC_ASSERT(itr != index.end());
   return itr->trx;
}
D
Daniel Larimer 已提交
130
*/
N
Nathan Hourt 已提交
131

132
std::vector<block_id_type> chain_controller::get_block_ids_on_fork(block_id_type head_of_fork) const
N
Nathan Hourt 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
{
  pair<fork_database::branch_type, fork_database::branch_type> branches = _fork_db.fetch_branch_from(head_block_id(), head_of_fork);
  if( !((branches.first.back()->previous_id() == branches.second.back()->previous_id())) )
  {
     edump( (head_of_fork)
            (head_block_id())
            (branches.first.size())
            (branches.second.size()) );
     assert(branches.first.back()->previous_id() == branches.second.back()->previous_id());
  }
  std::vector<block_id_type> result;
  for (const item_ptr& fork_block : branches.second)
    result.emplace_back(fork_block->id);
  result.emplace_back(branches.first.back()->previous_id());
  return result;
}

150

N
Nathan Hourt 已提交
151 152 153 154 155 156
/**
 * Push block "may fail" in which case every partial change is unwound.  After
 * push block is successful the block is appended to the chain database on disk.
 *
 * @return true if we switched forks as a result of this push.
 */
D
Daniel Larimer 已提交
157
void chain_controller::push_block(const signed_block& new_block, uint32_t skip)
D
Daniel Larimer 已提交
158
{ try {
D
Daniel Larimer 已提交
159
   with_skip_flags( skip, [&](){ 
D
Daniel Larimer 已提交
160
      return without_pending_transactions( [&]() {
161
         return _db.with_write_lock( [&]() {
162 163
            return _push_block(new_block);
         } );
N
Nathan Hourt 已提交
164 165
      });
   });
166
} FC_CAPTURE_AND_RETHROW((new_block)) }
N
Nathan Hourt 已提交
167

168
bool chain_controller::_push_block(const signed_block& new_block)
N
Nathan Hourt 已提交
169
{ try {
N
Nathan Hourt 已提交
170
   uint32_t skip = _skip_flags;
171
   if (!(skip&skip_fork_db)) {
N
Nathan Hourt 已提交
172
      /// TODO: if the block is greater than the head block and before the next maintenance interval
N
Nathan Hourt 已提交
173 174 175 176
      // verify that the block signer is in the current set of active producers.

      shared_ptr<fork_item> new_head = _fork_db.push_block(new_block);
      //If the head block from the longest chain does not build off of the current head, we need to switch forks.
177
      if (new_head->data.previous != head_block_id()) {
N
Nathan Hourt 已提交
178 179
         //If the newly pushed block is the same height as head, we get head back in new_head
         //Only switch forks if new_head is actually higher than head
180 181
         if (new_head->data.block_num() > head_block_num()) {
            wlog("Switching to fork: ${id}", ("id",new_head->data.id()));
N
Nathan Hourt 已提交
182 183 184
            auto branches = _fork_db.fetch_branch_from(new_head->data.id(), head_block_id());

            // pop blocks until we hit the forked block
185
            while (head_block_id() != branches.second.back()->data.previous)
N
Nathan Hourt 已提交
186 187 188
               pop_block();

            // push all blocks on the new fork
189 190
            for (auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
                ilog("pushing blocks from fork ${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->data.id()));
N
Nathan Hourt 已提交
191 192
                optional<fc::exception> except;
                try {
193
                   auto session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
194
                   _apply_block((*ritr)->data, skip);
N
Nathan Hourt 已提交
195 196
                   session.push();
                }
197 198 199
                catch (const fc::exception& e) { except = e; }
                if (except) {
                   wlog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
N
Nathan Hourt 已提交
200
                   // remove the rest of branches.first from the fork_db, those blocks are invalid
201 202
                   while (ritr != branches.first.rend()) {
                      _fork_db.remove((*ritr)->data.id());
N
Nathan Hourt 已提交
203 204
                      ++ritr;
                   }
205
                   _fork_db.set_head(branches.second.front());
N
Nathan Hourt 已提交
206 207

                   // pop all blocks from the bad fork
208
                   while (head_block_id() != branches.second.back()->data.previous)
N
Nathan Hourt 已提交
209 210 211
                      pop_block();

                   // restore all blocks from the good fork
212
                   for (auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr) {
213
                      auto session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
214
                      _apply_block((*ritr)->data, skip);
N
Nathan Hourt 已提交
215 216 217 218 219
                      session.push();
                   }
                   throw *except;
                }
            }
D
Daniel Larimer 已提交
220
            return true; //swithced fork
N
Nathan Hourt 已提交
221
         }
D
Daniel Larimer 已提交
222
         else return false; // didn't switch fork
N
Nathan Hourt 已提交
223 224 225 226
      }
   }

   try {
227
      auto session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
228
      _apply_block(new_block, skip);
N
Nathan Hourt 已提交
229 230 231 232 233 234 235 236
      session.push();
   } catch ( const fc::exception& e ) {
      elog("Failed to push new block:\n${e}", ("e", e.to_detail_string()));
      _fork_db.remove(new_block.id());
      throw;
   }

   return false;
237
} FC_CAPTURE_AND_RETHROW((new_block)) }
N
Nathan Hourt 已提交
238 239 240 241 242 243 244 245 246 247

/**
 * Attempts to push the transaction into the pending queue
 *
 * When called to push a locally generated transaction, set the skip_block_size_check bit on the skip argument. This
 * will allow the transaction to be pushed even if it causes the pending block size to exceed the maximum block size.
 * Although the transaction will probably not propagate further now, as the peers are likely to have their pending
 * queues full as well, it will be kept in the queue to be propagated later when a new block flushes out the pending
 * queues.
 */
248
transaction_trace chain_controller::push_transaction(const signed_transaction& trx, uint32_t skip)
N
Nathan Hourt 已提交
249
{ try {
250 251 252
   return with_skip_flags(skip, [&]() {
      return _db.with_write_lock([&]() {
         return _push_transaction(trx);
D
Daniel Larimer 已提交
253
      });
N
Nathan Hourt 已提交
254 255
   });
} FC_CAPTURE_AND_RETHROW((trx)) }
N
Nathan Hourt 已提交
256

257
transaction_trace chain_controller::_push_transaction(const signed_transaction& trx) {
258 259
   // If this is the first transaction pushed after applying a block, start a new undo session.
   // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives.
D
Daniel Larimer 已提交
260
   if( !_pending_block ) {
D
Daniel Larimer 已提交
261
      _start_pending_block();
D
Daniel Larimer 已提交
262
   }
263

264
   auto temp_session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
265

B
Bart Wyatt 已提交
266
   // for now apply the transaction serially but schedule it according to those invariants
267
   validate_referenced_accounts(trx);
N
Nathan Hourt 已提交
268
   check_transaction_authorization(trx);
N
Nathan Hourt 已提交
269

270
   auto shardnum = _pending_cycle.schedule( trx );
271 272 273 274 275 276 277 278
   auto cyclenum = _pending_block->regions.back().cycles_summary.size() - 1;
   if (shardnum == -1) {
      cyclenum += 1;
   }

   auto result = _apply_transaction(trx, _pending_block->regions.back().region, cyclenum);


279
   if( shardnum == -1 ) { /// schedule conflict start new cycle
280 281
      _finalize_pending_cycle();
      _start_pending_cycle();
B
Bart Wyatt 已提交
282
      shardnum = _pending_cycle.schedule( trx );
283 284
   }

285

286
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
287
   if( shardnum >= bcycle.size() ) {
288
      _start_pending_shard();
289 290
   }

291 292

   auto tid = trx.id();
B
Bart Wyatt 已提交
293
   bcycle.at(shardnum).emplace_back( tid );
294
   _pending_cycle_trace->shard_traces.at(shardnum).append(result);
B
Bart Wyatt 已提交
295

296 297
   /** for now we will just shove everything into the first shard */
   _pending_block->input_transactions.push_back(trx);
D
Daniel Larimer 已提交
298

N
Nathan Hourt 已提交
299 300 301 302
   // The transaction applied successfully. Merge its changes into the pending block session.
   temp_session.squash();

   // notify anyone listening to pending transactions
B
Bart Wyatt 已提交
303 304 305
   on_pending_transaction(trx);

   return result;
N
Nathan Hourt 已提交
306 307
}

308

309 310 311 312 313 314 315

void chain_controller::_start_pending_block()
{
   FC_ASSERT( !_pending_block );
   _pending_block         = signed_block();
   _pending_block_trace   = block_trace(*_pending_block);
   _pending_block_session = _db.start_undo_session(true);
316 317
   _pending_block->regions.resize(1);
   _pending_block_trace->region_traces.resize(1);
318 319 320
   _start_pending_cycle();
}

321 322
/**
 *  Wraps up all work for current shards, starts a new cycle, and
323
 *  executes any pending transactions
324
 */
325
void chain_controller::_start_pending_cycle() {
326
   _pending_block->regions.back().cycles_summary.resize( _pending_block->regions[0].cycles_summary.size() + 1 );
327
   _pending_cycle = pending_cycle_state();
328 329
   _pending_cycle_trace = cycle_trace();
   _start_pending_shard();
330 331

   /// TODO: check for deferred transactions and schedule them
332
} // _start_pending_cycle
333

334
void chain_controller::_start_pending_shard()
B
Bart Wyatt 已提交
335
{
336
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
337 338 339
   bcycle.resize( bcycle.size()+1 );

   _pending_cycle_trace->shard_traces.resize(_pending_cycle_trace->shard_traces.size() + 1 );
B
Bart Wyatt 已提交
340 341
}

342 343
void chain_controller::_finalize_pending_cycle()
{
344 345 346 347
   for( auto& shard : _pending_cycle_trace->shard_traces ) {
      shard.calculate_root();
   }

348
   _apply_cycle_trace(*_pending_cycle_trace);
349
   _pending_block_trace->region_traces.back().cycle_traces.emplace_back(std::move(*_pending_cycle_trace));
350 351
   _pending_cycle_trace.reset();
}
B
Bart Wyatt 已提交
352

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
void chain_controller::_apply_cycle_trace( const cycle_trace& res )
{
   for (const auto&st: res.shard_traces) {
      for (const auto &tr: st.transaction_traces) {
         for (const auto &dt: tr.deferred_transactions) {
            _db.create<generated_transaction_object>([&](auto &obj) {
               obj.trx_id = dt.id();
               obj.sender = dt.sender;
               obj.sender_id = dt.sender_id;
               obj.expiration = dt.expiration;
               obj.delay_until = dt.execute_after;
               obj.packed_trx.resize(fc::raw::pack_size(dt));
               fc::datastream<char *> ds(obj.packed_trx.data(), obj.packed_trx.size());
               fc::raw::pack(ds, dt);
            });
         }

         ///TODO: hook this up as a signal handler in a de-coupled "logger" that may just silently drop them
         for (const auto &ar : tr.action_traces) {
            if (!ar.console.empty()) {
               auto prefix = fc::format_string(
                  "[(${s},${a})->${r}]",
                  fc::mutable_variant_object()
                     ("s", ar.act.scope)
                     ("a", ar.act.name)
                     ("r", ar.receiver));
               std::cerr << prefix << ": CONSOLE OUTPUT BEGIN =====================" << std::endl;
               std::cerr << ar.console;
               std::cerr << prefix << ": CONSOLE OUTPUT END   =====================" << std::endl;
            }
383
         }
B
Bart Wyatt 已提交
384 385 386 387
      }
   }
}

388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
/**
 *  After applying all transactions successfully we can update
 *  the current block time, block number, producer stats, etc
 */
void chain_controller::_finalize_block( const block_trace& trace ) { try {
   const auto& b = trace.block;
   const producer_object& signing_producer = validate_block_header(_skip_flags, b);

   update_global_properties( b );
   update_global_dynamic_data( b );
   update_signing_producer(signing_producer, b);
   update_last_irreversible_block();

   create_block_summary(b);
   clear_expired_transactions();

404
   applied_block( trace ); //emit
405 406 407 408 409
   if (_currently_replaying_blocks)
     applied_irreversible_block(b);

} FC_CAPTURE_AND_RETHROW( (trace.block) ) }

410
signed_block chain_controller::generate_block(
D
Daniel Larimer 已提交
411 412 413
   block_timestamp_type when,
   account_name producer,
   const private_key_type& block_signing_private_key,
N
Nathan Hourt 已提交
414 415 416
   uint32_t skip /* = 0 */
   )
{ try {
N
Nathan Hourt 已提交
417
   return with_skip_flags( skip, [&](){
D
Daniel Larimer 已提交
418
      return _db.with_write_lock( [&](){
D
Daniel Larimer 已提交
419
         return _generate_block( when, producer, block_signing_private_key );
D
Daniel Larimer 已提交
420
      });
N
Nathan Hourt 已提交
421
   });
D
Daniel Larimer 已提交
422
} FC_CAPTURE_AND_RETHROW( (when) ) }
N
Nathan Hourt 已提交
423

D
Daniel Larimer 已提交
424 425 426 427 428
signed_block chain_controller::_generate_block( block_timestamp_type when, 
                                              account_name producer, 
                                              const private_key_type& block_signing_key )
{ try {
   uint32_t skip     = _skip_flags;
N
Nathan Hourt 已提交
429 430
   uint32_t slot_num = get_slot_at_time( when );
   FC_ASSERT( slot_num > 0 );
D
Daniel Larimer 已提交
431
   account_name scheduled_producer = get_scheduled_producer( slot_num );
N
Nathan Hourt 已提交
432
   FC_ASSERT( scheduled_producer == producer );
N
Nathan Hourt 已提交
433

N
Nathan Hourt 已提交
434
   const auto& producer_obj = get_producer(scheduled_producer);
N
Nathan Hourt 已提交
435

D
Daniel Larimer 已提交
436
   if( !_pending_block ) {
D
Daniel Larimer 已提交
437
      _start_pending_block();
438 439
   }

440
   _finalize_pending_cycle();
441

D
Daniel Larimer 已提交
442 443
   if( !(skip & skip_producer_signature) )
      FC_ASSERT( producer_obj.signing_key == block_signing_key.get_public_key() );
N
Nathan Hourt 已提交
444

445 446 447 448 449 450 451
      _pending_block->timestamp   = when;
      _pending_block->producer    = producer_obj.owner;
      _pending_block->previous    = head_block_id();
      _pending_block->block_mroot = get_dynamic_global_properties().block_merkle_root.get_root();
      _pending_block->transaction_mroot = _pending_block->calculate_transaction_merkle_root();
      _pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root();

452

453
      if( is_start_of_round( _pending_block->block_num() ) ) {
454 455 456
      auto latest_producer_schedule = _calculate_producer_schedule();
      if( latest_producer_schedule != _head_producer_schedule() )
         _pending_block->new_producers = latest_producer_schedule;
457 458
   }

N
Nathan Hourt 已提交
459
   if( !(skip & skip_producer_signature) )
D
Daniel Larimer 已提交
460
      _pending_block->sign( block_signing_key );
N
Nathan Hourt 已提交
461

462
   _finalize_block( *_pending_block_trace );
D
Daniel Larimer 已提交
463

464 465
   _pending_block_session->push();

D
Daniel Larimer 已提交
466 467
   auto result = move( *_pending_block );

468
   _pending_block_trace.reset();
469 470 471
   _pending_block.reset();
   _pending_block_session.reset();

D
Daniel Larimer 已提交
472
   if (!(skip&skip_fork_db)) {
D
Daniel Larimer 已提交
473
      _fork_db.push_block(result);
N
Nathan Hourt 已提交
474
   }
D
Daniel Larimer 已提交
475
   return result;
N
Nathan Hourt 已提交
476

N
Nathan Hourt 已提交
477
} FC_CAPTURE_AND_RETHROW( (producer) ) }
N
Nathan Hourt 已提交
478 479

/**
N
Nathan Hourt 已提交
480
 * Removes the most recent block from the database and undoes any changes it made.
N
Nathan Hourt 已提交
481
 */
482
void chain_controller::pop_block()
N
Nathan Hourt 已提交
483
{ try {
D
Daniel Larimer 已提交
484
   _pending_block_session.reset();
N
Nathan Hourt 已提交
485 486 487 488 489
   auto head_id = head_block_id();
   optional<signed_block> head_block = fetch_block_by_id( head_id );
   EOS_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" );

   _fork_db.pop_block();
490
   _db.undo();
N
Nathan Hourt 已提交
491 492
} FC_CAPTURE_AND_RETHROW() }

493
void chain_controller::clear_pending()
N
Nathan Hourt 已提交
494
{ try {
495
   _pending_block_trace.reset();
D
Daniel Larimer 已提交
496
   _pending_block.reset();
D
Daniel Larimer 已提交
497
   _pending_block_session.reset();
N
Nathan Hourt 已提交
498 499 500 501
} FC_CAPTURE_AND_RETHROW() }

//////////////////// private methods ////////////////////

D
Daniel Larimer 已提交
502
void chain_controller::_apply_block(const signed_block& next_block, uint32_t skip)
N
Nathan Hourt 已提交
503 504
{
   auto block_num = next_block.block_num();
505 506 507 508 509
   if (_checkpoints.size() && _checkpoints.rbegin()->second != block_id_type()) {
      auto itr = _checkpoints.find(block_num);
      if (itr != _checkpoints.end())
         FC_ASSERT(next_block.id() == itr->second,
                   "Block did not match checkpoint", ("checkpoint",*itr)("block_id",next_block.id()));
N
Nathan Hourt 已提交
510

511
      if (_checkpoints.rbegin()->first >= block_num)
N
Nathan Hourt 已提交
512 513
         skip = ~0;// WE CAN SKIP ALMOST EVERYTHING
   }
N
Nathan Hourt 已提交
514 515 516

   with_applying_block([&] {
      with_skip_flags(skip, [&] {
D
Daniel Larimer 已提交
517
         __apply_block(next_block);
N
Nathan Hourt 已提交
518 519
      });
   });
N
Nathan Hourt 已提交
520 521
}

522

D
Daniel Larimer 已提交
523
void chain_controller::__apply_block(const signed_block& next_block)
N
Nathan Hourt 已提交
524
{ try {
N
Nathan Hourt 已提交
525
   uint32_t skip = _skip_flags;
N
Nathan Hourt 已提交
526

D
Daniel Larimer 已提交
527 528 529
   /*
   FC_ASSERT((skip & skip_merkle_check) 
             || next_block.transaction_merkle_root == next_block.calculate_merkle_root(),
530 531
             "", ("next_block.transaction_merkle_root", next_block.transaction_merkle_root)
             ("calc",next_block.calculate_merkle_root())("next_block",next_block)("id",next_block.id()));
D
Daniel Larimer 已提交
532
             */
N
Nathan Hourt 已提交
533 534

   const producer_object& signing_producer = validate_block_header(skip, next_block);
535

536 537 538 539
   /// regions must be listed in order
   for( uint32_t i = 1; i < next_block.regions.size(); ++i )
      FC_ASSERT( next_block.regions[i-1].region < next_block.regions[i].region );

540 541 542 543 544 545 546

   /// cache the input tranasction ids so that they can be looked up when executing the
   /// summary
   map<transaction_id_type,const signed_transaction*> trx_index;
   for( const auto& t : next_block.input_transactions ) {
      trx_index[t.id()] = &t;
   }
547 548

   block_trace next_block_trace(next_block);
549 550
   next_block_trace.region_traces.reserve(next_block.regions.size());

551
   for( const auto& r : next_block.regions ) {
552 553 554
      region_trace r_trace;
      r_trace.cycle_traces.reserve(r.cycles_summary.size());

555 556
      for (uint32_t cycle_index; cycle_index < r.cycles_summary.size(); cycle_index++) {
         const auto& cycle = r.cycles_summary.at(cycle_index);
557 558 559
         cycle_trace c_trace;
         c_trace.shard_traces.reserve(cycle.size());

560
         for (const auto& shard: cycle) {
561
            shard_trace s_trace;
562 563 564 565
            for (const auto& receipt : shard) {
               if( receipt.status == transaction_receipt::executed ) {
                  auto itr = trx_index.find(receipt.id);
                  if( itr != trx_index.end() ) {
566
                     s_trace.append(_apply_transaction( *itr->second, r.region, cycle_index));
567 568
                  }
                  else
569 570 571
                  {
                     FC_ASSERT( !"deferred transactions not yet supported" );
                  }
B
Bart Wyatt 已提交
572
               }
573 574 575 576 577
               // validate_referenced_accounts(trx);
               // Check authorization, and allow irrelevant signatures.
               // If the block producer let it slide, we'll roll with it.
               // check_transaction_authorization(trx, true);
            } /// for each transaction id
N
Nathan Hourt 已提交
578

579 580 581
            s_trace.calculate_root();
            c_trace.shard_traces.emplace_back(move(s_trace));
         } /// for each shard
D
Daniel Larimer 已提交
582

583 584 585
         _apply_cycle_trace(c_trace);
         r_trace.cycle_traces.emplace_back(move(c_trace));
      } /// for each cycle
D
Daniel Larimer 已提交
586

587 588
      next_block_trace.region_traces.emplace_back(move(r_trace));
   } /// for each region
N
Nathan Hourt 已提交
589

590
   FC_ASSERT(next_block.action_mroot == next_block_trace.calculate_action_merkle_root());
N
Nathan Hourt 已提交
591

592 593
   _finalize_block( next_block_trace );
} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) )  }
D
Daniel Larimer 已提交
594

595
flat_set<public_key_type> chain_controller::get_required_keys(const signed_transaction& trx,
B
Bart Wyatt 已提交
596
                                                              const flat_set<public_key_type>& candidate_keys)const 
D
Daniel Larimer 已提交
597
{
598 599 600
   auto checker = make_auth_checker( [&](auto p){ return get_permission(p).auth; }, 
                                     get_global_properties().configuration.max_authority_depth,
                                     candidate_keys);
601

D
Daniel Larimer 已提交
602 603 604 605
   for (const auto& act : trx.actions ) {
      for (const auto& declared_auth : act.authorization) {
         if (!checker.satisfied(declared_auth)) {
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
606
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
607
                       ("auth", declared_auth));
608 609 610 611 612 613 614
         }
      }
   }

   return checker.used_keys();
}

615 616 617 618
void chain_controller::check_authorization( const transaction& trx, 
                                            flat_set<public_key_type> provided_keys,
                                            bool allow_unused_signatures,
                                            flat_set<account_name>    provided_accounts  )const
D
Daniel Larimer 已提交
619
{
620 621
   auto checker = make_auth_checker( [&](auto p){ return get_permission(p).auth; }, 
                                     get_global_properties().configuration.max_authority_depth,
622 623
                                     provided_keys, provided_accounts );

N
Nathan Hourt 已提交
624

625
   for( const auto& act : trx.actions ) {
626
      for( const auto& declared_auth : act.authorization ) {
D
Daniel Larimer 已提交
627

628 629
         const auto& min_permission = lookup_minimum_permission(declared_auth.actor, 
                                                                act.scope, act.name);
D
Daniel Larimer 已提交
630

N
Nathan Hourt 已提交
631 632
         if ((_skip_flags & skip_authority_check) == false) {
            const auto& index = _db.get_index<permission_index>().indices();
633 634
            EOS_ASSERT(get_permission(declared_auth).satisfies(min_permission, index), 
                       tx_irrelevant_auth,
D
Daniel Larimer 已提交
635
                       "action declares irrelevant authority '${auth}'; minimum authority is ${min}",
D
Daniel Larimer 已提交
636
                       ("auth", declared_auth)("min", min_permission.name));
N
Nathan Hourt 已提交
637 638
         }
         if ((_skip_flags & skip_transaction_signatures) == false) {
D
Daniel Larimer 已提交
639
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
640
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
641
                       ("auth", declared_auth));
N
Nathan Hourt 已提交
642 643
         }
      }
644
   }
N
Nathan Hourt 已提交
645

646
   if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false)
647
      EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
648 649
                 "transaction bears irrelevant signatures from these keys: ${keys}", 
                 ("keys", checker.unused_keys()));
N
Nathan Hourt 已提交
650 651
}

652 653 654 655 656 657
void chain_controller::check_transaction_authorization(const signed_transaction& trx, 
                                                       bool allow_unused_signatures)const 
{
   check_authorization( trx, trx.get_signature_keys( chain_id_type{} ), allow_unused_signatures );
}

D
Daniel Larimer 已提交
658
void chain_controller::validate_scope( const transaction& trx )const {
659 660 661 662 663 664 665 666
   for( uint32_t i = 1; i < trx.read_scope.size(); ++i ) {
      EOS_ASSERT( trx.read_scope[i-1] < trx.read_scope[i], transaction_exception, 
                  "Scopes must be sorted and unique" );
   }
   for( uint32_t i = 1; i < trx.write_scope.size(); ++i ) {
      EOS_ASSERT( trx.write_scope[i-1] < trx.write_scope[i], transaction_exception, 
                  "Scopes must be sorted and unique" );
   }
D
Daniel Larimer 已提交
667 668 669 670

   vector<account_name> intersection;
   std::set_intersection( trx.read_scope.begin(), trx.read_scope.end(),
                          trx.write_scope.begin(), trx.write_scope.end(),
671 672
                          std::back_inserter(intersection) );
   FC_ASSERT( intersection.size() == 0, "a transaction may not redeclare scope in readscope" );
673 674
}

D
Daniel Larimer 已提交
675 676 677
const permission_object& chain_controller::lookup_minimum_permission(account_name authorizer_account,
                                                                    account_name scope,
                                                                    action_name act_name) const {
N
Nathan Hourt 已提交
678
   try {
D
Daniel Larimer 已提交
679 680 681
      // First look up a specific link for this message act_name
      auto key = boost::make_tuple(authorizer_account, scope, act_name);
      auto link = _db.find<permission_link_object, by_action_name>(key);
682 683 684
      // If no specific link found, check for a contract-wide default
      if (link == nullptr) {
         get<2>(key) = "";
D
Daniel Larimer 已提交
685
         link = _db.find<permission_link_object, by_action_name>(key);
686 687 688
      }

      // If no specific or default link found, use active permission
D
Daniel Larimer 已提交
689
      auto permission_key = boost::make_tuple<account_name, permission_name>(authorizer_account, config::active_name );
690
      if (link != nullptr)
D
Daniel Larimer 已提交
691 692 693
         get<1>(permission_key) = link->required_permission;
      return _db.get<permission_object, by_owner>(permission_key);
   } FC_CAPTURE_AND_RETHROW((authorizer_account)(scope)(act_name))
N
Nathan Hourt 已提交
694 695
}

D
Daniel Larimer 已提交
696
void chain_controller::validate_uniqueness( const signed_transaction& trx )const {
N
Nathan Hourt 已提交
697
   if( !should_check_for_duplicate_transactions() ) return;
N
Nathan Hourt 已提交
698

N
Nathan Hourt 已提交
699
   auto transaction = _db.find<transaction_object, by_trx_id>(trx.id());
D
Daniel Larimer 已提交
700
   EOS_ASSERT(transaction == nullptr, tx_duplicate, "transaction is not unique");
701
}
702

D
Daniel Larimer 已提交
703
void chain_controller::record_transaction(const signed_transaction& trx) {
704 705
   //Insert transaction into unique transactions database.
    _db.create<transaction_object>([&](transaction_object& transaction) {
D
Daniel Larimer 已提交
706 707
        transaction.trx_id = trx.id(); 
        transaction.expiration = trx.expiration;
708 709 710 711
    });
}


D
Daniel Larimer 已提交
712
void chain_controller::validate_tapos(const transaction& trx)const {
N
Nathan Hourt 已提交
713
   if (!should_check_tapos()) return;
714

D
Daniel Larimer 已提交
715
   const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.ref_block_num);
716 717

   //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
D
Daniel Larimer 已提交
718
   EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), transaction_exception,
D
Daniel Larimer 已提交
719
              "transaction's reference block did not match. Is this transaction from a different fork?",
N
Nathan Hourt 已提交
720 721
              ("tapos_summary", tapos_block_summary));
}
722

D
Daniel Larimer 已提交
723 724
void chain_controller::validate_referenced_accounts( const transaction& trx )const 
{ try { 
D
Daniel Larimer 已提交
725
   for( const auto& scope : trx.read_scope )
726
      require_scope(scope);
D
Daniel Larimer 已提交
727
   for( const auto& scope : trx.write_scope )
728
      require_scope(scope);
D
Daniel Larimer 已提交
729

D
Daniel Larimer 已提交
730 731
   for( const auto& act : trx.actions ) {
      require_account(act.scope);
D
Daniel Larimer 已提交
732
      for (const auto& auth : act.authorization )
D
Daniel Larimer 已提交
733
         require_account(auth.actor);
734
   }
D
Daniel Larimer 已提交
735
} FC_CAPTURE_AND_RETHROW() }
D
Daniel Larimer 已提交
736

D
Daniel Larimer 已提交
737
void chain_controller::validate_expiration( const transaction& trx ) const
738
{ try {
D
Daniel Larimer 已提交
739
   fc::time_point now = head_block_time();
D
Daniel Larimer 已提交
740
   const auto& chain_configuration = get_global_properties().configuration;
741

D
Daniel Larimer 已提交
742
   EOS_ASSERT( time_point(trx.expiration) <= now + fc::seconds(chain_configuration.max_transaction_lifetime),
D
Daniel Larimer 已提交
743
              transaction_exception, "transaction expiration is too far in the future",
744
              ("trx.expiration",trx.expiration)("now",now)
D
Daniel Larimer 已提交
745 746
              ("max_til_exp",chain_configuration.max_transaction_lifetime));
   EOS_ASSERT( now <= time_point(trx.expiration), transaction_exception, "transaction is expired",
747 748
              ("now",now)("trx.exp",trx.expiration));
} FC_CAPTURE_AND_RETHROW((trx)) }
749

750

751 752
void chain_controller::require_scope( const scope_name& scope )const {
   switch( uint64_t(scope) ) {
753 754
      case config::eosio_all_scope:
      case config::eosio_auth_scope:
755 756 757 758 759 760
         return; /// built in scopes
      default:
         require_account(scope);
   }
}

D
Daniel Larimer 已提交
761
void chain_controller::require_account(const account_name& name) const {
N
Nathan Hourt 已提交
762 763 764
   auto account = _db.find<account_object, by_name>(name);
   FC_ASSERT(account != nullptr, "Account not found: ${name}", ("name", name));
}
N
Nathan Hourt 已提交
765

766
const producer_object& chain_controller::validate_block_header(uint32_t skip, const signed_block& next_block)const {
767 768
   EOS_ASSERT(head_block_id() == next_block.previous, block_validate_exception, "",
              ("head_block_id",head_block_id())("next.prev",next_block.previous));
D
Daniel Larimer 已提交
769
   EOS_ASSERT(head_block_time() < (fc::time_point)next_block.timestamp, block_validate_exception, "",
770
              ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()));
D
Daniel Larimer 已提交
771 772
   if (next_block.block_num() % config::blocks_per_round != 0) {
      EOS_ASSERT(!next_block.new_producers, block_validate_exception,
773
                 "Producer changes may only occur at the end of a round.");
N
Nathan Hourt 已提交
774
   }
D
Daniel Larimer 已提交
775 776
   
   const producer_object& producer = get_producer(get_scheduled_producer(get_slot_at_time(next_block.timestamp)));
N
Nathan Hourt 已提交
777

N
Nathan Hourt 已提交
778
   if(!(skip&skip_producer_signature))
779 780 781
      EOS_ASSERT(next_block.validate_signee(producer.signing_key), block_validate_exception,
                 "Incorrect block producer key: expected ${e} but got ${a}",
                 ("e", producer.signing_key)("a", public_key_type(next_block.signee())));
N
Nathan Hourt 已提交
782

783
   if(!(skip&skip_producer_schedule_check)) {
784 785 786
      EOS_ASSERT(next_block.producer == producer.owner, block_validate_exception,
                 "Producer produced block at wrong time",
                 ("block producer",next_block.producer)("scheduled producer",producer.owner));
N
Nathan Hourt 已提交
787 788
   }

789 790 791
   
   FC_ASSERT( next_block.calculate_transaction_merkle_root() == next_block.transaction_mroot, "merkle root does not match" );

N
Nathan Hourt 已提交
792 793 794
   return producer;
}

795
void chain_controller::create_block_summary(const signed_block& next_block) {
796
   auto sid = next_block.block_num() & 0xffff;
797
   _db.modify( _db.get<block_summary_object,by_id>(sid), [&](block_summary_object& p) {
798 799
         p.block_id = next_block.id();
   });
N
Nathan Hourt 已提交
800 801
}

802 803 804 805 806 807 808 809 810
/**
 *  Takes the top config::producer_count producers by total vote excluding any producer whose
 *  block_signing_key is null.  
 */
producer_schedule_type chain_controller::_calculate_producer_schedule()const {
   const auto& producers_by_vote = _db.get_index<contracts::producer_votes_multi_index,contracts::by_votes>();
   auto itr = producers_by_vote.begin();
   producer_schedule_type schedule;
   uint32_t count = 0;
811 812 813
   while( itr != producers_by_vote.end() && count < schedule.producers.size() ) {
      schedule.producers[count].producer_name = itr->owner_name;
      schedule.producers[count].block_signing_key = get_producer(itr->owner_name).signing_key;
814
      ++itr;
815
      if( schedule.producers[count].block_signing_key != public_key_type() ) {
816 817 818
         ++count;
      }
   }
819 820 821 822
   const auto& hps = _head_producer_schedule();
   schedule.version = hps.version;
   if( hps != schedule )
      ++schedule.version;
823 824 825 826 827 828 829 830 831 832 833 834 835
   return schedule;
}

/**
 *  Returns the most recent and/or pending producer schedule
 */
const producer_schedule_type& chain_controller::_head_producer_schedule()const {
   const auto& gpo = get_global_properties();
   if( gpo.pending_active_producers.size() ) 
      return gpo.pending_active_producers.back().second;
   return gpo.active_producers;
}

836
void chain_controller::update_global_properties(const signed_block& b) { try {
837 838
   // If we're at the end of a round, update the BlockchainConfiguration, producer schedule
   // and "producers" special account authority
839 840 841 842 843
   if( is_start_of_round( b.block_num() ) ) {
      auto schedule = _calculate_producer_schedule();
      if( b.new_producers )
      {
          FC_ASSERT( schedule == *b.new_producers, "pending producer set different than expected" );
844 845 846
      }

      const auto& gpo = get_global_properties();
847 848 849

      if( _head_producer_schedule() != schedule ) {
         FC_ASSERT( b.new_producers, "pending producer set changed but block didn't indicate it" );
850
      }
851 852 853 854 855 856 857 858
      _db.modify( gpo, [&]( auto& props ) {
         if( props.pending_active_producers.size() && props.pending_active_producers.back().first == b.block_num() )
            props.pending_active_producers.back().second = schedule;
         else
            props.pending_active_producers.push_back( make_pair(b.block_num(),schedule) );
      });


859

860
      auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
861
      for(auto& name : gpo.active_producers.producers ) {
862
         active_producers_authority.accounts.push_back({{name.producer_name, config::active_name}, 1});
863 864
      }

D
Daniel Larimer 已提交
865
      auto& po = _db.get<permission_object, by_owner>( boost::make_tuple(config::producers_account_name, 
866
                                                                         config::active_name ) );
867 868 869
      _db.modify(po,[active_producers_authority] (permission_object& po) {
         po.auth = active_producers_authority;
      });
870
   }
871
} FC_CAPTURE_AND_RETHROW() } 
872

873
void chain_controller::add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts ) {
874
   for (const auto& i : checkpts)
N
Nathan Hourt 已提交
875 876 877
      _checkpoints[i.first] = i.second;
}

878
bool chain_controller::before_last_checkpoint()const {
N
Nathan Hourt 已提交
879 880 881
   return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
}

882
const global_property_object& chain_controller::get_global_properties()const {
883
   return _db.get<global_property_object>();
N
Nathan Hourt 已提交
884 885
}

886
const dynamic_global_property_object&chain_controller::get_dynamic_global_properties() const {
887
   return _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
888 889
}

D
Daniel Larimer 已提交
890
time_point chain_controller::head_block_time()const {
N
Nathan Hourt 已提交
891 892 893
   return get_dynamic_global_properties().time;
}

894
uint32_t chain_controller::head_block_num()const {
N
Nathan Hourt 已提交
895 896 897
   return get_dynamic_global_properties().head_block_number;
}

898
block_id_type chain_controller::head_block_id()const {
N
Nathan Hourt 已提交
899 900 901
   return get_dynamic_global_properties().head_block_id;
}

D
Daniel Larimer 已提交
902
account_name chain_controller::head_block_producer() const {
903 904 905
   auto b = _fork_db.fetch_block(head_block_id());
   if( b ) return b->data.producer;

N
Nathan Hourt 已提交
906
   if (auto head_block = fetch_block_by_id(head_block_id()))
907
      return head_block->producer;
N
Nathan Hourt 已提交
908 909 910
   return {};
}

D
Daniel Larimer 已提交
911 912
const producer_object& chain_controller::get_producer(const account_name& owner_name) const 
{ try {
B
Bart Wyatt 已提交
913
   return _db.get<producer_object, by_owner>(owner_name);
D
Daniel Larimer 已提交
914
} FC_CAPTURE_AND_RETHROW( (owner_name) ) }
N
Nathan Hourt 已提交
915

916 917 918 919 920
const permission_object&   chain_controller::get_permission( const permission_level& level )const 
{ try {
   return _db.get<permission_object, by_owner>( boost::make_tuple(level.actor,level.permission) );
} FC_CAPTURE_AND_RETHROW( (level) ) }

921
uint32_t chain_controller::last_irreversible_block_num() const {
N
Nathan Hourt 已提交
922
   return get_dynamic_global_properties().last_irreversible_block_num;
N
Nathan Hourt 已提交
923 924
}

D
Daniel Larimer 已提交
925
void chain_controller::_initialize_indexes() {
926 927
   _db.add_index<account_index>();
   _db.add_index<permission_index>();
928
   _db.add_index<permission_link_index>();
929 930
   _db.add_index<action_permission_index>();
   _db.add_index<key_value_index>();
M
Matias Romeo 已提交
931
   _db.add_index<keystr_value_index>();
932
   _db.add_index<key128x128_value_index>();
933
   _db.add_index<key64x64x64_value_index>();
934 935 936 937 938

   _db.add_index<global_property_multi_index>();
   _db.add_index<dynamic_global_property_multi_index>();
   _db.add_index<block_summary_multi_index>();
   _db.add_index<transaction_multi_index>();
939
   _db.add_index<generated_transaction_multi_index>();
940
   _db.add_index<producer_multi_index>();
941
   _db.add_index<scope_serial_multi_index>();
N
Nathan Hourt 已提交
942 943
}

D
Daniel Larimer 已提交
944
void chain_controller::_initialize_chain(contracts::chain_initializer& starter)
N
Nathan Hourt 已提交
945
{ try {
946
   if (!_db.find<global_property_object>()) {
N
Nathan Hourt 已提交
947 948
      _db.with_write_lock([this, &starter] {
         auto initial_timestamp = starter.get_chain_start_time();
D
Daniel Larimer 已提交
949 950 951
         FC_ASSERT(initial_timestamp != time_point(), "Must initialize genesis timestamp." );
         FC_ASSERT( block_timestamp_type(initial_timestamp) == initial_timestamp,
                    "Genesis timestamp must be divisible by config::block_interval_ms" );
N
Nathan Hourt 已提交
952

953
         // Create global properties
N
Nathan Hourt 已提交
954 955 956
         _db.create<global_property_object>([&starter](global_property_object& p) {
            p.configuration = starter.get_chain_start_configuration();
            p.active_producers = starter.get_chain_start_producers();
957
         });
958

959
         _db.create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
N
Nathan Hourt 已提交
960
            p.time = initial_timestamp;
961 962
            p.recent_slots_filled = uint64_t(-1);
         });
N
Nathan Hourt 已提交
963

N
Nathan Hourt 已提交
964
         // Initialize block summary index
965 966
         for (int i = 0; i < 0x10000; i++)
            _db.create<block_summary_object>([&](block_summary_object&) {});
N
Nathan Hourt 已提交
967

D
Daniel Larimer 已提交
968 969
         auto acts = starter.prepare_database(*this, _db);

D
Daniel Larimer 已提交
970
         transaction genesis_setup_transaction;
971
         genesis_setup_transaction.write_scope = { config::eosio_all_scope };
D
Daniel Larimer 已提交
972 973 974 975 976
         genesis_setup_transaction.actions = move(acts);

         ilog( "applying genesis transaction" );
         with_skip_flags(skip_scope_check | skip_transaction_signatures | skip_authority_check | received_block, 
         [&](){ 
977
            _apply_transaction( genesis_setup_transaction, 0, 0 );
978
         });
979

980 981
      });
   }
N
Nathan Hourt 已提交
982 983
} FC_CAPTURE_AND_RETHROW() }

N
Nathan Hourt 已提交
984

985
void chain_controller::replay() {
986
   ilog("Replaying blockchain");
N
Nathan Hourt 已提交
987
   auto start = fc::time_point::now();
K
Kevin Heifner 已提交
988

K
Kevin Heifner 已提交
989
   auto on_exit = fc::make_scoped_exit([&_currently_replaying_blocks = _currently_replaying_blocks](){
K
Kevin Heifner 已提交
990 991 992 993
      _currently_replaying_blocks = false;
   });
   _currently_replaying_blocks = true;

994 995 996
   auto last_block = _block_log.read_head();
   if (!last_block) {
      elog("No blocks in block log; skipping replay");
N
Nathan Hourt 已提交
997 998 999 1000 1001
      return;
   }

   const auto last_block_num = last_block->block_num();

1002
   ilog("Replaying ${n} blocks...", ("n", last_block_num) );
1003 1004 1005 1006 1007
   for (uint32_t i = 1; i <= last_block_num; ++i) {
      if (i % 5000 == 0)
         std::cerr << "   " << double(i*100)/last_block_num << "%   "<<i << " of " <<last_block_num<<"   \n";
      fc::optional<signed_block> block = _block_log.read_block_by_num(i);
      FC_ASSERT(block, "Could not find block #${n} in block_log!", ("n", i));
D
Daniel Larimer 已提交
1008
      _apply_block(*block, skip_producer_signature |
N
Nathan Hourt 已提交
1009 1010 1011 1012
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_producer_schedule_check |
1013 1014
                          skip_authority_check |
                          received_block);
N
Nathan Hourt 已提交
1015 1016
   }
   auto end = fc::time_point::now();
1017 1018
   ilog("Done replaying ${n} blocks, elapsed time: ${t} sec",
        ("n", head_block_num())("t",double((end-start).count())/1000000.0));
N
Nathan Hourt 已提交
1019

1020
   _db.set_revision(head_block_num());
1021
}
N
Nathan Hourt 已提交
1022

D
Daniel Larimer 已提交
1023
void chain_controller::_spinup_db() {
1024 1025 1026 1027 1028
   // Rewind the database to the last irreversible block
   _db.with_write_lock([&] {
      _db.undo_all();
      FC_ASSERT(_db.revision() == head_block_num(), "Chainbase revision does not match head block num",
                ("rev", _db.revision())("head_block", head_block_num()));
1029

1030 1031
   });
}
N
Nathan Hourt 已提交
1032

D
Daniel Larimer 已提交
1033
void chain_controller::_spinup_fork_db()
N
Nathan Hourt 已提交
1034
{
1035 1036 1037 1038 1039 1040 1041 1042
   fc::optional<signed_block> last_block = _block_log.read_head();
   if(last_block.valid()) {
      _fork_db.start_block(*last_block);
      if (last_block->id() != head_block_id()) {
           FC_ASSERT(head_block_num() == 0, "last block ID does not match current chain state",
                     ("last_block->id", last_block->id())("head_block_num",head_block_num()));
      }
   }
N
Nathan Hourt 已提交
1043 1044
}

D
Daniel Larimer 已提交
1045
/*
1046 1047
ProducerRound chain_controller::calculate_next_round(const signed_block& next_block) {
   auto schedule = _admin->get_next_round(_db);
N
Nathan Hourt 已提交
1048 1049 1050 1051
   auto changes = get_global_properties().active_producers - schedule;
   EOS_ASSERT(boost::range::equal(next_block.producer_changes, changes), block_validate_exception,
              "Unexpected round changes in new block header",
              ("expected changes", changes)("block changes", next_block.producer_changes));
P
Pravin 已提交
1052 1053 1054
   
   fc::time_point tp = (fc::time_point)next_block.timestamp;
   utilities::rand::random rng(tp.sec_since_epoch());
1055 1056
   rng.shuffle(schedule);
   return schedule;
D
Daniel Larimer 已提交
1057
}*/
1058

1059
void chain_controller::update_global_dynamic_data(const signed_block& b) {
1060
   const dynamic_global_property_object& _dgp = _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
1061

1062 1063 1064
   const auto& bmroot = _dgp.block_merkle_root.get_root();
   FC_ASSERT( bmroot == b.block_mroot, "block merkle root does not match expected value" );

P
Pravin 已提交
1065
   uint32_t missed_blocks = head_block_num() == 0? 1 : get_slot_at_time((fc::time_point)b.timestamp);
1066
   assert(missed_blocks != 0);
N
Nathan Hourt 已提交
1067
   missed_blocks--;
N
Nathan Hourt 已提交
1068

1069 1070
//   if (missed_blocks)
//      wlog("Blockchain continuing after gap of ${b} missed blocks", ("b", missed_blocks));
N
Nathan Hourt 已提交
1071

N
Nathan Hourt 已提交
1072
   for(uint32_t i = 0; i < missed_blocks; ++i) {
N
Nathan Hourt 已提交
1073
      const auto& producer_missed = get_producer(get_scheduled_producer(i+1));
1074
      if(producer_missed.owner != b.producer) {
N
Nathan Hourt 已提交
1075 1076 1077 1078 1079 1080
         /*
         const auto& producer_account = producer_missed.producer_account(*this);
         if( (fc::time_point::now() - b.timestamp) < fc::seconds(30) )
            wlog( "Producer ${name} missed block ${n} around ${t}", ("name",producer_account.name)("n",b.block_num())("t",b.timestamp) );
            */

1081
         _db.modify( producer_missed, [&]( producer_object& w ) {
N
Nathan Hourt 已提交
1082 1083 1084 1085 1086 1087
           w.total_missed++;
         });
      }
   }

   // dynamic global properties updating
1088
   _db.modify( _dgp, [&]( dynamic_global_property_object& dgp ){
N
Nathan Hourt 已提交
1089 1090 1091
      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
1092
      dgp.current_producer = b.producer;
N
Nathan Hourt 已提交
1093 1094 1095 1096 1097 1098 1099
      dgp.current_absolute_slot += missed_blocks+1;

      // If we've missed more blocks than the bitmap stores, skip calculations and simply reset the bitmap
      if (missed_blocks < sizeof(dgp.recent_slots_filled) * 8) {
         dgp.recent_slots_filled <<= 1;
         dgp.recent_slots_filled += 1;
         dgp.recent_slots_filled <<= missed_blocks;
1100
      } else {
N
Nathan Hourt 已提交
1101
         dgp.recent_slots_filled = 0;
1102 1103
      }
      dgp.block_merkle_root.append( head_block_id() ); 
N
Nathan Hourt 已提交
1104 1105 1106 1107 1108
   });

   _fork_db.set_max_size( _dgp.head_block_number - _dgp.last_irreversible_block_num + 1 );
}

1109
void chain_controller::update_signing_producer(const producer_object& signing_producer, const signed_block& new_block)
N
Nathan Hourt 已提交
1110 1111
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
P
Pravin 已提交
1112
   uint64_t new_block_aslot = dpo.current_absolute_slot + get_slot_at_time( (fc::time_point)new_block.timestamp );
N
Nathan Hourt 已提交
1113

1114
   _db.modify( signing_producer, [&]( producer_object& _wit )
N
Nathan Hourt 已提交
1115 1116 1117 1118 1119 1120
   {
      _wit.last_aslot = new_block_aslot;
      _wit.last_confirmed_block_num = new_block.block_num();
   } );
}

1121
void chain_controller::update_last_irreversible_block()
N
Nathan Hourt 已提交
1122 1123 1124 1125
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

N
Nathan Hourt 已提交
1126
   vector<const producer_object*> producer_objs;
1127
   producer_objs.reserve(gpo.active_producers.producers.size());
D
Daniel Larimer 已提交
1128

1129
   std::transform(gpo.active_producers.producers.begin(), gpo.active_producers.producers.end(), std::back_inserter(producer_objs),
D
Daniel Larimer 已提交
1130
                  [this](const producer_key& pk) { return &get_producer(pk.producer_name); });
N
Nathan Hourt 已提交
1131

D
Daniel Larimer 已提交
1132
   static_assert(config::irreversible_threshold_percent > 0, "irreversible threshold must be nonzero");
N
Nathan Hourt 已提交
1133

D
Daniel Larimer 已提交
1134
   size_t offset = EOS_PERCENT(producer_objs.size(), config::percent_100- config::irreversible_threshold_percent);
1135 1136
   std::nth_element(producer_objs.begin(), producer_objs.begin() + offset, producer_objs.end(),
      [](const producer_object* a, const producer_object* b) {
N
Nathan Hourt 已提交
1137
         return a->last_confirmed_block_num < b->last_confirmed_block_num;
1138
      });
N
Nathan Hourt 已提交
1139

N
Nathan Hourt 已提交
1140
   uint32_t new_last_irreversible_block_num = producer_objs[offset]->last_confirmed_block_num;
N
Nathan Hourt 已提交
1141

1142
   if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) {
1143
      _db.modify(dpo, [&](dynamic_global_property_object& _dpo) {
N
Nathan Hourt 已提交
1144
         _dpo.last_irreversible_block_num = new_last_irreversible_block_num;
1145
      });
N
Nathan Hourt 已提交
1146
   }
1147 1148

   // Write newly irreversible blocks to disk. First, get the number of the last block on disk...
1149
   auto old_last_irreversible_block = _block_log.head();
1150 1151 1152 1153
   int last_block_on_disk = 0;
   // If this is null, there are no blocks on disk, so the zero is correct
   if (old_last_irreversible_block)
      last_block_on_disk = old_last_irreversible_block->block_num();
1154

1155
   if (last_block_on_disk < new_last_irreversible_block_num) {
1156 1157 1158 1159 1160
      for (auto block_to_write = last_block_on_disk + 1;
           block_to_write <= new_last_irreversible_block_num;
           ++block_to_write) {
         auto block = fetch_block_by_number(block_to_write);
         assert(block);
1161
         _block_log.append(*block);
K
Kevin Heifner 已提交
1162
         applied_irreversible_block(*block);
1163
      }
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
   }

   if( new_last_irreversible_block_num > last_block_on_disk ) {
      /// TODO: use upper / lower bound to find
      optional<producer_schedule_type> new_producer_schedule;
      for( const auto& item : gpo.pending_active_producers ) {
         if( item.first < new_last_irreversible_block_num ) {
            new_producer_schedule = item.second;
         }
      }
      if( new_producer_schedule ) {
         _db.modify( gpo, [&]( auto& props ){
             /// TODO: use upper / lower bound to remove range
              while( gpo.pending_active_producers.size() ) {
                 if( gpo.pending_active_producers.front().first < new_last_irreversible_block_num ) {
                   props.pending_active_producers.erase(props.pending_active_producers.begin());
                 }
              }
1182
              props.active_producers = *new_producer_schedule;
1183 1184 1185 1186
         });
      }
   }

N
Nathan Hourt 已提交
1187 1188 1189

   // Trim fork_database and undo histories
   _fork_db.set_max_size(head_block_num() - new_last_irreversible_block_num + 1);
1190
   _db.commit(new_last_irreversible_block_num);
N
Nathan Hourt 已提交
1191 1192
}

1193
void chain_controller::clear_expired_transactions()
N
Nathan Hourt 已提交
1194 1195
{ try {
   //Look for expired transactions in the deduplication list, and remove them.
D
Daniel Larimer 已提交
1196
   //transactions must have expired by at least two forking windows in order to be removed.
D
Daniel Larimer 已提交
1197
   /*
1198
   auto& transaction_idx = _db.get_mutable_index<transaction_multi_index>();
N
Nathan Hourt 已提交
1199
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
D
Daniel Larimer 已提交
1200
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->expiration) )
N
Nathan Hourt 已提交
1201
      transaction_idx.remove(*dedupe_index.rbegin());
1202 1203

   //Look for expired transactions in the pending generated list, and remove them.
D
Daniel Larimer 已提交
1204
   //transactions must have expired by at least two forking windows in order to be removed.
1205 1206 1207 1208
   auto& generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
   const auto& generated_index = generated_transaction_idx.indices().get<generated_transaction_object::by_expiration>();
   while( (!generated_index.empty()) && (head_block_time() > generated_index.rbegin()->trx.expiration) )
      generated_transaction_idx.remove(*generated_index.rbegin());
D
Daniel Larimer 已提交
1209
      */
N
Nathan Hourt 已提交
1210 1211 1212 1213
} FC_CAPTURE_AND_RETHROW() }

using boost::container::flat_set;

D
Daniel Larimer 已提交
1214
account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const
N
Nathan Hourt 已提交
1215 1216
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1217
   uint64_t current_aslot = dpo.current_absolute_slot + slot_num;
1218
   const auto& gpo = _db.get<global_property_object>();
D
Daniel Larimer 已提交
1219 1220 1221 1222
   //auto number_of_active_producers = gpo.active_producers.size();
   auto index = current_aslot % (config::blocks_per_round); //TODO configure number of repetitions by producer
   index /= config::producer_repititions;

1223
   return gpo.active_producers.producers[index].producer_name;
N
Nathan Hourt 已提交
1224 1225
}

D
Daniel Larimer 已提交
1226
block_timestamp_type chain_controller::get_slot_time(uint32_t slot_num)const
N
Nathan Hourt 已提交
1227
{
P
Pravin 已提交
1228
   if( slot_num == 0)
D
Daniel Larimer 已提交
1229
      return block_timestamp_type();
N
Nathan Hourt 已提交
1230 1231 1232 1233 1234 1235

   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

   if( head_block_num() == 0 )
   {
      // n.b. first block is at genesis_time plus one block interval
P
Pravin 已提交
1236 1237 1238
      auto genesis_time = block_timestamp_type(dpo.time);
      genesis_time.slot += slot_num;
      return (fc::time_point)genesis_time;
N
Nathan Hourt 已提交
1239 1240
   }

D
Daniel Larimer 已提交
1241
   auto head_block_abs_slot = block_timestamp_type(head_block_time());
P
Pravin 已提交
1242
   head_block_abs_slot.slot += slot_num;
D
Daniel Larimer 已提交
1243
   return head_block_abs_slot;
N
Nathan Hourt 已提交
1244 1245
}

D
Daniel Larimer 已提交
1246
uint32_t chain_controller::get_slot_at_time( block_timestamp_type when )const
N
Nathan Hourt 已提交
1247
{
D
Daniel Larimer 已提交
1248
   auto first_slot_time = get_slot_time(1);
N
Nathan Hourt 已提交
1249 1250
   if( when < first_slot_time )
      return 0;
D
Daniel Larimer 已提交
1251
   return block_timestamp_type(when).slot - first_slot_time.slot + 1;
N
Nathan Hourt 已提交
1252 1253
}

1254
uint32_t chain_controller::producer_participation_rate()const
N
Nathan Hourt 已提交
1255 1256
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
D
Daniel Larimer 已提交
1257
   return uint64_t(config::percent_100) * __builtin_popcountll(dpo.recent_slots_filled) / 64;
N
Nathan Hourt 已提交
1258 1259
}

D
Daniel Larimer 已提交
1260 1261
void chain_controller::_set_apply_handler( account_name contract, scope_name scope, action_name action, apply_handler v ) {
   _apply_handlers[contract][make_pair(scope,action)] = v;
1262
}
N
Nathan Hourt 已提交
1263

1264
transaction_trace chain_controller::_apply_transaction( const transaction& trx, uint32_t region_id, uint32_t cycle_index ) {
1265
   transaction_trace result(trx.id());
B
Bart Wyatt 已提交
1266

D
Daniel Larimer 已提交
1267
   for( const auto& act : trx.actions ) {
B
Bart Wyatt 已提交
1268
      apply_context context( *this, _db, trx, act,  act.scope  );
D
Daniel Larimer 已提交
1269
      context.exec();
1270
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
B
Bart Wyatt 已提交
1271
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
D
Daniel Larimer 已提交
1272
   }
B
Bart Wyatt 已提交
1273

1274 1275 1276 1277 1278
   for (auto& at: result.action_traces) {
      at.region_id = region_id;
      at.cycle_index = cycle_index;
   }

B
Bart Wyatt 已提交
1279
   return result;
D
Daniel Larimer 已提交
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
}

const apply_handler* chain_controller::find_apply_handler( account_name receiver, account_name scope, action_name act ) const
{
   auto native_handler_scope = _apply_handlers.find( receiver );
   if( native_handler_scope != _apply_handlers.end() ) {
      auto handler = native_handler_scope->second.find( make_pair( scope, act ) );
      if( handler != native_handler_scope->second.end() ) 
         return &handler->second;
   }
   return nullptr;
}

D
Daniel Larimer 已提交
1293
} } /// eosio::chain