controller.cpp 51.8 KB
Newer Older
D
Daniel Larimer 已提交
1
#include <eosio/chain/controller.hpp>
2
#include <eosio/chain/transaction_context.hpp>
D
Daniel Larimer 已提交
3 4 5 6 7 8 9 10 11 12 13 14

#include <eosio/chain/block_log.hpp>
#include <eosio/chain/fork_database.hpp>

#include <eosio/chain/account_object.hpp>
#include <eosio/chain/scope_sequence_object.hpp>
#include <eosio/chain/block_summary_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/contract_table_objects.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/transaction_object.hpp>

15
#include <eosio/chain/authorization_manager.hpp>
D
Daniel Larimer 已提交
16 17
#include <eosio/chain/resource_limits.hpp>

D
Daniel Larimer 已提交
18
#include <chainbase/chainbase.hpp>
D
Daniel Larimer 已提交
19 20
#include <fc/io/json.hpp>

D
Daniel Larimer 已提交
21 22
#include <eosio/chain/eosio_contract.hpp>

D
Daniel Larimer 已提交
23 24 25 26
namespace eosio { namespace chain {

using resource_limits::resource_limits_manager;

D
Daniel Larimer 已提交
27

D
Daniel Larimer 已提交
28 29 30 31 32 33 34 35
struct pending_state {
   pending_state( database::session&& s )
   :_db_session( move(s) ){}

   database::session                  _db_session;

