Skip to content

Commit

Permalink
Added monitortx and monitorblock
Browse files Browse the repository at this point in the history
  • Loading branch information
stcupp committed Jan 23, 2012
1 parent 1240a1b commit cd2b9c1
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 14 deletions.
2 changes: 1 addition & 1 deletion contrib/gitian-descriptors/gitian-win32.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ packages:
- "wine"
reference_datetime: "2011-01-30 00:00:00"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
- "url": "https://github.com/stcupp/bitcoin.git"
"dir": "bitcoin"
files:
- "qt-win32-4.7.4-gitian.zip"
Expand Down
2 changes: 1 addition & 1 deletion contrib/gitian-descriptors/gitian.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ packages:
- "libqrencode-dev"
reference_datetime: "2011-01-30 00:00:00"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
- "url": "https://github.com/stcupp/bitcoin.git"
"dir": "bitcoin"
files:
- "miniupnpc-1.6.tar.gz"
Expand Down
197 changes: 187 additions & 10 deletions src/bitcoinrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <boost/iostreams/stream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/xpressive/xpressive_dynamic.hpp>
#ifdef USE_SSL
#include <boost/asio/ssl.hpp>
#include <boost/filesystem.hpp>
Expand All @@ -35,6 +36,7 @@ using namespace boost::asio;
using namespace json_spirit;

void ThreadRPCServer2(void* parg);
void ThreadHTTPPOST2(void* parg);
typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable;

Expand Down Expand Up @@ -143,10 +145,51 @@ string AccountFromValue(const Value& value)
return strAccount;
}

