controller.cpp 78.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

#include <eosio/chain/block_log.hpp>
#include <eosio/chain/fork_database.hpp>
6
#include <eosio/chain/exceptions.hpp>
D
Daniel Larimer 已提交
7 8 9 10 11 12 13

#include <eosio/chain/account_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>
14
#include <eosio/chain/reversible_block_object.hpp>
D
Daniel Larimer 已提交
15

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

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

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

D
Daniel Larimer 已提交
25 26 27 28
namespace eosio { namespace chain {

using resource_limits::resource_limits_manager;

B
Bart Wyatt 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
class maybe_session {
   public:
      maybe_session() = default;

      maybe_session( maybe_session&& other)
      :_session(move(other._session))
      {
      }

      explicit maybe_session(database& db) {
         _session = db.start_undo_session(true);
      }

      maybe_session(const maybe_session&) = delete;

      void squash() {
         if (_session)
            _session->squash();
      }

      void undo() {
         if (_session)
            _session->undo();
      }

      void push() {
         if (_session)
            _session->push();
      }

      maybe_session& operator = ( maybe_session&& mv ) {
         if (mv._session) {
            _session = move(*mv._session);
            mv._session.reset();
         } else {
            _session.reset();
         }
66 67

         return *this;
B
Bart Wyatt 已提交
68 69 70 71 72
      };

   private:
      optional<database::session>     _session;
};
D
Daniel Larimer 已提交
73

D
Daniel Larimer 已提交
74
struct pending_state {
B
Bart Wyatt 已提交
75
   pending_state( maybe_session&& s )
D
Daniel Larimer 已提交
76 77
   :_db_session( move(s) ){}

B
Bart Wyatt 已提交
78
   maybe_session                      _db_session;
D
Daniel Larimer 已提交
79 80 81

   block_state_ptr                    _pending_block_state;

D
Daniel Larimer 已提交
82
   vector<action_receipt>             _actions;
D
Daniel Larimer 已提交
83

84
   controller::block_status           _block_status = controller::block_status::incomplete;
D
Daniel Larimer 已提交
85

86
   optional<block_id_type>            _producer_block_id;
87

D
Daniel Larimer 已提交
88 89 90 91 92 93
   void push() {
      _db_session.push();
   }
};

struct controller_impl {
D
Daniel Larimer 已提交
94
   controller&                    self;
D
Daniel Larimer 已提交
95
   chainbase::database            db;
96
   chainbase::database            reversible_blocks; ///< a special database to persist blocks that have successfully been applied but are still reversible
D
Daniel Larimer 已提交
97 98
   block_log                      blog;
   optional<pending_state>        pending;
99 100
   block_state_ptr                head;
   fork_database                  fork_db;
D
Daniel Larimer 已提交
101
   wasm_interface                 wasmif;
D
Daniel Larimer 已提交
102
   resource_limits_manager        resource_limits;
103
   authorization_manager          authorization;
D
Daniel Larimer 已提交
104
   controller::config             conf;
105
   chain_id_type                  chain_id;
106 107
   bool                           replaying= false;
   optional<fc::time_point>       replay_head_time;
A
Anton Perkov 已提交
108
   db_read_mode                   read_mode = db_read_mode::SPECULATIVE;
109
   bool                           in_trx_requiring_checks = false; ///< if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped
110
   optional<fc::microseconds>     subjective_cpu_leeway;
111
   bool                           trusted_producer_light_validation = false;
D
Daniel Larimer 已提交
112

D
Daniel Larimer 已提交
113 114 115
   typedef pair<scope_name,action_name>                   handler_key;
   map< account_name, map<handler_key, apply_handler> >   apply_handlers;

D
Daniel Larimer 已提交
116 117 118 119 120
   /**
    *  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.
    */
121
   map<digest_type, transaction_metadata_ptr>     unapplied_transactions;
D
Daniel Larimer 已提交
122

D
Daniel Larimer 已提交
123
   void pop_block() {
124
      auto prev = fork_db.get_block( head->header.previous );
125
      EOS_ASSERT( prev, block_validate_exception, "attempt to pop beyond last irreversible block" );
126

127
      if( const auto* b = reversible_blocks.find<reversible_block_object,by_num>(head->block_num) )
128
      {
129
         reversible_blocks.remove( *b );
130
      }
131

A
Anton Perkov 已提交
132
      if ( read_mode == db_read_mode::SPECULATIVE ) {
133 134 135
         for( const auto& t : head->trxs )
            unapplied_transactions[t->signed_id] = t;
      }
136
      head = prev;
D
Daniel Larimer 已提交
137
      db.undo();
138

D
Daniel Larimer 已提交
139 140 141
   }


A
arhag 已提交
142 143
   void set_apply_handler( account_name receiver, account_name contract, action_name action, apply_handler v ) {
      apply_handlers[receiver][make_pair(contract,action)] = v;
D
Daniel Larimer 已提交
144 145
   }

D
Daniel Larimer 已提交
146
   controller_impl( const controller::config& cfg, controller& s  )
D
Daniel Larimer 已提交
147
   :self(s),
148
    db( cfg.state_dir,
D
Daniel Larimer 已提交
149
        cfg.read_only ? database::read_only : database::read_write,
150 151
        cfg.state_size ),
    reversible_blocks( cfg.blocks_dir/config::reversible_blocks_dir_name,
152
        cfg.read_only ? database::read_only : database::read_write,
153
        cfg.reversible_cache_size ),
154 155
    blog( cfg.blocks_dir ),
    fork_db( cfg.state_dir ),
D
Daniel Larimer 已提交
156
    wasmif( cfg.wasm_runtime ),
D
Daniel Larimer 已提交
157
    resource_limits( db ),
D
Daniel Larimer 已提交
158
    authorization( s, db ),
159
    conf( cfg ),
160 161
    chain_id( cfg.genesis.compute_chain_id() ),
    read_mode( cfg.read_mode )
D
Daniel Larimer 已提交
162
   {
D
Daniel Larimer 已提交
163

A
arhag 已提交
164 165 166 167 168 169 170 171 172 173
#define SET_APP_HANDLER( receiver, contract, action) \
   set_apply_handler( #receiver, #contract, #action, &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )

   SET_APP_HANDLER( eosio, eosio, newaccount );
   SET_APP_HANDLER( eosio, eosio, setcode );
   SET_APP_HANDLER( eosio, eosio, setabi );
   SET_APP_HANDLER( eosio, eosio, updateauth );
   SET_APP_HANDLER( eosio, eosio, deleteauth );
   SET_APP_HANDLER( eosio, eosio, linkauth );
   SET_APP_HANDLER( eosio, eosio, unlinkauth );
174
/*
A
arhag 已提交
175 176 177
   SET_APP_HANDLER( eosio, eosio, postrecovery );
   SET_APP_HANDLER( eosio, eosio, passrecovery );
   SET_APP_HANDLER( eosio, eosio, vetorecovery );
178 179
*/

A
arhag 已提交
180
   SET_APP_HANDLER( eosio, eosio, canceldelay );
D
Daniel Larimer 已提交
181

182 183 184
   fork_db.irreversible.connect( [&]( auto b ) {
                                 on_irreversible(b);
                                 });
D
Daniel Larimer 已提交
185

D
Daniel Larimer 已提交
186 187
   }

188 189 190
   /**
    *  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
191
    *  cause a node to fork.
192
    *
193 194 195
    *  If it is ever desirable to let a signal handler bubble an exception out of this method
    *  a full audit of its uses needs to be undertaken.
    *
196 197
    */
   template<typename Signal, typename Arg>
198
   void emit( const Signal& s, Arg&& a ) {
199 200
      try {
        s(std::forward<Arg>(a));
B
Bucky Kittinger 已提交
201
      } catch (boost::interprocess::bad_alloc& e) {
B
Bucky Kittinger 已提交
202
         wlog( "bad alloc" );
B
Bucky Kittinger 已提交
203
         throw e;
A
arhag 已提交
204 205 206
      } catch ( controller_emit_signal_exception& e ) {
         wlog( "${details}", ("details", e.to_detail_string()) );
         throw e;
207 208
      } catch ( fc::exception& e ) {
         wlog( "${details}", ("details", e.to_detail_string()) );
209
      } catch ( ... ) {
210
         wlog( "signal handler threw exception" );
211 212 213
      }
   }

214 215 216 217 218
   void on_irreversible( const block_state_ptr& s ) {
      if( !blog.head() )
         blog.read_head();

      const auto& log_head = blog.head();
219
      EOS_ASSERT( log_head, block_log_exception, "block log head can not be found" );
220 221
      auto lh_block_num = log_head->block_num();

222 223
      db.commit( s->block_num );

224 225 226 227
      if( s->block_num <= lh_block_num ) {
//         edump((s->block_num)("double call to on_irr"));
//         edump((s->block_num)(s->block->previous)(log_head->id()));
         return;
228
      }
229

230 231
      EOS_ASSERT( s->block_num - 1  == lh_block_num, unlinkable_block_exception, "unlinkable block", ("s->block_num",s->block_num)("lh_block_num", lh_block_num) );
      EOS_ASSERT( s->block->previous == log_head->id(), unlinkable_block_exception, "irreversible doesn't link to block log head" );
232 233
      blog.append(s->block);

234
      const auto& ubi = reversible_blocks.get_index<reversible_block_index,by_num>();
235
      auto objitr = ubi.begin();
236
      while( objitr != ubi.end() && objitr->blocknum <= s->block_num ) {
237
         reversible_blocks.remove( *objitr );
238
         objitr = ubi.begin();
239
      }
240

A
Anton Perkov 已提交
241 242 243 244 245 246
      if ( read_mode == db_read_mode::IRREVERSIBLE ) {
         apply_block( s->block, controller::block_status::complete );
         fork_db.mark_in_current_chain( s, true );
         fork_db.set_validity( s, true );
         head = s;
      }
247
      emit( self.irreversible_block, s );
248 249
   }

D
Daniel Larimer 已提交
250 251 252
   void init() {

      /**
253 254 255 256 257 258 259 260
      *  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

261 262
         auto end = blog.read_head();
         if( end && end->block_num() > 1 ) {
B
Bart Wyatt 已提交
263
            auto end_time = end->timestamp.to_time_point();
264
            replaying = true;
265
            replay_head_time = end_time;
266 267 268 269
            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 ) ) {
270
               self.push_block( next, controller::block_status::irreversible );
271 272 273 274
               if( next->block_num() % 100 == 0 ) {
                  std::cerr << std::setw(10) << next->block_num() << " of " << end->block_num() <<"\r";
               }
            }
275 276
            std::cerr<< "\n";
            ilog( "${n} blocks replayed", ("n", head->block_num) );
277

A
arhag 已提交
278
            // if the irreverible log is played without undo sessions enabled, we need to sync the
279
            // revision ordinal to the appropriate expected value here.
A
arhag 已提交
280 281
            if( self.skip_db_sessions( controller::block_status::irreversible ) )
               db.set_revision(head->block_num);
282

283
            int rev = 0;
284
            while( auto obj = reversible_blocks.find<reversible_block_object,by_num>(head->block_num+1) ) {
285 286
               ++rev;
               self.push_block( obj->get_block(), controller::block_status::validated );
287 288
            }

289
            ilog( "${n} reversible blocks replayed", ("n",rev) );
290
            auto end = fc::time_point::now();
B
Bart Wyatt 已提交
291
            ilog( "replayed ${n} blocks in ${duration} seconds, ${mspb} ms/block",
A
arhag 已提交
292 293
                  ("n", head->block_num)("duration", (end-start).count()/1000000)
                  ("mspb", ((end-start).count()/1000.0)/head->block_num)        );
294
            replaying = false;
295
            replay_head_time.reset();
296 297

         } else if( !end ) {
298
            blog.reset_to_genesis( conf.genesis, head->block );
299 300
         }
      }
301

302
      const auto& ubi = reversible_blocks.get_index<reversible_block_index,by_num>();
303 304
      auto objitr = ubi.rbegin();
      if( objitr != ubi.rend() ) {
305
         EOS_ASSERT( objitr->blocknum == head->block_num, fork_database_exception,
306
                    "reversible block database is inconsistent with fork database, replay blockchain",
307 308 309
                    ("head",head->block_num)("unconfimed", objitr->blocknum)         );
      } else {
         auto end = blog.read_head();
310
         EOS_ASSERT( end && end->block_num() == head->block_num, fork_database_exception,
311
                    "fork database exists but reversible block database does not, replay blockchain",
312 313 314
                    ("blog_head",end->block_num())("head",head->block_num)  );
      }

315
      EOS_ASSERT( db.revision() >= head->block_num, fork_database_exception, "fork database is inconsistent with shared memory",
316 317 318 319 320 321 322 323 324
                 ("db",db.revision())("head",head->block_num) );

      if( db.revision() > head->block_num ) {
         wlog( "warning: database revision (${db}) is greater than head block number (${head}), "
               "attempting to undo pending changes",
               ("db",db.revision())("head",head->block_num) );
      }
      while( db.revision() > head->block_num ) {
         db.undo();
325 326
      }

D
Daniel Larimer 已提交
327 328 329 330
   }

   ~controller_impl() {
      pending.reset();
D
Daniel Larimer 已提交
331

D
Daniel Larimer 已提交
332
      db.flush();
333
      reversible_blocks.flush();
D
Daniel Larimer 已提交
334 335
   }

336
   void add_indices() {
337
      reversible_blocks.add_index<reversible_block_index>();
338

D
Daniel Larimer 已提交
339
      db.add_index<account_index>();
340
      db.add_index<account_sequence_index>();
D
Daniel Larimer 已提交
341

D
Daniel Larimer 已提交
342 343 344 345 346 347
      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 已提交
348
      db.add_index<index_long_double_index>();
D
Daniel Larimer 已提交
349 350 351 352 353 354 355

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

356 357
      authorization.add_indices();
      resource_limits.add_indices();
D
Daniel Larimer 已提交
358 359 360 361 362 363 364
   }

   void clear_all_undo() {
      // Rewind the database to the last irreversible block
      db.with_write_lock([&] {
         db.undo_all();
         /*
365
         FC_ASSERT(db.revision() == self.head_block_num(),
D
Daniel Larimer 已提交
366 367 368 369 370 371 372
                   "Chainbase revision does not match head block num",
                   ("rev", db.revision())("head_block", self.head_block_num()));
                   */
      });
   }

