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

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

B
Bart Wyatt 已提交
8 9
#include <eosio/chain/block_summary_object.hpp>
#include <eosio/chain/global_property_object.hpp>
10
#include <eosio/chain/contracts/contract_table_objects.hpp>
B
Bart Wyatt 已提交
11 12 13 14 15 16
#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/scope_sequence_object.hpp>
19
#include <eosio/chain/merkle.hpp>
N
Nathan Hourt 已提交
20

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

23
#include <eosio/utilities/rand.hpp>
24

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

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

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

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

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

uint32_t chain_controller::blocks_per_round()const {
46
  return get_global_properties().active_producers.producers.size()*config::producer_repetitions;
47 48
}

D
Daniel Larimer 已提交
49
chain_controller::chain_controller( const chain_controller::controller_config& cfg )
50 51 52
:_db( cfg.shared_memory_dir,
      (cfg.read_only ? database::read_only : database::read_write),
      cfg.shared_memory_size),
53
 _block_log(cfg.block_log_dir),
54
 _limits(cfg.limits)
D
Daniel Larimer 已提交
55 56 57
{
   _initialize_indexes();

58 59
   for (auto& f : cfg.applied_block_callbacks)
      applied_block.connect(f);
60 61
   for (auto& f : cfg.applied_irreversible_block_callbacks)
      applied_irreversible_block.connect(f);
62 63
   for (auto& f : cfg.on_pending_transaction_callbacks)
      on_pending_transaction.connect(f);
64

D
Daniel Larimer 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
   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();
}

86
bool chain_controller::is_known_block(const block_id_type& id)const
N
Nathan Hourt 已提交
87
{
88
   return _fork_db.is_known_block(id) || _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
89 90 91 92 93 94
}
/**
 * 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.
 */
95
bool chain_controller::is_known_transaction(const transaction_id_type& id)const
N
Nathan Hourt 已提交
96
{
97
   const auto& trx_idx = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
98 99 100
   return trx_idx.find( id ) != trx_idx.end();
}

101
block_id_type chain_controller::get_block_id_for_num(uint32_t block_num)const
N
Nathan Hourt 已提交
102
{ try {
103 104
   if (const auto& block = fetch_block_by_number(block_num))
      return block->id();
N
Nathan Hourt 已提交
105

106 107 108
   FC_THROW_EXCEPTION(unknown_block_exception, "Could not find block");
} FC_CAPTURE_AND_RETHROW((block_num)) }

109
optional<signed_block> chain_controller::fetch_block_by_id(const block_id_type& id)const
N
Nathan Hourt 已提交
110
{
111 112
   auto b = _fork_db.fetch_block(id);
   if(b) return b->data;
113
   return _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
114 115
}

116
optional<signed_block> chain_controller::fetch_block_by_number(uint32_t num)const
N
Nathan Hourt 已提交
117
{
118
   if (const auto& block = _block_log.read_block_by_num(num))
119 120
      return *block;

N
Nathan Hourt 已提交
121
   // Not in _block_log, so it must be since the last irreversible block. Grab it from _fork_db instead
122 123 124 125 126 127 128 129
   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 已提交
130 131 132
   return optional<signed_block>();
}

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

151

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

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

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

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

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

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

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

/**
 * 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.
 */
249
transaction_trace chain_controller::push_transaction(const packed_transaction& trx, uint32_t skip)
N
Nathan Hourt 已提交
250
{ try {
251 252
   return with_skip_flags(skip, [&]() {
      return _db.with_write_lock([&]() {
253
         return _push_transaction(trx);
D
Daniel Larimer 已提交
254
      });
N
Nathan Hourt 已提交
255 256
   });
} FC_CAPTURE_AND_RETHROW((trx)) }
N
Nathan Hourt 已提交
257

258
transaction_trace chain_controller::_push_transaction(const packed_transaction& trx) {
259
   transaction_metadata   mtrx( trx, get_chain_id(), head_block_time());
260
   check_transaction_authorization(mtrx.trx(), trx.signatures);
261
   auto result = _push_transaction(std::move(mtrx));
B
Bart Wyatt 已提交
262 263

   // notify anyone listening to pending transactions
264
   on_pending_transaction(_pending_transaction_metas.back(), trx);
B
Bart Wyatt 已提交
265

266 267
   _pending_block->input_transactions.emplace_back(trx);

B
Bart Wyatt 已提交
268 269 270 271
   return result;

}

B
Bart Wyatt 已提交
272 273 274 275
static void record_locks_for_data_access(const vector<action_trace>& action_traces, vector<shard_lock>& read_locks, vector<shard_lock>& write_locks ) {
   for (const auto& at: action_traces) {
      for (const auto& access: at.data_access) {
         if (access.type == data_access_info::read) {
276
            read_locks.emplace_back(shard_lock{access.code, access.scope});
B
Bart Wyatt 已提交
277
         } else {
278
            write_locks.emplace_back(shard_lock{access.code, access.scope});
B
Bart Wyatt 已提交
279 280 281 282 283
         }
      }
   }
}

284
transaction_trace chain_controller::_push_transaction( transaction_metadata&& data )
B
Bart Wyatt 已提交
285
{
286 287 288 289
   if (_limits.max_push_transaction_us.count() > 0) {
      data.processing_deadline = fc::time_point::now() + _limits.max_push_transaction_us;
   }

290
   const transaction& trx = data.trx();
291 292
   // 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 已提交
293
   if( !_pending_block ) {
D
Daniel Larimer 已提交
294
      _start_pending_block();
D
Daniel Larimer 已提交
295
   }
296

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

B
Bart Wyatt 已提交
299
   // for now apply the transaction serially but schedule it according to those invariants
300
   validate_referenced_accounts(trx);
N
Nathan Hourt 已提交
301

302 303
   auto cyclenum = _pending_block->regions.back().cycles_summary.size() - 1;

304 305 306
   /// TODO: move _pending_cycle into db so that it can be undone if transation fails, for now we will apply
   /// the transaction first so that there is nothing to undo... this only works because things are currently
   /// single threaded
B
Bart Wyatt 已提交
307 308 309
   // set cycle, shard, region etc
   data.region_id = 0;
   data.cycle_index = cyclenum;
B
Bart Wyatt 已提交
310
   data.shard_index = 0;
B
Bart Wyatt 已提交
311
   auto result = _apply_transaction( data );
312

313
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
B
Bart Wyatt 已提交
314
   auto& bshard = bcycle.front();
315

B
Bart Wyatt 已提交
316
   record_locks_for_data_access(result.action_traces, bshard.read_locks, bshard.write_locks);
317

318 319
   fc::deduplicate(bshard.read_locks);
   fc::deduplicate(bshard.write_locks);
320

B
Bart Wyatt 已提交
321
   bshard.transactions.emplace_back( result );
322

B
Bart Wyatt 已提交
323
   _pending_cycle_trace->shard_traces.at(0).append(result);
B
Bart Wyatt 已提交
324

N
Nathan Hourt 已提交
325 326 327
   // The transaction applied successfully. Merge its changes into the pending block session.
   temp_session.squash();

328 329
   _pending_transaction_metas.emplace_back(std::forward<transaction_metadata>(data));

B
Bart Wyatt 已提交
330
   return result;
N
Nathan Hourt 已提交
331 332
}

333 334 335 336 337 338
void chain_controller::_start_pending_block()
{
   FC_ASSERT( !_pending_block );
   _pending_block         = signed_block();
   _pending_block_trace   = block_trace(*_pending_block);
   _pending_block_session = _db.start_undo_session(true);
339 340
   _pending_block->regions.resize(1);
   _pending_block_trace->region_traces.resize(1);
341 342 343
   _start_pending_cycle();
}

344 345
/**
 *  Wraps up all work for current shards, starts a new cycle, and
346
 *  executes any pending transactions
347
 */
348
void chain_controller::_start_pending_cycle() {
349
   _pending_block->regions.back().cycles_summary.resize( _pending_block->regions[0].cycles_summary.size() + 1 );
350 351
   _pending_cycle_trace = cycle_trace();
   _start_pending_shard();
352 353

   /// TODO: check for deferred transactions and schedule them
354
} // _start_pending_cycle
355

