forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
238a72b
commit d39d440
Showing
10 changed files
with
291 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
#include <mainchainrpc.h> | ||
|
||
#include <chainparamsbase.h> | ||
#include <util.h> | ||
#include <utilstrencodings.h> | ||
#include <rpc/protocol.h> | ||
|
||
#include <support/events.h> | ||
|
||
#include <rpc/client.h> | ||
|
||
#include <event2/buffer.h> | ||
#include <event2/keyvalq_struct.h> | ||
|
||
/** Reply structure for request_done to fill in */ | ||
struct HTTPReply | ||
{ | ||
HTTPReply(): status(0), error(-1) {} | ||
|
||
int status; | ||
int error; | ||
std::string body; | ||
}; | ||
|
||
const char *http_errorstring(int code) | ||
{ | ||
switch(code) { | ||
#if LIBEVENT_VERSION_NUMBER >= 0x02010300 | ||
case EVREQ_HTTP_TIMEOUT: | ||
return "timeout reached"; | ||
case EVREQ_HTTP_EOF: | ||
return "EOF reached"; | ||
case EVREQ_HTTP_INVALID_HEADER: | ||
return "error while reading header, or invalid header"; | ||
case EVREQ_HTTP_BUFFER_ERROR: | ||
return "error encountered while reading or writing"; | ||
case EVREQ_HTTP_REQUEST_CANCEL: | ||
return "request was canceled"; | ||
case EVREQ_HTTP_DATA_TOO_LONG: | ||
return "response body is larger than allowed"; | ||
#endif | ||
default: | ||
return "unknown"; | ||
} | ||
} | ||
|
||
static void http_request_done(struct evhttp_request *req, void *ctx) | ||
{ | ||
HTTPReply *reply = static_cast<HTTPReply*>(ctx); | ||
|
||
if (req == NULL) { | ||
/* If req is NULL, it means an error occurred while connecting: the | ||
* error code will have been passed to http_error_cb. | ||
*/ | ||
reply->status = 0; | ||
return; | ||
} | ||
|
||
reply->status = evhttp_request_get_response_code(req); | ||
|
||
struct evbuffer *buf = evhttp_request_get_input_buffer(req); | ||
if (buf) | ||
{ | ||
size_t size = evbuffer_get_length(buf); | ||
const char *data = (const char*)evbuffer_pullup(buf, size); | ||
if (data) | ||
reply->body = std::string(data, size); | ||
evbuffer_drain(buf, size); | ||
} | ||
} | ||
|
||
#if LIBEVENT_VERSION_NUMBER >= 0x02010300 | ||
static void http_error_cb(enum evhttp_request_error err, void *ctx) | ||
{ | ||
HTTPReply *reply = static_cast<HTTPReply*>(ctx); | ||
reply->error = err; | ||
} | ||
#endif | ||
|
||
UniValue CallMainChainRPC(const std::string& strMethod, const UniValue& params) | ||
{ | ||
std::string host = gArgs.GetArg("-mainchainrpchost", DEFAULT_RPCCONNECT); | ||
int port = gArgs.GetArg("-mainchainrpcport", BaseParams().MainchainRPCPort()); | ||
|
||
// Obtain event base | ||
raii_event_base base = obtain_event_base(); | ||
|
||
// Synchronously look up hostname | ||
raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port); | ||
evhttp_connection_set_timeout(evcon.get(), gArgs.GetArg("-mainchainrpctimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); | ||
|
||
HTTPReply response; | ||
raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response); | ||
if (req == NULL) | ||
throw std::runtime_error("create http request failed"); | ||
#if LIBEVENT_VERSION_NUMBER >= 0x02010300 | ||
evhttp_request_set_error_cb(req.get(), http_error_cb); | ||
#endif | ||
|
||
// Get credentials | ||
std::string strRPCUserColonPass; | ||
if (gArgs.GetArg("-mainchainrpcpassword", "") == "") { | ||
// Try fall back to cookie-based authentication if no password is provided | ||
if (!GetMainchainAuthCookie(&strRPCUserColonPass)) { | ||
throw std::runtime_error(strprintf( | ||
_("Could not locate mainchain RPC credentials. No authentication cookie could be found, and no mainchainrpcpassword is set in the configuration file (%s)"), | ||
GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str())); | ||
} | ||
} else { | ||
strRPCUserColonPass = gArgs.GetArg("-mainchainrpcuser", "") + ":" + gArgs.GetArg("-mainchainrpcpassword", ""); | ||
} | ||
|
||
struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get()); | ||
assert(output_headers); | ||
evhttp_add_header(output_headers, "Host", host.c_str()); | ||
evhttp_add_header(output_headers, "Connection", "close"); | ||
evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str()); | ||
|
||
// Attach request data | ||
std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n"; | ||
struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get()); | ||
assert(output_buffer); | ||
evbuffer_add(output_buffer, strRequest.data(), strRequest.size()); | ||
|
||
int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/"); | ||
req.release(); // ownership moved to evcon in above call | ||
if (r != 0) { | ||
throw CConnectionFailed("send http request failed"); | ||
} | ||
|
||
event_base_dispatch(base.get()); | ||
|
||
if (response.status == 0) | ||
throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error)); | ||
else if (response.status == HTTP_UNAUTHORIZED) | ||
throw std::runtime_error("incorrect mainchainrpcuser or mainchainrpcpassword (authorization failed)"); | ||
else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) | ||
throw std::runtime_error(strprintf("server returned HTTP error %d", response.status)); | ||
else if (response.body.empty()) | ||
throw std::runtime_error("no response from server"); | ||
|
||
// Parse reply | ||
UniValue valReply(UniValue::VSTR); | ||
if (!valReply.read(response.body)) | ||
throw std::runtime_error("couldn't parse reply from server"); | ||
const UniValue& reply = valReply.get_obj(); | ||
if (reply.empty()) | ||
throw std::runtime_error("expected reply to have result, error and id properties"); | ||
|
||
return reply; | ||
} | ||
|
||
bool IsConfirmedBitcoinBlock(const uint256& hash, const int nMinConfirmationDepth, const int nbTxs) | ||
{ | ||
try { | ||
UniValue params(UniValue::VARR); | ||
params.push_back(hash.GetHex()); | ||
UniValue reply = CallMainChainRPC("getblockheader", params); | ||
if (!find_value(reply, "error").isNull()) | ||
return false; | ||
UniValue result = find_value(reply, "result"); | ||
if (!result.isObject()) | ||
return false; | ||
|
||
UniValue confirmations = find_value(result.get_obj(), "confirmations"); | ||
if (!confirmations.isNum() || confirmations.get_int64() < nMinConfirmationDepth) { | ||
return false; | ||
} | ||
|
||
// Only perform extra test if nbTxs has been provided (non-zero). | ||
if (nbTxs != 0) { | ||
UniValue nTx = find_value(result.get_obj(), "nTx"); | ||
if (!nTx.isNum() || nTx.get_int64() != nbTxs) { | ||
LogPrintf("ERROR: Invalid number of transactions in merkle block for %s\n", | ||
hash.GetHex()); | ||
return false; | ||
} | ||
} | ||
} catch (CConnectionFailed& e) { | ||
LogPrintf("ERROR: Lost connection to bitcoind RPC, you will want to restart after fixing this!\n"); | ||
return false; | ||
} catch (...) { | ||
LogPrintf("ERROR: Failure connecting to bitcoind RPC, you will want to restart after fixing this!\n"); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright (c) 2009-2010 Satoshi Nakamoto | ||
// Copyright (c) 2009-2014 The Bitcoin developers | ||
// Distributed under the MIT/X11 software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#ifndef BITCOIN_MAINCHAINRPC_H | ||
#define BITCOIN_MAINCHAINRPC_H | ||
|
||
#include <rpc/client.h> | ||
#include <rpc/protocol.h> | ||
#include <uint256.h> | ||
|
||
#include <string> | ||
#include <stdexcept> | ||
|
||
#include <univalue.h> | ||
|
||
static const bool DEFAULT_NAMED=false; | ||
static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; | ||
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; | ||
|
||
// | ||
// Exception thrown on connection error. This error is used to determine | ||
// when to wait if -rpcwait is given. | ||
// | ||
class CConnectionFailed : public std::runtime_error | ||
{ | ||
public: | ||
|
||
explicit inline CConnectionFailed(const std::string& msg) : | ||
std::runtime_error(msg) | ||
{} | ||
|
||
}; | ||
|
||
UniValue CallMainChainRPC(const std::string& strMethod, const UniValue& params); | ||
|
||
// Verify if the block with given hash has at least the specified minimum number | ||
// of confirmations. | ||
// For validating merkle blocks, you can provide the nbTxs parameter to verify if | ||
// it equals the number of transactions in the block. | ||
bool IsConfirmedBitcoinBlock(const uint256& hash, const int nMinConfirmationDepth, const int nbTxs); | ||
|
||
#endif // BITCOIN_MAINCHAINRPC_H | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters