github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/fs/blockchain/blockchain_api.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  
    21  #include "fs/blockchain/blockchain_api.h"
    22  #include "common/nebulas_currency.h"
    23  #include "fs/blockchain/trie/trie.h"
    24  #include "fs/util.h"
    25  #include <boost/property_tree/json_parser.hpp>
    26  #include <boost/property_tree/ptree.hpp>
    27  
    28  namespace neb {
    29  namespace fs {
    30  
    31  blockchain_api_base::~blockchain_api_base() {}
    32  
    33  blockchain_api::blockchain_api() {}
    34  
    35  blockchain_api::~blockchain_api() {}
    36  
    37  std::unique_ptr<std::vector<transaction_info_t>>
    38  blockchain_api::get_block_transactions_api(block_height_t height) {
    39  
    40    auto ret = std::make_unique<std::vector<transaction_info_t>>();
    41    // special for  block height 1
    42    if (height <= 1) {
    43      return ret;
    44    }
    45  
    46    auto block = blockchain::load_block_with_height(height);
    47    int64_t timestamp = block->header().timestamp();
    48  
    49    std::string events_root_str = block->header().events_root();
    50    neb::bytes events_root_bytes = neb::string_to_byte(events_root_str);
    51  
    52    for (auto &tx : block->transactions()) {
    53      transaction_info_t info;
    54  
    55      info.m_height = height;
    56      info.m_timestamp = timestamp;
    57  
    58      info.m_from = to_address(tx.from());
    59      info.m_to = to_address(tx.to());
    60      info.m_tx_value = storage_to_wei(neb::string_to_byte(tx.value()));
    61      info.m_gas_price = storage_to_wei(neb::string_to_byte(tx.gas_price()));
    62      info.m_tx_type = tx.data().type();
    63  
    64      // get topic chain.transactionResult
    65      std::string tx_hash_str = tx.hash();
    66      neb::bytes tx_hash_bytes = neb::string_to_byte(tx_hash_str);
    67      auto txs_result_ptr =
    68          get_transaction_result_api(events_root_bytes, tx_hash_bytes);
    69  
    70      info.m_status = txs_result_ptr->m_status;
    71      info.m_gas_used = txs_result_ptr->m_gas_used;
    72  
    73      // ignore failed transactions
    74      if (info.m_status == tx_status_succ) {
    75        ret->push_back(info);
    76      }
    77    }
    78    return ret;
    79  }
    80  
    81  std::unique_ptr<event_info_t>
    82  blockchain_api::get_transaction_result_api(const neb::bytes &events_root,
    83                                             const neb::bytes &tx_hash) {
    84    trie t;
    85    neb::bytes txs_result;
    86  
    87    for (int64_t id = 1;; id++) {
    88      neb::bytes id_bytes = neb::number_to_byte<neb::bytes>(id);
    89      neb::bytes events_tx_hash = tx_hash;
    90      events_tx_hash.append_bytes(id_bytes.value(), id_bytes.size());
    91  
    92      neb::bytes trie_node_bytes;
    93      bool ret = t.get_trie_node(events_root, events_tx_hash, trie_node_bytes);
    94      if (!ret) {
    95        break;
    96      }
    97      txs_result = trie_node_bytes;
    98    }
    99    assert(!txs_result.empty());
   100  
   101    std::string json_str = neb::byte_to_string(txs_result);
   102  
   103    return json_parse_event(json_str);
   104  }
   105  
   106  std::unique_ptr<event_info_t>
   107  blockchain_api::json_parse_event(const std::string &json) {
   108    boost::property_tree::ptree pt;
   109    std::stringstream ss(json);
   110    boost::property_tree::read_json(ss, pt);
   111  
   112    std::string topic = pt.get<std::string>("Topic");
   113    assert(topic.compare("chain.transactionResult") == 0);
   114  
   115    std::string data_json = pt.get<std::string>("Data");
   116    ss = std::stringstream(data_json);
   117    boost::property_tree::read_json(ss, pt);
   118  
   119    int32_t status = pt.get<int32_t>("status");
   120    wei_t gas_used = boost::lexical_cast<wei_t>(pt.get<std::string>("gas_used"));
   121  
   122    auto ret = std::make_unique<event_info_t>(event_info_t{status, gas_used});
   123    return ret;
   124  }
   125  
   126  std::unique_ptr<corepb::Account>
   127  blockchain_api::get_account_api(const address_t &addr, block_height_t height) {
   128  
   129    auto block = blockchain::load_block_with_height(height);
   130  
   131    // get block header account state
   132    std::string state_root_str = block->header().state_root();
   133    neb::bytes state_root_bytes = neb::string_to_byte(state_root_str);
   134  
   135    // get trie node
   136    trie t;
   137    neb::bytes trie_node_bytes;
   138    bool is_found = t.get_trie_node(state_root_bytes, addr, trie_node_bytes);
   139    auto corepb_account_ptr = std::make_unique<corepb::Account>();
   140    if (!is_found) {
   141      corepb_account_ptr->set_address(std::to_string(addr));
   142      corepb_account_ptr->set_balance(std::to_string(neb::wei_to_storage(0)));
   143      return corepb_account_ptr;
   144    }
   145  
   146    bool ret = corepb_account_ptr->ParseFromArray(trie_node_bytes.value(),
   147                                                  trie_node_bytes.size());
   148    if (!ret) {
   149      throw std::runtime_error("parse corepb Account failed");
   150    }
   151    return corepb_account_ptr;
   152  }
   153  
   154  std::unique_ptr<corepb::Transaction>
   155  blockchain_api::get_transaction_api(const std::string &tx_hash,
   156                                      block_height_t height) {
   157    auto corepb_txs_ptr = std::make_unique<corepb::Transaction>();
   158  
   159    // suppose height is the latest block height
   160    auto block = blockchain::load_block_with_height(height);
   161  
   162    // get block header transaction root
   163    std::string txs_root_str = block->header().txs_root();
   164    neb::bytes txs_root_bytes = neb::string_to_byte(txs_root_str);
   165  
   166    // get trie node
   167    trie t;
   168    neb::bytes tx_hash_bytes = neb::string_to_byte(tx_hash);
   169    neb::bytes trie_node_bytes;
   170    bool ret = t.get_trie_node(txs_root_bytes, tx_hash_bytes, trie_node_bytes);
   171    if (!ret) {
   172      return corepb_txs_ptr;
   173    }
   174  
   175    ret = corepb_txs_ptr->ParseFromArray(trie_node_bytes.value(),
   176                                         trie_node_bytes.size());
   177    if (!ret) {
   178      throw std::runtime_error("parse corepb Transaction failed");
   179    }
   180    return corepb_txs_ptr;
   181  }
   182  
   183  } // namespace fs
   184  } // namespace neb