chain_controller.cpp 47.4 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>
N
Nathan Hourt 已提交
19

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

22
#include <eos/utilities/rand.hpp>
23

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

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

#include <fstream>
#include <functional>
#include <iostream>
36
#include <chrono>
N
Nathan Hourt 已提交
37

P
Pravin 已提交
38
namespace eosio { namespace chain {
D
Daniel Larimer 已提交
39

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

D
Daniel Larimer 已提交
44 45 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
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();
}

73
bool chain_controller::is_known_block(const block_id_type& id)const
N
Nathan Hourt 已提交
74
{
75
   return _fork_db.is_known_block(id) || _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
76 77 78 79 80 81
}
/**
 * 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.
 */
82
bool chain_controller::is_known_transaction(const transaction_id_type& id)const
N
Nathan Hourt 已提交
83
{
84
   const auto& trx_idx = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
85 86 87
   return trx_idx.find( id ) != trx_idx.end();
}

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

93 94 95
   FC_THROW_EXCEPTION(unknown_block_exception, "Could not find block");
} FC_CAPTURE_AND_RETHROW((block_num)) }

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

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

N
Nathan Hourt 已提交
108
   // Not in _block_log, so it must be since the last irreversible block. Grab it from _fork_db instead
109 110 111 112 113 114 115 116
   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 已提交
117 118 119
   return optional<signed_block>();
}

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

130
std::vector<block_id_type> chain_controller::get_block_ids_on_fork(block_id_type head_of_fork) const
N
Nathan Hourt 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
{
  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;
}

148

N
Nathan Hourt 已提交
149 150 151 152 153 154
/**
 * 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 已提交
155
void chain_controller::push_block(const signed_block& new_block, uint32_t skip)
D
Daniel Larimer 已提交
156
{ try {
D
Daniel Larimer 已提交
157
   with_skip_flags( skip, [&](){ 
D
Daniel Larimer 已提交
158
      return without_pending_transactions( [&]() {
159
         return _db.with_write_lock( [&]() {
160 161
            return _push_block(new_block);
         } );
N
Nathan Hourt 已提交
162 163
      });
   });
164
} FC_CAPTURE_AND_RETHROW((new_block)) }
N
Nathan Hourt 已提交
165

166
bool chain_controller::_push_block(const signed_block& new_block)
N
Nathan Hourt 已提交
167
{ try {
N
Nathan Hourt 已提交
168
   uint32_t skip = _skip_flags;
169
   if (!(skip&skip_fork_db)) {
N
Nathan Hourt 已提交
170
      /// TODO: if the block is greater than the head block and before the next maintenance interval
N
Nathan Hourt 已提交
171 172 173 174
      // 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.
175
      if (new_head->data.previous != head_block_id()) {
N
Nathan Hourt 已提交
176 177
         //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
178 179
         if (new_head->data.block_num() > head_block_num()) {
            wlog("Switching to fork: ${id}", ("id",new_head->data.id()));
N
Nathan Hourt 已提交
180 181 182
            auto branches = _fork_db.fetch_branch_from(new_head->data.id(), head_block_id());

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

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

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

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

   try {
225
      auto session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
226
      _apply_block(new_block, skip);
N
Nathan Hourt 已提交
227 228 229 230 231 232 233 234
      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;
235
} FC_CAPTURE_AND_RETHROW((new_block)) }
N
Nathan Hourt 已提交
236 237 238 239 240 241 242 243 244 245

/**
 * 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.
 */
B
Bart Wyatt 已提交
246
transaction_result chain_controller::push_transaction(const signed_transaction& trx, uint32_t skip)
N
Nathan Hourt 已提交
247
{ try {
248 249 250
   return with_skip_flags(skip, [&]() {
      return _db.with_write_lock([&]() {
         return _push_transaction(trx);
D
Daniel Larimer 已提交
251
      });
N
Nathan Hourt 已提交
252 253
   });
} FC_CAPTURE_AND_RETHROW((trx)) }
N
Nathan Hourt 已提交
254

B
Bart Wyatt 已提交
255
transaction_result chain_controller::_push_transaction(const signed_transaction& trx) {
256 257
   // 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 已提交
258
   if( !_pending_block ) {
D
Daniel Larimer 已提交
259
      _start_pending_block();
D
Daniel Larimer 已提交
260
   }
261

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

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

   auto tid = trx.id();
N
Nathan Hourt 已提交
270

271 272
   auto shardnum = _pending_cycle.schedule( trx );
   if( shardnum == -1 ) { /// schedule conflict start new cycle
B
Bart Wyatt 已提交
273
      _finalize_cycle();
274
      _start_cycle();
B
Bart Wyatt 已提交
275
      shardnum = _pending_cycle.schedule( trx );
276 277 278 279 280 281 282
   }

   auto& bcycle = _pending_block->cycles_summary.back();
   if( shardnum >= bcycle.size() ) {
      bcycle.resize( bcycle.size()+1 );
   }

B
Bart Wyatt 已提交
283 284 285 286 287 288 289 290
   bcycle.at(shardnum).emplace_back( tid );


   if (shardnum >= _pending_shard_results.size()) {
      _pending_shard_results.resize(_pending_shard_results.size() + 1);
   }
   _pending_shard_results.at(shardnum).append(result);

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

N
Nathan Hourt 已提交
294 295 296 297
   // The transaction applied successfully. Merge its changes into the pending block session.
   temp_session.squash();

   // notify anyone listening to pending transactions
B
Bart Wyatt 已提交
298 299 300
   on_pending_transaction(trx);

   return result;
N
Nathan Hourt 已提交
301 302
}