Object txToJSON(const CTransaction& tx)
{
Object result;
result.push_back(Pair("hash", tx.GetHash().GetHex()));
result.push_back(Pair("ver", tx.nVersion));
result.push_back(Pair("vin_sz", tx.vin.size()));
result.push_back(Pair("vout_sz", tx.vout.size()));
result.push_back(Pair("lock_time", (boost::int64_t)tx.nLockTime));
Array txinputs;
Array txoutputs;

BOOST_FOREACH (const CTxIn&txin, tx.vin)
{
Object txar;
txar.push_back(Pair("prev_out",txin.prevout.hash.ToString()));
txar.push_back(Pair("n",(boost::int64_t)txin.prevout.n));
if(txin.prevout.IsNull())
{
txar.push_back(Pair("coinbase",HexStr(txin.scriptSig).c_str()));
} else {
txar.push_back(Pair("scriptSig",txin.scriptSig.ToString()));
}
txinputs.push_back(txar);
}

BOOST_FOREACH (const CTxOut&txout, tx.vout)
{
Object txar;
txar.push_back(Pair("value",(ValueFromAmount(txout.nValue))));
txar.push_back(Pair("scriptPubKey",txout.scriptPubKey.ToString()));
txoutputs.push_back(txar);
}
result.push_back(Pair("in", txinputs));
result.push_back(Pair("out", txoutputs));
return result;
}

Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
{
Object result;
result.push_back(Pair("hash", block.GetHash().GetHex()));
if (blockindex->pprev)
result.push_back(Pair("hashprevious", blockindex->pprev->GetBlockHash().GetHex()));
if (blockindex->pnext)
result.push_back(Pair("hashnext", blockindex->pnext->GetBlockHash().GetHex()));
result.push_back(Pair("blockcount", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
Expand All @@ -155,13 +198,8 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
Array txhashes;
BOOST_FOREACH (const CTransaction&tx, block.vtx)
txhashes.push_back(tx.GetHash().GetHex());
txhashes.push_back(txToJSON(tx));
result.push_back(Pair("tx", txhashes));

if (blockindex->pprev)
result.push_back(Pair("hashprevious", blockindex->pprev->GetBlockHash().GetHex()));
if (blockindex->pnext)
result.push_back(Pair("hashnext", blockindex->pnext->GetBlockHash().GetHex()));
return result;
}

Expand Down Expand Up @@ -2093,12 +2131,12 @@ set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllo
// and to be compatible with other JSON-RPC implementations.
//

string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
string HTTPPost(const string& host, const string& path, const string& strMsg, const map<string,string>& mapRequestHeaders)
{
ostringstream s;
s << "POST / HTTP/1.1\r\n"
s << "POST " << path << " HTTP/1.1\r\n"
<< "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
<< "Host: 127.0.0.1\r\n"
<< "Host: " << host << "\r\n"
<< "Content-Type: application/json\r\n"
<< "Content-Length: " << strMsg.size() << "\r\n"
<< "Connection: close\r\n"
Expand Down Expand Up @@ -2343,6 +2381,145 @@ class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
};
#endif

class CPOSTRequest
{
public:
CPOSTRequest(const string &_url, const string& _body) : url(_url), body(_body)
{
}

virtual bool POST()
{
using namespace boost::xpressive;
// This regex is wrong for IPv6 urls; see http://www.ietf.org/rfc/rfc2732.txt
// (they're weird; e.g "http://[::FFFF:129.144.52.38]:80/index.html" )
// I can live with non-raw-IPv6 urls for now...
static sregex url_regex = sregex::compile("^(http|https)://([^:/]+)(:[0-9]{1,5})?(.*)$");

boost::xpressive::smatch urlparts;
if (!regex_match(url, urlparts, url_regex))
{
printf("URL PARSING FAILED: %s\n", url.c_str());
return true;
}
string protocol = urlparts[1];
string host = urlparts[2];
string s_port = urlparts[3]; // Note: includes colon, e.g. ":8080"
bool fSSL = (protocol == "https" ? true : false);
int port = (fSSL ? 443 : 80);
if (s_port.size() > 1) { port = atoi(s_port.c_str()+1); }
string path = urlparts[4];
map<string, string> headers;

#ifdef USE_SSL
io_service io_service;
ssl::context context(io_service, ssl::context::sslv23);
context.set_options(ssl::context::no_sslv2);
SSLStream sslStream(io_service, context);
SSLIOStreamDevice d(sslStream, fSSL);
boost::iostreams::stream<SSLIOStreamDevice> stream(d);
if (!d.connect(host, boost::lexical_cast<string>(port)))
{
printf("POST: Couldn't connect to %s:%d", host.c_str(), port);
return false;
}
#else
if (fSSL)
{
printf("Cannot POST to SSL server, bitcoin compiled without full openssl libraries.");
return false;
}
ip::tcp::iostream stream(host, boost::lexical_cast<string>(port));
#endif

stream << HTTPPost(host, path, body, headers) << std::flush;
map<string, string> mapResponseHeaders;
string strReply;
int status = ReadHTTP(stream, mapResponseHeaders, strReply);
//printf("HTTP response %d: %s\n", status, strReply.c_str());
return (status < 300);
}

protected:
string url;
string body;
};

static vector<boost::shared_ptr<CPOSTRequest> > vPOSTQueue;
static CCriticalSection cs_vPOSTQueue;

void ThreadHTTPPOST(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadHTTPPOST(parg));
try
{
vnThreadsRunning[8]++;
ThreadHTTPPOST2(parg);
vnThreadsRunning[8]--;
}
catch (std::exception& e) {
vnThreadsRunning[8]--;
PrintException(&e, "ThreadHTTPPOST()");
} catch (...) {
vnThreadsRunning[8]--;
PrintException(NULL, "ThreadHTTPPOST()");
}
printf("ThreadHTTPPOST exiting\n");
}

void ThreadHTTPPOST2(void* parg)
{
printf("ThreadHTTPPOST started\n");

loop
{
if (fShutdown)
return;

vector<boost::shared_ptr<CPOSTRequest> > work;
CRITICAL_BLOCK(cs_vPOSTQueue)
{
work = vPOSTQueue;
vPOSTQueue.clear();
}
BOOST_FOREACH (boost::shared_ptr<CPOSTRequest> r, work)
r->POST();

if (vPOSTQueue.empty())
Sleep(100); // 100ms (1/10 second)
}
}

void monitorBlock(const CBlock& block, const CBlockIndex* pblockindex)
{
Array params; // JSON-RPC requests are always "params" : [ ... ]
params.push_back(blockToJSON(block, pblockindex));

string postBody = JSONRPCRequest("monitorblock", params, Value());

CRITICAL_BLOCK(cs_vPOSTQueue)
{
boost::shared_ptr<CPOSTRequest> postRequest(new CPOSTRequest(mapArgs["-monitorblockurl"], postBody));
vPOSTQueue.push_back(postRequest);
}
}

void monitorTx(const CTransaction& tx)
{
Array params; // JSON-RPC requests are always "params" : [ ... ]
params.push_back(txToJSON(tx));
if (params.empty())
return; // Not our transaction

string postBody = JSONRPCRequest("monitortx", params, Value());

CRITICAL_BLOCK(cs_vPOSTQueue)
{
boost::shared_ptr<CPOSTRequest> postRequest(new CPOSTRequest(mapArgs["-monitortxurl"], postBody));
vPOSTQueue.push_back(postRequest);
}
}

void ThreadRPCServer(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
Expand Down Expand Up @@ -2585,7 +2762,7 @@ Object CallRPC(const string& strMethod, const Array& params)

// Send request
string strRequest = JSONRPCRequest(strMethod, params, 1);
string strPost = HTTPPost(strRequest, mapRequestHeaders);
string strPost = HTTPPost("127.0.0.1", "/", strRequest, mapRequestHeaders);
stream << strPost << std::flush;

// Receive reply
Expand Down
1 change: 1 addition & 0 deletions src/bitcoinrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.

void ThreadHTTPPOST(void* parg);
void ThreadRPCServer(void* parg);
int CommandLineRPC(int argc, char *argv[]);
3 changes: 3 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,10 @@ bool AppInit2(int argc, char* argv[])
wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");

if (fServer)
{
CreateThread(ThreadRPCServer, NULL);
CreateThread(ThreadHTTPPOST, NULL);
}

#ifdef QT_GUI
if(GetStartOnSystemStartup())
Expand Down
11 changes: 10 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,11 @@ bool CBlock::AcceptBlock()
BOOST_FOREACH(CNode* pnode, vNodes)
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 140700))
pnode->PushInventory(CInv(MSG_BLOCK, hash));

