Browse Source

Auto merge of #1105 - bitcartel:zc.v0.11.2.z6_issue_424, r=ebfull

New private/public key pairs for broadcasting alert messages

Implements #424

Fixes and integrates method of sending alerts as described by upstream here:
- https://gist.github.com/laanwj/0e689cfa37b52bcbbb44

To send an alert:
- Copy private keys into alertkeys.h.
- Modify alert parameters and message found in sendalert.cpp
- Build and run to send the alert e.g. ./zcashd -printtoconsole -sendalert

Tested and verified with local nodes on alpha 6 testnet.
pull/145/head
zkbot 8 years ago
parent
commit
d20d866d89
  1. 1
      src/Makefile.am
  2. 10
      src/alertkeys.h
  3. 4
      src/chainparams.cpp
  4. 5
      src/init.cpp
  5. 159
      src/sendalert.cpp
  6. 178
      src/test/alert_tests.cpp
  7. BIN
      src/test/data/alertTests.raw

1
src/Makefile.am

@ -188,6 +188,7 @@ libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# server: shared between bitcoind and bitcoin-qt
libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS)
libbitcoin_server_a_SOURCES = \
sendalert.cpp \
addrman.cpp \
alert.cpp \
bloom.cpp \

10
src/alertkeys.h

@ -0,0 +1,10 @@
#ifndef BITCOIN_ALERTKEYS_H
#define BITCOIN_ALERTKEYS_H
// REMINDER: DO NOT COMMIT YOUR PRIVATE KEYS TO THE GIT REPOSITORY!
const char* pszPrivKey = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
const char* pszTestNetPrivKey = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
#endif

4
src/chainparams.cpp

@ -54,7 +54,7 @@ public:
pchMessageStart[1] = 0xee;
pchMessageStart[2] = 0x4e;
pchMessageStart[3] = 0xd8;
vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
vAlertPubKey = ParseHex("04b7ecf0baa90495ceb4e4090f6b2fd37eec1e9c85fac68a487f3ce11589692e4a317479316ee814e066638e1db54e37a10689b70286e6315b1087b6615d179264");
nDefaultPort = 8233;
nMinerThreads = 0;
nMaxTipAge = 24 * 60 * 60;
@ -149,7 +149,7 @@ public:
pchMessageStart[1] = 0xf0;
pchMessageStart[2] = 0x94;
pchMessageStart[3] = 0x11;
vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a");
vAlertPubKey = ParseHex("044e7a1553392325c871c5ace5d6ad73501c66f4c185d6b0453cf45dec5a1322e705c672ac1a27ef7cdaf588c10effdf50ed5f95f85f2f54a5f6159fca394ed0c6");
nDefaultPort = 18233;
nMinerThreads = 0;
nMaxTipAge = 0x7fffffff;

5
src/init.cpp

@ -52,6 +52,8 @@
using namespace std;
extern void ThreadSendAlert();
ZCJoinSplit* pzcashParams = NULL;
#ifdef ENABLE_WALLET
@ -1491,5 +1493,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
#endif
// SENDALERT
threadGroup.create_thread(boost::bind(ThreadSendAlert));
return !fRequestShutdown;
}

159
src/sendalert.cpp

