chain_controller.cpp 62.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>
7
#include <eosio/chain/contracts/staked_balance_objects.hpp>
N
Nathan Hourt 已提交
8

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

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

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

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

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

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

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

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

D
Daniel Larimer 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
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();
}

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

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

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

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

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

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

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

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 {
D
Daniel Larimer 已提交
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 signed_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 signed_transaction& trx) {
B
Bart Wyatt 已提交
259
   check_transaction_authorization(trx);
260
   transaction_metadata   mtrx( trx, get_chain_id(), head_block_time());
B
Bart Wyatt 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

   auto result = _push_transaction(mtrx);

   _pending_block->input_transactions.push_back(trx);

   // notify anyone listening to pending transactions
   on_pending_transaction(trx);

   return result;

}

transaction_trace chain_controller::_push_transaction( transaction_metadata& data )
{
   const transaction& trx = data.trx;
276
   bool force_new_cycle = false;
277 278
   // 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 已提交
279
   if( !_pending_block ) {
D
Daniel Larimer 已提交
280
      _start_pending_block();
D
Daniel Larimer 已提交
281
   }
282

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

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

288
   auto shardnum = 0;
289
   auto cyclenum = _pending_block->regions.back().cycles_summary.size() - 1;
290 291 292 293 294 295
   bool new_cycle = false;

   if (!force_new_cycle) {
      shardnum = _pending_cycle.schedule( trx );
   }
   if (shardnum == -1 || force_new_cycle) {
296
      cyclenum += 1;
297 298
      shardnum = 0;
      new_cycle = true;
299 300
   }

301 302 303
   /// 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 已提交
304 305 306 307 308
   // set cycle, shard, region etc
   data.region_id = 0;
   data.cycle_index = cyclenum;
   data.shard_index = shardnum;
   auto result = _apply_transaction( data );
309

310
   if( new_cycle ) { /// schedule conflict start new cycle
311 312
      _finalize_pending_cycle();
      _start_pending_cycle();
313
      FC_ASSERT(_pending_cycle.schedule( trx ) == shardnum);
314 315
   }

316

317
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
318
   if( shardnum >= bcycle.size() ) {
319
      _start_pending_shard();
320 321
   }

322

323
   bcycle.at(shardnum).emplace_back( result );
324
   _pending_cycle_trace->shard_traces.at(shardnum).append(result);
B
Bart Wyatt 已提交
325

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

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

332 333 334 335 336 337
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);
338 339
   _pending_block->regions.resize(1);
   _pending_block_trace->region_traces.resize(1);
340 341 342
   _start_pending_cycle();
}

343 344
/**
 *  Wraps up all work for current shards, starts a new cycle, and
345
 *  executes any pending transactions
346
 */
347
void chain_controller::_start_pending_cycle() {
348
   _pending_block->regions.back().cycles_summary.resize( _pending_block->regions[0].cycles_summary.size() + 1 );
349
   _pending_cycle = pending_cycle_state();
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 412 413 414 415 416 417 418 419 420
         ///TODO: hook this up as a signal handler in a de-coupled "logger" that may just silently drop them
         for (const auto &ar : tr.action_traces) {
            if (!ar.console.empty()) {
               auto prefix = fc::format_string(
                  "[(${s},${a})->${r}]",
                  fc::mutable_variant_object()
                     ("s", ar.act.scope)
                     ("a", ar.act.name)
                     ("r", ar.receiver));
               std::cerr << prefix << ": CONSOLE OUTPUT BEGIN =====================" << std::endl;
               std::cerr << ar.console;
               std::cerr << prefix << ": CONSOLE OUTPUT END   =====================" << std::endl;
            }
421
         }
B
Bart Wyatt 已提交
422 423 424 425
      }
   }
}

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

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

   create_block_summary(b);
   clear_expired_transactions();

442
   applied_block( trace ); //emit
443 444 445 446 447
   if (_currently_replaying_blocks)
     applied_irreversible_block(b);

} FC_CAPTURE_AND_RETHROW( (trace.block) ) }

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

D
Daniel Larimer 已提交
462 463 464 465 466
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 已提交
467 468
   uint32_t slot_num = get_slot_at_time( when );
   FC_ASSERT( slot_num > 0 );
D
Daniel Larimer 已提交
469
   account_name scheduled_producer = get_scheduled_producer( slot_num );
N
Nathan Hourt 已提交
470
   FC_ASSERT( scheduled_producer == producer );
N
Nathan Hourt 已提交
471

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

D
Daniel Larimer 已提交
474
   if( !_pending_block ) {
D
Daniel Larimer 已提交
475
      _start_pending_block();
476 477
   }

478
   _finalize_pending_cycle();
479

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

483 484 485 486 487 488 489
      _pending_block->timestamp   = when;
      _pending_block->producer    = producer_obj.owner;
      _pending_block->previous    = head_block_id();
      _pending_block->block_mroot = get_dynamic_global_properties().block_merkle_root.get_root();
      _pending_block->transaction_mroot = _pending_block->calculate_transaction_merkle_root();
      _pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root();

490

491
      if( is_start_of_round( _pending_block->block_num() ) ) {
492 493 494
      auto latest_producer_schedule = _calculate_producer_schedule();
      if( latest_producer_schedule != _head_producer_schedule() )
         _pending_block->new_producers = latest_producer_schedule;
495 496
   }

N
Nathan Hourt 已提交
497
   if( !(skip & skip_producer_signature) )
D
Daniel Larimer 已提交
498
      _pending_block->sign( block_signing_key );