   /**
373
    *  Sets fork database head to the genesis state.
D
Daniel Larimer 已提交
374 375
    */
   void initialize_fork_db() {
376
      wlog( " Initializing new blockchain with genesis state                  " );
377
      producer_schedule_type initial_schedule{ 0, {{config::system_account_name, conf.genesis.initial_key}} };
D
Daniel Larimer 已提交
378

379 380 381 382 383 384 385 386
      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 已提交
387

388
      head = std::make_shared<block_state>( genheader );
D
Daniel Larimer 已提交
389
      head->block = std::make_shared<signed_block>(genheader.header);
390
      fork_db.set( head );
D
Daniel Larimer 已提交
391 392 393
      db.set_revision( head->block_num );

      initialize_database();
D
Daniel Larimer 已提交
394 395
   }

396
   void create_native_account( account_name name, const authority& owner, const authority& active, bool is_privileged = false ) {
397
      db.create<account_object>([&](auto& a) {
D
Daniel Larimer 已提交
398 399
         a.name = name;
         a.creation_date = conf.genesis.initial_timestamp;
400
         a.privileged = is_privileged;
D
Daniel Larimer 已提交
401 402

         if( name == config::system_account_name ) {
D
Daniel Larimer 已提交
403
            a.set_abi(eosio_contract_abi(abi_def()));
D
Daniel Larimer 已提交
404 405
         }
      });
406 407 408 409
      db.create<account_sequence_object>([&](auto & a) {
        a.name = name;
      });

410 411 412 413
      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 已提交
414 415

      resource_limits.initialize_account(name);
416 417 418 419 420 421 422 423

      int64_t ram_delta = config::overhead_per_account_ram_bytes;
      ram_delta += 2*config::billable_size_v<permission_object>;
      ram_delta += owner_permission.auth.get_billable_size();
      ram_delta += active_permission.auth.get_billable_size();

      resource_limits.add_pending_ram_usage(name, ram_delta);
      resource_limits.verify_account_ram_usage(name);
D
Daniel Larimer 已提交
424 425 426 427 428 429 430
   }

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

431 432 433 434 435
      const auto& tapos_block_summary = db.get<block_summary_object>(1);
      db.modify( tapos_block_summary, [&]( auto& bs ) {
        bs.block_id = head->id;
      });

436
      conf.genesis.initial_configuration.validate();
437 438 439 440
      db.create<global_property_object>([&](auto& gpo ){
        gpo.configuration = conf.genesis.initial_configuration;
      });
      db.create<dynamic_global_property_object>([](auto&){});
441 442 443 444 445 446

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

448 449
      auto empty_authority = authority(1, {}, {});
      auto active_producers_authority = authority(1, {}, {});
D
Daniel Larimer 已提交
450 451
      active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});

452
      create_native_account( config::null_account_name, empty_authority, empty_authority );
453
      create_native_account( config::producers_account_name, empty_authority, active_producers_authority );
454 455 456 457 458 459 460 461 462 463 464
      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 );
D
Daniel Larimer 已提交
465 466
   }

467

468

469 470 471
   /**
    * @post regardless of the success of commit block there is no active pending block
    */
A
arhag 已提交
472
   void commit_block( bool add_to_fork_db ) {
473 474 475
      auto reset_pending_on_exit = fc::make_scoped_exit([this]{
         pending.reset();
      });
476

477 478 479 480 481 482
      try {
         if (add_to_fork_db) {
            pending->_pending_block_state->validated = true;
            auto new_bsp = fork_db.add(pending->_pending_block_state);
            emit(self.accepted_block_header, pending->_pending_block_state);
            head = fork_db.head();
483
            EOS_ASSERT(new_bsp == head, fork_database_exception, "committed block did not become the new head in fork database");
484
         }
485

486 487 488 489 490 491
         if( !replaying ) {
            reversible_blocks.create<reversible_block_object>( [&]( auto& ubo ) {
               ubo.blocknum = pending->_pending_block_state->block_num;
               ubo.set_block( pending->_pending_block_state->block );
            });
         }
492

493 494 495 496 497 498
         emit( self.accepted_block, pending->_pending_block_state );
      } catch (...) {
         // dont bother resetting pending, instead abort the block
         reset_pending_on_exit.cancel();
         abort_block();
         throw;
499 500
      }

501
      // push the state for pending.
502
      pending->push();
D
Daniel Larimer 已提交
503
   }
D
Daniel Larimer 已提交
504