   block_state_ptr                    _pending_block_state;

D
Daniel Larimer 已提交
36
   vector<action_receipt>             _actions;
D
Daniel Larimer 已提交
37

D
Daniel Larimer 已提交
38

D
Daniel Larimer 已提交
39 40 41 42 43 44
   void push() {
      _db_session.push();
   }
};

struct controller_impl {
D
Daniel Larimer 已提交
45
   controller&                    self;
D
Daniel Larimer 已提交
46 47 48
   chainbase::database            db;
   block_log                      blog;
   optional<pending_state>        pending;
49 50
   block_state_ptr                head;
   fork_database                  fork_db;
D
Daniel Larimer 已提交
51
   wasm_interface                 wasmif;
D
Daniel Larimer 已提交
52
   resource_limits_manager        resource_limits;
53
   authorization_manager          authorization;
D
Daniel Larimer 已提交
54
   controller::config             conf;
D
Daniel Larimer 已提交
55
   bool                           replaying = false;
D
Daniel Larimer 已提交
56

D
Daniel Larimer 已提交
57 58 59
   typedef pair<scope_name,action_name>                   handler_key;
   map< account_name, map<handler_key, apply_handler> >   apply_handlers;

D
Daniel Larimer 已提交
60 61 62 63 64
   /**
    *  Transactions that were undone by pop_block or abort_block, transactions
    *  are removed from this list if they are re-applied in other blocks. Producers
    *  can query this list when scheduling new transactions into blocks.
    */
65
   map<digest_type, transaction_metadata_ptr>     unapplied_transactions;
D
Daniel Larimer 已提交
66

D
Daniel Larimer 已提交
67
   void pop_block() {
68 69
      auto prev = fork_db.get_block( head->header.previous );
      FC_ASSERT( prev, "attempt to pop beyond last irreversible block" );
D
Daniel Larimer 已提交
70
      for( const auto& t : head->trxs )
71
         unapplied_transactions[t->signed_id] = t;
72
      head = prev;
D
Daniel Larimer 已提交
73
      db.undo();
D
Daniel Larimer 已提交
74 75 76
   }


D
Daniel Larimer 已提交
77 78 79 80
   void set_apply_handler( account_name contract, scope_name scope, action_name action, apply_handler v ) {
      apply_handlers[contract][make_pair(scope,action)] = v;
   }

D
Daniel Larimer 已提交
81
   controller_impl( const controller::config& cfg, controller& s  )
D
Daniel Larimer 已提交
82 83
   :self(s),
    db( cfg.shared_memory_dir,
D
Daniel Larimer 已提交
84 85 86
        cfg.read_only ? database::read_only : database::read_write,
        cfg.shared_memory_size ),
    blog( cfg.block_log_dir ),
D
Daniel Larimer 已提交
87
    fork_db( cfg.shared_memory_dir ),
D
Daniel Larimer 已提交
88
    wasmif( cfg.wasm_runtime ),
D
Daniel Larimer 已提交
89
    resource_limits( db ),
D
Daniel Larimer 已提交
90 91
    authorization( s, db ),
    conf( cfg )
D
Daniel Larimer 已提交
92
   {
D
Daniel Larimer 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

#define SET_APP_HANDLER( contract, scope, action, nspace ) \
   set_apply_handler( #contract, #scope, #action, &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )
   SET_APP_HANDLER( eosio, eosio, newaccount, eosio );
   SET_APP_HANDLER( eosio, eosio, setcode, eosio );
   SET_APP_HANDLER( eosio, eosio, setabi, eosio );
   SET_APP_HANDLER( eosio, eosio, updateauth, eosio );
   SET_APP_HANDLER( eosio, eosio, deleteauth, eosio );
   SET_APP_HANDLER( eosio, eosio, linkauth, eosio );
   SET_APP_HANDLER( eosio, eosio, unlinkauth, eosio );
   SET_APP_HANDLER( eosio, eosio, onerror, eosio );
   SET_APP_HANDLER( eosio, eosio, postrecovery, eosio );
   SET_APP_HANDLER( eosio, eosio, passrecovery, eosio );
   SET_APP_HANDLER( eosio, eosio, vetorecovery, eosio );
   SET_APP_HANDLER( eosio, eosio, canceldelay, eosio );

109 110 111
   fork_db.irreversible.connect( [&]( auto b ) {
                                 on_irreversible(b);
                                 });
D
Daniel Larimer 已提交
112

D
Daniel Larimer 已提交
113 114
   }

115 116 117
   /**
    *  Plugins / observers listening to signals emited (such as accepted_transaction) might trigger
    *  errors and throw exceptions. Unless those exceptions are caught it could impact consensus and/or
118
    *  cause a node to fork.
119
    *
120
    *  TODO: define special exceptions that can be thrown to reject transactions or blocks
121 122
    */
   template<typename Signal, typename Arg>
123
   void emit( const Signal& s, Arg&& a ) {
124 125 126 127 128 129 130 131
      try {
        s(std::forward<Arg>(a));
      } catch ( ... ) {
         elog( "signal handler threw exception" );
      }
   }


132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
   void on_irreversible( const block_state_ptr& s ) {
      if( !blog.head() )
         blog.read_head();

      const auto& log_head = blog.head();
      FC_ASSERT( log_head );
      auto lh_block_num = log_head->block_num();

      if( s->block_num - 1  == lh_block_num ) {
         FC_ASSERT( s->block->previous == log_head->id(), "irreversible doesn't link to block log head" );
         blog.append( s->block );
      } else if( s->block_num -1 > lh_block_num ) {
         wlog( "skipped blocks..." );
         edump((s->block_num)(log_head->block_num()));
         if( s->block_num == log_head->block_num() ) {
            FC_ASSERT( s->id == log_head->id(), "", ("s->id",s->id)("hid",log_head->id()) );
         }
      }
150
      emit( self.irreversible_block, s );
151 152 153
      db.commit( s->block_num );
   }

D
Daniel Larimer 已提交
154 155 156
   void init() {

      /**
157 158 159 160 161 162 163 164 165 166 167 168 169 170
      *  The fork database needs an initial block_state to be set before
      *  it can accept any new blocks. This initial block state can be found
      *  in the database (whose head block state should be irreversible) or
      *  it would be the genesis state.
      */
      if( !head ) {
         initialize_fork_db(); // set head to genesis state
      }

      FC_ASSERT( db.revision() == head->block_num, "fork database is inconsistent with shared memory",
                 ("db",db.revision())("head",head->block_num) );

      /**
       * The undoable state contains state transitions from blocks
D
Daniel Larimer 已提交
171 172 173 174 175
       * in the fork database that could be reversed. Because this
       * is a new startup and the fork database is empty, we must
       * unwind that pending state. This state will be regenerated
       * when we catch up to the head block later.
       */
176
      //clear_all_undo();
D
Daniel Larimer 已提交
177 178 179 180
   }

   ~controller_impl() {
      pending.reset();
181
      fork_db.close();
D
Daniel Larimer 已提交
182

183
      edump((db.revision())(head->block_num)(blog.read_head()->block_num()));
D
Daniel Larimer 已提交
184

D
Daniel Larimer 已提交
185 186 187
      db.flush();
   }

188
   void add_indices() {
D
Daniel Larimer 已提交
189
      db.add_index<account_index>();
190
      db.add_index<account_sequence_index>();
D
Daniel Larimer 已提交
191

D
Daniel Larimer 已提交
192 193 194 195 196 197
      db.add_index<table_id_multi_index>();
      db.add_index<key_value_index>();
      db.add_index<index64_index>();
      db.add_index<index128_index>();
      db.add_index<index256_index>();
      db.add_index<index_double_index>();
K
Khaled Al-Hassanieh 已提交
198
      db.add_index<index_long_double_index>();
D
Daniel Larimer 已提交
199 200 201 202 203 204 205 206

      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>();
      db.add_index<generated_transaction_multi_index>();
      db.add_index<scope_sequence_multi_index>();

207 208
      authorization.add_indices();
      resource_limits.add_indices();
D
Daniel Larimer 已提交
209 210 211 212 213 214 215
   }

   void clear_all_undo() {
      // Rewind the database to the last irreversible block
      db.with_write_lock([&] {
         db.undo_all();
         /*
216
         FC_ASSERT(db.revision() == self.head_block_num(),
D
Daniel Larimer 已提交
217 218 219 220 221 222 223
                   "Chainbase revision does not match head block num",
                   ("rev", db.revision())("head_block", self.head_block_num()));
                   */
      });
   }

   /**
224
    *  Sets fork database head to the genesis state.
D
Daniel Larimer 已提交
225 226
    */
   void initialize_fork_db() {
227 228
      wlog( " Initializing new blockchain with genesis state                  " );
      producer_schedule_type initial_schedule{ 0, {{N(eosio), conf.genesis.initial_key}} };
D
Daniel Larimer 已提交
229

230 231 232 233 234 235 236 237
      block_header_state genheader;
      genheader.active_schedule       = initial_schedule;
      genheader.pending_schedule      = initial_schedule;
      genheader.pending_schedule_hash = fc::sha256::hash(initial_schedule);
      genheader.header.timestamp      = conf.genesis.initial_timestamp;
      genheader.header.action_mroot   = conf.genesis.compute_chain_id();
      genheader.id                    = genheader.header.id();
      genheader.block_num             = genheader.header.block_num();
D
Daniel Larimer 已提交
238

239
      head = std::make_shared<block_state>( genheader );
D
Daniel Larimer 已提交
240
      head->block = std::make_shared<signed_block>(genheader.header);
241
      fork_db.set( head );
D
Daniel Larimer 已提交
242 243 244
      db.set_revision( head->block_num );

      initialize_database();
A
arhag 已提交
245

D
Daniel Larimer 已提交
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
      auto end = blog.read_head();
      if( end && end->block_num() > 1 ) {
         replaying = true;
         ilog( "existing block log, attempting to replay ${n} blocks", ("n",end->block_num()) );

         auto start = fc::time_point::now();
         while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) {
            self.push_block( next );
            if( next->block_num() % 10 == 0 ) {
               std::cerr << std::setw(10) << next->block_num() << " of " << end->block_num() <<"\r";
            }
         }
         std::cerr<< "\n";
         auto end = fc::time_point::now();
         ilog( "replayed blocks in ${n} seconds", ("n", (end-start).count()/1000000.0) );
         replaying = false;

      } else if( !end ) {
         blog.append( head->block );
      }
D
Daniel Larimer 已提交
266 267
   }

268
   void create_native_account( account_name name, const authority& owner, const authority& active, bool is_privileged = false ) {
269
      db.create<account_object>([&](auto& a) {
D
Daniel Larimer 已提交
270 271
         a.name = name;
         a.creation_date = conf.genesis.initial_timestamp;
272
         a.privileged = is_privileged;
D
Daniel Larimer 已提交
273 274

         if( name == config::system_account_name ) {
D
Daniel Larimer 已提交
275
            a.set_abi(eosio_contract_abi(abi_def()));
D
Daniel Larimer 已提交
276 277
         }
      });
278 279 280 281
      db.create<account_sequence_object>([&](auto & a) {
        a.name = name;
      });

282 283 284 285
      const auto& owner_permission  = authorization.create_permission(name, config::owner_name, 0,
                                                                      owner, conf.genesis.initial_timestamp );
      const auto& active_permission = authorization.create_permission(name, config::active_name, owner_permission.id,
                                                                      active, conf.genesis.initial_timestamp );
D
Daniel Larimer 已提交
286 287

      resource_limits.initialize_account(name);
288 289 290 291 292 293 294 295
      resource_limits.add_pending_account_ram_usage(
         name,
         (int64_t)(config::billable_size_v<permission_object> + owner_permission.auth.get_billable_size())
      );
      resource_limits.add_pending_account_ram_usage(
         name,
         (int64_t)(config::billable_size_v<permission_object> + active_permission.auth.get_billable_size())
      );
D
Daniel Larimer 已提交
296 297 298 299 300 301 302
   }

   void initialize_database() {
      // Initialize block summary index
      for (int i = 0; i < 0x10000; i++)
         db.create<block_summary_object>([&](block_summary_object&) {});

303 304 305 306 307
      const auto& tapos_block_summary = db.get<block_summary_object>(1);
      db.modify( tapos_block_summary, [&]( auto& bs ) {
        bs.block_id = head->id;
      });

308 309 310 311
      db.create<global_property_object>([&](auto& gpo ){
        gpo.configuration = conf.genesis.initial_configuration;
      });
      db.create<dynamic_global_property_object>([](auto&){});
312 313 314 315 316 317

      authorization.initialize_database();
      resource_limits.initialize_database();

      authority system_auth(conf.genesis.initial_key);
      create_native_account( config::system_account_name, system_auth, system_auth, true );
D
Daniel Larimer 已提交
318

319 320
      auto empty_authority = authority(1, {}, {});
      auto active_producers_authority = authority(1, {}, {});
D
Daniel Larimer 已提交
321 322
      active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});

323 324
      create_native_account( config::nobody_account_name, empty_authority, empty_authority );
      create_native_account( config::producers_account_name, empty_authority, active_producers_authority );
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
      const auto& active_permission       = authorization.get_permission({config::producers_account_name, config::active_name});
      const auto& majority_permission     = authorization.create_permission( config::producers_account_name,
                                                                             config::majority_producers_permission_name,
                                                                             active_permission.id,
                                                                             active_producers_authority,
                                                                             conf.genesis.initial_timestamp );
      const auto& minority_permission     = authorization.create_permission( config::producers_account_name,
                                                                             config::minority_producers_permission_name,
                                                                             majority_permission.id,
                                                                             active_producers_authority,
                                                                             conf.genesis.initial_timestamp );
      const auto& any_producer_permission = authorization.create_permission( config::producers_account_name,
                                                                             config::any_producer_permission_name,
                                                                             minority_permission.id,
                                                                             active_producers_authority,
                                                                             conf.genesis.initial_timestamp );
D
Daniel Larimer 已提交
341 342
   }

343

344

A
arhag 已提交
345
   void commit_block( bool add_to_fork_db ) {
D
Daniel Larimer 已提交
346 347
      if( add_to_fork_db ) {
         pending->_pending_block_state->validated = true;
348 349 350
         auto new_bsp = fork_db.add( pending->_pending_block_state );
         head = fork_db.head();
         FC_ASSERT( new_bsp == head, "committed block did not become the new head in fork database" );
351
      }
352

353
      //ilog((fc::json::to_pretty_string(*pending->_pending_block_state->block)));
354
      emit( self.accepted_block, pending->_pending_block_state );
D
Daniel Larimer 已提交
355 356
      pending->push();
      pending.reset();
D
Daniel Larimer 已提交
357

358
      self.log_irreversible_blocks();
D
Daniel Larimer 已提交
359
   }
D
Daniel Larimer 已提交
360

361 362 363 364
   transaction_trace_ptr apply_onerror( const generated_transaction_object& gto,
                                        fc::time_point deadline,
                                        uint64_t cpu_usage,
                                        fc::time_point start                     ) {
D
Daniel Larimer 已提交
365
      signed_transaction etrx;
366 367 368 369 370 371
      // Deliver onerror action containing the failed deferred transaction directly back to the sender.
      etrx.actions.emplace_back( vector<permission_level>{{gto.sender,config::active_name}},
                                 gto.sender, onerror::get_name(),
                                 fc::raw::pack( onerror( gto.sender_id, gto.packed_trx.data(), gto.packed_trx.size() ) ) );
      etrx.expiration = self.pending_block_time() + fc::microseconds(999'999); // Round up to avoid appearing expired
      etrx.set_reference_block( self.head_block_id() );
D
Daniel Larimer 已提交
372

373 374 375 376 377
      transaction_trace_ptr trace;
      try {
         transaction_context trx_context( trace, self, etrx, etrx.id(), deadline, true, 0, cpu_usage );
         trx_context.exec(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
         trace->elapsed = fc::time_point::now() - start;
D
Daniel Larimer 已提交
378

379 380 381 382 383
         auto orig_block_transactions_size = pending->_pending_block_state->block->transactions.size();
         auto orig_state_actions_size      = pending->_actions.size();
         try {
            trace->receipt = push_receipt( gto.trx_id, transaction_receipt::soft_fail, trace->cpu_usage, trace->net_usage );
            fc::move_append( pending->_actions, move(trx_context.executed) );
D
Daniel Larimer 已提交
384

385
            remove_scheduled_transaction( gto );
D
Daniel Larimer 已提交
386

387
            emit( self.applied_transaction, trace );
D
Daniel Larimer 已提交
388

389 390 391 392 393 394 395 396 397 398 399 400
            trx_context.squash();
            return trace;
         } catch( ... ) {
            pending->_pending_block_state->block->transactions.resize(orig_block_transactions_size);
            pending->_actions.resize(orig_state_actions_size);
            throw;
         }
      } catch( const fc::exception& e ) {
         trace->hard_except = e;
         trace->hard_except_ptr = std::current_exception();
      }
      return trace;
D
Daniel Larimer 已提交
401 402
   }

403 404 405 406
   void remove_scheduled_transaction( const generated_transaction_object& gto, bool expire = false ) {
      if( expire ) {
         push_receipt( gto.trx_id, transaction_receipt::expired, 0, 0 );
      }
D
Daniel Larimer 已提交
407

408
      resource_limits.add_pending_account_ram_usage(gto.payer,
409
                                     -(config::billable_size_v<generated_transaction_object> + gto.packed_trx.size()));
D
Daniel Larimer 已提交
410 411 412 413

      db.remove( gto );
   }

414 415 416 417
   void push_scheduled_transaction( const generated_transaction_object& gto, fc::time_point deadline  )
   { try {
      auto undo_session = db.start_undo_session(true);

D
Daniel Larimer 已提交
418
      fc::datastream<const char*> ds( gto.packed_trx.data(), gto.packed_trx.size() );
D
Daniel Larimer 已提交
419

420 421 422 423
      FC_ASSERT( gto.delay_until <= self.pending_block_time(), "this transaction isn't ready",
                 ("gto.delay_until",gto.delay_until)("pbt",self.pending_block_time())          );
      if( gto.expiration < self.pending_block_time() ) {
         remove_scheduled_transaction( gto, true ); // expire the transaction
D
Daniel Larimer 已提交
424 425
         return;
      }
426 427 428

      optional<fc::exception> soft_except;
      optional<fc::exception> hard_except;
429
      std::exception_ptr except_ptr;
D
Daniel Larimer 已提交
430
      std::exception_ptr hard_except_ptr;
431

432
      auto start = fc::time_point::now();
D
Daniel Larimer 已提交
433
      transaction_trace_ptr trace;
434 435 436
      flat_set<account_name>  bill_to_accounts;
      uint64_t max_cpu;
      bool abort_on_error = false;
D
Daniel Larimer 已提交
437 438 439
      try {
         signed_transaction dtrx;
         fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
440

441 442 443 444 445
         transaction_context trx_context( trace, self, dtrx, gto.trx_id, deadline, gto.published );
         bill_to_accounts = trx_context.bill_to_accounts;
         max_cpu = trx_context.max_cpu;
         trx_context.exec(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
         trace->elapsed = fc::time_point::now() - start;
446 447 448

         fc::move_append( pending->_actions, move(trx_context.executed) );

449 450 451 452
         trace->receipt = push_receipt( gto.trx_id,
                                        transaction_receipt::executed,
                                        trace->cpu_usage,
                                        trace->net_usage );
453

454
         remove_scheduled_transaction( gto );
455

456
         try {
457
            emit( self.applied_transaction, trace );
458 459 460 461
         } catch( ... ) {
            abort_on_error = true;
            throw;
         }
462
         trx_context.squash();
463
         undo_session.squash();
464
         return;
D
Daniel Larimer 已提交
465
      } catch( const fc::exception& e ) {
466 467 468 469 470
         if( abort_on_error ) // abort_on_error should  normally should not be set at this point, but if it is then that means
            throw;            // something went wrong while emitting the applied_transaction signal and we should abort
         trace->soft_except = e;
         trace->soft_except_ptr = std::current_exception();
         trace->elapsed = fc::time_point::now() - start;
D
Daniel Larimer 已提交
471
      }
472 473 474 475 476 477 478
      // Only soft or hard failure logic below:

      // Make sure failure was not due to problems with deserializing the deferred transaction.
      FC_ASSERT( bool(trace), "failed to deserialize transaction" );

      if( gto.sender != account_name() ) {
         // Attempt error handling for the generated transaction.
479
         edump((soft_except->to_detail_string()));
480 481 482 483 484 485
         auto error_trace = apply_onerror( gto, deadline, trace->cpu_usage, start );
         error_trace->failed_dtrx_trace = trace;
         trace = error_trace;
         if( !trace->hard_except_ptr ) {
            undo_session.squash();
            return;
486
         }
487 488 489 490 491 492
      } else {
         // Soft failures are not allowed for delayed transactions; upgrade to hard failure.
         trace->hard_except     = std::move(trace->soft_except);
         trace->soft_except.reset();
         trace->hard_except_ptr = trace->soft_except_ptr;
         trace->soft_except_ptr = nullptr;
D
Daniel Larimer 已提交
493
      }
494
      // Only hard failure logic below:
495

496 497 498 499 500
      trace->cpu_usage = ((trace->cpu_usage + 1023)/1024)*1024; // Round up cpu_usage to nearest multiple of 1024
      trace->cpu_usage = std::min(trace->cpu_usage, max_cpu);
      resource_limits.add_transaction_usage( bill_to_accounts, trace->cpu_usage, 0,
                                             block_timestamp_type(self.pending_block_time()).slot ); // Should never fail
      trace->elapsed = fc::time_point::now() - start;
501

502
      trace->receipt = push_receipt( gto.trx_id, transaction_receipt::hard_fail, trace->cpu_usage, 0 );
503

504
      remove_scheduled_transaction( gto );
505

506
      emit( self.applied_transaction, trace );
507 508 509

      undo_session.squash();
   } FC_CAPTURE_AND_RETHROW() } /// push_scheduled_transaction
D
Daniel Larimer 已提交
510

511 512 513 514

   /**
    *  Adds the transaction receipt to the pending block and returns it.
    */
515 516
   template<typename T>
   const transaction_receipt& push_receipt( const T& trx, transaction_receipt_header::status_enum status,
517 518 519 520 521
                                            uint64_t cpu_usage, uint64_t net_usage ) {
      uint64_t kcpu_usage      = cpu_usage / 1024;
      uint64_t net_usage_words = net_usage / 8;
      FC_ASSERT( kcpu_usage*1024 == cpu_usage, "cpu_usage is not divisible by 1024" );
      FC_ASSERT( net_usage_words*8 == net_usage, "net_usage is not divisible by 8" );
522 523 524 525 526 527 528 529
      pending->_pending_block_state->block->transactions.emplace_back( trx );
      transaction_receipt& r = pending->_pending_block_state->block->transactions.back();
      r.kcpu_usage           = kcpu_usage;
      r.net_usage_words      = net_usage_words;
      r.status               = status;
      return r;
   }

530
   bool push_next_unapplied_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
531
      auto itr = unapplied_transactions.begin();
532
      if( itr == unapplied_transactions.end() )
533
         return false;
D
Daniel Larimer 已提交
534

535 536 537
      // Intentionally copy transaction_metadata_ptr because it will be removed from unapplied_transactions and make the const& dangling.
      push_transaction( transaction_metadata_ptr(itr->second), deadline );
      return true;
D
Daniel Larimer 已提交
538 539
   }

540 541
   void transaction_trace_notify( const transaction_metadata_ptr& trx, const transaction_trace_ptr& trace ) {
      if( trx->on_result ) {
542 543
         (trx->on_result)(trace);
         trx->on_result = decltype(trx->on_result)(); //assign empty std::function
544 545
      }
   }
546

547 548 549 550 551
   /**
    *  This is the entry point for new transactions to the block state. It will check authorization and
    *  determine whether to execute it now or to delay it. Lastly it inserts a transaction receipt into
    *  the pending block.
    */
552 553
   void push_transaction( const transaction_metadata_ptr& trx,
                          fc::time_point deadline = fc::time_point::maximum(),
554 555
                          bool implicit = false )
   { try {
D
Daniel Larimer 已提交
556
      if( deadline == fc::time_point() ) {
557
         unapplied_transactions[trx->signed_id] = trx;
D
Daniel Larimer 已提交
558 559
         return;
      }
560

561
      auto start = fc::time_point::now();
562
      transaction_trace_ptr trace;
D
Daniel Larimer 已提交
563 564
      try {
         unapplied_transactions.erase( trx->signed_id );
565

566 567
         transaction_context trx_context( trace, self, trx->trx, trx->id, deadline,
                                          implicit, ( implicit ? 0 : trx->packed_trx.get_billable_size() ) );
568

569
         fc::microseconds required_delay(0);
570
         if( !implicit ) {
571 572
            required_delay = limit_delay( authorization.check_authorization( trx->trx.actions, trx->recover_keys() ) );
         }
573 574 575 576
         trx_context.delay = fc::seconds(trx->trx.delay_sec);
         EOS_ASSERT( trx_context.delay >= required_delay, transaction_exception,
                     "authorization imposes a delay (${required_delay} sec) greater than the delay specified in transaction header (${specified_delay} sec)",
                     ("required_delay", required_delay.to_seconds())("specified_delay", trx_context.delay.to_seconds()) );
577

578
         emit( self.accepted_transaction, trx);
579 580 581

         trx_context.exec(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
         trace->elapsed = fc::time_point::now() - start;
582

583 584 585
         auto orig_block_transactions_size = pending->_pending_block_state->block->transactions.size();
         auto orig_state_transactions_size = pending->_pending_block_state->trxs.size();
         auto orig_state_actions_size      = pending->_actions.size();
D
Daniel Larimer 已提交
586

587 588 589 590 591 592 593
         try {
            if( !implicit ) {
               transaction_receipt::status_enum s = ( trx_context.delay == fc::seconds(0) )
                                                    ? transaction_receipt::executed
                                                    : transaction_receipt::delayed;
               trace->receipt = push_receipt( trx->packed_trx, s, trace->cpu_usage, trace->net_usage );
               pending->_pending_block_state->trxs.emplace_back(trx);
D
Daniel Larimer 已提交
594
            } else {
595 596 597
               trace->receipt.status          = transaction_receipt::executed;
               trace->receipt.kcpu_usage      = trace->cpu_usage / 1024;
               trace->receipt.net_usage_words = trace->net_usage / 8;
D
Daniel Larimer 已提交
598
            }
599 600
            fc::move_append( pending->_actions, move(trx_context.executed) );

601
            transaction_trace_notify( trx, trace );
602

603
            emit( self.applied_transaction, trace );
604 605 606 607 608 609 610
            trx_context.squash();
            return;
         } catch( ... ) {
            pending->_pending_block_state->block->transactions.resize(orig_block_transactions_size);
            pending->_pending_block_state->trxs.resize(orig_state_transactions_size);
            pending->_actions.resize(orig_state_actions_size);
            throw;
611
         }
612 613
      } catch( const fc::exception& e ) {
         trace->hard_except = e;
D
Daniel Larimer 已提交
614
         trace->hard_except_ptr = std::current_exception();
D
Daniel Larimer 已提交
615
      }
616
      transaction_trace_notify( trx, trace );
617
   } FC_CAPTURE_AND_RETHROW() } /// push_transaction
D
Daniel Larimer 已提交
618

619

620
   void start_block( block_timestamp_type when ) {
621
      FC_ASSERT( !pending );
D
Daniel Larimer 已提交
622

623
      FC_ASSERT( db.revision() == head->block_num, "",
624
                ("db.revision()", db.revision())("controller_head_block", head->block_num)("fork_db_head_block", fork_db.head()->block_num) );
D
Daniel Larimer 已提交
625

626
      pending = db.start_undo_session(true);
627 628


629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
      pending->_pending_block_state = std::make_shared<block_state>( *head, when ); // promotes pending schedule (if any) to active
      pending->_pending_block_state->in_current_chain = true;

      const auto& gpo = db.get<global_property_object>();
      if( gpo.proposed_schedule_block_num.valid() && // if there is a proposed schedule that was proposed in a block ...
          ( *gpo.proposed_schedule_block_num <= pending->_pending_block_state->dpos_last_irreversible_blocknum ) && // ... that has now become irreversible ...
          pending->_pending_block_state->pending_schedule.producers.size() == 0 && // ... and there is room for a new pending schedule ...
          head->pending_schedule.producers.size() == 0 // ... and not just because it was promoted to active at the start of this block, then:
        )
      {
         // Promote proposed schedule to pending schedule.
         ilog( "promoting proposed schedule (set in block ${proposed_num}) to pending; current block: ${n} lib: ${lib} schedule: ${schedule} ",
               ("proposed_num", *gpo.proposed_schedule_block_num)("n", pending->_pending_block_state->block_num)
               ("lib", pending->_pending_block_state->dpos_last_irreversible_blocknum)
               ("schedule", static_cast<producer_schedule_type>(gpo.proposed_schedule) ) );
         pending->_pending_block_state->set_new_producers( gpo.proposed_schedule );
         db.modify( gpo, [&]( auto& gp ) {
            gp.proposed_schedule_block_num = optional<block_num_type>();
            gp.proposed_schedule.clear();
         });
      }
D
Daniel Larimer 已提交
650

651 652 653 654 655 656
      try {
         auto onbtrx = std::make_shared<transaction_metadata>( get_on_block_transaction() );
         push_transaction( onbtrx, fc::time_point::maximum(), true );
      } catch ( ... ) {
         ilog( "on block transaction failed, but shouldn't impact block generation, system contract needs update" );
      }
A
arhag 已提交
657 658 659

      clear_expired_input_transactions();
      update_producers_authority();
660
   } // start_block
D
Daniel Larimer 已提交
661 662


D
Daniel Larimer 已提交
663

664 665
   void sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
      auto p = pending->_pending_block_state;
666
      p->sign( signer_callback );
667 668
      static_cast<signed_block_header&>(*p->block) = p->header;
   } /// sign_block
D
Daniel Larimer 已提交
669

670
   void apply_block( const signed_block_ptr& b ) { try {
671 672 673 674 675 676 677 678 679
      try {
         start_block( b->timestamp );

         for( const auto& receipt : b->transactions ) {
            if( receipt.trx.contains<packed_transaction>() ) {
               auto& pt = receipt.trx.get<packed_transaction>();
               auto mtrx = std::make_shared<transaction_metadata>(pt);
               push_transaction( mtrx );
            }
D
Daniel Larimer 已提交
680 681 682
            else if( receipt.trx.contains<transaction_id_type>() ) {
               self.push_scheduled_transaction( receipt.trx.get<transaction_id_type>() );
            }
683
         }
D
Daniel Larimer 已提交
684

685 686
         finalize_block();
         sign_block( [&]( const auto& ){ return b->producer_signature; } );
D
Daniel Larimer 已提交
687

688 689 690
         // this is implied by the signature passing
         //FC_ASSERT( b->id() == pending->_pending_block_state->block->id(),
         //           "applying block didn't produce expected block id" );
D
Daniel Larimer 已提交
691

692 693
         commit_block(false);
         return;
D
Daniel Larimer 已提交
694
      } catch ( const fc::exception& e ) {
695 696
         edump((e.to_detail_string()));
         abort_block();
D
Daniel Larimer 已提交
697 698
         throw;
      }
699
   } FC_CAPTURE_AND_RETHROW() } /// apply_block
700 701


702
   void push_block( const signed_block_ptr& b ) {
D
Daniel Larimer 已提交
703
      try {
704
         FC_ASSERT( b );
D
Daniel Larimer 已提交
705
         auto new_header_state = fork_db.add( b );
706
         emit( self.accepted_block_header, new_header_state );
D
Daniel Larimer 已提交
707
         maybe_switch_forks();
A
arhag 已提交
708
      } FC_LOG_AND_RETHROW()
709
   }
710

711 712
   void push_confirmation( const header_confirmation& c ) {
      fork_db.add( c );
713
      emit( self.accepted_confirmation, c );
714 715 716 717
      maybe_switch_forks();
   }

   void maybe_switch_forks() {
718 719 720 721
      auto new_head = fork_db.head();

      if( new_head->header.previous == head->id ) {
         try {
722
            abort_block();
723
            apply_block( new_head->block );
724
            fork_db.mark_in_current_chain( new_head, true );
725 726 727
            fork_db.set_validity( new_head, true );
            head = new_head;
         } catch ( const fc::exception& e ) {
728
            fork_db.set_validity( new_head, false ); // Removes new_head from fork_db index, so no need to mark it as not in the current chain.
729 730
            throw;
         }
731
      } else if( new_head->id != head->id ) {
732
         ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
A
arhag 已提交
733
              ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
734 735
         auto branches = fork_db.fetch_branch_from( new_head->id, head->id );

736 737
         for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
            fork_db.mark_in_current_chain( *itr , false );
738
            pop_block();
739
         }
A
arhag 已提交
740
         FC_ASSERT( self.head_block_id() == branches.second.back()->header.previous,
741
                    "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
742 743 744 745 746

         for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
            optional<fc::exception> except;
            try {
               apply_block( (*ritr)->block );
747
               head = *ritr;
748
               fork_db.mark_in_current_chain( *ritr, true );
749 750 751
            }
            catch (const fc::exception& e) { except = e; }
            if (except) {
752
               elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
753

754 755 756 757
               while (ritr != branches.first.rend() ) {
                  fork_db.set_validity( *ritr, false );
                  ++ritr;
               }
758

759
               // pop all blocks from the bad fork
760 761
               for( auto itr = (ritr + 1).base(); itr != branches.second.end(); ++itr ) {
                  fork_db.mark_in_current_chain( *itr , false );
762
                  pop_block();
763
               }
A
arhag 已提交
764
               FC_ASSERT( self.head_block_id() == branches.second.back()->header.previous,
765
                          "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
766

767 768 769
               // re-apply good blocks
               for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
                  apply_block( (*ritr)->block );
770
                  head = *ritr;
771
                  fork_db.mark_in_current_chain( *ritr, true );
772 773 774 775
               }
               throw *except;
            } // end if exception
         } /// end for each block in branch
776
         ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id));
777 778 779
      }
   } /// push_block

780
   void abort_block() {
781
      if( pending ) {
782
         for( const auto& t : pending->_pending_block_state->trxs )
783
            unapplied_transactions[t->signed_id] = t;
784 785
         pending.reset();
      }
786 787
   }

D
Daniel Larimer 已提交
788 789 790 791 792

   bool should_enforce_runtime_limits()const {
      return false;
   }

D
Daniel Larimer 已提交
793 794 795 796 797 798 799 800
   void set_action_merkle() {
      vector<digest_type> action_digests;
      action_digests.reserve( pending->_actions.size() );
      for( const auto& a : pending->_actions )
         action_digests.emplace_back( a.digest() );

      pending->_pending_block_state->header.action_mroot = merkle( move(action_digests) );
   }
D
Daniel Larimer 已提交
801

D
Daniel Larimer 已提交
802 803
   void set_trx_merkle() {
      vector<digest_type> trx_digests;
D
Daniel Larimer 已提交
804 805 806
      const auto& trxs = pending->_pending_block_state->block->transactions;
      trx_digests.reserve( trxs.size() );
      for( const auto& a : trxs )
D
Daniel Larimer 已提交
807
         trx_digests.emplace_back( a.digest() );
D
Daniel Larimer 已提交
808

D
Daniel Larimer 已提交
809
      pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) );