N
Nathan Hourt 已提交
499

500
   _finalize_block( *_pending_block_trace );
D
Daniel Larimer 已提交
501

502 503
   _pending_block_session->push();

D
Daniel Larimer 已提交
504 505
   auto result = move( *_pending_block );

506
   _pending_block_trace.reset();
507 508 509
   _pending_block.reset();
   _pending_block_session.reset();

D
Daniel Larimer 已提交
510
   if (!(skip&skip_fork_db)) {
D
Daniel Larimer 已提交
511
      _fork_db.push_block(result);
N
Nathan Hourt 已提交
512
   }
D
Daniel Larimer 已提交
513
   return result;
N
Nathan Hourt 已提交
514

N
Nathan Hourt 已提交
515
} FC_CAPTURE_AND_RETHROW( (producer) ) }
N
Nathan Hourt 已提交
516 517

/**
N
Nathan Hourt 已提交
518
 * Removes the most recent block from the database and undoes any changes it made.
N
Nathan Hourt 已提交
519
 */
520
void chain_controller::pop_block()
N
Nathan Hourt 已提交
521
{ try {
D
Daniel Larimer 已提交
522
   _pending_block_session.reset();
N
Nathan Hourt 已提交
523 524 525 526 527
   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();
528
   _db.undo();
N
Nathan Hourt 已提交
529 530
} FC_CAPTURE_AND_RETHROW() }

531
void chain_controller::clear_pending()
N
Nathan Hourt 已提交
532
{ try {
533
   _pending_block_trace.reset();
D
Daniel Larimer 已提交
534
   _pending_block.reset();
D
Daniel Larimer 已提交
535
   _pending_block_session.reset();
N
Nathan Hourt 已提交
536 537 538 539
} FC_CAPTURE_AND_RETHROW() }

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

D
Daniel Larimer 已提交
540
void chain_controller::_apply_block(const signed_block& next_block, uint32_t skip)
N
Nathan Hourt 已提交
541 542
{
   auto block_num = next_block.block_num();
543 544 545 546 547
   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 已提交
548

549
      if (_checkpoints.rbegin()->first >= block_num)
N
Nathan Hourt 已提交
550 551
         skip = ~0;// WE CAN SKIP ALMOST EVERYTHING
   }
N
Nathan Hourt 已提交
552 553 554

   with_applying_block([&] {
      with_skip_flags(skip, [&] {
D
Daniel Larimer 已提交
555
         __apply_block(next_block);
N
Nathan Hourt 已提交
556 557
      });
   });
N
Nathan Hourt 已提交
558 559
}

560

D
Daniel Larimer 已提交
561
void chain_controller::__apply_block(const signed_block& next_block)
N
Nathan Hourt 已提交
562
{ try {
N
Nathan Hourt 已提交
563
   uint32_t skip = _skip_flags;
N
Nathan Hourt 已提交
564

D
Daniel Larimer 已提交
565 566 567
   /*
   FC_ASSERT((skip & skip_merkle_check) 
             || next_block.transaction_merkle_root == next_block.calculate_merkle_root(),
568 569
             "", ("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 已提交
570
             */
N
Nathan Hourt 已提交
571 572

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

574 575 576 577
   /// 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 );

578 579 580 581 582 583 584

   /// 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;
   }
585 586

   block_trace next_block_trace(next_block);
587 588
   next_block_trace.region_traces.reserve(next_block.regions.size());

589
   for( const auto& r : next_block.regions ) {
590 591 592
      region_trace r_trace;
      r_trace.cycle_traces.reserve(r.cycles_summary.size());

593
      for (uint32_t cycle_index = 0; cycle_index < r.cycles_summary.size(); cycle_index++) {
594
         const auto& cycle = r.cycles_summary.at(cycle_index);
595 596 597
         cycle_trace c_trace;
         c_trace.shard_traces.reserve(cycle.size());

598
         uint32_t shard_index = 0;
599
         for (const auto& shard: cycle) {
600
            shard_trace s_trace;
601
            for (const auto& receipt : shard) {
602
                auto make_metadata = [&](){
603 604
                  auto itr = trx_index.find(receipt.id);
                  if( itr != trx_index.end() ) {
605
                     return transaction_metadata( *itr->second, get_chain_id(), next_block.timestamp );
B
Bart Wyatt 已提交
606
                  } else {
607
                     const auto& gtrx = _db.get<generated_transaction_object,by_trx_id>(receipt.id);
B
Bart Wyatt 已提交
608
                     auto trx = fc::raw::unpack<deferred_transaction>(gtrx.packed_trx.data(), gtrx.packed_trx.size());
609
                     return transaction_metadata(trx, gtrx.published, trx.sender, trx.sender_id, gtrx.packed_trx.data(), gtrx.packed_trx.size() );
610
                  }
611
               };
B
Bart Wyatt 已提交
612

613 614 615 616
               auto mtrx = make_metadata();
               mtrx.region_id = r.region;
               mtrx.cycle_index = cycle_index;
               mtrx.shard_index = shard_index;
B
Bart Wyatt 已提交
617

618 619 620
               s_trace.transaction_traces.emplace_back(_apply_transaction(mtrx));

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

622 623 624 625 626
               // 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 已提交
627

628
            ++shard_index;
629 630 631
            s_trace.calculate_root();
            c_trace.shard_traces.emplace_back(move(s_trace));
         } /// for each shard
D
Daniel Larimer 已提交
632

633 634 635
         _apply_cycle_trace(c_trace);
         r_trace.cycle_traces.emplace_back(move(c_trace));
      } /// for each cycle
D
Daniel Larimer 已提交
636

637 638
      next_block_trace.region_traces.emplace_back(move(r_trace));
   } /// for each region
N
Nathan Hourt 已提交
639

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

642 643
   _finalize_block( next_block_trace );
} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) )  }
D
Daniel Larimer 已提交
644

