danicoin/src/Wallet/WalletRpcServer.cpp

283 lines
11 KiB
C++
Raw Normal View History

// Copyright (c) 2011-2016 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2014-04-02 16:00:17 +00:00
2015-07-30 15:22:07 +00:00
#include "WalletRpcServer.h"
2015-05-27 12:08:46 +00:00
#include <fstream>
2015-07-30 15:22:07 +00:00
#include "Common/CommandLine.h"
2015-05-27 12:08:46 +00:00
#include "Common/StringTools.h"
2015-07-30 15:22:07 +00:00
#include "CryptoNoteCore/CryptoNoteFormatUtils.h"
#include "CryptoNoteCore/Account.h"
2014-04-02 16:00:17 +00:00
#include "crypto/hash.h"
2015-07-30 15:22:07 +00:00
#include "WalletLegacy/WalletHelper.h"
2015-05-27 12:08:46 +00:00
// #include "wallet_errors.h"
2014-04-02 16:00:17 +00:00
2015-07-30 15:22:07 +00:00
#include "Rpc/JsonRpc.h"
2014-04-02 16:00:17 +00:00
2015-05-27 12:08:46 +00:00
using namespace Logging;
using namespace CryptoNote;
2015-05-27 12:08:46 +00:00
2015-07-30 15:22:07 +00:00
namespace Tools {
2015-05-27 12:08:46 +00:00
const command_line::arg_descriptor<uint16_t> wallet_rpc_server::arg_rpc_bind_port = { "rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server", 0, true };
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_ip = { "rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1" };
2014-04-02 16:00:17 +00:00
void wallet_rpc_server::init_options(boost::program_options::options_description& desc) {
command_line::add_arg(desc, arg_rpc_bind_ip);
command_line::add_arg(desc, arg_rpc_bind_port);
}
//------------------------------------------------------------------------------------------------------------------------------
2015-05-27 12:08:46 +00:00
wallet_rpc_server::wallet_rpc_server(
System::Dispatcher& dispatcher,
Logging::ILogger& log,
2015-07-30 15:22:07 +00:00
CryptoNote::IWalletLegacy&w,
2015-05-27 12:08:46 +00:00
CryptoNote::INode& n,
CryptoNote::Currency& currency,
const std::string& walletFile)
:
HttpServer(dispatcher, log),
logger(log, "WalletRpc"),
m_dispatcher(dispatcher),
m_stopComplete(dispatcher),
m_wallet(w),
m_node(n),
m_currency(currency),
m_walletFilename(walletFile) {
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::run() {
2015-05-27 12:08:46 +00:00
start(m_bind_ip, m_port);
m_stopComplete.wait();
return true;
}
2015-05-27 12:08:46 +00:00
void wallet_rpc_server::send_stop_signal() {
m_dispatcher.remoteSpawn([this] {
std::cout << "wallet_rpc_server::send_stop_signal()" << std::endl;
stop();
m_stopComplete.set();
});
}
2015-05-27 12:08:46 +00:00
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::handle_command_line(const boost::program_options::variables_map& vm) {
m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip);
m_port = command_line::get_arg(vm, arg_rpc_bind_port);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::init(const boost::program_options::variables_map& vm) {
2015-05-27 12:08:46 +00:00
if (!handle_command_line(vm)) {
logger(ERROR) << "Failed to process command line in wallet_rpc_server";
return false;
}
return true;
}
2015-05-27 12:08:46 +00:00
void wallet_rpc_server::processRequest(const CryptoNote::HttpRequest& request, CryptoNote::HttpResponse& response) {
using namespace CryptoNote::JsonRpc;
JsonRpcRequest jsonRequest;
JsonRpcResponse jsonResponse;
try {
2015-05-27 12:08:46 +00:00
jsonRequest.parseRequest(request.getBody());
jsonResponse.setId(jsonRequest.getId());
static std::unordered_map<std::string, JsonMemberMethod> s_methods = {
{ "getbalance", makeMemberMethod(&wallet_rpc_server::on_getbalance) },
{ "transfer", makeMemberMethod(&wallet_rpc_server::on_transfer) },
{ "store", makeMemberMethod(&wallet_rpc_server::on_store) },
{ "get_payments", makeMemberMethod(&wallet_rpc_server::on_get_payments) },
{ "get_transfers", makeMemberMethod(&wallet_rpc_server::on_get_transfers) },
{ "get_height", makeMemberMethod(&wallet_rpc_server::on_get_height) },
{ "reset", makeMemberMethod(&wallet_rpc_server::on_reset) }
};
auto it = s_methods.find(jsonRequest.getMethod());
if (it == s_methods.end()) {
throw JsonRpcError(errMethodNotFound);
}
it->second(this, jsonRequest, jsonResponse);
} catch (const JsonRpcError& err) {
jsonResponse.setError(err);
} catch (const std::exception& e) {
jsonResponse.setError(JsonRpcError(WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR, e.what()));
2014-04-02 16:00:17 +00:00
}
2015-05-27 12:08:46 +00:00
response.setBody(jsonResponse.getBody());
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res) {
2015-07-30 15:22:07 +00:00
res.locked_amount = m_wallet.pendingBalance();
res.available_balance = m_wallet.actualBalance();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-05-27 12:08:46 +00:00
bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res) {
2015-07-30 15:22:07 +00:00
std::vector<CryptoNote::WalletLegacyTransfer> transfers;
for (auto it = req.destinations.begin(); it != req.destinations.end(); it++) {
2015-07-30 15:22:07 +00:00
CryptoNote::WalletLegacyTransfer transfer;
transfer.address = it->address;
transfer.amount = it->amount;
transfers.push_back(transfer);
2014-04-02 16:00:17 +00:00
}
std::vector<uint8_t> extra;
if (!req.payment_id.empty()) {
std::string payment_id_str = req.payment_id;
2015-07-30 15:22:07 +00:00
Crypto::Hash payment_id;
2015-05-27 12:08:46 +00:00
if (!CryptoNote::parsePaymentId(payment_id_str, payment_id)) {
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID,
"Payment id has invalid format: \"" + payment_id_str + "\", expected 64-character string");
2014-04-02 16:00:17 +00:00
}
2015-07-30 15:22:07 +00:00
BinaryArray extra_nonce;
CryptoNote::setPaymentIdToTransactionExtraNonce(extra_nonce, payment_id);
if (!CryptoNote::addExtraNonceToTransactionExtra(extra, extra_nonce)) {
2015-05-27 12:08:46 +00:00
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID,
"Something went wrong with payment_id. Please check its format: \"" + payment_id_str + "\", expected 64-character string");
2014-04-02 16:00:17 +00:00
}
}
2014-06-25 17:21:42 +00:00
std::string extraString;
std::copy(extra.begin(), extra.end(), std::back_inserter(extraString));
try {
2015-05-27 12:08:46 +00:00
CryptoNote::WalletHelper::SendCompleteResultObserver sent;
WalletHelper::IWalletRemoveObserverGuard removeGuard(m_wallet, sent);
2014-06-25 17:21:42 +00:00
CryptoNote::TransactionId tx = m_wallet.sendTransaction(transfers, req.fee, extraString, req.mixin, req.unlock_time);
2015-07-30 15:22:07 +00:00
if (tx == WALLET_LEGACY_INVALID_TRANSACTION_ID) {
2015-05-27 12:08:46 +00:00
throw std::runtime_error("Couldn't send transaction");
}
std::error_code sendError = sent.wait(tx);
removeGuard.removeObserver();
if (sendError) {
2015-05-27 12:08:46 +00:00
throw std::system_error(sendError);
2014-04-02 16:00:17 +00:00
}
2015-07-30 15:22:07 +00:00
CryptoNote::WalletLegacyTransaction txInfo;
m_wallet.getTransaction(tx, txInfo);
2015-05-27 12:08:46 +00:00
res.tx_hash = Common::podToHex(txInfo.hash);
} catch (const std::exception& e) {
2015-05-27 12:08:46 +00:00
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR, e.what());
2014-04-02 16:00:17 +00:00
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-05-27 12:08:46 +00:00
bool wallet_rpc_server::on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res) {
try {
2015-05-27 12:08:46 +00:00
WalletHelper::storeWallet(m_wallet, m_walletFilename);
} catch (std::exception& e) {
2015-05-27 12:08:46 +00:00
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR, std::string("Couldn't save wallet: ") + e.what());
}
2015-05-27 12:08:46 +00:00
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
2015-05-27 12:08:46 +00:00
bool wallet_rpc_server::on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res) {
2015-07-30 15:22:07 +00:00
Crypto::Hash expectedPaymentId;
CryptoNote::BinaryArray payment_id_blob;
2015-05-27 12:08:46 +00:00
2015-07-30 15:22:07 +00:00
if (!Common::fromHex(req.payment_id, payment_id_blob)) {
2015-05-27 12:08:46 +00:00
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID, "Payment ID has invald format");
2014-04-02 16:00:17 +00:00
}
2014-04-29 16:26:45 +00:00
if (sizeof(expectedPaymentId) != payment_id_blob.size()) {
2015-05-27 12:08:46 +00:00
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID, "Payment ID has invalid size");
}
2015-07-30 15:22:07 +00:00
expectedPaymentId = *reinterpret_cast<const Crypto::Hash*>(payment_id_blob.data());
size_t transactionsCount = m_wallet.getTransactionCount();
for (size_t trantransactionNumber = 0; trantransactionNumber < transactionsCount; ++trantransactionNumber) {
2015-07-30 15:22:07 +00:00
WalletLegacyTransaction txInfo;
m_wallet.getTransaction(trantransactionNumber, txInfo);
2015-07-30 15:22:07 +00:00
if (txInfo.state != WalletLegacyTransactionState::Active || txInfo.blockHeight == WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT) {
continue;
2014-04-29 16:26:45 +00:00
}
if (txInfo.totalAmount < 0) continue;
std::vector<uint8_t> extraVec;
extraVec.reserve(txInfo.extra.size());
std::for_each(txInfo.extra.begin(), txInfo.extra.end(), [&extraVec](const char el) { extraVec.push_back(el); });
2014-04-29 16:26:45 +00:00
2015-07-30 15:22:07 +00:00
Crypto::Hash paymentId;
if (getPaymentIdFromTxExtra(extraVec, paymentId) && paymentId == expectedPaymentId) {
2014-04-29 16:26:45 +00:00
wallet_rpc::payment_details rpc_payment;
2015-05-27 12:08:46 +00:00
rpc_payment.tx_hash = Common::podToHex(txInfo.hash);
rpc_payment.amount = txInfo.totalAmount;
2015-05-27 12:08:46 +00:00
rpc_payment.block_height = txInfo.blockHeight;
rpc_payment.unlock_time = txInfo.unlockTime;
2014-04-29 16:26:45 +00:00
res.payments.push_back(rpc_payment);
}
}
return true;
}
2015-05-27 12:08:46 +00:00
bool wallet_rpc_server::on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res) {
res.transfers.clear();
size_t transactionsCount = m_wallet.getTransactionCount();
for (size_t trantransactionNumber = 0; trantransactionNumber < transactionsCount; ++trantransactionNumber) {
2015-07-30 15:22:07 +00:00
WalletLegacyTransaction txInfo;
m_wallet.getTransaction(trantransactionNumber, txInfo);
2015-07-30 15:22:07 +00:00
if (txInfo.state != WalletLegacyTransactionState::Active || txInfo.blockHeight == WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT) {
continue;
}
std::string address = "";
if (txInfo.totalAmount < 0) {
if (txInfo.transferCount > 0) {
2015-07-30 15:22:07 +00:00
WalletLegacyTransfer tr;
m_wallet.getTransfer(txInfo.firstTransferId, tr);
address = tr.address;
}
}
wallet_rpc::Transfer transfer;
transfer.time = txInfo.timestamp;
transfer.output = txInfo.totalAmount < 0;
2015-05-27 12:08:46 +00:00
transfer.transactionHash = Common::podToHex(txInfo.hash);
transfer.amount = std::abs(txInfo.totalAmount);
transfer.fee = txInfo.fee;
transfer.address = address;
transfer.blockIndex = txInfo.blockHeight;
transfer.unlockTime = txInfo.unlockTime;
transfer.paymentId = "";
std::vector<uint8_t> extraVec;
extraVec.reserve(txInfo.extra.size());
std::for_each(txInfo.extra.begin(), txInfo.extra.end(), [&extraVec](const char el) { extraVec.push_back(el); });
2015-07-30 15:22:07 +00:00
Crypto::Hash paymentId;
transfer.paymentId = (getPaymentIdFromTxExtra(extraVec, paymentId) && paymentId != NULL_HASH ? Common::podToHex(paymentId) : "");
res.transfers.push_back(transfer);
}
return true;
}
2015-05-27 12:08:46 +00:00
bool wallet_rpc_server::on_get_height(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res) {
res.height = m_node.getLastLocalBlockHeight();
return true;
}
2015-05-27 12:08:46 +00:00
bool wallet_rpc_server::on_reset(const wallet_rpc::COMMAND_RPC_RESET::request& req, wallet_rpc::COMMAND_RPC_RESET::response& res) {
m_wallet.reset();
return true;
}
2014-04-29 16:26:45 +00:00
}