D
Daniel Larimer 已提交
810 811 812
   }


813
   void finalize_block()
D
Daniel Larimer 已提交
814
   { try {
D
Daniel Larimer 已提交
815 816 817
      if( !pending ) self.start_block();

      /*
818
      ilog( "finalize block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}",
A
arhag 已提交
819 820
            ("n",pending->_pending_block_state->block_num)
            ("id",pending->_pending_block_state->header.id())
821
            ("t",pending->_pending_block_state->header.timestamp)
A
arhag 已提交
822 823
            ("p",pending->_pending_block_state->header.producer)
            ("signing_key", pending->_pending_block_state->block_signing_key)
824 825
            ("v",pending->_pending_block_state->header.schedule_version)
            ("lib",pending->_pending_block_state->dpos_last_irreversible_blocknum)
826
            ("ndtrxs",db.get_index<generated_transaction_multi_index,by_trx_id>().size())
827 828
            ("np",pending->_pending_block_state->header.new_producers)
            );
829
      */
D
Daniel Larimer 已提交
830

A
arhag 已提交
831 832 833 834 835 836 837 838 839
      // Update resource limits:
      resource_limits.process_account_limit_updates();
      const auto& chain_config = self.get_global_properties().configuration;
      resource_limits.set_block_parameters(
         {EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct), chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}},
         {EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}}
      );
      resource_limits.process_block_usage(pending->_pending_block_state->block_num);

D
Daniel Larimer 已提交
840 841 842 843 844 845
      set_action_merkle();
      set_trx_merkle();

      auto p = pending->_pending_block_state;
      p->id = p->header.id();

A
arhag 已提交
846
      create_block_summary(p->id);
D
Daniel Larimer 已提交
847 848 849

   } FC_CAPTURE_AND_RETHROW() }

A
arhag 已提交
850 851
   void update_producers_authority() {
      const auto& producers = pending->_pending_block_state->active_schedule.producers;
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886

      auto update_permission = [&]( auto& permission, auto threshold ) {
         auto auth = authority( threshold, {}, {});
         for( auto& p : producers ) {
            auth.accounts.push_back({{p.producer_name, config::active_name}, 1});
         }

         if( static_cast<authority>(permission.auth) != auth ) { // TODO: use a more efficient way to check that authority has not changed
            db.modify(permission, [&]( auto& po ) {
               po.auth = auth;
            });
         }
      };

      uint32_t num_producers = producers.size();
      auto calculate_threshold = [=]( uint32_t numerator, uint32_t denominator ) {
         return ( (num_producers * numerator) / denominator ) + 1;
      };

      update_permission( authorization.get_permission({config::producers_account_name,
                                                       config::active_name}),
                         calculate_threshold( 2, 3 ) /* more than two-thirds */                      );

      update_permission( authorization.get_permission({config::producers_account_name,
                                                       config::majority_producers_permission_name}),
                         calculate_threshold( 1, 2 ) /* more than one-half */                        );

      update_permission( authorization.get_permission({config::producers_account_name,
                                                       config::minority_producers_permission_name}),
                         calculate_threshold( 1, 3 ) /* more than one-third */                       );

      update_permission( authorization.get_permission({config::producers_account_name,
                                                       config::any_producer_permission_name}), 1     );

      //TODO: Add tests
A
arhag 已提交
887
   }
D
Daniel Larimer 已提交
888

A
arhag 已提交
889 890 891
   void create_block_summary(const block_id_type& id) {
      auto block_num = block_header::num_from_id(id);
      auto sid = block_num & 0xffff;
D
Daniel Larimer 已提交
892
      db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
A
arhag 已提交
893
          bso.block_id = id;
D
Daniel Larimer 已提交
894 895 896
      });
   }

A
arhag 已提交
897 898

   void clear_expired_input_transactions() {
D
Daniel Larimer 已提交
899 900 901
      //Look for expired transactions in the deduplication list, and remove them.
      auto& transaction_idx = db.get_mutable_index<transaction_multi_index>();
      const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
A
arhag 已提交
902 903
      auto now = self.pending_block_time();
      while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
D
Daniel Larimer 已提交
904 905 906 907
         transaction_idx.remove(*dedupe_index.begin());
      }
   }

A
arhag 已提交
908 909
   fc::microseconds limit_delay( fc::microseconds delay )const {
      auto max_delay = fc::seconds( self.get_global_properties().configuration.max_transaction_delay );
910
      return std::min(delay, max_delay);
A
arhag 已提交
911 912
   }

D
Daniel Larimer 已提交
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
   /*
   bool should_check_tapos()const { return true; }

   void validate_tapos( const transaction& trx )const {
      if( !should_check_tapos() ) return;

      const auto& tapos_block_summary = db.get<block_summary_object>((uint16_t)trx.ref_block_num);

      //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
      EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception,
                 "Transaction's reference block did not match. Is this transaction from a different fork?",
                 ("tapos_summary", tapos_block_summary));
   }
   */


   /**
    *  At the start of each block we notify the system contract with a transaction that passes in
    *  the block header of the prior block (which is currently our head block)
    */
D
Daniel Larimer 已提交
933
   signed_transaction get_on_block_transaction()
D
Daniel Larimer 已提交
934 935 936 937 938
   {
      action on_block_act;
      on_block_act.account = config::system_account_name;
      on_block_act.name = N(onblock);
      on_block_act.authorization = vector<permission_level>{{config::system_account_name, config::active_name}};
A
arhag 已提交
939
      on_block_act.data = fc::raw::pack(self.head_block_header());
D
Daniel Larimer 已提交
940

D
Daniel Larimer 已提交
941
      signed_transaction trx;
D
Daniel Larimer 已提交
942
      trx.actions.emplace_back(std::move(on_block_act));
A
arhag 已提交
943 944
      trx.set_reference_block(self.head_block_id());
      trx.expiration = self.head_block_time() + fc::seconds(1);
D
Daniel Larimer 已提交
945 946 947
      return trx;
   }

948
}; /// controller_impl
D
Daniel Larimer 已提交
949

950
const resource_limits_manager&   controller::get_resource_limits_manager()const
D
Daniel Larimer 已提交
951 952 953
{
   return my->resource_limits;
}
954
resource_limits_manager&         controller::get_mutable_resource_limits_manager()
D
Daniel Larimer 已提交
955 956 957
{
   return my->resource_limits;
}
D
Daniel Larimer 已提交
958

959 960 961 962 963 964 965 966
const authorization_manager&   controller::get_authorization_manager()const
{
   return my->authorization;
}
authorization_manager&         controller::get_mutable_authorization_manager()
{
   return my->authorization;
}
D
Daniel Larimer 已提交
967 968 969 970 971 972 973 974 975 976 977 978

controller::controller( const controller::config& cfg )
:my( new controller_impl( cfg, *this ) )
{
}

