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

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

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

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

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

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

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

using resource_limits::resource_limits_manager;

D
Daniel Larimer 已提交
27

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

   database::session                  _db_session;
   vector<transaction_metadata_ptr>   _applied_transaction_metas;

   block_state_ptr                    _pending_block_state;

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

D
Daniel Larimer 已提交
39

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

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

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

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

D
Daniel Larimer 已提交
67 68 69 70 71 72 73 74 75 76 77
   block_id_type head_block_id()const {
      return head->id;
   }
   time_point head_block_time()const {
      return head->header.timestamp;
   }
   const block_header& head_block_header()const {
      return head->header;
   }

   void pop_block() {
78 79
      auto prev = fork_db.get_block( head->header.previous );
      FC_ASSERT( prev, "attempt to pop beyond last irreversible block" );
D
Daniel Larimer 已提交
80
      for( const auto& t : head->trxs )
81
         unapplied_transactions[t->signed_id] = t;
82
      head = prev;
D
Daniel Larimer 已提交
83
      db.undo();
D
Daniel Larimer 已提交
84 85 86
   }


D
Daniel Larimer 已提交
87 88 89 90
   void set_apply_handler( account_name contract, scope_name scope, action_name action, apply_handler v ) {
      apply_handlers[contract][make_pair(scope,action)] = v;
   }

D
Daniel Larimer 已提交
91
   controller_impl( const controller::config& cfg, controller& s  )
D
Daniel Larimer 已提交
92 93
   :self(s),
    db( cfg.shared_memory_dir,
D
Daniel Larimer 已提交
94 95 96
        cfg.read_only ? database::read_only : database::read_write,
        cfg.shared_memory_size ),
    blog( cfg.block_log_dir ),
D
Daniel Larimer 已提交
97
    fork_db( cfg.shared_memory_dir ),
D
Daniel Larimer 已提交
98
    wasmif( cfg.wasm_runtime ),
D
Daniel Larimer 已提交
99
    resource_limits( db ),
D
Daniel Larimer 已提交
100 101
    authorization( s, db ),
    conf( cfg )
D
Daniel Larimer 已提交
102
   {
D
Daniel Larimer 已提交
103
      head = fork_db.head();
D
Daniel Larimer 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121


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


D
Daniel Larimer 已提交
122 123 124 125
   }

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

      /**
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
      *  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
#warning What if head is empty because the user deleted forkdb.dat? Will this not corrupt the database?
         db.set_revision( head->block_num );
         initialize_database();
      }

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

      /**
       * The undoable state contains state transitions from blocks
D
Daniel Larimer 已提交
146 147 148 149 150
       * in the fork database that could be reversed. Because this
       * is a new startup and the fork database is empty, we must
       * unwind that pending state. This state will be regenerated
       * when we catch up to the head block later.
       */
151
      //clear_all_undo();
D
Daniel Larimer 已提交
152 153 154 155
   }

   ~controller_impl() {
      pending.reset();
D
Daniel Larimer 已提交
156 157 158

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

D
Daniel Larimer 已提交
159 160 161
      db.flush();
   }

162
   void add_indices() {
D
Daniel Larimer 已提交
163
      db.add_index<account_index>();
164
      db.add_index<account_sequence_index>();
D
Daniel Larimer 已提交
165

D
Daniel Larimer 已提交
166 167 168 169 170 171
      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>();
D
Daniel Larimer 已提交
172 173 174 175 176 177 178 179

      db.add_index<global_property_multi_index>();
      db.add_index<dynamic_global_property_multi_index>();
      db.add_index<block_summary_multi_index>();
      db.add_index<transaction_multi_index>();
      db.add_index<generated_transaction_multi_index>();
      db.add_index<scope_sequence_multi_index>();

180 181
      authorization.add_indices();
      resource_limits.add_indices();
D
Daniel Larimer 已提交
182 183 184 185 186 187 188
   }

   void clear_all_undo() {
      // Rewind the database to the last irreversible block
      db.with_write_lock([&] {
         db.undo_all();
         /*
189
         FC_ASSERT(db.revision() == self.head_block_num(),
D
Daniel Larimer 已提交
190 191 192 193 194 195 196
                   "Chainbase revision does not match head block num",
                   ("rev", db.revision())("head_block", self.head_block_num()));
                   */
      });
   }

   /**
197
    *  Sets fork database head to the genesis state.
D
Daniel Larimer 已提交
198 199
    */
   void initialize_fork_db() {
200 201
      wlog( " Initializing new blockchain with genesis state                  " );
      producer_schedule_type initial_schedule{ 0, {{N(eosio), conf.genesis.initial_key}} };
D
Daniel Larimer 已提交
202

203 204 205 206 207 208 209 210
      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 已提交
211

212 213
      head = std::make_shared<block_state>( genheader );
      signed_block genblock(genheader.header);
D
Daniel Larimer 已提交
214

215 216 217
      edump((genheader.header));
      edump((genblock));
      blog.append( genblock );
218

219
      fork_db.set( head );
D
Daniel Larimer 已提交
220 221
   }

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

         if( name == config::system_account_name ) {
D
Daniel Larimer 已提交
229
            a.set_abi(eosio_contract_abi(abi_def()));
D
Daniel Larimer 已提交
230 231
         }
      });