645
flat_set<public_key_type> chain_controller::get_required_keys(const signed_transaction& trx,
B
Bart Wyatt 已提交
646
                                                              const flat_set<public_key_type>& candidate_keys)const 
D
Daniel Larimer 已提交
647
{
648
   auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
649 650
                                     get_global_properties().configuration.max_authority_depth,
                                     candidate_keys);
651

D
Daniel Larimer 已提交
652 653 654 655
   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 已提交
656
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
657
                       ("auth", declared_auth));
658 659 660 661 662 663 664
         }
      }
   }

   return checker.used_keys();
}

665
void chain_controller::check_authorization( const vector<action>& actions,
666 667 668
                                            flat_set<public_key_type> provided_keys,
                                            bool allow_unused_signatures,
                                            flat_set<account_name>    provided_accounts  )const
D
Daniel Larimer 已提交
669
{
670
   auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
671
                                     get_global_properties().configuration.max_authority_depth,
672 673
                                     provided_keys, provided_accounts );

N
Nathan Hourt 已提交
674

675
   for( const auto& act : actions ) {
676
      for( const auto& declared_auth : act.authorization ) {
D
Daniel Larimer 已提交
677

678 679 680 681 682 683 684 685 686 687 688 689 690
         // check a minimum permission if one is set, otherwise assume the contract code will validate
         auto min_permission_name = lookup_minimum_permission(declared_auth.actor, act.scope, act.name);
         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 已提交
691 692
         }
         if ((_skip_flags & skip_transaction_signatures) == false) {
D
Daniel Larimer 已提交
693
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
694
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
695
                       ("auth", declared_auth));
N
Nathan Hourt 已提交
696 697
         }
      }
698
   }
N
Nathan Hourt 已提交
699

700
   if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false)
701
      EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
702 703
                 "transaction bears irrelevant signatures from these keys: ${keys}", 
                 ("keys", checker.unused_keys()));
N
Nathan Hourt 已提交
704 705
}

706 707 708
void chain_controller::check_transaction_authorization(const signed_transaction& trx, 
                                                       bool allow_unused_signatures)const 
{
709
   check_authorization( trx.actions, trx.get_signature_keys( chain_id_type{} ), allow_unused_signatures );
710 711
}

D
Daniel Larimer 已提交
712
void chain_controller::validate_scope( const transaction& trx )const {
713 714 715 716 717 718 719 720
   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 已提交
721

722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
   /**
    * We need to verify that all authorizing accounts have write scope because write
    * access is necessary to update bandwidth usage.
    */
   ///{
   auto has_write_scope = [&]( auto s ) { return std::binary_search( trx.write_scope.begin(),
                                                                     trx.write_scope.end(),
                                                                     s ); };
   for( const auto& a : trx.actions ) {
      for( const auto& auth : a.authorization ) {
         FC_ASSERT( has_write_scope( auth.actor ), "write scope of the authorizing account is required" );
      }
   }
   ///@}

D
Daniel Larimer 已提交
737 738 739
   vector<account_name> intersection;
   std::set_intersection( trx.read_scope.begin(), trx.read_scope.end(),
                          trx.write_scope.begin(), trx.write_scope.end(),
740 741
                          std::back_inserter(intersection) );
   FC_ASSERT( intersection.size() == 0, "a transaction may not redeclare scope in readscope" );
742 743
}

744
optional<permission_name> chain_controller::lookup_minimum_permission(account_name authorizer_account,
D
Daniel Larimer 已提交
745 746
                                                                    account_name scope,
                                                                    action_name act_name) const {
747 748 749 750 751 752
   // 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 已提交
753
   try {
D
Daniel Larimer 已提交
754 755 756
      // 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);
757 758 759
      // If no specific link found, check for a contract-wide default
      if (link == nullptr) {
         get<2>(key) = "";
D
Daniel Larimer 已提交
760
         link = _db.find<permission_link_object, by_action_name>(key);
761 762 763 764
      }

      // If no specific or default link found, use active permission
      if (link != nullptr)
765 766 767
         return link->required_permission;
      else
         return N(active);
D
Daniel Larimer 已提交
768
   } FC_CAPTURE_AND_RETHROW((authorizer_account)(scope)(act_name))
N
Nathan Hourt 已提交
769 770
}

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

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

778
void chain_controller::record_transaction(const transaction& trx) {
779 780
   //Insert transaction into unique transactions database.
    _db.create<transaction_object>([&](transaction_object& transaction) {
D
Daniel Larimer 已提交
781 782
        transaction.trx_id = trx.id(); 
        transaction.expiration = trx.expiration;
783 784 785 786
    });
}


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

D
Daniel Larimer 已提交
790
   const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.ref_block_num);
791 792

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

D
Daniel Larimer 已提交
798 799
void chain_controller::validate_referenced_accounts( const transaction& trx )const 
{ try { 
D
Daniel Larimer 已提交
800
   for( const auto& scope : trx.read_scope )
801
      require_scope(scope);
D
Daniel Larimer 已提交
802
   for( const auto& scope : trx.write_scope )
803
      require_scope(scope);
D
Daniel Larimer 已提交
804

D
Daniel Larimer 已提交
805 806
   for( const auto& act : trx.actions ) {
      require_account(act.scope);
D
Daniel Larimer 已提交
807
      for (const auto& auth : act.authorization )
D
Daniel Larimer 已提交
808
         require_account(auth.actor);
809
   }
D
Daniel Larimer 已提交
810
} FC_CAPTURE_AND_RETHROW() }
D
Daniel Larimer 已提交
811

