From ead61e35365cfec10c0c3e817e5c8d917b157681 Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Tue, 26 Jul 2022 12:18:56 +0100 Subject: [PATCH 1/3] Prevent closing of sockets in use --- src/masternodes/anchors.cpp | 30 +---- src/masternodes/anchors.h | 7 +- src/spv/bitcoin/BRPeer.cpp | 240 ++++++++++-------------------------- src/spv/bitcoin/BRPeer.h | 24 ---- src/spv/spv_rpc.cpp | 8 ++ src/spv/spv_wrapper.cpp | 58 ++------- src/spv/spv_wrapper.h | 15 +-- 7 files changed, 101 insertions(+), 281 deletions(-) diff --git a/src/masternodes/anchors.cpp b/src/masternodes/anchors.cpp index 21f6c717aa..a2b9f6287d 100644 --- a/src/masternodes/anchors.cpp +++ b/src/masternodes/anchors.cpp @@ -338,7 +338,7 @@ void CAnchorAuthIndex::PruneOlderThan(THeight height) } CAnchorIndex::CAnchorIndex(size_t nCacheSize, bool fMemory, bool fWipe) - : db(new CDBWrapper(GetDataDir() / "anchors", nCacheSize, fMemory, fWipe)) + : db(std::make_unique(GetDataDir() / "anchors", nCacheSize, fMemory, fWipe)) { } @@ -522,8 +522,7 @@ void CAnchorIndex::CheckPendingAnchors() continue; } - const auto timestamp = spv::pspv->ReadTxTimestamp(rec.txHash); - const auto blockHeight = spv::pspv->ReadTxBlockHeight(rec.txHash); + const auto [blockHeight, timestamp] = spv::pspv->ReadTxHeightTime(rec.txHash); const auto blockHash = panchors->ReadBlockHash(rec.btcHeight); // Do not delete, TX time still pending. If block height is set to max we cannot trust the timestamp. @@ -669,15 +668,10 @@ bool CAnchorIndex::ActivateBestAnchor(bool forced) return top != oldTop; } -bool CAnchorIndex::AddToAnchorPending(CAnchor const & anchor, uint256 const & btcTxHash, THeight btcBlockHeight, bool overwrite) +bool CAnchorIndex::AddToAnchorPending(const AnchorRec& rec) { AssertLockHeld(cs_main); - AnchorRec rec{ anchor, btcTxHash, btcBlockHeight }; - if (overwrite) { - DeletePendingByBtcTx(btcTxHash); - } - return db->Write(std::make_pair(DB_PENDING, rec.txHash), rec); } @@ -688,20 +682,13 @@ bool CAnchorIndex::GetPendingByBtcTx(uint256 const & txHash, AnchorRec & rec) co return db->Read(std::make_pair(DB_PENDING, txHash), rec); } -bool CAnchorIndex::DeletePendingByBtcTx(uint256 const & btcTxHash) +void CAnchorIndex::DeletePendingByBtcTx(uint256 const & btcTxHash) { AssertLockHeld(cs_main); - AnchorRec pending; - - if (GetPendingByBtcTx(btcTxHash, pending)) { - if (db->Exists(std::make_pair(DB_PENDING, btcTxHash))) { - db->Erase(std::make_pair(DB_PENDING, btcTxHash)); - } - return true; + if (db->Exists(std::make_pair(DB_PENDING, btcTxHash))) { + db->Erase(std::make_pair(DB_PENDING, btcTxHash)); } - - return false; } bool CAnchorIndex::WriteBlock(const uint32_t height, const uint256& blockHash) @@ -729,11 +716,6 @@ bool CAnchorIndex::DbExists(const uint256 & hash) const return db->Exists(std::make_pair(DB_ANCHORS, hash)); } -bool CAnchorIndex::DbRead(uint256 const & hash, AnchorRec & rec) const -{ - return db->Read(std::make_pair(DB_ANCHORS, hash), rec); -} - bool CAnchorIndex::DbWrite(AnchorRec const & rec) { return db->Write(std::make_pair(DB_ANCHORS, rec.txHash), rec); diff --git a/src/masternodes/anchors.h b/src/masternodes/anchors.h index 713b058425..cfa9a8f8fc 100644 --- a/src/masternodes/anchors.h +++ b/src/masternodes/anchors.h @@ -186,7 +186,7 @@ class CAnchorAuthIndex class CAnchorIndex { private: - std::shared_ptr db; + std::unique_ptr db; std::unique_ptr batch; public: using Signature = std::vector; @@ -248,9 +248,9 @@ class CAnchorIndex void UpdateLastHeight(uint32_t height); // Post-fork anchor pending, requires chain context to validate. Some pending may be bogus, intentional or not. - bool AddToAnchorPending(CAnchor const & anchor, uint256 const & btcTxHash, THeight btcBlockHeight, bool overwrite = false); + bool AddToAnchorPending(const AnchorRec& rec); bool GetPendingByBtcTx(uint256 const & txHash, AnchorRec & rec) const; - bool DeletePendingByBtcTx(uint256 const & btcTxHash); + void DeletePendingByBtcTx(uint256 const & btcTxHash); void ForEachPending(std::function callback); // Used to apply chain context to post-fork anchors which get added to pending. @@ -297,7 +297,6 @@ class CAnchorIndex } bool DbExists(uint256 const & hash) const; - bool DbRead(uint256 const & hash, AnchorRec & anchor) const; bool DbWrite(AnchorRec const & anchor); bool DbErase(uint256 const & hash); }; diff --git a/src/spv/bitcoin/BRPeer.cpp b/src/spv/bitcoin/BRPeer.cpp index bf044063cf..d2a39d40c1 100644 --- a/src/spv/bitcoin/BRPeer.cpp +++ b/src/spv/bitcoin/BRPeer.cpp @@ -23,13 +23,14 @@ // THE SOFTWARE. #include "BRPeer.h" -#include "BRMerkleBlock.h" #include "BRAddress.h" -#include "BRSet.h" #include "BRArray.h" #include "BRCrypto.h" #include "BRInt.h" -#include +#include "BRMerkleBlock.h" +#include "BRSet.h" +#include +#include #include #include @@ -38,16 +39,6 @@ #include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include - #define HEADER_LENGTH 24 #define MAX_MSG_LENGTH 0x02000000 #define MAX_GETDATA_HASHES 50000 @@ -569,7 +560,7 @@ static int _BRPeerAcceptGetdataMessage(BRPeer *peer, const uint8_t *msg, size_t } peer_log(peer, "publishing tx: %s", txHex.c_str()); - BRPeerSendMessage(peer, buf.data(), bufLen, MSG_TX); + BRPeerSendMessage(peer, buf.data(), bufLen, NetMsgType::TX); break; } @@ -592,7 +583,7 @@ static int _BRPeerAcceptGetdataMessage(BRPeer *peer, const uint8_t *msg, size_t memcpy(&buf[o], notfound, 36*array_count(notfound)); o += 36*array_count(notfound); array_free(notfound); - BRPeerSendMessage(peer, buf.data(), o, MSG_NOTFOUND); + BRPeerSendMessage(peer, buf.data(), o, NetMsgType::NOTFOUND); } } @@ -659,7 +650,7 @@ static int _BRPeerAcceptPingMessage(BRPeer *peer, const uint8_t *msg, size_t msg } else { peer_log(peer, "got ping"); - BRPeerSendMessage(peer, msg, msgLen, MSG_PONG); + BRPeerSendMessage(peer, msg, msgLen, NetMsgType::PONG); } return r; @@ -780,7 +771,7 @@ static int _BRPeerAcceptRejectMessage(BRPeer *peer, const uint8_t *msg, size_t m code = msg[off++]; strLen = (size_t)BRVarInt(&msg[off], (off <= msgLen ? msgLen - off : 0), &len); off += len; - if (type == MSG_TX) hashLen = sizeof(UInt256); + if (type == NetMsgType::TX) hashLen = sizeof(UInt256); if (off + strLen + hashLen > msgLen) { peer_log(peer, "malformed reject message, length is %zu, should be >= %zu", msgLen, off + strLen + hashLen); @@ -832,142 +823,37 @@ static int _BRPeerAcceptMessage(BRPeer *peer, const uint8_t *msg, size_t msgLen, BRPeerContext *ctx = (BRPeerContext *)peer; int r = 1; - if (ctx->currentBlock && strncmp(MSG_TX, type, 12) != 0) { // if we receive a non-tx message, merkleblock is done + if (ctx->currentBlock && strncmp(NetMsgType::TX, type, 12) != 0) { // if we receive a non-tx message, merkleblock is done peer_log(peer, "incomplete merkleblock %s, expected %zu more tx, got %s", u256hex(ctx->currentBlock->blockHash).c_str(), array_count(ctx->currentBlockTxHashes), type); array_clear(ctx->currentBlockTxHashes); ctx->currentBlock = NULL; r = 0; } - else if (strncmp(MSG_VERSION, type, 12) == 0) r = _BRPeerAcceptVersionMessage(peer, msg, msgLen); - else if (strncmp(MSG_VERACK, type, 12) == 0) r = _BRPeerAcceptVerackMessage(peer, msg, msgLen); - else if (strncmp(MSG_ADDR, type, 12) == 0) r = _BRPeerAcceptAddrMessage(peer, msg, msgLen); - else if (strncmp(MSG_INV, type, 12) == 0) r = _BRPeerAcceptInvMessage(peer, msg, msgLen); - else if (strncmp(MSG_TX, type, 12) == 0) r = _BRPeerAcceptTxMessage(peer, msg, msgLen); - else if (strncmp(MSG_HEADERS, type, 12) == 0) r = _BRPeerAcceptHeadersMessage(peer, msg, msgLen); - else if (strncmp(MSG_GETADDR, type, 12) == 0) r = _BRPeerAcceptGetaddrMessage(peer, msg, msgLen); - else if (strncmp(MSG_GETDATA, type, 12) == 0) r = _BRPeerAcceptGetdataMessage(peer, msg, msgLen); - else if (strncmp(MSG_NOTFOUND, type, 12) == 0) r = _BRPeerAcceptNotfoundMessage(peer, msg, msgLen); - else if (strncmp(MSG_PING, type, 12) == 0) r = _BRPeerAcceptPingMessage(peer, msg, msgLen); - else if (strncmp(MSG_PONG, type, 12) == 0) r = _BRPeerAcceptPongMessage(peer, msg, msgLen); - else if (strncmp(MSG_MERKLEBLOCK, type, 12) == 0) r = _BRPeerAcceptMerkleblockMessage(peer, msg, msgLen); - else if (strncmp(MSG_REJECT, type, 12) == 0) r = _BRPeerAcceptRejectMessage(peer, msg, msgLen); - else if (strncmp(MSG_FEEFILTER, type, 12) == 0) r = _BRPeerAcceptFeeFilterMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::VERSION, type, 12) == 0) r = _BRPeerAcceptVersionMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::VERACK, type, 12) == 0) r = _BRPeerAcceptVerackMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::ADDR, type, 12) == 0) r = _BRPeerAcceptAddrMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::INV, type, 12) == 0) r = _BRPeerAcceptInvMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::TX, type, 12) == 0) r = _BRPeerAcceptTxMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::HEADERS, type, 12) == 0) r = _BRPeerAcceptHeadersMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::GETADDR, type, 12) == 0) r = _BRPeerAcceptGetaddrMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::GETDATA, type, 12) == 0) r = _BRPeerAcceptGetdataMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::NOTFOUND, type, 12) == 0) r = _BRPeerAcceptNotfoundMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::PING, type, 12) == 0) r = _BRPeerAcceptPingMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::PONG, type, 12) == 0) r = _BRPeerAcceptPongMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::MERKLEBLOCK, type, 12) == 0) r = _BRPeerAcceptMerkleblockMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::REJECT, type, 12) == 0) r = _BRPeerAcceptRejectMessage(peer, msg, msgLen); + else if (strncmp(NetMsgType::FEEFILTER, type, 12) == 0) r = _BRPeerAcceptFeeFilterMessage(peer, msg, msgLen); else peer_log(peer, "dropping %s, length %zu, not implemented", type, msgLen); return r; } -static int _BRPeerOpenSocket(BRPeer *peer, int domain, double timeout, int *error) -{ - BRPeerContext *ctx = (BRPeerContext *)peer; - struct sockaddr_storage addr; - struct timeval tv; - fd_set fds; - socklen_t addrLen, optLen; - int count, arg = 0, err = 0, on = 1, r = 1; - SOCKET sock = INVALID_SOCKET; - - ctx->lock.lock(); - sock = ctx->socket = socket(domain, SOCK_STREAM, IPPROTO_TCP); - ctx->lock.unlock(); - - if (sock == INVALID_SOCKET) { - err = WSAGetLastError(); - r = 0; - } - else { -#ifdef WIN32 - int set = 1; - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int)); -#else - tv.tv_sec = 1; // one second timeout for send/receive, so thread doesn't block for too long - tv.tv_usec = 0; - setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (sockopt_arg_type) &tv, sizeof(tv)); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (sockopt_arg_type) &tv, sizeof(tv)); - setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (sockopt_arg_type) &on, sizeof(on)); -#ifdef SO_NOSIGPIPE // BSD based systems have a SO_NOSIGPIPE socket option to supress SIGPIPE signals - setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); -#endif -#endif - -#ifdef WIN32 - u_long nBlock = 1; // Non-Blocking - if (ioctlsocket(sock, FIONBIO, &nBlock) == SOCKET_ERROR) { - r = 0; - } -#else - arg = fcntl(sock, F_GETFL, NULL); - if (arg < 0 || fcntl(sock, F_SETFL, arg | O_NONBLOCK) == SOCKET_ERROR) r = 0; // temporarily set socket non-blocking -#endif - if (! r) err = WSAGetLastError(); - } - - if (r) { - memset(&addr, 0, sizeof(addr)); - - if (domain == PF_INET6) { - ((struct sockaddr_in6 *)&addr)->sin6_family = AF_INET6; - ((struct sockaddr_in6 *)&addr)->sin6_addr = *(struct in6_addr *)&peer->address; - ((struct sockaddr_in6 *)&addr)->sin6_port = htons(peer->port); - addrLen = sizeof(struct sockaddr_in6); - } - else { - ((struct sockaddr_in *)&addr)->sin_family = AF_INET; - ((struct sockaddr_in *)&addr)->sin_addr = *(struct in_addr *)&peer->address.u32[3]; - ((struct sockaddr_in *)&addr)->sin_port = htons(peer->port); - addrLen = sizeof(struct sockaddr_in); - } - -#ifdef WIN32 - if (connect(sock, (struct sockaddr *)&addr, addrLen) == SOCKET_ERROR) err = WSAGetLastError(); -#else - if (connect(sock, (struct sockaddr *)&addr, addrLen) < 0) err = errno; -#endif - - // Connection in progress. -#ifdef WIN32 - if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK || err == WSAEINVAL) { -#else - if (err == EINPROGRESS) { -#endif - err = 0; - optLen = sizeof(err); - tv.tv_sec = timeout; - tv.tv_usec = (long)(timeout*1000000) % 1000000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - count = select(sock + 1, NULL, &fds, NULL, &tv); - - if (count <= 0 || getsockopt(sock, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&err, &optLen) == SOCKET_ERROR || err) { - if (count == 0) err = ETIMEDOUT; - if (count < 0 || ! err) err = WSAGetLastError(); - r = 0; - } - } - else if (err) { - r = 0; - } - - if (r) peer_log(peer, "socket connected"); - -#ifdef WIN32 - u_long nZero = 0; - ioctlsocket(sock, FIONBIO, &nZero); -#else - fcntl(sock, F_SETFL, arg); -#endif - } - if (! r && err) peer_log(peer, "connect error: %d: %s", err, strerror(err)); - if (error && err) *error = err; - return r; -} - static int _peerCheckAndGetSocket (BRPeerContext *ctx, SOCKET *socket) { int exists; ctx->lock.lock(); - exists = ctx->socket != INVALID_SOCKET; + exists = ctx->socket >= 0; if (NULL != socket) *socket = ctx->socket; ctx->lock.unlock(); @@ -1013,12 +899,23 @@ static void *_peerThreadRoutine(void *arg) threadCleanup guard(ctx->threadCleanup, ctx->info); - int domain{PF_INET6}; - if (_BRPeerIsIPv4(peer)) { - domain = PF_INET; + const auto hostName{BRPeerHostString(peer)}; + bool connected{false}; + CService resolved; + + if (Lookup(hostName.c_str(), resolved, peer->port, fNameLookup && !HaveNameProxy())) { + CAddress addrConnect{resolved, NODE_NONE}; + + if (addrConnect.IsValid()) { + ctx->socket = CreateSocket(addrConnect); + + if (ctx->socket != INVALID_SOCKET) { + connected = ConnectSocketDirectly(addrConnect, const_cast(ctx->socket), nConnectTimeout, false); + } + } } - - if (_BRPeerOpenSocket(peer, domain, CONNECT_TIMEOUT, &error)) { + + if (connected) { struct timeval tv; double time = 0, msgTimeout; uint8_t header[HEADER_LENGTH], *payload = (uint8_t *)malloc(0x1000); @@ -1034,17 +931,10 @@ static void *_peerThreadRoutine(void *arg) len = 0; while (socket != INVALID_SOCKET && ! error && len < HEADER_LENGTH) { -// n = read(socket, &header[len], sizeof(header) - len); n = recv(socket, (char*)&header[len], sizeof(header) - len, 0); if (n > 0) len += n; if (n == 0) error = ECONNRESET; if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) error = WSAGetLastError(); - if (error == WSAENOTSOCK) { - ctx->lock.lock(); - socket = ctx->socket = INVALID_SOCKET; - ctx->lock.unlock(); - continue; - } gettimeofday(&tv, NULL); time = tv.tv_sec + (double)tv.tv_usec/1000000; if (! error && time >= _peerGetDisconnectTime(ctx)) error = ETIMEDOUT; @@ -1091,17 +981,10 @@ static void *_peerThreadRoutine(void *arg) msgTimeout = time + MESSAGE_TIMEOUT; while (socket != INVALID_SOCKET && ! error && len < msgLen) { -// n = read(socket, &payload[len], msgLen - len); n = recv(socket, (char *) &payload[len], msgLen - len, 0); if (n > 0) len += n; if (n == 0) error = ECONNRESET; if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) error = WSAGetLastError(); - if (error == WSAENOTSOCK) { - ctx->lock.lock(); - socket = ctx->socket = INVALID_SOCKET; - ctx->lock.unlock(); - continue; - } gettimeofday(&tv, NULL); time = tv.tv_sec + (double)tv.tv_usec/1000000; if (n > 0) msgTimeout = time + MESSAGE_TIMEOUT; @@ -1131,15 +1014,21 @@ static void *_peerThreadRoutine(void *arg) ctx->lock.lock(); socket = ctx->socket; - ctx->status = BRPeerStatusDisconnected; + const auto status = ctx->status; ctx->lock.unlock(); - if (socket != INVALID_SOCKET) { + if (status != BRPeerStatusDisconnected) { + if (socket != INVALID_SOCKET) { #ifdef WIN32 - closesocket(socket); + closesocket(socket); #else - close(socket); + close(socket); #endif + } + + ctx->lock.lock(); + ctx->status = BRPeerStatusDisconnected; + ctx->lock.unlock(); } peer_log(peer, "disconnected"); @@ -1297,9 +1186,14 @@ int BRPeerConnect(BRPeer *peer) void BRPeerDisconnect(BRPeer *peer) { BRPeerContext *ctx = (BRPeerContext *)peer; + + ctx->lock.lock(); + const auto status = ctx->status; + ctx->lock.unlock(); + SOCKET socket = INVALID_SOCKET; - if (_peerCheckAndGetSocket(ctx, &socket)) { + if (status != BRPeerStatusDisconnected && _peerCheckAndGetSocket(ctx, &socket)) { ctx->lock.lock(); ctx->status = BRPeerStatusDisconnected; ctx->lock.unlock(); @@ -1490,12 +1384,12 @@ void BRPeerSendVersionMessage(BRPeer *peer) UInt32SetLE(&msg[off], 0); // last block received off += sizeof(uint32_t); msg[off++] = 0; // relay transactions (0 for SPV bloom filter mode) - BRPeerSendMessage(peer, msg.data(), msg.size(), MSG_VERSION); + BRPeerSendMessage(peer, msg.data(), msg.size(), NetMsgType::VERSION); } void BRPeerSendVerackMessage(BRPeer *peer) { - BRPeerSendMessage(peer, NULL, 0, MSG_VERACK); + BRPeerSendMessage(peer, NULL, 0, NetMsgType::VERACK); ((BRPeerContext *)peer)->sentVerack = 1; } @@ -1505,14 +1399,14 @@ void BRPeerSendAddr(BRPeer *peer) size_t msgLen = BRVarIntSet(msg.data(), msg.size(), 0); //TODO: send peer addresses we know about - BRPeerSendMessage(peer, msg.data(), msgLen, MSG_ADDR); + BRPeerSendMessage(peer, msg.data(), msgLen, NetMsgType::ADDR); } void BRPeerSendFilterload(BRPeer *peer, const uint8_t *filter, size_t filterLen) { ((BRPeerContext *)peer)->sentFilter = 1; ((BRPeerContext *)peer)->sentMempool = 0; - BRPeerSendMessage(peer, filter, filterLen, MSG_FILTERLOAD); + BRPeerSendMessage(peer, filter, filterLen, NetMsgType::FILTERLOAD); } void BRPeerSendMempool(BRPeer *peer, const UInt256 knownTxHashes[], size_t knownTxCount, void *info, @@ -1538,7 +1432,7 @@ void BRPeerSendMempool(BRPeer *peer, const UInt256 knownTxHashes[], size_t known ctx->mempoolCallback = completionCallback; } - BRPeerSendMessage(peer, NULL, 0, MSG_MEMPOOL); + BRPeerSendMessage(peer, NULL, 0, NetMsgType::MEMPOOL); } else { peer_log(peer, "mempool request already sent"); @@ -1567,7 +1461,7 @@ void BRPeerSendGetheaders(BRPeer *peer, const UInt256 locators[], size_t locator if (locatorsCount > 0) { peer_log(peer, "calling getheaders with %zu locators: [%s,%s %s]", locatorsCount, u256hex(locators[0]).c_str(), (locatorsCount > 2 ? " ...," : ""), (locatorsCount > 1 ? u256hex(locators[locatorsCount - 1]).c_str() : "")); - BRPeerSendMessage(peer, msg.data(), off, MSG_GETHEADERS); + BRPeerSendMessage(peer, msg.data(), off, NetMsgType::GETHEADERS); } } @@ -1592,7 +1486,7 @@ void BRPeerSendGetblocks(BRPeer *peer, const UInt256 locators[], size_t locators if (locatorsCount > 0) { peer_log(peer, "calling getblocks with %zu locators: [%s,%s %s]", locatorsCount, u256hex(locators[0]).c_str(), (locatorsCount > 2 ? " ...," : ""), (locatorsCount > 1 ? u256hex(locators[locatorsCount - 1]).c_str() : "")); - BRPeerSendMessage(peer, msg.data(), off, MSG_GETBLOCKS); + BRPeerSendMessage(peer, msg.data(), off, NetMsgType::GETBLOCKS); } } @@ -1617,7 +1511,7 @@ void BRPeerSendInv(BRPeer *peer, const UInt256 txHashes[], size_t txCount) off += sizeof(UInt256); } - BRPeerSendMessage(peer, msg.data(), off, MSG_INV); + BRPeerSendMessage(peer, msg.data(), off, NetMsgType::INV); } } @@ -1650,14 +1544,14 @@ void BRPeerSendGetdata(BRPeer *peer, const UInt256 txHashes[], size_t txCount, c } ((BRPeerContext *)peer)->sentGetdata = 1; - BRPeerSendMessage(peer, msg.data(), off, MSG_GETDATA); + BRPeerSendMessage(peer, msg.data(), off, NetMsgType::GETDATA); } } void BRPeerSendGetaddr(BRPeer *peer) { ((BRPeerContext *)peer)->sentGetaddr = 1; - BRPeerSendMessage(peer, NULL, 0, MSG_GETADDR); + BRPeerSendMessage(peer, NULL, 0, NetMsgType::GETADDR); } void BRPeerSendPing(BRPeer *peer, void *info, void (*pongCallback)(void *info, int success)) @@ -1671,7 +1565,7 @@ void BRPeerSendPing(BRPeer *peer, void *info, void (*pongCallback)(void *info, i array_add(ctx->pongInfo, info); array_add(ctx->pongCallback, pongCallback); UInt64SetLE(msg, ctx->nonce); - BRPeerSendMessage(peer, msg, sizeof(msg), MSG_PING); + BRPeerSendMessage(peer, msg, sizeof(msg), NetMsgType::PING); } // useful to get additional tx after a bloom filter update diff --git a/src/spv/bitcoin/BRPeer.h b/src/spv/bitcoin/BRPeer.h index dcb681c761..4971f48f03 100644 --- a/src/spv/bitcoin/BRPeer.h +++ b/src/spv/bitcoin/BRPeer.h @@ -98,30 +98,6 @@ extern boost::mutex log_mutex; #define BR_VERSION "2.1" #define USER_AGENT "/bread:" BR_VERSION "/" -// explanation of message types at: https://en.bitcoin.it/wiki/Protocol_specification -#define MSG_VERSION "version" -#define MSG_VERACK "verack" -#define MSG_ADDR "addr" -#define MSG_INV "inv" -#define MSG_GETDATA "getdata" -#define MSG_NOTFOUND "notfound" -#define MSG_GETBLOCKS "getblocks" -#define MSG_GETHEADERS "getheaders" -#define MSG_TX "tx" -#define MSG_BLOCK "block" -#define MSG_HEADERS "headers" -#define MSG_GETADDR "getaddr" -#define MSG_MEMPOOL "mempool" -#define MSG_PING "ping" -#define MSG_PONG "pong" -#define MSG_FILTERLOAD "filterload" -#define MSG_FILTERADD "filteradd" -#define MSG_FILTERCLEAR "filterclear" -#define MSG_MERKLEBLOCK "merkleblock" -#define MSG_ALERT "alert" -#define MSG_REJECT "reject" // described in BIP61: https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki -#define MSG_FEEFILTER "feefilter"// described in BIP133 https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki - #define REJECT_INVALID 0x10 // transaction is invalid for some reason (invalid signature, output value > input, etc) #define REJECT_SPENT 0x12 // an input is already spent #define REJECT_NONSTANDARD 0x40 // not mined/relayed because it is "non-standard" (type or version unknown by server) diff --git a/src/spv/spv_rpc.cpp b/src/spv/spv_rpc.cpp index a51f6e339f..f4b6c0bb57 100644 --- a/src/spv/spv_rpc.cpp +++ b/src/spv/spv_rpc.cpp @@ -1274,6 +1274,10 @@ static UniValue spv_dumpprivkey(const JSONRPCRequest& request) }, }.Check(request); + if (!spv::pspv) { + throw JSONRPCError(RPC_INVALID_REQUEST, "spv module disabled"); + } + auto locked_chain = pwallet->chain().lock(); LOCK2(pwallet->cs_wallet, locked_chain->mutex()); @@ -1299,6 +1303,10 @@ static UniValue spv_getbalance(const JSONRPCRequest& request) }, }.Check(request); + if (!spv::pspv) { + throw JSONRPCError(RPC_INVALID_REQUEST, "spv module disabled"); + } + return ValueFromAmount(spv::pspv->GetBitcoinBalance()); } diff --git a/src/spv/spv_wrapper.cpp b/src/spv/spv_wrapper.cpp index 6a7ced2ee0..dd9b65f2d9 100644 --- a/src/spv/spv_wrapper.cpp +++ b/src/spv/spv_wrapper.cpp @@ -200,7 +200,7 @@ static void SetCheckpoints() } CSpvWrapper::CSpvWrapper(bool isMainnet, size_t nCacheSize, bool fMemory, bool fWipe) - : db(new CDBWrapper(GetDataDir() / (isMainnet ? "spv" : "spv_testnet"), nCacheSize, fMemory, fWipe)) + : db(std::make_unique(GetDataDir() / (isMainnet ? "spv" : "spv_testnet"), nCacheSize, fMemory, fWipe)) { SetCheckpoints(); @@ -354,12 +354,6 @@ bool CSpvWrapper::Rescan(int height) return true; } -// we cant return the whole params itself due to conflicts in include files -uint8_t CSpvWrapper::GetPKHashPrefix() const -{ - return BRPeerManagerChainParams(manager)->base58_p2pkh; -} - uint8_t CSpvWrapper::GetP2SHPrefix() const { return BRPeerManagerChainParams(manager)->base58_p2sh; @@ -370,11 +364,6 @@ BRWallet * CSpvWrapper::GetWallet() return wallet; } -bool CSpvWrapper::IsInitialSync() const -{ - return initialSync; -} - uint32_t CSpvWrapper::GetLastBlockHeight() const { return BRPeerManagerLastBlockHeight(manager); @@ -391,17 +380,6 @@ void CSpvWrapper::OnBalanceChanged(uint64_t balance) LogPrint(BCLog::SPV, "balance changed: %lu\n", balance); } -std::vector CSpvWrapper::GetWalletTxs() const -{ - std::vector txs; - txs.resize(BRWalletTransactions(wallet, nullptr, 0)); - size_t count = BRWalletTransactions(wallet, txs.data(), txs.size()); - - LogPrint(BCLog::SPV, "wallet txs count: %lu\n", count); - - return txs; -} - void CSpvWrapper::OnTxAdded(BRTransaction * tx) { /// @attention called under spv manager lock!!! @@ -415,7 +393,7 @@ void CSpvWrapper::OnTxAdded(BRTransaction * tx) LogPrint(BCLog::SPV, "IsAnchorTx(): %s\n", txHash.ToString()); LOCK(cs_main); - if (ValidateAnchor(anchor) && panchors->AddToAnchorPending(anchor, txHash, tx->blockHeight)) { + if (ValidateAnchor(anchor) && panchors->AddToAnchorPending({anchor, txHash, tx->blockHeight})) { LogPrint(BCLog::SPV, "adding anchor to pending %s\n", txHash.ToString()); } } @@ -440,7 +418,7 @@ void CSpvWrapper::OnTxUpdated(const UInt256 txHashes[], size_t txCount, uint32_t if (panchors->GetPendingByBtcTx(txHash, oldPending)) { LogPrint(BCLog::SPV, "updating anchor pending %s\n", txHash.ToString()); - if (panchors->AddToAnchorPending(oldPending.anchor, txHash, blockHeight, true)) { + if (panchors->AddToAnchorPending({oldPending.anchor, txHash, blockHeight})) { LogPrint(BCLog::ANCHORING, "Anchor pending added/updated %s\n", txHash.ToString()); } } @@ -583,27 +561,15 @@ void CSpvWrapper::UpdateTx(uint256 const & hash, uint32_t blockHeight, uint32_t panchors->WriteBlock(blockHeight, blockHash); } -uint32_t CSpvWrapper::ReadTxTimestamp(uint256 const & hash) -{ - std::pair const key{std::make_pair(DB_SPVTXS, hash)}; - db_tx_rec txrec; - if (db->Read(key, txrec)) { - return txrec.second.second; - } - - return 0; -} - -uint32_t CSpvWrapper::ReadTxBlockHeight(uint256 const & hash) +std::pair CSpvWrapper::ReadTxHeightTime(uint256 const & hash) { std::pair const key{std::make_pair(DB_SPVTXS, hash)}; db_tx_rec txrec; if (db->Read(key, txrec)) { - return txrec.second.first; + return txrec.second; } - // If not found return the default value of an unconfirmed TX. - return std::numeric_limits::max(); + return {std::numeric_limits::max(), 0}; } void CSpvWrapper::EraseTx(uint256 const & hash) @@ -814,7 +780,7 @@ UniValue CSpvWrapper::ListReceived(int nMinDepth, std::string address) { int32_t confirmations{0}; const auto txHash = to_uint256(txid->txHash); - const auto blockHeight = ReadTxBlockHeight(txHash); + const auto [blockHeight, blocktime] = ReadTxHeightTime(txHash); if (blockHeight != std::numeric_limits::max()) { @@ -897,7 +863,7 @@ UniValue CSpvWrapper::GetHTLCReceived(const std::string& addr) { uint256 txid = to_uint256(txInfo.first->txHash); uint64_t confirmations{0}; - uint32_t blockHeight = ReadTxBlockHeight(txid); + auto [blockHeight, blocktime] = ReadTxHeightTime(txid); if (blockHeight != std::numeric_limits::max()) { @@ -915,11 +881,11 @@ UniValue CSpvWrapper::GetHTLCReceived(const std::string& addr) uint256 spent; if (BRWalletTxSpent(wallet, txInfo.first, output, spent)) { - blockHeight = ReadTxBlockHeight(spent); + const auto [spentHeight, spentTime] = ReadTxHeightTime(spent); confirmations = 0; - if (blockHeight != std::numeric_limits::max()) + if (spentHeight != std::numeric_limits::max()) { - confirmations = spv::pspv->GetLastBlockHeight() - blockHeight + 1; + confirmations = spv::pspv->GetLastBlockHeight() - spentHeight + 1; } UniValue spentItem(UniValue::VOBJ); @@ -1278,7 +1244,7 @@ std::pair CSpvWrapper::CreateHTLCTransaction(CWallet* { // Skip outputs without enough confirms to meet contract requirements if (!seller) { - uint32_t blockHeight = ReadTxBlockHeight(to_uint256(output.first->txHash)); + auto [blockHeight, blocktime] = ReadTxHeightTime(to_uint256(output.first->txHash)); uint64_t confirmations = blockHeight != std::numeric_limits::max() ? spv::pspv->GetLastBlockHeight() - blockHeight + 1 : 0; if (confirmations < script.first.locktime) { continue; diff --git a/src/spv/spv_wrapper.h b/src/spv/spv_wrapper.h index c9e8506478..1ab477ace2 100644 --- a/src/spv/spv_wrapper.h +++ b/src/spv/spv_wrapper.h @@ -79,7 +79,7 @@ using namespace boost::multi_index; class CSpvWrapper { private: - std::shared_ptr db; + std::unique_ptr db; std::unique_ptr batch; BRPeerManager *manager = nullptr; @@ -96,6 +96,7 @@ class CSpvWrapper public: CSpvWrapper(bool isMainnet, size_t nCacheSize, bool fMemory = false, bool fWipe = false); virtual ~CSpvWrapper(); + void Load(); virtual void Connect(); @@ -107,13 +108,10 @@ class CSpvWrapper BRWallet * GetWallet(); - bool IsInitialSync() const; virtual uint32_t GetLastBlockHeight() const; virtual uint32_t GetEstimatedBlockHeight() const; - uint8_t GetPKHashPrefix() const; - uint8_t GetP2SHPrefix() const; - std::vector GetWalletTxs() const; + uint8_t GetP2SHPrefix() const; bool SendRawTx(TBytes rawtx, std::promise * promise = nullptr); @@ -135,11 +133,8 @@ class CSpvWrapper void OnBlockNotify(const UInt256& blockHash); void OnTxNotify(const UInt256& txHash); - // Get time stamp of Bitcoin TX - uint32_t ReadTxTimestamp(uint256 const & hash); - - // Get block height of Bitcoin TX - uint32_t ReadTxBlockHeight(uint256 const & hash); + // Get time stamp and height of Bitcoin TX + std::pair ReadTxHeightTime(uint256 const & hash); // Bitcoin networking calls UniValue GetPeers(); From 08b73176c941727f4c7a89b33f8aded05f8f68aa Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Tue, 26 Jul 2022 16:57:40 +0100 Subject: [PATCH 2/3] Restore time include --- src/spv/bitcoin/BRPeer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spv/bitcoin/BRPeer.cpp b/src/spv/bitcoin/BRPeer.cpp index e942e016e4..15e9420648 100644 --- a/src/spv/bitcoin/BRPeer.cpp +++ b/src/spv/bitcoin/BRPeer.cpp @@ -40,6 +40,8 @@ #include +#include + #define HEADER_LENGTH 24 #define MAX_MSG_LENGTH 0x02000000 #define MAX_GETDATA_HASHES 50000 From c1c8597c66d314406d786b91a729c89b696a44ad Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Wed, 27 Jul 2022 11:34:37 +0100 Subject: [PATCH 3/3] Restore previous behaviour --- src/spv/bitcoin/BRPeer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spv/bitcoin/BRPeer.cpp b/src/spv/bitcoin/BRPeer.cpp index 15e9420648..bf27b1ff6e 100644 --- a/src/spv/bitcoin/BRPeer.cpp +++ b/src/spv/bitcoin/BRPeer.cpp @@ -856,7 +856,7 @@ static int _peerCheckAndGetSocket (BRPeerContext *ctx, SOCKET *socket) { int exists; ctx->lock.lock(); - exists = ctx->socket >= 0; + exists = ctx->socket != INVALID_SOCKET; if (NULL != socket) *socket = ctx->socket; ctx->lock.unlock();