Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14865129
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
23 KB
Subscribers
None
View Options
diff --git a/src/chain.cpp b/src/chain.cpp
index 8e61e0ec2..c2d3439e3 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -1,143 +1,143 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chain.h>
void CChain::SetTip(CBlockIndex &block) {
CBlockIndex *pindex = █
vChain.resize(pindex->nHeight + 1);
while (pindex && vChain[pindex->nHeight] != pindex) {
vChain[pindex->nHeight] = pindex;
pindex = pindex->pprev;
}
}
std::vector<BlockHash> LocatorEntries(const CBlockIndex *index) {
int step = 1;
std::vector<BlockHash> have;
if (index == nullptr) {
return have;
}
have.reserve(32);
while (index) {
have.emplace_back(index->GetBlockHash());
if (index->nHeight == 0) {
break;
}
// Exponentially larger steps back, plus the genesis block.
int height = std::max(index->nHeight - step, 0);
// Use skiplist.
index = index->GetAncestor(height);
if (have.size() > 10) {
step *= 2;
}
}
return have;
}
CBlockLocator GetLocator(const CBlockIndex *index) {
- return CBlockLocator{std::move(LocatorEntries(index))};
+ return CBlockLocator{LocatorEntries(index)};
}
CBlockLocator CChain::GetLocator() const {
return ::GetLocator(Tip());
}
const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
if (pindex == nullptr) {
return nullptr;
}
if (pindex->nHeight > Height()) {
pindex = pindex->GetAncestor(Height());
}
while (pindex && !Contains(pindex)) {
pindex = pindex->pprev;
}
return pindex;
}
CBlockIndex *CChain::FindEarliestAtLeast(int64_t nTime, int height) const {
std::pair<int64_t, int> blockparams = std::make_pair(nTime, height);
std::vector<CBlockIndex *>::const_iterator lower = std::lower_bound(
vChain.begin(), vChain.end(), blockparams,
[](CBlockIndex *pBlock,
const std::pair<int64_t, int> &_blockparams) -> bool {
return pBlock->GetBlockTimeMax() < _blockparams.first ||
pBlock->nHeight < _blockparams.second;
});
return (lower == vChain.end() ? nullptr : *lower);
}
arith_uint256 GetBlockProof(const CBlockIndex &block) {
arith_uint256 bnTarget;
bool fNegative;
bool fOverflow;
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
if (fNegative || fOverflow || bnTarget == 0) {
return 0;
}
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
// as it's too large for an arith_uint256. However, as 2**256 is at least as
// large as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) /
// (bnTarget+1)) + 1, or ~bnTarget / (bnTarget+1) + 1.
return (~bnTarget / (bnTarget + 1)) + 1;
}
int64_t GetBlockProofEquivalentTime(const CBlockIndex &to,
const CBlockIndex &from,
const CBlockIndex &tip,
const Consensus::Params ¶ms) {
arith_uint256 r;
int sign = 1;
if (to.nChainWork > from.nChainWork) {
r = to.nChainWork - from.nChainWork;
} else {
r = from.nChainWork - to.nChainWork;
sign = -1;
}
r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);
if (r.bits() > 63) {
return sign * std::numeric_limits<int64_t>::max();
}
return sign * int64_t(r.GetLow64());
}
/**
* Find the last common ancestor two blocks have.
* Both pa and pb must be non null.
*/
const CBlockIndex *LastCommonAncestor(const CBlockIndex *pa,
const CBlockIndex *pb) {
if (pa->nHeight > pb->nHeight) {
pa = pa->GetAncestor(pb->nHeight);
} else if (pb->nHeight > pa->nHeight) {
pb = pb->GetAncestor(pa->nHeight);
}
while (pa != pb && pa && pb) {
if (pa->pskip && pb->pskip && pa->pskip != pb->pskip) {
pa = pa->pskip;
pb = pb->pskip;
assert(pa->nHeight == pb->nHeight);
} else {
pa = pa->pprev;
pb = pb->pprev;
}
}
// Eventually all chain branches meet at the genesis block.
assert(pa == pb);
return pa;
}
bool AreOnTheSameFork(const CBlockIndex *pa, const CBlockIndex *pb) {
if (pa->nHeight > pb->nHeight) {
pa = pa->GetAncestor(pb->nHeight);
} else if (pb->nHeight > pa->nHeight) {
pb = pb->GetAncestor(pa->nHeight);
}
return pa == pb;
}
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 9ed059718..696312c20 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -1,126 +1,126 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_PRIMITIVES_BLOCK_H
#define BITCOIN_PRIMITIVES_BLOCK_H
#include <primitives/blockhash.h>
#include <primitives/transaction.h>
#include <serialize.h>
#include <uint256.h>
#include <util/time.h>
/**
* Nodes collect new transactions into a block, hash them into a hash tree, and
* scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block to
* everyone and the block is added to the block chain. The first transaction in
* the block is a special one that creates a new coin owned by the creator of
* the block.
*/
class CBlockHeader {
public:
// header
int32_t nVersion;
BlockHash hashPrevBlock;
uint256 hashMerkleRoot;
uint32_t nTime;
uint32_t nBits;
uint32_t nNonce;
CBlockHeader() { SetNull(); }
SERIALIZE_METHODS(CBlockHeader, obj) {
READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot,
obj.nTime, obj.nBits, obj.nNonce);
}
void SetNull() {
nVersion = 0;
hashPrevBlock = BlockHash();
hashMerkleRoot.SetNull();
nTime = 0;
nBits = 0;
nNonce = 0;
}
bool IsNull() const { return (nBits == 0); }
BlockHash GetHash() const;
NodeSeconds Time() const {
return NodeSeconds{std::chrono::seconds{nTime}};
}
int64_t GetBlockTime() const { return (int64_t)nTime; }
};
class CBlock : public CBlockHeader {
public:
// network and disk
std::vector<CTransactionRef> vtx;
// memory only
mutable bool fChecked;
CBlock() { SetNull(); }
CBlock(const CBlockHeader &header) {
SetNull();
*(static_cast<CBlockHeader *>(this)) = header;
}
SERIALIZE_METHODS(CBlock, obj) {
READWRITEAS(CBlockHeader, obj);
READWRITE(obj.vtx);
}
void SetNull() {
CBlockHeader::SetNull();
vtx.clear();
fChecked = false;
}
CBlockHeader GetBlockHeader() const {
CBlockHeader block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrevBlock;
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
return block;
}
std::string ToString() const;
};
/**
* Describes a place in the block chain to another node such that if the other
* node doesn't have the same branch, it can find a recent common trunk. The
* further back it is, the further before the fork it may be.
*/
struct CBlockLocator {
std::vector<BlockHash> vHave;
CBlockLocator() {}
- explicit CBlockLocator(const std::vector<BlockHash> &vHaveIn)
- : vHave(vHaveIn) {}
+ explicit CBlockLocator(std::vector<BlockHash> &&vHaveIn)
+ : vHave(std::move(vHaveIn)) {}
SERIALIZE_METHODS(CBlockLocator, obj) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(nVersion);
}
READWRITE(obj.vHave);
}
void SetNull() { vHave.clear(); }
bool IsNull() const { return vHave.empty(); }
};
#endif // BITCOIN_PRIMITIVES_BLOCK_H
diff --git a/src/seeder/bitcoin.cpp b/src/seeder/bitcoin.cpp
index aedb0ce4b..f234782e0 100644
--- a/src/seeder/bitcoin.cpp
+++ b/src/seeder/bitcoin.cpp
@@ -1,311 +1,312 @@
// Copyright (c) 2017-2020 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <seeder/bitcoin.h>
#include <chainparams.h>
#include <clientversion.h>
#include <common/args.h>
#include <hash.h>
#include <netbase.h>
#include <primitives/blockhash.h>
#include <seeder/db.h>
#include <seeder/messagewriter.h>
#include <serialize.h>
#include <uint256.h>
#include <util/sock.h>
#include <util/time.h>
#include <algorithm>
#define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL
void CSeederNode::Send() {
if (!sock) {
return;
}
if (vSend.empty()) {
return;
}
int nBytes = sock->Send(&vSend[0], vSend.size(), 0);
if (nBytes > 0) {
vSend.erase(vSend.begin(), vSend.begin() + nBytes);
} else {
sock.reset();
}
}
PeerMessagingState CSeederNode::ProcessMessage(std::string strCommand,
CDataStream &recv) {
// tfm::format(std::cout, "%s: RECV %s\n", ToString(you),
// strCommand);
if (strCommand == NetMsgType::VERSION) {
int64_t nTime;
CService addrMe;
uint64_t nNonce = 1;
uint64_t nServiceInt;
recv >> nVersion >> nServiceInt >> nTime;
yourServices = ServiceFlags(nServiceInt);
// Ignore the addrMe service bits sent by the peer
recv.ignore(8);
recv >> addrMe;
// The version message includes information about the sending node
// which we don't use:
// - 8 bytes (service bits)
// - 16 bytes (ipv6 address)
// - 2 bytes (port)
recv.ignore(26);
recv >> nNonce;
recv >> strSubVer;
recv >> nStartingHeight;
vSend.SetVersion(std::min(nVersion, PROTOCOL_VERSION));
MessageWriter::WriteMessage(vSend, NetMsgType::VERACK);
return PeerMessagingState::AwaitingMessages;
}
if (strCommand == NetMsgType::VERACK) {
vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION));
// tfm::format(std::cout, "\n%s: version %i\n", ToString(you),
// nVersion);
if (vAddr) {
MessageWriter::WriteMessage(vSend, NetMsgType::GETADDR);
std::vector<BlockHash> locatorHash(
1, Params().Checkpoints().mapCheckpoints.rbegin()->second);
MessageWriter::WriteMessage(vSend, NetMsgType::GETHEADERS,
- CBlockLocator(locatorHash), uint256());
+ CBlockLocator(std::move(locatorHash)),
+ uint256());
doneAfter = Now<NodeSeconds>() + GetTimeout();
} else {
doneAfter = Now<NodeSeconds>() + 1s;
}
return PeerMessagingState::AwaitingMessages;
}
if (strCommand == NetMsgType::ADDR && vAddr) {
std::vector<CAddress> vAddrNew;
recv >> vAddrNew;
// tfm::format(std::cout, "%s: got %i addresses\n",
// ToString(you),
// (int)vAddrNew.size());
auto now = Now<NodeSeconds>();
std::vector<CAddress>::iterator it = vAddrNew.begin();
if (vAddrNew.size() > 1) {
if (TicksSinceEpoch<std::chrono::seconds>(doneAfter) == 0 ||
doneAfter > now + 1s) {
doneAfter = now + 1s;
}
}
while (it != vAddrNew.end()) {
CAddress &addr = *it;
// tfm::format(std::cout, "%s: got address %s\n",
// ToString(you),
// addr.ToString(), (int)(vAddr->size()));
it++;
if (addr.nTime <= NodeSeconds{100000000s} ||
addr.nTime > now + 10min) {
addr.nTime = now - 5 * 24h;
}
if (addr.nTime > now - 7 * 24h) {
vAddr->push_back(addr);
}
// tfm::format(std::cout, "%s: added address %s (#%i)\n",
// ToString(you),
// addr.ToString(), (int)(vAddr->size()));
if (vAddr->size() > ADDR_SOFT_CAP) {
doneAfter = NodeSeconds{1s};
return PeerMessagingState::Finished;
}
}
return PeerMessagingState::AwaitingMessages;
}
return PeerMessagingState::AwaitingMessages;
}
bool CSeederNode::ProcessMessages() {
if (vRecv.empty()) {
return false;
}
const CMessageHeader::MessageMagic netMagic = Params().NetMagic();
do {
CDataStream::iterator pstart = std::search(
vRecv.begin(), vRecv.end(), BEGIN(netMagic), END(netMagic));
uint32_t nHeaderSize =
GetSerializeSize(CMessageHeader(netMagic), vRecv.GetVersion());
if (vRecv.end() - pstart < nHeaderSize) {
if (vRecv.size() > nHeaderSize) {
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
}
break;
}
vRecv.erase(vRecv.begin(), pstart);
std::vector<std::byte> vHeaderSave(vRecv.begin(),
vRecv.begin() + nHeaderSize);
CMessageHeader hdr(netMagic);
vRecv >> hdr;
if (!hdr.IsValidWithoutConfig(netMagic)) {
// tfm::format(std::cout, "%s: BAD (invalid header)\n",
// ToString(you));
ban = 100000;
return true;
}
std::string strCommand = hdr.GetCommand();
unsigned int nMessageSize = hdr.nMessageSize;
if (nMessageSize > MAX_SIZE) {
// tfm::format(std::cout, "%s: BAD (message too large)\n",
// ToString(you));
ban = 100000;
return true;
}
if (nMessageSize > vRecv.size()) {
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
break;
}
if (vRecv.GetVersion() >= 209) {
uint256 hash = Hash(Span{vRecv}.first(nMessageSize));
if (memcmp(hash.begin(), hdr.pchChecksum,
CMessageHeader::CHECKSUM_SIZE) != 0) {
continue;
}
}
std::vector<std::byte> vec{vRecv.begin(), vRecv.begin() + nMessageSize};
CDataStream vMsg(MakeUCharSpan(vec), vRecv.GetType(),
vRecv.GetVersion());
vRecv.ignore(nMessageSize);
if (ProcessMessage(strCommand, vMsg) == PeerMessagingState::Finished) {
return true;
}
// tfm::format(std::cout, "%s: done processing %s\n",
// ToString(you),
// strCommand);
} while (1);
return false;
}
CSeederNode::CSeederNode(const CService &ip, std::vector<CAddress> *vAddrIn)
: vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0), nHeaderStart(-1),
nMessageStart(-1), nVersion(0), vAddr(vAddrIn), ban(0),
doneAfter(NodeSeconds{0s}), you(ip),
yourServices(ServiceFlags(NODE_NETWORK)) {
if (GetTime() > 1329696000) {
vSend.SetVersion(209);
vRecv.SetVersion(209);
}
}
bool CSeederNode::Run() {
// FIXME: This logic is duplicated with CConnman::ConnectNode for no
// good reason.
bool connected = false;
proxyType proxy;
if (you.IsValid()) {
bool proxyConnectionFailed = false;
if (GetProxy(you.GetNetwork(), proxy)) {
sock = CreateSock(proxy.proxy);
if (!sock) {
return false;
}
connected = ConnectThroughProxy(
proxy, you.ToStringIP(), you.GetPort(), *sock, nConnectTimeout,
proxyConnectionFailed);
} else {
// no proxy needed (none set for target network)
sock = CreateSock(you);
if (!sock) {
return false;
}
// no proxy needed (none set for target network)
connected =
ConnectSocketDirectly(you, *sock, nConnectTimeout, false);
}
}
if (!connected) {
// tfm::format(std::cout, "Cannot connect to %s\n",
// ToString(you));
sock.reset();
return false;
}
// Write version message
// Don't include the time in CAddress serialization. See D14753.
uint64_t nLocalServices = 0;
uint64_t nLocalNonce = BITCOIN_SEED_NONCE;
uint64_t your_services{yourServices};
uint64_t my_services{ServiceFlags(NODE_NETWORK)};
uint8_t fRelayTxs = 0;
const std::string clientName = gArgs.GetArg("-uaclientname", CLIENT_NAME);
const std::string clientVersion =
gArgs.GetArg("-uaclientversion", FormatVersion(CLIENT_VERSION));
const std::string userAgent =
FormatUserAgent(clientName, clientVersion, {"seeder"});
MessageWriter::WriteMessage(vSend, NetMsgType::VERSION, PROTOCOL_VERSION,
nLocalServices, GetTime(), your_services, you,
my_services, CService(), nLocalNonce, userAgent,
GetRequireHeight(), fRelayTxs);
Send();
bool res = true;
NodeSeconds now;
while (now = Now<NodeSeconds>(),
ban == 0 &&
(TicksSinceEpoch<std::chrono::seconds>(doneAfter) == 0 ||
doneAfter > now) &&
sock) {
char pchBuf[0x10000];
fd_set fdsetRecv;
fd_set fdsetError;
FD_ZERO(&fdsetRecv);
FD_ZERO(&fdsetError);
FD_SET(sock->Get(), &fdsetRecv);
FD_SET(sock->Get(), &fdsetError);
struct timeval wa;
if (TicksSinceEpoch<std::chrono::seconds>(doneAfter) != 0) {
wa.tv_sec = (doneAfter - now).count();
wa.tv_usec = 0;
} else {
wa.tv_sec = GetTimeout().count();
wa.tv_usec = 0;
}
int ret =
select(sock->Get() + 1, &fdsetRecv, nullptr, &fdsetError, &wa);
if (ret != 1) {
if (TicksSinceEpoch<std::chrono::seconds>(doneAfter) == 0) {
res = false;
}
break;
}
int nBytes = sock->Recv(pchBuf, sizeof(pchBuf), 0);
int nPos = vRecv.size();
if (nBytes > 0) {
vRecv.resize(nPos + nBytes);
memcpy(&vRecv[nPos], pchBuf, nBytes);
} else if (nBytes == 0) {
// tfm::format(std::cout, "%s: BAD (connection closed
// prematurely)\n",
// ToString(you));
res = false;
break;
} else {
// tfm::format(std::cout, "%s: BAD (connection error)\n",
// ToString(you));
res = false;
break;
}
ProcessMessages();
Send();
}
if (!sock) {
res = false;
}
sock.reset();
return (ban == 0) && res;
}
diff --git a/src/seeder/test/message_writer_tests.cpp b/src/seeder/test/message_writer_tests.cpp
index 961f58073..21d362163 100644
--- a/src/seeder/test/message_writer_tests.cpp
+++ b/src/seeder/test/message_writer_tests.cpp
@@ -1,92 +1,92 @@
// Copyright (c) 2020 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <hash.h>
#include <primitives/block.h>
#include <protocol.h>
#include <seeder/messagewriter.h>
#include <streams.h>
#include <version.h>
#include <boost/test/unit_test.hpp>
#include <string>
#include <vector>
BOOST_AUTO_TEST_SUITE(message_writer_tests)
template <typename... Args>
static void CheckMessage(CDataStream &expectedMessage, std::string command,
Args &&...args) {
CDataStream message(SER_NETWORK, PROTOCOL_VERSION);
MessageWriter::WriteMessage(message, command, std::forward<Args>(args)...);
BOOST_CHECK_EQUAL(message.size(), expectedMessage.size());
for (size_t i = 0; i < message.size(); i++) {
BOOST_CHECK_EQUAL(uint8_t(message[i]), uint8_t(expectedMessage[i]));
}
}
BOOST_AUTO_TEST_CASE(simple_header_and_payload_message_writer_test) {
SelectParams(CBaseChainParams::MAIN);
int64_t now = GetTime();
uint64_t nonce = 0;
uint64_t serviceFlags = uint64_t(ServiceFlags(NODE_NETWORK));
CService service;
CAddress addrTo(service, ServiceFlags(NODE_NETWORK));
CAddress addrFrom(service, ServiceFlags(NODE_NETWORK));
std::string user_agent = "/Bitcoin ABC:0.0.0(seeder)/";
int start_height = 1;
CDataStream versionPayload(SER_NETWORK, PROTOCOL_VERSION);
versionPayload << PROTOCOL_VERSION << serviceFlags << now << addrTo
<< addrFrom << nonce << user_agent << start_height;
CMessageHeader versionhdr(Params().NetMagic(), NetMsgType::VERSION,
versionPayload.size());
uint256 hash = Hash(versionPayload);
memcpy(versionhdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
CDataStream expectedVersion(SER_NETWORK, PROTOCOL_VERSION);
expectedVersion << versionhdr << versionPayload;
CheckMessage(expectedVersion, NetMsgType::VERSION, PROTOCOL_VERSION,
serviceFlags, now, addrTo, addrFrom, nonce, user_agent,
start_height);
}
BOOST_AUTO_TEST_CASE(header_empty_payload_message_writer_test) {
SelectParams(CBaseChainParams::MAIN);
CMessageHeader verackHeader(Params().NetMagic(), NetMsgType::VERACK, 0);
CDataStream expectedVerack(SER_NETWORK, PROTOCOL_VERSION);
// This is an empty payload, but is still necessary for the checksum
std::vector<uint8_t> payload;
uint256 hash = Hash(payload);
memcpy(verackHeader.pchChecksum, hash.begin(),
CMessageHeader::CHECKSUM_SIZE);
expectedVerack << verackHeader;
CheckMessage(expectedVerack, NetMsgType::VERACK);
}
BOOST_AUTO_TEST_CASE(write_getheaders_message_test) {
SelectParams(CBaseChainParams::MAIN);
CDataStream payload(SER_NETWORK, PROTOCOL_VERSION);
BlockHash bhash(uint256S(
"0000000099f5509b5f36b1926bcf82b21d936ebeadee811030dfbbb7fae915d7"));
std::vector<BlockHash> vlocator(1, bhash);
- CBlockLocator locatorhash(vlocator);
+ CBlockLocator locatorhash(std::move(vlocator));
payload << locatorhash << uint256();
uint256 hash = Hash(payload);
CMessageHeader msgHeader(Params().NetMagic(), NetMsgType::GETHEADERS,
payload.size());
memcpy(msgHeader.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
CDataStream expectedMsg(SER_NETWORK, PROTOCOL_VERSION);
expectedMsg << msgHeader << payload;
CheckMessage(expectedMsg, NetMsgType::GETHEADERS, locatorhash, uint256());
}
BOOST_AUTO_TEST_SUITE_END()
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, May 22, 01:51 (13 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5866292
Default Alt Text
(23 KB)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment