Skip to content
This repository was archived by the owner on Feb 1, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 183 additions & 3 deletions src/net/messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "net/nodestate.h"
#include "net/packetmanager.h"
#include "net/protocol.h"
#include "net/versionmessage.h"
#include "networks/netman.h"
#include "networks/networktemplate.h"
#include "policy/fees.h"
Expand Down Expand Up @@ -117,6 +118,43 @@ void PushNodeVersion(CNode *pnode, CConnman &connman, int64_t nTime)
}
}

// should currently send the exact same data aside from nTime as version message
void PushDynamicVersion(CNode *pnode, CConnman &connman, int64_t nTime)
{
uint64_t nLocalNodeServices = (uint64_t)pnode->GetLocalServices();
int nNodeStartingHeight = pnetMan->getChainActive()->chainActive.Height();
NodeId nodeid = pnode->GetId();
CAddress addr = pnode->addr;

CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices));
CAddress addrMe = CAddress(CService(), nLocalNodeServices);

CDynamicVersionMessage versionmsg;
versionmsg.write(VersionMsgCode::VERSION, PROTOCOL_VERSION);
versionmsg.write(VersionMsgCode::LOCAL_NODE_SERVICES, nLocalNodeServices);
versionmsg.write(VersionMsgCode::TIME, nTime);
versionmsg.write(VersionMsgCode::ADDR_YOU, addrYou);
versionmsg.write(VersionMsgCode::ADDR_ME, addrMe);
versionmsg.write(VersionMsgCode::NONCE, nLocalHostNonce);
versionmsg.write(VersionMsgCode::SUBVERSION, strSubVersion);
versionmsg.write(VersionMsgCode::NODE_START_HEIGHT, nNodeStartingHeight);
versionmsg.write(VersionMsgCode::RELAY_TXES, ::fRelayTxes);

connman.PushMessage(pnode, NetMsgType::DYNAMICVERSION, versionmsg);

if (g_logger->fLogIPs)
{
LogPrintf("send dynamic version message: version %d, blocks=%d, "
"us=%s, them=%s, peer=%d\n",
PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
}
else
{
LogPrintf("send dynamic version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION,
nNodeStartingHeight, addrMe.ToString(), nodeid);
}
}