controller::~controller() {
}


void controller::startup() {

979 980 981
   // ilog( "${c}", ("c",fc::json::to_pretty_string(cfg)) );
   my->add_indices();

D
Daniel Larimer 已提交
982 983
   my->head = my->fork_db.head();
   if( !my->head ) {
D
Daniel Larimer 已提交
984
      elog( "No head block in fork db, perhaps we need to replay" );
985 986 987
      my->init();
   } else {
   //  my->db.set_revision( my->head->block_num );
D
Daniel Larimer 已提交
988 989 990
   }
}

D
Daniel Larimer 已提交
991
chainbase::database& controller::db()const { return my->db; }
D
Daniel Larimer 已提交
992 993 994


void controller::start_block( block_timestamp_type when ) {
995
   my->start_block(when);
D
Daniel Larimer 已提交
996 997 998
}

void controller::finalize_block() {
D
Daniel Larimer 已提交
999
   my->finalize_block();
D
Daniel Larimer 已提交
1000 1001
}

1002 1003
void controller::sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
   my->sign_block( signer_callback );
D
Daniel Larimer 已提交
1004 1005 1006
}

void controller::commit_block() {
D
Daniel Larimer 已提交
1007
   my->commit_block(true);
D
Daniel Larimer 已提交
1008 1009
}

1010 1011
void controller::abort_block() {
   my->abort_block();
D
Daniel Larimer 已提交
1012 1013
}

D
Daniel Larimer 已提交
1014
void controller::push_block( const signed_block_ptr& b ) {
1015
   my->push_block( b );
D
Daniel Larimer 已提交
1016
   log_irreversible_blocks();
D
Daniel Larimer 已提交
1017 1018
}

1019 1020 1021 1022
void controller::push_confirmation( const header_confirmation& c ) {
   my->push_confirmation( c );
}

D
Daniel Larimer 已提交
1023 1024 1025
void controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline ) {
   my->push_transaction(trx, deadline);
}
1026 1027 1028

bool controller::push_next_unapplied_transaction( fc::time_point deadline ) {
   return my->push_next_unapplied_transaction( deadline );
D
Daniel Larimer 已提交
1029 1030
}

D
Daniel Larimer 已提交
1031
transaction_trace_ptr controller::sync_push( const transaction_metadata_ptr& trx, time_point deadline ) {
D
Daniel Larimer 已提交
1032 1033 1034 1035 1036 1037 1038 1039
   auto start = fc::time_point::now();
   try {
      FC_ASSERT( deadline != fc::time_point() );
      transaction_trace_ptr trace;
      trx->on_result = [&]( const transaction_trace_ptr& t ){ trace = t; };
      my->push_transaction( trx, deadline );
      return trace;
   } FC_CAPTURE_AND_RETHROW( (fc::time_point::now()-start)(deadline) ) 
D
Daniel Larimer 已提交
1040
}
D
Daniel Larimer 已提交
1041

1042
bool controller::push_next_scheduled_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
1043
   const auto& idx = db().get_index<generated_transaction_multi_index,by_delay>();
1044 1045 1046 1047 1048 1049
   auto itr = idx.begin();
   if( itr != idx.end() && itr->delay_until <= pending_block_time() ) {
      my->push_scheduled_transaction( *itr, deadline );
      return true;
   }
   return false;
D
Daniel Larimer 已提交
1050
}
D
Daniel Larimer 已提交
1051

1052
void controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline ) {
D
Daniel Larimer 已提交
1053 1054 1055 1056
   const auto& idx = db().get_index<generated_transaction_multi_index,by_trx_id>();
   auto itr = idx.find( trxid );
   FC_ASSERT( itr != idx.end(), "unknown transaction" );
   my->push_scheduled_transaction( *itr, deadline );
D
Daniel Larimer 已提交
1057 1058 1059 1060 1061
}

uint32_t controller::head_block_num()const {
   return my->head->block_num;
}
A
arhag 已提交
1062 1063 1064
time_point controller::head_block_time()const {
   return my->head->header.timestamp;
}
D
Daniel Larimer 已提交
1065 1066 1067
block_id_type controller::head_block_id()const {
   return my->head->id;
}
D
Daniel Larimer 已提交
1068 1069 1070
account_name  controller::head_block_producer()const {
   return my->head->header.producer;
}
A
arhag 已提交
1071 1072
const block_header& controller::head_block_header()const {
   return my->head->header;
D
Daniel Larimer 已提交
1073
}
A
arhag 已提交
1074 1075
block_state_ptr controller::head_block_state()const {
   return my->head;
D
Daniel Larimer 已提交
1076 1077
}

A
arhag 已提交
1078 1079 1080
block_state_ptr controller::pending_block_state()const {
   if( my->pending ) return my->pending->_pending_block_state;
   return block_state_ptr();
1081 1082 1083 1084
}
time_point controller::pending_block_time()const {
   FC_ASSERT( my->pending, "no pending block" );
   return my->pending->_pending_block_state->header.timestamp;
D
Daniel Larimer 已提交
1085 1086
}

A
arhag 已提交
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
uint32_t controller::last_irreversible_block_num() const {
   return my->head->bft_irreversible_blocknum;
}

block_id_type controller::last_irreversible_block_id() const {
   auto lib_num = my->head->bft_irreversible_blocknum;
   const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)lib_num);

   if( block_header::num_from_id(tapos_block_summary.block_id) == lib_num )
      return tapos_block_summary.block_id;

   return fetch_block_by_number(lib_num)->id();

}

D
Daniel Larimer 已提交
1102 1103 1104
const dynamic_global_property_object& controller::get_dynamic_global_properties()const {
  return my->db.get<dynamic_global_property_object>();
}
D
Daniel Larimer 已提交
1105 1106 1107
const global_property_object& controller::get_global_properties()const {
  return my->db.get<global_property_object>();
}
D
Daniel Larimer 已提交
1108 1109 1110 1111

/**
 *  This method reads the current dpos_irreverible block number, if it is higher
 *  than the last block number of the log, it grabs the next block from the
1112
 *  fork database, saves it to disk, then removes the block from the fork database.
D
Daniel Larimer 已提交
1113 1114 1115 1116
 *
 *  Any forks built off of a different block with the same number are also pruned.
 */
void controller::log_irreversible_blocks() {
1117
   /*
1118
   if( !my->blog.head() )
D
Daniel Larimer 已提交
1119
      my->blog.read_head();
1120

D
Daniel Larimer 已提交
1121 1122 1123
   const auto& log_head = my->blog.head();
   auto lib = my->head->dpos_last_irreversible_blocknum;

1124 1125 1126 1127 1128 1129 1130 1131 1132 1133

   if( lib > 2 ) {
      if( log_head && log_head->block_num() > lib ) {
         auto blk = my->fork_db.get_block_in_current_chain_by_num( lib - 1 );
         FC_ASSERT( blk, "unable to find block state", ("block_num",lib-1));
         my->fork_db.prune( blk  );
         my->db.commit( lib -1 );
         return;
      }

D
Daniel Larimer 已提交
1134
      while( log_head && (log_head->block_num()+1) < lib ) {
D
Daniel Larimer 已提交
1135
         auto lhead = log_head->block_num();
1136 1137
         auto blk = my->fork_db.get_block_in_current_chain_by_num( lhead + 1 );
         FC_ASSERT( blk, "unable to find block state", ("block_num",lhead+1));
1138
         irreversible_block( blk );
D
Daniel Larimer 已提交
1139 1140 1141 1142 1143

         if( !my->replaying ) {
            my->blog.append( blk->block );
         }

D
Daniel Larimer 已提交
1144 1145
         my->fork_db.prune( blk );
         my->db.commit( lhead );
D
Daniel Larimer 已提交
1146 1147
      }
   }
1148
   */
D
Daniel Larimer 已提交
1149
}
1150
signed_block_ptr controller::fetch_block_by_id( block_id_type id )const {
D
Daniel Larimer 已提交
1151
   idump((id));
1152 1153
   auto state = my->fork_db.get_block(id);
   if( state ) return state->block;
D
Daniel Larimer 已提交
1154
   edump((block_header::num_from_id(id)));
1155
   auto bptr = fetch_block_by_number( block_header::num_from_id(id) );
D
Daniel Larimer 已提交
1156 1157
   if( bptr && bptr->id() == id ) return bptr;
   elog( "not found" );
1158 1159 1160
   return signed_block_ptr();
}