232 233 234 235
      db.create<account_sequence_object>([&](auto & a) {
        a.name = name;
      });

236 237 238 239
      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 已提交
240 241

      resource_limits.initialize_account(name);
242 243 244 245 246 247 248 249
      resource_limits.add_pending_account_ram_usage(
         name,
         (int64_t)(config::billable_size_v<permission_object> + owner_permission.auth.get_billable_size())
      );
      resource_limits.add_pending_account_ram_usage(
         name,
         (int64_t)(config::billable_size_v<permission_object> + active_permission.auth.get_billable_size())
      );
D
Daniel Larimer 已提交
250 251 252 253 254 255 256
   }

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

257 258 259 260 261
      const auto& tapos_block_summary = db.get<block_summary_object>(1);
      db.modify( tapos_block_summary, [&]( auto& bs ) {
        bs.block_id = head->id;
      });

262 263 264 265
      db.create<global_property_object>([&](auto& gpo ){
        gpo.configuration = conf.genesis.initial_configuration;
      });
      db.create<dynamic_global_property_object>([](auto&){});
266 267 268 269 270 271

      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 已提交
272 273 274 275 276

      auto empty_authority = authority(0, {}, {});
      auto active_producers_authority = authority(0, {}, {});
      active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});

277 278
      create_native_account( config::nobody_account_name, empty_authority, empty_authority );
      create_native_account( config::producers_account_name, empty_authority, active_producers_authority );
D
Daniel Larimer 已提交
279 280
   }

281 282 283 284 285 286 287
   void set_pending_tapos() {
      const auto& tapos_block_summary = db.get<block_summary_object>((uint16_t)pending->_pending_block_state->block_num);
      db.modify( tapos_block_summary, [&]( auto& bs ) {
        bs.block_id = pending->_pending_block_state->id;
      });
   }

D
Daniel Larimer 已提交
288
   void commit_block( bool add_to_fork_db ) {
289 290 291 292
      set_pending_tapos();
      resource_limits.process_account_limit_updates();
      resource_limits.process_block_usage( pending->_pending_block_state->block_num );

D
Daniel Larimer 已提交
293 294
      if( add_to_fork_db ) {
         pending->_pending_block_state->validated = true;
295 296 297
         auto new_bsp = fork_db.add( pending->_pending_block_state );
         head = fork_db.head();
         FC_ASSERT( new_bsp == head, "committed block did not become the new head in fork database" );
298
      }
299

D
Daniel Larimer 已提交
300 301
      pending->push();
      pending.reset();
302
      self.accepted_block( head );
D
Daniel Larimer 已提交
303
   }
D
Daniel Larimer 已提交
304

305
   transaction_trace_ptr apply_onerror( const generated_transaction_object& gto, fc::time_point deadline, uint32_t cpu_usage ) {
D
Daniel Larimer 已提交
306 307 308
      signed_transaction etrx;
      etrx.actions.emplace_back(vector<permission_level>{{gto.sender,config::active_name}},
                                onerror( gto.sender_id, gto.packed_trx.data(), gto.packed_trx.size()) );
D
Daniel Larimer 已提交
309

D
Daniel Larimer 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323

      etrx.expiration = self.pending_block_time() + fc::seconds(1);
      etrx.set_reference_block( self.head_block_id() );

      transaction_context trx_context( self, etrx, etrx.id() );
      trx_context.deadline = deadline;
      /// TODO: forward cpu usage into error trx_context.cpu_usage = cpu_usage;
      trx_context.is_input  = false;
      trx_context.exec();

      db.remove( gto );
      trx_context.squash();

      return move(trx_context.trace);
D
Daniel Larimer 已提交
324 325
   }

