controller.cpp 49.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 109

#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 );


D
Daniel Larimer 已提交
110 111 112 113
   }

   void init() {
      // ilog( "${c}", ("c",fc::json::to_pretty_string(cfg)) );
114
      add_indices();
D
Daniel Larimer 已提交
115 116

      /**
117 118 119 120 121 122 123 124 125 126 127 128 129 130
      *  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 已提交
131 132 133 134 135
       * 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.
       */
136
      //clear_all_undo();
D
Daniel Larimer 已提交
137 138 139 140
   }

   ~controller_impl() {
      pending.reset();
D
Daniel Larimer 已提交
141 142 143

      edump((db.revision())(head->block_num));

D
Daniel Larimer 已提交
144 145 146
      db.flush();
   }

147
   void add_indices() {
D
Daniel Larimer 已提交
148
      db.add_index<account_index>();
149
      db.add_index<account_sequence_index>();
D
Daniel Larimer 已提交
150

D
Daniel Larimer 已提交
151 152 153 154 155 156
      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 已提交
157
      db.add_index<index_long_double_index>();
D
Daniel Larimer 已提交
158 159 160 161 162 163 164 165

      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>();

166 167
      authorization.add_indices();
      resource_limits.add_indices();
D
Daniel Larimer 已提交
168 169 170 171 172 173 174
   }

   void clear_all_undo() {
      // Rewind the database to the last irreversible block
      db.with_write_lock([&] {
         db.undo_all();
         /*
175
         FC_ASSERT(db.revision() == self.head_block_num(),
D
Daniel Larimer 已提交
176 177 178 179 180 181 182
                   "Chainbase revision does not match head block num",
                   ("rev", db.revision())("head_block", self.head_block_num()));
                   */
      });
   }

   /**
183
    *  Sets fork database head to the genesis state.
D
Daniel Larimer 已提交
184 185
    */
   void initialize_fork_db() {
186 187
      wlog( " Initializing new blockchain with genesis state                  " );
      producer_schedule_type initial_schedule{ 0, {{N(eosio), conf.genesis.initial_key}} };
D
Daniel Larimer 已提交
188

189 190 191 192 193 194 195 196
      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 已提交
197

198
      head = std::make_shared<block_state>( genheader );
D
Daniel Larimer 已提交
199
      head->block = std::make_shared<signed_block>(genheader.header);
200
      fork_db.set( head );
D
Daniel Larimer 已提交
201 202 203
      db.set_revision( head->block_num );

      initialize_database();
A
arhag 已提交
204

D
Daniel Larimer 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
      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 已提交
225 226
   }

227
   void create_native_account( account_name name, const authority& owner, const authority& active, bool is_privileged = false ) {
228
      db.create<account_object>([&](auto& a) {
D
Daniel Larimer 已提交
229 230
         a.name = name;
         a.creation_date = conf.genesis.initial_timestamp;
231
         a.privileged = is_privileged;
D
Daniel Larimer 已提交
232 233

         if( name == config::system_account_name ) {
D
Daniel Larimer 已提交
234
            a.set_abi(eosio_contract_abi(abi_def()));
D
Daniel Larimer 已提交
235 236
         }
      });
237 238 239 240
      db.create<account_sequence_object>([&](auto & a) {
        a.name = name;
      });

241 242 243 244
      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 已提交
245 246

      resource_limits.initialize_account(name);
247 248 249 250 251 252 253 254
      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 已提交
255 256 257 258 259 260 261
   }

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

262 263 264 265 266
      const auto& tapos_block_summary = db.get<block_summary_object>(1);
      db.modify( tapos_block_summary, [&]( auto& bs ) {
        bs.block_id = head->id;
      });

267 268 269 270
      db.create<global_property_object>([&](auto& gpo ){
        gpo.configuration = conf.genesis.initial_configuration;
      });
      db.create<dynamic_global_property_object>([](auto&){});
271 272 273 274 275 276

      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 已提交
277

278 279
      auto empty_authority = authority(1, {}, {});
      auto active_producers_authority = authority(1, {}, {});
D
Daniel Larimer 已提交
280 281
      active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});

282 283
      create_native_account( config::nobody_account_name, empty_authority, empty_authority );
      create_native_account( config::producers_account_name, empty_authority, active_producers_authority );
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
      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 已提交
300 301
   }

302

303

A
arhag 已提交
304
   void commit_block( bool add_to_fork_db ) {
D
Daniel Larimer 已提交
305 306
      if( add_to_fork_db ) {
         pending->_pending_block_state->validated = true;
307 308 309
         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" );
310
      }
311

312
      //ilog((fc::json::to_pretty_string(*pending->_pending_block_state->block)));
D
Daniel Larimer 已提交
313
      self.accepted_block( pending->_pending_block_state );
D
Daniel Larimer 已提交
314 315
      pending->push();
      pending.reset();
D
Daniel Larimer 已提交
316 317 318 319

      if( !replaying ) {
         self.log_irreversible_blocks();
      }
D
Daniel Larimer 已提交
320
   }
D
Daniel Larimer 已提交
321

322 323 324 325
   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 已提交
326
      signed_transaction etrx;
327 328 329 330 331 332
      // 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 已提交
333

334 335 336 337 338
      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 已提交
339

340 341 342 343 344
         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 已提交
345

346
            remove_scheduled_transaction( gto );
D
Daniel Larimer 已提交
347

348
            self.applied_transaction( trace );
D
Daniel Larimer 已提交
349

350 351 352 353 354 355 356 357 358 359 360 361
            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 已提交
362 363
   }

364 365 366 367
   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 已提交
368

369
      resource_limits.add_pending_account_ram_usage(gto.payer,
370
                                     -(config::billable_size_v<generated_transaction_object> + gto.packed_trx.size()));
D
Daniel Larimer 已提交
371 372 373 374

      db.remove( gto );
   }

375 376 377 378
   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 已提交
379
      fc::datastream<const char*> ds( gto.packed_trx.data(), gto.packed_trx.size() );
D
Daniel Larimer 已提交
380

381 382 383 384
      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 已提交
385 386
         return;
      }
387 388 389

      optional<fc::exception> soft_except;
      optional<fc::exception> hard_except;
390
      std::exception_ptr except_ptr;
D
Daniel Larimer 已提交
391
      std::exception_ptr hard_except_ptr;
392

393
      auto start = fc::time_point::now();
D
Daniel Larimer 已提交
394
      transaction_trace_ptr trace;
395 396 397
      flat_set<account_name>  bill_to_accounts;
      uint64_t max_cpu;
      bool abort_on_error = false;
D
Daniel Larimer 已提交
398 399 400
      try {
         signed_transaction dtrx;
         fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
401

402 403 404 405 406
         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;
407 408 409

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

A
arhag 已提交
410 411
         trx_context.trace->receipt = push_receipt( gto.trx_id,
                                                    transaction_receipt::executed,
412 413
                                                    trace->cpu_usage,
                                                    trace->net_usage );
414

415
         remove_scheduled_transaction( gto );
416

417 418 419 420 421 422
         try {
            self.applied_transaction( trx_context.trace );
         } catch( ... ) {
            abort_on_error = true;
            throw;
         }
423
         trx_context.squash();
424
         undo_session.squash();
425
         return;
D
Daniel Larimer 已提交
426
      } catch( const fc::exception& e ) {
427 428 429 430 431
         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 已提交
432
      }
433 434 435 436 437 438 439
      // 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.
440
         edump((soft_except->to_detail_string()));
441 442 443 444 445 446
         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;
447
         }
448 449 450 451 452 453
      } 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 已提交
454
      }
455
      // Only hard failure logic below:
456

457 458 459 460 461
      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;
462

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

465
      remove_scheduled_transaction( gto );
466

D
Daniel Larimer 已提交
467
      self.applied_transaction( trace );
468 469 470

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

472 473 474 475

   /**
    *  Adds the transaction receipt to the pending block and returns it.
    */
476 477
   template<typename T>
   const transaction_receipt& push_receipt( const T& trx, transaction_receipt_header::status_enum status,
478 479 480 481 482
                                            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" );
483 484 485 486 487 488 489 490
      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;
   }

491
   bool push_next_unapplied_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
492
      auto itr = unapplied_transactions.begin();
493
      if( itr == unapplied_transactions.end() )
494
         return false;
D
Daniel Larimer 已提交
495