356
void chain_controller::_start_pending_shard()
B
Bart Wyatt 已提交
357
{
358
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
359 360 361
   bcycle.resize( bcycle.size()+1 );

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

364 365
void chain_controller::_finalize_pending_cycle()
{
366 367 368 369
   for( auto& shard : _pending_cycle_trace->shard_traces ) {
      shard.calculate_root();
   }

370
   _apply_cycle_trace(*_pending_cycle_trace);
371
   _pending_block_trace->region_traces.back().cycle_traces.emplace_back(std::move(*_pending_cycle_trace));
372 373
   _pending_cycle_trace.reset();
}
B
Bart Wyatt 已提交
374

375 376 377 378 379
void chain_controller::_apply_cycle_trace( const cycle_trace& res )
{
   for (const auto&st: res.shard_traces) {
      for (const auto &tr: st.transaction_traces) {
         for (const auto &dt: tr.deferred_transactions) {
380
            _db.create<generated_transaction_object>([&](generated_transaction_object &obj) {
381 382 383 384 385
               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;
386
               obj.published = head_block_time();
387 388 389 390 391 392
               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);
            });
         }

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
         if (tr.canceled_deferred.size() > 0 ) {
            auto &generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
            const auto &generated_index = generated_transaction_idx.indices().get<by_sender_id>();
            for (const auto &dr: tr.canceled_deferred) {
               while(!generated_index.empty()) {
                  const auto& itr = generated_index.lower_bound(boost::make_tuple(dr.sender, dr.sender_id));
                  if (itr == generated_index.end() || itr->sender != dr.sender || itr->sender_id != dr.sender_id ) {
                     break;
                  }

                  generated_transaction_idx.remove(*itr);
               }
            }
         }

408 409 410 411
         ///TODO: hook this up as a signal handler in a de-coupled "logger" that may just silently drop them
         for (const auto &ar : tr.action_traces) {
            if (!ar.console.empty()) {
               auto prefix = fc::format_string(
B
Bart Wyatt 已提交
412
                  "[(${a},${n})->${r}]",
413
                  fc::mutable_variant_object()
B
Bart Wyatt 已提交
414 415
                     ("a", ar.act.account)
                     ("n", ar.act.name)
416 417 418 419 420
                     ("r", ar.receiver));
               std::cerr << prefix << ": CONSOLE OUTPUT BEGIN =====================" << std::endl;
               std::cerr << ar.console;
               std::cerr << prefix << ": CONSOLE OUTPUT END   =====================" << std::endl;
            }
421
         }
B
Bart Wyatt 已提交
422 423 424 425
      }
   }
}

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
/**
 *  After applying all transactions successfully we can update
 *  the current block time, block number, producer stats, etc
 */
void chain_controller::_finalize_block( const block_trace& trace ) { try {
   const auto& b = trace.block;
   const producer_object& signing_producer = validate_block_header(_skip_flags, b);

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

   create_block_summary(b);
   clear_expired_transactions();

441
   update_last_irreversible_block();
442
   update_rate_limiting();
443

444
   applied_block( trace ); //emit
445 446 447 448 449
   if (_currently_replaying_blocks)
     applied_irreversible_block(b);

} FC_CAPTURE_AND_RETHROW( (trace.block) ) }

450
signed_block chain_controller::generate_block(
D
Daniel Larimer 已提交
451 452 453
   block_timestamp_type when,
   account_name producer,
   const private_key_type& block_signing_private_key,
N
Nathan Hourt 已提交
454 455 456
   uint32_t skip /* = 0 */
   )
{ try {
457
   return with_skip_flags( skip | created_block, [&](){
D
Daniel Larimer 已提交
458
      return _db.with_write_lock( [&](){
D
Daniel Larimer 已提交
459
         return _generate_block( when, producer, block_signing_private_key );
D
Daniel Larimer 已提交
460
      });
N
Nathan Hourt 已提交
461
   });
D
Daniel Larimer 已提交
462
} FC_CAPTURE_AND_RETHROW( (when) ) }
N
Nathan Hourt 已提交
463

464 465
signed_block chain_controller::_generate_block( block_timestamp_type when,
                                              account_name producer,
D
Daniel Larimer 已提交
466 467
                                              const private_key_type& block_signing_key )
{ try {
468

469 470 471 472 473 474
   try {
      uint32_t skip     = _skip_flags;
      uint32_t slot_num = get_slot_at_time( when );
      FC_ASSERT( slot_num > 0 );
      account_name scheduled_producer = get_scheduled_producer( slot_num );
      FC_ASSERT( scheduled_producer == producer );
N
Nathan Hourt 已提交
475

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

478 479 480
      if( !_pending_block ) {
         _start_pending_block();
      }
481

482
      _finalize_pending_cycle();
483

484
      if( !(skip & skip_producer_signature) )
K
Kevin Heifner 已提交
485 486
         FC_ASSERT( producer_obj.signing_key == block_signing_key.get_public_key(),
                    "producer key ${pk}, block key ${bk}", ("pk", producer_obj.signing_key)("bk", block_signing_key.get_public_key()) );
N
Nathan Hourt 已提交
487

488 489 490 491
         _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();
492
         _pending_block->transaction_mroot = transaction_metadata::calculate_transaction_merkle_root( _pending_transaction_metas );
493
         _pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root();
494

495 496 497 498 499
         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;
      }
500

501 502
      if( !(skip & skip_producer_signature) )
         _pending_block->sign( block_signing_key );
503

504
      _finalize_block( *_pending_block_trace );
N
Nathan Hourt 已提交
505

506
      _pending_block_session->push();
D
Daniel Larimer 已提交
507

508
      auto result = move( *_pending_block );
509

510
      clear_pending();
D
Daniel Larimer 已提交
511

512 513 514 515 516
      if (!(skip&skip_fork_db)) {
         _fork_db.push_block(result);
      }
      return result;
   } catch ( ... ) {
517
      clear_pending();
518

519 520 521
      elog( "error while producing block" );
      _start_pending_block();
      throw;
N
Nathan Hourt 已提交
522 523
   }

N
Nathan Hourt 已提交
524
} FC_CAPTURE_AND_RETHROW( (producer) ) }
N
Nathan Hourt 已提交
525 526

/**
N
Nathan Hourt 已提交
527
 * Removes the most recent block from the database and undoes any changes it made.
N
Nathan Hourt 已提交
528
 */
529
void chain_controller::pop_block()
N
Nathan Hourt 已提交
530
{ try {
D
Daniel Larimer 已提交
531
   _pending_block_session.reset();
N
Nathan Hourt 已提交
532 533 534 535 536
   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();
537
   _db.undo();
N
Nathan Hourt 已提交
538 539
} FC_CAPTURE_AND_RETHROW() }

540
void chain_controller::clear_pending()
N
Nathan Hourt 已提交
541
{ try {
542
   _pending_block_trace.reset();
D
Daniel Larimer 已提交
543
   _pending_block.reset();
D
Daniel Larimer 已提交
544
   _pending_block_session.reset();
545
   _pending_transaction_metas.clear();
N
Nathan Hourt 已提交
546 547 548 549
} FC_CAPTURE_AND_RETHROW() }

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

D
Daniel Larimer 已提交
550
void chain_controller::_apply_block(const signed_block& next_block, uint32_t skip)
N
Nathan Hourt 已提交
551 552
{
   auto block_num = next_block.block_num();
553 554 555 556 557
   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 已提交
558

559
      if (_checkpoints.rbegin()->first >= block_num)
N
Nathan Hourt 已提交
560 561
         skip = ~0;// WE CAN SKIP ALMOST EVERYTHING
   }
N
Nathan Hourt 已提交
562 563 564

   with_applying_block([&] {
      with_skip_flags(skip, [&] {
D
Daniel Larimer 已提交
565
         __apply_block(next_block);
N
Nathan Hourt 已提交
566 567
      });
   });
N
Nathan Hourt 已提交
568 569
}

570 571
static void validate_shard_locks(const vector<shard_lock>& locks, const string& tag) {
   if (locks.size() < 2) {
572 573 574
      return;
   }

B
Bart Wyatt 已提交
575
   for (auto cur = locks.begin() + 1; cur != locks.end(); ++cur) {
576
      auto prev = cur - 1;
B
Bart Wyatt 已提交
577 578
      EOS_ASSERT(*prev != *cur, block_lock_exception, "${tag} lock \"${a}::${s}\" is not unique", ("tag",tag)("a",cur->account)("s",cur->scope));
      EOS_ASSERT(*prev < *cur,  block_lock_exception, "${tag} locks are not sorted", ("tag",tag));
579 580
   }
}
581