D
Daniel Larimer 已提交
326
   void push_scheduled_transaction( const generated_transaction_object& gto, fc::time_point deadline  ) {
D
Daniel Larimer 已提交
327
      fc::datastream<const char*> ds( gto.packed_trx.data(), gto.packed_trx.size() );
D
Daniel Larimer 已提交
328

329 330 331 332 333
      FC_ASSERT( gto.delay_until <= self.pending_block_time() );

      optional<fc::exception> soft_except;
      optional<fc::exception> hard_except;

D
Daniel Larimer 已提交
334
      transaction_trace_ptr trace;
335
      uint32_t apply_cpu_usage = 0;
D
Daniel Larimer 已提交
336 337 338
      try {
         signed_transaction dtrx;
         fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
339 340

         transaction_context trx_context( self, dtrx, gto.trx_id );
D
Daniel Larimer 已提交
341
         trace = trx_context.trace;
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357

         trx_context.deadline  = deadline;
         trx_context.published = gto.published;
         trx_context.net_usage = 0;
         trx_context.apply_context_free = false;
         trx_context.is_input           = false;
         try {
            trx_context.exec();
         } catch ( ... ) {
            apply_cpu_usage = trx_context.trace->cpu_usage;
            throw;
         }

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

         trx_context.trace->receipt = push_receipt( gto.trx_id, transaction_receipt::executed, trx_context.trace->kcpu_usage(), 0 );
358 359

         db.remove( gto );
360
         trx_context.squash();
D
Daniel Larimer 已提交
361
         self.applied_transaction( trx_context.trace );
D
Daniel Larimer 已提交
362
      } catch( const fc::exception& e ) {
363
         soft_except = e;
D
Daniel Larimer 已提交
364
      }
D
Daniel Larimer 已提交
365
      if( soft_except && gto.sender != account_name() ) { /// TODO: soft errors should not go to error handlers (deadline error)
366 367 368 369
         edump((soft_except->to_detail_string()));
         try {
            auto trace = apply_onerror( gto, deadline, apply_cpu_usage  );
            trace->soft_except = soft_except;
D
Daniel Larimer 已提交
370
            self.applied_transaction( trace );
371 372 373
         } catch ( const fc::exception& e ) {
            hard_except = e;
         }
D
Daniel Larimer 已提交
374
      }
375

D
Daniel Larimer 已提交
376 377 378 379 380 381
      edump((hard_except->to_detail_string()));
      db.remove( gto );
      trace->receipt  = push_receipt( gto.trx_id, transaction_receipt::hard_fail, (apply_cpu_usage+999)/1000, 0 );
      trace->soft_except = soft_except;
      trace->hard_except = hard_except;
      self.applied_transaction( trace );
D
Daniel Larimer 已提交
382
   } /// push_scheduled_transaction
D
Daniel Larimer 已提交
383

384 385 386 387

   /**
    *  Adds the transaction receipt to the pending block and returns it.
    */
388 389
   template<typename T>
   const transaction_receipt& push_receipt( const T& trx, transaction_receipt_header::status_enum status,
390 391 392 393 394 395 396 397 398
                      uint32_t kcpu_usage, uint32_t net_usage_words ) {
      pending->_pending_block_state->block->transactions.emplace_back( trx );
      transaction_receipt& r = pending->_pending_block_state->block->transactions.back();
      r.kcpu_usage           = kcpu_usage;
      r.net_usage_words      = net_usage_words;
      r.status               = status;
      return r;
   }

D
Daniel Larimer 已提交
399 400
   void push_unapplied_transaction( fc::time_point deadline ) {
      auto itr = unapplied_transactions.begin();
401
      if( itr == unapplied_transactions.end() )
D
Daniel Larimer 已提交
402 403 404 405 406
         return;

      push_transaction( itr->second, deadline );
   }

407

408 409 410 411 412
   /**
    *  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.
    */