496 497 498
      // 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 已提交
499 500
   }

501 502
   void transaction_trace_notify( const transaction_metadata_ptr& trx, const transaction_trace_ptr& trace ) {
      if( trx->on_result ) {
503 504
         (trx->on_result)(trace);
         trx->on_result = decltype(trx->on_result)(); //assign empty std::function
505 506
      }
   }
507

508 509 510 511 512
   /**
    *  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.
    */
513 514
   void push_transaction( const transaction_metadata_ptr& trx,
                          fc::time_point deadline = fc::time_point::maximum(),
515 516
                          bool implicit = false )
   { try {
D
Daniel Larimer 已提交
517
      if( deadline == fc::time_point() ) {
518
         unapplied_transactions[trx->signed_id] = trx;
D
Daniel Larimer 已提交
519 520
         return;
      }
521

522
      auto start = fc::time_point::now();
523
      transaction_trace_ptr trace;
D
Daniel Larimer 已提交
524 525
      try {
         unapplied_transactions.erase( trx->signed_id );
526

527 528
         transaction_context trx_context( trace, self, trx->trx, trx->id, deadline,
                                          implicit, ( implicit ? 0 : trx->packed_trx.get_billable_size() ) );
529

530
         fc::microseconds required_delay(0);
531
         if( !implicit ) {
532 533
            required_delay = limit_delay( authorization.check_authorization( trx->trx.actions, trx->recover_keys() ) );
         }
534 535 536 537
         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()) );
538

539 540 541 542
         self.accepted_transaction(trx);

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

544 545 546
         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 已提交
547

548 549 550 551 552 553 554
         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 已提交
555
            } else {
556 557 558
               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 已提交
559
            }
560 561 562 563 564 565 566 567 568 569 570 571 572
            fc::move_append( pending->_actions, move(trx_context.executed) );

            if( !implicit )
               transaction_trace_notify(trx, trace);

            self.applied_transaction(trace);
            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;
573
         }
574 575
      } catch( const fc::exception& e ) {
         trace->hard_except = e;
D
Daniel Larimer 已提交
576
         trace->hard_except_ptr = std::current_exception();
D
Daniel Larimer 已提交
577
      }
578
      transaction_trace_notify(trx, trace);
579
   } FC_CAPTURE_AND_RETHROW() } /// push_transaction
D
Daniel Larimer 已提交
580

581

582
   void start_block( block_timestamp_type when ) {
583
      FC_ASSERT( !pending );
D
Daniel Larimer 已提交
584

585
      FC_ASSERT( db.revision() == head->block_num, "",
A
arhag 已提交
586
                ("db_head_block", db.revision())("controller_head_block", head->block_num)("fork_db_head_block", fork_db.head()->block_num) );
D
Daniel Larimer 已提交
587

588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
      pending = db.start_undo_session(true);
      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 已提交
610

611 612 613 614 615 616
      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 已提交
617 618 619

      clear_expired_input_transactions();
      update_producers_authority();
620
   } // start_block
D
Daniel Larimer 已提交
621 622


D
Daniel Larimer 已提交
623

624 625
   void sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
      auto p = pending->_pending_block_state;
626
      p->sign( signer_callback );
627 628
      static_cast<signed_block_header&>(*p->block) = p->header;
   } /// sign_block
D
Daniel Larimer 已提交
629

630
   void apply_block( const signed_block_ptr& b ) { try {
631 632 633 634 635 636 637 638 639
      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 已提交
640 641 642
            else if( receipt.trx.contains<transaction_id_type>() ) {
               self.push_scheduled_transaction( receipt.trx.get<transaction_id_type>() );
            }
643
         }
D
Daniel Larimer 已提交
644

645 646
         finalize_block();
         sign_block( [&]( const auto& ){ return b->producer_signature; } );
D
Daniel Larimer 已提交
647

648 649 650
         // 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 已提交
651

652 653
         commit_block(false);
         return;
D
Daniel Larimer 已提交
654
      } catch ( const fc::exception& e ) {
655 656
         edump((e.to_detail_string()));
         abort_block();
D
Daniel Larimer 已提交
657 658
         throw;
      }
659
   } FC_CAPTURE_AND_RETHROW() } /// apply_block