D
Daniel Larimer 已提交
1161
signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const  { try {
1162
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
D
Daniel Larimer 已提交
1163 1164 1165
   if( blk_state ) {
      return blk_state->block;
   }
1166

D
Daniel Larimer 已提交
1167
   ilog( "blog read by number ${n}", ("n", block_num) );
D
Daniel Larimer 已提交
1168
   return my->blog.read_block_by_num(block_num);
D
Daniel Larimer 已提交
1169
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
D
Daniel Larimer 已提交
1170 1171

void controller::pop_block() {
1172
   my->pop_block();
D
Daniel Larimer 已提交
1173 1174
}

1175
bool controller::set_proposed_producers( vector<producer_key> producers ) {
1176 1177
   const auto& gpo = get_global_properties();
   auto cur_block_num = head_block_num() + 1;
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192

   if( gpo.proposed_schedule_block_num.valid() ) {
      if( *gpo.proposed_schedule_block_num != cur_block_num )
         return false; // there is already a proposed schedule set in a previous block, wait for it to become pending

      if( std::equal( producers.begin(), producers.end(),
                      gpo.proposed_schedule.producers.begin(), gpo.proposed_schedule.producers.end() ) )
         return false; // the proposed producer schedule does not change
   }

   producer_schedule_type sch;

   decltype(sch.producers.cend()) end;
   decltype(end)                  begin;

1193
   if( my->pending->_pending_block_state->pending_schedule.producers.size() == 0 ) {
1194 1195 1196 1197
      const auto& active_sch = my->pending->_pending_block_state->active_schedule;
      begin = active_sch.producers.begin();
      end   = active_sch.producers.end();
      sch.version = active_sch.version + 1;
1198
   } else {
1199 1200 1201 1202
      const auto& pending_sch = my->pending->_pending_block_state->pending_schedule;
      begin = pending_sch.producers.begin();
      end   = pending_sch.producers.end();
      sch.version = pending_sch.version + 1;
1203
   }
1204 1205 1206 1207 1208 1209

   if( std::equal( producers.begin(), producers.end(), begin, end ) )
      return false; // the producer schedule would not change

   sch.producers = std::move(producers);

1210 1211
   my->db.modify( gpo, [&]( auto& gp ) {
      gp.proposed_schedule_block_num = cur_block_num;
1212
      gp.proposed_schedule = std::move(sch);
1213
   });
1214
   return true;
D
Daniel Larimer 已提交
1215
}
1216 1217

const producer_schedule_type&    controller::active_producers()const {
1218 1219
   if ( !(my->pending) )
      return  my->head->active_schedule;
D
Daniel Larimer 已提交
1220 1221 1222
   return my->pending->_pending_block_state->active_schedule;
}

1223
const producer_schedule_type&    controller::pending_producers()const {
1224 1225
   if ( !(my->pending) )
      return  my->head->pending_schedule;
D
Daniel Larimer 已提交
1226 1227 1228
   return my->pending->_pending_block_state->pending_schedule;
}

1229 1230 1231 1232 1233 1234 1235 1236 1237
optional<producer_schedule_type> controller::proposed_producers()const {
   const auto& gpo = get_global_properties();
   if( !gpo.proposed_schedule_block_num.valid() )
      return optional<producer_schedule_type>();

   return gpo.proposed_schedule;
}


D
Daniel Larimer 已提交
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
const apply_handler* controller::find_apply_handler( account_name receiver, account_name scope, action_name act ) const
{
   auto native_handler_scope = my->apply_handlers.find( receiver );
   if( native_handler_scope != my->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;
}
wasm_interface& controller::get_wasm_interface() {
   return my->wasmif;
}
D
Daniel Larimer 已提交
1251

1252
const account_object& controller::get_account( account_name name )const
D
Daniel Larimer 已提交
1253 1254 1255
{ try {
   return my->db.get<account_object, by_name>(name);
} FC_CAPTURE_AND_RETHROW( (name) ) }
D
Daniel Larimer 已提交
1256

1257 1258 1259 1260
const map<digest_type, transaction_metadata_ptr>&  controller::unapplied_transactions()const {
   return my->unapplied_transactions;
}

A
arhag 已提交
1261 1262 1263
fc::microseconds controller::limit_delay( fc::microseconds delay )const {
   return my->limit_delay( delay );
}
1264 1265 1266 1267 1268 1269

void controller::validate_referenced_accounts( const transaction& trx )const {
   for( const auto& a : trx.context_free_actions ) {
      get_account( a.account );
      FC_ASSERT( a.authorization.size() == 0 );
   }
D
Daniel Larimer 已提交
1270
   bool one_auth = false;
1271 1272
   for( const auto& a : trx.actions ) {
      get_account( a.account );
1273
      for( const auto& auth : a.authorization ) {
D
Daniel Larimer 已提交
1274
         one_auth = true;
1275 1276 1277
         get_account( auth.actor );
      }
   }
D
Daniel Larimer 已提交
1278
   EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" );
1279 1280 1281 1282 1283
}

void controller::validate_expiration( const transaction& trx )const { try {
   const auto& chain_configuration = get_global_properties().configuration;

1284 1285 1286 1287 1288
   EOS_ASSERT( time_point(trx.expiration) >= pending_block_time(),
               expired_tx_exception,
               "transaction has expired, "
               "expiration is ${trx.expiration} and pending block time is ${pending_block_time}",
               ("trx.expiration",trx.expiration)("pending_block_time",pending_block_time()));
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
   EOS_ASSERT( time_point(trx.expiration) <= pending_block_time() + fc::seconds(chain_configuration.max_transaction_lifetime),
               tx_exp_too_far_exception,
               "Transaction expiration is too far in the future relative to the reference time of ${reference_time}, "
               "expiration is ${trx.expiration} and the maximum transaction lifetime is ${max_til_exp} seconds",
               ("trx.expiration",trx.expiration)("reference_time",pending_block_time())
               ("max_til_exp",chain_configuration.max_transaction_lifetime) );
} FC_CAPTURE_AND_RETHROW((trx)) }

void controller::validate_tapos( const transaction& trx )const { try {
   const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)trx.ref_block_num);

   //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
   EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception,
              "Transaction's reference block did not match. Is this transaction from a different fork?",
              ("tapos_summary", tapos_block_summary));
1304 1305
} FC_CAPTURE_AND_RETHROW() }

1306

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