505
   // The returned scoped_exit should not exceed the lifetime of the pending which existed when make_block_restore_point was called.
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
   fc::scoped_exit<std::function<void()>> make_block_restore_point() {
      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();

      std::function<void()> callback = [this,
                                        orig_block_transactions_size,
                                        orig_state_transactions_size,
                                        orig_state_actions_size]()
      {
         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);
      };

      return fc::make_scoped_exit( std::move(callback) );
   }

524
   transaction_trace_ptr apply_onerror( const generated_transaction& gtrx,
525
                                        fc::time_point deadline,
526
                                        fc::time_point start,
A
arhag 已提交
527
                                        uint32_t& cpu_time_to_bill_us, // only set on failure
528
                                        uint32_t billed_cpu_time_us,
529
                                        bool explicit_billed_cpu_time = false ) {
D
Daniel Larimer 已提交
530
      signed_transaction etrx;
531
      // Deliver onerror action containing the failed deferred transaction directly back to the sender.
532 533
      etrx.actions.emplace_back( vector<permission_level>{{gtrx.sender, config::active_name}},
                                 onerror( gtrx.sender_id, gtrx.packed_trx.data(), gtrx.packed_trx.size() ) );
534
      etrx.expiration = self.pending_block_time() + fc::microseconds(999'999); // Round up to avoid appearing expired
535
      etrx.set_reference_block( self.head_block_id() );
D
Daniel Larimer 已提交
536

537
      transaction_context trx_context( self, etrx, etrx.id(), start );
A
arhag 已提交
538
      trx_context.deadline = deadline;
539
      trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time;
540
      trx_context.billed_cpu_time_us = billed_cpu_time_us;
541
      transaction_trace_ptr trace = trx_context.trace;
542
      try {
A
arhag 已提交
543
         trx_context.init_for_implicit_trx();
544
         trx_context.published = gtrx.published;
545
         trx_context.trace->action_traces.emplace_back();
546
         trx_context.dispatch_action( trx_context.trace->action_traces.back(), etrx.actions.back(), gtrx.sender );
547
         trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
D
Daniel Larimer 已提交
548

549
         auto restore = make_block_restore_point();
550
         trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::soft_fail,
551
                                        trx_context.billed_cpu_time_us, trace->net_usage );
552
         fc::move_append( pending->_actions, move(trx_context.executed) );
D
Daniel Larimer 已提交
553

554 555 556
         trx_context.squash();
         restore.cancel();
         return trace;
557
      } catch( const fc::exception& e ) {
A
arhag 已提交
558
         cpu_time_to_bill_us = trx_context.update_billed_cpu_time( fc::time_point::now() );
559 560
         trace->except = e;
         trace->except_ptr = std::current_exception();
561 562
      }
      return trace;
D
Daniel Larimer 已提交
563 564
   }

565
   void remove_scheduled_transaction( const generated_transaction_object& gto ) {
566 567 568 569 570
      resource_limits.add_pending_ram_usage(
         gto.payer,
         -(config::billable_size_v<generated_transaction_object> + gto.packed_trx.size())
      );
      // No need to verify_account_ram_usage since we are only reducing memory
D
Daniel Larimer 已提交
571 572 573 574

      db.remove( gto );
   }

575
   bool failure_is_subjective( const fc::exception& e ) const {
576
      auto code = e.code();
A
arhag 已提交
577 578
      return    (code == subjective_block_production_exception::code_value)
             || (code == block_net_usage_exceeded::code_value)
579
             || (code == greylist_net_usage_exceeded::code_value)
580
             || (code == block_cpu_usage_exceeded::code_value)
581
             || (code == greylist_cpu_usage_exceeded::code_value)
582 583 584 585 586
             || (code == deadline_exception::code_value)
             || (code == leeway_deadline_exception::code_value)
             || (code == actor_whitelist_exception::code_value)
             || (code == actor_blacklist_exception::code_value)
             || (code == contract_whitelist_exception::code_value)
A
arhag 已提交
587
             || (code == contract_blacklist_exception::code_value)
A
arhag 已提交
588 589
             || (code == action_blacklist_exception::code_value)
             || (code == key_blacklist_exception::code_value);
590 591
   }

592 593 594 595 596 597
   bool scheduled_failure_is_subjective( const fc::exception& e ) const {
      auto code = e.code();
      return    (code == tx_cpu_usage_exceeded::code_value)
             || failure_is_subjective(e);
   }

598
   transaction_trace_ptr push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time = false ) {
599 600
      const auto& idx = db.get_index<generated_transaction_multi_index,by_trx_id>();
      auto itr = idx.find( trxid );
601
      EOS_ASSERT( itr != idx.end(), unknown_transaction_exception, "unknown transaction" );
602
      return push_scheduled_transaction( *itr, deadline, billed_cpu_time_us, explicit_billed_cpu_time );
603 604
   }

605
   transaction_trace_ptr push_scheduled_transaction( const generated_transaction_object& gto, fc::time_point deadline, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time = false )
606
   { try {
B
Bart Wyatt 已提交
607 608 609
      maybe_session undo_session;
      if ( !self.skip_db_sessions() )
         undo_session = maybe_session(db);
610

611
      auto gtrx = generated_transaction(gto);
D
Daniel Larimer 已提交
612

613 614 615 616 617 618 619 620 621 622 623 624
      // remove the generated transaction object after making a copy
      // this will ensure that anything which affects the GTO multi-index-container will not invalidate
      // data we need to successfully retire this transaction.
      //
      // IF the transaction FAILs in a subjective way, `undo_session` should expire without being squashed
      // resulting in the GTO being restored and available for a future block to retire.
      remove_scheduled_transaction(gto);

      fc::datastream<const char*> ds( gtrx.packed_trx.data(), gtrx.packed_trx.size() );

      EOS_ASSERT( gtrx.delay_until <= self.pending_block_time(), transaction_exception, "this transaction isn't ready",
                 ("gtrx.delay_until",gtrx.delay_until)("pbt",self.pending_block_time())          );
625

626 627 628
      signed_transaction dtrx;
      fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
      transaction_metadata_ptr trx = std::make_shared<transaction_metadata>( dtrx );
629 630
      trx->accepted = true;
      trx->scheduled = true;
631

632
      transaction_trace_ptr trace;
633
      if( gtrx.expiration < self.pending_block_time() ) {
634
         trace = std::make_shared<transaction_trace>();
635
         trace->id = gtrx.trx_id;
636 637 638
         trace->block_num = self.pending_block_state()->block_num;
         trace->block_time = self.pending_block_time();
         trace->producer_block_id = self.pending_producer_block_id();
639
         trace->scheduled = true;
640
         trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction
641 642
         emit( self.accepted_transaction, trx );
         emit( self.applied_transaction, trace );
643
         undo_session.squash();
644
         return trace;
D
Daniel Larimer 已提交
645
      }
646

647 648 649 650 651
      auto reset_in_trx_requiring_checks = fc::make_scoped_exit([old_value=in_trx_requiring_checks,this](){
         in_trx_requiring_checks = old_value;
      });
      in_trx_requiring_checks = true;

A
arhag 已提交
652 653
      uint32_t cpu_time_to_bill_us = billed_cpu_time_us;

654
      transaction_context trx_context( self, dtrx, gtrx.trx_id );
B
Bart Wyatt 已提交
655
      trx_context.leeway =  fc::microseconds(0); // avoid stealing cpu resource
A
arhag 已提交
656
      trx_context.deadline = deadline;
657
      trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time;
658
      trx_context.billed_cpu_time_us = billed_cpu_time_us;
659
      trace = trx_context.trace;
D
Daniel Larimer 已提交
660
      try {
661
         trx_context.init_for_deferred_trx( gtrx.published );
662 663
         trx_context.exec();
         trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
664

665
         auto restore = make_block_restore_point();
666

667
         trace->receipt = push_receipt( gtrx.trx_id,
668
                                        transaction_receipt::executed,
669
                                        trx_context.billed_cpu_time_us,
670
                                        trace->net_usage );
671

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

674
         emit( self.accepted_transaction, trx );
675
         emit( self.applied_transaction, trace );
676

677
         trx_context.squash();
678
         undo_session.squash();
679

680
         restore.cancel();
681

682
         return trace;
D
Daniel Larimer 已提交
683
      } catch( const fc::exception& e ) {
A
arhag 已提交
684
         cpu_time_to_bill_us = trx_context.update_billed_cpu_time( fc::time_point::now() );
685 686
         trace->except = e;
         trace->except_ptr = std::current_exception();
687
         trace->elapsed = fc::time_point::now() - trx_context.start;
D
Daniel Larimer 已提交
688
      }
689
      trx_context.undo();
690

691
      // Only subjective OR soft OR hard failure logic below:
692

693
      if( gtrx.sender != account_name() && !failure_is_subjective(*trace->except)) {
694
         // Attempt error handling for the generated transaction.
695
         dlog("${detail}", ("detail", trace->except->to_detail_string()));
696
         auto error_trace = apply_onerror( gtrx, deadline, trx_context.pseudo_start, cpu_time_to_bill_us, billed_cpu_time_us, explicit_billed_cpu_time );
697 698
         error_trace->failed_dtrx_trace = trace;
         trace = error_trace;
699
         if( !trace->except_ptr ) {
700 701
            emit( self.accepted_transaction, trx );
            emit( self.applied_transaction, trace );
702
            undo_session.squash();
703
            return trace;
704
         }
705
         trace->elapsed = fc::time_point::now() - trx_context.start;
D
Daniel Larimer 已提交
706
      }
707

708
      // Only subjective OR hard failure logic below:
709

710 711 712 713 714 715 716 717 718
      // subjectivity changes based on producing vs validating
      bool subjective  = false;
      if (explicit_billed_cpu_time) {
         subjective = failure_is_subjective(*trace->except);
      } else {
         subjective = scheduled_failure_is_subjective(*trace->except);
      }

      if ( !subjective ) {
719 720
         // hard failure logic

721
         if( !explicit_billed_cpu_time ) {
722 723 724
            auto& rl = self.get_mutable_resource_limits_manager();
            rl.update_account_usage( trx_context.bill_to_accounts, block_timestamp_type(self.pending_block_time()).slot );
            int64_t account_cpu_limit = 0;
725
            std::tie( std::ignore, account_cpu_limit, std::ignore, std::ignore ) = trx_context.max_bandwidth_billed_accounts_can_pay( true );
726 727 728 729

            cpu_time_to_bill_us = static_cast<uint32_t>( std::min( std::min( static_cast<int64_t>(cpu_time_to_bill_us),
                                                                             account_cpu_limit                          ),
                                                                   trx_context.initial_objective_duration_limit.count()    ) );
730
         }
A
arhag 已提交
731

732
         resource_limits.add_transaction_usage( trx_context.bill_to_accounts, cpu_time_to_bill_us, 0,
A
arhag 已提交
733 734 735
                                                block_timestamp_type(self.pending_block_time()).slot ); // Should never fail

         trace->receipt = push_receipt(gtrx.trx_id, transaction_receipt::hard_fail, cpu_time_to_bill_us, 0);
736 737

         emit( self.accepted_transaction, trx );
738
         emit( self.applied_transaction, trace );
739

740
         undo_session.squash();
741 742 743
      } else {
         emit( self.accepted_transaction, trx );
         emit( self.applied_transaction, trace );
744
      }
745

746
      return trace;
747
   } FC_CAPTURE_AND_RETHROW() } /// push_scheduled_transaction