413 414
   void push_transaction( const transaction_metadata_ptr& trx,
                          fc::time_point deadline = fc::time_point::maximum(),
D
Daniel Larimer 已提交
415 416 417 418 419
                          bool implicit = false ) {
      if( deadline == fc::time_point() ) {
         unapplied_transactions[trx->id] = trx;
         return;
      }
420

421
      transaction_trace_ptr trace;
D
Daniel Larimer 已提交
422 423
      try {
         unapplied_transactions.erase( trx->signed_id );
424

D
Daniel Larimer 已提交
425
         transaction_context trx_context( self, trx->trx, trx->id );
426
         trace = trx_context.trace;
427

D
Daniel Larimer 已提交
428
         auto required_delay = authorization.check_authorization( trx->trx.actions, trx->recover_keys() );
429

D
Daniel Larimer 已提交
430 431 432 433 434 435
         trx_context.deadline  = deadline;
         trx_context.published = self.pending_block_time();
         trx_context.net_usage = self.validate_net_usage( trx );
         trx_context.is_input  = !implicit;
         trx_context.delay = std::max( fc::seconds(trx->trx.delay_sec), required_delay );
         trx_context.exec();
436

D
Daniel Larimer 已提交
437 438 439 440 441 442 443 444 445 446
         fc::move_append( pending->_actions, move(trx_context.executed) );


         const auto& trace = trx_context.trace;
         if( !implicit ) {
            if( trx_context.delay == fc::seconds(0) ) {
               trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::executed, trace->kcpu_usage(), trx_context.net_usage );
            } else {
               trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::delayed, trace->kcpu_usage(), trx_context.net_usage );
            }
447
         }
448

D
Daniel Larimer 已提交
449 450 451 452
         pending->_pending_block_state->trxs.emplace_back(trx);
         self.accepted_transaction(trx);
         trx_context.squash();
      } catch ( const fc::exception& e ) {
453
         trace->soft_except = e;
D
Daniel Larimer 已提交
454
      }
455

D
Daniel Larimer 已提交
456
      if( trx->on_result ) {
457
         (*trx->on_result)(trace);
D
Daniel Larimer 已提交
458
      }
459
   } /// push_transaction
D
Daniel Larimer 已提交
460

461

462
   void start_block( block_timestamp_type when ) {
463
      FC_ASSERT( !pending );
D
Daniel Larimer 已提交
464

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

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
      pending = db.start_undo_session(true);
      pending->_pending_block_state = std::make_shared<block_state>( *head, when ); // promotes pending schedule (if any) to active
      pending->_pending_block_state->in_current_chain = true;

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

491 492 493 494 495 496
      try {
         auto onbtrx = std::make_shared<transaction_metadata>( get_on_block_transaction() );
         push_transaction( onbtrx, fc::time_point::maximum(), true );
      } catch ( ... ) {
         ilog( "on block transaction failed, but shouldn't impact block generation, system contract needs update" );
      }
497
   } // start_block
D
Daniel Larimer 已提交
498 499


D
Daniel Larimer 已提交
500

501 502
   void sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
      auto p = pending->_pending_block_state;
503
      p->sign( signer_callback );
504 505
      static_cast<signed_block_header&>(*p->block) = p->header;
   } /// sign_block
D
Daniel Larimer 已提交
506

507
   void apply_block( const signed_block_ptr& b ) {
508 509 510 511 512 513 514 515 516 517
      try {
         start_block( b->timestamp );

         for( const auto& receipt : b->transactions ) {
            if( receipt.trx.contains<packed_transaction>() ) {
               auto& pt = receipt.trx.get<packed_transaction>();
               auto mtrx = std::make_shared<transaction_metadata>(pt);
               push_transaction( mtrx );
            }
         }
D
Daniel Larimer 已提交
518

519 520
         finalize_block();
         sign_block( [&]( const auto& ){ return b->producer_signature; } );
D
Daniel Larimer 已提交
521

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

526 527
         commit_block(false);
         return;
D
Daniel Larimer 已提交
528
      } catch ( const fc::exception& e ) {
529 530
         edump((e.to_detail_string()));
         abort_block();
D
Daniel Larimer 已提交
531 532
         throw;
      }
533 534 535
   } /// apply_block


536
   void push_block( const signed_block_ptr& b ) {
537 538
      auto new_header_state = fork_db.add( b );
      self.accepted_block_header( new_header_state );
539 540
      maybe_switch_forks();
   }
541

