Better wording for transaction fee notification messages
[novacoin.git] / net.h
diff --git a/net.h b/net.h
index 11197cc..b3bd74d 100644 (file)
--- a/net.h
+++ b/net.h
-// Copyright (c) 2009-2010 Satoshi Nakamoto\r
-// Distributed under the MIT/X11 software license, see the accompanying\r
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.\r
-\r
-class CMessageHeader;\r
-class CAddress;\r
-class CInv;\r
-class CRequestTracker;\r
-class CNode;\r
-class CBlockIndex;\r
-extern int nBestHeight;\r
-\r
-\r
-\r
-#define DEFAULT_PORT    htons(8333)\r
-static const unsigned int PUBLISH_HOPS = 5;\r
-enum\r
-{\r
-    NODE_NETWORK = (1 << 0),\r
-};\r
-\r
-\r
-\r
-\r
-bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet);\r
-bool GetMyExternalIP(unsigned int& ipRet);\r
-bool AddAddress(CAddress addr, bool fCurrentlyOnline=true);\r
-void AddressCurrentlyConnected(const CAddress& addr);\r
-CNode* FindNode(unsigned int ip);\r
-CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);\r
-void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);\r
-bool AnySubscribed(unsigned int nChannel);\r
-bool BindListenPort(string& strError=REF(string()));\r
-void StartNode(void* parg);\r
-bool StopNode();\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-//\r
-// Message header\r
-//  (4) message start\r
-//  (12) command\r
-//  (4) size\r
-//  (4) checksum\r
-\r
-// The message start string is designed to be unlikely to occur in normal data.\r
-// The characters are rarely used upper ascii, not valid as UTF-8, and produce\r
-// a large 4-byte int at any alignment.\r
-static const char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };\r
-\r
-class CMessageHeader\r
-{\r
-public:\r
-    enum { COMMAND_SIZE=12 };\r
-    char pchMessageStart[sizeof(::pchMessageStart)];\r
-    char pchCommand[COMMAND_SIZE];\r
-    unsigned int nMessageSize;\r
-    unsigned int nChecksum;\r
-\r
-    CMessageHeader()\r
-    {\r
-        memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));\r
-        memset(pchCommand, 0, sizeof(pchCommand));\r
-        pchCommand[1] = 1;\r
-        nMessageSize = -1;\r
-        nChecksum = 0;\r
-    }\r
-\r
-    CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)\r
-    {\r
-        memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));\r
-        strncpy(pchCommand, pszCommand, COMMAND_SIZE);\r
-        nMessageSize = nMessageSizeIn;\r
-        nChecksum = 0;\r
-    }\r
-\r
-    IMPLEMENT_SERIALIZE\r
-    (\r
-        READWRITE(FLATDATA(pchMessageStart));\r
-        READWRITE(FLATDATA(pchCommand));\r
-        READWRITE(nMessageSize);\r
-        if (nVersion >= 209)\r
-            READWRITE(nChecksum);\r
-    )\r
-\r
-    string GetCommand()\r
-    {\r
-        if (pchCommand[COMMAND_SIZE-1] == 0)\r
-            return string(pchCommand, pchCommand + strlen(pchCommand));\r
-        else\r
-            return string(pchCommand, pchCommand + COMMAND_SIZE);\r
-    }\r
-\r
-    bool IsValid()\r
-    {\r
-        // Check start string\r
-        if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)\r
-            return false;\r
-\r
-        // Check the command string for errors\r
-        for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)\r
-        {\r
-            if (*p1 == 0)\r
-            {\r
-                // Must be all zeros after the first zero\r
-                for (; p1 < pchCommand + COMMAND_SIZE; p1++)\r
-                    if (*p1 != 0)\r
-                        return false;\r
-            }\r
-            else if (*p1 < ' ' || *p1 > 0x7E)\r
-                return false;\r
-        }\r
-\r
-        // Message size\r
-        if (nMessageSize > 0x10000000)\r
-        {\r
-            printf("CMessageHeader::IsValid() : nMessageSize too large %u\n", nMessageSize);\r
-            return false;\r
-        }\r
-\r
-        return true;\r
-    }\r
-};\r
-\r
-\r
-\r
-\r
-\r
-\r
-static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };\r
-\r
-class CAddress\r
-{\r
-public:\r
-    uint64 nServices;\r
-    unsigned char pchReserved[12];\r
-    unsigned int ip;\r
-    unsigned short port;\r
-\r
-    // disk only\r
-    unsigned int nTime;\r
-\r
-    // memory only\r
-    unsigned int nLastTry;\r
-\r
-    CAddress()\r
-    {\r
-        Init();\r
-    }\r
-\r
-    CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=NODE_NETWORK)\r
-    {\r
-        Init();\r
-        ip = ipIn;\r
-        port = portIn;\r
-        nServices = nServicesIn;\r
-    }\r
-\r
-    explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK)\r
-    {\r
-        Init();\r
-        ip = sockaddr.sin_addr.s_addr;\r
-        port = sockaddr.sin_port;\r
-        nServices = nServicesIn;\r
-    }\r
-\r
-    explicit CAddress(const char* pszIn, uint64 nServicesIn=NODE_NETWORK)\r
-    {\r
-        Init();\r
-        SetAddress(pszIn);\r
-        nServices = nServicesIn;\r
-    }\r
-\r
-    explicit CAddress(string strIn, uint64 nServicesIn=NODE_NETWORK)\r
-    {\r
-        Init();\r
-        SetAddress(strIn.c_str());\r
-        nServices = nServicesIn;\r
-    }\r
-\r
-    void Init()\r
-    {\r
-        nServices = NODE_NETWORK;\r
-        memcpy(pchReserved, pchIPv4, sizeof(pchReserved));\r
-        ip = INADDR_NONE;\r
-        port = DEFAULT_PORT;\r
-        nTime = GetAdjustedTime();\r
-        nLastTry = 0;\r
-    }\r
-\r
-    bool SetAddress(const char* pszIn)\r
-    {\r
-        ip = INADDR_NONE;\r
-        port = DEFAULT_PORT;\r
-        char psz[100];\r
-        strlcpy(psz, pszIn, sizeof(psz));\r
-        unsigned int a=0, b=0, c=0, d=0, e=0;\r
-        if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4)\r
-            return false;\r
-        char* pszPort = strchr(psz, ':');\r
-        if (pszPort)\r
-        {\r
-            *pszPort++ = '\0';\r
-            port = htons(atoi(pszPort));\r
-            if (atoi(pszPort) < 0 || atoi(pszPort) > USHRT_MAX)\r
-                port = htons(USHRT_MAX);\r
-        }\r
-        ip = inet_addr(psz);\r
-        return IsValid();\r
-    }\r
-\r
-    bool SetAddress(string strIn)\r
-    {\r
-        return SetAddress(strIn.c_str());\r
-    }\r
-\r
-    IMPLEMENT_SERIALIZE\r
-    (\r
-        if (nType & SER_DISK)\r
-        {\r
-            READWRITE(nVersion);\r
-            READWRITE(nTime);\r
-        }\r
-        READWRITE(nServices);\r
-        READWRITE(FLATDATA(pchReserved)); // for IPv6\r
-        READWRITE(ip);\r
-        READWRITE(port);\r
-    )\r
-\r
-    friend inline bool operator==(const CAddress& a, const CAddress& b)\r
-    {\r
-        return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&\r
-                a.ip   == b.ip &&\r
-                a.port == b.port);\r
-    }\r
-\r
-    friend inline bool operator!=(const CAddress& a, const CAddress& b)\r
-    {\r
-        return (!(a == b));\r
-    }\r
-\r
-    friend inline bool operator<(const CAddress& a, const CAddress& b)\r
-    {\r
-        int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));\r
-        if (ret < 0)\r
-            return true;\r
-        else if (ret == 0)\r
-        {\r
-            if (ntohl(a.ip) < ntohl(b.ip))\r
-                return true;\r
-            else if (a.ip == b.ip)\r
-                return ntohs(a.port) < ntohs(b.port);\r
-        }\r
-        return false;\r
-    }\r
-\r
-    vector<unsigned char> GetKey() const\r
-    {\r
-        CDataStream ss;\r
-        ss.reserve(18);\r
-        ss << FLATDATA(pchReserved) << ip << port;\r
-\r
-        #if defined(_MSC_VER) && _MSC_VER < 1300\r
-        return vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);\r
-        #else\r
-        return vector<unsigned char>(ss.begin(), ss.end());\r
-        #endif\r
-    }\r
-\r
-    struct sockaddr_in GetSockAddr() const\r
-    {\r
-        struct sockaddr_in sockaddr;\r
-        memset(&sockaddr, 0, sizeof(sockaddr));\r
-        sockaddr.sin_family = AF_INET;\r
-        sockaddr.sin_addr.s_addr = ip;\r
-        sockaddr.sin_port = port;\r
-        return sockaddr;\r
-    }\r
-\r
-    bool IsIPv4() const\r
-    {\r
-        return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);\r
-    }\r
-\r
-    bool IsRoutable() const\r
-    {\r
-        return IsValid() &&\r
-            !(GetByte(3) == 10 ||\r
-              (GetByte(3) == 192 && GetByte(2) == 168) ||\r
-              GetByte(3) == 127 ||\r
-              GetByte(3) == 0);\r
-    }\r
-\r
-    bool IsValid() const\r
-    {\r
-        // Clean up 3-byte shifted addresses caused by garbage in size field\r
-        // of addr messages from versions before 0.2.9 checksum.\r
-        // Two consecutive addr messages look like this:\r
-        // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...\r
-        // so if the first length field is garbled, it reads the second batch\r
-        // of addr misaligned by 3 bytes.\r
-        if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)\r
-            return false;\r
-\r
-        return (ip != 0 && ip != INADDR_NONE && port != htons(USHRT_MAX));\r
-    }\r
-\r
-    unsigned char GetByte(int n) const\r
-    {\r
-        return ((unsigned char*)&ip)[3-n];\r
-    }\r
-\r
-    string ToStringIPPort() const\r
-    {\r
-        return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));\r
-    }\r
-\r
-    string ToStringIP() const\r
-    {\r
-        return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));\r
-    }\r
-\r
-    string ToStringPort() const\r
-    {\r
-        return strprintf("%u", ntohs(port));\r
-    }\r
-\r
-    string ToStringLog() const\r
-    {\r
-        return "";\r
-    }\r
-\r
-    string ToString() const\r
-    {\r
-        return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));\r
-    }\r
-\r
-    void print() const\r
-    {\r
-        printf("CAddress(%s)\n", ToString().c_str());\r
-    }\r
-};\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-enum\r
-{\r
-    MSG_TX = 1,\r
-    MSG_BLOCK,\r
-};\r
-\r
-static const char* ppszTypeName[] =\r
-{\r
-    "ERROR",\r
-    "tx",\r
-    "block",\r
-};\r
-\r
-class CInv\r
-{\r
-public:\r
-    int type;\r
-    uint256 hash;\r
-\r
-    CInv()\r
-    {\r
-        type = 0;\r
-        hash = 0;\r
-    }\r
-\r
-    CInv(int typeIn, const uint256& hashIn)\r
-    {\r
-        type = typeIn;\r
-        hash = hashIn;\r
-    }\r
-\r
-    CInv(const string& strType, const uint256& hashIn)\r
-    {\r
-        int i;\r
-        for (i = 1; i < ARRAYLEN(ppszTypeName); i++)\r
-        {\r
-            if (strType == ppszTypeName[i])\r
-            {\r
-                type = i;\r
-                break;\r
-            }\r
-        }\r
-        if (i == ARRAYLEN(ppszTypeName))\r
-            throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));\r
-        hash = hashIn;\r
-    }\r
-\r
-    IMPLEMENT_SERIALIZE\r
-    (\r
-        READWRITE(type);\r
-        READWRITE(hash);\r
-    )\r
-\r
-    friend inline bool operator<(const CInv& a, const CInv& b)\r
-    {\r
-        return (a.type < b.type || (a.type == b.type && a.hash < b.hash));\r
-    }\r
-\r
-    bool IsKnownType() const\r
-    {\r
-        return (type >= 1 && type < ARRAYLEN(ppszTypeName));\r
-    }\r
-\r
-    const char* GetCommand() const\r
-    {\r
-        if (!IsKnownType())\r
-            throw std::out_of_range(strprintf("CInv::GetCommand() : type=% unknown type", type));\r
-        return ppszTypeName[type];\r
-    }\r
-\r
-    string ToString() const\r
-    {\r
-        return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,16).c_str());\r
-    }\r
-\r
-    void print() const\r
-    {\r
-        printf("CInv(%s)\n", ToString().c_str());\r
-    }\r
-};\r
-\r
-\r
-\r
-\r
-\r
-class CRequestTracker\r
-{\r
-public:\r
-    void (*fn)(void*, CDataStream&);\r
-    void* param1;\r
-\r
-    explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)\r
-    {\r
-        fn = fnIn;\r
-        param1 = param1In;\r
-    }\r
-\r
-    bool IsNull()\r
-    {\r
-        return fn == NULL;\r
-    }\r
-};\r
-\r
-\r
-\r
-\r
-\r
-extern bool fClient;\r
-extern uint64 nLocalServices;\r
-extern CAddress addrLocalHost;\r
-extern CNode* pnodeLocalHost;\r
-extern uint64 nLocalHostNonce;\r
-extern array<int, 10> vnThreadsRunning;\r
-extern SOCKET hListenSocket;\r
-extern int64 nThreadSocketHandlerHeartbeat;\r
-\r
-extern vector<CNode*> vNodes;\r
-extern CCriticalSection cs_vNodes;\r
-extern map<vector<unsigned char>, CAddress> mapAddresses;\r
-extern CCriticalSection cs_mapAddresses;\r
-extern map<CInv, CDataStream> mapRelay;\r
-extern deque<pair<int64, CInv> > vRelayExpiration;\r
-extern CCriticalSection cs_mapRelay;\r
-extern map<CInv, int64> mapAlreadyAskedFor;\r
-\r
-// Settings\r
-extern int fUseProxy;\r
-extern CAddress addrProxy;\r
-\r
-\r
-\r
-\r
-\r
-\r
-class CNode\r
-{\r
-public:\r
-    // socket\r
-    uint64 nServices;\r
-    SOCKET hSocket;\r
-    CDataStream vSend;\r
-    CDataStream vRecv;\r
-    CCriticalSection cs_vSend;\r
-    CCriticalSection cs_vRecv;\r
-    int64 nLastSend;\r
-    int64 nLastRecv;\r
-    int64 nLastSendEmpty;\r
-    int64 nTimeConnected;\r
-    unsigned int nHeaderStart;\r
-    unsigned int nMessageStart;\r
-    CAddress addr;\r
-    int nVersion;\r
-    bool fClient;\r
-    bool fInbound;\r
-    bool fNetworkNode;\r
-    bool fSuccessfullyConnected;\r
-    bool fDisconnect;\r
-protected:\r
-    int nRefCount;\r
-public:\r
-    int64 nReleaseTime;\r
-    map<uint256, CRequestTracker> mapRequests;\r
-    CCriticalSection cs_mapRequests;\r
-    uint256 hashContinue;\r
-    CBlockIndex* pindexLastGetBlocksBegin;\r
-    uint256 hashLastGetBlocksEnd;\r
-    int nStartingHeight;\r
-\r
-    // flood\r
-    vector<CAddress> vAddrToSend;\r
-    set<CAddress> setAddrKnown;\r
-    bool fGetAddr;\r
-\r
-    // inventory based relay\r
-    set<CInv> setInventoryKnown;\r
-    vector<CInv> vInventoryToSend;\r
-    CCriticalSection cs_inventory;\r
-    multimap<int64, CInv> mapAskFor;\r
-\r
-    // publish and subscription\r
-    vector<char> vfSubscribe;\r
-\r
-\r
-    CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)\r
-    {\r
-        nServices = 0;\r
-        hSocket = hSocketIn;\r
-        vSend.SetType(SER_NETWORK);\r
-        vSend.SetVersion(0);\r
-        vRecv.SetType(SER_NETWORK);\r
-        vRecv.SetVersion(0);\r
-        // Version 0.2 obsoletes 20 Feb 2012\r
-        if (GetTime() > 1329696000)\r
-        {\r
-            vSend.SetVersion(209);\r
-            vRecv.SetVersion(209);\r
-        }\r
-        nLastSend = 0;\r
-        nLastRecv = 0;\r
-        nLastSendEmpty = GetTime();\r
-        nTimeConnected = GetTime();\r
-        nHeaderStart = -1;\r
-        nMessageStart = -1;\r
-        addr = addrIn;\r
-        nVersion = 0;\r
-        fClient = false; // set by version message\r
-        fInbound = fInboundIn;\r
-        fNetworkNode = false;\r
-        fSuccessfullyConnected = false;\r
-        fDisconnect = false;\r
-        nRefCount = 0;\r
-        nReleaseTime = 0;\r
-        hashContinue = 0;\r
-        pindexLastGetBlocksBegin = 0;\r
-        hashLastGetBlocksEnd = 0;\r
-        nStartingHeight = -1;\r
-        fGetAddr = false;\r
-        vfSubscribe.assign(256, false);\r
-\r
-        // Push a version message\r
-        /// when NTP implemented, change to just nTime = GetAdjustedTime()\r
-        int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());\r
-        CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);\r
-        CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);\r
-        RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));\r
-        PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,\r
-                    nLocalHostNonce, string(pszSubVer), nBestHeight);\r
-    }\r
-\r
-    ~CNode()\r
-    {\r
-        if (hSocket != INVALID_SOCKET)\r
-        {\r
-            closesocket(hSocket);\r
-            hSocket = INVALID_SOCKET;\r
-        }\r
-    }\r
-\r
-private:\r
-    CNode(const CNode&);\r
-    void operator=(const CNode&);\r
-public:\r
-\r
-\r
-    int GetRefCount()\r
-    {\r
-        return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);\r
-    }\r
-\r
-    CNode* AddRef(int64 nTimeout=0)\r
-    {\r
-        if (nTimeout != 0)\r
-            nReleaseTime = max(nReleaseTime, GetTime() + nTimeout);\r
-        else\r
-            nRefCount++;\r
-        return this;\r
-    }\r
-\r
-    void Release()\r
-    {\r
-        nRefCount--;\r
-    }\r
-\r
-\r
-\r
-    void AddAddressKnown(const CAddress& addr)\r
-    {\r
-        setAddrKnown.insert(addr);\r
-    }\r
-\r
-    void PushAddress(const CAddress& addr)\r
-    {\r
-        // Known checking here is only to save space from duplicates.\r
-        // SendMessages will filter it again for knowns that were added\r
-        // after addresses were pushed.\r
-        if (addr.IsValid() && !setAddrKnown.count(addr))\r
-            vAddrToSend.push_back(addr);\r
-    }\r
-\r
-\r
-    void AddInventoryKnown(const CInv& inv)\r
-    {\r
-        CRITICAL_BLOCK(cs_inventory)\r
-            setInventoryKnown.insert(inv);\r
-    }\r
-\r
-    void PushInventory(const CInv& inv)\r
-    {\r
-        CRITICAL_BLOCK(cs_inventory)\r
-            if (!setInventoryKnown.count(inv))\r
-                vInventoryToSend.push_back(inv);\r
-    }\r
-\r
-    void AskFor(const CInv& inv)\r
-    {\r
-        // We're using mapAskFor as a priority queue,\r
-        // the key is the earliest time the request can be sent\r
-        int64& nRequestTime = mapAlreadyAskedFor[inv];\r
-        printf("askfor %s   %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);\r
-\r
-        // Make sure not to reuse time indexes to keep things in the same order\r
-        int64 nNow = (GetTime() - 1) * 1000000;\r
-        static int64 nLastTime;\r
-        nLastTime = nNow = max(nNow, ++nLastTime);\r
-\r
-        // Each retry is 2 minutes after the last\r
-        nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow);\r
-        mapAskFor.insert(make_pair(nRequestTime, inv));\r
-    }\r
-\r
-\r
-\r
-    void BeginMessage(const char* pszCommand)\r
-    {\r
-        cs_vSend.Enter();\r
-        if (nHeaderStart != -1)\r
-            AbortMessage();\r
-        nHeaderStart = vSend.size();\r
-        vSend << CMessageHeader(pszCommand, 0);\r
-        nMessageStart = vSend.size();\r
-        if (fDebug)\r
-            printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
-        printf("sending: %s ", pszCommand);\r
-    }\r
-\r
-    void AbortMessage()\r
-    {\r
-        if (nHeaderStart == -1)\r
-            return;\r
-        vSend.resize(nHeaderStart);\r
-        nHeaderStart = -1;\r
-        nMessageStart = -1;\r
-        cs_vSend.Leave();\r
-        printf("(aborted)\n");\r
-    }\r
-\r
-    void EndMessage()\r
-    {\r
-        if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)\r
-        {\r
-            printf("dropmessages DROPPING SEND MESSAGE\n");\r
-            AbortMessage();\r
-            return;\r
-        }\r
-\r
-        if (nHeaderStart == -1)\r
-            return;\r
-\r
-        // Set the size\r
-        unsigned int nSize = vSend.size() - nMessageStart;\r
-        memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));\r
-\r
-        // Set the checksum\r
-        if (vSend.GetVersion() >= 209)\r
-        {\r
-            uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());\r
-            unsigned int nChecksum = 0;\r
-            memcpy(&nChecksum, &hash, sizeof(nChecksum));\r
-            assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));\r
-            memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));\r
-        }\r
-\r
-        printf("(%d bytes) ", nSize);\r
-        printf("\n");\r
-\r
-        nHeaderStart = -1;\r
-        nMessageStart = -1;\r
-        cs_vSend.Leave();\r
-    }\r
-\r
-    void EndMessageAbortIfEmpty()\r
-    {\r
-        if (nHeaderStart == -1)\r
-            return;\r
-        int nSize = vSend.size() - nMessageStart;\r
-        if (nSize > 0)\r
-            EndMessage();\r
-        else\r
-            AbortMessage();\r
-    }\r
-\r
-    const char* GetMessageCommand() const\r
-    {\r
-        if (nHeaderStart == -1)\r
-            return "";\r
-        return &vSend[nHeaderStart] + offsetof(CMessageHeader, pchCommand);\r
-    }\r
-\r
-\r
-\r
-\r
-    void PushMessage(const char* pszCommand)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1>\r
-    void PushMessage(const char* pszCommand, const T1& a1)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1, typename T2>\r
-    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1 << a2;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1, typename T2, typename T3>\r
-    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1 << a2 << a3;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1, typename T2, typename T3, typename T4>\r
-    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1 << a2 << a3 << a4;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1, typename T2, typename T3, typename T4, typename T5>\r
-    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1 << a2 << a3 << a4 << a5;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>\r
-    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1 << a2 << a3 << a4 << a5 << a6;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>\r
-    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>\r
-    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>\r
-    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)\r
-    {\r
-        try\r
-        {\r
-            BeginMessage(pszCommand);\r
-            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;\r
-            EndMessage();\r
-        }\r
-        catch (...)\r
-        {\r
-            AbortMessage();\r
-            throw;\r
-        }\r
-    }\r
-\r
-\r
-    void PushRequest(const char* pszCommand,\r
-                     void (*fn)(void*, CDataStream&), void* param1)\r
-    {\r
-        uint256 hashReply;\r
-        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));\r
-\r
-        CRITICAL_BLOCK(cs_mapRequests)\r
-            mapRequests[hashReply] = CRequestTracker(fn, param1);\r
-\r
-        PushMessage(pszCommand, hashReply);\r
-    }\r
-\r
-    template<typename T1>\r
-    void PushRequest(const char* pszCommand, const T1& a1,\r
-                     void (*fn)(void*, CDataStream&), void* param1)\r
-    {\r
-        uint256 hashReply;\r
-        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));\r
-\r
-        CRITICAL_BLOCK(cs_mapRequests)\r
-            mapRequests[hashReply] = CRequestTracker(fn, param1);\r
-\r
-        PushMessage(pszCommand, hashReply, a1);\r
-    }\r
-\r
-    template<typename T1, typename T2>\r
-    void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,\r
-                     void (*fn)(void*, CDataStream&), void* param1)\r
-    {\r
-        uint256 hashReply;\r
-        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));\r
-\r
-        CRITICAL_BLOCK(cs_mapRequests)\r
-            mapRequests[hashReply] = CRequestTracker(fn, param1);\r
-\r
-        PushMessage(pszCommand, hashReply, a1, a2);\r
-    }\r
-\r
-\r
-\r
-    void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);\r
-    bool IsSubscribed(unsigned int nChannel);\r
-    void Subscribe(unsigned int nChannel, unsigned int nHops=0);\r
-    void CancelSubscribe(unsigned int nChannel);\r
-    void CloseSocketDisconnect();\r
-    void Cleanup();\r
-};\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-inline void RelayInventory(const CInv& inv)\r
-{\r
-    // Put on lists to offer to the other nodes\r
-    CRITICAL_BLOCK(cs_vNodes)\r
-        foreach(CNode* pnode, vNodes)\r
-            pnode->PushInventory(inv);\r
-}\r
-\r
-template<typename T>\r
-void RelayMessage(const CInv& inv, const T& a)\r
-{\r
-    CDataStream ss(SER_NETWORK);\r
-    ss.reserve(10000);\r
-    ss << a;\r
-    RelayMessage(inv, ss);\r
-}\r
-\r
-template<>\r
-inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)\r
-{\r
-    CRITICAL_BLOCK(cs_mapRelay)\r
-    {\r
-        // Expire old relay messages\r
-        while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())\r
-        {\r
-            mapRelay.erase(vRelayExpiration.front().second);\r
-            vRelayExpiration.pop_front();\r
-        }\r
-\r
-        // Save original serialized message so newer versions are preserved\r
-        mapRelay[inv] = ss;\r
-        vRelayExpiration.push_back(make_pair(GetTime() + 15 * 60, inv));\r
-    }\r
-\r
-    RelayInventory(inv);\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-//\r
-// Templates for the publish and subscription system.\r
-// The object being published as T& obj needs to have:\r
-//   a set<unsigned int> setSources member\r
-//   specializations of AdvertInsert and AdvertErase\r
-// Currently implemented for CTable and CProduct.\r
-//\r
-\r
-template<typename T>\r
-void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)\r
-{\r
-    // Add to sources\r
-    obj.setSources.insert(pfrom->addr.ip);\r
-\r
-    if (!AdvertInsert(obj))\r
-        return;\r
-\r
-    // Relay\r
-    CRITICAL_BLOCK(cs_vNodes)\r
-        foreach(CNode* pnode, vNodes)\r
-            if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))\r
-                pnode->PushMessage("publish", nChannel, nHops, obj);\r
-}\r
-\r
-template<typename T>\r
-void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)\r
-{\r
-    uint256 hash = obj.GetHash();\r
-\r
-    CRITICAL_BLOCK(cs_vNodes)\r
-        foreach(CNode* pnode, vNodes)\r
-            if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))\r
-                pnode->PushMessage("pub-cancel", nChannel, nHops, hash);\r
-\r
-    AdvertErase(obj);\r
-}\r
-\r
-template<typename T>\r
-void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)\r
-{\r
-    // Remove a source\r
-    obj.setSources.erase(pfrom->addr.ip);\r
-\r
-    // If no longer supported by any sources, cancel it\r
-    if (obj.setSources.empty())\r
-        AdvertStopPublish(pfrom, nChannel, nHops, obj);\r
-}\r
+// 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.
+
+class CMessageHeader;
+class CAddress;
+class CInv;
+class CRequestTracker;
+class CNode;
+class CBlockIndex;
+extern int nBestHeight;
+
+
+
+inline unsigned short GetDefaultPort() { return fTestNet ? htons(18333) : htons(8333); }
+static const unsigned int PUBLISH_HOPS = 5;
+enum
+{
+    NODE_NETWORK = (1 << 0),
+};
+
+
+
+
+bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet);
+bool GetMyExternalIP(unsigned int& ipRet);
+bool AddAddress(CAddress addr, int64 nTimePenalty=0);
+void AddressCurrentlyConnected(const CAddress& addr);
+CNode* FindNode(unsigned int ip);
+CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
+void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
+bool AnySubscribed(unsigned int nChannel);
+void MapPort(bool fMapPort);
+void DNSAddressSeed();
+bool BindListenPort(string& strError=REF(string()));
+void StartNode(void* parg);
+bool StopNode();
+
+
+
+
+
+
+
+
+//
+// Message header
+//  (4) message start
+//  (12) command
+//  (4) size
+//  (4) checksum
+
+extern char pchMessageStart[4];
+
+class CMessageHeader
+{
+public:
+    enum { COMMAND_SIZE=12 };
+    char pchMessageStart[sizeof(::pchMessageStart)];
+    char pchCommand[COMMAND_SIZE];
+    unsigned int nMessageSize;
+    unsigned int nChecksum;
+
+    CMessageHeader()
+    {
+        memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
+        memset(pchCommand, 0, sizeof(pchCommand));
+        pchCommand[1] = 1;
+        nMessageSize = -1;
+        nChecksum = 0;
+    }
+
+    CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
+    {
+        memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
+        strncpy(pchCommand, pszCommand, COMMAND_SIZE);
+        nMessageSize = nMessageSizeIn;
+        nChecksum = 0;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(FLATDATA(pchMessageStart));
+        READWRITE(FLATDATA(pchCommand));
+        READWRITE(nMessageSize);
+        if (nVersion >= 209)
+            READWRITE(nChecksum);
+    )
+
+    string GetCommand()
+    {
+        if (pchCommand[COMMAND_SIZE-1] == 0)
+            return string(pchCommand, pchCommand + strlen(pchCommand));
+        else
+            return string(pchCommand, pchCommand + COMMAND_SIZE);
+    }
+
+    bool IsValid()
+    {
+        // Check start string
+        if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
+            return false;
+
+        // Check the command string for errors
+        for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
+        {
+            if (*p1 == 0)
+            {
+                // Must be all zeros after the first zero
+                for (; p1 < pchCommand + COMMAND_SIZE; p1++)
+                    if (*p1 != 0)
+                        return false;
+            }
+            else if (*p1 < ' ' || *p1 > 0x7E)
+                return false;
+        }
+
+        // Message size
+        if (nMessageSize > MAX_SIZE)
+        {
+            printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize);
+            return false;
+        }
+
+        return true;
+    }
+};
+
+
+
+
+
+
+static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
+
+class CAddress
+{
+public:
+    uint64 nServices;
+    unsigned char pchReserved[12];
+    unsigned int ip;
+    unsigned short port;
+
+    // disk and network only
+    unsigned int nTime;
+
+    // memory only
+    unsigned int nLastTry;
+
+    CAddress()
+    {
+        Init();
+    }
+
+    CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        ip = ipIn;
+        port = (portIn == 0 ? GetDefaultPort() : portIn);
+        nServices = nServicesIn;
+    }
+
+    explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        ip = sockaddr.sin_addr.s_addr;
+        port = sockaddr.sin_port;
+        nServices = nServicesIn;
+    }
+
+    explicit CAddress(const char* pszIn, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        SetAddress(pszIn);
+        nServices = nServicesIn;
+    }
+
+    explicit CAddress(string strIn, uint64 nServicesIn=NODE_NETWORK)
+    {
+        Init();
+        SetAddress(strIn.c_str());
+        nServices = nServicesIn;
+    }
+
+    void Init()
+    {
+        nServices = NODE_NETWORK;
+        memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
+        ip = INADDR_NONE;
+        port = GetDefaultPort();
+        nTime = 100000000;
+        nLastTry = 0;
+    }
+
+    bool SetAddress(const char* pszIn)
+    {
+        ip = INADDR_NONE;
+        port = GetDefaultPort();
+        char psz[100];
+        strlcpy(psz, pszIn, sizeof(psz));
+        unsigned int a=0, b=0, c=0, d=0, e=0;
+        if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4)
+            return false;
+        char* pszPort = strchr(psz, ':');
+        if (pszPort)
+        {
+            *pszPort++ = '\0';
+            port = htons(atoi(pszPort));
+            if (atoi(pszPort) < 0 || atoi(pszPort) > USHRT_MAX)
+                port = htons(USHRT_MAX);
+        }
+        ip = inet_addr(psz);
+        return IsValid();
+    }
+
+    bool SetAddress(string strIn)
+    {
+        return SetAddress(strIn.c_str());
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        if (fRead)
+            const_cast<CAddress*>(this)->Init();
+        if (nType & SER_DISK)
+            READWRITE(nVersion);
+        if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
+            READWRITE(nTime);
+        READWRITE(nServices);
+        READWRITE(FLATDATA(pchReserved)); // for IPv6
+        READWRITE(ip);
+        READWRITE(port);
+    )
+
+    friend inline bool operator==(const CAddress& a, const CAddress& b)
+    {
+        return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
+                a.ip   == b.ip &&
+                a.port == b.port);
+    }
+
+    friend inline bool operator!=(const CAddress& a, const CAddress& b)
+    {
+        return (!(a == b));
+    }
+
+    friend inline bool operator<(const CAddress& a, const CAddress& b)
+    {
+        int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
+        if (ret < 0)
+            return true;
+        else if (ret == 0)
+        {
+            if (ntohl(a.ip) < ntohl(b.ip))
+                return true;
+            else if (a.ip == b.ip)
+                return ntohs(a.port) < ntohs(b.port);
+        }
+        return false;
+    }
+
+    vector<unsigned char> GetKey() const
+    {
+        CDataStream ss;
+        ss.reserve(18);
+        ss << FLATDATA(pchReserved) << ip << port;
+
+        #if defined(_MSC_VER) && _MSC_VER < 1300
+        return vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
+        #else
+        return vector<unsigned char>(ss.begin(), ss.end());
+        #endif
+    }
+
+    struct sockaddr_in GetSockAddr() const
+    {
+        struct sockaddr_in sockaddr;
+        memset(&sockaddr, 0, sizeof(sockaddr));
+        sockaddr.sin_family = AF_INET;
+        sockaddr.sin_addr.s_addr = ip;
+        sockaddr.sin_port = port;
+        return sockaddr;
+    }
+
+    bool IsIPv4() const
+    {
+        return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
+    }
+
+    bool IsRoutable() const
+    {
+        return IsValid() &&
+            !(GetByte(3) == 10 ||
+              (GetByte(3) == 192 && GetByte(2) == 168) ||
+              GetByte(3) == 127 ||
+              GetByte(3) == 0);
+    }
+
+    bool IsValid() const
+    {
+        // Clean up 3-byte shifted addresses caused by garbage in size field
+        // of addr messages from versions before 0.2.9 checksum.
+        // Two consecutive addr messages look like this:
+        // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
+        // so if the first length field is garbled, it reads the second batch
+        // of addr misaligned by 3 bytes.
+        if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
+            return false;
+
+        return (ip != 0 && ip != INADDR_NONE && port != htons(USHRT_MAX));
+    }
+
+    unsigned char GetByte(int n) const
+    {
+        return ((unsigned char*)&ip)[3-n];
+    }
+
+    string ToStringIPPort() const
+    {
+        return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
+    }
+
+    string ToStringIP() const
+    {
+        return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
+    }
+
+    string ToStringPort() const
+    {
+        return strprintf("%u", ntohs(port));
+    }
+
+    string ToStringLog() const
+    {
+        return "";
+    }
+
+    string ToString() const
+    {
+        return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
+    }
+
+    void print() const
+    {
+        printf("CAddress(%s)\n", ToString().c_str());
+    }
+};
+
+
+
+
+
+
+
+enum
+{
+    MSG_TX = 1,
+    MSG_BLOCK,
+};
+
+static const char* ppszTypeName[] =
+{
+    "ERROR",
+    "tx",
+    "block",
+};
+
+class CInv
+{
+public:
+    int type;
+    uint256 hash;
+
+    CInv()
+    {
+        type = 0;
+        hash = 0;
+    }
+
+    CInv(int typeIn, const uint256& hashIn)
+    {
+        type = typeIn;
+        hash = hashIn;
+    }
+
+    CInv(const string& strType, const uint256& hashIn)
+    {
+        int i;
+        for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
+        {
+            if (strType == ppszTypeName[i])
+            {
+                type = i;
+                break;
+            }
+        }
+        if (i == ARRAYLEN(ppszTypeName))
+            throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
+        hash = hashIn;
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(type);
+        READWRITE(hash);
+    )
+
+    friend inline bool operator<(const CInv& a, const CInv& b)
+    {
+        return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
+    }
+
+    bool IsKnownType() const
+    {
+        return (type >= 1 && type < ARRAYLEN(ppszTypeName));
+    }
+
+    const char* GetCommand() const
+    {
+        if (!IsKnownType())
+            throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
+        return ppszTypeName[type];
+    }
+
+    string ToString() const
+    {
+        return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
+    }
+
+    void print() const
+    {
+        printf("CInv(%s)\n", ToString().c_str());
+    }
+};
+
+
+
+
+
+class CRequestTracker
+{
+public:
+    void (*fn)(void*, CDataStream&);
+    void* param1;
+
+    explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
+    {
+        fn = fnIn;
+        param1 = param1In;
+    }
+
+    bool IsNull()
+    {
+        return fn == NULL;
+    }
+};
+
+
+
+
+
+extern bool fClient;
+extern uint64 nLocalServices;
+extern CAddress addrLocalHost;
+extern CNode* pnodeLocalHost;
+extern uint64 nLocalHostNonce;
+extern array<int, 10> vnThreadsRunning;
+extern SOCKET hListenSocket;
+
+extern vector<CNode*> vNodes;
+extern CCriticalSection cs_vNodes;
+extern map<vector<unsigned char>, CAddress> mapAddresses;
+extern CCriticalSection cs_mapAddresses;
+extern map<CInv, CDataStream> mapRelay;
+extern deque<pair<int64, CInv> > vRelayExpiration;
+extern CCriticalSection cs_mapRelay;
+extern map<CInv, int64> mapAlreadyAskedFor;
+
+// Settings
+extern int fUseProxy;
+extern CAddress addrProxy;
+
+
+
+
+
+
+class CNode
+{
+public:
+    // socket
+    uint64 nServices;
+    SOCKET hSocket;
+    CDataStream vSend;
+    CDataStream vRecv;
+    CCriticalSection cs_vSend;
+    CCriticalSection cs_vRecv;
+    int64 nLastSend;
+    int64 nLastRecv;
+    int64 nLastSendEmpty;
+    int64 nTimeConnected;
+    unsigned int nHeaderStart;
+    unsigned int nMessageStart;
+    CAddress addr;
+    int nVersion;
+    string strSubVer;
+    bool fClient;
+    bool fInbound;
+    bool fNetworkNode;
+    bool fSuccessfullyConnected;
+    bool fDisconnect;
+protected:
+    int nRefCount;
+public:
+    int64 nReleaseTime;
+    map<uint256, CRequestTracker> mapRequests;
+    CCriticalSection cs_mapRequests;
+    uint256 hashContinue;
+    CBlockIndex* pindexLastGetBlocksBegin;
+    uint256 hashLastGetBlocksEnd;
+    int nStartingHeight;
+
+    // flood relay
+    vector<CAddress> vAddrToSend;
+    set<CAddress> setAddrKnown;
+    bool fGetAddr;
+    set<uint256> setKnown;
+
+    // inventory based relay
+    set<CInv> setInventoryKnown;
+    vector<CInv> vInventoryToSend;
+    CCriticalSection cs_inventory;
+    multimap<int64, CInv> mapAskFor;
+
+    // publish and subscription
+    vector<char> vfSubscribe;
+
+
+    CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
+    {
+        nServices = 0;
+        hSocket = hSocketIn;
+        vSend.SetType(SER_NETWORK);
+        vSend.SetVersion(0);
+        vRecv.SetType(SER_NETWORK);
+        vRecv.SetVersion(0);
+        // Version 0.2 obsoletes 20 Feb 2012
+        if (GetTime() > 1329696000)
+        {
+            vSend.SetVersion(209);
+            vRecv.SetVersion(209);
+        }
+        nLastSend = 0;
+        nLastRecv = 0;
+        nLastSendEmpty = GetTime();
+        nTimeConnected = GetTime();
+        nHeaderStart = -1;
+        nMessageStart = -1;
+        addr = addrIn;
+        nVersion = 0;
+        strSubVer = "";
+        fClient = false; // set by version message
+        fInbound = fInboundIn;
+        fNetworkNode = false;
+        fSuccessfullyConnected = false;
+        fDisconnect = false;
+        nRefCount = 0;
+        nReleaseTime = 0;
+        hashContinue = 0;
+        pindexLastGetBlocksBegin = 0;
+        hashLastGetBlocksEnd = 0;
+        nStartingHeight = -1;
+        fGetAddr = false;
+        vfSubscribe.assign(256, false);
+
+        // Be shy and don't send version until we hear
+        if (!fInbound)
+            PushVersion();
+    }
+
+    ~CNode()
+    {
+        if (hSocket != INVALID_SOCKET)
+        {
+            closesocket(hSocket);
+            hSocket = INVALID_SOCKET;
+        }
+    }
+
+private:
+    CNode(const CNode&);
+    void operator=(const CNode&);
+public:
+
+
+    int GetRefCount()
+    {
+        return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
+    }
+
+    CNode* AddRef(int64 nTimeout=0)
+    {
+        if (nTimeout != 0)
+            nReleaseTime = max(nReleaseTime, GetTime() + nTimeout);
+        else
+            nRefCount++;
+        return this;
+    }
+
+    void Release()
+    {
+        nRefCount--;
+    }
+
+
+
+    void AddAddressKnown(const CAddress& addr)
+    {
+        setAddrKnown.insert(addr);
+    }
+
+    void PushAddress(const CAddress& addr)
+    {
+        // Known checking here is only to save space from duplicates.
+        // SendMessages will filter it again for knowns that were added
+        // after addresses were pushed.
+        if (addr.IsValid() && !setAddrKnown.count(addr))
+            vAddrToSend.push_back(addr);
+    }
+
+
+    void AddInventoryKnown(const CInv& inv)
+    {
+        CRITICAL_BLOCK(cs_inventory)
+            setInventoryKnown.insert(inv);
+    }
+
+    void PushInventory(const CInv& inv)
+    {
+        CRITICAL_BLOCK(cs_inventory)
+            if (!setInventoryKnown.count(inv))
+                vInventoryToSend.push_back(inv);
+    }
+
+    void AskFor(const CInv& inv)
+    {
+        // We're using mapAskFor as a priority queue,
+        // the key is the earliest time the request can be sent
+        int64& nRequestTime = mapAlreadyAskedFor[inv];
+        printf("askfor %s   %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
+
+        // Make sure not to reuse time indexes to keep things in the same order
+        int64 nNow = (GetTime() - 1) * 1000000;
+        static int64 nLastTime;
+        nLastTime = nNow = max(nNow, ++nLastTime);
+
+        // Each retry is 2 minutes after the last
+        nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow);
+        mapAskFor.insert(make_pair(nRequestTime, inv));
+    }
+
+
+
+    void BeginMessage(const char* pszCommand)
+    {
+        cs_vSend.Enter();
+        if (nHeaderStart != -1)
+            AbortMessage();
+        nHeaderStart = vSend.size();
+        vSend << CMessageHeader(pszCommand, 0);
+        nMessageStart = vSend.size();
+        if (fDebug)
+            printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+        printf("sending: %s ", pszCommand);
+    }
+
+    void AbortMessage()
+    {
+        if (nHeaderStart == -1)
+            return;
+        vSend.resize(nHeaderStart);
+        nHeaderStart = -1;
+        nMessageStart = -1;
+        cs_vSend.Leave();
+        printf("(aborted)\n");
+    }
+
+    void EndMessage()
+    {
+        if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
+        {
+            printf("dropmessages DROPPING SEND MESSAGE\n");
+            AbortMessage();
+            return;
+        }
+
+        if (nHeaderStart == -1)
+            return;
+
+        // 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");
+
+        nHeaderStart = -1;
+        nMessageStart = -1;
+        cs_vSend.Leave();
+    }
+
+    void EndMessageAbortIfEmpty()
+    {
+        if (nHeaderStart == -1)
+            return;
+        int nSize = vSend.size() - nMessageStart;
+        if (nSize > 0)
+            EndMessage();
+        else
+            AbortMessage();
+    }
+
+
+
+    void PushVersion()
+    {
+        /// when NTP implemented, change to just nTime = GetAdjustedTime()
+        int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
+        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), nBestHeight);
+    }
+
+
+
+
+    void PushMessage(const char* pszCommand)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1>
+    void PushMessage(const char* pszCommand, const T1& a1)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+
+    void PushRequest(const char* pszCommand,
+                     void (*fn)(void*, CDataStream&), void* param1)
+    {
+        uint256 hashReply;
+        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
+
+        CRITICAL_BLOCK(cs_mapRequests)
+            mapRequests[hashReply] = CRequestTracker(fn, param1);
+
+        PushMessage(pszCommand, hashReply);
+    }
+
+    template<typename T1>
+    void PushRequest(const char* pszCommand, const T1& a1,
+                     void (*fn)(void*, CDataStream&), void* param1)
+    {
+        uint256 hashReply;
+        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
+
+        CRITICAL_BLOCK(cs_mapRequests)
+            mapRequests[hashReply] = CRequestTracker(fn, param1);
+
+        PushMessage(pszCommand, hashReply, a1);
+    }
+
+    template<typename T1, typename T2>
+    void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
+                     void (*fn)(void*, CDataStream&), void* param1)
+    {
+        uint256 hashReply;
+        RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
+
+        CRITICAL_BLOCK(cs_mapRequests)
+            mapRequests[hashReply] = CRequestTracker(fn, param1);
+
+        PushMessage(pszCommand, hashReply, a1, a2);
+    }
+
+
+
+    void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
+    bool IsSubscribed(unsigned int nChannel);
+    void Subscribe(unsigned int nChannel, unsigned int nHops=0);
+    void CancelSubscribe(unsigned int nChannel);
+    void CloseSocketDisconnect();
+    void Cleanup();
+};
+
+
+
+
+
+
+
+
+
+
+inline void RelayInventory(const CInv& inv)
+{
+    // Put on lists to offer to the other nodes
+    CRITICAL_BLOCK(cs_vNodes)
+        foreach(CNode* pnode, vNodes)
+            pnode->PushInventory(inv);
+}
+
+template<typename T>
+void RelayMessage(const CInv& inv, const T& a)
+{
+    CDataStream ss(SER_NETWORK);
+    ss.reserve(10000);
+    ss << a;
+    RelayMessage(inv, ss);
+}
+
+template<>
+inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
+{
+    CRITICAL_BLOCK(cs_mapRelay)
+    {
+        // Expire old relay messages
+        while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
+        {
+            mapRelay.erase(vRelayExpiration.front().second);
+            vRelayExpiration.pop_front();
+        }
+
+        // Save original serialized message so newer versions are preserved
+        mapRelay[inv] = ss;
+        vRelayExpiration.push_back(make_pair(GetTime() + 15 * 60, inv));
+    }
+
+    RelayInventory(inv);
+}
+
+
+
+
+
+
+
+
+//
+// Templates for the publish and subscription system.
+// The object being published as T& obj needs to have:
+//   a set<unsigned int> setSources member
+//   specializations of AdvertInsert and AdvertErase
+// Currently implemented for CTable and CProduct.
+//
+
+template<typename T>
+void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
+{
+    // Add to sources
+    obj.setSources.insert(pfrom->addr.ip);
+
+    if (!AdvertInsert(obj))
+        return;
+
+    // Relay
+    CRITICAL_BLOCK(cs_vNodes)
+        foreach(CNode* pnode, vNodes)
+            if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
+                pnode->PushMessage("publish", nChannel, nHops, obj);
+}
+
+template<typename T>
+void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
+{
+    uint256 hash = obj.GetHash();
+
+    CRITICAL_BLOCK(cs_vNodes)
+        foreach(CNode* pnode, vNodes)
+            if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
+                pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
+
+    AdvertErase(obj);
+}
+
+template<typename T>
+void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
+{
+    // Remove a source
+    obj.setSources.erase(pfrom->addr.ip);
+
+    // If no longer supported by any sources, cancel it
+    if (obj.setSources.empty())
+        AdvertStopPublish(pfrom, nChannel, nHops, obj);
+}