660 661


662
   void push_block( const signed_block_ptr& b ) {
D
Daniel Larimer 已提交
663 664 665 666
      try {
         auto new_header_state = fork_db.add( b );
         self.accepted_block_header( new_header_state );
         maybe_switch_forks();
A
arhag 已提交
667
      } FC_LOG_AND_RETHROW()
668
   }
669

670 671 672 673 674 675 676
   void push_confirmation( const header_confirmation& c ) {
      fork_db.add( c );
      self.accepted_confirmation( c );
      maybe_switch_forks();
   }

   void maybe_switch_forks() {
677 678 679 680
      auto new_head = fork_db.head();

      if( new_head->header.previous == head->id ) {
         try {
681
            abort_block();
682
            apply_block( new_head->block );
683
            fork_db.mark_in_current_chain( new_head, true );
684 685 686
            fork_db.set_validity( new_head, true );
            head = new_head;
         } catch ( const fc::exception& e ) {
687
            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.
688 689
            throw;
         }
690
      } else if( new_head->id != head->id ) {
691
         ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
A
arhag 已提交
692
              ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
693 694
         auto branches = fork_db.fetch_branch_from( new_head->id, head->id );

695 696
         for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
            fork_db.mark_in_current_chain( *itr , false );
697
            pop_block();
698
         }
A
arhag 已提交
699
         FC_ASSERT( self.head_block_id() == branches.second.back()->header.previous,
700
                    "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
701 702 703 704 705

         for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
            optional<fc::exception> except;
            try {
               apply_block( (*ritr)->block );
706
               head = *ritr;
707
               fork_db.mark_in_current_chain( *ritr, true );
708 709 710
            }
            catch (const fc::exception& e) { except = e; }
            if (except) {
711
               elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
712

713 714 715 716
               while (ritr != branches.first.rend() ) {
                  fork_db.set_validity( *ritr, false );
                  ++ritr;
               }
717

718
               // pop all blocks from the bad fork
719 720
               for( auto itr = (ritr + 1).base(); itr != branches.second.end(); ++itr ) {
                  fork_db.mark_in_current_chain( *itr , false );
721
                  pop_block();
722
               }
A
arhag 已提交
723
               FC_ASSERT( self.head_block_id() == branches.second.back()->header.previous,
724
                          "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
725

726 727 728
               // re-apply good blocks
               for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
                  apply_block( (*ritr)->block );
729
                  head = *ritr;
730
                  fork_db.mark_in_current_chain( *ritr, true );
731 732 733 734
               }
               throw *except;
            } // end if exception
         } /// end for each block in branch
735
         ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id));
736 737 738
      }
   } /// push_block

739
   void abort_block() {
740
      if( pending ) {
741
         for( const auto& t : pending->_pending_block_state->trxs )
742
            unapplied_transactions[t->signed_id] = t;
743 744
         pending.reset();
      }
745 746
   }

D
Daniel Larimer 已提交
747 748 749 750 751

   bool should_enforce_runtime_limits()const {
      return false;
   }

D
Daniel Larimer 已提交
752 753 754 755 756 757 758 759
   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 已提交
760

D
Daniel Larimer 已提交
761 762
   void set_trx_merkle() {
      vector<digest_type> trx_digests;
D
Daniel Larimer 已提交
763 764 765
      const auto& trxs = pending->_pending_block_state->block->transactions;
      trx_digests.reserve( trxs.size() );
      for( const auto& a : trxs )
D
Daniel Larimer 已提交
766
         trx_digests.emplace_back( a.digest() );
D
Daniel Larimer 已提交
767

D
Daniel Larimer 已提交
768
      pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) );
D
Daniel Larimer 已提交
769 770 771
   }


772
   void finalize_block()