542 543 544 545 546 547 548
   void push_confirmation( const header_confirmation& c ) {
      fork_db.add( c );
      self.accepted_confirmation( c );
      maybe_switch_forks();
   }

   void maybe_switch_forks() {
549 550 551 552
      auto new_head = fork_db.head();

      if( new_head->header.previous == head->id ) {
         try {
553
            abort_block();
554
            apply_block( new_head->block );
555
            fork_db.mark_in_current_chain( new_head, true );
556 557 558
            fork_db.set_validity( new_head, true );
            head = new_head;
         } catch ( const fc::exception& e ) {
559
            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.
560 561
            throw;
         }
562
      } else if( new_head->id != head->id ) {
563
         ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
A
arhag 已提交
564
              ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
565 566
         auto branches = fork_db.fetch_branch_from( new_head->id, head->id );

567 568
         for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
            fork_db.mark_in_current_chain( *itr , false );
569
            pop_block();
570 571 572
         }
         FC_ASSERT( head_block_id() == branches.second.back()->header.previous,
                    "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
573 574 575 576 577

         for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
            optional<fc::exception> except;
            try {
               apply_block( (*ritr)->block );
578
               head = *ritr;
579
               fork_db.mark_in_current_chain( *ritr, true );
580 581 582
            }
            catch (const fc::exception& e) { except = e; }
            if (except) {
583
               elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
584

585 586 587 588
               while (ritr != branches.first.rend() ) {
                  fork_db.set_validity( *ritr, false );
                  ++ritr;
               }
589

590
               // pop all blocks from the bad fork
591 592
               for( auto itr = (ritr + 1).base(); itr != branches.second.end(); ++itr ) {
                  fork_db.mark_in_current_chain( *itr , false );
593
                  pop_block();
594 595 596
               }
               FC_ASSERT( head_block_id() == branches.second.back()->header.previous,
                          "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
597

598 599 600
               // re-apply good blocks
               for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
                  apply_block( (*ritr)->block );
601
                  head = *ritr;
602
                  fork_db.mark_in_current_chain( *ritr, true );
603 604 605 606
               }
               throw *except;
            } // end if exception
         } /// end for each block in branch
607
         ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id));
608 609 610
      }
   } /// push_block

611
   void abort_block() {
612
      if( pending ) {
613 614
         for( const auto& t : pending->_applied_transaction_metas )
            unapplied_transactions[t->signed_id] = t;
615 616
         pending.reset();
      }
617 618
   }

D
Daniel Larimer 已提交
619 620 621 622 623

   bool should_enforce_runtime_limits()const {
      return false;
   }

D
Daniel Larimer 已提交
624 625 626 627 628 629 630 631
   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 已提交
632

D
Daniel Larimer 已提交
633 634
   void set_trx_merkle() {
      vector<digest_type> trx_digests;
D
Daniel Larimer 已提交
635 636 637
      const auto& trxs = pending->_pending_block_state->block->transactions;
      trx_digests.reserve( trxs.size() );
      for( const auto& a : trxs )
D
Daniel Larimer 已提交
638
         trx_digests.emplace_back( a.digest() );
D
Daniel Larimer 已提交
639

D
Daniel Larimer 已提交
640
      pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) );
D
Daniel Larimer 已提交
641 642 643
   }


644
   void finalize_block()
D
Daniel Larimer 已提交
645
   { try {
A
arhag 已提交
646 647 648
      ilog( "finalize block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} ${np}",
            ("n",pending->_pending_block_state->block_num)
            ("id",pending->_pending_block_state->header.id())
649
            ("t",pending->_pending_block_state->header.timestamp)
A
arhag 已提交
650 651
            ("p",pending->_pending_block_state->header.producer)
            ("signing_key", pending->_pending_block_state->block_signing_key)
652 653 654 655
            ("v",pending->_pending_block_state->header.schedule_version)
            ("lib",pending->_pending_block_state->dpos_last_irreversible_blocknum)
            ("np",pending->_pending_block_state->header.new_producers)
            );
D
Daniel Larimer 已提交
656 657 658 659 660 661 662

      set_action_merkle();
      set_trx_merkle();

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

D
Daniel Larimer 已提交
663
      create_block_summary();
D
Daniel Larimer 已提交
664

D
Daniel Larimer 已提交
665

666
      /* TODO RESTORE
D
Daniel Larimer 已提交
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
      const auto& b = trace.block;
      update_global_properties( b );
      update_global_dynamic_data( b );
      update_signing_producer(signing_producer, b);

      create_block_summary(b);
      clear_expired_transactions();

      update_last_irreversible_block();

      resource_limits.process_account_limit_updates();

      const auto& chain_config = self.get_global_properties().configuration;
      resource_limits.set_block_parameters(
         {EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct), chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}},
         {EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}}
      );

      */
   } FC_CAPTURE_AND_RETHROW() }

