chain_controller.cpp 47.3 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 341 342 343 344 345 346 347 348 349 350 351 352 353
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) {
         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;
      }
   }
}

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

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

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

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

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

387 388 389 390 391
   _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();
392

393 394 395 396
   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;
397 398
   }

N
Nathan Hourt 已提交
399
   if( !(skip & skip_producer_signature) )
D
Daniel Larimer 已提交
400
      _pending_block->sign( block_signing_key );
N
Nathan Hourt 已提交
401

D
Daniel Larimer 已提交
402 403
   _finalize_block( *_pending_block );

404 405
   _pending_block_session->push();

D
Daniel Larimer 已提交
406 407
   auto result = move( *_pending_block );

408 409 410
   _pending_block.reset();
   _pending_block_session.reset();

D
Daniel Larimer 已提交
411
   if (!(skip&skip_fork_db)) {
D
Daniel Larimer 已提交
412
      _fork_db.push_block(result);
N
Nathan Hourt 已提交
413
   }
D
Daniel Larimer 已提交
414
   return result;
N
Nathan Hourt 已提交
415

N
Nathan Hourt 已提交
416
} FC_CAPTURE_AND_RETHROW( (producer) ) }
N
Nathan Hourt 已提交
417

D
Daniel Larimer 已提交
418 419 420
void chain_controller::_start_pending_block() {
   FC_ASSERT( !_pending_block );
   _pending_block         = signed_block();
421 422
   _pending_block->cycles_summary.resize(1);
   _pending_block->cycles_summary[0].resize(1);
D
Daniel Larimer 已提交
423
   _pending_block_session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
424 425
}

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

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

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

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

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

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

468

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

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

   const producer_object& signing_producer = validate_block_header(skip, next_block);
481 482 483 484 485 486 487 488


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

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

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

520
   _finalize_block( next_block );
N
Nathan Hourt 已提交
521 522
} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) )  }

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

538
   applied_block( b ); //emit
D
Daniel Larimer 已提交
539 540
   if (_currently_replaying_blocks)
     applied_irreversible_block(b);
541 542

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

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

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

   return checker.used_keys();
}

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

N
Nathan Hourt 已提交
573

574
   for( const auto& act : trx.actions ) {
575
      for( const auto& declared_auth : act.authorization ) {
D
Daniel Larimer 已提交
576

577 578
         const auto& min_permission = lookup_minimum_permission(declared_auth.actor, 
                                                                act.scope, act.name);
D
Daniel Larimer 已提交
579

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

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

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

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

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

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

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

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

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


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

D
Daniel Larimer 已提交
664
   const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.ref_block_num);
665 666

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

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

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

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

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

699

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

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

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

N
Nathan Hourt 已提交
727
   if(!(skip&skip_producer_signature))
728 729 730
      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 已提交
731

732
   if(!(skip&skip_producer_schedule_check)) {
733 734 735
      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 已提交
736 737
   }

738 739 740
   
   FC_ASSERT( next_block.calculate_transaction_merkle_root() == next_block.transaction_mroot, "merkle root does not match" );

N
Nathan Hourt 已提交
741 742 743
   return producer;
}

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

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

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

      const auto& gpo = get_global_properties();
796 797 798

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


808

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

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

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

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

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

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

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

843
uint32_t chain_controller::head_block_num()const {
N
Nathan Hourt 已提交
844 845 846
   return get_dynamic_global_properties().head_block_number;
}

847
block_id_type chain_controller::head_block_id()const {
N
Nathan Hourt 已提交
848 849 850
   return get_dynamic_global_properties().head_block_id;
}

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

N
Nathan Hourt 已提交
855
   if (auto head_block = fetch_block_by_id(head_block_id()))
856
      return head_block->producer;
N
Nathan Hourt 已提交
857 858 859
   return {};
}

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

865 866 867 868 869
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) ) }

870
uint32_t chain_controller::last_irreversible_block_num() const {
N
Nathan Hourt 已提交
871
   return get_dynamic_global_properties().last_irreversible_block_num;
N
Nathan Hourt 已提交
872 873
}

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

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

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

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

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

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

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

D
Daniel Larimer 已提交
918
         transaction genesis_setup_transaction;
919
         genesis_setup_transaction.write_scope = { config::eosio_all_scope };
D
Daniel Larimer 已提交
920 921 922 923 924 925
         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 );
926
         });
927

928 929
      });
   }
N
Nathan Hourt 已提交
930 931
} FC_CAPTURE_AND_RETHROW() }

N
Nathan Hourt 已提交
932

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

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

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

   const auto last_block_num = last_block->block_num();

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

968
   _db.set_revision(head_block_num());
969
}
N
Nathan Hourt 已提交
970

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

978 979
   });
}
N
Nathan Hourt 已提交
980

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   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());
                 }
              }
1130
              props.active_producers = *new_producer_schedule;
1131 1132 1133 1134
         });
      }
   }

N
Nathan Hourt 已提交
1135 1136 1137

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

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

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

using boost::container::flat_set;

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

1171
   return gpo.active_producers.producers[index].producer_name;
N
Nathan Hourt 已提交
1172 1173
}

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

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

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

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

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

D
Daniel Larimer 已提交
1208 1209
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;
1210
}
N
Nathan Hourt 已提交
1211

B
Bart Wyatt 已提交
1212 1213 1214
transaction_result chain_controller::_apply_transaction( const transaction& trx ) {
   transaction_result result(trx.id());

D
Daniel Larimer 已提交
1215
   for( const auto& act : trx.actions ) {
B
Bart Wyatt 已提交
1216
      apply_context context( *this, _db, trx, act,  act.scope  );
D
Daniel Larimer 已提交
1217
      context.exec();
B
Bart Wyatt 已提交
1218 1219
      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 已提交
1220
   }
B
Bart Wyatt 已提交
1221 1222

   return result;
D
Daniel Larimer 已提交
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
}

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