Compare commits

...

2 Commits

Author SHA1 Message Date
s_nakamoto
42605ce8bc better prevention of inventory relaying during initial download,
message checksum between nodes with 0.2.9 or higher,
optimization level up from -O0 to -O2,
rpc functions: setlabel, getlabel, getaddressesbylabel, getreceivedbyaddress, getreceivedbylabel, listreceivedbyaddress, listreceivedbylabel
 -- version 0.2.9

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@78 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-05-26 00:05:26 +00:00
s_nakamoto
124baa4ccb build-osx.txt build instructions and makefile.osx from Laszlo
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@77 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-05-25 23:58:27 +00:00
15 changed files with 638 additions and 101 deletions

209
build-osx.txt Normal file
View File

@@ -0,0 +1,209 @@
Mac OS X build instructions
Laszlo Hanyecz (solar@heliacal.net)
Tested on 10.5 and 10.6 intel. PPC is not supported because it's big-endian.
All of the commands should be executed in Terminal.app.. it's in
/Applications/Utilities
You need to install XCode with all the options checked so that the compiler
and everything is available in /usr not just /Developer
I think it comes on the DVD but you can get the current version from
http://developer.apple.com
1. Pick a directory to work inside.. something like ~/bitcoin works. The
structure I use looks like this:
(~ is your home directory)
~/bitcoin
~/bitcoin/trunk # source code
~/bitcoin/deps # dependencies.. like libraries and headers needed to compile
~/bitcoin/Bitcoin.app # the application bundle where you can run the app
Just execute: mkdir ~/bitcoin
This will create the top dir for you..
WARNING: do not use the ~ notation with the configure scripts.. use the full
name of the directory, for example /Users/james/bitcoin/deps for a user named
'james'. In my examples I am using 'macosuser' so make sure you change that.
2. Check out the trunk version of the bitcoin code from subversion:
cd ~/bitcoin
svn checkout https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk
This will make ~/bitcoin/trunk for you with all the files from subversion.
3. Get and build the dependencies
Boost
-----
Download from http://www.boost.org/users/download/
I'm assuming it ended up in ~/Downloads..
mkdir ~/bitcoin/deps
cd ~/bitcoin/deps
tar xvjf ~/Downloads/boost_1_42_0.tar.bz2
cd boost_1_42_0
./bootstrap.sh
./bjam architecture=combined address-model=32_64 macosx-version=10.6 macosx-version-min=10.5 link=static runtime-link=static --toolset=darwin --prefix=/Users/macosuser/bitcoin/deps install
This part takes a while.. use your judgement and fix it if something doesn't
build for some reason.
Change the prefix to whatever your directory is (my username in this example
is macosuser). I'm also running on 10.6 so i have macosx-version=10.6 change
to 10.5 if you're using leopard.
This is what my output looked like at the end:
...failed updating 2 targets...
...skipped 144 targets...
...updated 8074 targets...
OpenSSL
-------
Download from http://www.openssl.org/source/
We would like to build this as a 32 bit/64 bit library so we actually build it
2 times and join it together here.. If you downloaded with safari it already
uncompressed it so it will just be a tar not a tar.gz
cd ~/bitcoin/deps
tar xvf ~/Downloads/openssl-1.0.0.tar
mv openssl-1.0.0 openssl-1.0.0-i386
tar xvf ~/Downloads/openssl-1.0.0.tar
mv openssl-1.0.0 openssl-1.0.0-x86_64
# build i386 (32 bit intel) binary
cd openssl-1.0.0-i386
./Configure --prefix=/Users/macosuser/bitcoin/deps --openssldir=/Users/macosuser/deps/openssl darwin-i386-cc && make
make install # only do this on one of the architectures, to install the headers
cd ..
# build x86_64 (64 bit intel) binary
cd openssl-1.0.0-x86_64
./Configure --prefix=/Users/macosuser/bitcoin/deps --openssldir=/Users/macosuser/deps/openssl darwin64-x86_64-cc && make
cd ..
# combine the libs
cd ~/bitcoin/deps
lipo -arch i386 openssl-1.0.0-i386/libcrypto.a -arch x86_64 openssl-1.0.0-x86_64/libcrypto.a -o lib/libcrypto.a -create
lipo -arch i386 openssl-1.0.0-i386/libssl.a -arch x86_64 openssl-1.0.0-x86_64/libssl.a -o lib/libssl.a -create
Verify your binaries
file lib/libcrypto.a
output should look like this:
ib/libcrypto.a: Mach-O universal binary with 2 architectures
lib/libcrypto.a (for architecture i386): current ar archive random library
lib/libcrypto.a (for architecture x86_64): current ar archive random library
Berkeley DB
-----------
Download from http://freshmeat.net/projects/berkeleydb/
cd ~/bitcoin/deps
tar xvf ~/Downloads/db-4.8.26.tar
cd db-4.8.26/build_unix
../dist/configure --prefix=/Users/macosuser/bitcoin/deps --enable-cxx && make && make install
wxWidgets
---------
This is the big one..
Check it out from svn
cd ~/bitcoin/deps
svn checkout http://svn.wxwidgets.org/svn/wx/wxWidgets/trunk wxWidgets-trunk
This will make a wxWidgets-trunk directory in deps.
Use this script snippet, change your prefix to whatever your dir is:
PREFIX=~/bitcoin/deps
SRCDIR="$PREFIX/wxWidgets-trunk"
BUILDDIR="$SRCDIR/macbuild"
cd "$PREFIX" &&
#svn checkout http://svn.wxwidgets.org/svn/wx/wxWidgets/trunk wxWidgets-trunk &&
cd "$SRCDIR" &&
[ -f include/wx/hashmap.h.orig ] || cp include/wx/hashmap.h include/wx/hashmap.h.orig &&
sed 's/if wxUSE_STL/if 0 \&\& wxUSE_STL/g' < include/wx/hashmap.h.orig > include/wx/hashmap.h &&
[ -f include/wx/hashset.h.orig ] || cp include/wx/hashset.h include/wx/hashset.h.orig &&
sed 's/if wxUSE_STL/if 0 \&\& wxUSE_STL/g' < include/wx/hashset.h.orig > include/wx/hashset.h &&
rm -vrf "$BUILDDIR" &&
mkdir "$BUILDDIR" &&
cd "$BUILDDIR" &&
../configure --prefix="$PREFIX" \
--with-osx_cocoa \
--disable-shared \
--disable-debug_flag \
--with-macosx-version-min=10.5 \
--enable-stl \
--enable-utf8 \
--enable-universal_binary \
--with-libjpeg=builtin \
--with-libpng=builtin \
--with-regex=builtin \
--with-libtiff=builtin \
--with-zlib=builtin \
--with-expat=builtin \
--with-macosx-sdk=/Developer/SDKs/MacOSX10.5.sdk &&
find . -name Makefile |
while read i; do
echo $i;
sed 's/-arch i386/-arch i386 -arch x86_64/g' < "$i" > "$i".new &&
mv "$i" "$i".old &&
mv "$i".new "$i";
done
make &&
make install
Now you should be able to build bitcoin
cd ~/bitcoin/trunk
make -f makefile.osx bitcoin
Before you can run it, you need to create an application bundle for Mac OS.
Create the directories in terminal using mkdir and copy the files into place.
They are available at http://heliacal.net/~solar/bitcoin/mac-build/
You need the Info.plist and the .ins file. The Contents/MacOS/bitcoin file is
the output of the build.
Your directory structure should look like this:
Bitcoin.app
Bitcoin.app/Contents
Bitcoin.app/Contents/Info.plist
Bitcoin.app/Contents/MacOS
Bitcoin.app/Contents/MacOS/bitcoin
Bitcoin.app/Contents/Resources
Bitcoin.app/Contents/Resources/BitcoinAppIcon.icns
To run it you can just click the Bitcoin.app in Finder, or just do open
~/bitcoin/Bitcoin.app
If you want to run it with arguments you can just run it without backgrounding
by specifying the full name in terminal:
~/bitcoin/Bitcoin.app/Contents/MacOS/bitcoin -addnode=192.75.207.66

