command line and JSON-RPC first draft, requires Boost 1.35 or higher for boost::asio,

added SetBitcoinAddress and GetBitcoinAddress methods on CScript, 
critsect interlocks around mapAddressBook, 
added some random delays in tx broadcast to improve privacy, 
now compiles with MSVC 8.0

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@60 1a98c847-1fd6-4fd8-948a-caf3550aa51b
This commit is contained in:
s_nakamoto
2010-02-12 20:38:44 +00:00
parent fa9dbd6b62
commit 98500d70a8
23 changed files with 1202 additions and 348 deletions

468
ui.cpp
View File

@@ -21,7 +21,6 @@ DEFINE_EVENT_TYPE(wxEVT_REPLY3)
CMainFrame* pframeMain = NULL;
CMyTaskBarIcon* ptaskbaricon = NULL;
map<string, string> mapAddressBook;
bool fRandSendTest = false;
void RandSend();
extern int g_isPainting;
@@ -177,8 +176,11 @@ void CalledMessageBox(const string& message, const string& caption, int style, w
int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
{
if (mapArgs.count("-noui"))
if (fDaemon)
{
printf("wxMessageBox %s: %s\n", caption.c_str(), message.c_str());
return wxOK;
}
#ifdef __WXMSW__
return wxMessageBox(message, caption, style, parent, x, y);
@@ -413,7 +415,7 @@ void Shutdown(void* parg)
StopNode();
DBFlush(true);
CreateThread(ExitTimeout, NULL);
Sleep(10);
Sleep(50);
printf("Bitcoin exiting\n\n");
fExit = true;
exit(0);
@@ -697,19 +699,22 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
vector<unsigned char> vchPubKey;
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
{
string strAddress = PubKeyToAddress(vchPubKey);
if (mapAddressBook.count(strAddress))
CRITICAL_BLOCK(cs_mapAddressBook)
{
//strDescription += "Received payment to ";
//strDescription += "Received with address ";
strDescription += "From: unknown, To: ";
strDescription += strAddress;
/// The labeling feature is just too confusing, so I hid it
/// by putting it at the end where it runs off the screen.
/// It can still be seen by widening the column, or in the
/// details dialog.
if (!mapAddressBook[strAddress].empty())
strDescription += " (" + mapAddressBook[strAddress] + ")";
string strAddress = PubKeyToAddress(vchPubKey);
if (mapAddressBook.count(strAddress))
{
//strDescription += "Received payment to ";
//strDescription += "Received with address ";
strDescription += "From: unknown, To: ";
strDescription += strAddress;
/// The labeling feature is just too confusing, so I hid it
/// by putting it at the end where it runs off the screen.
/// It can still be seen by widening the column, or in the
/// details dialog.
if (!mapAddressBook[strAddress].empty())
strDescription += " (" + mapAddressBook[strAddress] + ")";
}
}
}
break;
@@ -776,8 +781,9 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
}
string strDescription = "To: ";
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strDescription += mapAddressBook[strAddress] + " ";
CRITICAL_BLOCK(cs_mapAddressBook)
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strDescription += mapAddressBook[strAddress] + " ";
strDescription += strAddress;
if (!mapValue["message"].empty())
{
@@ -1273,238 +1279,241 @@ void CMainFrame::OnListItemActivatedOrdersReceived(wxListEvent& event)
CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
{
string strHTML;
strHTML.reserve(4000);
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
int64 nTime = wtx.GetTxTime();
int64 nCredit = wtx.GetCredit();
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
strHTML += "<b>Status:</b> " + FormatTxStatus(wtx);
int nRequests = wtx.GetRequestCount();
if (nRequests != -1)
CRITICAL_BLOCK(cs_mapAddressBook)
{
if (nRequests == 0)
strHTML += ", has not been successfully broadcast yet";
else if (nRequests == 1)
strHTML += strprintf(", broadcast through %d node", nRequests);
else
strHTML += strprintf(", broadcast through %d nodes", nRequests);
}
strHTML += "<br>";
string strHTML;
strHTML.reserve(4000);
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";
int64 nTime = wtx.GetTxTime();
int64 nCredit = wtx.GetCredit();
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
//
// From
//
if (wtx.IsCoinBase())
{
strHTML += "<b>Source:</b> Generated<br>";
}
else if (!wtx.mapValue["from"].empty())
{
// Online transaction
if (!wtx.mapValue["from"].empty())
strHTML += "<b>From:</b> " + HtmlEscape(wtx.mapValue["from"]) + "<br>";
}
else
{
// Offline transaction
if (nNet > 0)
strHTML += "<b>Status:</b> " + FormatTxStatus(wtx);
int nRequests = wtx.GetRequestCount();
if (nRequests != -1)
{
// Credit
foreach(const CTxOut& txout, wtx.vout)
if (nRequests == 0)
strHTML += ", has not been successfully broadcast yet";
else if (nRequests == 1)
strHTML += strprintf(", broadcast through %d node", nRequests);
else
strHTML += strprintf(", broadcast through %d nodes", nRequests);
}
strHTML += "<br>";
strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";
//
// From
//
if (wtx.IsCoinBase())
{
strHTML += "<b>Source:</b> Generated<br>";
}
else if (!wtx.mapValue["from"].empty())
{
// Online transaction
if (!wtx.mapValue["from"].empty())
strHTML += "<b>From:</b> " + HtmlEscape(wtx.mapValue["from"]) + "<br>";
}
else
{
// Offline transaction
if (nNet > 0)
{
if (txout.IsMine())
// Credit
foreach(const CTxOut& txout, wtx.vout)
{
vector<unsigned char> vchPubKey;
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
if (txout.IsMine())
{
string strAddress = PubKeyToAddress(vchPubKey);
if (mapAddressBook.count(strAddress))
vector<unsigned char> vchPubKey;
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
{
strHTML += "<b>From:</b> unknown<br>";
string strAddress = PubKeyToAddress(vchPubKey);
if (mapAddressBook.count(strAddress))
{
strHTML += "<b>From:</b> unknown<br>";
strHTML += "<b>To:</b> ";
strHTML += HtmlEscape(strAddress);
if (!mapAddressBook[strAddress].empty())
strHTML += " (yours, label: " + mapAddressBook[strAddress] + ")";
else
strHTML += " (yours)";
strHTML += "<br>";
}
}
break;
}
}
}
}
//
// To
//
string strAddress;
if (!wtx.mapValue["to"].empty())
{
// Online transaction
strAddress = wtx.mapValue["to"];
strHTML += "<b>To:</b> ";
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strHTML += mapAddressBook[strAddress] + " ";
strHTML += HtmlEscape(strAddress) + "<br>";
}
//
// Amount
//
if (wtx.IsCoinBase() && nCredit == 0)
{
//
// Coinbase
//
int64 nUnmatured = 0;
foreach(const CTxOut& txout, wtx.vout)
nUnmatured += txout.GetCredit();
if (wtx.IsInMainChain())
strHTML += strprintf("<b>Credit:</b> (%s matures in %d more blocks)<br>", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
else
strHTML += "<b>Credit:</b> (not accepted)<br>";
}
else if (nNet > 0)
{
//
// Credit
//
strHTML += "<b>Credit:</b> " + FormatMoney(nNet) + "<br>";
}
else
{
bool fAllFromMe = true;
foreach(const CTxIn& txin, wtx.vin)
fAllFromMe = fAllFromMe && txin.IsMine();
bool fAllToMe = true;
foreach(const CTxOut& txout, wtx.vout)
fAllToMe = fAllToMe && txout.IsMine();
if (fAllFromMe)
{
//
// Debit
//
foreach(const CTxOut& txout, wtx.vout)
{
if (txout.IsMine())
continue;
if (wtx.mapValue["to"].empty())
{
// Offline transaction
uint160 hash160;
if (ExtractHash160(txout.scriptPubKey, hash160))
{
string strAddress = Hash160ToAddress(hash160);
strHTML += "<b>To:</b> ";
strHTML += HtmlEscape(strAddress);
if (!mapAddressBook[strAddress].empty())
strHTML += " (yours, label: " + mapAddressBook[strAddress] + ")";
else
strHTML += " (yours)";
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strHTML += mapAddressBook[strAddress] + " ";
strHTML += strAddress;
strHTML += "<br>";
}
}
break;
strHTML += "<b>Debit:</b> " + FormatMoney(-txout.nValue) + "<br>";
}
}
}
}
//
// To
//
string strAddress;
if (!wtx.mapValue["to"].empty())
{
// Online transaction
strAddress = wtx.mapValue["to"];
strHTML += "<b>To:</b> ";
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strHTML += mapAddressBook[strAddress] + " ";
strHTML += HtmlEscape(strAddress) + "<br>";
}
//
// Amount
//
if (wtx.IsCoinBase() && nCredit == 0)
{
//
// Coinbase
//
int64 nUnmatured = 0;
foreach(const CTxOut& txout, wtx.vout)
nUnmatured += txout.GetCredit();
if (wtx.IsInMainChain())
strHTML += strprintf("<b>Credit:</b> (%s matures in %d more blocks)<br>", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
else
strHTML += "<b>Credit:</b> (not accepted)<br>";
}
else if (nNet > 0)
{
//
// Credit
//
strHTML += "<b>Credit:</b> " + FormatMoney(nNet) + "<br>";
}
else
{
bool fAllFromMe = true;
foreach(const CTxIn& txin, wtx.vin)
fAllFromMe = fAllFromMe && txin.IsMine();
bool fAllToMe = true;
foreach(const CTxOut& txout, wtx.vout)
fAllToMe = fAllToMe && txout.IsMine();
if (fAllFromMe)
{
//
// Debit
//
foreach(const CTxOut& txout, wtx.vout)
{
if (txout.IsMine())
continue;
if (wtx.mapValue["to"].empty())
if (fAllToMe)
{
// Offline transaction
uint160 hash160;
if (ExtractHash160(txout.scriptPubKey, hash160))
{
string strAddress = Hash160ToAddress(hash160);
strHTML += "<b>To:</b> ";
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strHTML += mapAddressBook[strAddress] + " ";
strHTML += strAddress;
strHTML += "<br>";
}
// Payment to self
/// issue: can't tell which is the payment and which is the change anymore
//int64 nValue = wtx.vout[0].nValue;
//strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";
//strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";
}
strHTML += "<b>Debit:</b> " + FormatMoney(-txout.nValue) + "<br>";
int64 nTxFee = nDebit - wtx.GetValueOut();
if (nTxFee > 0)
strHTML += "<b>Transaction fee:</b> " + FormatMoney(-nTxFee) + "<br>";
}
if (fAllToMe)
else
{
// Payment to self
/// issue: can't tell which is the payment and which is the change anymore
//int64 nValue = wtx.vout[0].nValue;
//strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";
//strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";
//
// Mixed debit transaction
//
foreach(const CTxIn& txin, wtx.vin)
if (txin.IsMine())
strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
foreach(const CTxOut& txout, wtx.vout)
if (txout.IsMine())
strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
}
int64 nTxFee = nDebit - wtx.GetValueOut();
if (nTxFee > 0)
strHTML += "<b>Transaction fee:</b> " + FormatMoney(-nTxFee) + "<br>";
}
else
strHTML += "<b>Net amount:</b> " + FormatMoney(nNet, true) + "<br>";
//
// Message
//
if (!wtx.mapValue["message"].empty())
strHTML += "<br><b>Message:</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
if (wtx.IsCoinBase())
strHTML += "<br>Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.<br>";
//
// Debug view
//
if (fDebug)
{
//
// Mixed debit transaction
//
strHTML += "<hr><br>debug print<br><br>";
foreach(const CTxIn& txin, wtx.vin)
if (txin.IsMine())
strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
foreach(const CTxOut& txout, wtx.vout)
if (txout.IsMine())
strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
}
}
strHTML += "<b>Net amount:</b> " + FormatMoney(nNet, true) + "<br>";
//
// Message
//
if (!wtx.mapValue["message"].empty())
strHTML += "<br><b>Message:</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
if (wtx.IsCoinBase())
strHTML += "<br>Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.<br>";
//
// Debug view
//
if (fDebug)
{
strHTML += "<hr><br>debug print<br><br>";
foreach(const CTxIn& txin, wtx.vin)
if (txin.IsMine())
strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
foreach(const CTxOut& txout, wtx.vout)
if (txout.IsMine())
strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
strHTML += "<b>Inputs:</b><br>";
CRITICAL_BLOCK(cs_mapWallet)
{
foreach(const CTxIn& txin, wtx.vin)
strHTML += "<b>Inputs:</b><br>";
CRITICAL_BLOCK(cs_mapWallet)
{
COutPoint prevout = txin.prevout;
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
if (mi != mapWallet.end())
foreach(const CTxIn& txin, wtx.vin)
{
const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size())
COutPoint prevout = txin.prevout;
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
if (mi != mapWallet.end())
{
strHTML += HtmlEscape(prev.ToString(), true);
strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";
strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size())
{
strHTML += HtmlEscape(prev.ToString(), true);
strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";
strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
}
}
}
}
strHTML += "<br><hr><br><b>Transaction:</b><br>";
strHTML += HtmlEscape(wtx.ToString(), true);
}
strHTML += "<br><hr><br><b>Transaction:</b><br>";
strHTML += HtmlEscape(wtx.ToString(), true);
strHTML += "</font></html>";
string(strHTML.begin(), strHTML.end()).swap(strHTML);
m_htmlWin->SetPage(strHTML);
m_buttonOK->SetFocus();
}
strHTML += "</font></html>";
string(strHTML.begin(), strHTML.end()).swap(strHTML);
m_htmlWin->SetPage(strHTML);
m_buttonOK->SetFocus();
}
void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
@@ -1686,9 +1695,10 @@ CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
#if !wxUSE_UNICODE
// Workaround until upgrade to wxWidgets supporting UTF-8
// Hack to change the (c) character from UTF-8 back to ANSI
wxString str = m_staticTextMain->GetLabel();
if (str.Find('<EFBFBD>') != wxNOT_FOUND)
str.Remove(str.Find('<EFBFBD>'), 1);
if (str.Find('\xC2') != wxNOT_FOUND)
str.Remove(str.Find('\xC2'), 1);
m_staticTextMain->SetLabel(str);
#endif
#ifndef __WXMSW__
@@ -1843,10 +1853,11 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
if (!SendMoney(scriptPubKey, nValue, wtx))
return;
wxMessageBox("Payment sent ", "Sending...");
string strError = SendMoney(scriptPubKey, nValue, wtx);
if (strError != "")
wxMessageBox(strError + " ", "Sending...");
else
wxMessageBox("Payment sent ", "Sending...");
}
else
{
@@ -1869,8 +1880,9 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
return;
}
if (!mapAddressBook.count(strAddress))
SetAddressBookName(strAddress, "");
CRITICAL_BLOCK(cs_mapAddressBook)
if (!mapAddressBook.count(strAddress))
SetAddressBookName(strAddress, "");
EndModal(true);
}
@@ -2227,6 +2239,7 @@ CYourAddressDialog::CYourAddressDialog(wxWindow* parent, const string& strInitSe
// Fill listctrl with address book data
CRITICAL_BLOCK(cs_mapKeys)
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
@@ -2366,6 +2379,7 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
// Fill listctrl with address book data
CRITICAL_BLOCK(cs_mapKeys)
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
@@ -3515,6 +3529,12 @@ bool CMyApp::OnInit2()
//
// Parameters
//
if (argc > 1 && argv[1][0] != '-' && argv[1][0] != '/')
{
int ret = CommandLineRPC(argc, argv);
exit(ret);
}
ParseParameters(argc, argv);
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
@@ -3557,6 +3577,13 @@ bool CMyApp::OnInit2()
if (mapArgs.count("-printtodebugger"))
fPrintToDebugger = true;
if (mapArgs.count("-daemon") || mapArgs.count("-d"))
{
fDaemon = true;
/// todo: need to fork
/// should it fork after the bind/single instance stuff?
}
if (!fDebug && !pszSetDataDir[0])
ShrinkDebugFile();
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
@@ -3730,7 +3757,7 @@ bool CMyApp::OnInit2()
//
// Create the main frame window
//
if (!mapArgs.count("-noui"))
if (!fDaemon)
{
pframeMain = new CMainFrame(NULL);
if (mapArgs.count("-min"))
@@ -3752,6 +3779,9 @@ bool CMyApp::OnInit2()
if (!CreateThread(StartNode, NULL))
wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
if (mapArgs.count("-server") || fDaemon)
CreateThread(ThreadRPCServer, NULL);
if (fFirstRun)
SetStartOnSystemStartup(true);