D
Daniel Larimer 已提交
773
   { try {
D
Daniel Larimer 已提交
774 775 776
      if( !pending ) self.start_block();

      /*
777
      ilog( "finalize block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}",
A
arhag 已提交
778 779
            ("n",pending->_pending_block_state->block_num)
            ("id",pending->_pending_block_state->header.id())
780
            ("t",pending->_pending_block_state->header.timestamp)
A
arhag 已提交
781 782
            ("p",pending->_pending_block_state->header.producer)
            ("signing_key", pending->_pending_block_state->block_signing_key)
783 784
            ("v",pending->_pending_block_state->header.schedule_version)
            ("lib",pending->_pending_block_state->dpos_last_irreversible_blocknum)
785
            ("ndtrxs",db.get_index<generated_transaction_multi_index,by_trx_id>().size())
786 787
            ("np",pending->_pending_block_state->header.new_producers)
            );
788
      */
D
Daniel Larimer 已提交
789

A
arhag 已提交
790 791 792 793 794 795 796 797 798
      // 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 已提交
799 800 801 802 803 804
      set_action_merkle();
      set_trx_merkle();

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

A
arhag 已提交
805
      create_block_summary(p->id);
D
Daniel Larimer 已提交
806 807 808

   } FC_CAPTURE_AND_RETHROW() }

A
arhag 已提交
809 810
   void update_producers_authority() {
      const auto& producers = pending->_pending_block_state->active_schedule.producers;
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845

      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 已提交
846
   }
D
Daniel Larimer 已提交
847

A
arhag 已提交
848 849 850
   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 已提交
851
      db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
A
arhag 已提交
852
          bso.block_id = id;
D
Daniel Larimer 已提交
853 854 855
      });
   }

A
arhag 已提交
856 857

   void clear_expired_input_transactions() {
D
Daniel Larimer 已提交
858 859 860
      //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 已提交
861 862
      auto now = self.pending_block_time();
      while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
D
Daniel Larimer 已提交
863 864 865 866
         transaction_idx.remove(*dedupe_index.begin());
      }
   }

A
arhag 已提交
867 868
   fc::microseconds limit_delay( fc::microseconds delay )const {
      auto max_delay = fc::seconds( self.get_global_properties().configuration.max_transaction_delay );
869
      return std::min(delay, max_delay);
A
arhag 已提交
870 871
   }

D
Daniel Larimer 已提交
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
   /*
   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 已提交
892
   signed_transaction get_on_block_transaction()
D
Daniel Larimer 已提交
893 894 895 896 897
   {
      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 已提交
898
      on_block_act.data = fc::raw::pack(self.head_block_header());
D
Daniel Larimer 已提交
899

D
Daniel Larimer 已提交
900
      signed_transaction trx;
D
Daniel Larimer 已提交
901
      trx.actions.emplace_back(std::move(on_block_act));
A
arhag 已提交
902 903
      trx.set_reference_block(self.head_block_id());
      trx.expiration = self.head_block_time() + fc::seconds(1);
D
Daniel Larimer 已提交
904 905 906
      return trx;
   }

907
}; /// controller_impl
D
Daniel Larimer 已提交
908

909
const resource_limits_manager&   controller::get_resource_limits_manager()const
D
Daniel Larimer 已提交
910 911 912
{
   return my->resource_limits;
}
913
resource_limits_manager&         controller::get_mutable_resource_limits_manager()
D
Daniel Larimer 已提交
914 915 916
{
   return my->resource_limits;
}
D
Daniel Larimer 已提交
917

918 919 920 921 922 923 924 925
const authorization_manager&   controller::get_authorization_manager()const
{
   return my->authorization;
}
authorization_manager&         controller::get_mutable_authorization_manager()
{
   return my->authorization;
}
D
Daniel Larimer 已提交
926 927 928 929 930 931 932 933 934 935 936

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

controller::~controller() {
}


void controller::startup() {
937
   my->init();
D
Daniel Larimer 已提交
938 939 940 941

   /*
   my->head = my->fork_db.head();
   if( !my->head ) {
D
Daniel Larimer 已提交
942
      elog( "No head block in fork db, perhaps we need to replay" );
D
Daniel Larimer 已提交
943 944 945 946
   }
   */
}

D
Daniel Larimer 已提交
947
chainbase::database& controller::db()const { return my->db; }
D
Daniel Larimer 已提交
948 949 950


void controller::start_block( block_timestamp_type when ) {
951
   my->start_block(when);
D
Daniel Larimer 已提交
952 953 954
}

void controller::finalize_block() {
D
Daniel Larimer 已提交
955
   my->finalize_block();
D
Daniel Larimer 已提交
956 957
}