D
Daniel Larimer 已提交
812
void chain_controller::validate_expiration( const transaction& trx ) const
813
{ try {
D
Daniel Larimer 已提交
814
   fc::time_point now = head_block_time();
D
Daniel Larimer 已提交
815
   const auto& chain_configuration = get_global_properties().configuration;
816

D
Daniel Larimer 已提交
817
   EOS_ASSERT( time_point(trx.expiration) <= now + fc::seconds(chain_configuration.max_transaction_lifetime),
D
Daniel Larimer 已提交
818
              transaction_exception, "transaction expiration is too far in the future",
819
              ("trx.expiration",trx.expiration)("now",now)
D
Daniel Larimer 已提交
820 821
              ("max_til_exp",chain_configuration.max_transaction_lifetime));
   EOS_ASSERT( now <= time_point(trx.expiration), transaction_exception, "transaction is expired",
822 823
              ("now",now)("trx.exp",trx.expiration));
} FC_CAPTURE_AND_RETHROW((trx)) }
824

825

826 827
void chain_controller::require_scope( const scope_name& scope )const {
   switch( uint64_t(scope) ) {
828 829
      case config::eosio_all_scope:
      case config::eosio_auth_scope:
830 831 832 833 834 835
         return; /// built in scopes
      default:
         require_account(scope);
   }
}

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

841
const producer_object& chain_controller::validate_block_header(uint32_t skip, const signed_block& next_block)const {
842 843
   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 已提交
844
   EOS_ASSERT(head_block_time() < (fc::time_point)next_block.timestamp, block_validate_exception, "",
845
              ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()));