303 304 305 306 307 308 309 310

/**
 *  Wraps up all work for current shards, starts a new cycle, and
 *  executes any pending transactions 
 */
void chain_controller::_start_cycle() {
   _pending_block->cycles_summary.resize( _pending_block->cycles_summary.size() + 1 );
   _pending_cycle = pending_cycle_state();
B
Bart Wyatt 已提交
311
   _pending_shard_results.clear();
312 313 314 315

   /// TODO: check for deferred transactions and schedule them
} // _start_cycle

B
Bart Wyatt 已提交
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
void chain_controller::_finalize_cycle()
{
   for (const auto& res: _pending_shard_results) {
      _apply_shard_results(res);
   }
}

void chain_controller::_apply_shard_results( const shard_result& res )
{
   for (const auto& tr: res.transaction_results) {
      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_results) {
341 342 343 344 345 346 347 348 349 350 351
         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;
         }
B
Bart Wyatt 已提交
352 353 354 355
      }
   }
}

356
signed_block chain_controller::generate_block(
D
Daniel Larimer 已提交
357 358 359
   block_timestamp_type when,
   account_name producer,
   const private_key_type& block_signing_private_key,
N
Nathan Hourt 已提交
360 361 362
   uint32_t skip /* = 0 */
   )
{ try {
N
Nathan Hourt 已提交
363
   return with_skip_flags( skip, [&](){
D
Daniel Larimer 已提交
364
      return _db.with_write_lock( [&](){
D
Daniel Larimer 已提交
365
         return _generate_block( when, producer, block_signing_private_key );
D
Daniel Larimer 已提交
366
      });
N
Nathan Hourt 已提交
367
   });
D
Daniel Larimer 已提交
368
} FC_CAPTURE_AND_RETHROW( (when) ) }
N
Nathan Hourt 已提交
369

D
Daniel Larimer 已提交
370 371 372 373 374
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 已提交
375 376
   uint32_t slot_num = get_slot_at_time( when );
   FC_ASSERT( slot_num > 0 );
D
Daniel Larimer 已提交
377
   account_name scheduled_producer = get_scheduled_producer( slot_num );
N
Nathan Hourt 已提交
378
   FC_ASSERT( scheduled_producer == producer );
N
Nathan Hourt 已提交
379

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

D
Daniel Larimer 已提交
382
   if( !_pending_block ) {
D
Daniel Larimer 已提交
383
      _start_pending_block();
384 385
   }

386 387
   _finalize_cycle();

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

391 392 393 394 395
   _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();
396

397 398 399 400
   if( is_start_of_round( _pending_block->block_num() ) ) {
      auto latest_producer_schedule = _calculate_producer_schedule();
      if( latest_producer_schedule != _head_producer_schedule() )
         _pending_block->new_producers = latest_producer_schedule;
401 402
   }

N
Nathan Hourt 已提交
403
   if( !(skip & skip_producer_signature) )
D
Daniel Larimer 已提交
404
      _pending_block->sign( block_signing_key );
N
Nathan Hourt 已提交
405

D
Daniel Larimer 已提交
406 407
   _finalize_block( *_pending_block );

408 409
   _pending_block_session->push();

D
Daniel Larimer 已提交
410 411
   auto result = move( *_pending_block );

412 413 414
   _pending_block.reset();
   _pending_block_session.reset();

D
Daniel Larimer 已提交
415
   if (!(skip&skip_fork_db)) {
D
Daniel Larimer 已提交
416
      _fork_db.push_block(result);
N
Nathan Hourt 已提交
417
   }
D
Daniel Larimer 已提交
418
   return result;
N
Nathan Hourt 已提交
419

N
Nathan Hourt 已提交
420
} FC_CAPTURE_AND_RETHROW( (producer) ) }
N
Nathan Hourt 已提交
421

D
Daniel Larimer 已提交
422 423 424 425
void chain_controller::_start_pending_block() {
   FC_ASSERT( !_pending_block );
   _pending_block         = signed_block();
   _pending_block_session = _db.start_undo_session(true);
426
   _start_cycle();
D
Daniel Larimer 已提交
427 428
}