D
Daniel Larimer 已提交
582
void chain_controller::__apply_block(const signed_block& next_block)
N
Nathan Hourt 已提交
583
{ try {
584 585
   optional<fc::time_point> processing_deadline;
   if (!_currently_replaying_blocks && _limits.max_push_block_us.count() > 0) {
B
Bart Wyatt 已提交
586
      processing_deadline = fc::time_point::now() + _limits.max_push_block_us;
587 588
   }

N
Nathan Hourt 已提交
589
   uint32_t skip = _skip_flags;
N
Nathan Hourt 已提交
590

D
Daniel Larimer 已提交
591
   /*
592
   FC_ASSERT((skip & skip_merkle_check)
D
Daniel Larimer 已提交
593
             || next_block.transaction_merkle_root == next_block.calculate_merkle_root(),
594 595
             "", ("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 已提交
596
             */
N
Nathan Hourt 已提交
597 598

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

600 601 602 603
   /// regions must be listed in order
   for( uint32_t i = 1; i < next_block.regions.size(); ++i )
      FC_ASSERT( next_block.regions[i-1].region < next_block.regions[i].region );

604 605 606

   /// cache the input tranasction ids so that they can be looked up when executing the
   /// summary
607
   vector<transaction_metadata> input_metas;
B
Bart Wyatt 已提交
608 609
   input_metas.reserve(next_block.input_transactions.size());
   map<transaction_id_type,size_t> trx_index;
610
   for( const auto& t : next_block.input_transactions ) {
611
      input_metas.emplace_back(t, chain_id_type(), next_block.timestamp);
B
Bart Wyatt 已提交
612
      trx_index[input_metas.back().id] =  input_metas.size() - 1;
613
   }
614 615

   block_trace next_block_trace(next_block);
616 617
   next_block_trace.region_traces.reserve(next_block.regions.size());

618
   for( const auto& r : next_block.regions ) {
619 620 621
      region_trace r_trace;
      r_trace.cycle_traces.reserve(r.cycles_summary.size());

622
      for (uint32_t cycle_index = 0; cycle_index < r.cycles_summary.size(); cycle_index++) {
623
         const auto& cycle = r.cycles_summary.at(cycle_index);
624 625 626
         cycle_trace c_trace;
         c_trace.shard_traces.reserve(cycle.size());

627 628
         // validate that no read_scope is used as a write scope in this cycle and that no two shards
         // share write scopes
629 630
         set<shard_lock> read_locks;
         map<shard_lock, uint32_t> write_locks;
631 632 633 634 635

         for (uint32_t shard_index = 0; shard_index < cycle.size(); shard_index++) {
            const auto& shard = cycle.at(shard_index);

            // Validate that the shards scopes are correct and available
636 637 638 639
            validate_shard_locks(shard.read_locks,  "read");
            validate_shard_locks(shard.write_locks, "write");

            for (const auto& s: shard.read_locks) {
B
Bart Wyatt 已提交
640
               EOS_ASSERT(write_locks.count(s) == 0, block_concurrency_exception,
641 642 643
                  "shard ${i} requires read lock \"${a}::${s}\" which is locked for write by shard ${j}",
                  ("i", shard_index)("s", s)("j", write_locks[s]));
               read_locks.emplace(s);
644 645
            }

646
            for (const auto& s: shard.write_locks) {
B
Bart Wyatt 已提交
647
               EOS_ASSERT(write_locks.count(s) == 0, block_concurrency_exception,
648
                  "shard ${i} requires write lock \"${a}::${s}\" which is locked for write by shard ${j}",
B
Bart Wyatt 已提交
649 650 651 652
                  ("i", shard_index)("a", s.account)("s", s.scope)("j", write_locks[s]));
               EOS_ASSERT(read_locks.count(s) == 0, block_concurrency_exception,
                  "shard ${i} requires write lock \"${a}::${s}\" which is locked for read",
                  ("i", shard_index)("a", s.account)("s", s.scope));
653
               write_locks[s] = shard_index;
654 655
            }

B
Bart Wyatt 已提交
656 657 658
            vector<shard_lock> used_read_locks;
            vector<shard_lock> used_write_locks;

659
            shard_trace s_trace;
B
Bart Wyatt 已提交
660
            for (const auto& receipt : shard.transactions) {
661 662
                optional<transaction_metadata> _temp;
                auto make_metadata = [&]() -> transaction_metadata* {
663 664
                  auto itr = trx_index.find(receipt.id);
                  if( itr != trx_index.end() ) {
B
Bart Wyatt 已提交
665
                     return &input_metas.at(itr->second);
B
Bart Wyatt 已提交
666
                  } else {
667
                     const auto& gtrx = _db.get<generated_transaction_object,by_trx_id>(receipt.id);
B
Bart Wyatt 已提交
668
                     auto trx = fc::raw::unpack<deferred_transaction>(gtrx.packed_trx.data(), gtrx.packed_trx.size());
669 670
                     _temp.emplace(trx, gtrx.published, trx.sender, trx.sender_id, gtrx.packed_trx.data(), gtrx.packed_trx.size() );
                     return &*_temp;
671
                  }
672
               };
B
Bart Wyatt 已提交
673

674 675 676 677 678 679
               auto *mtrx = make_metadata();
               mtrx->region_id = r.region;
               mtrx->cycle_index = cycle_index;
               mtrx->shard_index = shard_index;
               mtrx->allowed_read_locks.emplace(&shard.read_locks);
               mtrx->allowed_write_locks.emplace(&shard.write_locks);
680
               mtrx->processing_deadline = processing_deadline;
B
Bart Wyatt 已提交
681

682
               s_trace.transaction_traces.emplace_back(_apply_transaction(*mtrx));
B
Bart Wyatt 已提交
683
               record_locks_for_data_access(s_trace.transaction_traces.back().action_traces, used_read_locks, used_write_locks);
684 685

               FC_ASSERT(receipt.status == s_trace.transaction_traces.back().status);
B
Bart Wyatt 已提交
686

687 688 689 690 691
               // validate_referenced_accounts(trx);
               // Check authorization, and allow irrelevant signatures.
               // If the block producer let it slide, we'll roll with it.
               // check_transaction_authorization(trx, true);
            } /// for each transaction id
N
Nathan Hourt 已提交
692

B
Bart Wyatt 已提交
693 694 695 696 697 698 699 700 701 702
            // Validate that the producer didn't list extra locks to bloat the size of the block
            // TODO: this check can be removed when blocks are irreversible
            fc::deduplicate(used_read_locks);
            fc::deduplicate(used_write_locks);

            EOS_ASSERT(std::equal(used_read_locks.cbegin(), used_read_locks.cend(), shard.read_locks.begin()),
               block_lock_exception, "Read locks for executing shard: ${s} do not match those listed in the block", ("s", shard_index));
            EOS_ASSERT(std::equal(used_write_locks.cbegin(), used_write_locks.cend(), shard.write_locks.begin()),
               block_lock_exception, "Write locks for executing shard: ${s} do not match those listed in the block", ("s", shard_index));

703 704 705
            s_trace.calculate_root();
            c_trace.shard_traces.emplace_back(move(s_trace));
         } /// for each shard
D
Daniel Larimer 已提交
706

707 708 709
         _apply_cycle_trace(c_trace);
         r_trace.cycle_traces.emplace_back(move(c_trace));
      } /// for each cycle
D
Daniel Larimer 已提交
710

711 712
      next_block_trace.region_traces.emplace_back(move(r_trace));
   } /// for each region
N
Nathan Hourt 已提交
713

714
   FC_ASSERT(next_block.action_mroot == next_block_trace.calculate_action_merkle_root());
715
   FC_ASSERT( transaction_metadata::calculate_transaction_merkle_root(input_metas) == next_block.transaction_mroot, "merkle root does not match" );
N
Nathan Hourt 已提交
716

717
   _finalize_block( next_block_trace );
718
} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) )  }
D
Daniel Larimer 已提交
719