D
Daniel Larimer 已提交
688 689 690 691 692 693 694 695 696

   void create_block_summary() {
      auto p = pending->_pending_block_state;
      auto sid = p->block_num & 0xffff;
      db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
          bso.block_id = p->id;
      });
   }

D
Daniel Larimer 已提交
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
   void clear_expired_transactions() {
      //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>();
      while( (!dedupe_index.empty()) && (head_block_time() > fc::time_point(dedupe_index.begin()->expiration) ) ) {
         transaction_idx.remove(*dedupe_index.begin());
      }

      // Look for expired transactions in the pending generated list, and remove them.
      // TODO: expire these by sending error to handler
      auto& generated_transaction_idx = db.get_mutable_index<generated_transaction_multi_index>();
      const auto& generated_index = generated_transaction_idx.indices().get<by_expiration>();
      while( (!generated_index.empty()) && (head_block_time() > generated_index.begin()->expiration) ) {
      // TODO:   destroy_generated_transaction(*generated_index.begin());
      }
   }

   /*
   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 已提交
734
   signed_transaction get_on_block_transaction()
D
Daniel Larimer 已提交
735 736 737 738 739 740 741
   {
      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}};
      on_block_act.data = fc::raw::pack(head_block_header());

D
Daniel Larimer 已提交
742
      signed_transaction trx;
D
Daniel Larimer 已提交
743 744 745 746 747 748
      trx.actions.emplace_back(std::move(on_block_act));
      trx.set_reference_block(head_block_id());
      trx.expiration = head_block_time() + fc::seconds(1);
      return trx;
   }

749
}; /// controller_impl
D
Daniel Larimer 已提交
750

751
const resource_limits_manager&   controller::get_resource_limits_manager()const
D
Daniel Larimer 已提交
752 753 754
{
   return my->resource_limits;
}
755
resource_limits_manager&         controller::get_mutable_resource_limits_manager()
D
Daniel Larimer 已提交
756 757 758
{
   return my->resource_limits;
}
D
Daniel Larimer 已提交
759

760 761 762 763 764 765 766 767
const authorization_manager&   controller::get_authorization_manager()const
{
   return my->authorization;
}
authorization_manager&         controller::get_mutable_authorization_manager()
{
   return my->authorization;
}
D
Daniel Larimer 已提交
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792

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

controller::~controller() {
}


void controller::startup() {
   my->head = my->fork_db.head();
   if( !my->head ) {
   }

   /*
   auto head = my->blog.read_head();
   if( head && head_block_num() < head->block_num() ) {
      wlog( "\nDatabase in inconsistant state, replaying block log..." );
      //replay();
   }
   */
}

D
Daniel Larimer 已提交
793
chainbase::database& controller::db()const { return my->db; }
D
Daniel Larimer 已提交
794 795 796


void controller::start_block( block_timestamp_type when ) {
797
   my->start_block(when);
D
Daniel Larimer 已提交
798 799 800
}

void controller::finalize_block() {
D
Daniel Larimer 已提交
801
   my->finalize_block();
D
Daniel Larimer 已提交
802 803
}

804 805
void controller::sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
   my->sign_block( signer_callback );
D
Daniel Larimer 已提交
806 807 808
}

void controller::commit_block() {
D
Daniel Larimer 已提交
809
   my->commit_block(true);
D
Daniel Larimer 已提交
810 811
}

D
Daniel Larimer 已提交
812 813 814
block_state_ptr controller::head_block_state()const {
   return my->head;
}
815

D
Daniel Larimer 已提交
816 817 818 819
block_state_ptr controller::pending_block_state()const {
   if( my->pending ) return my->pending->_pending_block_state;
   return block_state_ptr();
}
D
Daniel Larimer 已提交
820

821 822
void controller::abort_block() {
   my->abort_block();
D
Daniel Larimer 已提交
823 824
}