958 959
void controller::sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
   my->sign_block( signer_callback );
D
Daniel Larimer 已提交
960 961 962
}

void controller::commit_block() {
D
Daniel Larimer 已提交
963
   my->commit_block(true);
D
Daniel Larimer 已提交
964 965
}

966 967
void controller::abort_block() {
   my->abort_block();
D
Daniel Larimer 已提交
968 969
}

D
Daniel Larimer 已提交
970
void controller::push_block( const signed_block_ptr& b ) {
971
   my->push_block( b );
D
Daniel Larimer 已提交
972 973 974
   if( !my->replaying ) {
      log_irreversible_blocks();
   }
D
Daniel Larimer 已提交
975 976
}

977 978 979 980
void controller::push_confirmation( const header_confirmation& c ) {
   my->push_confirmation( c );
}

D
Daniel Larimer 已提交
981 982 983
void controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline ) {
   my->push_transaction(trx, deadline);
}
984 985 986

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

D
Daniel Larimer 已提交
989 990
transaction_trace_ptr controller::sync_push( const transaction_metadata_ptr& trx, time_point deadline ) {
   FC_ASSERT( deadline != fc::time_point() );
991
   transaction_trace_ptr trace;
992
   trx->on_result = [&]( const transaction_trace_ptr& t ){ trace = t; };
D
Daniel Larimer 已提交
993
   my->push_transaction( trx, deadline );
994
   return trace;
D
Daniel Larimer 已提交
995
}
D
Daniel Larimer 已提交
996

997
bool controller::push_next_scheduled_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
998
   const auto& idx = db().get_index<generated_transaction_multi_index,by_delay>();
999 1000 1001 1002 1003 1004
   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 已提交
1005
}
D
Daniel Larimer 已提交
1006

1007
void controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline ) {
D
Daniel Larimer 已提交
1008 1009 1010 1011
   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 已提交
1012 1013 1014 1015 1016
}

uint32_t controller::head_block_num()const {
   return my->head->block_num;
}
A
arhag 已提交
1017 1018 1019
time_point controller::head_block_time()const {
   return my->head->header.timestamp;
}
D
Daniel Larimer 已提交
1020 1021 1022
block_id_type controller::head_block_id()const {
   return my->head->id;
}
D
Daniel Larimer 已提交
1023 1024 1025
account_name  controller::head_block_producer()const {
   return my->head->header.producer;
}
A
arhag 已提交
1026 1027
const block_header& controller::head_block_header()const {
   return my->head->header;
D
Daniel Larimer 已提交
1028
}
A
arhag 已提交
1029 1030
block_state_ptr controller::head_block_state()const {
   return my->head;
D
Daniel Larimer 已提交
1031 1032
}

A
arhag 已提交
1033 1034 1035
block_state_ptr controller::pending_block_state()const {
   if( my->pending ) return my->pending->_pending_block_state;
   return block_state_ptr();
1036 1037 1038 1039
}
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 已提交
1040 1041
}

A
arhag 已提交
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
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 已提交
1057 1058 1059
const dynamic_global_property_object& controller::get_dynamic_global_properties()const {
  return my->db.get<dynamic_global_property_object>();
}
D
Daniel Larimer 已提交
1060 1061 1062
const global_property_object& controller::get_global_properties()const {
  return my->db.get<global_property_object>();
}
D
Daniel Larimer 已提交
1063 1064 1065 1066

/**
 *  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
1067
 *  fork database, saves it to disk, then removes the block from the fork database.
D
Daniel Larimer 已提交
1068 1069 1070 1071
 *
 *  Any forks built off of a different block with the same number are also pruned.
 */