720 721
flat_set<public_key_type> chain_controller::get_required_keys(const transaction& trx,
                                                              const flat_set<public_key_type>& candidate_keys)const
D
Daniel Larimer 已提交
722
{
723
   auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
724 725
                                     get_global_properties().configuration.max_authority_depth,
                                     candidate_keys);
726

727
   for (const auto& act : trx.actions ) {
D
Daniel Larimer 已提交
728 729 730
      for (const auto& declared_auth : act.authorization) {
         if (!checker.satisfied(declared_auth)) {
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
731
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
732
                       ("auth", declared_auth));
733 734 735 736 737 738 739
         }
      }
   }

   return checker.used_keys();
}

740
void chain_controller::check_authorization( const vector<action>& actions,
741 742 743
                                            flat_set<public_key_type> provided_keys,
                                            bool allow_unused_signatures,
                                            flat_set<account_name>    provided_accounts  )const
D
Daniel Larimer 已提交
744
{
745
   auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
746
                                     get_global_properties().configuration.max_authority_depth,
747 748
                                     provided_keys, provided_accounts );

N
Nathan Hourt 已提交
749

750
   for( const auto& act : actions ) {
751
      for( const auto& declared_auth : act.authorization ) {
D
Daniel Larimer 已提交
752

753
         // check a minimum permission if one is set, otherwise assume the contract code will validate
B
Bart Wyatt 已提交
754
         auto min_permission_name = lookup_minimum_permission(declared_auth.actor, act.account, act.name);
755 756 757 758 759 760 761 762 763 764 765
         if (min_permission_name) {
            const auto& min_permission = _db.get<permission_object, by_owner>(boost::make_tuple(declared_auth.actor, *min_permission_name));


            if ((_skip_flags & skip_authority_check) == false) {
               const auto &index = _db.get_index<permission_index>().indices();
               EOS_ASSERT(get_permission(declared_auth).satisfies(min_permission, index),
                          tx_irrelevant_auth,
                          "action declares irrelevant authority '${auth}'; minimum authority is ${min}",
                          ("auth", declared_auth)("min", min_permission.name));
            }
N
Nathan Hourt 已提交
766 767
         }
         if ((_skip_flags & skip_transaction_signatures) == false) {
D
Daniel Larimer 已提交
768
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
769
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
770
                       ("auth", declared_auth));
N
Nathan Hourt 已提交
771 772
         }
      }
773
   }
N
Nathan Hourt 已提交
774

775
   if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false)
776
      EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
777
                 "transaction bears irrelevant signatures from these keys: ${keys}",
778
                 ("keys", checker.unused_keys()));
N
Nathan Hourt 已提交
779 780
}

781 782
void chain_controller::check_transaction_authorization(const transaction& trx,
                                                       const vector<signature_type>& signatures,
783
                                                       bool allow_unused_signatures)const
784
{
785
   check_authorization( trx.actions, trx.get_signature_keys( signatures, chain_id_type{} ), allow_unused_signatures );
786 787
}

788
optional<permission_name> chain_controller::lookup_minimum_permission(account_name authorizer_account,
D
Daniel Larimer 已提交
789 790
                                                                    account_name scope,
                                                                    action_name act_name) const {
791 792 793 794 795 796
   // updateauth is a special case where any permission _may_ be suitable depending
   // on the contents of the action
   if (scope == config::system_account_name && act_name == N(updateauth)) {
      return optional<permission_name>();
   }

N
Nathan Hourt 已提交
797
   try {
D
Daniel Larimer 已提交
798 799 800
      // 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);
801 802 803
      // If no specific link found, check for a contract-wide default
      if (link == nullptr) {
         get<2>(key) = "";
D
Daniel Larimer 已提交
804
         link = _db.find<permission_link_object, by_action_name>(key);
805 806 807 808
      }

      // If no specific or default link found, use active permission
      if (link != nullptr)
809 810 811
         return link->required_permission;
      else
         return N(active);
D
Daniel Larimer 已提交
812
   } FC_CAPTURE_AND_RETHROW((authorizer_account)(scope)(act_name))
N
Nathan Hourt 已提交
813 814
}

815
void chain_controller::validate_uniqueness( const transaction& trx )const {
N
Nathan Hourt 已提交
816
   if( !should_check_for_duplicate_transactions() ) return;
N
Nathan Hourt 已提交
817

818
   auto transaction = _db.find<transaction_object, by_trx_id>(trx.id());
D
Daniel Larimer 已提交
819
   EOS_ASSERT(transaction == nullptr, tx_duplicate, "transaction is not unique");
820
}
821

822
void chain_controller::record_transaction(const transaction& trx) {
823 824
   //Insert transaction into unique transactions database.
    _db.create<transaction_object>([&](transaction_object& transaction) {
825
        transaction.trx_id = trx.id();
D
Daniel Larimer 已提交
826
        transaction.expiration = trx.expiration;
827 828 829 830
    });
}


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

D
Daniel Larimer 已提交
834
   const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.ref_block_num);
835 836

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

842 843
void chain_controller::validate_referenced_accounts( const transaction& trx )const
{ try {
D
Daniel Larimer 已提交
844
   for( const auto& act : trx.actions ) {
B
Bart Wyatt 已提交
845
      require_account(act.account);
D
Daniel Larimer 已提交
846
      for (const auto& auth : act.authorization )
D
Daniel Larimer 已提交
847
         require_account(auth.actor);
848
   }
D
Daniel Larimer 已提交
849
} FC_CAPTURE_AND_RETHROW() }
D
Daniel Larimer 已提交
850

D
Daniel Larimer 已提交
851
void chain_controller::validate_expiration( const transaction& trx ) const
852
{ try {
D
Daniel Larimer 已提交
853
   fc::time_point now = head_block_time();
D
Daniel Larimer 已提交
854
   const auto& chain_configuration = get_global_properties().configuration;
855

D
Daniel Larimer 已提交
856
   EOS_ASSERT( time_point(trx.expiration) <= now + fc::seconds(chain_configuration.max_transaction_lifetime),
D
Daniel Larimer 已提交
857
              transaction_exception, "transaction expiration is too far in the future",
858
              ("trx.expiration",trx.expiration)("now",now)
D
Daniel Larimer 已提交
859 860
              ("max_til_exp",chain_configuration.max_transaction_lifetime));
   EOS_ASSERT( now <= time_point(trx.expiration), transaction_exception, "transaction is expired",
861 862
              ("now",now)("trx.exp",trx.expiration));
} FC_CAPTURE_AND_RETHROW((trx)) }
863

864

865 866
void chain_controller::require_scope( const scope_name& scope )const {
   switch( uint64_t(scope) ) {
867 868
      case config::eosio_all_scope:
      case config::eosio_auth_scope:
869 870 871 872 873 874
         return; /// built in scopes
      default:
         require_account(scope);
   }
}

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

880
const producer_object& chain_controller::validate_block_header(uint32_t skip, const signed_block& next_block)const {
881 882
   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 已提交
883
   EOS_ASSERT(head_block_time() < (fc::time_point)next_block.timestamp, block_validate_exception, "",
884
              ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()));
K
Kevin Heifner 已提交
885
   if (((fc::time_point)next_block.timestamp) > head_block_time() + fc::microseconds(config::block_interval_ms*1000)) {
886
      elog("head_block_time ${h}, next_block ${t}, block_interval ${bi}",
887 888 889
           ("h", head_block_time())("t", next_block.timestamp)("bi", config::block_interval_ms));
      elog("Did not produce block within block_interval ${bi}ms, took ${t}ms)",
           ("bi", config::block_interval_ms)("t", (time_point(next_block.timestamp) - head_block_time()).count() / 1000));
890
   }
891 892

   if( !is_start_of_round( next_block.block_num() ) )  {
D
Daniel Larimer 已提交
893
      EOS_ASSERT(!next_block.new_producers, block_validate_exception,
894
                 "Producer changes may only occur at the end of a round.");
N
Nathan Hourt 已提交
895
   }
896

D
Daniel Larimer 已提交
897
   const producer_object& producer = get_producer(get_scheduled_producer(get_slot_at_time(next_block.timestamp)));
N
Nathan Hourt 已提交
898