D
Daniel Larimer 已提交
825
void controller::push_block( const signed_block_ptr& b ) {
826
   my->push_block( b );
D
Daniel Larimer 已提交
827 828
}

829 830 831 832
void controller::push_confirmation( const header_confirmation& c ) {
   my->push_confirmation( c );
}

D
Daniel Larimer 已提交
833 834 835 836 837
void controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline ) {
   my->push_transaction(trx, deadline);
}
void controller::push_unapplied_transaction( fc::time_point deadline ) {
   my->push_unapplied_transaction( deadline );
D
Daniel Larimer 已提交
838 839
}

D
Daniel Larimer 已提交
840
transaction_trace_ptr controller::sync_push( const transaction_metadata_ptr& trx ) {
841 842
   transaction_trace_ptr trace;
   trx->on_result = [&]( const transaction_trace_ptr& t ){ trace = t; }; 
D
Daniel Larimer 已提交
843
   my->push_transaction( trx );
844
   return trace;
D
Daniel Larimer 已提交
845
}
D
Daniel Larimer 已提交
846

D
Daniel Larimer 已提交
847
void controller::push_next_scheduled_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
848
   const auto& idx = db().get_index<generated_transaction_multi_index,by_delay>();
849
   if( idx.begin() != idx.end() )
D
Daniel Larimer 已提交
850
      my->push_scheduled_transaction( *idx.begin(), deadline );
D
Daniel Larimer 已提交
851
}
D
Daniel Larimer 已提交
852
void controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline ) {
D
Daniel Larimer 已提交
853 854 855 856 857 858
   /// lookup scheduled trx and then apply it...
}

uint32_t controller::head_block_num()const {
   return my->head->block_num;
}
D
Daniel Larimer 已提交
859 860 861
block_id_type controller::head_block_id()const {
   return my->head->id;
}
D
Daniel Larimer 已提交
862

D
Daniel Larimer 已提交
863
time_point controller::head_block_time()const {
864 865 866 867 868 869
   return my->head_block_time();
}

time_point controller::pending_block_time()const {
   FC_ASSERT( my->pending, "no pending block" );
   return my->pending->_pending_block_state->header.timestamp;
D
Daniel Larimer 已提交
870 871
}

D
Daniel Larimer 已提交
872 873 874
const dynamic_global_property_object& controller::get_dynamic_global_properties()const {
  return my->db.get<dynamic_global_property_object>();
}
D
Daniel Larimer 已提交
875 876 877
const global_property_object& controller::get_global_properties()const {
  return my->db.get<global_property_object>();
}
D
Daniel Larimer 已提交
878 879 880 881

/**
 *  This method reads the current dpos_irreverible block number, if it is higher
 *  than the last block number of the log, it grabs the next block from the
882
 *  fork database, saves it to disk, then removes the block from the fork database.
D
Daniel Larimer 已提交
883 884 885 886
 *
 *  Any forks built off of a different block with the same number are also pruned.
 */
void controller::log_irreversible_blocks() {
887
   if( !my->blog.head() )
D
Daniel Larimer 已提交
888
      my->blog.read_head();
889

D
Daniel Larimer 已提交
890 891 892 893 894 895
   const auto& log_head = my->blog.head();
   auto lib = my->head->dpos_last_irreversible_blocknum;

   if( lib > 1 ) {
      while( log_head && log_head->block_num() < lib ) {
         auto lhead = log_head->block_num();
896 897
         auto blk = my->fork_db.get_block_in_current_chain_by_num( lhead + 1 );
         FC_ASSERT( blk, "unable to find block state", ("block_num",lhead+1));
898
         irreversible_block( blk );
D
Daniel Larimer 已提交
899
         my->blog.append( *blk->block );
D
Daniel Larimer 已提交
900 901
         my->fork_db.prune( blk );
         my->db.commit( lhead );
D
Daniel Larimer 已提交
902 903 904
      }
   }
}
905 906 907 908 909 910 911 912 913
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) );
   if( bptr->id() == id ) return bptr;
   return signed_block_ptr();
}

signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const  {
D
Daniel Larimer 已提交
914 915 916
   optional<signed_block> b = my->blog.read_block_by_num(block_num);
   if( b ) return std::make_shared<signed_block>( move(*b) );

917
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
D
Daniel Larimer 已提交
918 919 920
   if( blk_state ) return blk_state->block;
   return signed_block_ptr();
}
D
Daniel Larimer 已提交
921 922