void controller::log_irreversible_blocks() {
1072
   if( !my->blog.head() )
D
Daniel Larimer 已提交
1073
      my->blog.read_head();
1074

D
Daniel Larimer 已提交
1075 1076 1077 1078
   const auto& log_head = my->blog.head();
   auto lib = my->head->dpos_last_irreversible_blocknum;

   if( lib > 1 ) {
D
Daniel Larimer 已提交
1079
      while( log_head && (log_head->block_num()+1) < lib ) {
D
Daniel Larimer 已提交
1080
         auto lhead = log_head->block_num();
1081 1082
         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));
1083
         irreversible_block( blk );
D
Daniel Larimer 已提交
1084
         my->blog.append( blk->block );
D
Daniel Larimer 已提交
1085 1086
         my->fork_db.prune( blk );
         my->db.commit( lhead );
D
Daniel Larimer 已提交
1087 1088 1089
      }
   }
}
1090
signed_block_ptr controller::fetch_block_by_id( block_id_type id )const {
D
Daniel Larimer 已提交
1091
   idump((id));
1092 1093
   auto state = my->fork_db.get_block(id);
   if( state ) return state->block;
D
Daniel Larimer 已提交
1094
   edump((block_header::num_from_id(id)));
1095
   auto bptr = fetch_block_by_number( block_header::num_from_id(id) );
D
Daniel Larimer 已提交
1096 1097
   if( bptr && bptr->id() == id ) return bptr;
   elog( "not found" );
1098 1099 1100
   return signed_block_ptr();
}

D
Daniel Larimer 已提交
1101
signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const  { try {
1102
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
D
Daniel Larimer 已提交
1103 1104 1105
   if( blk_state ) {
      return blk_state->block;
   }
1106

D
Daniel Larimer 已提交
1107
   ilog( "blog read by number ${n}", ("n", block_num) );
D
Daniel Larimer 已提交
1108
   return my->blog.read_block_by_num(block_num);
D
Daniel Larimer 已提交
1109
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
D
Daniel Larimer 已提交
1110 1111

void controller::pop_block() {
1112
   my->pop_block();
D
Daniel Larimer 已提交
1113 1114
}

1115
bool controller::set_proposed_producers( vector<producer_key> producers ) {
1116 1117
   const auto& gpo = get_global_properties();
   auto cur_block_num = head_block_num() + 1;
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132

   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;

1133
   if( my->pending->_pending_block_state->pending_schedule.producers.size() == 0 ) {
1134 1135 1136 1137
      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;
1138
   } else {
1139 1140 1141 1142
      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;
1143
   }
1144 1145 1146 1147 1148 1149

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

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

1150 1151
   my->db.modify( gpo, [&]( auto& gp ) {
      gp.proposed_schedule_block_num = cur_block_num;
1152
      gp.proposed_schedule = std::move(sch);
1153
   });
1154
   return true;
D
Daniel Larimer 已提交
1155
}
1156 1157

const producer_schedule_type&    controller::active_producers()const {
1158 1159
   if ( !(my->pending) )
      return  my->head->active_schedule;
D
Daniel Larimer 已提交
1160 1161 1162
   return my->pending->_pending_block_state->active_schedule;
}

1163
const producer_schedule_type&    controller::pending_producers()const {
1164 1165
   if ( !(my->pending) )
      return  my->head->pending_schedule;
D
Daniel Larimer 已提交
1166 1167 1168
   return my->pending->_pending_block_state->pending_schedule;
}

1169 1170 1171 1172 1173 1174 1175 1176 1177
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 已提交
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
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 已提交
1191

1192
const account_object& controller::get_account( account_name name )const
D
Daniel Larimer 已提交
1193 1194 1195
{ try {
   return my->db.get<account_object, by_name>(name);
} FC_CAPTURE_AND_RETHROW( (name) ) }
D
Daniel Larimer 已提交
1196

1197 1198 1199 1200
const map<digest_type, transaction_metadata_ptr>&  controller::unapplied_transactions()const {
   return my->unapplied_transactions;
}

A
arhag 已提交
1201 1202 1203
fc::microseconds controller::limit_delay( fc::microseconds delay )const {
   return my->limit_delay( delay );
}
1204 1205 1206 1207 1208 1209

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 已提交
1210
   bool one_auth = false;
1211 1212
   for( const auto& a : trx.actions ) {
      get_account( a.account );
1213
      for( const auto& auth : a.authorization ) {
D
Daniel Larimer 已提交
1214
         one_auth = true;
1215 1216 1217
         get_account( auth.actor );
      }
   }
D
Daniel Larimer 已提交
1218
   EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" );
1219 1220 1221 1222 1223
}

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

1224 1225 1226 1227 1228
   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()));
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
   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));
1244 1245
} FC_CAPTURE_AND_RETHROW() }

1246

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