void InitializeNode(CNode *pnode, CConnman &connman)
{
nodestateman.InitializeNodeState(pnode);
Expand Down Expand Up @@ -1064,7 +1102,16 @@ bool static ProcessMessage(CNode *pfrom,
PushNodeVersion(pfrom, connman, GetAdjustedTime());
}

connman.PushMessage(pfrom, NetMsgType::VERACK);
if (pfrom->nVersion >= MIN_NETVERSION_EXTENSION_VERSION)
{
// until this replaces the version message completely, a lot of this message is
// duplicated data as the version message
PushDynamicVersion(pfrom, connman, GetAdjustedTime());
}
else
{
connman.PushMessage(pfrom, NetMsgType::VERACK);
}

pfrom->nServices = nServices;
pfrom->SetAddrLocal(addrMe);
Expand Down Expand Up @@ -1141,6 +1188,115 @@ bool static ProcessMessage(CNode *pfrom,
return true;
}

else if (strCommand == NetMsgType::DYNAMICVERSION)
{
CDynamicVersionMessage versionmsg;
vRecv >> versionmsg;

int64_t nTime;
CAddress addrMe;
CAddress addrFrom;
uint64_t nNonce = 1;
uint64_t nServiceInt;
ServiceFlags nServices;
int nVersion;
std::string strSubVer;
std::string cleanSubVer;
int nStartingHeight = -1;
bool fRelay = true;

// get the value from the map
int *temp_version = (int *)versionmsg.read(VersionMsgCode::VERSION);
nVersion = *temp_version;
free(temp_version);
//verify it with the current version message
if (nVersion != pfrom->nVersion)
{
LogPrint("NET", "there is a mismatch between the version message and dynamic version message nVersion field \n");
}

uint64_t *temp_serviceint = (uint64_t *)versionmsg.read(VersionMsgCode::LOCAL_NODE_SERVICES);
nServiceInt = *temp_serviceint;
free(temp_serviceint);
nServices = ServiceFlags(nServiceInt);
if (nServices != pfrom->nServices)
{
LogPrint("NET", "there is a mismatch between the version message and dynamic version message nServices field \n");
}

int64_t *temp_time = (int64_t *)versionmsg.read(VersionMsgCode::TIME);
nTime = *temp_time;
free(temp_time);
int64_t nTimeOffset = nTime - GetTime();
if (nTimeOffset != pfrom->nTimeOffset)
{
LogPrint("NET", "there is a mismatch between the version message and dynamic version message nTime field \n");
}


CAddress *temp_addryou = (CAddress *)versionmsg.read(VersionMsgCode::ADDR_YOU);
addrMe = *temp_addryou;
free(temp_addryou);
if (addrMe != pfrom->GetAddrLocal())
{
LogPrint("NET", "there is a mismatch between the version message and dynamic version message addrMe field \n");
}


if (!vRecv.empty())
{
CAddress *temp_addrme = (CAddress *)versionmsg.read(VersionMsgCode::ADDR_ME);
addrFrom = *temp_addrme;
free(temp_addrme);

uint64_t *temp_nonce = (uint64_t *)versionmsg.read(VersionMsgCode::NONCE);
nNonce = *temp_nonce;
free(temp_nonce);
// no need to check nonce
}
if (!vRecv.empty())
{
char *temp_substr = (char *)versionmsg.read(VersionMsgCode::SUBVERSION);
strSubVer = std::string(temp_substr);
cleanSubVer = SanitizeString(strSubVer);
free(temp_substr);
// this should never trigger because it was previously checked by version
if (strSubVer.size() > MAX_SUBVERSION_LENGTH)
{
LogPrintf("ERROR WITH DYNAMIC VERSION STRSUBVER CHECKS, ASSERTING FALSE \n");
assert(false);
LOCK(cs_main);
Misbehaving(pfrom, 50, "bad strsubver");
return false;
}
if (cleanSubVer != pfrom->cleanSubVer)
{
LogPrint("NET", "there is a mismatch between the version message and dynamic version message cleanSubVer field \n");
}
}
if (!vRecv.empty())
{
int *temp_startheight = (int *)versionmsg.read(VersionMsgCode::NODE_START_HEIGHT);
nStartingHeight = *temp_startheight;
free(temp_startheight);
if (nStartingHeight != pfrom->nStartingHeight)
{
LogPrint("NET", "there is a mismatch between the version message and dynamic version message nStartingHeight field \n");
}
}
if (!vRecv.empty())
{
bool *temp_relay = (bool *)versionmsg.read(VersionMsgCode::RELAY_TXES);
fRelay = *temp_relay;
free(temp_relay);
if (fRelay != pfrom->fRelayTxes)
{
LogPrint("NET", "there is a mismatch between the version message and dynamic version message fRelay field \n");
}
}

connman.PushMessage(pfrom, NetMsgType::DYNAMICVERACK);
}

else if (pfrom->nVersion == 0)
{
Expand All @@ -1149,8 +1305,7 @@ bool static ProcessMessage(CNode *pfrom,
return false;
}


if (strCommand == NetMsgType::VERACK)
else if (strCommand == NetMsgType::VERACK)
{
pfrom->SetRecvVersion(std::min(pfrom->nVersion.load(), PROTOCOL_VERSION));

Expand All @@ -1172,7 +1327,32 @@ bool static ProcessMessage(CNode *pfrom,
{
connman.PushMessage(pfrom, NetMsgType::NSVERSION, NETWORK_SERVICE_VERSION);
}
pfrom->fSuccessfullyConnected = true;
}

// dynamic verack is the same as a verack for now
else if (strCommand == NetMsgType::DYNAMICVERACK)
{
pfrom->SetRecvVersion(std::min(pfrom->nVersion.load(), PROTOCOL_VERSION));

if (!pfrom->fInbound)
{
// Mark this node as currently connected, so we update its timestamp
// later.
CNodeStateAccessor state(nodestateman, pfrom->GetId());
state->fCurrentlyConnected = true;
}

// Tell our peer we prefer to receive headers rather than inv's
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
connman.PushMessage(pfrom, NetMsgType::SENDHEADERS);

if (pfrom->nVersion >= NETWORK_SERVICE_PROTOCOL_VERSION && IsBetaEnabled())
{
connman.PushMessage(pfrom, NetMsgType::NSVERSION, NETWORK_SERVICE_VERSION);
}
pfrom->fSuccessfullyConnected = true;
}

Expand Down
5 changes: 4 additions & 1 deletion src/net/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
namespace NetMsgType
{
const char *VERSION = "version";
const char *DYNAMICVERSION = "dversion";
const char *VERACK = "verack";
const char *DYNAMICVERACK = "dverack";
const char *ADDR = "addr";
const char *INV = "inv";
const char *GETDATA = "getdata";
Expand Down Expand Up @@ -55,7 +57,8 @@ static const char *ppszTypeName[] = {
/** All known message types. Keep this in the same order as the list of
* messages above and in protocol.h.
*/
const static std::string allNetMessageTypes[] = {NetMsgType::VERSION, NetMsgType::VERACK, NetMsgType::ADDR,
const static std::string allNetMessageTypes[] = {NetMsgType::VERSION, NetMsgType::VERACK, NetMsgType::DYNAMICVERSION, NetMsgType::DYNAMICVERACK,
NetMsgType::ADDR,
NetMsgType::INV, NetMsgType::GETDATA, NetMsgType::MERKLEBLOCK, NetMsgType::GETHEADERS, NetMsgType::TX,
NetMsgType::HEADERS, NetMsgType::BLOCK, NetMsgType::GETADDR, NetMsgType::PING, NetMsgType::PONG,
NetMsgType::NOTFOUND, NetMsgType::FILTERLOAD, NetMsgType::FILTERADD, NetMsgType::FILTERCLEAR, NetMsgType::REJECT,
Expand Down
8 changes: 8 additions & 0 deletions src/net/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ extern const char *VERSION;
* @see https://bitcoin.org/en/developer-reference#verack
*/
extern const char *VERACK;

// dynamic version is to replace the fixed version message at some future date
extern const char *DYNAMICVERSION;

// dynamic verack is to replace the verack message at some future date, corresponds
// with dyamic version
extern const char *DYNAMICVERACK;

/**
* The addr (IP address) message relays connection information for peers on the
* network.
Expand Down
106 changes: 106 additions & 0 deletions src/net/versionmessage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// This file is part of the Eccoin project
// Copyright (c) 2020 The Eccoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef ECCOIN_VERSIONMESSAGE_H
#define ECCOIN_VERSIONMESSAGE_H


#include "protocol.h"
#include "serialize.h"
#include "tinyformat.h"
#include "util/utilstrencodings.h"
#include <string>
#include <unordered_map>
#include <vector>

// clang-format off

enum VersionMsgCode
{
VERSION = 0x0000000000000000UL,
LOCAL_NODE_SERVICES = 0x0000000000000001UL,
TIME = 0x0000000000000002UL,
ADDR_YOU = 0x0000000000000003UL,
ADDR_ME = 0x0000000000000004UL,
NONCE = 0x0000000000000005UL,
SUBVERSION = 0x0000000000000006UL,
NODE_START_HEIGHT = 0x0000000000000007UL,
RELAY_TXES = 0x0000000000000008UL,
};

// clang-format on

/*
// not used. this is just for reference
static const std::unordered_map<VersionMsgCode, typename T> VersionMsgType (
{
{VersionMsgCode::PROTOCOL_VERSION, int },
{VersionMsgCode::LOCAL_NODE_SERVICES, uint64_t },
{VersionMsgCode::ADDR_YOU, CAddress },
{VersionMsgCode::TIME, int64_t },
{VersionMsgCode::ADDR_ME, CAddress },
{VersionMsgCode::NONCE, uint64_t },
{VersionMsgCode::SUBVERSION, std::string },
{VersionMsgCode::NODE_START_HEIGHT, int },
{VersionMsgCode::RELAY_TXES, bool },
);
*/

const size_t MAX_VERSION_MAP_SIZE = 100000;

class CDynamicVersionMessage
{
public:
std::map<uint64_t, std::vector<uint8_t> > version_map;

CDynamicVersionMessage() {}
ADD_SERIALIZE_METHODS;

void *read(const VersionMsgCode k) const
{
if (version_map.count(k) == 0)
{
return nullptr;
}
const std::vector<uint8_t> &vec = version_map.at(k);
char* v = nullptr;
try
{
CDataStream s(vec, SER_NETWORK, PROTOCOL_VERSION);
v = (char *)malloc(s.size());
s.read(v, s.size());
}
catch (...)
{
LogPrintf("Error reading version message key %016llx. Assuming zero.\n", k);
v = nullptr;
}
return v;
}

template <typename T>
void write(const VersionMsgCode key, const T &val)
{
CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
s << val;

std::vector<uint8_t> vec;
vec.insert(vec.begin(), s.begin(), s.end());
version_map[key] = vec;
}

template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action)
{
READWRITE(version_map);
if (GetSerializeSize(version_map, SER_NETWORK, PROTOCOL_VERSION) > MAX_VERSION_MAP_SIZE)
{
throw std::ios_base::failure(
strprintf("A version message version_map might at most be %d bytes.", MAX_VERSION_MAP_SIZE));
}
}
};

#endif
6 changes: 4 additions & 2 deletions src/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@
*/


static const int PROTOCOL_VERSION = 60040;
static const int PROTOCOL_VERSION = 60042;

// earlier versions not supported as of Feb 2012, and are disconnected
static const int MIN_PROTO_VERSION = 60037;
static const int MIN_PROTO_VERSION = 60041;

//! "filter*" commands are disabled without NODE_BLOOM after and including this version
static const int NO_BLOOM_VERSION = 60034;

static const int NETWORK_SERVICE_PROTOCOL_VERSION = 60040;

static const int MIN_NETVERSION_EXTENSION_VERSION = 60042;

/**
* Versioning for network services
*/
Expand Down