aboutsummaryrefslogtreecommitdiff
path: root/main.cpp
diff options
context:
space:
mode:
authors_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>2010-02-12 20:38:44 +0000
committers_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>2010-02-12 20:38:44 +0000
commit98500d70a8cf25af4bab80526fd128ccdc36ceeb (patch)
tree61624e0903150505dc09977ae9ff1bc9ab40ee2b /main.cpp
parentfa9dbd6b62ab161c29c9b8cf97b9c8da8ef4346e (diff)
downloadbitcoin-98500d70a8cf25af4bab80526fd128ccdc36ceeb.tar.xz
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
Diffstat (limited to 'main.cpp')
-rw-r--r--main.cpp151
1 files changed, 105 insertions, 46 deletions
diff --git a/main.cpp b/main.cpp
index 53acf8a753..90d239fa0f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -26,6 +26,7 @@ CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL;
+int64 nTimeBestReceived = 0;
map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
@@ -45,6 +46,9 @@ CKey keyUser;
map<uint256, int> mapRequestCount;
CCriticalSection cs_mapRequestCount;
+map<string, string> mapAddressBook;
+CCriticalSection cs_mapAddressBook;
+
// Settings
int fGenerateBitcoins = false;
int64 nTransactionFee = 0;
@@ -573,7 +577,7 @@ bool CTransaction::RemoveFromMemoryPool()
-int CMerkleTx::GetDepthInMainChain() const
+int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const
{
if (hashBlock == 0 || nIndex == -1)
return 0;
@@ -594,6 +598,7 @@ int CMerkleTx::GetDepthInMainChain() const
fMerkleVerified = true;
}
+ nHeightRet = pindex->nHeight;
return pindexBest->nHeight - pindex->nHeight + 1;
}
@@ -708,15 +713,20 @@ void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
}
}
-void RelayWalletTransactions()
+void ResendWalletTransactions()
{
- static int64 nLastTime;
- if (GetTime() - nLastTime < 10 * 60)
+ // Do this infrequently and randomly to avoid giving away
+ // that these are our transactions.
+ static int64 nNextTime;
+ if (GetTime() < nNextTime)
+ return;
+ bool fFirst = (nNextTime == 0);
+ nNextTime = GetTime() + GetRand(120 * 60);
+ if (fFirst)
return;
- nLastTime = GetTime();
// Rebroadcast any of our txes that aren't in a block yet
- printf("RelayWalletTransactions()\n");
+ printf("ResendWalletTransactions()\n");
CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
{
@@ -725,7 +735,10 @@ void RelayWalletTransactions()
foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
CWalletTx& wtx = item.second;
- mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
+ // Don't rebroadcast until it's had plenty of time that
+ // it should have gotten in already by now.
+ if (nTimeBestReceived - wtx.nTimeReceived > 60 * 60)
+ mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
}
foreach(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
@@ -1219,10 +1232,11 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
}
}
- // New best link
+ // New best block
hashBestChain = hash;
pindexBest = pindexNew;
nBestHeight = pindexBest->nHeight;
+ nTimeBestReceived = GetTime();
nTransactionsUpdated++;
printf("AddToBlockIndex: new best=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);
}
@@ -1232,9 +1246,6 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
if (pindexNew == pindexBest)
{
- // Relay wallet transactions that haven't gotten in yet
- RelayWalletTransactions();
-
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
CRITICAL_BLOCK(cs_mapWallet)
@@ -2248,7 +2259,7 @@ bool SendMessages(CNode* pto)
return true;
// Keep-alive ping
- if (pto->nLastSend && GetTime() - pto->nLastSend > 12 * 60 && pto->vSend.empty())
+ if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
pto->PushMessage("ping");
// Address refresh broadcast
@@ -2270,60 +2281,81 @@ bool SendMessages(CNode* pto)
}
}
+ // Delay tx inv messages to protect privacy,
+ // trickle them out to a few nodes at a time.
+ bool fSendTxInv = false;
+ if (GetTimeMillis() - pto->nLastSentTxInv > 1800 + GetRand(200))
+ {
+ pto->nLastSentTxInv = GetTimeMillis();
+ fSendTxInv = true;
+ }
+
+ // Resend wallet transactions that haven't gotten in a block yet
+ ResendWalletTransactions();
+
//
// Message: addr
//
- vector<CAddress> vAddrToSend;
- vAddrToSend.reserve(pto->vAddrToSend.size());
+ vector<CAddress> vAddr;
+ vAddr.reserve(pto->vAddrToSend.size());
foreach(const CAddress& addr, pto->vAddrToSend)
{
// returns true if wasn't already contained in the set
if (pto->setAddrKnown.insert(addr).second)
{
- vAddrToSend.push_back(addr);
- if (vAddrToSend.size() >= 1000)
+ vAddr.push_back(addr);
+ if (vAddr.size() >= 1000)
{
- pto->PushMessage("addr", vAddrToSend);
- vAddrToSend.clear();
+ pto->PushMessage("addr", vAddr);
+ vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
- if (!vAddrToSend.empty())
- pto->PushMessage("addr", vAddrToSend);
+ if (!vAddr.empty())
+ pto->PushMessage("addr", vAddr);
//
// Message: inventory
//
- vector<CInv> vInventoryToSend;
+ vector<CInv> vInv;
+ vector<CInv> vInvWait;
CRITICAL_BLOCK(pto->cs_inventory)
{
- vInventoryToSend.reserve(pto->vInventoryToSend.size());
+ vInv.reserve(pto->vInventoryToSend.size());
+ vInvWait.reserve(pto->vInventoryToSend.size());
foreach(const CInv& inv, pto->vInventoryToSend)
{
+ // delay txes
+ if (!fSendTxInv && inv.type == MSG_TX)
+ {
+ vInvWait.push_back(inv);
+ continue;
+ }
+
// returns true if wasn't already contained in the set
if (pto->setInventoryKnown.insert(inv).second)
{
- vInventoryToSend.push_back(inv);
- if (vInventoryToSend.size() >= 1000)
+ vInv.push_back(inv);
+ if (vInv.size() >= 1000)
{
- pto->PushMessage("inv", vInventoryToSend);
- vInventoryToSend.clear();
+ pto->PushMessage("inv", vInv);
+ vInv.clear();
}
}
}
- pto->vInventoryToSend.clear();
+ pto->vInventoryToSend = vInvWait;
}
- if (!vInventoryToSend.empty())
- pto->PushMessage("inv", vInventoryToSend);
+ if (!vInv.empty())
+ pto->PushMessage("inv", vInv);
//
// Message: getdata
//
- vector<CInv> vAskFor;
+ vector<CInv> vGetData;
int64 nNow = GetTime() * 1000000;
CTxDB txdb("r");
while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
@@ -2332,17 +2364,17 @@ bool SendMessages(CNode* pto)
if (!AlreadyHave(txdb, inv))
{
printf("sending getdata: %s\n", inv.ToString().c_str());
- vAskFor.push_back(inv);
- if (vAskFor.size() >= 1000)
+ vGetData.push_back(inv);
+ if (vGetData.size() >= 1000)
{
- pto->PushMessage("getdata", vAskFor);
- vAskFor.clear();
+ pto->PushMessage("getdata", vGetData);
+ vGetData.clear();
}
}
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
- if (!vAskFor.empty())
- pto->PushMessage("getdata", vAskFor);
+ if (!vGetData.empty())
+ pto->PushMessage("getdata", vGetData);
}
return true;
@@ -2405,7 +2437,6 @@ void ThreadBitcoinMiner(void* parg)
vnThreadsRunning[3]--;
PrintException(NULL, "ThreadBitcoinMiner()");
}
-
printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
}
@@ -2842,6 +2873,13 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CK
// Fill a vout back to self with any change
if (nValueIn > nTotalValue)
{
+ // Note: We use a new key here to keep it from being obvious which side is the change.
+ // The drawback is that by not reusing a previous key, the change may be lost if a
+ // backup is restored, if the backup doesn't have the new private key for the change.
+ // If we reused the old key, it would be possible to add code to look for and
+ // rediscover unknown transactions that were written with keys of ours to recover
+ // post-backup change.
+
// New private key
if (keyRet.IsNull())
keyRet.MakeNewKey();
@@ -2899,7 +2937,7 @@ bool CommitTransactionSpent(const CWalletTx& wtxNew, const CKey& key)
//// update: This matters even less now that fSpent can get corrected
//// when transactions are seen in VerifySignature. The remote chance of
//// unmarked fSpent will be handled by that. Don't need to make this
- //// transactional.
+ //// transactional. Pls delete this comment block later.
// This is only to keep the database open to defeat the auto-flush for the
// duration of this scope. This is the only place where this optimization
@@ -2932,7 +2970,7 @@ bool CommitTransactionSpent(const CWalletTx& wtxNew, const CKey& key)
-bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
+string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
{
CRITICAL_BLOCK(cs_main)
{
@@ -2945,13 +2983,13 @@ bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
strError = strprintf("Error: This is an oversized transaction that requires a transaction fee of %s ", FormatMoney(nFeeRequired).c_str());
else
strError = "Error: Transaction creation failed ";
- wxMessageBox(strError, "Sending...");
- return error("SendMoney() : %s", strError.c_str());
+ printf("SendMoney() : %s", strError.c_str());
+ return strError;
}
if (!CommitTransactionSpent(wtxNew, key))
{
- wxMessageBox("Error finalizing transaction ", "Sending...");
- return error("SendMoney() : Error finalizing transaction");
+ printf("SendMoney() : Error finalizing transaction");
+ return "Error finalizing transaction";
}
// Track how many getdata requests our transaction gets
@@ -2964,11 +3002,32 @@ bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
if (!wtxNew.AcceptTransaction())
{
// This must not fail. The transaction has already been signed and recorded.
- wxMessageBox("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.", "Sending...");
- return error("SendMoney() : Error: Transaction not valid");
+ printf("SendMoney() : Error: Transaction not valid");
+ return "Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.";
}
wtxNew.RelayWalletTransaction();
}
MainFrameRepaint();
- return true;
+ return "";
+}
+
+
+
+string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew)
+{
+ // Check amount
+ if (nValue <= 0)
+ return "Invalid amount";
+ if (nValue + nTransactionFee > GetBalance())
+ return "You don't have enough money";
+
+ // Parse bitcoin address
+ uint160 hash160;
+ if (!AddressToHash160(strAddress, hash160))
+ return "Invalid bitcoin address";
+
+ // Send to bitcoin address
+ CScript scriptPubKey;
+ scriptPubKey.SetBitcoinAddress(hash160);
+ return SendMoney(scriptPubKey, nValue, wtxNew);
}