text: // Copyright (c) 2011-2016 The Cryptonote developers
  // Copyright (c) 2014-2016 SDN developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #include "RPCTestNode.h"
  
  #include <future>
  #include <vector>
  #include <thread>
  
  #include "Common/StringTools.h"
  #include "CryptoNoteCore/CryptoNoteTools.h"
  #include "NodeRpcProxy/NodeRpcProxy.h"
  #include "Rpc/CoreRpcServerCommandsDefinitions.h"
  #include "Rpc/HttpClient.h"
  #include "Rpc/JsonRpc.h"
  
  #include "Logger.h"
  #include "NodeCallback.h"
  
  using namespace cn;
  using namespace platform_system;
  
  namespace Tests {
  
  RPCTestNode::RPCTestNode(uint16_t port, platform_system::Dispatcher& d) : 
    m_rpcPort(port), m_dispatcher(d), m_httpClient(d, "127.0.0.1", port) {
  }
  
  bool RPCTestNode::startMining(size_t threadsCount, const std::string& address) { 
    LOG_DEBUG("startMining()");
  
    try {
      COMMAND_RPC_START_MINING::request req;
      COMMAND_RPC_START_MINING::response resp;
      req.miner_address = address;
      req.threads_count = threadsCount;
  
      invokeJsonCommand(m_httpClient, "/start_mining", req, resp);
      if (resp.status != CORE_RPC_STATUS_OK) {
        throw std::runtime_error(resp.status);
      }
    } catch (std::exception& e) {
      std::cout << "startMining() RPC call fail: " << e.what();
      return false;
    }
  
    return true;
  }
  
  bool RPCTestNode::getBlockTemplate(const std::string& minerAddress, cn::Block& blockTemplate, uint64_t& difficulty) {
    LOG_DEBUG("getBlockTemplate()");
  
    try {
      COMMAND_RPC_GETBLOCKTEMPLATE::request req;
      COMMAND_RPC_GETBLOCKTEMPLATE::response rsp;
      req.wallet_address = minerAddress;
      req.reserve_size = 0;
  
      JsonRpc::invokeJsonRpcCommand(m_httpClient, "getblocktemplate", req, rsp);
      if (rsp.status != CORE_RPC_STATUS_OK) {
        throw std::runtime_error(rsp.status);
      }
  
      difficulty = rsp.difficulty;
  
      BinaryArray blockBlob = (::common::fromHex(rsp.blocktemplate_blob));
      return fromBinaryArray(blockTemplate, blockBlob);
    } catch (std::exception& e) {
      LOG_ERROR("JSON-RPC call startMining() failed: " + std::string(e.what()));
      return false;
    }
  
    return true;
  }
  
  bool RPCTestNode::submitBlock(const std::string& block) {
    LOG_DEBUG("submitBlock()");
  
    try {
      COMMAND_RPC_SUBMITBLOCK::request req;
      COMMAND_RPC_SUBMITBLOCK::response res;
      req.push_back(block);
      JsonRpc::invokeJsonRpcCommand(m_httpClient, "submitblock", req, res);
      if (res.status != CORE_RPC_STATUS_OK) {
        throw std::runtime_error(res.status);
      }
    } catch (std::exception& e) {
      LOG_ERROR("RPC call of submit_block returned error: " + std::string(e.what()));
      return false;
    }
  
    return true;
  }
  
  bool RPCTestNode::stopMining() { 
    LOG_DEBUG("stopMining()");
  
    try {
      COMMAND_RPC_STOP_MINING::request req;
      COMMAND_RPC_STOP_MINING::response resp;
      invokeJsonCommand(m_httpClient, "/stop_mining", req, resp);
      if (resp.status != CORE_RPC_STATUS_OK) {
        throw std::runtime_error(resp.status);
      }
    } catch (std::exception& e) {
      std::cout << "stopMining() RPC call fail: " << e.what();
      return false;
    }
  
    return true;
  }
  
  bool RPCTestNode::getTailBlockId(crypto::Hash& tailBlockId) {
    LOG_DEBUG("getTailBlockId()");
  
    try {
      COMMAND_RPC_GET_LAST_BLOCK_HEADER::request req;
      COMMAND_RPC_GET_LAST_BLOCK_HEADER::response rsp;
      JsonRpc::invokeJsonRpcCommand(m_httpClient, "getlastblockheader", req, rsp);
      if (rsp.status != CORE_RPC_STATUS_OK) {
        throw std::runtime_error(rsp.status);
      }
  
      return ::common::podFromHex(rsp.block_header.hash, tailBlockId);
    } catch (std::exception& e) {
      LOG_ERROR("JSON-RPC call getTailBlockId() failed: " + std::string(e.what()));
      return false;
    }
  
    return true;
  }
  
  bool RPCTestNode::makeINode(std::unique_ptr<cn::INode>& node) {
    std::unique_ptr<cn::INode> newNode(new cn::NodeRpcProxy("127.0.0.1", m_rpcPort));
    NodeCallback cb;
    newNode->init(cb.callback());
    auto ec = cb.get();
  
    if (ec) {
      LOG_ERROR("init error: " + ec.message() + ':' + TO_STRING(ec.value()));
      return false;
    }
  
    LOG_DEBUG("NodeRPCProxy on port " + TO_STRING(m_rpcPort) + " initialized");
    node = std::move(newNode);
    return true;
  }
  
  bool RPCTestNode::stopDaemon() {
    try {
      LOG_DEBUG("stopDaemon()");
      COMMAND_RPC_STOP_DAEMON::request req;
      COMMAND_RPC_STOP_DAEMON::response resp;
      invokeJsonCommand(m_httpClient, "/stop_daemon", req, resp);
      if (resp.status != CORE_RPC_STATUS_OK) {
        throw std::runtime_error(resp.status);
      }
    } catch (std::exception& e) {
      std::cout << "stopDaemon() RPC call fail: " << e.what();
      return false;
    }
  
    return true;
  }
  
  uint64_t RPCTestNode::getLocalHeight() {
    try {
      cn::COMMAND_RPC_GET_INFO::request req;
      cn::COMMAND_RPC_GET_INFO::response rsp;
      invokeJsonCommand(m_httpClient, "/getinfo", req, rsp);
      if (rsp.status == CORE_RPC_STATUS_OK) {
        return rsp.height;
      }
    } catch (std::exception&) {
    }
  
    return 0;
  }
  
  }
  