github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/util/bc_generator.cpp (about)

     1  // Copyright (C) 2018 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // (at your option) any later version.
    10  //
    11  // the go-nebulas library is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with the go-nebulas library.  If not, see
    18  // <http://www.gnu.org/licenses/>.
    19  //
    20  #include "util/bc_generator.h"
    21  #include "crypto/hash.h"
    22  #include "fs/bc_storage_session.h"
    23  #include "fs/proto/trie.pb.h"
    24  #include "util/chrono.h"
    25  #include "util/json_parser.h"
    26  #include <boost/property_tree/json_parser.hpp>
    27  #include <boost/property_tree/ptree.hpp>
    28  
    29  namespace neb {
    30  namespace util {
    31  void all_accounts::add_account(
    32      const std::shared_ptr<corepb::Account> &account) {
    33    address_t addr = get_address_from_account(account.get());
    34    m_all_accounts.insert(std::make_pair(addr, std::move(account)));
    35    m_all_addresses.push_back(addr);
    36  }
    37  
    38  corepb::Account *all_accounts::random_account() const {
    39    if (m_all_accounts.empty())
    40      throw std::invalid_argument("no account yet");
    41    std::uniform_int_distribution<uint64_t> dist(0, m_all_accounts.size() - 1);
    42    const address_t &addr = m_all_addresses[dist(m_random_generator)];
    43    auto it = m_all_accounts.find(addr);
    44    return it->second.get();
    45  }
    46  
    47  uint64_t all_accounts::get_nonce(const address_t &addr) {
    48    auto it = m_all_accounts.find(addr);
    49    if (it == m_all_accounts.end())
    50      return 0;
    51    return it->second->nonce();
    52  }
    53  
    54  void all_accounts::increase_nonce(const address_t &addr) {
    55    auto it = m_all_accounts.find(addr);
    56    if (it == m_all_accounts.end())
    57      return;
    58  
    59    auto account = it->second;
    60    account->set_nonce(account->nonce());
    61  }
    62  
    63  void all_accounts::increase_balance(const address_t &addr, const wei &val) {
    64    auto it = m_all_accounts.find(addr);
    65    if (it == m_all_accounts.end())
    66      return;
    67  
    68    auto account = it->second;
    69    wei_t b = storage_to_wei(string_to_byte(account->balance()));
    70    b = b + val.wei_value();
    71    account->set_balance(byte_to_string(wei_to_storage(b)));
    72  }
    73  
    74  bool all_accounts::decrease_balance(const address_t &addr, const wei &val) {
    75    auto it = m_all_accounts.find(addr);
    76    if (it == m_all_accounts.end()) {
    77      return false;
    78    }
    79  
    80    auto account = it->second;
    81    wei_t b = storage_to_wei(string_to_byte(account->balance()));
    82    b = b - val.wei_value();
    83    if (b < 0) {
    84      return false;
    85    }
    86    account->set_balance(byte_to_string(wei_to_storage(b)));
    87    return true;
    88  }
    89  
    90  corepb::Account *all_accounts::random_user_account() const {
    91    corepb::Account *account = random_account();
    92    address_t addr = get_address_from_account(account);
    93    while (!is_normal_address(addr)) {
    94      account = random_account();
    95      addr = get_address_from_account(account);
    96    }
    97    return account;
    98  }
    99  
   100  corepb::Account *all_accounts::random_contract_account() const {
   101    corepb::Account *account = random_account();
   102    address_t addr = get_address_from_account(account);
   103    uint32_t retry_max_num = m_all_accounts.size();
   104    while (!is_contract_address(addr)) {
   105      account = random_account();
   106      addr = get_address_from_account(account);
   107      if (--retry_max_num < 0) {
   108        return nullptr;
   109      }
   110    }
   111    return account;
   112  }
   113  
   114  address_t get_address_from_account(corepb::Account *account) {
   115    return to_address(account->address());
   116  }
   117  
   118  generate_block::generate_block(all_accounts *accounts, uint64_t height)
   119      : m_all_accounts(accounts), m_height(height) {}
   120  
   121  std::shared_ptr<corepb::Account>
   122  generate_block::gen_user_account(const nas &v) {
   123    std::shared_ptr<corepb::Account> ret = std::make_shared<corepb::Account>();
   124    address_t addr(NAS_ADDRESS_LEN);
   125    addr[0] = NAS_ADDRESS_MAGIC_NUM;
   126    addr[1] = NAS_ADDRESS_ACCOUNT_MAGIC_NUM;
   127    for (int i = 2; i < NAS_ADDRESS_LEN;) {
   128      int32_t num = std::rand();
   129      int32_t *p = (int32_t *)(addr.value() + i);
   130      *p = num;
   131      i += 4;
   132    }
   133    ret->set_address(address_to_string(addr));
   134    std::string balance = byte_to_string(wei_to_storage(v.wei_value()));
   135    ret->set_balance(balance);
   136    m_all_accounts->add_account(ret);
   137    return ret;
   138  }
   139  
   140  std::shared_ptr<corepb::Account>
   141  generate_block::add_deploy_transaction(const address_t &owner,
   142                                         const bytes &payload) {
   143    transaction_ptr tx(new corepb::Transaction());
   144    tx->set_to(address_to_string(owner));
   145    tx->set_from(address_to_string(owner));
   146    corepb::Data *data = new corepb::Data();
   147    data->set_type("deploy");
   148    boost::property_tree::ptree pt;
   149    pt.put("Data", payload.to_base64());
   150    std::string payload_str;
   151    neb::util::json_parser::write_json(payload_str, pt);
   152    data->set_payload(payload_str);
   153    tx->set_allocated_data(data);
   154    tx->set_timestamp(util::now());
   155    tx->set_nonce(m_all_accounts->get_nonce(owner));
   156    wei value(1000_wei);
   157    bool b_ret = m_all_accounts->decrease_balance(owner, value);
   158    if (b_ret == false)
   159      return nullptr;
   160    tx->set_value(byte_to_string(wei_to_storage(value.wei_value())));
   161    m_all_accounts->increase_nonce(owner);
   162    neb::bytes b(tx->ByteSizeLong());
   163    tx->SerializeToArray(b.value(), b.size());
   164    tx->set_hash(byte_to_string(from_fix_bytes(crypto::sha3_256_hash(b))));
   165    m_transactions.push_back(tx);
   166  
   167    std::shared_ptr<corepb::Account> ret = std::make_shared<corepb::Account>();
   168    address_t addr(NAS_ADDRESS_LEN);
   169    addr[0] = NAS_ADDRESS_MAGIC_NUM;
   170    addr[1] = NAS_ADDRESS_CONTRACT_MAGIC_NUM;
   171    for (int i = 2; i < NAS_ADDRESS_LEN;) {
   172      int32_t num = std::rand();
   173      int32_t *p = (int32_t *)(addr.value() + i);
   174      *p = num;
   175      i += 4;
   176    }
   177    ret->set_address(address_to_string(addr));
   178    ret->set_birth_place(tx->hash());
   179    m_all_accounts->add_account(ret);
   180  
   181    return ret;
   182  }
   183  std::shared_ptr<corepb::Transaction>
   184  generate_block::add_protocol_transaction(const address_t &owner,
   185                                           const bytes &payload) {
   186    transaction_ptr tx(new corepb::Transaction());
   187    tx->set_to(address_to_string(owner));
   188    tx->set_from(address_to_string(owner));
   189    corepb::Data *data = new corepb::Data();
   190    data->set_type("protocol");
   191    boost::property_tree::ptree pt;
   192    pt.put("Data", payload.to_base64());
   193  
   194    std::string payload_str;
   195    neb::util::json_parser::write_json(payload_str, pt);
   196    data->set_payload(payload_str);
   197    wei value(1000_wei);
   198    bool ret = m_all_accounts->decrease_balance(owner, value);
   199    if (ret == false)
   200      return nullptr;
   201    tx->set_value(byte_to_string(wei_to_storage(value.wei_value())));
   202    tx->set_allocated_data(data);
   203    tx->set_timestamp(util::now());
   204    tx->set_nonce(m_all_accounts->get_nonce(owner));
   205    m_all_accounts->increase_nonce(owner);
   206    neb::bytes b(tx->ByteSizeLong());
   207    tx->SerializeToArray(b.value(), b.size());
   208    tx->set_hash(byte_to_string(from_fix_bytes(crypto::sha3_256_hash(b))));
   209    m_transactions.push_back(tx);
   210  
   211    return tx;
   212  }
   213  std::shared_ptr<corepb::Transaction>
   214  generate_block::add_binary_transaction(const address_t &from,
   215                                         const address_t &to, const nas &value) {
   216    transaction_ptr tx(new corepb::Transaction());
   217    tx->set_to(address_to_string(to));
   218    tx->set_from(address_to_string(from));
   219    corepb::Data *data = new corepb::Data();
   220    data->set_type("binary");
   221    bool ret = m_all_accounts->decrease_balance(from, wei(value));
   222    if (ret == false)
   223      return nullptr;
   224    m_all_accounts->increase_balance(to, wei(value));
   225    std::string v = byte_to_string(wei_to_storage(value.wei_value()));
   226    tx->set_value(v);
   227    tx->set_allocated_data(data);
   228    tx->set_timestamp(util::now());
   229    tx->set_nonce(m_all_accounts->get_nonce(from));
   230    m_all_accounts->increase_nonce(from);
   231    neb::bytes b(tx->ByteSizeLong());
   232    tx->SerializeToArray(b.value(), b.size());
   233    tx->set_hash(byte_to_string(from_fix_bytes(crypto::sha3_256_hash(b))));
   234    m_transactions.push_back(tx);
   235  
   236    return tx;
   237  }
   238  
   239  std::shared_ptr<corepb::Transaction>
   240  generate_block::add_call_transaction(const address_t &from,
   241                                       const address_t &to) {
   242    transaction_ptr tx(new corepb::Transaction());
   243    tx->set_to(address_to_string(to));
   244    tx->set_from(address_to_string(from));
   245    corepb::Data *data = new corepb::Data();
   246    data->set_type("call");
   247    tx->set_allocated_data(data);
   248    tx->set_timestamp(util::now());
   249    wei value(1000_wei);
   250    std::string v = byte_to_string(wei_to_storage(value.wei_value()));
   251    tx->set_value(v);
   252    tx->set_nonce(m_all_accounts->get_nonce(from));
   253    m_all_accounts->increase_nonce(from);
   254    neb::bytes b(tx->ByteSizeLong());
   255    tx->SerializeToArray(b.value(), b.size());
   256    tx->set_hash(byte_to_string(from_fix_bytes(crypto::sha3_256_hash(b))));
   257    m_transactions.push_back(tx);
   258  
   259    return tx;
   260  }
   261  
   262  void generate_block::write_to_blockchain_db() {
   263    // 1. generate corepb::Block
   264    std::unique_ptr<corepb::BlockHeader> header =
   265        std::make_unique<corepb::BlockHeader>();
   266    header->set_timestamp(util::now());
   267  
   268    std::unique_ptr<corepb::Block> block = std::make_unique<corepb::Block>();
   269    block->set_allocated_header(header.get());
   270    block->set_height(m_height);
   271    for (auto &tx : m_transactions) {
   272      corepb::Transaction *etx = block->add_transactions();
   273      *etx = *tx;
   274    }
   275    std::string block_str = block->SerializeAsString();
   276    header->set_hash(
   277        byte_to_string(from_fix_bytes(crypto::sha3_256_hash(block_str))));
   278  
   279    // 2. update to LIB
   280    fs::blockchain::write_LIB_block(block.get());
   281    block->release_header();
   282  
   283    // 3. write all accounts to DB
   284    //! We use triepb::Node to write all accounts to db.
   285    //! This is a trick!
   286    //! Ideally, we should use trie to shrink db size.
   287    //! Yet, we only fill several fields in Account, so it's ok to write dup data.
   288    triepb::Node t_accounts;
   289    m_all_accounts->for_each_account(
   290        [&t_accounts](const std::shared_ptr<corepb::Account> &account) {
   291          std::string *s = t_accounts.add_val();
   292          *s = account->SerializeAsString();
   293        });
   294  
   295    std::string key = std::string("account") + std::to_string(m_height);
   296    std::string account_str = t_accounts.SerializeAsString();
   297    fs::bc_storage_session::instance().put_bytes(string_to_byte(key),
   298                                                 string_to_byte(account_str));
   299  }
   300  
   301  std::vector<std::shared_ptr<corepb::Account>>
   302  generate_block::read_accounts_in_height(block_height_t height) {
   303    std::string key = std::string("account") + std::to_string(height);
   304    auto account_str =
   305        fs::bc_storage_session::instance().get_bytes(string_to_byte(key));
   306    triepb::Node t_accounts;
   307    t_accounts.ParseFromArray(account_str.value(), account_str.size());
   308    std::vector<std::shared_ptr<corepb::Account>> ret;
   309    for (size_t i = 0; i < t_accounts.val_size(); ++i) {
   310      std::string s = t_accounts.val(i);
   311      std::shared_ptr<corepb::Account> account =
   312          std::make_shared<corepb::Account>();
   313      account->ParseFromString(s);
   314      ret.push_back(account);
   315    }
   316    return ret;
   317  }
   318  
   319  std::shared_ptr<corepb::Block>
   320  generate_block::read_block_with_height(block_height_t height) {
   321    std::unique_ptr<corepb::Block> block =
   322        fs::blockchain::load_block_with_height(height);
   323    return std::shared_ptr<corepb::Block>(std::move(block));
   324  }
   325  
   326  } // namespace util
   327  } // namespace neb