aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/bitcoin-cli.cpp30
-rw-r--r--src/bitcoin-tx.cpp190
-rw-r--r--src/main.cpp201
-rw-r--r--src/net.cpp46
-rw-r--r--src/net.h49
-rw-r--r--src/netmessagemaker.h36
-rw-r--r--src/streams.h69
-rw-r--r--src/test/data/tx_valid.json18
-rw-r--r--src/test/streams_tests.cpp58
10 files changed, 425 insertions, 273 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5a5e3abcfa..69ae02f582 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -111,6 +111,7 @@ BITCOIN_CORE_H = \
net.h \
netaddress.h \
netbase.h \
+ netmessagemaker.h \
noui.h \
policy/fees.h \
policy/policy.h \
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 392d1b9329..b272640819 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -24,15 +24,13 @@
#include <univalue.h>
-using namespace std;
-
static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const int CONTINUE_EXECUTION=-1;
std::string HelpMessageCli()
{
- string strUsage;
+ std::string strUsage;
strUsage += HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("This help message"));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
@@ -187,7 +185,7 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
}
#endif
-UniValue CallRPC(const string& strMethod, const UniValue& params)
+UniValue CallRPC(const std::string& strMethod, const UniValue& params)
{
std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
int port = GetArg("-rpcport", BaseParams().RPCPort());
@@ -195,18 +193,18 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
// Create event base
struct event_base *base = event_base_new(); // TODO RAII
if (!base)
- throw runtime_error("cannot create event_base");
+ throw std::runtime_error("cannot create event_base");
// Synchronously look up hostname
struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII
if (evcon == NULL)
- throw runtime_error("create connection failed");
+ throw std::runtime_error("create connection failed");
evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
HTTPReply response;
struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
if (req == NULL)
- throw runtime_error("create http request failed");
+ throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
evhttp_request_set_error_cb(req, http_error_cb);
#endif
@@ -216,7 +214,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
if (mapArgs["-rpcpassword"] == "") {
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
- throw runtime_error(strprintf(
+ throw std::runtime_error(strprintf(
_("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
@@ -251,26 +249,26 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
if (response.status == 0)
throw CConnectionFailed(strprintf("couldn't connect to server\n(make sure server is running and you are connecting to the correct RPC port: %d %s)", response.error, http_errorstring(response.error)));
else if (response.status == HTTP_UNAUTHORIZED)
- throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
+ throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
- throw runtime_error(strprintf("server returned HTTP error %d", response.status));
+ throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
else if (response.body.empty())
- throw runtime_error("no response from server");
+ throw std::runtime_error("no response from server");
// Parse reply
UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body))
- throw runtime_error("couldn't parse reply from server");
+ throw std::runtime_error("couldn't parse reply from server");
const UniValue& reply = valReply.get_obj();
if (reply.empty())
- throw runtime_error("expected reply to have result, error and id properties");
+ throw std::runtime_error("expected reply to have result, error and id properties");
return reply;
}
int CommandLineRPC(int argc, char *argv[])
{
- string strPrint;
+ std::string strPrint;
int nRet = 0;
try {
// Skip switches
@@ -286,7 +284,7 @@ int CommandLineRPC(int argc, char *argv[])
args.push_back(line);
}
if (args.size() < 1)
- throw runtime_error("too few parameters (need at least command)");
+ throw std::runtime_error("too few parameters (need at least command)");
std::string strMethod = args[0];
UniValue params = RPCConvertValues(strMethod, std::vector<std::string>(args.begin()+1, args.end()));
@@ -340,7 +338,7 @@ int CommandLineRPC(int argc, char *argv[])
throw;
}
catch (const std::exception& e) {
- strPrint = string("error: ") + e.what();
+ strPrint = std::string("error: ") + e.what();
nRet = EXIT_FAILURE;
}
catch (...) {
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 6d17bc392f..346d8e180d 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -26,10 +26,8 @@
#include <boost/algorithm/string.hpp>
#include <boost/assign/list_of.hpp>
-using namespace std;
-
static bool fCreateBlank;
-static map<string,UniValue> registers;
+static std::map<std::string,UniValue> registers;
static const int CONTINUE_EXECUTION=-1;
//
@@ -103,52 +101,52 @@ static int AppInitRawTx(int argc, char* argv[])
return CONTINUE_EXECUTION;
}
-static void RegisterSetJson(const string& key, const string& rawJson)
+static void RegisterSetJson(const std::string& key, const std::string& rawJson)
{
UniValue val;
if (!val.read(rawJson)) {
- string strErr = "Cannot parse JSON for key " + key;
- throw runtime_error(strErr);
+ std::string strErr = "Cannot parse JSON for key " + key;
+ throw std::runtime_error(strErr);
}
registers[key] = val;
}
-static void RegisterSet(const string& strInput)
+static void RegisterSet(const std::string& strInput)
{
// separate NAME:VALUE in string
size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
+ if ((pos == std::string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
- throw runtime_error("Register input requires NAME:VALUE");
+ throw std::runtime_error("Register input requires NAME:VALUE");
- string key = strInput.substr(0, pos);
- string valStr = strInput.substr(pos + 1, string::npos);
+ std::string key = strInput.substr(0, pos);
+ std::string valStr = strInput.substr(pos + 1, std::string::npos);
RegisterSetJson(key, valStr);
}
-static void RegisterLoad(const string& strInput)
+static void RegisterLoad(const std::string& strInput)
{
// separate NAME:FILENAME in string
size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
+ if ((pos == std::string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
- throw runtime_error("Register load requires NAME:FILENAME");
+ throw std::runtime_error("Register load requires NAME:FILENAME");
- string key = strInput.substr(0, pos);
- string filename = strInput.substr(pos + 1, string::npos);
+ std::string key = strInput.substr(0, pos);
+ std::string filename = strInput.substr(pos + 1, std::string::npos);
FILE *f = fopen(filename.c_str(), "r");
if (!f) {
- string strErr = "Cannot open file " + filename;
- throw runtime_error(strErr);
+ std::string strErr = "Cannot open file " + filename;
+ throw std::runtime_error(strErr);
}
// load file chunks into one big buffer
- string valStr;
+ std::string valStr;
while ((!feof(f)) && (!ferror(f))) {
char buf[4096];
int bread = fread(buf, 1, sizeof(buf), f);
@@ -162,55 +160,55 @@ static void RegisterLoad(const string& strInput)
fclose(f);
if (error) {
- string strErr = "Error reading file " + filename;
- throw runtime_error(strErr);
+ std::string strErr = "Error reading file " + filename;
+ throw std::runtime_error(strErr);
}
// evaluate as JSON buffer register
RegisterSetJson(key, valStr);
}
-static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
+static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newVersion = atoi64(cmdVal);
if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
- throw runtime_error("Invalid TX version requested");
+ throw std::runtime_error("Invalid TX version requested");
tx.nVersion = (int) newVersion;
}
-static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
+static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newLocktime = atoi64(cmdVal);
if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
- throw runtime_error("Invalid TX locktime requested");
+ throw std::runtime_error("Invalid TX locktime requested");
tx.nLockTime = (unsigned int) newLocktime;
}
-static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
+static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
{
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
// separate TXID:VOUT in string
if (vStrInputParts.size()<2)
- throw runtime_error("TX input missing separator");
+ throw std::runtime_error("TX input missing separator");
// extract and validate TXID
- string strTxid = vStrInputParts[0];
+ std::string strTxid = vStrInputParts[0];
if ((strTxid.size() != 64) || !IsHex(strTxid))
- throw runtime_error("invalid TX input txid");
+ throw std::runtime_error("invalid TX input txid");
uint256 txid(uint256S(strTxid));
static const unsigned int minTxOutSz = 9;
static const unsigned int maxVout = MAX_BLOCK_BASE_SIZE / minTxOutSz;
// extract and validate vout
- string strVout = vStrInputParts[1];
+ std::string strVout = vStrInputParts[1];
int vout = atoi(strVout);
if ((vout < 0) || (vout > (int)maxVout))
- throw runtime_error("invalid TX input vout");
+ throw std::runtime_error("invalid TX input vout");
// extract the optional sequence number
uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();
@@ -222,26 +220,26 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
tx.vin.push_back(txin);
}
-static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
+static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
{
// separate VALUE:ADDRESS in string
size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
+ if ((pos == std::string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
- throw runtime_error("TX output missing separator");
+ throw std::runtime_error("TX output missing separator");
// extract and validate VALUE
- string strValue = strInput.substr(0, pos);
+ std::string strValue = strInput.substr(0, pos);
CAmount value;
if (!ParseMoney(strValue, value))
- throw runtime_error("invalid TX output value");
+ throw std::runtime_error("invalid TX output value");
// extract and validate ADDRESS
- string strAddr = strInput.substr(pos + 1, string::npos);
+ std::string strAddr = strInput.substr(pos + 1, std::string::npos);
CBitcoinAddress addr(strAddr);
if (!addr.IsValid())
- throw runtime_error("invalid TX output address");
+ throw std::runtime_error("invalid TX output address");
// build standard output script via GetScriptForDestination()
CScript scriptPubKey = GetScriptForDestination(addr.Get());
@@ -251,7 +249,7 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
tx.vout.push_back(txout);
}
-static void MutateTxAddOutData(CMutableTransaction& tx, const string& strInput)
+static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput)
{
CAmount value = 0;
@@ -259,20 +257,20 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const string& strInput)
size_t pos = strInput.find(':');
if (pos==0)
- throw runtime_error("TX output value not specified");
+ throw std::runtime_error("TX output value not specified");
- if (pos != string::npos) {
+ if (pos != std::string::npos) {
// extract and validate VALUE
- string strValue = strInput.substr(0, pos);
+ std::string strValue = strInput.substr(0, pos);
if (!ParseMoney(strValue, value))
- throw runtime_error("invalid TX output value");
+ throw std::runtime_error("invalid TX output value");
}
// extract and validate DATA
- string strData = strInput.substr(pos + 1, string::npos);
+ std::string strData = strInput.substr(pos + 1, std::string::npos);
if (!IsHex(strData))
- throw runtime_error("invalid TX output data");
+ throw std::runtime_error("invalid TX output data");
std::vector<unsigned char> data = ParseHex(strData);
@@ -280,22 +278,22 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const string& strInput)
tx.vout.push_back(txout);
}
-static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput)
+static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
{
// separate VALUE:SCRIPT in string
size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
+ if ((pos == std::string::npos) ||
(pos == 0))
- throw runtime_error("TX output missing separator");
+ throw std::runtime_error("TX output missing separator");
// extract and validate VALUE
- string strValue = strInput.substr(0, pos);
+ std::string strValue = strInput.substr(0, pos);
CAmount value;
if (!ParseMoney(strValue, value))
- throw runtime_error("invalid TX output value");
+ throw std::runtime_error("invalid TX output value");
// extract and validate script
- string strScript = strInput.substr(pos + 1, string::npos);
+ std::string strScript = strInput.substr(pos + 1, std::string::npos);
CScript scriptPubKey = ParseScript(strScript); // throws on err
// construct TxOut, append to transaction output list
@@ -303,26 +301,26 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput
tx.vout.push_back(txout);
}
-static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx)
+static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested deletion index
int inIdx = atoi(strInIdx);
if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
- string strErr = "Invalid TX input index '" + strInIdx + "'";
- throw runtime_error(strErr.c_str());
+ std::string strErr = "Invalid TX input index '" + strInIdx + "'";
+ throw std::runtime_error(strErr.c_str());
}
// delete input from transaction
tx.vin.erase(tx.vin.begin() + inIdx);
}
-static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx)
+static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
{
// parse requested deletion index
int outIdx = atoi(strOutIdx);
if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {
- string strErr = "Invalid TX output index '" + strOutIdx + "'";
- throw runtime_error(strErr.c_str());
+ std::string strErr = "Invalid TX output index '" + strOutIdx + "'";
+ throw std::runtime_error(strErr.c_str());
}
// delete output from transaction
@@ -342,7 +340,7 @@ static const struct {
{"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
};
-static bool findSighashFlags(int& flags, const string& flagStr)
+static bool findSighashFlags(int& flags, const std::string& flagStr)
{
flags = 0;
@@ -356,17 +354,17 @@ static bool findSighashFlags(int& flags, const string& flagStr)
return false;
}
-uint256 ParseHashUO(map<string,UniValue>& o, string strKey)
+uint256 ParseHashUO(std::map<std::string,UniValue>& o, std::string strKey)
{
if (!o.count(strKey))
return uint256();
return ParseHashUV(o[strKey], strKey);
}
-vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
+std::vector<unsigned char> ParseHexUO(std::map<std::string,UniValue>& o, std::string strKey)
{
if (!o.count(strKey)) {
- vector<unsigned char> emptyVec;
+ std::vector<unsigned char> emptyVec;
return emptyVec;
}
return ParseHexUV(o[strKey], strKey);
@@ -375,24 +373,24 @@ vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
static CAmount AmountFromValue(const UniValue& value)
{
if (!value.isNum() && !value.isStr())
- throw runtime_error("Amount is not a number or string");
+ throw std::runtime_error("Amount is not a number or string");
CAmount amount;
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
- throw runtime_error("Invalid amount");
+ throw std::runtime_error("Invalid amount");
if (!MoneyRange(amount))
- throw runtime_error("Amount out of range");
+ throw std::runtime_error("Amount out of range");
return amount;
}
-static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
+static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
{
int nHashType = SIGHASH_ALL;
if (flagStr.size() > 0)
if (!findSighashFlags(nHashType, flagStr))
- throw runtime_error("unknown sighash flag/sign option");
+ throw std::runtime_error("unknown sighash flag/sign option");
- vector<CTransaction> txVariants;
+ std::vector<CTransaction> txVariants;
txVariants.push_back(tx);
// mergedTx will end up with all the signatures; it
@@ -403,17 +401,17 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
CCoinsViewCache view(&viewDummy);
if (!registers.count("privatekeys"))
- throw runtime_error("privatekeys register variable must be set.");
+ throw std::runtime_error("privatekeys register variable must be set.");
CBasicKeyStore tempKeystore;
UniValue keysObj = registers["privatekeys"];
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
- throw runtime_error("privatekey not a string");
+ throw std::runtime_error("privatekey not a std::string");
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
if (!fGood)
- throw runtime_error("privatekey not valid");
+ throw std::runtime_error("privatekey not valid");
CKey key = vchSecret.GetKey();
tempKeystore.AddKey(key);
@@ -421,34 +419,34 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
// Add previous txouts given in the RPC call:
if (!registers.count("prevtxs"))
- throw runtime_error("prevtxs register variable must be set.");
+ throw std::runtime_error("prevtxs register variable must be set.");
UniValue prevtxsObj = registers["prevtxs"];
{
for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {
UniValue prevOut = prevtxsObj[previdx];
if (!prevOut.isObject())
- throw runtime_error("expected prevtxs internal object");
+ throw std::runtime_error("expected prevtxs internal object");
- map<string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
+ std::map<std::string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
if (!prevOut.checkObject(types))
- throw runtime_error("prevtxs internal object typecheck fail");
+ throw std::runtime_error("prevtxs internal object typecheck fail");
uint256 txid = ParseHashUV(prevOut["txid"], "txid");
int nOut = atoi(prevOut["vout"].getValStr());
if (nOut < 0)
- throw runtime_error("vout must be positive");
+ throw std::runtime_error("vout must be positive");
- vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
+ std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
{
CCoinsModifier coins = view.ModifyCoins(txid);
if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
- string err("Previous output scriptPubKey mismatch:\n");
+ std::string err("Previous output scriptPubKey mismatch:\n");
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
- throw runtime_error(err);
+ throw std::runtime_error(err);
}
if ((unsigned int)nOut >= coins->vout.size())
coins->vout.resize(nOut+1);
@@ -464,7 +462,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
prevOut.exists("redeemScript")) {
UniValue v = prevOut["redeemScript"];
- vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
+ std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
}
@@ -521,8 +519,8 @@ public:
}
};
-static void MutateTx(CMutableTransaction& tx, const string& command,
- const string& commandVal)
+static void MutateTx(CMutableTransaction& tx, const std::string& command,
+ const std::string& commandVal)
{
std::unique_ptr<Secp256k1Init> ecc;
@@ -557,7 +555,7 @@ static void MutateTx(CMutableTransaction& tx, const string& command,
RegisterSet(commandVal);
else
- throw runtime_error("unknown command");
+ throw std::runtime_error("unknown command");
}
static void OutputTxJSON(const CTransaction& tx)
@@ -565,20 +563,20 @@ static void OutputTxJSON(const CTransaction& tx)
UniValue entry(UniValue::VOBJ);
TxToUniv(tx, uint256(), entry);
- string jsonOutput = entry.write(4);
+ std::string jsonOutput = entry.write(4);
fprintf(stdout, "%s\n", jsonOutput.c_str());
}
static void OutputTxHash(const CTransaction& tx)
{
- string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
+ std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
fprintf(stdout, "%s\n", strHexHash.c_str());
}
static void OutputTxHex(const CTransaction& tx)
{
- string strHex = EncodeHexTx(tx);
+ std::string strHex = EncodeHexTx(tx);
fprintf(stdout, "%s\n", strHex.c_str());
}
@@ -593,10 +591,10 @@ static void OutputTx(const CTransaction& tx)
OutputTxHex(tx);
}
-static string readStdin()
+static std::string readStdin()
{
char buf[4096];
- string ret;
+ std::string ret;
while (!feof(stdin)) {
size_t bread = fread(buf, 1, sizeof(buf), stdin);
@@ -606,7 +604,7 @@ static string readStdin()
}
if (ferror(stdin))
- throw runtime_error("error reading stdin");
+ throw std::runtime_error("error reading stdin");
boost::algorithm::trim_right(ret);
@@ -615,7 +613,7 @@ static string readStdin()
static int CommandLineRawTx(int argc, char* argv[])
{
- string strPrint;
+ std::string strPrint;
int nRet = 0;
try {
// Skip switches; Permit common stdin convention "-"
@@ -631,15 +629,15 @@ static int CommandLineRawTx(int argc, char* argv[])
if (!fCreateBlank) {
// require at least one param
if (argc < 2)
- throw runtime_error("too few parameters");
+ throw std::runtime_error("too few parameters");
// param: hex-encoded bitcoin transaction
- string strHexTx(argv[1]);
+ std::string strHexTx(argv[1]);
if (strHexTx == "-") // "-" implies standard input
strHexTx = readStdin();
if (!DecodeHexTx(txDecodeTmp, strHexTx, true))
- throw runtime_error("invalid transaction encoding");
+ throw std::runtime_error("invalid transaction encoding");
startArg = 2;
} else
@@ -648,10 +646,10 @@ static int CommandLineRawTx(int argc, char* argv[])
CMutableTransaction tx(txDecodeTmp);
for (int i = startArg; i < argc; i++) {
- string arg = argv[i];
- string key, value;
+ std::string arg = argv[i];
+ std::string key, value;
size_t eqpos = arg.find('=');
- if (eqpos == string::npos)
+ if (eqpos == std::string::npos)
key = arg;
else {
key = arg.substr(0, eqpos);
@@ -668,7 +666,7 @@ static int CommandLineRawTx(int argc, char* argv[])
throw;
}
catch (const std::exception& e) {
- strPrint = string("error: ") + e.what();
+ strPrint = std::string("error: ") + e.what();
nRet = EXIT_FAILURE;
}
catch (...) {
diff --git a/src/main.cpp b/src/main.cpp
index 2fe993ca49..6bb81fab24 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -18,6 +18,7 @@
#include "init.h"
#include "merkleblock.h"
#include "net.h"
+#include "netmessagemaker.h"
#include "netbase.h"
#include "policy/fees.h"
#include "policy/policy.h"
@@ -368,8 +369,8 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices));
CAddress addrMe = CAddress(CService(), nLocalNodeServices);
- connman.PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
- nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes);
+ connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
+ nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes));
if (fLogIPs)
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
@@ -530,13 +531,13 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
- connman.PushMessage(pnodeStop, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
return true;
});
lNodesAnnouncingHeaderAndIDs.pop_front();
}
fAnnounceUsingCMPCTBLOCK = true;
- connman.PushMessage(pfrom, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
}
}
@@ -4886,9 +4887,8 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
{
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
-
vector<CInv> vNotFound;
-
+ CNetMsgMaker msgMaker(pfrom->GetSendVersion());
LOCK(cs_main);
while (it != pfrom->vRecvGetData.end()) {
@@ -4942,9 +4942,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
if (!ReadBlockFromDisk(block, (*mi).second, consensusParams))
assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
- connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
+ connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block));
else if (inv.type == MSG_WITNESS_BLOCK)
- connman.PushMessage(pfrom, NetMsgType::BLOCK, block);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, block));
else if (inv.type == MSG_FILTERED_BLOCK)
{
bool sendMerkleBlock = false;
@@ -4957,7 +4957,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
}
if (sendMerkleBlock) {
- connman.PushMessage(pfrom, NetMsgType::MERKLEBLOCK, merkleBlock);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock));
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
// Note that there is currently no way for a node to request any single transactions we didn't send here -
@@ -4966,7 +4966,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
- connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *block.vtx[pair.first]);
+ connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *block.vtx[pair.first]));
}
// else
// no response
@@ -4978,11 +4978,12 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// and we don't feel like constructing the object for them, so
// instead we respond with the full, non-compact block.
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;
+ int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness);
- connman.PushMessageWithFlag(pfrom, fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
+ connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
} else
- connman.PushMessageWithFlag(pfrom, fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
+ connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, block));
}
// Trigger the peer node to send a getblocks request for the next batch of inventory
@@ -4993,7 +4994,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// wait for other stuff first.
vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
- connman.PushMessage(pfrom, NetMsgType::INV, vInv);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv));
pfrom->hashContinue.SetNull();
}
}
@@ -5003,15 +5004,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// Send stream from relay memory
bool push = false;
auto mi = mapRelay.find(inv.hash);
+ int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
if (mi != mapRelay.end()) {
- connman.PushMessageWithFlag(pfrom, inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, NetMsgType::TX, *mi->second);
+ connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
push = true;
} else if (pfrom->timeLastMempoolReq) {
auto txinfo = mempool.info(inv.hash);
// To protect privacy, do not answer getdata using the mempool when
// that TX couldn't have been INVed in reply to a MEMPOOL request.
if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) {
- connman.PushMessageWithFlag(pfrom, inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, NetMsgType::TX, *txinfo.tx);
+ connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
push = true;
}
}
@@ -5038,7 +5040,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// do that because they want to know about (and store and rebroadcast and
// risk analyze) the dependencies of transactions relevant to them, without
// having to download the entire memory pool.
- connman.PushMessage(pfrom, NetMsgType::NOTFOUND, vNotFound);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound));
}
}
@@ -5079,16 +5081,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (strCommand == NetMsgType::VERSION)
{
- // Feeler connections exist only to verify if address is online.
- if (pfrom->fFeeler) {
- assert(pfrom->fInbound == false);
- pfrom->fDisconnect = true;
- }
-
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
- connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
+ connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")));
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 1);
return false;
@@ -5108,8 +5104,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pfrom->nServicesExpected & ~pfrom->nServices)
{
LogPrint("net", "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->id, pfrom->nServices, pfrom->nServicesExpected);
- connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
- strprintf("Expected to offer services %08x", pfrom->nServicesExpected));
+ connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
+ strprintf("Expected to offer services %08x", pfrom->nServicesExpected)));
pfrom->fDisconnect = true;
return false;
}
@@ -5118,8 +5114,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
// disconnect from peers older than this proto version
LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
- connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
- strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION));
+ connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
+ strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)));
pfrom->fDisconnect = true;
return false;
}
@@ -5176,8 +5172,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// Change version
- connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::VERACK);
- pfrom->SetSendVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
+ connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
+ int nSendVersion = std::min(pfrom->nVersion, PROTOCOL_VERSION);
+ pfrom->SetSendVersion(nSendVersion);
if (!pfrom->fInbound)
{
@@ -5200,7 +5197,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Get recent addresses
if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000)
{
- connman.PushMessage(pfrom, NetMsgType::GETADDR);
+ connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
pfrom->fGetAddr = true;
}
connman.MarkAddressGood(pfrom->addr);
@@ -5220,6 +5217,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int64_t nTimeOffset = nTime - GetTime();
pfrom->nTimeOffset = nTimeOffset;
AddTimeData(pfrom->addr, nTimeOffset);
+
+ // Feeler connections exist only to verify if address is online.
+ if (pfrom->fFeeler) {
+ assert(pfrom->fInbound == false);
+ pfrom->fDisconnect = true;
+ }
+ return true;
}
@@ -5231,8 +5235,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return false;
}
+ // At this point, the outgoing message serialization version can't change.
+ CNetMsgMaker msgMaker(pfrom->GetSendVersion());
- else if (strCommand == NetMsgType::VERACK)
+ if (strCommand == NetMsgType::VERACK)
{
pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
@@ -5247,7 +5253,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// 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);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
}
if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) {
// Tell our peer we are willing to provide version 1 or 2 cmpctblocks
@@ -5258,9 +5264,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 2;
if (pfrom->GetLocalServices() & NODE_WITNESS)
- connman.PushMessage(pfrom, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
nCMPCTBLOCKVersion = 1;
- connman.PushMessage(pfrom, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
}
}
@@ -5385,7 +5391,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// fell back to inv we probably have a reorg which we should get the headers for first,
// we now only provide a getheaders response here. When we receive the headers, we will
// then ask for the blocks we need.
- connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash));
LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
}
}
@@ -5408,7 +5414,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
if (!vToFetch.empty())
- connman.PushMessage(pfrom, NetMsgType::GETDATA, vToFetch);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vToFetch));
}
@@ -5520,7 +5526,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
resp.txn[i] = block.vtx[req.indexes[i]];
}
- connman.PushMessageWithFlag(pfrom, State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp);
+ int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
+ connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
}
@@ -5569,7 +5576,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip.
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
- connman.PushMessage(pfrom, NetMsgType::HEADERS, vHeaders);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
}
@@ -5732,8 +5739,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->id,
FormatStateMessage(state));
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
- connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
- state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
+ state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash));
if (nDoS > 0) {
Misbehaving(pfrom->GetId(), nDoS);
}
@@ -5751,7 +5758,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!IsInitialBlockDownload())
- connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
return true;
}
@@ -5784,7 +5791,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// so we just grab the block via normal getdata
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, NetMsgType::GETDATA, vInv);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
}
return true;
}
@@ -5828,7 +5835,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Duplicate txindexes, the block is now in-flight, so just request it
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, NetMsgType::GETDATA, vInv);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return true;
}
@@ -5852,7 +5859,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman);
} else {
req.blockhash = pindex->GetBlockHash();
- connman.PushMessage(pfrom, NetMsgType::GETBLOCKTXN, req);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
}
}
} else {
@@ -5861,7 +5868,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// mempool will probably be useless - request the block normally
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, NetMsgType::GETDATA, vInv);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return true;
} else {
// If this was an announce-cmpctblock, we want the same treatment as a header message
@@ -5903,7 +5910,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Might have collided, fall back to getdata now :(
std::vector<CInv> invs;
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash));
- connman.PushMessage(pfrom, NetMsgType::GETDATA, invs);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
} else {
// Block is either okay, or possibly we received
// READ_STATUS_CHECKBLOCK_FAILED.
@@ -5980,7 +5987,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// nUnconnectingHeaders gets reset back to 0.
if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++;
- connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
LogPrint("net", "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(),
@@ -6027,7 +6034,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
- connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256());
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
}
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
@@ -6080,7 +6087,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// In any case, we want to download using a compact block, not a regular one
vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
}
- connman.PushMessage(pfrom, NetMsgType::GETDATA, vGetData);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
}
}
}
@@ -6184,7 +6191,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// it, if the remote node sends a ping once per second and this node takes 5
// seconds to respond to each, the 5th ping the remote sends would appear to
// return very quickly.
- connman.PushMessage(pfrom, NetMsgType::PONG, nonce);
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
}
}
@@ -6440,7 +6447,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman)
}
catch (const std::ios_base::failure& e)
{
- connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message"));
+ connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")));
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from under-length message on vRecv
@@ -6505,9 +6512,12 @@ bool SendMessages(CNode* pto, CConnman& connman)
const Consensus::Params& consensusParams = Params().GetConsensus();
{
// Don't send anything until we get its version message
- if (pto->nVersion == 0)
+ if (pto->nVersion == 0 || pto->fDisconnect)
return true;
+ // If we get here, the outgoing message serialization version is set and can't change.
+ CNetMsgMaker msgMaker(pto->GetSendVersion());
+
//
// Message: ping
//
@@ -6520,7 +6530,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
// Ping automatically sent as a latency probe & keepalive.
pingSend = true;
}
- if (pingSend && !pto->fDisconnect) {
+ if (pingSend) {
uint64_t nonce = 0;
while (nonce == 0) {
GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
@@ -6529,11 +6539,11 @@ bool SendMessages(CNode* pto, CConnman& connman)
pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
- connman.PushMessage(pto, NetMsgType::PING, nonce);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
} else {
// Peer is too old to support ping command with nonce, pong will never arrive.
pto->nPingNonceSent = 0;
- connman.PushMessage(pto, NetMsgType::PING);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING));
}
}
@@ -6541,6 +6551,28 @@ bool SendMessages(CNode* pto, CConnman& connman)
if (!lockMain)
return true;
+ CNodeState &state = *State(pto->GetId());
+
+ BOOST_FOREACH(const CBlockReject& reject, state.rejects)
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
+ state.rejects.clear();
+
+ if (state.fShouldBan) {
+ state.fShouldBan = false;
+ if (pto->fWhitelisted)
+ LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString());
+ else {
+ pto->fDisconnect = true;
+ if (pto->addr.IsLocal())
+ LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
+ else
+ {
+ connman.Ban(pto->addr, BanReasonNodeMisbehaving);
+ }
+ return true;
+ }
+ }
+
// Address refresh broadcast
int64_t nNow = GetTimeMicros();
if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
@@ -6564,44 +6596,24 @@ bool SendMessages(CNode* pto, CConnman& connman)
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
- connman.PushMessage(pto, NetMsgType::ADDR, vAddr);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
- connman.PushMessage(pto, NetMsgType::ADDR, vAddr);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
// we only send the big addr message once
if (pto->vAddrToSend.capacity() > 40)
pto->vAddrToSend.shrink_to_fit();
}
- CNodeState &state = *State(pto->GetId());
- if (state.fShouldBan) {
- if (pto->fWhitelisted)
- LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString());
- else {
- pto->fDisconnect = true;
- if (pto->addr.IsLocal())
- LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
- else
- {
- connman.Ban(pto->addr, BanReasonNodeMisbehaving);
- }
- }
- state.fShouldBan = false;
- }
-
- BOOST_FOREACH(const CBlockReject& reject, state.rejects)
- connman.PushMessage(pto, NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock);
- state.rejects.clear();
-
// Start block sync
if (pindexBestHeader == NULL)
pindexBestHeader = chainActive.Tip();
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do.
- if (!state.fSyncStarted && !pto->fClient && !pto->fDisconnect && !fImporting && !fReindex) {
+ if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today.
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
state.fSyncStarted = true;
@@ -6617,7 +6629,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight);
- connman.PushMessage(pto, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256());
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()));
}
}
@@ -6706,7 +6718,8 @@ bool SendMessages(CNode* pto, CConnman& connman)
CBlock block;
assert(ReadBlockFromDisk(block, pBestIndex, consensusParams));
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
- connman.PushMessageWithFlag(pto, state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
+ int nSendFlags = state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
+ connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
state.pindexBestHeaderSent = pBestIndex;
} else if (state.fPreferHeaders) {
if (vHeaders.size() > 1) {
@@ -6718,7 +6731,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
LogPrint("net", "%s: sending header %s to peer=%d\n", __func__,
vHeaders.front().GetHash().ToString(), pto->id);
}
- connman.PushMessage(pto, NetMsgType::HEADERS, vHeaders);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
state.pindexBestHeaderSent = pBestIndex;
} else
fRevertToInv = true;
@@ -6764,7 +6777,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
BOOST_FOREACH(const uint256& hash, pto->vInventoryBlockToSend) {
vInv.push_back(CInv(MSG_BLOCK, hash));
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, NetMsgType::INV, vInv);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
@@ -6810,7 +6823,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
pto->filterInventoryKnown.insert(hash);
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, NetMsgType::INV, vInv);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
@@ -6876,7 +6889,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
}
}
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, NetMsgType::INV, vInv);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
pto->filterInventoryKnown.insert(hash);
@@ -6884,28 +6897,30 @@ bool SendMessages(CNode* pto, CConnman& connman)
}
}
if (!vInv.empty())
- connman.PushMessage(pto, NetMsgType::INV, vInv);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
// Detect whether we're stalling
nNow = GetTimeMicros();
- if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) {
+ if (state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) {
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
// should only happen during initial block download.
LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id);
pto->fDisconnect = true;
+ return true;
}
// In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval
// (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout.
// We compensate for other peers to prevent killing off peers due to our own downstream link
// being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
// to unreasonably increase our timeout.
- if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) {
+ if (state.vBlocksInFlight.size() > 0) {
QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0);
if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) {
LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id);
pto->fDisconnect = true;
+ return true;
}
}
@@ -6913,7 +6928,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
// Message: getdata (blocks)
//
vector<CInv> vGetData;
- if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
vector<CBlockIndex*> vToDownload;
NodeId staller = -1;
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
@@ -6935,7 +6950,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
//
// Message: getdata (non-blocks)
//
- while (!pto->fDisconnect && !pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
+ while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
{
const CInv& inv = (*pto->mapAskFor.begin()).second;
if (!AlreadyHave(inv))
@@ -6945,7 +6960,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
- connman.PushMessage(pto, NetMsgType::GETDATA, vGetData);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
vGetData.clear();
}
} else {
@@ -6955,20 +6970,20 @@ bool SendMessages(CNode* pto, CConnman& connman)
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
- connman.PushMessage(pto, NetMsgType::GETDATA, vGetData);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
//
// Message: feefilter
//
// We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
- if (!pto->fDisconnect && pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
!(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
int64_t timeNow = GetTimeMicros();
if (timeNow > pto->nextSendTimeFeeFilter) {
CAmount filterToSend = filterRounder.round(currentFilter);
if (filterToSend != pto->lastSentFeeFilter) {
- connman.PushMessage(pto, NetMsgType::FEEFILTER, filterToSend);
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
pto->lastSentFeeFilter = filterToSend;
}
pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
diff --git a/src/net.cpp b/src/net.cpp
index 15c4514f15..ce87150ae3 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -768,13 +768,13 @@ const uint256& CNetMessage::GetMessageHash() const
// requires LOCK(cs_vSend)
size_t SocketSendData(CNode *pnode)
{
- std::deque<CSerializeData>::iterator it = pnode->vSendMsg.begin();
+ auto it = pnode->vSendMsg.begin();
size_t nSentSize = 0;
while (it != pnode->vSendMsg.end()) {
- const CSerializeData &data = *it;
+ const auto &data = *it;
assert(data.size() > pnode->nSendOffset);
- int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
+ int nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
if (nBytes > 0) {
pnode->nLastSend = GetTime();
pnode->nSendBytes += nBytes;
@@ -2612,30 +2612,19 @@ void CNode::AskFor(const CInv& inv)
mapAskFor.insert(std::make_pair(nRequestTime, inv));
}
-CDataStream CConnman::BeginMessage(CNode* pnode, int nVersion, int flags, const std::string& sCommand)
+void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
{
- return {SER_NETWORK, (nVersion ? nVersion : pnode->GetSendVersion()) | flags, CMessageHeader(Params().MessageStart(), sCommand.c_str(), 0) };
-}
-
-void CConnman::EndMessage(CDataStream& strm)
-{
- // Set the size
- assert(strm.size () >= CMessageHeader::HEADER_SIZE);
- unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE;
- WriteLE32((uint8_t*)&strm[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
- // Set the checksum
- uint256 hash = Hash(strm.begin() + CMessageHeader::HEADER_SIZE, strm.end());
- memcpy((char*)&strm[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE);
-
-}
+ size_t nMessageSize = msg.data.size();
+ size_t nTotalSize = nMessageSize + CMessageHeader::HEADER_SIZE;
+ LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.command.c_str()), nMessageSize, pnode->id);
-void CConnman::PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand)
-{
- if(strm.empty())
- return;
+ std::vector<unsigned char> serializedHeader;
+ serializedHeader.reserve(CMessageHeader::HEADER_SIZE);
+ uint256 hash = Hash(msg.data.data(), msg.data.data() + nMessageSize);
+ CMessageHeader hdr(Params().MessageStart(), msg.command.c_str(), nMessageSize);
+ memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
- unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE;
- LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(sCommand.c_str()), nSize, pnode->id);
+ CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, serializedHeader, 0, hdr};
size_t nBytesSent = 0;
{
@@ -2644,11 +2633,14 @@ void CConnman::PushMessage(CNode* pnode, CDataStream& strm, const std::string& s
return;
}
bool optimisticSend(pnode->vSendMsg.empty());
- pnode->vSendMsg.emplace_back(strm.begin(), strm.end());
//log total amount of bytes per command
- pnode->mapSendBytesPerMsgCmd[sCommand] += strm.size();
- pnode->nSendSize += strm.size();
+ pnode->mapSendBytesPerMsgCmd[msg.command] += nTotalSize;
+ pnode->nSendSize += nTotalSize;
+
+ pnode->vSendMsg.push_back(std::move(serializedHeader));
+ if (nMessageSize)
+ pnode->vSendMsg.push_back(std::move(msg.data));
// If write queue empty, attempt "optimistic write"
if (optimisticSend == true)
diff --git a/src/net.h b/src/net.h
index 7a32e21f4a..a4a9fb676a 100644
--- a/src/net.h
+++ b/src/net.h
@@ -101,6 +101,20 @@ class CTransaction;
class CNodeStats;
class CClientUIInterface;
+struct CSerializedNetMsg
+{
+ CSerializedNetMsg() = default;
+ CSerializedNetMsg(CSerializedNetMsg&&) = default;
+ CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default;
+ // No copying, only moves.
+ CSerializedNetMsg(const CSerializedNetMsg& msg) = delete;
+ CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;
+
+ std::vector<unsigned char> data;
+ std::string command;
+};
+
+
class CConnman
{
public:
@@ -138,32 +152,7 @@ public:
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
- template <typename... Args>
- void PushMessageWithVersionAndFlag(CNode* pnode, int nVersion, int flag, const std::string& sCommand, Args&&... args)
- {
- auto msg(BeginMessage(pnode, nVersion, flag, sCommand));
- ::SerializeMany(msg, std::forward<Args>(args)...);
- EndMessage(msg);
- PushMessage(pnode, msg, sCommand);
- }
-
- template <typename... Args>
- void PushMessageWithFlag(CNode* pnode, int flag, const std::string& sCommand, Args&&... args)
- {
- PushMessageWithVersionAndFlag(pnode, 0, flag, sCommand, std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- void PushMessageWithVersion(CNode* pnode, int nVersion, const std::string& sCommand, Args&&... args)
- {
- PushMessageWithVersionAndFlag(pnode, nVersion, 0, sCommand, std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- void PushMessage(CNode* pnode, const std::string& sCommand, Args&&... args)
- {
- PushMessageWithVersionAndFlag(pnode, 0, 0, sCommand, std::forward<Args>(args)...);
- }
+ void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);
template<typename Callable>
bool ForEachNodeContinueIf(Callable&& func)
@@ -374,10 +363,6 @@ private:
unsigned int GetReceiveFloodSize() const;
- CDataStream BeginMessage(CNode* node, int nVersion, int flags, const std::string& sCommand);
- void PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand);
- void EndMessage(CDataStream& strm);
-
// Network stats
void RecordBytesRecv(uint64_t bytes);
void RecordBytesSent(uint64_t bytes);
@@ -601,7 +586,7 @@ public:
size_t nSendSize; // total size of all vSendMsg entries
size_t nSendOffset; // offset inside the first vSendMsg already sent
uint64_t nSendBytes;
- std::deque<CSerializeData> vSendMsg;
+ std::deque<std::vector<unsigned char>> vSendMsg;
CCriticalSection cs_vSend;
std::deque<CInv> vRecvGetData;
@@ -771,7 +756,7 @@ public:
{
// The send version should always be explicitly set to
// INIT_PROTO_VERSION rather than using this value until the handshake
- // is complete. See PushMessageWithVersion().
+ // is complete.
assert(nSendVersion != 0);
return nSendVersion;
}
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
new file mode 100644
index 0000000000..7167434a19
--- /dev/null
+++ b/src/netmessagemaker.h
@@ -0,0 +1,36 @@
+// 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_NETMESSAGEMAKER_H
+#define BITCOIN_NETMESSAGEMAKER_H
+
+#include "net.h"
+#include "serialize.h"
+
+class CNetMsgMaker
+{
+public:
+ CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
+
+ template <typename... Args>
+ CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args)
+ {
+ CSerializedNetMsg msg;
+ msg.command = std::move(sCommand);
+ CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
+ return msg;
+ }
+
+ template <typename... Args>
+ CSerializedNetMsg Make(std::string sCommand, Args&&... args)
+ {
+ return Make(0, std::move(sCommand), std::forward<Args>(args)...);
+ }
+
+private:
+ const int nVersion;
+};
+
+#endif // BITCOIN_NETMESSAGEMAKER_H
diff --git a/src/streams.h b/src/streams.h
index c3e7c9e9e4..b508784238 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -69,6 +69,75 @@ OverrideStream<S> WithOrVersion(S* s, int nVersionFlag)
return OverrideStream<S>(s, s->GetType(), s->GetVersion() | nVersionFlag);
}
+/* Minimal stream for overwriting and/or appending to an existing byte vector
+ *
+ * The referenced vector will grow as necessary
+ */
+class CVectorWriter
+{
+ public:
+
+/*
+ * @param[in] nTypeIn Serialization Type
+ * @param[in] nVersionIn Serialization Version (including any flags)
+ * @param[in] vchDataIn Referenced byte vector to overwrite/append
+ * @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
+ * grow as necessary to max(index, vec.size()). So to append, use vec.size().
+*/
+ CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
+ {
+ if(nPos > vchData.size())
+ vchData.resize(nPos);
+ }
+/*
+ * (other params same as above)
+ * @param[in] args A list of items to serialize starting at nPos.
+*/
+ template <typename... Args>
+ CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
+ {
+ ::SerializeMany(*this, std::forward<Args>(args)...);
+ }
+ void write(const char* pch, size_t nSize)
+ {
+ assert(nPos <= vchData.size());
+ size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
+ if (nOverwrite) {
+ memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
+ }
+ if (nOverwrite < nSize) {
+ vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
+ }
+ nPos += nSize;
+ }
+ template<typename T>
+ CVectorWriter& operator<<(const T& obj)
+ {
+ // Serialize to this stream
+ ::Serialize(*this, obj);
+ return (*this);
+ }
+ int GetVersion() const
+ {
+ return nVersion;
+ }
+ int GetType() const
+ {
+ return nType;
+ }
+ void seek(size_t nSize)
+ {
+ nPos += nSize;
+ if(nPos > vchData.size())
+ vchData.resize(nPos);
+ }
+private:
+ const int nType;
+ const int nVersion;
+ std::vector<unsigned char>& vchData;
+ size_t nPos;
+};
+
/** Double ended buffer combining vector and stream-like interfaces.
*
* >> and << read and write unformatted data using the above serialization templates.
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 2f299aa5fe..27acb2f16a 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -53,7 +53,7 @@
["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"],
["It results in signing the constant 1, instead of something generated based on the transaction,"],
["when the input doing the signing has an index greater than the maximum output index"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"], ["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"]],
"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"],
["An invalid P2SH Transaction"],
@@ -334,9 +334,9 @@
"0100000000010100010000000000000000000000000000000000000000000000000000000000000000000023220020ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000", "P2SH,WITNESS"],
["Witness with SigHash Single|AnyoneCanPay"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000],
-["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
+["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]],
"0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000", "P2SH,WITNESS"],
@@ -359,9 +359,9 @@
"0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"],
["Witness with SigHash None|AnyoneCanPay"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
+["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000],
-["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]],
"0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff04b60300000000000001519e070000000000000151860b00000000000001009600000000000000015100000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"],
@@ -390,9 +390,9 @@
"01000000000103000100000000000000000000000000000000000000000000000000000000000000000000000200000000010000000000000000000000000000000000000000000000000000000000000100000000ffffffff000100000000000000000000000000000000000000000000000000000000000002000000000200000003e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"],
["Witness with SigHash All|AnyoneCanPay"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
+["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000],
-["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]],
"0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"],
@@ -458,8 +458,8 @@
"0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff02e8030000000000000151e90300000000000001510247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "P2SH,WITNESS"],
["Witness Single|AnyoneCanPay does not hash input's position (permutation)"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1000],
-["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1001]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1001],
+["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1000]],
"0100000000010200010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff02e9030000000000000151e80300000000000001510248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "P2SH,WITNESS"],
["Non witness Single|AnyoneCanPay hash input's position"],
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 34f501e867..8b715ce93e 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -15,6 +15,64 @@ using namespace boost::assign; // bring 'operator+=()' into scope
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(streams_vector_writer)
+{
+ unsigned char a(1);
+ unsigned char b(2);
+ unsigned char bytes[] = { 3, 4, 5, 6 };
+ std::vector<unsigned char> vch;
+
+ // Each test runs twice. Serializing a second time at the same starting
+ // point should yield the same results, even if the first test grew the
+ // vector.
+
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
+ vch.clear();
+
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
+ vch.clear();
+
+ vch.resize(5, 0);
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
+ vch.clear();
+
+ vch.resize(4, 0);
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
+ vch.clear();
+
+ vch.resize(4, 0);
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
+ vch.clear();
+
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
+ BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
+ BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
+ vch.clear();
+
+ vch.resize(4, 8);
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
+ vch.clear();
+}
+
BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
{
std::vector<char> in;