N
Nathan Hourt 已提交
429
/**
N
Nathan Hourt 已提交
430
 * Removes the most recent block from the database and undoes any changes it made.
N
Nathan Hourt 已提交
431
 */
432
void chain_controller::pop_block()
N
Nathan Hourt 已提交
433
{ try {
D
Daniel Larimer 已提交
434
   _pending_block_session.reset();
N
Nathan Hourt 已提交
435 436 437 438 439
   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();
440
   _db.undo();
N
Nathan Hourt 已提交
441 442
} FC_CAPTURE_AND_RETHROW() }

443
void chain_controller::clear_pending()
N
Nathan Hourt 已提交
444
{ try {
D
Daniel Larimer 已提交
445
   _pending_block.reset();
D
Daniel Larimer 已提交
446
   _pending_block_session.reset();
N
Nathan Hourt 已提交
447 448 449 450
} FC_CAPTURE_AND_RETHROW() }

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

D
Daniel Larimer 已提交
451
void chain_controller::_apply_block(const signed_block& next_block, uint32_t skip)
N
Nathan Hourt 已提交
452 453
{
   auto block_num = next_block.block_num();
454 455 456 457 458
   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 已提交
459

460
      if (_checkpoints.rbegin()->first >= block_num)
N
Nathan Hourt 已提交
461 462
         skip = ~0;// WE CAN SKIP ALMOST EVERYTHING
   }
N
Nathan Hourt 已提交
463 464 465

   with_applying_block([&] {
      with_skip_flags(skip, [&] {
D
Daniel Larimer 已提交
466
         __apply_block(next_block);
N
Nathan Hourt 已提交
467 468
      });
   });
N
Nathan Hourt 已提交
469 470
}

471

D
Daniel Larimer 已提交
472
void chain_controller::__apply_block(const signed_block& next_block)
N
Nathan Hourt 已提交
473
{ try {
N
Nathan Hourt 已提交
474
   uint32_t skip = _skip_flags;
N
Nathan Hourt 已提交
475

D
Daniel Larimer 已提交
476 477 478
   /*
   FC_ASSERT((skip & skip_merkle_check) 
             || next_block.transaction_merkle_root == next_block.calculate_merkle_root(),
479 480
             "", ("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 已提交
481
             */
N
Nathan Hourt 已提交
482 483

   const producer_object& signing_producer = validate_block_header(skip, next_block);
484 485 486 487 488 489 490 491


   /// 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;
   }
N
Nathan Hourt 已提交
492
   
493
   for (const auto& cycle : next_block.cycles_summary) {
B
Bart Wyatt 已提交
494 495
      vector<shard_result> results;
      results.reserve(cycle.size());
496
      for (const auto& shard: cycle) {
B
Bart Wyatt 已提交
497 498 499
         results.emplace_back();
         auto& result = results.back();

500 501 502 503
         for (const auto& receipt : shard) {
            if( receipt.status == transaction_receipt::executed ) {
               auto itr = trx_index.find(receipt.id);
               if( itr != trx_index.end() ) {
504
                  result.append(_apply_transaction( *itr->second ));
B
Bart Wyatt 已提交
505
               }
506 507 508 509 510 511
               else 
               {
                  FC_ASSERT( !"deferred transactions not yet supported" );
               }
            }
            // validate_referenced_accounts(trx);
512 513
            // Check authorization, and allow irrelevant signatures.
            // If the block producer let it slide, we'll roll with it.
514 515 516
            // check_transaction_authorization(trx, true);
         } /// for each transaction id
      } /// for each shard
B
Bart Wyatt 已提交
517 518 519 520

      for (const auto res: results) {
         _apply_shard_results(res);
      }
521
   } /// for each cycle
N
Nathan Hourt 已提交
522

523
   _finalize_block( next_block );
N
Nathan Hourt 已提交
524 525
} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) )  }

D
Daniel Larimer 已提交
526 527 528 529
/**
 *  After applying all transactions successfully we can update
 *  the current block time, block number, producer stats, etc
 */
530
void chain_controller::_finalize_block( const signed_block& b ) { try {
D
Daniel Larimer 已提交
531 532 533 534 535 536 537 538 539 540
   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();

541
   applied_block( b ); //emit
D
Daniel Larimer 已提交
542 543
   if (_currently_replaying_blocks)
     applied_irreversible_block(b);
544 545

} FC_CAPTURE_AND_RETHROW( (b) ) }
D
Daniel Larimer 已提交
546

D
Daniel Larimer 已提交
547
flat_set<public_key_type> chain_controller::get_required_keys(const signed_transaction& trx, 
B
Bart Wyatt 已提交
548
                                                              const flat_set<public_key_type>& candidate_keys)const 