K
Kevin Heifner 已提交
846
   if (((fc::time_point)next_block.timestamp) > head_block_time() + fc::microseconds(config::block_interval_ms*1000)) {
K
Kevin Heifner 已提交
847
      elog("head_block_time ${h}, next_block ${t}, "block_interval ${bi}",
848 849 850
           ("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));
851
   }
D
Daniel Larimer 已提交
852 853
   if (next_block.block_num() % config::blocks_per_round != 0) {
      EOS_ASSERT(!next_block.new_producers, block_validate_exception,
854
                 "Producer changes may only occur at the end of a round.");
N
Nathan Hourt 已提交
855
   }
D
Daniel Larimer 已提交
856 857
   
   const producer_object& producer = get_producer(get_scheduled_producer(get_slot_at_time(next_block.timestamp)));
N
Nathan Hourt 已提交
858

N
Nathan Hourt 已提交
859
   if(!(skip&skip_producer_signature))
860 861 862
      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 已提交
863

864
   if(!(skip&skip_producer_schedule_check)) {
865 866 867
      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 已提交
868 869
   }

870 871 872
   
   FC_ASSERT( next_block.calculate_transaction_merkle_root() == next_block.transaction_mroot, "merkle root does not match" );

N
Nathan Hourt 已提交
873 874 875
   return producer;
}

876
void chain_controller::create_block_summary(const signed_block& next_block) {
877
   auto sid = next_block.block_num() & 0xffff;
878
   _db.modify( _db.get<block_summary_object,by_id>(sid), [&](block_summary_object& p) {
879 880
         p.block_id = next_block.id();
   });
N
Nathan Hourt 已提交
881 882
}

883 884 885 886 887 888 889 890 891
/**
 *  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;
892 893 894
   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;
895
      ++itr;
896
      if( schedule.producers[count].block_signing_key != public_key_type() ) {
897 898 899
         ++count;
      }
   }
900 901 902 903
   const auto& hps = _head_producer_schedule();
   schedule.version = hps.version;
   if( hps != schedule )
      ++schedule.version;
904 905 906 907 908 909 910 911 912 913 914 915 916
   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;
}

917
void chain_controller::update_global_properties(const signed_block& b) { try {
918 919
   // If we're at the end of a round, update the BlockchainConfiguration, producer schedule
   // and "producers" special account authority
920 921 922 923 924
   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" );
925 926 927
      }

      const auto& gpo = get_global_properties();
928 929 930

      if( _head_producer_schedule() != schedule ) {
         FC_ASSERT( b.new_producers, "pending producer set changed but block didn't indicate it" );
931
      }
932 933 934 935 936 937 938 939
      _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) );
      });


940

941
      auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
942
      for(auto& name : gpo.active_producers.producers ) {
943
         active_producers_authority.accounts.push_back({{name.producer_name, config::active_name}, 1});
944 945
      }

D
Daniel Larimer 已提交
946
      auto& po = _db.get<permission_object, by_owner>( boost::make_tuple(config::producers_account_name, 
947
                                                                         config::active_name ) );
948 949 950
      _db.modify(po,[active_producers_authority] (permission_object& po) {
         po.auth = active_producers_authority;
      });
951
   }
952
} FC_CAPTURE_AND_RETHROW() } 
953

954
void chain_controller::add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts ) {
955
   for (const auto& i : checkpts)
N
Nathan Hourt 已提交
956 957 958
      _checkpoints[i.first] = i.second;
}

959
bool chain_controller::before_last_checkpoint()const {
N
Nathan Hourt 已提交
960 961 962
   return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
}

963
const global_property_object& chain_controller::get_global_properties()const {
964
   return _db.get<global_property_object>();
N
Nathan Hourt 已提交
965 966
}

967
const dynamic_global_property_object&chain_controller::get_dynamic_global_properties() const {
968
   return _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
969 970
}

D
Daniel Larimer 已提交
971
time_point chain_controller::head_block_time()const {
N
Nathan Hourt 已提交
972 973 974
   return get_dynamic_global_properties().time;
}

975
uint32_t chain_controller::head_block_num()const {
N
Nathan Hourt 已提交
976 977 978
   return get_dynamic_global_properties().head_block_number;
}

979
block_id_type chain_controller::head_block_id()const {
N
Nathan Hourt 已提交
980 981 982
   return get_dynamic_global_properties().head_block_id;
}

D
Daniel Larimer 已提交
983
account_name chain_controller::head_block_producer() const {
984 985 986
   auto b = _fork_db.fetch_block(head_block_id());
   if( b ) return b->data.producer;

N
Nathan Hourt 已提交
987
   if (auto head_block = fetch_block_by_id(head_block_id()))
988
      return head_block->producer;
N
Nathan Hourt 已提交
989 990 991
   return {};
}

D
Daniel Larimer 已提交
992 993
const producer_object& chain_controller::get_producer(const account_name& owner_name) const 
{ try {
B
Bart Wyatt 已提交
994
   return _db.get<producer_object, by_owner>(owner_name);
D
Daniel Larimer 已提交
995
} FC_CAPTURE_AND_RETHROW( (owner_name) ) }
N
Nathan Hourt 已提交
996

997 998 999 1000 1001
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) ) }

1002
uint32_t chain_controller::last_irreversible_block_num() const {
N
Nathan Hourt 已提交
1003
   return get_dynamic_global_properties().last_irreversible_block_num;
N
Nathan Hourt 已提交
1004 1005
}

D
Daniel Larimer 已提交
1006
void chain_controller::_initialize_indexes() {
1007 1008
   _db.add_index<account_index>();
   _db.add_index<permission_index>();
1009
   _db.add_index<permission_usage_index>();
1010
   _db.add_index<permission_link_index>();
1011
   _db.add_index<action_permission_index>();
1012 1013 1014 1015 1016
   _db.add_index<contracts::table_id_multi_index>();
   _db.add_index<contracts::key_value_index>();
   _db.add_index<contracts::keystr_value_index>();
   _db.add_index<contracts::key128x128_value_index>();
   _db.add_index<contracts::key64x64x64_value_index>();
1017 1018 1019 1020 1021

   _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>();
1022
   _db.add_index<generated_transaction_multi_index>();
1023
   _db.add_index<producer_multi_index>();
1024
   _db.add_index<scope_sequence_multi_index>();
1025 1026
   _db.add_index<bandwidth_usage_index>();
   _db.add_index<compute_usage_index>();
N
Nathan Hourt 已提交
1027 1028
}

D
Daniel Larimer 已提交
1029
void chain_controller::_initialize_chain(contracts::chain_initializer& starter)
N
Nathan Hourt 已提交
1030
{ try {
1031
   if (!_db.find<global_property_object>()) {
N
Nathan Hourt 已提交
1032 1033
      _db.with_write_lock([this, &starter] {
         auto initial_timestamp = starter.get_chain_start_time();
D
Daniel Larimer 已提交
1034 1035 1036
         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 已提交
1037

1038
         // Create global properties
1039
         const auto& gp = _db.create<global_property_object>([&starter](global_property_object& p) {
N
Nathan Hourt 已提交
1040 1041
            p.configuration = starter.get_chain_start_configuration();
            p.active_producers = starter.get_chain_start_producers();
1042
         });
1043

1044
         _db.create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
N
Nathan Hourt 已提交
1045
            p.time = initial_timestamp;
1046
            p.recent_slots_filled = uint64_t(-1);
1047 1048
            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 );
1049
         });
N
Nathan Hourt 已提交
1050

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

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

D
Daniel Larimer 已提交
1057
         transaction genesis_setup_transaction;
1058
         genesis_setup_transaction.write_scope = { config::eosio_all_scope };
D
Daniel Larimer 已提交
1059 1060 1061
         genesis_setup_transaction.actions = move(acts);

         ilog( "applying genesis transaction" );
1062
         with_skip_flags(skip_scope_check | skip_transaction_signatures | skip_authority_check | received_block | genesis_setup, 
D
Daniel Larimer 已提交
1063
         [&](){ 
1064
            transaction_metadata tmeta( genesis_setup_transaction );
1065
            __apply_transaction( tmeta );
1066
         });
1067
         ilog( "done applying genesis transaction" );
1068 1069
      });
   }
N
Nathan Hourt 已提交
1070 1071
} FC_CAPTURE_AND_RETHROW() }

N
Nathan Hourt 已提交
1072

1073
void chain_controller::replay() {
1074
   ilog("Replaying blockchain");
N
Nathan Hourt 已提交
1075
   auto start = fc::time_point::now();
K
Kevin Heifner 已提交
1076

K
Kevin Heifner 已提交
1077
   auto on_exit = fc::make_scoped_exit([&_currently_replaying_blocks = _currently_replaying_blocks](){
K
Kevin Heifner 已提交
1078 1079 1080 1081
      _currently_replaying_blocks = false;
   });
   _currently_replaying_blocks = true;

1082 1083 1084
   auto last_block = _block_log.read_head();
   if (!last_block) {
      elog("No blocks in block log; skipping replay");
N
Nathan Hourt 已提交
1085 1086 1087 1088 1089
      return;
   }

   const auto last_block_num = last_block->block_num();

1090
   ilog("Replaying ${n} blocks...", ("n", last_block_num) );
1091 1092 1093 1094 1095
   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 已提交
1096
      _apply_block(*block, skip_producer_signature |
N
Nathan Hourt 已提交
1097 1098 1099 1100
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_producer_schedule_check |
1101 1102
                          skip_authority_check |
                          received_block);
N
Nathan Hourt 已提交
1103 1104
   }
   auto end = fc::time_point::now();
1105 1106
   ilog("Done replaying ${n} blocks, elapsed time: ${t} sec",
        ("n", head_block_num())("t",double((end-start).count())/1000000.0));
N
Nathan Hourt 已提交
1107

1108
   _db.set_revision(head_block_num());
1109
}
N
Nathan Hourt 已提交
1110

D
Daniel Larimer 已提交
1111
void chain_controller::_spinup_db() {
1112 1113 1114 1115 1116
   // 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()));
1117

1118 1119
   });
}
N
Nathan Hourt 已提交
1120

D
Daniel Larimer 已提交
1121
void chain_controller::_spinup_fork_db()
N
Nathan Hourt 已提交
1122
{
1123 1124 1125 1126 1127 1128 1129 1130
   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 已提交
1131 1132
}

D
Daniel Larimer 已提交
1133
/*
1134 1135
ProducerRound chain_controller::calculate_next_round(const signed_block& next_block) {
   auto schedule = _admin->get_next_round(_db);
N
Nathan Hourt 已提交
1136 1137 1138 1139
   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 已提交
1140 1141 1142
   
   fc::time_point tp = (fc::time_point)next_block.timestamp;
   utilities::rand::random rng(tp.sec_since_epoch());
1143 1144
   rng.shuffle(schedule);
   return schedule;
D
Daniel Larimer 已提交
1145
}*/
1146

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

1150 1151 1152
   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 已提交
1153
   uint32_t missed_blocks = head_block_num() == 0? 1 : get_slot_at_time((fc::time_point)b.timestamp);
1154
   assert(missed_blocks != 0);
N
Nathan Hourt 已提交
1155
   missed_blocks--;
N
Nathan Hourt 已提交
1156

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

1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
   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 已提交
1174 1175 1176
      }
   }