if(GetBoolArg("-monitorblocks") && mapArgs.count("-monitorblockurl") && hashBestChain == hash)
{
extern void monitorBlock(const CBlock&, const CBlockIndex*);
monitorBlock(*this, pindexBest);
}
return true;
}

Expand Down Expand Up @@ -2370,6 +2374,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool fMissingInputs = false;
if (tx.AcceptToMemoryPool(true, &fMissingInputs))
{
if(GetBoolArg("-monitortx") && mapArgs.count("-monitortxurl"))
{
extern void monitorTx(const CTransaction&);
monitorTx(tx);
}
SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
Expand Down
3 changes: 2 additions & 1 deletion src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1727,7 +1727,7 @@ bool StopNode()
nTransactionsUpdated++;
int64 nStart = GetTime();
while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0
|| (fHaveUPnP && vnThreadsRunning[5] > 0) || vnThreadsRunning[6] > 0 || vnThreadsRunning[7] > 0
|| (fHaveUPnP && vnThreadsRunning[5] > 0) || vnThreadsRunning[6] > 0 || vnThreadsRunning[7] > 0 || vnThreadsRunning[8] > 0
)
{
if (GetTime() - nStart > 20)
Expand All @@ -1742,6 +1742,7 @@ bool StopNode()
if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n");
if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n");
if (vnThreadsRunning[7] > 0) printf("ThreadOpenAddedConnections still running\n");
if (vnThreadsRunning[8] > 0) printf("ThreadHTTPPOST still running\n");
while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
Sleep(20);
Sleep(50);
Expand Down

0 comments on commit cd2b9c1

Please sign in to comment.