@ -0,0 +1,159 @@
// Copyright (c) 2016 The Zcash developers
// Original code from: https://gist.github.com/laanwj/0e689cfa37b52bcbbb44
/*
To set up a new alert system
----------------------------
Create a new alert key pair:
openssl ecparam -name secp256k1 -genkey -param_enc explicit -outform PEM -out data.pem
Get the private key in hex:
openssl ec -in data.pem -outform DER | tail -c 279 | xxd -p -c 279
Get the public key in hex:
openssl ec -in data.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65
Update the public keys found in chainparams.cpp.
To send an alert message
------------------------
Copy the private keys into alertkeys.h.
Modify the alert parameters, id and message found in this file.
Build and run with -sendalert or -printalert.
./zcashd -printtoconsole -sendalert
One minute after starting up, the alert will be broadcast. It is then
flooded through the network until the nRelayUntil time, and will be
active until nExpiration OR the alert is cancelled.
If you make a mistake, send another alert with nCancel set to cancel
the bad alert.
*/
#include "main.h"
#include "net.h"
#include "alert.h"
#include "init.h"
#include "util.h"
#include "utiltime.h"
#include "key.h"
#include "clientversion.h"
#include "chainparams.h"
#include "alertkeys.h"
static const int64_t DAYS = 24 * 60 * 60;
void ThreadSendAlert()
{
if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert"))
return;
MilliSleep(60*1000); // Wait a minute so we get connected
//
// Alerts are relayed around the network until nRelayUntil, flood
// filling to every node.
// After the relay time is past, new nodes are told about alerts
// when they connect to peers, until either nExpiration or
// the alert is cancelled by a newer alert.
// Nodes never save alerts to disk, they are in-memory-only.
//
CAlert alert;
alert.nRelayUntil = GetTime() + 15 * 60;
alert.nExpiration = GetTime() + 365 * 60 * 60;
alert.nID = 1000; // use https://github.com/zcash/zcash/wiki/specification#assigned-numbers to keep track of alert IDs
alert.nCancel = 0; // cancels previous messages up to this ID number
// These versions are protocol versions
// 70002 : 0.11.2.*
alert.nMinVer = 70002;
alert.nMaxVer = 70002;
//
// main.cpp:
// 1000 for Misc warnings like out of disk space and clock is wrong
// 2000 for longer invalid proof-of-work chain
// Higher numbers mean higher priority
alert.nPriority = 5000;
alert.strComment = "";
alert.strStatusBar = "URGENT: Upgrade required: see https://z.cash";
// Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done:
// alert.setSubVer.insert(std::string("/Satoshi:0.7.2/"));
// Sign
const CChainParams& chainparams = Params();
std::string networkID = chainparams.NetworkIDString();
bool fIsTestNet = networkID.compare("test") == 0;
std::vector<unsigned char> vchTmp(ParseHex(fIsTestNet ? pszTestNetPrivKey : pszPrivKey));
CPrivKey vchPrivKey(vchTmp.begin(), vchTmp.end());
CDataStream sMsg(SER_NETWORK, CLIENT_VERSION);
sMsg << *(CUnsignedAlert*)&alert;
alert.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
CKey key;
if (!key.SetPrivKey(vchPrivKey, false))
{
printf("ThreadSendAlert() : key.SetPrivKey failed\n");
return;
}
if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
{
printf("ThreadSendAlert() : key.Sign failed\n");
return;
}
// Test
CDataStream sBuffer(SER_NETWORK, CLIENT_VERSION);
sBuffer << alert;
CAlert alert2;
sBuffer >> alert2;
if (!alert2.CheckSignature(chainparams.AlertKey()))
{
printf("ThreadSendAlert() : CheckSignature failed\n");
return;
}
assert(alert2.vchMsg == alert.vchMsg);
assert(alert2.vchSig == alert.vchSig);
alert.SetNull();
printf("\nThreadSendAlert:\n");
printf("hash=%s\n", alert2.GetHash().ToString().c_str());
printf("%s\n", alert2.ToString().c_str());
printf("vchMsg=%s\n", HexStr(alert2.vchMsg).c_str());
printf("vchSig=%s\n", HexStr(alert2.vchSig).c_str());
// Confirm
if (!mapArgs.count("-sendalert"))
return;
while (vNodes.size() < 1 && !ShutdownRequested())
MilliSleep(500);
if (ShutdownRequested())
return;
// Send
printf("ThreadSendAlert() : Sending alert\n");
int nSent = 0;
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (alert2.RelayTo(pnode))
{
printf("ThreadSendAlert() : Sent alert to %s\n", pnode->addr.ToString().c_str());
nSent++;
}
}
}
printf("ThreadSendAlert() : Alert sent to %d nodes\n", nSent);
}

178
src/test/alert_tests.cpp