1177 1178
   const auto& props = get_global_properties();

N
Nathan Hourt 已提交
1179
   // dynamic global properties updating
1180
   _db.modify( _dgp, [&]( dynamic_global_property_object& dgp ){
N
Nathan Hourt 已提交
1181 1182 1183
      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
1184
      dgp.current_producer = b.producer;
N
Nathan Hourt 已提交
1185
      dgp.current_absolute_slot += missed_blocks+1;
1186 1187 1188 1189 1190
      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 已提交
1191 1192 1193 1194 1195 1196

      // 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;
1197 1198 1199 1200 1201
      } else
         if(config::percent_100 * get_global_properties().active_producers.producers.size() / config::blocks_per_round > config::required_producer_participation)
            dgp.recent_slots_filled = uint64_t(-1);
         else
            dgp.recent_slots_filled = 0;
1202
      dgp.block_merkle_root.append( head_block_id() ); 
N
Nathan Hourt 已提交
1203 1204 1205 1206 1207
   });

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

1208
void chain_controller::update_signing_producer(const producer_object& signing_producer, const signed_block& new_block)
N
Nathan Hourt 已提交
1209 1210
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
P
Pravin 已提交
1211
   uint64_t new_block_aslot = dpo.current_absolute_slot + get_slot_at_time( (fc::time_point)new_block.timestamp );
N
Nathan Hourt 已提交
1212

1213
   _db.modify( signing_producer, [&]( producer_object& _wit )
N
Nathan Hourt 已提交
1214 1215 1216 1217 1218 1219
   {
      _wit.last_aslot = new_block_aslot;
      _wit.last_confirmed_block_num = new_block.block_num();
   } );
}

1220
void chain_controller::update_last_irreversible_block()
N
Nathan Hourt 已提交
1221 1222 1223 1224
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

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

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

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

D
Daniel Larimer 已提交
1233
   size_t offset = EOS_PERCENT(producer_objs.size(), config::percent_100- config::irreversible_threshold_percent);
1234 1235
   std::nth_element(producer_objs.begin(), producer_objs.begin() + offset, producer_objs.end(),
      [](const producer_object* a, const producer_object* b) {
N
Nathan Hourt 已提交
1236
         return a->last_confirmed_block_num < b->last_confirmed_block_num;
1237
      });
N
Nathan Hourt 已提交
1238

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

1241
   if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) {
1242
      _db.modify(dpo, [&](dynamic_global_property_object& _dpo) {
N
Nathan Hourt 已提交
1243
         _dpo.last_irreversible_block_num = new_last_irreversible_block_num;
1244
      });
N
Nathan Hourt 已提交
1245
   }
1246 1247

   // Write newly irreversible blocks to disk. First, get the number of the last block on disk...
1248
   auto old_last_irreversible_block = _block_log.head();
1249 1250 1251 1252
   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();
1253

1254
   if (last_block_on_disk < new_last_irreversible_block_num) {
1255 1256 1257 1258 1259
      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);
1260
         _block_log.append(*block);
K
Kevin Heifner 已提交
1261
         applied_irreversible_block(*block);
1262
      }
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
   }

   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());
                 }
              }
1281
              props.active_producers = *new_producer_schedule;