N
Nathan Hourt 已提交
899
   if(!(skip&skip_producer_signature))
900 901 902
      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 已提交
903

904
   if(!(skip&skip_producer_schedule_check)) {
905 906 907
      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 已提交
908 909
   }

910

N
Nathan Hourt 已提交
911 912 913
   return producer;
}

914
void chain_controller::create_block_summary(const signed_block& next_block) {
915
   auto sid = next_block.block_num() & 0xffff;
916
   _db.modify( _db.get<block_summary_object,by_id>(sid), [&](block_summary_object& p) {
917 918
         p.block_id = next_block.id();
   });
N
Nathan Hourt 已提交
919 920
}

921 922
/**
 *  Takes the top config::producer_count producers by total vote excluding any producer whose
923
 *  block_signing_key is null.
924 925
 */
producer_schedule_type chain_controller::_calculate_producer_schedule()const {
926
   producer_schedule_type schedule = get_global_properties().new_active_producers;
927

928 929 930 931
   const auto& hps = _head_producer_schedule();
   schedule.version = hps.version;
   if( hps != schedule )
      ++schedule.version;
932 933 934 935 936 937
   return schedule;
}

/**
 *  Returns the most recent and/or pending producer schedule
 */
D
Daniel Larimer 已提交
938
const shared_producer_schedule_type& chain_controller::_head_producer_schedule()const {
939
   const auto& gpo = get_global_properties();
940
   if( gpo.pending_active_producers.size() )
941 942 943 944
      return gpo.pending_active_producers.back().second;
   return gpo.active_producers;
}

945
void chain_controller::update_global_properties(const signed_block& b) { try {
946 947
   // If we're at the end of a round, update the BlockchainConfiguration, producer schedule
   // and "producers" special account authority
948 949 950 951 952
   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" );
953 954 955
      }

      const auto& gpo = get_global_properties();
956 957 958

      if( _head_producer_schedule() != schedule ) {
         FC_ASSERT( b.new_producers, "pending producer set changed but block didn't indicate it" );
959
      }
960 961 962 963
      _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
D
Daniel Larimer 已提交
964 965 966 967 968
         {
            props.pending_active_producers.emplace_back( props.pending_active_producers.get_allocator() );// props.pending_active_producers.size()+1, props.pending_active_producers.get_allocator() );
            auto& back = props.pending_active_producers.back();
            back.first = b.block_num();
            back.second = schedule;
969

D
Daniel Larimer 已提交
970
         }
971 972
      });

973

974
      auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
975
      for(auto& name : gpo.active_producers.producers ) {
976
         active_producers_authority.accounts.push_back({{name.producer_name, config::active_name}, 1});
977 978
      }

979
      auto& po = _db.get<permission_object, by_owner>( boost::make_tuple(config::producers_account_name,
980
                                                                         config::active_name ) );
981 982 983
      _db.modify(po,[active_producers_authority] (permission_object& po) {
         po.auth = active_producers_authority;
      });
984
   }
985
} FC_CAPTURE_AND_RETHROW() }
986

987
void chain_controller::add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts ) {
988
   for (const auto& i : checkpts)
N
Nathan Hourt 已提交
989 990 991
      _checkpoints[i.first] = i.second;
}

992
bool chain_controller::before_last_checkpoint()const {
N
Nathan Hourt 已提交
993 994 995
   return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
}

996
const global_property_object& chain_controller::get_global_properties()const {
997
   return _db.get<global_property_object>();
N
Nathan Hourt 已提交
998 999
}

1000
const dynamic_global_property_object&chain_controller::get_dynamic_global_properties() const {
1001
   return _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
1002 1003
}

D
Daniel Larimer 已提交
1004
time_point chain_controller::head_block_time()const {
N
Nathan Hourt 已提交
1005 1006 1007
   return get_dynamic_global_properties().time;
}

1008
uint32_t chain_controller::head_block_num()const {
N
Nathan Hourt 已提交
1009 1010 1011
   return get_dynamic_global_properties().head_block_number;
}

1012
block_id_type chain_controller::head_block_id()const {
N
Nathan Hourt 已提交
1013 1014 1015
   return get_dynamic_global_properties().head_block_id;
}

D
Daniel Larimer 已提交
1016
account_name chain_controller::head_block_producer() const {
1017 1018 1019
   auto b = _fork_db.fetch_block(head_block_id());
   if( b ) return b->data.producer;

N
Nathan Hourt 已提交
1020
   if (auto head_block = fetch_block_by_id(head_block_id()))
1021
      return head_block->producer;
N
Nathan Hourt 已提交
1022 1023 1024
   return {};
}

1025
const producer_object& chain_controller::get_producer(const account_name& owner_name) const
D
Daniel Larimer 已提交
1026
{ try {
B
Bart Wyatt 已提交
1027
   return _db.get<producer_object, by_owner>(owner_name);
D
Daniel Larimer 已提交
1028
} FC_CAPTURE_AND_RETHROW( (owner_name) ) }
N
Nathan Hourt 已提交
1029

1030
const permission_object&   chain_controller::get_permission( const permission_level& level )const
1031 1032 1033 1034
{ try {
   return _db.get<permission_object, by_owner>( boost::make_tuple(level.actor,level.permission) );
} FC_CAPTURE_AND_RETHROW( (level) ) }

1035
uint32_t chain_controller::last_irreversible_block_num() const {
N
Nathan Hourt 已提交
1036
   return get_dynamic_global_properties().last_irreversible_block_num;
N
Nathan Hourt 已提交
1037 1038
}

D
Daniel Larimer 已提交
1039
void chain_controller::_initialize_indexes() {
1040 1041
   _db.add_index<account_index>();
   _db.add_index<permission_index>();
1042
   _db.add_index<permission_usage_index>();
1043
   _db.add_index<permission_link_index>();
1044
   _db.add_index<action_permission_index>();
D
Daniel Larimer 已提交
1045 1046 1047



1048 1049
   _db.add_index<contracts::table_id_multi_index>();
   _db.add_index<contracts::key_value_index>();
D
Daniel Larimer 已提交
1050
   _db.add_index<contracts::index64_index>();
1051
   _db.add_index<contracts::index128_index>();
1052
   _db.add_index<contracts::index256_index>();
D
Daniel Larimer 已提交
1053 1054


1055 1056
   _db.add_index<contracts::keystr_value_index>();
   _db.add_index<contracts::key128x128_value_index>();
1057
   _db.add_index<contracts::key64x64_value_index>();
1058
   _db.add_index<contracts::key64x64x64_value_index>();
1059 1060 1061 1062 1063

   _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>();
1064
   _db.add_index<generated_transaction_multi_index>();
1065
   _db.add_index<producer_multi_index>();
1066
   _db.add_index<scope_sequence_multi_index>();
1067 1068
   _db.add_index<bandwidth_usage_index>();
   _db.add_index<compute_usage_index>();
N
Nathan Hourt 已提交
1069 1070
}

D
Daniel Larimer 已提交
1071
void chain_controller::_initialize_chain(contracts::chain_initializer& starter)
N
Nathan Hourt 已提交
1072
{ try {
1073
   if (!_db.find<global_property_object>()) {
N
Nathan Hourt 已提交
1074 1075
      _db.with_write_lock([this, &starter] {
         auto initial_timestamp = starter.get_chain_start_time();
D
Daniel Larimer 已提交
1076 1077 1078
         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 已提交
1079

1080
         // Create global properties
1081
         const auto& gp = _db.create<global_property_object>([&starter](global_property_object& p) {
N
Nathan Hourt 已提交
1082 1083
            p.configuration = starter.get_chain_start_configuration();
            p.active_producers = starter.get_chain_start_producers();
1084
            p.new_active_producers = starter.get_chain_start_producers();
1085
            wdump((starter.get_chain_start_producers()));
1086
         });
1087

1088
         _db.create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
N
Nathan Hourt 已提交
1089
            p.time = initial_timestamp;
1090
            p.recent_slots_filled = uint64_t(-1);
1091 1092
            p.virtual_net_bandwidth = gp.configuration.max_block_size * (config::blocksize_average_window_ms / config::block_interval_ms );
            p.virtual_act_bandwidth = gp.configuration.max_block_acts * (config::blocksize_average_window_ms / config::block_interval_ms );
1093
         });
N
Nathan Hourt 已提交
1094

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

B
Bart Wyatt 已提交
1099
         starter.prepare_database(*this, _db);
1100

B
Bart Wyatt 已提交
1101
         ilog( "done initializing chain" );
1102 1103
      });
   }