D
Daniel Larimer 已提交
549
{
550 551 552
   auto checker = make_auth_checker( [&](auto p){ return get_permission(p).auth; }, 
                                     get_global_properties().configuration.max_authority_depth,
                                     candidate_keys);
553

D
Daniel Larimer 已提交
554 555 556 557
   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 已提交
558
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
559
                       ("auth", declared_auth));
560 561 562 563 564 565 566
         }
      }
   }

   return checker.used_keys();
}

567 568 569 570
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 已提交
571
{
572 573
   auto checker = make_auth_checker( [&](auto p){ return get_permission(p).auth; }, 
                                     get_global_properties().configuration.max_authority_depth,
574 575
                                     provided_keys, provided_accounts );

N
Nathan Hourt 已提交
576

577
   for( const auto& act : trx.actions ) {
578
      for( const auto& declared_auth : act.authorization ) {
D
Daniel Larimer 已提交
579

580 581
         const auto& min_permission = lookup_minimum_permission(declared_auth.actor, 
                                                                act.scope, act.name);
D
Daniel Larimer 已提交
582

N
Nathan Hourt 已提交
583 584
         if ((_skip_flags & skip_authority_check) == false) {
            const auto& index = _db.get_index<permission_index>().indices();
585 586
            EOS_ASSERT(get_permission(declared_auth).satisfies(min_permission, index), 
                       tx_irrelevant_auth,
D
Daniel Larimer 已提交
587
                       "action declares irrelevant authority '${auth}'; minimum authority is ${min}",
D
Daniel Larimer 已提交
588
                       ("auth", declared_auth)("min", min_permission.name));
N
Nathan Hourt 已提交
589 590
         }
         if ((_skip_flags & skip_transaction_signatures) == false) {
D
Daniel Larimer 已提交
591
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
592
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
593
                       ("auth", declared_auth));
N
Nathan Hourt 已提交
594 595
         }
      }
596
   }
N
Nathan Hourt 已提交
597

598
   if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false)
599
      EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
600 601
                 "transaction bears irrelevant signatures from these keys: ${keys}", 
                 ("keys", checker.unused_keys()));
N
Nathan Hourt 已提交
602 603
}

604 605 606 607 608 609
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 已提交
610
void chain_controller::validate_scope( const transaction& trx )const {
611 612 613 614 615 616 617 618
   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 已提交
619 620 621 622

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

D
Daniel Larimer 已提交
627 628 629
const permission_object& chain_controller::lookup_minimum_permission(account_name authorizer_account,
                                                                    account_name scope,
                                                                    action_name act_name) const {
N
Nathan Hourt 已提交
630
   try {
D
Daniel Larimer 已提交
631 632 633
      // 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);
634 635 636
      // If no specific link found, check for a contract-wide default
      if (link == nullptr) {
         get<2>(key) = "";
D
Daniel Larimer 已提交
637
         link = _db.find<permission_link_object, by_action_name>(key);
638 639 640
      }

      // If no specific or default link found, use active permission
D
Daniel Larimer 已提交
641
      auto permission_key = boost::make_tuple<account_name, permission_name>(authorizer_account, config::active_name );
642
      if (link != nullptr)
D
Daniel Larimer 已提交
643 644 645
         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 已提交
646 647
}

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

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

D
Daniel Larimer 已提交
655
void chain_controller::record_transaction(const signed_transaction& trx) {
656 657
   //Insert transaction into unique transactions database.
    _db.create<transaction_object>([&](transaction_object& transaction) {
D
Daniel Larimer 已提交
658 659
        transaction.trx_id = trx.id(); 
        transaction.expiration = trx.expiration;
660 661 662 663
    });
}


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

D
Daniel Larimer 已提交
667
   const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.ref_block_num);
668 669

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

D
Daniel Larimer 已提交
675 676
void chain_controller::validate_referenced_accounts( const transaction& trx )const 
{ try { 
D
Daniel Larimer 已提交
677
   for( const auto& scope : trx.read_scope )
678
      require_scope(scope);
D
Daniel Larimer 已提交
679
   for( const auto& scope : trx.write_scope )
680
      require_scope(scope);
D
Daniel Larimer 已提交
681

D
Daniel Larimer 已提交
682 683
   for( const auto& act : trx.actions ) {
      require_account(act.scope);
D
Daniel Larimer 已提交
684
      for (const auto& auth : act.authorization )
D
Daniel Larimer 已提交
685
         require_account(auth.actor);
686
   }
D
Daniel Larimer 已提交
687
} FC_CAPTURE_AND_RETHROW() }
D
Daniel Larimer 已提交
688

D
Daniel Larimer 已提交
689
void chain_controller::validate_expiration( const transaction& trx ) const
690
{ try {
D
Daniel Larimer 已提交
691
   fc::time_point now = head_block_time();
D
Daniel Larimer 已提交
692
   const auto& chain_configuration = get_global_properties().configuration;
693

D
Daniel Larimer 已提交
694
   EOS_ASSERT( time_point(trx.expiration) <= now + fc::seconds(chain_configuration.max_transaction_lifetime),
D
Daniel Larimer 已提交
695
              transaction_exception, "transaction expiration is too far in the future",
696
              ("trx.expiration",trx.expiration)("now",now)
D
Daniel Larimer 已提交
697 698
              ("max_til_exp",chain_configuration.max_transaction_lifetime));
   EOS_ASSERT( now <= time_point(trx.expiration), transaction_exception, "transaction is expired",
699 700
              ("now",now)("trx.exp",trx.expiration));
} FC_CAPTURE_AND_RETHROW((trx)) }
701

702

703 704
void chain_controller::require_scope( const scope_name& scope )const {
   switch( uint64_t(scope) ) {
705 706
      case config::eosio_all_scope:
      case config::eosio_auth_scope:
707 708 709 710 711 712
         return; /// built in scopes
      default:
         require_account(scope);
   }
}

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

718
const producer_object& chain_controller::validate_block_header(uint32_t skip, const signed_block& next_block)const {
719 720
   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 已提交
721
   EOS_ASSERT(head_block_time() < (fc::time_point)next_block.timestamp, block_validate_exception, "",
722
              ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()));
D
Daniel Larimer 已提交
723 724
   if (next_block.block_num() % config::blocks_per_round != 0) {
      EOS_ASSERT(!next_block.new_producers, block_validate_exception,
725
                 "Producer changes may only occur at the end of a round.");
N
Nathan Hourt 已提交
726
   }
D
Daniel Larimer 已提交
727 728
   
   const producer_object& producer = get_producer(get_scheduled_producer(get_slot_at_time(next_block.timestamp)));
N
Nathan Hourt 已提交
729

N
Nathan Hourt 已提交
730
   if(!(skip&skip_producer_signature))
731 732 733
      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 已提交
734

735
   if(!(skip&skip_producer_schedule_check)) {
736 737 738
      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 已提交
739 740
   }

741 742 743
   
   FC_ASSERT( next_block.calculate_transaction_merkle_root() == next_block.transaction_mroot, "merkle root does not match" );

N
Nathan Hourt 已提交
744 745 746
   return producer;
}