D
Daniel Larimer 已提交
748

749 750 751 752

   /**
    *  Adds the transaction receipt to the pending block and returns it.
    */
753 754
   template<typename T>
   const transaction_receipt& push_receipt( const T& trx, transaction_receipt_header::status_enum status,
755
                                            uint64_t cpu_usage_us, uint64_t net_usage ) {
756
      uint64_t net_usage_words = net_usage / 8;
757
      EOS_ASSERT( net_usage_words*8 == net_usage, transaction_exception, "net_usage is not divisible by 8" );
758 759
      pending->_pending_block_state->block->transactions.emplace_back( trx );
      transaction_receipt& r = pending->_pending_block_state->block->transactions.back();
760
      r.cpu_usage_us         = cpu_usage_us;
761 762 763 764 765 766 767 768 769 770
      r.net_usage_words      = net_usage_words;
      r.status               = status;
      return r;
   }

   /**
    *  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.
    */
771 772
   transaction_trace_ptr push_transaction( const transaction_metadata_ptr& trx,
                                           fc::time_point deadline,
773 774
                                           uint32_t billed_cpu_time_us,
                                           bool explicit_billed_cpu_time = false )
A
arhag 已提交
775
   {
776
      EOS_ASSERT(deadline != fc::time_point(), transaction_exception, "deadline cannot be uninitialized");
777

778
      transaction_trace_ptr trace;
D
Daniel Larimer 已提交
779
      try {
780
         transaction_context trx_context(self, trx->trx, trx->id);
K
Kayan 已提交
781
         if ((bool)subjective_cpu_leeway && pending->_block_status == controller::block_status::incomplete) {
782 783
            trx_context.leeway = *subjective_cpu_leeway;
         }
A
arhag 已提交
784
         trx_context.deadline = deadline;
785
         trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time;
786
         trx_context.billed_cpu_time_us = billed_cpu_time_us;
787 788
         trace = trx_context.trace;
         try {
789
            if( trx->implicit ) {
A
arhag 已提交
790
               trx_context.init_for_implicit_trx();
791
               trx_context.can_subjectively_fail = false;
792
            } else {
793
               bool skip_recording = replay_head_time && (time_point(trx->trx.expiration) <= *replay_head_time);
A
arhag 已提交
794 795
               trx_context.init_for_input_trx( trx->packed_trx.get_unprunable_size(),
                                               trx->packed_trx.get_prunable_size(),
796 797
                                               trx->trx.signatures.size(),
                                               skip_recording);
798
            }
799

800
            if( trx_context.can_subjectively_fail && pending->_block_status == controller::block_status::incomplete ) {
801 802 803 804
               check_actor_list( trx_context.bill_to_accounts ); // Assumes bill_to_accounts is the set of actors authorizing the transaction
            }


805 806
            trx_context.delay = fc::seconds(trx->trx.delay_sec);

807
            if( !self.skip_auth_check() && !trx->implicit ) {
808 809
               authorization.check_authorization(
                       trx->trx.actions,
810
                       trx->recover_keys( chain_id ),
811 812
                       {},
                       trx_context.delay,
B
Bucky Kittinger 已提交
813
                       [](){}
814 815
                       /*std::bind(&transaction_context::add_cpu_usage_and_check_time, &trx_context,
                                 std::placeholders::_1)*/,
816 817 818 819 820 821 822 823
                       false
               );
            }
            trx_context.exec();
            trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful

            auto restore = make_block_restore_point();

824
            if (!trx->implicit) {
825 826 827
               transaction_receipt::status_enum s = (trx_context.delay == fc::seconds(0))
                                                    ? transaction_receipt::executed
                                                    : transaction_receipt::delayed;
828
               trace->receipt = push_receipt(trx->packed_trx, s, trx_context.billed_cpu_time_us, trace->net_usage);
829 830 831 832
               pending->_pending_block_state->trxs.emplace_back(trx);
            } else {
               transaction_receipt_header r;
               r.status = transaction_receipt::executed;
833
               r.cpu_usage_us = trx_context.billed_cpu_time_us;
834 835 836
               r.net_usage_words = trace->net_usage / 8;
               trace->receipt = r;
            }
D
Daniel Larimer 已提交
837

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

840 841 842
            // call the accept signal but only once for this transaction
            if (!trx->accepted) {
               trx->accepted = true;
843
               emit( self.accepted_transaction, trx);
844
            }
845

846
            emit(self.applied_transaction, trace);
847

848

A
Anton Perkov 已提交
849
            if ( read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete ) {
850 851 852
               //this may happen automatically in destructor, but I prefere make it more explicit
               trx_context.undo();
            } else {
853 854 855
               restore.cancel();
               trx_context.squash();
            }
856

857
            if (!trx->implicit) {
858 859
               unapplied_transactions.erase( trx->signed_id );
            }
860 861 862 863 864
            return trace;
         } catch (const fc::exception& e) {
            trace->except = e;
            trace->except_ptr = std::current_exception();
         }
865

866 867 868 869
         if (!failure_is_subjective(*trace->except)) {
            unapplied_transactions.erase( trx->signed_id );
         }

870 871 872
         emit( self.accepted_transaction, trx );
         emit( self.applied_transaction, trace );

873 874 875
         return trace;
      } FC_CAPTURE_AND_RETHROW((trace))
   } /// push_transaction
D
Daniel Larimer 已提交
876

877

878 879 880
   void start_block( block_timestamp_type when, uint16_t confirm_block_count, controller::block_status s,
                     const optional<block_id_type>& producer_block_id )
   {
B
Bart Wyatt 已提交
881
      EOS_ASSERT( !pending, block_validate_exception, "pending block already exists" );
D
Daniel Larimer 已提交
882

B
Bart Wyatt 已提交
883 884 885
      auto guard_pending = fc::make_scoped_exit([this](){
         pending.reset();
      });
886

887
      if (!self.skip_db_sessions(s)) {
888 889
         EOS_ASSERT( db.revision() == head->block_num, database_exception, "db revision is not on par with head block",
                     ("db.revision()", db.revision())("controller_head_block", head->block_num)("fork_db_head_block", fork_db.head()->block_num) );
890

B
Bart Wyatt 已提交
891
         pending.emplace(maybe_session(db));
892
      } else {
B
Bart Wyatt 已提交
893
         pending.emplace(maybe_session());
894
      }
895

896
      pending->_block_status = s;
897
      pending->_producer_block_id = producer_block_id;
898 899 900
      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;

901 902 903 904
      pending->_pending_block_state->set_confirmed(confirm_block_count);

      auto was_pending_promoted = pending->_pending_block_state->maybe_promote_pending();

905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
      //modify state in speculative block only if we are speculative reads mode (other wise we need clean state for head or irreversible reads)
      if ( read_mode == db_read_mode::SPECULATIVE || pending->_block_status != controller::block_status::incomplete ) {

         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_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 ...
             !was_pending_promoted // ... and not just because it was promoted to active at the start of this block, then:
         )
            {
               // Promote proposed schedule to pending schedule.
               if( !replaying ) {
                  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_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();
                  });
            }
928

929 930
         try {
            auto onbtrx = std::make_shared<transaction_metadata>( get_on_block_transaction() );
931
            onbtrx->implicit = true;
932 933 934 935
            auto reset_in_trx_requiring_checks = fc::make_scoped_exit([old_value=in_trx_requiring_checks,this](){
                  in_trx_requiring_checks = old_value;
               });
            in_trx_requiring_checks = true;
936
            push_transaction( onbtrx, fc::time_point::maximum(), self.get_global_properties().configuration.min_transaction_cpu_usage, true );
937 938 939 940 941 942 943
         } catch( const boost::interprocess::bad_alloc& e  ) {
            elog( "on block transaction failed due to a bad allocation" );
            throw;
         } catch( const fc::exception& e ) {
            wlog( "on block transaction failed, but shouldn't impact block generation, system contract needs update" );
            edump((e.to_detail_string()));
         } catch( ... ) {
944
         }