N
Nathan Hourt 已提交
1104 1105
} FC_CAPTURE_AND_RETHROW() }

N
Nathan Hourt 已提交
1106

1107
void chain_controller::replay() {
1108
   ilog("Replaying blockchain");
N
Nathan Hourt 已提交
1109
   auto start = fc::time_point::now();
K
Kevin Heifner 已提交
1110

K
Kevin Heifner 已提交
1111
   auto on_exit = fc::make_scoped_exit([&_currently_replaying_blocks = _currently_replaying_blocks](){
K
Kevin Heifner 已提交
1112 1113 1114 1115
      _currently_replaying_blocks = false;
   });
   _currently_replaying_blocks = true;

1116 1117 1118
   auto last_block = _block_log.read_head();
   if (!last_block) {
      elog("No blocks in block log; skipping replay");
N
Nathan Hourt 已提交
1119 1120 1121 1122 1123
      return;
   }

   const auto last_block_num = last_block->block_num();

1124
   ilog("Replaying ${n} blocks...", ("n", last_block_num) );
1125 1126 1127 1128 1129
   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 已提交
1130
      _apply_block(*block, skip_producer_signature |
N
Nathan Hourt 已提交
1131 1132 1133 1134
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_producer_schedule_check |
1135 1136
                          skip_authority_check |
                          received_block);
N
Nathan Hourt 已提交
1137 1138
   }
   auto end = fc::time_point::now();
1139 1140
   ilog("Done replaying ${n} blocks, elapsed time: ${t} sec",
        ("n", head_block_num())("t",double((end-start).count())/1000000.0));
N
Nathan Hourt 已提交
1141

1142
   _db.set_revision(head_block_num());
1143
}
N
Nathan Hourt 已提交
1144

D
Daniel Larimer 已提交
1145
void chain_controller::_spinup_db() {
1146 1147 1148 1149 1150
   // 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()));
1151

1152 1153
   });
}
N
Nathan Hourt 已提交
1154

D
Daniel Larimer 已提交
1155
void chain_controller::_spinup_fork_db()
N
Nathan Hourt 已提交
1156
{
1157 1158 1159 1160 1161 1162 1163 1164
   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 已提交
1165 1166
}

D
Daniel Larimer 已提交
1167
/*
1168 1169
ProducerRound chain_controller::calculate_next_round(const signed_block& next_block) {
   auto schedule = _admin->get_next_round(_db);
N
Nathan Hourt 已提交
1170 1171 1172 1173
   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));
1174

P
Pravin 已提交
1175 1176
   fc::time_point tp = (fc::time_point)next_block.timestamp;
   utilities::rand::random rng(tp.sec_since_epoch());
1177 1178
   rng.shuffle(schedule);
   return schedule;
D
Daniel Larimer 已提交
1179
}*/
1180

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

1184 1185 1186
   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 已提交
1187
   uint32_t missed_blocks = head_block_num() == 0? 1 : get_slot_at_time((fc::time_point)b.timestamp);
1188
   assert(missed_blocks != 0);
N
Nathan Hourt 已提交
1189
   missed_blocks--;
N
Nathan Hourt 已提交
1190

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

1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
   if (!(_skip_flags & skip_missed_block_penalty)) {
      for (uint32_t i = 0; i < missed_blocks; ++i) {
         const auto &producer_missed = get_producer(get_scheduled_producer(i + 1));
         if (producer_missed.owner != b.producer) {
            /*
            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) );
               */

            _db.modify(producer_missed, [&](producer_object &w) {
               w.total_missed++;
            });
         }
N
Nathan Hourt 已提交
1208 1209 1210
      }
   }

1211 1212
   const auto& props = get_global_properties();

N
Nathan Hourt 已提交
1213
   // dynamic global properties updating
1214
   _db.modify( _dgp, [&]( dynamic_global_property_object& dgp ){
N
Nathan Hourt 已提交
1215 1216 1217
      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
1218
      dgp.current_producer = b.producer;
N
Nathan Hourt 已提交
1219
      dgp.current_absolute_slot += missed_blocks+1;
1220 1221 1222 1223 1224
      dgp.average_block_size.add_usage( fc::raw::pack_size(b), b.timestamp );

      dgp.update_virtual_net_bandwidth( props.configuration );
      dgp.update_virtual_act_bandwidth( props.configuration );

N
Nathan Hourt 已提交
1225 1226 1227 1228 1229 1230

      // 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;
1231
      } else
1232
         if(config::percent_100 * get_global_properties().active_producers.producers.size() / blocks_per_round() > config::required_producer_participation)
1233 1234 1235
            dgp.recent_slots_filled = uint64_t(-1);
         else
            dgp.recent_slots_filled = 0;
1236
      dgp.block_merkle_root.append( head_block_id() );
N
Nathan Hourt 已提交
1237 1238 1239 1240 1241
   });

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

1242
void chain_controller::update_signing_producer(const producer_object& signing_producer, const signed_block& new_block)
N
Nathan Hourt 已提交
1243 1244
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
P
Pravin 已提交
1245
   uint64_t new_block_aslot = dpo.current_absolute_slot + get_slot_at_time( (fc::time_point)new_block.timestamp );
N
Nathan Hourt 已提交
1246

1247
   _db.modify( signing_producer, [&]( producer_object& _wit )
N
Nathan Hourt 已提交
1248 1249 1250 1251 1252 1253
   {
      _wit.last_aslot = new_block_aslot;
      _wit.last_confirmed_block_num = new_block.block_num();
   } );
}

1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
void chain_controller::update_or_create_producers( const producer_schedule_type& producers ) {
   for ( auto prod : producers.producers ) {
      if ( _db.find<producer_object, by_owner>(prod.producer_name) == nullptr ) {
         _db.create<producer_object>( [&]( auto& pro ) {
            pro.owner       = prod.producer_name;
            pro.signing_key = prod.block_signing_key;
         });
      }
   }
}

1265
void chain_controller::update_last_irreversible_block()
N
Nathan Hourt 已提交
1266 1267 1268 1269
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

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

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

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

D
Daniel Larimer 已提交
1279
   size_t offset = EOS_PERCENT(producer_objs.size(), config::percent_100- config::irreversible_threshold_percent);
1280 1281
   std::nth_element(producer_objs.begin(), producer_objs.begin() + offset, producer_objs.end(),
      [](const producer_object* a, const producer_object* b) {
N
Nathan Hourt 已提交
1282
         return a->last_confirmed_block_num < b->last_confirmed_block_num;
1283
      });
N
Nathan Hourt 已提交
1284

1285 1286 1287 1288 1289 1290
   uint32_t new_last_irreversible_block_num = producer_objs[offset]->last_confirmed_block_num;
   // TODO: right now the code cannot handle the head block being irreversible for reasons that are purely
   // implementation details.  We can and should remove this special case once the rest of the logic is fixed.
   if (producer_objs.size() == 1) {
      new_last_irreversible_block_num -= 1;
   }
1291

N
Nathan Hourt 已提交
1292

1293
   if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) {
1294
      _db.modify(dpo, [&](dynamic_global_property_object& _dpo) {
N
Nathan Hourt 已提交
1295
         _dpo.last_irreversible_block_num = new_last_irreversible_block_num;
1296
      });
N
Nathan Hourt 已提交
1297
   }
1298 1299

   // Write newly irreversible blocks to disk. First, get the number of the last block on disk...
1300
   auto old_last_irreversible_block = _block_log.head();
1301
   unsigned last_block_on_disk = 0;
1302 1303 1304
   // 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();
1305

1306
   if (last_block_on_disk < new_last_irreversible_block_num) {
1307 1308 1309 1310
      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);
1311
         FC_ASSERT( block, "unable to find last irreversible block to write" );
1312
         _block_log.append(*block);
K
Kevin Heifner 已提交
1313
         applied_irreversible_block(*block);