1282 1283 1284 1285
         });
      }
   }

N
Nathan Hourt 已提交
1286 1287 1288

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

1292
void chain_controller::clear_expired_transactions()
N
Nathan Hourt 已提交
1293 1294
{ try {
   //Look for expired transactions in the deduplication list, and remove them.
D
Daniel Larimer 已提交
1295
   //transactions must have expired by at least two forking windows in order to be removed.
D
Daniel Larimer 已提交
1296
   /*
1297
   auto& transaction_idx = _db.get_mutable_index<transaction_multi_index>();
N
Nathan Hourt 已提交
1298
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
D
Daniel Larimer 已提交
1299
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->expiration) )
N
Nathan Hourt 已提交
1300
      transaction_idx.remove(*dedupe_index.rbegin());
B
Bart Wyatt 已提交
1301
      */
1302
   //Look for expired transactions in the pending generated list, and remove them.
D
Daniel Larimer 已提交
1303
   //transactions must have expired by at least two forking windows in order to be removed.
1304
   auto& generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
B
Bart Wyatt 已提交
1305 1306
   const auto& generated_index = generated_transaction_idx.indices().get<by_expiration>();
   while( (!generated_index.empty()) && (head_block_time() > generated_index.rbegin()->expiration) )
1307
      generated_transaction_idx.remove(*generated_index.rbegin());
B
Bart Wyatt 已提交
1308

N
Nathan Hourt 已提交
1309 1310 1311 1312
} FC_CAPTURE_AND_RETHROW() }

using boost::container::flat_set;

D
Daniel Larimer 已提交
1313
account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const
N
Nathan Hourt 已提交
1314 1315
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1316
   uint64_t current_aslot = dpo.current_absolute_slot + slot_num;
1317
   const auto& gpo = _db.get<global_property_object>();
D
Daniel Larimer 已提交
1318 1319 1320 1321
   //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;

1322
   return gpo.active_producers.producers[index].producer_name;
N
Nathan Hourt 已提交
1323 1324
}

D
Daniel Larimer 已提交
1325
block_timestamp_type chain_controller::get_slot_time(uint32_t slot_num)const
N
Nathan Hourt 已提交
1326
{
P
Pravin 已提交
1327
   if( slot_num == 0)
D
Daniel Larimer 已提交
1328
      return block_timestamp_type();
N
Nathan Hourt 已提交
1329 1330 1331 1332 1333 1334

   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 已提交
1335 1336 1337
      auto genesis_time = block_timestamp_type(dpo.time);
      genesis_time.slot += slot_num;
      return (fc::time_point)genesis_time;
N
Nathan Hourt 已提交
1338 1339
   }

D
Daniel Larimer 已提交
1340
   auto head_block_abs_slot = block_timestamp_type(head_block_time());
P
Pravin 已提交
1341
   head_block_abs_slot.slot += slot_num;
D
Daniel Larimer 已提交
1342
   return head_block_abs_slot;
N
Nathan Hourt 已提交
1343 1344
}

D
Daniel Larimer 已提交
1345
uint32_t chain_controller::get_slot_at_time( block_timestamp_type when )const
N
Nathan Hourt 已提交
1346
{
D
Daniel Larimer 已提交
1347
   auto first_slot_time = get_slot_time(1);
N
Nathan Hourt 已提交
1348 1349
   if( when < first_slot_time )
      return 0;
D
Daniel Larimer 已提交
1350
   return block_timestamp_type(when).slot - first_slot_time.slot + 1;
N
Nathan Hourt 已提交
1351 1352
}

1353
uint32_t chain_controller::producer_participation_rate()const
N
Nathan Hourt 已提交
1354 1355
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
D
Daniel Larimer 已提交
1356
   return uint64_t(config::percent_100) * __builtin_popcountll(dpo.recent_slots_filled) / 64;
N
Nathan Hourt 已提交
1357 1358
}

D
Daniel Larimer 已提交
1359 1360
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;
1361
}
N
Nathan Hourt 已提交
1362

1363
static void log_handled_exceptions(const transaction& trx) {
B
Bart Wyatt 已提交
1364 1365 1366 1367
   try {
      throw;
   } catch (const checktime_exceeded&) {
      throw;
1368
   } FC_CAPTURE_AND_LOG((trx));
B
Bart Wyatt 已提交
1369 1370
}

1371 1372 1373 1374 1375 1376 1377
transaction_trace chain_controller::__apply_transaction( transaction_metadata& meta ) {
   transaction_trace result(meta.id);
   for (const auto &act : meta.trx.actions) {
      apply_context context(*this, _db, meta.trx, act, meta.published, meta.sender);
      context.exec();
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
1378
      fc::move_append(result.canceled_deferred, std::move(context.results.canceled_deferred));
1379
   }
B
Bart Wyatt 已提交
1380

1381
   uint32_t act_usage = result.action_traces.size();
1382

1383 1384 1385 1386 1387 1388 1389
   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 &&
          at.act.scope == config::system_account_name &&
          at.act.name == N(setcode)) {
         act_usage += config::setcode_act_usage;
B
Bart Wyatt 已提交
1390
      }
1391
   }
B
Bart Wyatt 已提交
1392

1393
   update_usage(meta, act_usage);
1394
   record_transaction(meta.trx);
1395 1396
   return result;
}
B
Bart Wyatt 已提交
1397