2
db.h
View File

@@ -328,6 +328,8 @@ public:
bool EraseName(const string& strAddress)
{
// This should only be used for sending addresses, never for receiving addresses,
// receiving addresses must always have an address book entry if they're not change return.
CRITICAL_BLOCK(cs_mapAddressBook)
mapAddressBook.erase(strAddress);
nWalletDBUpdated++;

View File

@@ -224,9 +224,6 @@ bool CMyApp::Initialize(int& argc, wxChar** argv)
}
}
if (fDaemon)
fprintf(stdout, "bitcoin server starting\n");
#ifdef __WXGTK__
if (fDaemon || fCommandLine)
{
@@ -447,7 +444,8 @@ bool CMyApp::OnInit2()
//
// Load data files
//
bool fFirstRun;
if (fDaemon)
fprintf(stdout, "bitcoin server starting\n");
strErrors = "";
int64 nStart;
@@ -465,6 +463,7 @@ bool CMyApp::OnInit2()
printf("Loading wallet...\n");
nStart = GetTimeMillis();
bool fFirstRun;
if (!LoadWallet(fFirstRun))
strErrors += _("Error loading wallet.dat \n");
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);

View File

@@ -1336,19 +1336,12 @@ bool CBlock::AcceptBlock()
if (!AddToBlockIndex(nFile, nBlockPos))
return error("AcceptBlock() : AddToBlockIndex failed");
// Don't relay old inventory during initial block download.
// Please keep this number updated to a few thousand below current block count.
if (hashBestChain == hash && nBestHeight > 55000)
RelayInventory(CInv(MSG_BLOCK, hash));
// // Add atoms to user reviews for coins created
// vector<unsigned char> vchPubKey;
// if (ExtractPubKey(vtx[0].vout[0].scriptPubKey, false, vchPubKey))
// {
// unsigned short nAtom = GetRand(USHRT_MAX - 100) + 100;
// vector<unsigned short> vAtoms(1, nAtom);
// AddAtomsAndPropagate(Hash(vchPubKey.begin(), vchPubKey.end()), vAtoms, true);
// }
// Relay inventory, but don't relay old inventory during initial block download
if (hashBestChain == hash)
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 55000))
pnode->PushInventory(CInv(MSG_BLOCK, hash));
return true;
}
@@ -1721,6 +1714,7 @@ bool ProcessMessages(CNode* pfrom)
// (4) message start
// (12) command
// (4) size
// (4) checksum
// (x) data
//
@@ -1728,12 +1722,13 @@ bool ProcessMessages(CNode* pfrom)
{
// Scan for message start
CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
if (vRecv.end() - pstart < sizeof(CMessageHeader))
int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
if (vRecv.end() - pstart < nHeaderSize)
{
if (vRecv.size() > sizeof(CMessageHeader))
if (vRecv.size() > nHeaderSize)
{
printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
vRecv.erase(vRecv.begin(), vRecv.end() - sizeof(CMessageHeader));
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
}
break;
}
@@ -1742,6 +1737,7 @@ bool ProcessMessages(CNode* pfrom)
vRecv.erase(vRecv.begin(), pstart);
// Read header
vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
CMessageHeader hdr;
vRecv >> hdr;
if (!hdr.IsValid())
@@ -1757,10 +1753,9 @@ bool ProcessMessages(CNode* pfrom)
{
// Rewind and wait for rest of message
///// need a mechanism to give up waiting for overlong message size error
//if (fDebug)
// printf("message-break\n");
vRecv.insert(vRecv.begin(), BEGIN(hdr), END(hdr));
Sleep(100);
if (fDebug)
printf("message-break\n");
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
break;
}
@@ -1768,6 +1763,20 @@ bool ProcessMessages(CNode* pfrom)
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
vRecv.ignore(nMessageSize);
// Checksum
if (vRecv.GetVersion() >= 209)
{
uint256 hash = Hash(vMsg.begin(), vMsg.end());
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum)
{
printf("ProcessMessage(%s, %d bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
continue;
}
}
// Process message
bool fRet = false;
try
@@ -1844,6 +1853,9 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> addrFrom >> nNonce;
if (pfrom->nVersion >= 106 && !vRecv.empty())
vRecv >> strSubVer;
if (pfrom->nVersion >= 209 && !vRecv.empty())
vRecv >> pfrom->nStartingHeight;
if (pfrom->nVersion == 0)
return false;
@@ -1854,9 +1866,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true;
}
pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
if (pfrom->fClient)
{
@@ -1866,6 +1875,13 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
AddTimeData(pfrom->addr.ip, nTime);
// Change version
if (pfrom->nVersion >= 209)
pfrom->PushMessage("verack");
pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
if (pfrom->nVersion < 209)
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
// Ask the first connected node for block updates
static bool fAskedForBlocks;
if (!fAskedForBlocks && !pfrom->fClient)
@@ -1876,7 +1892,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true;
printf("version message: version %d\n", pfrom->nVersion);
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
}
@@ -1887,6 +1903,12 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
else if (strCommand == "verack")
{
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
}
else if (strCommand == "addr")
{
vector<CAddress> vAddr;
@@ -2101,9 +2123,8 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> *pblock;
//// debug print
// printf("received block:\n");
// pblock->print();
printf("received block %s\n", pblock->GetHash().ToString().substr(0,16).c_str());
// pblock->print();
CInv inv(MSG_BLOCK, pblock->GetHash());
pfrom->AddInventoryKnown(inv);
@@ -2388,8 +2409,11 @@ void GenerateBitcoins(bool fGenerate)
int nAddThreads = nProcessors - vnThreadsRunning[3];
printf("Starting %d BitcoinMiner threads\n", nAddThreads);
for (int i = 0; i < nAddThreads; i++)
{
if (!CreateThread(ThreadBitcoinMiner, NULL))
printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
Sleep(10);
}
}
}