1314
      }
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
   }

   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 ) {
1326
         update_or_create_producers( *new_producer_schedule );
1327
         _db.modify( gpo, [&]( auto& props ){
1328
              boost::range::remove_erase_if(props.pending_active_producers,
1329
                                            [new_last_irreversible_block_num](const typename decltype(props.pending_active_producers)::value_type& v) -> bool {
1330 1331
                                               return v.first < new_last_irreversible_block_num;
                                            });
1332
              props.active_producers = *new_producer_schedule;
1333 1334 1335 1336
         });
      }
   }

N
Nathan Hourt 已提交
1337 1338
   // Trim fork_database and undo histories
   _fork_db.set_max_size(head_block_num() - new_last_irreversible_block_num + 1);
1339
   _db.commit(new_last_irreversible_block_num);
N
Nathan Hourt 已提交
1340 1341
}

1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
void chain_controller::update_rate_limiting()
{
   const auto* ptu = _db.find<pending_total_usage_object>();
   if (ptu) {
      auto& gdp = get_dynamic_global_properties();
      _db.modify( gdp, [&]( dynamic_global_property_object& p ) {
         p.total_net_weight = ptu->total_net_weight;
         p.total_cpu_weight = ptu->total_cpu_weight;
         p.total_db_capacity = ptu->total_db_capacity;
      });
   }
}

1355
void chain_controller::clear_expired_transactions()
N
Nathan Hourt 已提交
1356 1357
{ try {
   //Look for expired transactions in the deduplication list, and remove them.
D
Daniel Larimer 已提交
1358
   //transactions must have expired by at least two forking windows in order to be removed.
D
Daniel Larimer 已提交
1359
   /*
1360
   auto& transaction_idx = _db.get_mutable_index<transaction_multi_index>();
N
Nathan Hourt 已提交
1361
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
D
Daniel Larimer 已提交
1362
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->expiration) )
N
Nathan Hourt 已提交
1363
      transaction_idx.remove(*dedupe_index.rbegin());
B
Bart Wyatt 已提交
1364
      */
1365
   //Look for expired transactions in the pending generated list, and remove them.
D
Daniel Larimer 已提交
1366
   //transactions must have expired by at least two forking windows in order to be removed.
1367
   auto& generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
B
Bart Wyatt 已提交
1368 1369
   const auto& generated_index = generated_transaction_idx.indices().get<by_expiration>();
   while( (!generated_index.empty()) && (head_block_time() > generated_index.rbegin()->expiration) )
1370
      generated_transaction_idx.remove(*generated_index.rbegin());
B
Bart Wyatt 已提交
1371

N
Nathan Hourt 已提交
1372 1373 1374 1375
} FC_CAPTURE_AND_RETHROW() }

using boost::container::flat_set;

D
Daniel Larimer 已提交
1376
account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const
N
Nathan Hourt 已提交
1377 1378
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1379
   uint64_t current_aslot = dpo.current_absolute_slot + slot_num;
1380
   const auto& gpo = _db.get<global_property_object>();
1381
   auto number_of_active_producers = gpo.active_producers.producers.size();
1382 1383
   auto index = current_aslot % (number_of_active_producers * config::producer_repetitions);
   index /= config::producer_repetitions;
1384 1385
   FC_ASSERT( gpo.active_producers.producers.size() > 0, "no producers defined" );

1386
   return gpo.active_producers.producers[index].producer_name;
N
Nathan Hourt 已提交
1387 1388
}

D
Daniel Larimer 已提交
1389
block_timestamp_type chain_controller::get_slot_time(uint32_t slot_num)const
N
Nathan Hourt 已提交
1390
{
P
Pravin 已提交
1391
   if( slot_num == 0)
D
Daniel Larimer 已提交
1392
      return block_timestamp_type();
N
Nathan Hourt 已提交
1393 1394 1395 1396 1397 1398

   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 已提交
1399 1400 1401
      auto genesis_time = block_timestamp_type(dpo.time);
      genesis_time.slot += slot_num;
      return (fc::time_point)genesis_time;
N
Nathan Hourt 已提交
1402 1403
   }

D
Daniel Larimer 已提交
1404
   auto head_block_abs_slot = block_timestamp_type(head_block_time());
P
Pravin 已提交
1405
   head_block_abs_slot.slot += slot_num;
D
Daniel Larimer 已提交
1406
   return head_block_abs_slot;
N
Nathan Hourt 已提交
1407 1408
}

D
Daniel Larimer 已提交
1409
uint32_t chain_controller::get_slot_at_time( block_timestamp_type when )const
N
Nathan Hourt 已提交
1410
{
D
Daniel Larimer 已提交
1411
   auto first_slot_time = get_slot_time(1);
N
Nathan Hourt 已提交
1412 1413
   if( when < first_slot_time )
      return 0;
D
Daniel Larimer 已提交
1414
   return block_timestamp_type(when).slot - first_slot_time.slot + 1;
N
Nathan Hourt 已提交
1415 1416
}

1417
uint32_t chain_controller::producer_participation_rate()const
N
Nathan Hourt 已提交
1418 1419
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
D
Daniel Larimer 已提交
1420
   return uint64_t(config::percent_100) * __builtin_popcountll(dpo.recent_slots_filled) / 64;
N
Nathan Hourt 已提交
1421 1422
}

D
Daniel Larimer 已提交
1423 1424
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;
1425
}
N
Nathan Hourt 已提交
1426

1427
static void log_handled_exceptions(const transaction& trx) {
B
Bart Wyatt 已提交
1428 1429 1430 1431
   try {
      throw;
   } catch (const checktime_exceeded&) {
      throw;
1432
   } FC_CAPTURE_AND_LOG((trx));
B
Bart Wyatt 已提交
1433 1434
}

1435 1436
transaction_trace chain_controller::__apply_transaction( transaction_metadata& meta ) {
   transaction_trace result(meta.id);
D
Daniel Larimer 已提交
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447

   for (const auto &act : meta.trx().context_free_actions) {
      FC_ASSERT( act.authorization.size() == 0, "context free actions cannot require authorization" );
      apply_context context(*this, _db, act, meta);
      context.context_free = true;
      context.exec();
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
      FC_ASSERT( result.deferred_transactions.size() == 0 );
      FC_ASSERT( result.canceled_deferred.size() == 0 );
   }

1448
   for (const auto &act : meta.trx().actions) {
1449
      apply_context context(*this, _db, act, meta);
1450
      context.exec();
D
Daniel Larimer 已提交
1451 1452 1453
      context.used_context_free_api |= act.authorization.size();

      FC_ASSERT( context.used_context_free_api, "action did not reference database state, it should be moved to context_free_actions", ("act",act) );
1454 1455
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
1456
      fc::move_append(result.canceled_deferred, std::move(context.results.canceled_deferred));
1457
   }
B
Bart Wyatt 已提交
1458

1459
   uint32_t act_usage = result.action_traces.size();
1460

1461 1462 1463 1464
   for (auto &at: result.action_traces) {
      at.region_id = meta.region_id;
      at.cycle_index = meta.cycle_index;
      if (at.receiver == config::system_account_name &&
B
Bart Wyatt 已提交
1465
          at.act.account == config::system_account_name &&
1466 1467
          at.act.name == N(setcode)) {
         act_usage += config::setcode_act_usage;
B
Bart Wyatt 已提交
1468
      }
1469
   }
B
Bart Wyatt 已提交
1470

1471
   update_usage(meta, act_usage);
1472
   record_transaction(meta.trx());
1473 1474
   return result;
}
B
Bart Wyatt 已提交
1475

1476 1477 1478 1479 1480 1481
transaction_trace chain_controller::_apply_transaction( transaction_metadata& meta ) {
   try {
      auto temp_session = _db.start_undo_session(true);
      auto result = __apply_transaction(meta);
      temp_session.squash();
      return result;
B
Bart Wyatt 已提交
1482 1483
   } catch (...) {
      // if there is no sender, there is no error handling possible, rethrow
1484
      if (!meta.sender) {
B
Bart Wyatt 已提交
1485 1486
         throw;
      }
1487
      // log exceptions we can handle with the error handle, throws otherwise
1488
      log_handled_exceptions(meta.trx());
1489

B
Bart Wyatt 已提交
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
      return _apply_error( meta );
   }
}