D
Daniel Larimer 已提交
945

946 947
         clear_expired_input_transactions();
         update_producers_authority();
948
      }
A
arhag 已提交
949

B
Bart Wyatt 已提交
950
      guard_pending.cancel();
951
   } // start_block
D
Daniel Larimer 已提交
952 953


D
Daniel Larimer 已提交
954

955
   void sign_block( const std::function<signature_type( const digest_type& )>& signer_callback  ) {
956
      auto p = pending->_pending_block_state;
957

958
      p->sign( signer_callback );
959

960 961
      static_cast<signed_block_header&>(*p->block) = p->header;
   } /// sign_block
D
Daniel Larimer 已提交
962

963
   void apply_block( const signed_block_ptr& b, controller::block_status s ) { try {
964
      try {
965
         EOS_ASSERT( b->block_extensions.size() == 0, block_validate_exception, "no supported extensions" );
966 967
         auto producer_block_id = b->id();
         start_block( b->timestamp, b->confirmed, s , producer_block_id);
968

969 970
         transaction_trace_ptr trace;

971
         for( const auto& receipt : b->transactions ) {
A
arhag 已提交
972
            auto num_pending_receipts = pending->_pending_block_state->block->transactions.size();
973 974 975
            if( receipt.trx.contains<packed_transaction>() ) {
               auto& pt = receipt.trx.get<packed_transaction>();
               auto mtrx = std::make_shared<transaction_metadata>(pt);
976
               trace = push_transaction( mtrx, fc::time_point::maximum(), receipt.cpu_usage_us, true );
977
            } else if( receipt.trx.contains<transaction_id_type>() ) {
B
Bart Wyatt 已提交
978
               trace = push_scheduled_transaction( receipt.trx.get<transaction_id_type>(), fc::time_point::maximum(), receipt.cpu_usage_us, true );
A
arhag 已提交
979 980
            } else {
               EOS_ASSERT( false, block_validate_exception, "encountered unexpected receipt type" );
D
Daniel Larimer 已提交
981
            }
A
arhag 已提交
982

983
            bool transaction_failed =  trace && trace->except;
984 985
            bool transaction_can_fail = receipt.status == transaction_receipt_header::hard_fail && receipt.trx.contains<transaction_id_type>();
            if( transaction_failed && !transaction_can_fail) {
986 987 988 989
               edump((*trace));
               throw *trace->except;
            }

A
arhag 已提交
990 991 992 993 994 995 996 997
            EOS_ASSERT( pending->_pending_block_state->block->transactions.size() > 0,
                        block_validate_exception, "expected a receipt",
                        ("block", *b)("expected_receipt", receipt)
                      );
            EOS_ASSERT( pending->_pending_block_state->block->transactions.size() == num_pending_receipts + 1,
                        block_validate_exception, "expected receipt was not added",
                        ("block", *b)("expected_receipt", receipt)
                      );
998
            const transaction_receipt_header& r = pending->_pending_block_state->block->transactions.back();
999 1000 1001
            EOS_ASSERT( r == static_cast<const transaction_receipt_header&>(receipt),
                        block_validate_exception, "receipt does not match",
                        ("producer_receipt", receipt)("validator_receipt", pending->_pending_block_state->block->transactions.back()) );
1002
         }
D
Daniel Larimer 已提交
1003

1004
         finalize_block();
1005

1006
         // this implicitly asserts that all header fields (less the signature) are identical
1007
         EOS_ASSERT(producer_block_id == pending->_pending_block_state->header.id(),
1008
                   block_validate_exception, "Block ID does not match",
1009
                   ("producer_block_id",producer_block_id)("validator_block_id",pending->_pending_block_state->header.id()));
1010 1011 1012 1013

         // We need to fill out the pending block state's block because that gets serialized in the reversible block log
         // in the future we can optimize this by serializing the original and not the copy

1014 1015 1016 1017 1018
         // we can always trust this signature because,
         //   - prior to apply_block, we call fork_db.add which does a signature check IFF the block is untrusted
         //   - OTHERWISE the block is trusted and therefore we trust that the signature is valid
         // Also, as ::sign_block does not lazily calculate the digest of the block, we can just short-circuit to save cycles
         pending->_pending_block_state->header.producer_signature = b->producer_signature;
1019
         static_cast<signed_block_header&>(*pending->_pending_block_state->block) =  pending->_pending_block_state->header;
D
Daniel Larimer 已提交
1020

1021 1022
         commit_block(false);
         return;
D
Daniel Larimer 已提交
1023
      } catch ( const fc::exception& e ) {
1024 1025
         edump((e.to_detail_string()));
         abort_block();
D
Daniel Larimer 已提交
1026 1027
         throw;
      }
1028
   } FC_CAPTURE_AND_RETHROW() } /// apply_block
1029 1030


1031
   void push_block( const signed_block_ptr& b, controller::block_status s ) {
1032
      EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block");
1033

1034 1035
      auto reset_prod_light_validation = fc::make_scoped_exit([old_value=trusted_producer_light_validation, this]() {
         trusted_producer_light_validation = old_value;
1036
      });
D
Daniel Larimer 已提交
1037
      try {
1038 1039
         EOS_ASSERT( b, block_validate_exception, "trying to push empty block" );
         EOS_ASSERT( s != controller::block_status::incomplete, block_validate_exception, "invalid block status for a completed block" );
A
arhag 已提交
1040
         emit( self.pre_accepted_block, b );
1041
         bool trust = !conf.force_all_checks && (s == controller::block_status::irreversible || s == controller::block_status::validated);
1042
         auto new_header_state = fork_db.add( b, trust );
1043
         if (conf.trusted_producers.count(b->producer)) {
1044
            trusted_producer_light_validation = true;
1045
         };
1046
         emit( self.accepted_block_header, new_header_state );
1047

A
Anton Perkov 已提交
1048 1049 1050
         if ( read_mode != db_read_mode::IRREVERSIBLE ) {
            maybe_switch_forks( s );
         }
1051 1052 1053 1054

         // on replay irreversible is not emitted by fork database, so emit it explicitly here
         if( s == controller::block_status::irreversible )
            emit( self.irreversible_block, new_header_state );
A
arhag 已提交
1055

1056
      } FC_LOG_AND_RETHROW( )
1057
   }
1058

1059
   void push_confirmation( const header_confirmation& c ) {
1060
      EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a confirmation when there is a pending block");
1061
      fork_db.add( c );
1062
      emit( self.accepted_confirmation, c );
A
Anton Perkov 已提交
1063 1064 1065
      if ( read_mode != db_read_mode::IRREVERSIBLE ) {
         maybe_switch_forks();
      }
1066 1067
   }

1068
   void maybe_switch_forks( controller::block_status s = controller::block_status::complete ) {
1069 1070 1071 1072
      auto new_head = fork_db.head();

      if( new_head->header.previous == head->id ) {
         try {
1073
            apply_block( new_head->block, s );
1074
            fork_db.mark_in_current_chain( new_head, true );
1075 1076 1077
            fork_db.set_validity( new_head, true );
            head = new_head;
         } catch ( const fc::exception& e ) {
1078
            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.
1079 1080
            throw;
         }
1081
      } else if( new_head->id != head->id ) {
1082
         ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
A
arhag 已提交
1083
              ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
1084 1085
         auto branches = fork_db.fetch_branch_from( new_head->id, head->id );

1086 1087
         for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
            fork_db.mark_in_current_chain( *itr , false );
1088
            pop_block();
1089
         }
1090
         EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception,
1091
                    "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
1092 1093 1094 1095

         for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
            optional<fc::exception> except;
            try {
1096
               apply_block( (*ritr)->block, (*ritr)->validated ? controller::block_status::validated : controller::block_status::complete );
1097
               head = *ritr;
1098
               fork_db.mark_in_current_chain( *ritr, true );
1099
               (*ritr)->validated = true;
1100 1101 1102
            }
            catch (const fc::exception& e) { except = e; }
            if (except) {
1103
               elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
1104

1105 1106 1107
               // ritr currently points to the block that threw
               // if we mark it invalid it will automatically remove all forks built off it.
               fork_db.set_validity( *ritr, false );
1108

1109
               // pop all blocks from the bad fork
1110 1111 1112
               // ritr base is a forward itr to the last block successfully applied
               auto applied_itr = ritr.base();
               for( auto itr = applied_itr; itr != branches.first.end(); ++itr ) {
1113
                  fork_db.mark_in_current_chain( *itr , false );
1114
                  pop_block();
1115
               }
1116
               EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception,
1117
                          "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
1118

1119 1120
               // re-apply good blocks
               for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
1121
                  apply_block( (*ritr)->block, controller::block_status::validated /* we previously validated these blocks*/ );
1122
                  head = *ritr;
1123
                  fork_db.mark_in_current_chain( *ritr, true );
1124 1125 1126 1127
               }
               throw *except;
            } // end if exception
         } /// end for each block in branch
1128
         ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id));
1129 1130 1131
      }
   } /// push_block

1132
   void abort_block() {
1133
      if( pending ) {
A
Anton Perkov 已提交
1134
         if ( read_mode == db_read_mode::SPECULATIVE ) {
1135 1136 1137
            for( const auto& t : pending->_pending_block_state->trxs )
               unapplied_transactions[t->signed_id] = t;
         }
1138 1139
         pending.reset();
      }
1140 1141
   }