747
void chain_controller::create_block_summary(const signed_block& next_block) {
748
   auto sid = next_block.block_num() & 0xffff;
749
   _db.modify( _db.get<block_summary_object,by_id>(sid), [&](block_summary_object& p) {
750 751
         p.block_id = next_block.id();
   });
N
Nathan Hourt 已提交
752 753
}

754 755 756 757 758 759 760 761 762
/**
 *  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;
763 764 765
   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;
766
      ++itr;
767
      if( schedule.producers[count].block_signing_key != public_key_type() ) {
768 769 770
         ++count;
      }
   }
771 772 773 774
   const auto& hps = _head_producer_schedule();
   schedule.version = hps.version;
   if( hps != schedule )
      ++schedule.version;
775 776 777 778 779 780 781 782 783 784 785 786 787
   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;
}

788
void chain_controller::update_global_properties(const signed_block& b) { try {
789 790
   // If we're at the end of a round, update the BlockchainConfiguration, producer schedule
   // and "producers" special account authority
791 792 793 794 795
   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" );
796 797 798
      }

      const auto& gpo = get_global_properties();
799 800 801

      if( _head_producer_schedule() != schedule ) {
         FC_ASSERT( b.new_producers, "pending producer set changed but block didn't indicate it" );
802
      }
803 804 805 806 807 808 809 810
      _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) );
      });


811

812
      auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
813
      for(auto& name : gpo.active_producers.producers ) {
814
         active_producers_authority.accounts.push_back({{name.producer_name, config::active_name}, 1});
815 816
      }

D
Daniel Larimer 已提交
817
      auto& po = _db.get<permission_object, by_owner>( boost::make_tuple(config::producers_account_name, 
818
                                                                         config::active_name ) );
819 820 821
      _db.modify(po,[active_producers_authority] (permission_object& po) {
         po.auth = active_producers_authority;
      });
822
   }
823
} FC_CAPTURE_AND_RETHROW() } 
824

825
void chain_controller::add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts ) {
826
   for (const auto& i : checkpts)
N
Nathan Hourt 已提交
827 828 829
      _checkpoints[i.first] = i.second;
}

830
bool chain_controller::before_last_checkpoint()const {
N
Nathan Hourt 已提交
831 832 833
   return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
}

834
const global_property_object& chain_controller::get_global_properties()const {
835
   return _db.get<global_property_object>();
N
Nathan Hourt 已提交
836 837
}

838
const dynamic_global_property_object&chain_controller::get_dynamic_global_properties() const {
839
   return _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
840 841
}

D
Daniel Larimer 已提交
842
time_point chain_controller::head_block_time()const {
N
Nathan Hourt 已提交
843 844 845
   return get_dynamic_global_properties().time;
}

846
uint32_t chain_controller::head_block_num()const {
N
Nathan Hourt 已提交
847 848 849
   return get_dynamic_global_properties().head_block_number;
}

850
block_id_type chain_controller::head_block_id()const {
N
Nathan Hourt 已提交
851 852 853
   return get_dynamic_global_properties().head_block_id;
}

D
Daniel Larimer 已提交
854
account_name chain_controller::head_block_producer() const {
855 856 857
   auto b = _fork_db.fetch_block(head_block_id());
   if( b ) return b->data.producer;

N
Nathan Hourt 已提交
858
   if (auto head_block = fetch_block_by_id(head_block_id()))
859
      return head_block->producer;
N
Nathan Hourt 已提交
860 861 862
   return {};
}

D
Daniel Larimer 已提交
863 864
const producer_object& chain_controller::get_producer(const account_name& owner_name) const 
{ try {
B
Bart Wyatt 已提交
865
   return _db.get<producer_object, by_owner>(owner_name);
D
Daniel Larimer 已提交
866
} FC_CAPTURE_AND_RETHROW( (owner_name) ) }
N
Nathan Hourt 已提交
867

868 869 870 871 872
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) ) }

873
uint32_t chain_controller::last_irreversible_block_num() const {
N
Nathan Hourt 已提交
874
   return get_dynamic_global_properties().last_irreversible_block_num;
N
Nathan Hourt 已提交
875 876
}

D
Daniel Larimer 已提交
877
void chain_controller::_initialize_indexes() {
878 879
   _db.add_index<account_index>();
   _db.add_index<permission_index>();
880
   _db.add_index<permission_link_index>();
881 882
   _db.add_index<action_permission_index>();
   _db.add_index<key_value_index>();
M
Matias Romeo 已提交
883
   _db.add_index<keystr_value_index>();
884
   _db.add_index<key128x128_value_index>();
885
   _db.add_index<key64x64x64_value_index>();
886 887 888 889 890

   _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>();
891
   _db.add_index<generated_transaction_multi_index>();
892
   _db.add_index<producer_multi_index>();
N
Nathan Hourt 已提交
893 894
}

D
Daniel Larimer 已提交
895
void chain_controller::_initialize_chain(contracts::chain_initializer& starter)
N
Nathan Hourt 已提交
896
{ try {
897
   if (!_db.find<global_property_object>()) {
N
Nathan Hourt 已提交
898 899
      _db.with_write_lock([this, &starter] {
         auto initial_timestamp = starter.get_chain_start_time();
D
Daniel Larimer 已提交
900 901 902
         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 已提交
903

904
         // Create global properties
N
Nathan Hourt 已提交
905 906 907
         _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();
908
         });
909

910
         _db.create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
N
Nathan Hourt 已提交
911
            p.time = initial_timestamp;
912 913
            p.recent_slots_filled = uint64_t(-1);
         });
N
Nathan Hourt 已提交
914

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

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

D
Daniel Larimer 已提交
921
         transaction genesis_setup_transaction;
922
         genesis_setup_transaction.write_scope = { config::eosio_all_scope };
D
Daniel Larimer 已提交
923 924 925 926 927 928
         genesis_setup_transaction.actions = move(acts);

         ilog( "applying genesis transaction" );
         with_skip_flags(skip_scope_check | skip_transaction_signatures | skip_authority_check | received_block, 
         [&](){ 
            _apply_transaction( genesis_setup_transaction );
929
         });
930

931 932
      });
   }
N
Nathan Hourt 已提交
933 934
} FC_CAPTURE_AND_RETHROW() }

N
Nathan Hourt 已提交
935

936
void chain_controller::replay() {
937
   ilog("Replaying blockchain");
N
Nathan Hourt 已提交
938
   auto start = fc::time_point::now();
K
Kevin Heifner 已提交
939

K
Kevin Heifner 已提交
940
   auto on_exit = fc::make_scoped_exit([&_currently_replaying_blocks = _currently_replaying_blocks](){
K
Kevin Heifner 已提交
941 942 943 944
      _currently_replaying_blocks = false;
   });
   _currently_replaying_blocks = true;

945 946 947
   auto last_block = _block_log.read_head();
   if (!last_block) {
      elog("No blocks in block log; skipping replay");
N
Nathan Hourt 已提交
948 949 950 951 952
      return;
   }

   const auto last_block_num = last_block->block_num();

953
   ilog("Replaying ${n} blocks...", ("n", last_block_num) );
954 955 956 957 958
   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 已提交
959
      _apply_block(*block, skip_producer_signature |
N
Nathan Hourt 已提交
960 961 962 963
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_producer_schedule_check |
964 965
                          skip_authority_check |
                          received_block);
N
Nathan Hourt 已提交
966 967
   }
   auto end = fc::time_point::now();
968 969
   ilog("Done replaying ${n} blocks, elapsed time: ${t} sec",
        ("n", head_block_num())("t",double((end-start).count())/1000000.0));
N
Nathan Hourt 已提交
970

971
   _db.set_revision(head_block_num());
972
}
N
Nathan Hourt 已提交
973

D
Daniel Larimer 已提交
974
void chain_controller::_spinup_db() {
975 976 977 978 979
   // 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()));
980

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

D
Daniel Larimer 已提交
984
void chain_controller::_spinup_fork_db()
N
Nathan Hourt 已提交
985
{
986 987 988 989 990 991 992 993
   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 已提交
994 995
}

D
Daniel Larimer 已提交
996
/*
997 998
ProducerRound chain_controller::calculate_next_round(const signed_block& next_block) {
   auto schedule = _admin->get_next_round(_db);
N
Nathan Hourt 已提交
999 1000 1001 1002
   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 已提交
1003 1004 1005
   
   fc::time_point tp = (fc::time_point)next_block.timestamp;
   utilities::rand::random rng(tp.sec_since_epoch());
1006 1007
   rng.shuffle(schedule);
   return schedule;
D
Daniel Larimer 已提交
1008
}*/
1009

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