View File

@@ -29,7 +29,7 @@ LIBS= \
WXDEFS=-DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-mthreads -O0 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h

65
makefile.osx Normal file
View File

@@ -0,0 +1,65 @@
# Copyright (c) 2009-2010 Satoshi Nakamoto
# Distributed under the MIT/X11 software license, see the accompanying
# file license.txt or http://www.opensource.org/licenses/mit-license.php.
# Mac OS X makefile for bitcoin
# Laszlo Hanyecz (solar@heliacal.net)
DEPSDIR=/Users/macosuser/bitcoin/deps
INCLUDEPATHS= \
-I"$(DEPSDIR)/include"
LIBPATHS= \
-L"$(DEPSDIR)/lib"
WXLIBS=$(shell $(DEPSDIR)/bin/wx-config --libs --static)
LIBS= -dead_strip \
$(DEPSDIR)/lib/libdb_cxx-4.8.a \
$(DEPSDIR)/lib/libboost_system.a \
$(DEPSDIR)/lib/libboost_filesystem.a \
$(DEPSDIR)/lib/libcrypto.a
WXDEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -DNOPCH -DMSG_NOSIGNAL=0
DEBUGFLAGS=-g -DwxDEBUG_LEVEL=0
# ppc doesn't work because we don't support big-endian
CFLAGS=-mmacosx-version-min=10.5 -arch i386 -arch x86_64 -O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h
all: bitcoin
obj/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -o $@ $<
obj/sha.o: sha.cpp sha.h
g++ -c $(CFLAGS) -O3 -o $@ $<
OBJS= \
obj/util.o \
obj/script.o \
obj/db.o \
obj/net.o \
obj/irc.o \
obj/main.o \
obj/rpc.o \
obj/init.o
bitcoin: $(OBJS) obj/ui.o obj/uibase.o obj/sha.o
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS)
obj/nogui/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -DwxUSE_GUI=0 -o $@ $<
bitcoind: $(OBJS:obj/%=obj/nogui/%) obj/sha.o
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS)
clean:
-rm -f obj/*.o
-rm -f obj/nogui/*.o

View File

@@ -29,7 +29,7 @@ LIBS= \
WXDEFS=-D__WXGTK__ -DNOPCH
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-O0 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
CFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h

30
net.h
View File

@@ -8,6 +8,7 @@ class CInv;
class CRequestTracker;
class CNode;
class CBlockIndex;
extern int nBestHeight;
@@ -59,7 +60,7 @@ public:
char pchMessageStart[sizeof(::pchMessageStart)];
char pchCommand[COMMAND_SIZE];
unsigned int nMessageSize;
//unsigned int nChecksum;
unsigned int nChecksum;
CMessageHeader()
{
@@ -67,7 +68,7 @@ public:
memset(pchCommand, 0, sizeof(pchCommand));
pchCommand[1] = 1;
nMessageSize = -1;
//nChecksum = 0;
nChecksum = 0;
}
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
@@ -75,6 +76,7 @@ public:
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
strncpy(pchCommand, pszCommand, COMMAND_SIZE);
nMessageSize = nMessageSizeIn;
nChecksum = 0;
}
IMPLEMENT_SERIALIZE
@@ -82,8 +84,8 @@ public:
READWRITE(FLATDATA(pchMessageStart));
READWRITE(FLATDATA(pchCommand));
READWRITE(nMessageSize);
//if (nVersion >= 209 && GetCommand() != "version")
// READWRITE(nChecksum);
if (nVersion >= 209)
READWRITE(nChecksum);
)
string GetCommand()
@@ -475,6 +477,7 @@ extern CAddress addrProxy;
class CNode
{
public:
@@ -507,6 +510,7 @@ public:
uint256 hashContinue;
CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd;
int nStartingHeight;
// flood
vector<CAddress> vAddrToSend;
@@ -529,7 +533,9 @@ public:
nServices = 0;
hSocket = hSocketIn;
vSend.SetType(SER_NETWORK);
vSend.SetVersion(0);
vRecv.SetType(SER_NETWORK);
vRecv.SetVersion(0);
nLastSend = 0;
nLastRecv = 0;
nLastSendEmpty = GetTime();
@@ -548,6 +554,7 @@ public:
hashContinue = 0;
pindexLastGetBlocksBegin = 0;
hashLastGetBlocksEnd = 0;
nStartingHeight = -1;
fGetAddr = false;
nNextSendTxInv = 0;
vfSubscribe.assign(256, false);
@@ -558,7 +565,8 @@ public:
CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, string(pszSubVer));
PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, string(pszSubVer), nBestHeight);
}
~CNode()
@@ -680,10 +688,20 @@ public:
if (nHeaderStart == -1)
return;
// Patch in the size
// Set the size
unsigned int nSize = vSend.size() - nMessageStart;
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
// Set the checksum
if (vSend.GetVersion() >= 209)
{
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
}
printf("(%d bytes) ", nSize);
printf("\n");

305
rpc.cpp
View File

@@ -26,7 +26,7 @@ void ThreadRPCServer2(void* parg);
///
/// Note: I'm not finished designing this interface, it's still subject to change.
/// Note: This interface may still be subject to change.
///
@@ -188,6 +188,73 @@ Value getnewaddress(const Array& params)
}
Value setlabel(const Array& params)
{
if (params.size() < 1 || params.size() > 2)
throw runtime_error(
"setlabel <bitcoinaddress> <label>\n"
"Sets the label associated with the given address.");
string strAddress = params[0].get_str();
string strLabel;
if (params.size() > 1)
strLabel = params[1].get_str();
SetAddressBookName(strAddress, strLabel);
return Value::null;
}
Value getlabel(const Array& params)
{
if (params.size() != 1)
throw runtime_error(
"getlabel <bitcoinaddress>\n"
"Returns the label associated with the given address.");
string strAddress = params[0].get_str();
string strLabel;
CRITICAL_BLOCK(cs_mapAddressBook)
{
map<string, string>::iterator mi = mapAddressBook.find(strAddress);
if (mi != mapAddressBook.end() && !(*mi).second.empty())
strLabel = (*mi).second;
}
return strLabel;
}
Value getaddressesbylabel(const Array& params)
{
if (params.size() != 1)
throw runtime_error(
"getaddressesbylabel <label>\n"
"Returns the list of addresses with the given label.");
string strLabel = params[0].get_str();
// Find all addresses that have the given label
Array ret;
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
const string& strAddress = item.first;
const string& strName = item.second;
if (strName == strLabel)
{
// We're only adding valid bitcoin addresses and not ip addresses
CScript scriptPubKey;
if (scriptPubKey.SetBitcoinAddress(strAddress))
ret.push_back(strAddress);
}
}
}
return ret;
}
Value sendtoaddress(const Array& params)
{
if (params.size() < 2 || params.size() > 4)
@@ -237,11 +304,11 @@ Value listtransactions(const Array& params)
}
Value getamountreceived(const Array& params)
Value getreceivedbyaddress(const Array& params)
{
if (params.size() < 1 || params.size() > 2)
throw runtime_error(
"getamountreceived <bitcoinaddress> [minconf=1]\n"
"getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
"Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
// Bitcoin address
@@ -249,6 +316,8 @@ Value getamountreceived(const Array& params)
CScript scriptPubKey;
if (!scriptPubKey.SetBitcoinAddress(strAddress))
throw runtime_error("Invalid bitcoin address");
if (!IsMine(scriptPubKey))
return (double)0.0;
// Minimum confirmations
int nMinDepth = 1;
@@ -276,6 +345,59 @@ Value getamountreceived(const Array& params)
}
Value getreceivedbylabel(const Array& params)
{
if (params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbylabel <label> [minconf=1]\n"
"Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.");
// Get the set of pub keys that have the label
string strLabel = params[0].get_str();
set<CScript> setPubKey;
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
const string& strAddress = item.first;
const string& strName = item.second;
if (strName == strLabel)
{
// We're only counting our own valid bitcoin addresses and not ip addresses
CScript scriptPubKey;
if (scriptPubKey.SetBitcoinAddress(strAddress))
if (IsMine(scriptPubKey))
setPubKey.insert(scriptPubKey);
}
}
}
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 1)
nMinDepth = params[1].get_int();
// Tally
int64 nAmount = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
foreach(const CTxOut& txout, wtx.vout)
if (setPubKey.count(txout.scriptPubKey))
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
}
}
return (double)nAmount / (double)COIN;
}
struct tallyitem
{
int64 nAmount;
@@ -287,23 +409,18 @@ struct tallyitem
}
};
Value getallreceived(const Array& params)
Value ListReceived(const Array& params, bool fByLabels)
{
if (params.size() > 1)
throw runtime_error(
"getallreceived [minconf=1]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"Returns an array of objects containing:\n"
" \"address\" : receiving address\n"
" \"amount\" : total amount received by the address\n"
" \"confirmations\" : number of confirmations of the most recent transaction included\n"
" \"label\" : the label of the receiving address");
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
// Whether to include empty accounts
bool fIncludeEmpty = false;
if (params.size() > 1)
fIncludeEmpty = params[1].get_bool();
// Tally
map<uint160, tallyitem> mapTally;
CRITICAL_BLOCK(cs_mapWallet)
@@ -318,18 +435,11 @@ Value getallreceived(const Array& params)
if (nDepth < nMinDepth)
continue;
// Filter out debits and payments to self, which may have change return
// we don't want to count.
int64 nCredit = wtx.GetCredit(true);
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
if (nNet <= 0)
continue;
foreach(const CTxOut& txout, wtx.vout)
{
// Only counting our own bitcoin addresses and not ip addresses
uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160();
if (hash160 == 0 || !mapPubKeys.count(hash160))
if (hash160 == 0 || !mapPubKeys.count(hash160)) // IsMine
continue;
tallyitem& item = mapTally[hash160];
@@ -341,27 +451,100 @@ Value getallreceived(const Array& params)
// Reply
Array ret;
map<string, tallyitem> mapLabelTally;
CRITICAL_BLOCK(cs_mapAddressBook)
{
for (map<uint160, tallyitem>::iterator it = mapTally.begin(); it != mapTally.end(); ++it)
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
string strAddress = Hash160ToAddress((*it).first);
string strLabel;
map<string, string>::iterator mi = mapAddressBook.find(strAddress);
if (mi != mapAddressBook.end())
strLabel = (*mi).second;
const string& strAddress = item.first;
const string& strLabel = item.second;
uint160 hash160;
if (!AddressToHash160(strAddress, hash160))
continue;
map<uint160, tallyitem>::iterator it = mapTally.find(hash160);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
int64 nAmount = 0;
int nConf = INT_MAX;
if (it != mapTally.end())
{
nAmount = (*it).second.nAmount;
nConf = (*it).second.nConf;
}
if (fByLabels)
{
tallyitem& item = mapLabelTally[strLabel];
item.nAmount += nAmount;
item.nConf = min(item.nConf, nConf);
}
else
{
Object obj;
obj.push_back(Pair("address", strAddress));
obj.push_back(Pair("label", strLabel));
obj.push_back(Pair("amount", (double)nAmount / (double)COIN));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj);
}
}
}
if (fByLabels)
{
for (map<string, tallyitem>::iterator it = mapLabelTally.begin(); it != mapLabelTally.end(); ++it)
{
int64 nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
Object obj;
obj.push_back(Pair("address", strAddress));
obj.push_back(Pair("amount", (double)(*it).second.nAmount / (double)COIN));
obj.push_back(Pair("confirmations", (*it).second.nConf));
obj.push_back(Pair("label", strLabel));
obj.push_back(Pair("label", (*it).first));
obj.push_back(Pair("amount", (double)nAmount / (double)COIN));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj);
}
}
return ret;
}
Value listreceivedbyaddress(const Array& params)
{
if (params.size() > 2)
throw runtime_error(
"listreceivedbyaddress [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include addresses that haven't received any payments.\n"
"Returns an array of objects containing:\n"
" \"address\" : receiving address\n"
" \"label\" : the label of the receiving address\n"
" \"amount\" : total amount received by the address\n"
" \"confirmations\" : number of confirmations of the most recent transaction included");
return ListReceived(params, false);
}
Value listreceivedbylabel(const Array& params)
{
if (params.size() > 2)
throw runtime_error(
"listreceivedbylabel [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include labels that haven't received any payments.\n"
"Returns an array of objects containing:\n"
" \"label\" : the label of the receiving addresses\n"
" \"amount\" : total amount received by addresses with this label\n"
" \"confirmations\" : number of confirmations of the most recent transaction included");
return ListReceived(params, true);
}
@@ -375,20 +558,27 @@ Value getallreceived(const Array& params)
typedef Value(*rpcfn_type)(const Array& params);
pair<string, rpcfn_type> pCallTable[] =
{
make_pair("stop", &stop),
make_pair("getblockcount", &getblockcount),
make_pair("getblocknumber", &getblocknumber),
make_pair("getconnectioncount", &getconnectioncount),
make_pair("getdifficulty", &getdifficulty),
make_pair("getbalance", &getbalance),
make_pair("getgenerate", &getgenerate),
make_pair("setgenerate", &setgenerate),
make_pair("getinfo", &getinfo),
make_pair("getnewaddress", &getnewaddress),
make_pair("sendtoaddress", &sendtoaddress),
make_pair("listtransactions", &listtransactions),
make_pair("getamountreceived", &getamountreceived),
make_pair("getallreceived", &getallreceived),
make_pair("stop", &stop),
make_pair("getblockcount", &getblockcount),
make_pair("getblocknumber", &getblocknumber),
make_pair("getconnectioncount", &getconnectioncount),
make_pair("getdifficulty", &getdifficulty),
make_pair("getbalance", &getbalance),
make_pair("getgenerate", &getgenerate),
make_pair("setgenerate", &setgenerate),
make_pair("getinfo", &getinfo),
make_pair("getnewaddress", &getnewaddress),
make_pair("setlabel", &setlabel),
make_pair("getlabel", &getlabel),
make_pair("getaddressesbylabel", &getaddressesbylabel),
make_pair("sendtoaddress", &sendtoaddress),
make_pair("listtransactions", &listtransactions),
make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbylabel", &getreceivedbylabel),
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbylabel", &listreceivedbylabel),
};
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
@@ -666,13 +856,20 @@ int CommandLineRPC(int argc, char *argv[])
//
// Special case other types
//
if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
if (strMethod == "listtransactions" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listtransactions" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
if (strMethod == "listtransactions" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listtransactions" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]);
// Execute
Value result = CallRPC(strMethod, params);

View File

@@ -19,7 +19,7 @@ class CScript;
class CDataStream;
class CAutoFile;
static const int VERSION = 208;
static const int VERSION = 209;
static const char* pszSubVer = ".0";
@@ -809,6 +809,18 @@ public:
vch.insert(it, first, last);
}
void insert(iterator it, vector<char>::const_iterator first, vector<char>::const_iterator last)
{
if (it == vch.begin() + nReadPos && last - first <= nReadPos)
{
// special case for inserting at the front when there's room
nReadPos -= (last - first);
memcpy(&vch[nReadPos], &first[0], last - first);
}
else
vch.insert(it, first, last);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1300
void insert(iterator it, const char* first, const char* last)
{

9
ui.cpp
View File

@@ -193,6 +193,12 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* pa
return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
}
void CalledSetStatusBar(const string& strText, int nField)
{
if (pframeMain && pframeMain->m_statusBar)
pframeMain->m_statusBar->SetStatusText(strText, nField);
}
void SetDefaultReceivingAddress(const string& strAddress)
{
// Update main window address and database
@@ -268,7 +274,8 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
nDateWidth += 12;
#ifdef __WXMAC__
nDateWidth += 2;
nDateWidth += 5;
dResize -= 0.01;
#endif
wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
foreach(wxListCtrl* p, pplistCtrl)

9
ui.h
View File

@@ -30,6 +30,7 @@ string FormatTxStatus(const CWalletTx& wtx);
void UIThreadCall(boost::function0<void>);
int ThreadSafeMessageBox(const string& message, const string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent);
void CalledSetStatusBar(const string& strText, int nField);
void MainFrameRepaint();
void CreateMainWindow();
@@ -48,6 +49,14 @@ inline bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWin
return true;
}
inline void CalledSetStatusBar(const string& strText, int nField)
{
}
inline void UIThreadCall(boost::function0<void> fn)
{
}
inline void MainFrameRepaint()
{
}

View File

@@ -77,7 +77,6 @@ class CMainFrameBase : public wxFrame
wxMenu* m_menuFile;
wxMenu* m_menuHelp;
wxToolBar* m_toolBar;
wxStatusBar* m_statusBar;
wxStaticText* m_staticText32;
wxButton* m_buttonNew;
@@ -121,6 +120,7 @@ class CMainFrameBase : public wxFrame
public:
wxMenu* m_menuOptions;
wxStatusBar* m_statusBar;
wxTextCtrl* m_textCtrlAddress;
wxListCtrl* m_listCtrlAll;
wxListCtrl* m_listCtrlSentReceived;

View File

@@ -293,7 +293,7 @@
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_statusBar</property>
<property name="permission">protected</property>
<property name="permission">public</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style">wxST_SIZEGRIP</property>

View File

@@ -250,11 +250,6 @@ string strprintf(const char* format, ...)
if (p == NULL)
throw std::bad_alloc();
}
#ifdef _MSC_VER
// msvc optimisation
if (p == buffer)
return string(p, p+ret);
#endif
string str(p, p+ret);
if (p != buffer)
delete p;