transaction_trace chain_controller::_apply_error( transaction_metadata& meta ) {
   transaction_trace result(meta.id);
   result.status = transaction_trace::soft_fail;

   transaction etrx;
   etrx.actions.emplace_back(vector<permission_level>{{meta.sender_id,config::active_name}},
1500
                             contracts::onerror(meta.raw_data, meta.raw_data + meta.raw_size) );
B
Bart Wyatt 已提交
1501 1502

   try {
1503 1504
      auto temp_session = _db.start_undo_session(true);

1505
      apply_context context(*this, _db, etrx.actions.front(), meta);
D
Daniel Larimer 已提交
1506
      context.exec();
1507
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
B
Bart Wyatt 已提交
1508 1509
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));

B
Bart Wyatt 已提交
1510
      uint32_t act_usage = result.action_traces.size();
1511

B
Bart Wyatt 已提交
1512 1513 1514
      for (auto &at: result.action_traces) {
         at.region_id = meta.region_id;
         at.cycle_index = meta.cycle_index;
1515
      }
1516

B
Bart Wyatt 已提交
1517
      update_usage(meta, act_usage);
1518
      record_transaction(meta.trx());
1519 1520

      temp_session.squash();
B
Bart Wyatt 已提交
1521
      return result;
1522

B
Bart Wyatt 已提交
1523
   } catch (...) {
1524 1525 1526 1527
      // log exceptions we can handle with the error handle, throws otherwise
      log_handled_exceptions(etrx);

      // fall through to marking this tx as hard-failing
B
Bart Wyatt 已提交
1528 1529 1530 1531
   }

   // if we have an objective error, on an error handler, we return hard fail for the trx
   result.status = transaction_trace::hard_fail;
1532 1533 1534
   return result;
}

1535
void chain_controller::push_deferred_transactions( bool flush )
B
Bart Wyatt 已提交
1536
{
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
   if (flush && _pending_cycle_trace && _pending_cycle_trace->shard_traces.size() > 0) {
      // TODO: when we go multithreaded this will need a better way to see if there are flushable
      // deferred transactions in the shards
      auto maybe_start_new_cycle = [&]() {
         for (const auto &st: _pending_cycle_trace->shard_traces) {
            for (const auto &tr: st.transaction_traces) {
               for (const auto &dt: tr.deferred_transactions) {
                  if (fc::time_point(dt.execute_after) <= head_block_time()) {
                     // force a new cycle and break out
                     _finalize_pending_cycle();
                     _start_pending_cycle();
                     return;
                  }
               }
            }
         }
      };
B
Bart Wyatt 已提交
1554

1555 1556
      maybe_start_new_cycle();
   }
B
Bart Wyatt 已提交
1557

1558 1559 1560
   auto& generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
   auto& generated_index = generated_transaction_idx.indices().get<by_delay>();
   vector<const generated_transaction_object*> candidates;
B
Bart Wyatt 已提交
1561

1562 1563 1564 1565
   for( auto itr = generated_index.rbegin(); itr != generated_index.rend() && (head_block_time() >= itr->delay_until); ++itr) {
      const auto &gtrx = *itr;
      candidates.emplace_back(&gtrx);
   }
B
Bart Wyatt 已提交
1566

1567 1568 1569 1570
   for (const auto* trx_p: candidates) {
      if (!is_known_transaction(trx_p->trx_id)) {
         try {
            auto trx = fc::raw::unpack<deferred_transaction>(trx_p->packed_trx.data(), trx_p->packed_trx.size());
1571
            transaction_metadata mtrx (trx, trx_p->published, trx.sender, trx.sender_id, trx_p->packed_trx.data(), trx_p->packed_trx.size());
1572
            _push_transaction(std::move(mtrx));
1573 1574 1575 1576 1577
            generated_transaction_idx.remove(*trx_p);
         } FC_CAPTURE_AND_LOG((trx_p->trx_id)(trx_p->sender));
      } else {
         generated_transaction_idx.remove(*trx_p);
      }
B
Bart Wyatt 已提交
1578 1579 1580 1581
   }
}


1582 1583 1584 1585 1586
/**
 *  @param act_usage The number of "actions" delivered directly or indirectly by applying meta.trx
 */
void chain_controller::update_usage( transaction_metadata& meta, uint32_t act_usage )
{
1587
   set<std::pair<account_name, permission_name>> authorizing_accounts;
1588

1589
   for( const auto& act : meta.trx().actions )
1590
      for( const auto& auth : act.authorization )
1591
         authorizing_accounts.emplace( auth.actor, auth.permission );
1592

1593 1594 1595
   auto trx_size = meta.bandwidth_usage + config::fixed_bandwidth_overhead_per_transaction;

   const auto& dgpo = get_dynamic_global_properties();
1596

1597 1598 1599 1600
   if( meta.signing_keys ) {
      act_usage += meta.signing_keys->size();
   }

1601 1602
   auto head_time = head_block_time();
   for( const auto& authaccnt : authorizing_accounts ) {
1603

B
Bart Wyatt 已提交
1604
      const auto& buo = _db.get<resource_limits_object,by_owner>( authaccnt.first );
1605
      _db.modify( buo, [&]( auto& bu ){
1606
          bu.bytes.add_usage( trx_size, head_time );
1607
          bu.acts.add_usage( act_usage, head_time );
1608
      });
1609

1610 1611 1612 1613
      uint128_t  used_ubytes        = buo.bytes.value;
      uint128_t  used_uacts         = buo.acts.value;
      uint128_t  virtual_max_ubytes = dgpo.virtual_net_bandwidth * config::rate_limiting_precision;
      uint128_t  virtual_max_uacts  = dgpo.virtual_act_bandwidth * config::rate_limiting_precision;
1614

1615
      if( !(_skip_flags & genesis_setup) ) {
K
Kevin Heifner 已提交
1616 1617
         #warning TODO: restore bandwidth checks
         /* setting of bandwidth currently not implemented
1618
         FC_ASSERT( (used_ubytes * dgpo.total_net_weight) <=  (buo.net_weight * virtual_max_ubytes), "authorizing account '${n}' has insufficient net bandwidth for this transaction",
1619
                    ("n",name(authaccnt.first))
1620
                    ("used_bytes",double(used_ubytes)/1000000.)
1621
                    ("user_net_weight",buo.net_weight)
1622
                    ("virtual_max_bytes", double(virtual_max_ubytes)/1000000. )
1623
                    ("total_net_weight", dgpo.total_net_weight)
1624
                    );
1625
         FC_ASSERT( (used_uacts * dgpo.total_cpu_weight)  <=  (buo.cpu_weight* virtual_max_uacts),  "authorizing account '${n}' has insufficient compute bandwidth for this transaction",
1626
                    ("n",name(authaccnt.first))
1627
                    ("used_acts",double(used_uacts)/1000000.)
1628
                    ("user_cpu_weight",buo.cpu_weight)
1629
                    ("virtual_max_uacts", double(virtual_max_uacts)/1000000. )
1630 1631
                    ("total_cpu_tokens", dgpo.total_cpu_weight)
                  );
K
Kevin Heifner 已提交
1632
         */
1633
      }
1634 1635 1636

      // for any transaction not sent by code, update the affirmative last time a given permission was used
      if (!meta.sender) {
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
         const auto *puo = _db.find<permission_usage_object, by_account_permission>(boost::make_tuple(authaccnt.first, authaccnt.second));
         if (puo) {
            _db.modify(*puo, [this](permission_usage_object &pu) {
               pu.last_used = head_block_time();
            });
         } else {
            _db.create<permission_usage_object>([this, &authaccnt](permission_usage_object &pu){
               pu.account = authaccnt.first;
               pu.permission = authaccnt.second;
               pu.last_used = head_block_time();
            });
         }
1649
      }
1650 1651
   }

1652 1653 1654 1655
   _db.modify( dgpo, [&]( auto& props ) {
      props.average_block_acts.add_usage( act_usage, head_time );
   });

D
Daniel Larimer 已提交
1656 1657 1658 1659 1660 1661 1662
}

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 ) );
1663
      if( handler != native_handler_scope->second.end() )
D
Daniel Larimer 已提交
1664 1665 1666 1667 1668
         return &handler->second;
   }
   return nullptr;
}

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