@ -26,62 +26,208 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
#if 0
//
// alertTests contains 7 alerts, generated with this code:
// (SignAndSave code not shown, alert signing key is secret)
//
#include "key.h"
#include "alertkeys.h"
#include <iostream>
/*
* If the alert key pairs have changed, the test suite will fail as the
* test data is now invalid. To create valid test data, signed with a
* new alert private key, follow these steps:
*
* 1. Copy your private key into alertkeys.h. Don't commit this file!
* See sendalert.cpp for more info.
*
* 2. Set the GENERATE_ALERTS_FLAG to true.
*
* 3. Build and run:
* test_bitcoin -t Generate_Alert_Test_Data
*
* 4. Test data is saved in your current directory as alertTests.raw.NEW
* Copy this file to: src/test/data/alertTests.raw
*
* For debugging purposes, terminal output can be copied into:
* src/test/data/alertTests.raw.h
*
* 5. Clean up...
* - Set GENERATE_ALERTS_FLAG back to false.
* - Remove your private key from alertkeys.h
*
* 6. Build and verify the new test data:
* test_bitcoin -t Alert_tests
*
*/
#define GENERATE_ALERTS_FLAG false
#if GENERATE_ALERTS_FLAG
// NOTE:
// A function SignAndSave() was used by Bitcoin Core to create alert test data
// but it has not been made publicly available. So instead, we have adapted
// some publicly available code which achieves the intended result:
// https://gist.github.com/lukem512/9b272bd35e2cdefbf386
// Code to output a C-style array of values
template<typename T>
std::string HexStrArray(const T itbegin, const T itend, int lineLength)
{
std::string rv;
static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
rv.reserve((itend-itbegin)*3);
int i = 0;
for(T it = itbegin; it < itend; ++it)
{
unsigned char val = (unsigned char)(*it);
if(it != itbegin)
{
if (i % lineLength == 0)
rv.push_back('\n');
else
rv.push_back(' ');
}
rv.push_back('0');
rv.push_back('x');
rv.push_back(hexmap[val>>4]);
rv.push_back(hexmap[val&15]);
rv.push_back(',');
i++;
}
return rv;
}
template<typename T>
inline std::string HexStrArray(const T& vch, int lineLength)
{
return HexStrArray(vch.begin(), vch.end(), lineLength);
}
// Sign CAlert with alert private key
bool SignAlert(CAlert &alert)
{
// serialize alert data
CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
sMsg << *(CUnsignedAlert*)&alert;
alert.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
// sign alert
std::vector<unsigned char> vchTmp(ParseHex(pszPrivKey));
CPrivKey vchPrivKey(vchTmp.begin(), vchTmp.end());
CKey key;
if (!key.SetPrivKey(vchPrivKey, false))
{
printf("key.SetPrivKey failed\n");
return false;
}
if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
{
printf("SignAlert() : key.Sign failed\n");
return false;
}
return true;
}
// Sign a CAlert and serialize it
bool SignAndSerialize(CAlert &alert, CDataStream &buffer)
{
// Sign
if(!SignAlert(alert))
{
printf("SignAndSerialize() : could not sign alert\n");
return false;
}
// ...and save!
buffer << alert;
return true;
}
void GenerateAlertTests()
{
CDataStream sBuffer(SER_DISK, CLIENT_VERSION);
CAlert alert;
alert.nRelayUntil = 60;
alert.nExpiration = 24 * 60 * 60;
alert.nID = 1;
alert.nCancel = 0; // cancels previous messages up to this ID number
alert.nCancel = 0; // cancels previous messages up to this ID number
alert.nMinVer = 0; // These versions are protocol versions
alert.nMaxVer = 999001;
alert.nPriority = 1;
alert.strComment = "Alert comment";
alert.strStatusBar = "Alert 1";
SignAndSave(alert, "test/alertTests");
// Replace SignAndSave with SignAndSerialize
SignAndSerialize(alert, sBuffer);
// More tests go here ...
alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
alert.strStatusBar = "Alert 1 for Satoshi 0.1.0";
SignAndSave(alert, "test/alertTests");
SignAndSerialize(alert, sBuffer);
alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0";
SignAndSave(alert, "test/alertTests");
SignAndSerialize(alert, sBuffer);
alert.setSubVer.clear();
++alert.nID;
alert.nCancel = 1;
alert.nPriority = 100;
alert.strStatusBar = "Alert 2, cancels 1";
SignAndSave(alert, "test/alertTests");
SignAndSerialize(alert, sBuffer);
alert.nExpiration += 60;
++alert.nID;
SignAndSave(alert, "test/alertTests");
SignAndSerialize(alert, sBuffer);
++alert.nID;
alert.nMinVer = 11;
alert.nMaxVer = 22;
SignAndSave(alert, "test/alertTests");
SignAndSerialize(alert, sBuffer);
++alert.nID;
alert.strStatusBar = "Alert 2 for Satoshi 0.1.0";
alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
SignAndSave(alert, "test/alertTests");
SignAndSerialize(alert, sBuffer);
++alert.nID;
alert.nMinVer = 0;
alert.nMaxVer = 999999;
alert.strStatusBar = "Evil Alert'; /bin/ls; echo '";
alert.setSubVer.clear();
SignAndSave(alert, "test/alertTests");
bool b = SignAndSerialize(alert, sBuffer);
if (b) {
// Print the hex array, which will become the contents of alertTest.raw.h
std::vector<unsigned char> vch = std::vector<unsigned char>(sBuffer.begin(), sBuffer.end());
printf("%s\n", HexStrArray(vch, 8).c_str());
// Write the data to alertTests.raw.NEW, to be copied to src/test/data/alertTests.raw
std::ofstream outfile("alertTests.raw.NEW", std::ios::out | std::ios::binary);
outfile.write((const char*)&vch[0], vch.size());
outfile.close();
}
}
#endif
struct GenerateAlertTestsFixture : public TestingSetup {
GenerateAlertTestsFixture() {}
~GenerateAlertTestsFixture() {}
};
BOOST_FIXTURE_TEST_SUITE(Generate_Alert_Test_Data, GenerateAlertTestsFixture);
BOOST_AUTO_TEST_CASE(GenerateTheAlertTests)
{
GenerateAlertTests();
}
BOOST_AUTO_TEST_SUITE_END()
#else
struct ReadAlerts : public TestingSetup
{
@ -255,3 +401,5 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
}
BOOST_AUTO_TEST_SUITE_END()
#endif

BIN
src/test/data/alertTests.raw

Binary file not shown.
Loading…
Cancel
Save