1013 1014 1015
   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 已提交
1016
   uint32_t missed_blocks = head_block_num() == 0? 1 : get_slot_at_time((fc::time_point)b.timestamp);
1017
   assert(missed_blocks != 0);
N
Nathan Hourt 已提交
1018
   missed_blocks--;
N
Nathan Hourt 已提交
1019

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

N
Nathan Hourt 已提交
1023
   for(uint32_t i = 0; i < missed_blocks; ++i) {
N
Nathan Hourt 已提交
1024
      const auto& producer_missed = get_producer(get_scheduled_producer(i+1));
1025
      if(producer_missed.owner != b.producer) {
N
Nathan Hourt 已提交
1026 1027 1028 1029 1030 1031
         /*
         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) );
            */

1032
         _db.modify( producer_missed, [&]( producer_object& w ) {
N
Nathan Hourt 已提交
1033 1034 1035 1036 1037 1038
           w.total_missed++;
         });
      }
   }

   // dynamic global properties updating
1039
   _db.modify( _dgp, [&]( dynamic_global_property_object& dgp ){
N
Nathan Hourt 已提交
1040 1041 1042
      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
1043
      dgp.current_producer = b.producer;
N
Nathan Hourt 已提交
1044 1045 1046 1047 1048 1049 1050
      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;
1051
      } else {
N
Nathan Hourt 已提交
1052
         dgp.recent_slots_filled = 0;
1053 1054
      }
      dgp.block_merkle_root.append( head_block_id() ); 
N
Nathan Hourt 已提交
1055 1056 1057 1058 1059
   });

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