1398 1399 1400 1401 1402 1403
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 已提交
1404 1405
   } catch (...) {
      // if there is no sender, there is no error handling possible, rethrow
1406
      if (!meta.sender) {
B
Bart Wyatt 已提交
1407 1408
         throw;
      }
1409 1410
      // log exceptions we can handle with the error handle, throws otherwise
      log_handled_exceptions(meta.trx);
1411

B
Bart Wyatt 已提交
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426
      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.read_scope = meta.trx.read_scope;
   etrx.write_scope = meta.trx.write_scope;
   etrx.actions.emplace_back(vector<permission_level>{{meta.sender_id,config::active_name}},
                             contracts::onerror(meta.generated_data, meta.generated_data + meta.generated_size) );

   try {
1427 1428 1429
      auto temp_session = _db.start_undo_session(true);

      apply_context context(*this, _db, etrx, etrx.actions.front(), meta.published, meta.sender);
D
Daniel Larimer 已提交
1430
      context.exec();
1431
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
B
Bart Wyatt 已提交
1432 1433
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));

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

B
Bart Wyatt 已提交
1436 1437 1438
      for (auto &at: result.action_traces) {
         at.region_id = meta.region_id;
         at.cycle_index = meta.cycle_index;
1439
      }
1440

B
Bart Wyatt 已提交
1441 1442
      update_usage(meta, act_usage);
      record_transaction(meta.trx);
1443 1444

      temp_session.squash();
B
Bart Wyatt 已提交
1445
      return result;
1446

B
Bart Wyatt 已提交
1447
   } catch (...) {
1448 1449 1450 1451
      // 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 已提交
1452 1453 1454 1455
   }

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

1459
void chain_controller::push_deferred_transactions( bool flush )
B
Bart Wyatt 已提交
1460
{
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
   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 已提交
1478

1479 1480
      maybe_start_new_cycle();
   }
B
Bart Wyatt 已提交
1481

1482 1483 1484
   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 已提交
1485

1486 1487 1488 1489
   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 已提交
1490

1491 1492 1493 1494
   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());
1495
            transaction_metadata mtrx (trx, trx_p->published, trx.sender, trx.sender_id, trx_p->packed_trx.data(), trx_p->packed_trx.size());
1496 1497 1498 1499 1500 1501
            _push_transaction(mtrx);
            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 已提交
1502 1503 1504 1505
   }
}


1506 1507 1508 1509 1510
/**
 *  @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 )
{
1511
   set<std::pair<account_name, permission_name>> authorizing_accounts;
1512

1513
   for( const auto& act : meta.trx.actions )
1514
      for( const auto& auth : act.authorization )
1515
         authorizing_accounts.emplace( auth.actor, auth.permission );
1516

1517 1518 1519
   auto trx_size = meta.bandwidth_usage + config::fixed_bandwidth_overhead_per_transaction;

   const auto& dgpo = get_dynamic_global_properties();
1520

1521 1522 1523 1524
   if( meta.signing_keys ) {
      act_usage += meta.signing_keys->size();
   }

1525 1526
   auto head_time = head_block_time();
   for( const auto& authaccnt : authorizing_accounts ) {
1527
      const auto& buo = _db.get<bandwidth_usage_object,by_owner>( authaccnt.first );
1528
      _db.modify( buo, [&]( auto& bu ){
1529
          bu.bytes.add_usage( trx_size, head_time );
1530
          bu.acts.add_usage( act_usage, head_time );
1531
      });
1532
      const auto& sbo = _db.get<contracts::staked_balance_object, contracts::by_owner_name>(authaccnt.first);
1533 1534
      // TODO enable this after fixing divide by 0 with virtual_net_bandwidth and total_staked_tokens
      /// note: buo.bytes.value is in ubytes and virtual_net_bandwidth is in bytes, so
1535 1536 1537
      //  we convert to fixed int uin128_t with 60 bits of precision, divide by rate limiting precision
      //  then divide by virtual max_block_size which gives us % of virtual max block size in fixed width

1538 1539 1540 1541 1542 1543 1544 1545
      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;
      uint64_t   user_stake         = sbo.staked_balance;
      
      if( !(_skip_flags & genesis_setup) ) {
         FC_ASSERT( (used_ubytes * dgpo.total_staked_tokens) <=  (user_stake * virtual_max_ubytes), "authorizing account '${n}' has insufficient net bandwidth for this transaction",
1546
                    ("n",name(authaccnt.first))
1547 1548 1549 1550 1551 1552
                    ("used_bytes",double(used_ubytes)/1000000.)
                    ("user_stake",user_stake)
                    ("virtual_max_bytes", double(virtual_max_ubytes)/1000000. )
                    ("total_staked_tokens", dgpo.total_staked_tokens)
                    );
         FC_ASSERT( (used_uacts * dgpo.total_staked_tokens)  <=  (user_stake * virtual_max_uacts),  "authorizing account '${n}' has insufficient compute bandwidth for this transaction",
1553
                    ("n",name(authaccnt.first))
1554 1555 1556 1557 1558 1559
                    ("used_acts",double(used_uacts)/1000000.)
                    ("user_stake",user_stake)
                    ("virtual_max_uacts", double(virtual_max_uacts)/1000000. )
                    ("total_staked_tokens", dgpo.total_staked_tokens)
                    );
      }
1560 1561 1562

      // for any transaction not sent by code, update the affirmative last time a given permission was used
      if (!meta.sender) {
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
         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();
            });
         }
1575
      }
1576 1577
   }

1578 1579 1580 1581
   _db.modify( dgpo, [&]( auto& props ) {
      props.average_block_acts.add_usage( act_usage, head_time );
   });

D
Daniel Larimer 已提交
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594
}

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