void controller::pop_block() {
923
   my->pop_block();
D
Daniel Larimer 已提交
924 925
}

926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
void controller::set_proposed_producers( const producer_schedule_type& sch ) {
   const auto& gpo = get_global_properties();
   auto cur_block_num = head_block_num() + 1;
   FC_ASSERT( !gpo.proposed_schedule_block_num.valid() || *gpo.proposed_schedule_block_num == cur_block_num,
              "there is already a proposed schedule set in a previous block, wait for it to become pending" );
   uint32_t next_proposed_schedule_version = 0;
   if( my->pending->_pending_block_state->pending_schedule.producers.size() == 0 ) {
      next_proposed_schedule_version = my->pending->_pending_block_state->active_schedule.version + 1;
   } else {
      next_proposed_schedule_version = my->pending->_pending_block_state->pending_schedule.version + 1;
   }
   FC_ASSERT( sch.version == next_proposed_schedule_version, "wrong producer schedule version specified" );
   my->db.modify( gpo, [&]( auto& gp ) {
      gp.proposed_schedule_block_num = cur_block_num;
      gp.proposed_schedule = sch;
   });
D
Daniel Larimer 已提交
942
}
943 944

const producer_schedule_type&    controller::active_producers()const {
D
Daniel Larimer 已提交
945 946 947
   return my->pending->_pending_block_state->active_schedule;
}

948
const producer_schedule_type&    controller::pending_producers()const {
D
Daniel Larimer 已提交
949 950 951
   return my->pending->_pending_block_state->pending_schedule;
}

952 953 954 955 956 957 958 959 960
optional<producer_schedule_type> controller::proposed_producers()const {
   const auto& gpo = get_global_properties();
   if( !gpo.proposed_schedule_block_num.valid() )
      return optional<producer_schedule_type>();

   return gpo.proposed_schedule;
}


D
Daniel Larimer 已提交
961 962 963 964 965 966 967 968 969 970 971 972 973
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 已提交
974

975
const account_object& controller::get_account( account_name name )const
D
Daniel Larimer 已提交
976 977 978
{ try {
   return my->db.get<account_object, by_name>(name);
} FC_CAPTURE_AND_RETHROW( (name) ) }
D
Daniel Larimer 已提交
979

980 981 982 983 984 985 986 987 988 989
const map<digest_type, transaction_metadata_ptr>&  controller::unapplied_transactions()const {
   return my->unapplied_transactions;
}


void controller::validate_referenced_accounts( const transaction& trx )const {
   for( const auto& a : trx.context_free_actions ) {
      get_account( a.account );
      FC_ASSERT( a.authorization.size() == 0 );
   }
D
Daniel Larimer 已提交
990
   bool one_auth = false;
991 992
   for( const auto& a : trx.actions ) {
      get_account( a.account );
993
      for( const auto& auth : a.authorization ) {
D
Daniel Larimer 已提交
994
         one_auth = true;
995 996 997
         get_account( auth.actor );
      }
   }
D
Daniel Larimer 已提交
998
   EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" );
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
}

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

   EOS_ASSERT( time_point(trx.expiration) >= pending_block_time(), expired_tx_exception, "transaction has expired" );
   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)) }

D
Daniel Larimer 已提交
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
uint64_t controller::validate_net_usage( const transaction_metadata_ptr& trx )const {
   const auto& cfg = get_global_properties().configuration;

   auto actual_net_usage = cfg.base_per_transaction_net_usage + trx->packed_trx.get_billable_size();

   actual_net_usage = ((actual_net_usage + 7)/8) * 8; // Round up to nearest multiple of 8

   uint32_t net_usage_limit = trx->trx.max_net_usage_words.value * 8UL; // overflow checked in validate_transaction_without_state
   EOS_ASSERT( net_usage_limit == 0 || actual_net_usage <= net_usage_limit, tx_resource_exhausted,
               "declared net usage limit of transaction is too low: ${actual_net_usage} > ${declared_limit}",
               ("actual_net_usage", actual_net_usage)("declared_limit",net_usage_limit) );

   return actual_net_usage;
}

1028 1029 1030 1031 1032 1033 1034
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));
1035 1036
} FC_CAPTURE_AND_RETHROW() }

1037

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