1060
void chain_controller::update_signing_producer(const producer_object& signing_producer, const signed_block& new_block)
N
Nathan Hourt 已提交
1061 1062
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
P
Pravin 已提交
1063
   uint64_t new_block_aslot = dpo.current_absolute_slot + get_slot_at_time( (fc::time_point)new_block.timestamp );
N
Nathan Hourt 已提交
1064

1065
   _db.modify( signing_producer, [&]( producer_object& _wit )
N
Nathan Hourt 已提交
1066 1067 1068 1069 1070 1071
   {
      _wit.last_aslot = new_block_aslot;
      _wit.last_confirmed_block_num = new_block.block_num();
   } );
}

1072
void chain_controller::update_last_irreversible_block()
N
Nathan Hourt 已提交
1073 1074 1075 1076
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

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

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

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

D
Daniel Larimer 已提交
1085
   size_t offset = EOS_PERCENT(producer_objs.size(), config::percent_100- config::irreversible_threshold_percent);
1086 1087
   std::nth_element(producer_objs.begin(), producer_objs.begin() + offset, producer_objs.end(),
      [](const producer_object* a, const producer_object* b) {
N
Nathan Hourt 已提交
1088
         return a->last_confirmed_block_num < b->last_confirmed_block_num;
1089
      });
N
Nathan Hourt 已提交
1090

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

1093
   if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) {
1094
      _db.modify(dpo, [&](dynamic_global_property_object& _dpo) {
N
Nathan Hourt 已提交
1095
         _dpo.last_irreversible_block_num = new_last_irreversible_block_num;
1096
      });
N
Nathan Hourt 已提交
1097
   }
1098 1099

   // Write newly irreversible blocks to disk. First, get the number of the last block on disk...
1100
   auto old_last_irreversible_block = _block_log.head();