D
Daniel Larimer 已提交
1142 1143 1144 1145 1146

   bool should_enforce_runtime_limits()const {
      return false;
   }

D
Daniel Larimer 已提交
1147 1148 1149 1150 1151 1152 1153 1154
   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 已提交
1155

D
Daniel Larimer 已提交
1156 1157
   void set_trx_merkle() {
      vector<digest_type> trx_digests;
D
Daniel Larimer 已提交
1158 1159 1160
      const auto& trxs = pending->_pending_block_state->block->transactions;
      trx_digests.reserve( trxs.size() );
      for( const auto& a : trxs )
D
Daniel Larimer 已提交
1161
         trx_digests.emplace_back( a.digest() );
D
Daniel Larimer 已提交
1162

D
Daniel Larimer 已提交
1163
      pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) );
D
Daniel Larimer 已提交
1164 1165 1166
   }


1167
   void finalize_block()
1168
   {
1169
      EOS_ASSERT(pending, block_validate_exception, "it is not valid to finalize when there is no pending block");
1170 1171
      try {

D
Daniel Larimer 已提交
1172 1173

      /*
1174
      ilog( "finalize block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}",
A
arhag 已提交
1175 1176
            ("n",pending->_pending_block_state->block_num)
            ("id",pending->_pending_block_state->header.id())
1177
            ("t",pending->_pending_block_state->header.timestamp)
A
arhag 已提交
1178 1179
            ("p",pending->_pending_block_state->header.producer)
            ("signing_key", pending->_pending_block_state->block_signing_key)
1180
            ("v",pending->_pending_block_state->header.schedule_version)
1181
            ("lib",pending->_pending_block_state->dpos_irreversible_blocknum)
1182
            ("ndtrxs",db.get_index<generated_transaction_multi_index,by_trx_id>().size())
1183 1184
            ("np",pending->_pending_block_state->header.new_producers)
            );
1185
      */
D
Daniel Larimer 已提交
1186

A
arhag 已提交
1187 1188 1189
      // Update resource limits:
      resource_limits.process_account_limit_updates();
      const auto& chain_config = self.get_global_properties().configuration;
1190
      uint32_t max_virtual_mult = 1000;
1191
      uint64_t CPU_TARGET = EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct);
A
arhag 已提交
1192
      resource_limits.set_block_parameters(
1193 1194
         { CPU_TARGET, chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, max_virtual_mult, {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, max_virtual_mult, {99, 100}, {1000, 999}}
A
arhag 已提交
1195 1196 1197
      );
      resource_limits.process_block_usage(pending->_pending_block_state->block_num);

D
Daniel Larimer 已提交
1198 1199 1200 1201 1202 1203
      set_action_merkle();
      set_trx_merkle();

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

A
arhag 已提交
1204
      create_block_summary(p->id);
D
Daniel Larimer 已提交
1205 1206 1207

   } FC_CAPTURE_AND_RETHROW() }

A
arhag 已提交
1208 1209
   void update_producers_authority() {
      const auto& producers = pending->_pending_block_state->active_schedule.producers;
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241

      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 */                       );

      //TODO: Add tests
A
arhag 已提交
1242
   }
D
Daniel Larimer 已提交
1243

A
arhag 已提交
1244 1245 1246
   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 已提交
1247
      db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
A
arhag 已提交
1248
          bso.block_id = id;
D
Daniel Larimer 已提交
1249 1250 1251
      });
   }

A
arhag 已提交
1252 1253

   void clear_expired_input_transactions() {
D
Daniel Larimer 已提交
1254 1255 1256
      //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 已提交
1257 1258
      auto now = self.pending_block_time();
      while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
D
Daniel Larimer 已提交
1259 1260 1261 1262
         transaction_idx.remove(*dedupe_index.begin());
      }
   }

1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278

   void check_actor_list( const flat_set<account_name>& actors )const {
      if( conf.actor_whitelist.size() > 0 ) {
         vector<account_name> excluded;
         excluded.reserve( actors.size() );
         set_difference( actors.begin(), actors.end(),
                         conf.actor_whitelist.begin(), conf.actor_whitelist.end(),
                         std::back_inserter(excluded) );
         EOS_ASSERT( excluded.size() == 0, actor_whitelist_exception,
                     "authorizing actor(s) in transaction are not on the actor whitelist: ${actors}",
                     ("actors", excluded)
                   );
      } else if( conf.actor_blacklist.size() > 0 ) {
         vector<account_name> blacklisted;
         blacklisted.reserve( actors.size() );
         set_intersection( actors.begin(), actors.end(),
1279
                           conf.actor_blacklist.begin(), conf.actor_blacklist.end(),
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
                           std::back_inserter(blacklisted)
                         );
         EOS_ASSERT( blacklisted.size() == 0, actor_blacklist_exception,
                     "authorizing actor(s) in transaction are on the actor blacklist: ${actors}",
                     ("actors", blacklisted)
                   );
      }
   }

   void check_contract_list( account_name code )const {
      if( conf.contract_whitelist.size() > 0 ) {
         EOS_ASSERT( conf.contract_whitelist.find( code ) != conf.contract_whitelist.end(),
                     contract_whitelist_exception,
                     "account '${code}' is not on the contract whitelist", ("code", code)
                   );
      } else if( conf.contract_blacklist.size() > 0 ) {
         EOS_ASSERT( conf.contract_blacklist.find( code ) == conf.contract_blacklist.end(),
                     contract_blacklist_exception,
                     "account '${code}' is on the contract blacklist", ("code", code)
                   );
      }
   }

A
arhag 已提交
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
   void check_action_list( account_name code, action_name action )const {
      if( conf.action_blacklist.size() > 0 ) {
         EOS_ASSERT( conf.action_blacklist.find( std::make_pair(code, action) ) == conf.action_blacklist.end(),
                     action_blacklist_exception,
                     "action '${code}::${action}' is on the action blacklist",
                     ("code", code)("action", action)
                   );
      }
   }

A
arhag 已提交
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
   void check_key_list( const public_key_type& key )const {
      if( conf.key_blacklist.size() > 0 ) {
         EOS_ASSERT( conf.key_blacklist.find( key ) == conf.key_blacklist.end(),
                     key_blacklist_exception,
                     "public key '${key}' is on the key blacklist",
                     ("key", key)
                   );
      }
   }

D
Daniel Larimer 已提交
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
   /*
   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 已提交
1343
   signed_transaction get_on_block_transaction()
D
Daniel Larimer 已提交
1344 1345 1346 1347 1348
   {
      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 已提交
1349
      on_block_act.data = fc::raw::pack(self.head_block_header());
D
Daniel Larimer 已提交
1350

D
Daniel Larimer 已提交
1351
      signed_transaction trx;
D
Daniel Larimer 已提交
1352
      trx.actions.emplace_back(std::move(on_block_act));
A
arhag 已提交
1353
      trx.set_reference_block(self.head_block_id());
A
arhag 已提交
1354
      trx.expiration = self.pending_block_time() + fc::microseconds(999'999); // Round up to nearest second to avoid appearing expired
D
Daniel Larimer 已提交
1355 1356 1357
      return trx;
   }

1358
}; /// controller_impl
D
Daniel Larimer 已提交
1359

1360
const resource_limits_manager&   controller::get_resource_limits_manager()const
D
Daniel Larimer 已提交
1361 1362 1363
{
   return my->resource_limits;
}
1364
resource_limits_manager&         controller::get_mutable_resource_limits_manager()
D
Daniel Larimer 已提交
1365 1366 1367
{
   return my->resource_limits;
}
D
Daniel Larimer 已提交
1368

1369 1370 1371 1372 1373 1374 1375 1376
const authorization_manager&   controller::get_authorization_manager()const
{
   return my->authorization;
}
authorization_manager&         controller::get_mutable_authorization_manager()
{
   return my->authorization;
}
D
Daniel Larimer 已提交
1377 1378 1379 1380 1381 1382 1383

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

controller::~controller() {
1384
   my->abort_block();
1385 1386 1387 1388
   //close fork_db here, because it can generate "irreversible" signal to this controller,
   //in case if read-mode == IRREVERSIBLE, we will apply latest irreversible block
   //for that we need 'my' to be valid pointer pointing to valid controller_impl.
   my->fork_db.close();
D
Daniel Larimer 已提交
1389 1390 1391 1392 1393
}


void controller::startup() {

1394 1395 1396
   // ilog( "${c}", ("c",fc::json::to_pretty_string(cfg)) );
   my->add_indices();

D
Daniel Larimer 已提交
1397 1398
   my->head = my->fork_db.head();
   if( !my->head ) {
D
Daniel Larimer 已提交
1399
      elog( "No head block in fork db, perhaps we need to replay" );
D
Daniel Larimer 已提交
1400
   }
1401
   my->init();
D
Daniel Larimer 已提交
1402 1403
}

D
Daniel Larimer 已提交
1404
chainbase::database& controller::db()const { return my->db; }
D
Daniel Larimer 已提交
1405

1406 1407
fork_database& controller::fork_db()const { return my->fork_db; }

D
Daniel Larimer 已提交
1408

1409
void controller::start_block( block_timestamp_type when, uint16_t confirm_block_count) {
B
Bart Wyatt 已提交
1410
   validate_db_available_size();
1411
   my->start_block(when, confirm_block_count, block_status::incomplete, optional<block_id_type>() );
D
Daniel Larimer 已提交
1412 1413 1414
}

void controller::finalize_block() {
B
Bart Wyatt 已提交
1415
   validate_db_available_size();
D
Daniel Larimer 已提交
1416
   my->finalize_block();
D
Daniel Larimer 已提交
1417 1418
}

1419
void controller::sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
1420
   my->sign_block( signer_callback );
D
Daniel Larimer 已提交
1421 1422 1423
}

void controller::commit_block() {
B
Bart Wyatt 已提交
1424
   validate_db_available_size();
1425
   validate_reversible_available_size();
D
Daniel Larimer 已提交
1426
   my->commit_block(true);
D
Daniel Larimer 已提交
1427 1428
}

1429 1430
void controller::abort_block() {
   my->abort_block();
D
Daniel Larimer 已提交
1431 1432
}

1433
void controller::push_block( const signed_block_ptr& b, block_status s ) {
B
Bart Wyatt 已提交
1434
   validate_db_available_size();
1435
   validate_reversible_available_size();
1436
   my->push_block( b, s );
D
Daniel Larimer 已提交
1437 1438
}

1439
void controller::push_confirmation( const header_confirmation& c ) {
B
Bart Wyatt 已提交
1440
   validate_db_available_size();
1441 1442 1443
   my->push_confirmation( c );
}

1444
transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline, uint32_t billed_cpu_time_us ) {
B
Bart Wyatt 已提交
1445
   validate_db_available_size();
1446
   EOS_ASSERT( get_read_mode() != chain::db_read_mode::READ_ONLY, transaction_type_exception, "push transaction not allowed in read-only mode" );
1447
   EOS_ASSERT( trx && !trx->implicit && !trx->scheduled, transaction_type_exception, "Implicit/Scheduled transaction not allowed" );
1448
   return my->push_transaction(trx, deadline, billed_cpu_time_us, billed_cpu_time_us > 0 );
D
Daniel Larimer 已提交
1449
}
1450

D
Daniel Larimer 已提交
1451 1452
transaction_trace_ptr controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline, uint32_t billed_cpu_time_us )
{
B
Bart Wyatt 已提交
1453
   validate_db_available_size();
1454
   return my->push_scheduled_transaction( trxid, deadline, billed_cpu_time_us, billed_cpu_time_us > 0 );
D
Daniel Larimer 已提交
1455 1456
}

1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
const flat_set<account_name>& controller::get_actor_whitelist() const {
   return my->conf.actor_whitelist;
}
const flat_set<account_name>& controller::get_actor_blacklist() const {
   return my->conf.actor_blacklist;
}
const flat_set<account_name>& controller::get_contract_whitelist() const {
   return my->conf.contract_whitelist;
}
const flat_set<account_name>& controller::get_contract_blacklist() const {
   return my->conf.contract_blacklist;
}
const flat_set< pair<account_name, action_name> >& controller::get_action_blacklist() const {
   return my->conf.action_blacklist;
}
const flat_set<public_key_type>& controller::get_key_blacklist() const {
   return my->conf.key_blacklist;
}

void controller::set_actor_whitelist( const flat_set<account_name>& new_actor_whitelist ) {
   my->conf.actor_whitelist = new_actor_whitelist;
}
void controller::set_actor_blacklist( const flat_set<account_name>& new_actor_blacklist ) {
   my->conf.actor_blacklist = new_actor_blacklist;
}
void controller::set_contract_whitelist( const flat_set<account_name>& new_contract_whitelist ) {
   my->conf.contract_whitelist = new_contract_whitelist;
}
void controller::set_contract_blacklist( const flat_set<account_name>& new_contract_blacklist ) {
   my->conf.contract_blacklist = new_contract_blacklist;
}
void controller::set_action_blacklist( const flat_set< pair<account_name, action_name> >& new_action_blacklist ) {
   for (auto& act: new_action_blacklist) {
      EOS_ASSERT(act.first != account_name(), name_type_exception, "Action blacklist - contract name should not be empty");
      EOS_ASSERT(act.second != action_name(), action_type_exception, "Action blacklist - action name should not be empty");
   }
   my->conf.action_blacklist = new_action_blacklist;
}
void controller::set_key_blacklist( const flat_set<public_key_type>& new_key_blacklist ) {
   my->conf.key_blacklist = new_key_blacklist;
}

D
Daniel Larimer 已提交
1499 1500 1501
uint32_t controller::head_block_num()const {
   return my->head->block_num;
}
A
arhag 已提交
1502 1503 1504
time_point controller::head_block_time()const {
   return my->head->header.timestamp;
}
D
Daniel Larimer 已提交
1505 1506 1507
block_id_type controller::head_block_id()const {
   return my->head->id;
}
D
Daniel Larimer 已提交
1508 1509 1510
account_name  controller::head_block_producer()const {
   return my->head->header.producer;
}
A
arhag 已提交
1511 1512
const block_header& controller::head_block_header()const {
   return my->head->header;
D
Daniel Larimer 已提交
1513
}
A
arhag 已提交
1514 1515
block_state_ptr controller::head_block_state()const {
   return my->head;
D
Daniel Larimer 已提交
1516 1517
}

1518 1519 1520 1521 1522 1523 1524 1525
uint32_t controller::fork_db_head_block_num()const {
   return my->fork_db.head()->block_num;
}

block_id_type controller::fork_db_head_block_id()const {
   return my->fork_db.head()->id;
}

1526 1527 1528 1529 1530 1531 1532 1533
time_point controller::fork_db_head_block_time()const {
   return my->fork_db.head()->header.timestamp;
}

account_name  controller::fork_db_head_block_producer()const {
   return my->fork_db.head()->header.producer;
}

A
arhag 已提交
1534 1535 1536
block_state_ptr controller::pending_block_state()const {
   if( my->pending ) return my->pending->_pending_block_state;
   return block_state_ptr();
1537 1538
}
time_point controller::pending_block_time()const {
1539
   EOS_ASSERT( my->pending, block_validate_exception, "no pending block" );
1540
   return my->pending->_pending_block_state->header.timestamp;
D
Daniel Larimer 已提交
1541 1542
}

1543
optional<block_id_type> controller::pending_producer_block_id()const {
1544 1545 1546 1547
   EOS_ASSERT( my->pending, block_validate_exception, "no pending block" );
   return my->pending->_producer_block_id;
}

A
arhag 已提交
1548
uint32_t controller::last_irreversible_block_num() const {
1549
   return std::max(my->head->bft_irreversible_blocknum, my->head->dpos_irreversible_blocknum);
A
arhag 已提交
1550 1551 1552
}

block_id_type controller::last_irreversible_block_id() const {
1553
   auto lib_num = last_irreversible_block_num();
A
arhag 已提交
1554 1555 1556 1557 1558 1559 1560 1561 1562
   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 已提交
1563 1564 1565
const dynamic_global_property_object& controller::get_dynamic_global_properties()const {
  return my->db.get<dynamic_global_property_object>();
}
D
Daniel Larimer 已提交
1566 1567 1568
const global_property_object& controller::get_global_properties()const {
  return my->db.get<global_property_object>();
}
D
Daniel Larimer 已提交
1569

1570 1571 1572 1573
signed_block_ptr controller::fetch_block_by_id( block_id_type id )const {
   auto state = my->fork_db.get_block(id);
   if( state ) return state->block;
   auto bptr = fetch_block_by_number( block_header::num_from_id(id) );
D
Daniel Larimer 已提交
1574
   if( bptr && bptr->id() == id ) return bptr;
1575 1576 1577
   return signed_block_ptr();
}

D
Daniel Larimer 已提交
1578
signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const  { try {
1579
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
D
Daniel Larimer 已提交
1580 1581 1582
   if( blk_state ) {
      return blk_state->block;
   }
1583

D
Daniel Larimer 已提交
1584
   return my->blog.read_block_by_num(block_num);
D
Daniel Larimer 已提交
1585
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
D
Daniel Larimer 已提交
1586

A
arhag 已提交
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
block_state_ptr controller::fetch_block_state_by_id( block_id_type id )const {
   auto state = my->fork_db.get_block(id);
   return state;
}

block_state_ptr controller::fetch_block_state_by_number( uint32_t block_num )const  { try {
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
   return blk_state;
} FC_CAPTURE_AND_RETHROW( (block_num) ) }

1597 1598 1599 1600 1601 1602
block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try {
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
   if( blk_state ) {
      return blk_state->id;
   }

1603 1604 1605 1606 1607 1608
   auto signed_blk = my->blog.read_block_by_num(block_num);

   EOS_ASSERT( BOOST_LIKELY( signed_blk != nullptr ), unknown_block_exception,
               "Could not find block: ${block}", ("block", block_num) );

   return signed_blk->id();
1609 1610
} FC_CAPTURE_AND_RETHROW( (block_num) ) }

D
Daniel Larimer 已提交
1611
void controller::pop_block() {
1612
   my->pop_block();
D
Daniel Larimer 已提交
1613 1614
}

1615
int64_t controller::set_proposed_producers( vector<producer_key> producers ) {
1616 1617
   const auto& gpo = get_global_properties();
   auto cur_block_num = head_block_num() + 1;
1618 1619 1620

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

      if( std::equal( producers.begin(), producers.end(),
                      gpo.proposed_schedule.producers.begin(), gpo.proposed_schedule.producers.end() ) )
1625
         return -1; // the proposed producer schedule does not change
1626 1627 1628 1629 1630 1631 1632
   }

   producer_schedule_type sch;

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

1633
   if( my->pending->_pending_block_state->pending_schedule.producers.size() == 0 ) {
1634 1635 1636 1637
      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;
1638
   } else {
1639 1640 1641 1642
      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;
1643
   }
1644 1645

   if( std::equal( producers.begin(), producers.end(), begin, end ) )
1646
      return -1; // the producer schedule would not change
1647 1648 1649

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

1650 1651
   int64_t version = sch.version;

1652 1653
   my->db.modify( gpo, [&]( auto& gp ) {
      gp.proposed_schedule_block_num = cur_block_num;
1654
      gp.proposed_schedule = std::move(sch);
1655
   });
1656
   return version;
D
Daniel Larimer 已提交
1657
}
1658 1659

const producer_schedule_type&    controller::active_producers()const {
1660 1661
   if ( !(my->pending) )
      return  my->head->active_schedule;
D
Daniel Larimer 已提交
1662 1663 1664
   return my->pending->_pending_block_state->active_schedule;
}

1665
const producer_schedule_type&    controller::pending_producers()const {
1666 1667
   if ( !(my->pending) )
      return  my->head->pending_schedule;
D
Daniel Larimer 已提交
1668 1669 1670
   return my->pending->_pending_block_state->pending_schedule;
}

1671 1672 1673 1674 1675 1676 1677 1678
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;
}

1679 1680 1681 1682
bool controller::light_validation_allowed(bool replay_opts_disabled_by_policy) const {
   if (!my->pending || my->in_trx_requiring_checks) {
      return false;
   }
B
Bart Wyatt 已提交
1683

1684
   const auto pb_status = my->pending->_block_status;
B
Bart Wyatt 已提交
1685

1686
   // in a pending irreversible or previously validated block and we have forcing all checks
1687
   const bool consider_skipping_on_replay = (pb_status == block_status::irreversible || pb_status == block_status::validated) && !replay_opts_disabled_by_policy;
1688 1689

   // OR in a signed block and in light validation mode
1690
   const bool consider_skipping_on_validate = (pb_status == block_status::complete &&
1691
         (my->conf.block_validation_mode == validation_mode::LIGHT || my->trusted_producer_light_validation));
1692 1693 1694 1695 1696 1697 1698

   return consider_skipping_on_replay || consider_skipping_on_validate;
}


bool controller::skip_auth_check() const {
   return light_validation_allowed(my->conf.force_all_checks);
1699
}
1700

1701 1702
bool controller::skip_db_sessions( block_status bs ) const {
   bool consider_skipping = bs == block_status::irreversible;
B
Bart Wyatt 已提交
1703 1704 1705
   return consider_skipping
      && !my->conf.disable_replay_opts
      && !my->in_trx_requiring_checks;
1706 1707
}

1708 1709 1710 1711 1712 1713 1714 1715
bool controller::skip_db_sessions( ) const {
   if (my->pending) {
      return skip_db_sessions(my->pending->_block_status);
   } else {
      return false;
   }
}

1716
bool controller::skip_trx_checks() const {
B
Bart Wyatt 已提交
1717
   return light_validation_allowed(my->conf.disable_replay_opts);
1718
}
1719

1720 1721 1722 1723
bool controller::contracts_console()const {
   return my->conf.contracts_console;
}

1724 1725 1726 1727
chain_id_type controller::get_chain_id()const {
   return my->chain_id;
}

A
Anton Perkov 已提交
1728
db_read_mode controller::get_read_mode()const {
1729 1730 1731
   return my->read_mode;
}

B
Bart Wyatt 已提交
1732
validation_mode controller::get_validation_mode()const {
1733
   return my->conf.block_validation_mode;
B
Bart Wyatt 已提交
1734 1735
}

D
Daniel Larimer 已提交
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748
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 已提交
1749

1750
const account_object& controller::get_account( account_name name )const
D
Daniel Larimer 已提交
1751 1752 1753
{ try {
   return my->db.get<account_object, by_name>(name);
} FC_CAPTURE_AND_RETHROW( (name) ) }
D
Daniel Larimer 已提交
1754

1755 1756
vector<transaction_metadata_ptr> controller::get_unapplied_transactions() const {
   vector<transaction_metadata_ptr> result;
A
Anton Perkov 已提交
1757
   if ( my->read_mode == db_read_mode::SPECULATIVE ) {
1758 1759 1760 1761
      result.reserve(my->unapplied_transactions.size());
      for ( const auto& entry: my->unapplied_transactions ) {
         result.emplace_back(entry.second);
      }
1762 1763
   } else {
      EOS_ASSERT( my->unapplied_transactions.empty(), transaction_exception, "not empty unapplied_transactions in non-speculative mode" ); //should never happen
1764 1765 1766 1767 1768 1769 1770 1771
   }
   return result;
}

void controller::drop_unapplied_transaction(const transaction_metadata_ptr& trx) {
   my->unapplied_transactions.erase(trx->signed_id);
}

1772 1773 1774 1775
void controller::drop_all_unapplied_transactions() {
   my->unapplied_transactions.clear();
}

1776 1777 1778 1779
vector<transaction_id_type> controller::get_scheduled_transactions() const {
   const auto& idx = db().get_index<generated_transaction_multi_index,by_delay>();

   vector<transaction_id_type> result;
1780 1781 1782

   static const size_t max_reserve = 64;
   result.reserve(std::min(idx.size(), max_reserve));
1783 1784 1785 1786 1787 1788 1789

   auto itr = idx.begin();
   while( itr != idx.end() && itr->delay_until <= pending_block_time() ) {
      result.emplace_back(itr->trx_id);
      ++itr;
   }
   return result;
1790 1791
}

1792 1793 1794 1795
void controller::check_contract_list( account_name code )const {
   my->check_contract_list( code );
}

A
arhag 已提交
1796 1797 1798 1799
void controller::check_action_list( account_name code, action_name action )const {
   my->check_action_list( code, action );
}

A
arhag 已提交
1800 1801 1802 1803
void controller::check_key_list( const public_key_type& key )const {
   my->check_key_list( key );
}

1804 1805 1806 1807 1808 1809
bool controller::is_producing_block()const {
   if( !my->pending ) return false;

   return (my->pending->_block_status == block_status::incomplete);
}

1810 1811 1812 1813
bool controller::is_ram_billing_in_notify_allowed()const {
   return !is_producing_block() || my->conf.allow_ram_billing_in_notify;
}

1814 1815
void controller::validate_referenced_accounts( const transaction& trx )const {
   for( const auto& a : trx.context_free_actions ) {
1816 1817
      auto* code = my->db.find<account_object, by_name>(a.account);
      EOS_ASSERT( code != nullptr, transaction_exception,
A
arhag 已提交
1818
                  "action's code account '${account}' does not exist", ("account", a.account) );
1819 1820
      EOS_ASSERT( a.authorization.size() == 0, transaction_exception,
                  "context-free actions cannot have authorizations" );
1821
   }
D
Daniel Larimer 已提交
1822
   bool one_auth = false;
1823
   for( const auto& a : trx.actions ) {
1824 1825
      auto* code = my->db.find<account_object, by_name>(a.account);
      EOS_ASSERT( code != nullptr, transaction_exception,
A
arhag 已提交
1826
                  "action's code account '${account}' does not exist", ("account", a.account) );
1827
      for( const auto& auth : a.authorization ) {
D
Daniel Larimer 已提交
1828
         one_auth = true;
1829 1830
         auto* actor = my->db.find<account_object, by_name>(auth.actor);
         EOS_ASSERT( actor  != nullptr, transaction_exception,
A
arhag 已提交
1831
                     "action's authorizing actor '${account}' does not exist", ("account", auth.actor) );
1832 1833 1834
         EOS_ASSERT( my->authorization.find_permission(auth) != nullptr, transaction_exception,
                     "action's authorizations include a non-existent permission: {permission}",
                     ("permission", auth) );
1835 1836
      }
   }
D
Daniel Larimer 已提交
1837
   EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" );
1838 1839 1840 1841 1842
}

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

1843 1844 1845 1846 1847
   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()));
1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
   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));
1863 1864
} FC_CAPTURE_AND_RETHROW() }

B
Bart Wyatt 已提交
1865 1866 1867 1868 1869 1870
void controller::validate_db_available_size() const {
   const auto free = db().get_segment_manager()->get_free_memory();
   const auto guard = my->conf.state_guard_size;
   EOS_ASSERT(free >= guard, database_guard_exception, "database free: ${f}, guard size: ${g}", ("f", free)("g",guard));
}

1871 1872 1873 1874 1875 1876
void controller::validate_reversible_available_size() const {
   const auto free = my->reversible_blocks.get_segment_manager()->get_free_memory();
   const auto guard = my->conf.reversible_guard_size;
   EOS_ASSERT(free >= guard, reversible_guard_exception, "reversible free: ${f}, guard size: ${g}", ("f", free)("g",guard));
}

1877 1878 1879 1880
bool controller::is_known_unexpired_transaction( const transaction_id_type& id) const {
   return db().find<transaction_object, by_trx_id>(id);
}

1881 1882 1883
void controller::set_subjective_cpu_leeway(fc::microseconds leeway) {
   my->subjective_cpu_leeway = leeway;
}
1884

K
Kayan 已提交
1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
void controller::add_resource_greylist(const account_name &name) {
   my->conf.resource_greylist.insert(name);
}

void controller::remove_resource_greylist(const account_name &name) {
   my->conf.resource_greylist.erase(name);
}

bool controller::is_resource_greylisted(const account_name &name) const {
   return my->conf.resource_greylist.find(name) !=  my->conf.resource_greylist.end();
}

const flat_set<account_name> &controller::get_resource_greylist() const {
   return  my->conf.resource_greylist;
}
1900

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