1101 1102 1103 1104
   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();
1105

1106
   if (last_block_on_disk < new_last_irreversible_block_num) {
1107 1108 1109 1110 1111
      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);
1112
         _block_log.append(*block);
K
Kevin Heifner 已提交
1113
         applied_irreversible_block(*block);
1114
      }
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
   }

   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());
                 }
              }
1133
              props.active_producers = *new_producer_schedule;
1134 1135 1136 1137
         });
      }
   }

N
Nathan Hourt 已提交
1138 1139 1140

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

1144
void chain_controller::clear_expired_transactions()
N
Nathan Hourt 已提交
1145 1146
{ try {
   //Look for expired transactions in the deduplication list, and remove them.
D
Daniel Larimer 已提交
1147
   //transactions must have expired by at least two forking windows in order to be removed.
D
Daniel Larimer 已提交
1148
   /*
1149
   auto& transaction_idx = _db.get_mutable_index<transaction_multi_index>();
N
Nathan Hourt 已提交
1150
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
D
Daniel Larimer 已提交
1151
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->expiration) )
N
Nathan Hourt 已提交
1152
      transaction_idx.remove(*dedupe_index.rbegin());
1153 1154

   //Look for expired transactions in the pending generated list, and remove them.
D
Daniel Larimer 已提交
1155
   //transactions must have expired by at least two forking windows in order to be removed.
1156 1157 1158 1159
   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 已提交
1160
      */
N
Nathan Hourt 已提交
1161 1162 1163 1164
} FC_CAPTURE_AND_RETHROW() }

using boost::container::flat_set;

D
Daniel Larimer 已提交
1165
account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const
N
Nathan Hourt 已提交
1166 1167
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1168
   uint64_t current_aslot = dpo.current_absolute_slot + slot_num;
1169
   const auto& gpo = _db.get<global_property_object>();
D
Daniel Larimer 已提交
1170 1171 1172 1173
   //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;

1174
   return gpo.active_producers.producers[index].producer_name;
N
Nathan Hourt 已提交
1175 1176
}

D
Daniel Larimer 已提交
1177
block_timestamp_type chain_controller::get_slot_time(uint32_t slot_num)const
N
Nathan Hourt 已提交
1178
{
P
Pravin 已提交
1179
   if( slot_num == 0)
D
Daniel Larimer 已提交
1180
      return block_timestamp_type();
N
Nathan Hourt 已提交
1181 1182 1183 1184 1185 1186

   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 已提交
1187 1188 1189
      auto genesis_time = block_timestamp_type(dpo.time);
      genesis_time.slot += slot_num;
      return (fc::time_point)genesis_time;
N
Nathan Hourt 已提交
1190 1191
   }

D
Daniel Larimer 已提交
1192
   auto head_block_abs_slot = block_timestamp_type(head_block_time());
P
Pravin 已提交
1193
   head_block_abs_slot.slot += slot_num;
D
Daniel Larimer 已提交
1194
   return head_block_abs_slot;
N
Nathan Hourt 已提交
1195 1196
}

D
Daniel Larimer 已提交
1197
uint32_t chain_controller::get_slot_at_time( block_timestamp_type when )const
N
Nathan Hourt 已提交
1198
{
D
Daniel Larimer 已提交
1199
   auto first_slot_time = get_slot_time(1);
N
Nathan Hourt 已提交
1200 1201
   if( when < first_slot_time )
      return 0;
D
Daniel Larimer 已提交
1202
   return block_timestamp_type(when).slot - first_slot_time.slot + 1;
N
Nathan Hourt 已提交
1203 1204
}

1205
uint32_t chain_controller::producer_participation_rate()const
N
Nathan Hourt 已提交
1206 1207
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
D
Daniel Larimer 已提交
1208
   return uint64_t(config::percent_100) * __builtin_popcountll(dpo.recent_slots_filled) / 64;
N
Nathan Hourt 已提交
1209 1210
}

D
Daniel Larimer 已提交
1211 1212
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;
1213
}
N
Nathan Hourt 已提交
1214

B
Bart Wyatt 已提交
1215 1216 1217
transaction_result chain_controller::_apply_transaction( const transaction& trx ) {
   transaction_result result(trx.id());

D
Daniel Larimer 已提交
1218
   for( const auto& act : trx.actions ) {
B
Bart Wyatt 已提交
1219
      apply_context context( *this, _db, trx, act,  act.scope  );
D
Daniel Larimer 已提交
1220
      context.exec();
B
Bart Wyatt 已提交
1221 1222
      fc::move_append(result.action_results, std::move(context.results.applied_actions));
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
D
Daniel Larimer 已提交
1223
   }
B
Bart Wyatt 已提交
1224 1225

   return result;
D
Daniel Larimer 已提交
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
}

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 已提交
1239
} } /// eosio::chain