diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj
index 1043e5e92..316da8440 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj
+++ b/Builds/VisualStudio2012/RippleD.vcxproj
@@ -19,6 +19,12 @@
+
+ true
+ true
+ true
+ true
+
true
true
@@ -1318,9 +1324,8 @@
-
+
-
diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters
index 60d2cee69..7ebed7d71 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters
@@ -870,6 +870,9 @@
[0] Subtrees\beast
+
+ [1] Ripple\ripple_app\basics
+
@@ -1287,12 +1290,6 @@
[1] Ripple\ripple_client
-
- [1] Ripple\ripple_app\basics
-
-
- [1] Ripple\ripple_app\basics
-
[1] Ripple\ripple_basics\utility
@@ -1659,6 +1656,9 @@
[1] Ripple\ripple_core\validator
+
+ [1] Ripple\ripple_app\basics
+
diff --git a/TODO.txt b/TODO.txt
index 0a5bf27bc..75efe6c79 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -122,8 +122,6 @@ David Features:
use read/write locking semantics to update the values. Later, use Listeners
to notify dependent code to resolve the dependency inversion.
-- Merge ripple_Version.h and ripple_BuildVersion.h
-
- Rename LoadMonitor to LoadMeter, change LoadEvent to LoadMeter::ScopedSample
- Rename LedgerMaster to Ledgers, create ILedgers interface.
diff --git a/modules/ripple_app/basics/ripple_BuildInfo.cpp b/modules/ripple_app/basics/ripple_BuildInfo.cpp
new file mode 100644
index 000000000..c52bcad4d
--- /dev/null
+++ b/modules/ripple_app/basics/ripple_BuildInfo.cpp
@@ -0,0 +1,305 @@
+//------------------------------------------------------------------------------
+/*
+ Copyright (c) 2011-2013, OpenCoin, Inc.
+*/
+//==============================================================================
+
+String const& BuildInfo::getVersionString ()
+{
+ static char const* const rawText =
+
+ //--------------------------------------------------------------------------
+ //
+ // The build version number (edit this for each release)
+ //
+ "0.010-rc1"
+ //
+ //--------------------------------------------------------------------------
+ ;
+
+ struct StaticInitializer
+ {
+ StaticInitializer ()
+ {
+ // Sanity checking on the raw text
+
+ Version v;
+
+ if (! v.parse (rawText) || v.print () != rawText)
+ Throw (std::invalid_argument ("illegal server version format string"));
+
+ versionString = rawText;
+ }
+
+ String versionString;
+ };
+
+ static StaticInitializer value;
+
+ return value.versionString;
+}
+
+// The protocol version we speak and prefer.
+//
+BuildInfo::Protocol const& BuildInfo::getCurrentProtocol ()
+{
+ static Protocol currentProtocol (1, 2);
+
+ return currentProtocol;
+}
+
+// The oldest protocol version we will accept.
+//
+BuildInfo::Protocol const& BuildInfo::getMinimumProtocol ()
+{
+ static Protocol minimumProtocol (1, 2);
+
+ return minimumProtocol;
+}
+
+
+
+// Don't touch anything below this line
+//------------------------------------------------------------------------------
+
+char const* BuildInfo::getFullVersionString ()
+{
+ struct StaticInitializer
+ {
+ StaticInitializer ()
+ {
+ String s;
+
+ s << "Ripple-" << getVersionString ();
+
+ fullVersionString = s.toStdString ();
+ }
+
+ std::string fullVersionString;
+ };
+
+ static StaticInitializer value;
+
+ return value.fullVersionString.c_str ();
+}
+
+//------------------------------------------------------------------------------
+
+BuildInfo::Version::Version ()
+ : vmajor (0)
+ , vminor (0)
+{
+}
+
+bool BuildInfo::Version::parse (String const& s)
+{
+ // Many not have leading or trailing whitespace
+ if (s.trim () != s)
+ return false;
+
+ int const indexOfDot = s.indexOfChar ('.');
+
+ // Must have a dot
+ if (indexOfDot == -1)
+ return false;
+
+ String const majorString = s.substring (0, indexOfDot);
+
+ // Must only contain digits
+ if (! majorString.containsOnly ("0123456789"))
+ return false;
+
+ // Must match after conversion back and forth
+ if (String (majorString.getIntValue ()) != majorString)
+ return false;
+
+ int const indexOfDash = s.indexOfChar ('-');
+
+ // A dash must come after the dot.
+ if (indexOfDash >= 0 && indexOfDash <= indexOfDot)
+ return false;
+
+ String const minorString = (indexOfDash == -1) ?
+ s.substring (indexOfDot + 1) : s.substring (indexOfDot + 1, indexOfDash);
+
+ // Must be length three
+ if (minorString.length () != 3)
+ return false;
+
+ // Must only contain digits
+ if (! minorString.containsOnly ("0123456789"))
+ return false;
+
+ String const suffixString = (indexOfDash == -1) ?
+ "" : s.substring (indexOfDash + 1);
+
+ if (suffixString.length () > 0)
+ {
+ // Must be 4 characters or less
+ if (suffixString.length () > 4)
+ return false;
+
+ // Must start with a letter
+ if (! String::charToString (suffixString [0]).containsOnly ("abcdefghijklmnopqrstuvwxyz"))
+ return false;
+
+ // Must only contain letters and numbers
+ if (! String::charToString (suffixString [0]).containsOnly ("abcdefghijklmnopqrstuvwxyz01234567890"))
+ return false;
+ }
+
+ vmajor = majorString.getIntValue ();
+ vminor = minorString.getIntValue ();
+ suffix = suffixString;
+
+ return true;
+}
+
+String BuildInfo::Version::print () const noexcept
+{
+ String s;
+
+ s << String (vmajor) << "." << String (vminor).paddedLeft ('0', 3);
+
+ if (suffix.isNotEmpty ())
+ s << "-" << suffix;
+
+ return s;
+}
+
+//------------------------------------------------------------------------------
+
+BuildInfo::Protocol::Protocol ()
+ : vmajor (0)
+ , vminor (0)
+{
+}
+
+BuildInfo::Protocol::Protocol (unsigned short major_, unsigned short minor_)
+ : vmajor (major_)
+ , vminor (minor_)
+{
+}
+
+BuildInfo::Protocol::Protocol (PackedFormat packedVersion)
+{
+ vmajor = (packedVersion >> 16) & 0xffff;
+ vminor = (packedVersion & 0xffff);
+}
+
+BuildInfo::Protocol::PackedFormat BuildInfo::Protocol::toPacked () const noexcept
+{
+ return ((vmajor << 16) & 0xffff0000) | (vminor & 0xffff);
+}
+
+std::string BuildInfo::Protocol::toStdString () const noexcept
+{
+ String s;
+
+ s << String (vmajor) << "." << "vminor";
+
+ return s.toStdString ();
+}
+
+//------------------------------------------------------------------------------
+
+class BuildInfoTests : public UnitTest
+{
+public:
+ BuildInfoTests () : UnitTest ("BuildInfo", "ripple")
+ {
+ }
+
+ void checkVersion (String const& s)
+ {
+ BuildInfo::Version v;
+
+ expect (v.parse (s));
+
+ // Conversion back and forth should be identical
+ expect (v.print () == s);
+ }
+
+ void testVersion ()
+ {
+ beginTestCase ("version");
+
+ BuildInfo::Version v;
+
+ checkVersion ("0.000");
+ checkVersion ("1.002");
+ checkVersion ("10.002");
+ checkVersion ("99.999");
+ checkVersion ("99.999-r");
+ checkVersion ("99.999-r1");
+ checkVersion ("99.999-r123");
+
+ unexpected (v.parse (" 1.2")); // Many not have leading or trailing whitespace
+ unexpected (v.parse ("1.2 ")); // Many not have leading or trailing whitespace
+ unexpected (v.parse (" 1.2 ")); // Many not have leading or trailing whitespace
+ unexpected (v.parse ("2")); // Must have a dot
+ unexpected (v.parse ("23")); // Must have a dot
+ unexpected (v.parse ("4-rc1")); // Must have a dot
+ unexpected (v.parse ("01.000")); // No leading zeroes
+ unexpected (v.parse ("4-4.r")); // A dash must come after the dot.
+ unexpected (v.parse ("1.2345")); // Must be length three
+ unexpected (v.parse ("1a.2")); // Must only contain digits
+ unexpected (v.parse ("1.2b")); // Must only contain digits
+ unexpected (v.parse ("1.2-rxxx1")); // Must be 4 characters or less
+ unexpected (v.parse ("1.2-")); // Must start with a letter
+ unexpected (v.parse ("1.2-3")); // Must start with a letter
+ unexpected (v.parse ("1.2-r!")); // Must only contain letters and numbers
+ }
+
+ void checkProtcol (unsigned short vmajor, unsigned short vminor)
+ {
+ typedef BuildInfo::Protocol P;
+
+ expect (P (P (vmajor, vminor).toPacked ()) == P (vmajor, vminor));
+ }
+
+ void testProtocol ()
+ {
+ typedef BuildInfo::Protocol P;
+
+ beginTestCase ("protocol");
+
+ expect (P (0, 0).toPacked () == 0);
+ expect (P (0, 1).toPacked () == 1);
+ expect (P (0, 65535).toPacked () == 65535);
+
+ checkProtcol (0, 0);
+ checkProtcol (0, 1);
+ checkProtcol (0, 255);
+ checkProtcol (0, 65535);
+ checkProtcol (1, 0);
+ checkProtcol (1, 65535);
+ checkProtcol (65535, 65535);
+ }
+
+ void testValues ()
+ {
+ beginTestCase ("comparison");
+
+ typedef BuildInfo::Protocol P;
+
+ expect (P(1,2) == P(1,2));
+ expect (P(3,4) >= P(3,4));
+ expect (P(5,6) <= P(5,6));
+ expect (P(7,8) > P(6,7));
+ expect (P(7,8) < P(8,9));
+ expect (P(65535,0) < P(65535,65535));
+ expect (P(65535,65535) >= P(65535,65535));
+
+ expect (BuildInfo::getCurrentProtocol () >= BuildInfo::getMinimumProtocol ());
+ }
+
+ void runTest ()
+ {
+ testVersion ();
+ testProtocol ();
+ testValues ();
+ }
+};
+
+static BuildInfoTests buildInfoTests;
diff --git a/modules/ripple_app/basics/ripple_BuildInfo.h b/modules/ripple_app/basics/ripple_BuildInfo.h
new file mode 100644
index 000000000..e27693660
--- /dev/null
+++ b/modules/ripple_app/basics/ripple_BuildInfo.h
@@ -0,0 +1,145 @@
+//------------------------------------------------------------------------------
+/*
+ Copyright (c) 2011-2013, OpenCoin, Inc.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_BUILDINFO_H_INCLUDED
+#define RIPPLE_BUILDINFO_H_INCLUDED
+
+/** Versioning information for this build. */
+struct BuildInfo
+{
+ /** Server version.
+
+ The server version has three parts:
+
+ A non negative integer.
+ An integer between 0 and 999 inclusive.
+ An optional string. For example, "rc1"
+
+ The version string is formatted thusly:
+
+ '.' '.' ['-' ]
+
+ The minor version number is always padded with leading zeroes
+ to bring the number of characters up to exactly three. For example,
+ the server version string "12.045-rc1" has major version 12, minor
+ version 45, and suffix "rc1". A suffix may only consist of lowercase
+ letters and digits, and must start with a letter. The suffix may
+ be up to 4 characters. The major version may not be prefixed with
+ extra leading zeroes.
+
+ The suffix for a new official release is usually omitted. If hotfixes
+ are added to official releases they get a single leter suffix.
+
+ Release candidates are marked with suffixes starting with "rc" and
+ followed by a number starting from 1 to indicate the first
+ release candidate, with subsequent release candidates incrementing
+ the number. A final release candidate which becomes an official
+ release loses the suffix. The next release candidate will have a
+ new major or minor version number, and start back at "rc1".
+ */
+ static String const& getVersionString ();
+
+ /** Full server version string.
+
+ This includes the name of the server. It is used in the peer
+ protocol hello message and also the headers of some HTTP replies.
+ */
+ static char const* getFullVersionString ();
+
+ /** The server version's components. */
+ struct Version
+ {
+ int vmajor; // 0+
+ int vminor; // 0-999
+ String suffix; // Can be empty
+
+ //----
+
+ Version ();
+
+ /** Convert a string to components.
+ @return `false` if the string is improperly formatted.
+ */
+ bool parse (String const& s);
+
+ /** Convert the components to a string. */
+ String print () const noexcept;
+ };
+
+ //--------------------------------------------------------------------------
+
+ /** The wire protocol version.
+
+ The version consists of two unsigned 16 bit integers representing
+ major and minor version numbers. All values are permissible.
+ */
+ struct Protocol
+ {
+ unsigned short vmajor;
+ unsigned short vminor;
+
+ //----
+
+ /** The serialized format of the protocol version. */
+ typedef uint32 PackedFormat;
+
+ Protocol ();
+ Protocol (unsigned short vmajor, unsigned short vminor);
+ explicit Protocol (PackedFormat packedVersion);
+
+ PackedFormat toPacked () const noexcept;
+
+ std::string toStdString () const noexcept;
+
+ bool operator== (Protocol const& other) const noexcept { return toPacked () == other.toPacked (); }
+ bool operator!= (Protocol const& other) const noexcept { return toPacked () != other.toPacked (); }
+ bool operator>= (Protocol const& other) const noexcept { return toPacked () >= other.toPacked (); }
+ bool operator<= (Protocol const& other) const noexcept { return toPacked () <= other.toPacked (); }
+ bool operator> (Protocol const& other) const noexcept { return toPacked () > other.toPacked (); }
+ bool operator< (Protocol const& other) const noexcept { return toPacked () < other.toPacked (); }
+ };
+
+ /** The protocol version we speak and prefer. */
+ static Protocol const& getCurrentProtocol ();
+
+ /** The oldest protocol version we will accept. */
+ static Protocol const& getMinimumProtocol ();
+
+ //--------------------------------------------------------------------------
+ //
+ // DEPRECATED STUFF
+ //
+
+ /** Retrieve the build version number.
+
+ This is typically incremented when an official version is publshed
+ with a list of changes.
+
+ Format is:
+
+ ..
+ */
+ static char const* getBuildVersion ()
+ {
+ return "0.0.1";
+ }
+
+ /** Retrieve the client API version number.
+
+ The client API version is incremented whenever a new feature
+ or breaking change is made to the websocket / RPC interface.
+
+ Format is:
+
+
+ */
+ static char const* getClientVersion ()
+ {
+ return "1";
+ }
+};
+
+#endif
diff --git a/modules/ripple_app/basics/ripple_BuildVersion.h b/modules/ripple_app/basics/ripple_BuildVersion.h
deleted file mode 100644
index 6d5504c42..000000000
--- a/modules/ripple_app/basics/ripple_BuildVersion.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- Copyright (c) 2011-2013, OpenCoin, Inc.
-*/
-//==============================================================================
-
-#ifndef RIPPLE_BUILDVERSION_RIPPLEHEADER
-#define RIPPLE_BUILDVERSION_RIPPLEHEADER
-
-/** Versioning information for the build.
-*/
-
-class BuildVersion
-{
-public:
- /** Retrieve the build version number.
-
- This is typically incremented when an official version is publshed
- with a list of changes.
-
- Format is:
-
- ..
- */
- static char const* getBuildVersion ()
- {
- return "0.0.1";
- }
-
- /** Retrieve the client API version number.
-
- The client API version is incremented whenever a new feature
- or breaking change is made to the websocket / RPC interface.
-
- Format is:
-
-
- */
- static char const* getClientVersion ()
- {
- return "1";
- }
-};
-
-#endif
diff --git a/modules/ripple_app/basics/ripple_Version.h b/modules/ripple_app/basics/ripple_Version.h
deleted file mode 100644
index dae2dd046..000000000
--- a/modules/ripple_app/basics/ripple_Version.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- Copyright (c) 2011-2013, OpenCoin, Inc.
-*/
-//==============================================================================
-
-#ifndef RIPPLE_VERSION_H
-#define RIPPLE_VERSION_H
-
-//
-// Versions
-//
-
-// VFALCO TODO Roll this together into ripple_BuildVersion
-#define SERVER_VERSION_MAJOR 0
-#define SERVER_VERSION_MINOR 9
-#define SERVER_VERSION_SUB "-e"
-#define SERVER_NAME "Ripple"
-
-#define SV_STRINGIZE(x) SV_STRINGIZE2(x)
-#define SV_STRINGIZE2(x) #x
-#define SERVER_VERSION \
- (SERVER_NAME "-" SV_STRINGIZE(SERVER_VERSION_MAJOR) "." SV_STRINGIZE(SERVER_VERSION_MINOR) SERVER_VERSION_SUB)
-
-// Version we prefer to speak:
-#define PROTO_VERSION_MAJOR 1
-#define PROTO_VERSION_MINOR 2
-
-// Version we will speak to:
-#define MIN_PROTO_MAJOR 1
-#define MIN_PROTO_MINOR 2
-
-#define MAKE_VERSION_INT(maj,min) ((maj << 16) | min)
-#define GET_VERSION_MAJOR(ver) (ver >> 16)
-#define GET_VERSION_MINOR(ver) (ver & 0xff)
-
-#endif
-// vim:ts=4
diff --git a/modules/ripple_app/misc/NetworkOPs.cpp b/modules/ripple_app/misc/NetworkOPs.cpp
index 08da9c930..de64b67b3 100644
--- a/modules/ripple_app/misc/NetworkOPs.cpp
+++ b/modules/ripple_app/misc/NetworkOPs.cpp
@@ -1391,8 +1391,8 @@ Json::Value NetworkOPs::getServerInfo (bool human, bool admin)
{
Json::Value info = Json::objectValue;
- info ["build_version"] = BuildVersion::getBuildVersion ();
- info ["client_version"] = BuildVersion::getClientVersion ();
+ info ["build_version"] = BuildInfo::getBuildVersion ();
+ info ["client_version"] = BuildInfo::getClientVersion ();
if (getConfig ().TESTNET)
info["testnet"] = getConfig ().TESTNET;
diff --git a/modules/ripple_app/peers/ripple_Peer.cpp b/modules/ripple_app/peers/ripple_Peer.cpp
index 46a4a233c..e19dabb34 100644
--- a/modules/ripple_app/peers/ripple_Peer.cpp
+++ b/modules/ripple_app/peers/ripple_Peer.cpp
@@ -972,11 +972,11 @@ void PeerImp::recvHello (protocol::TMHello& packet)
WriteLog (lsINFO, Peer) << "Recv(Hello): " << getIP () << " :Clock far off -" << ourTime - packet.nettime ();
}
}
- else if (packet.protoversionmin () > MAKE_VERSION_INT (PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR))
+ else if (packet.protoversionmin () > BuildInfo::getCurrentProtocol().toPacked ())
{
- WriteLog (lsINFO, Peer) << "Recv(Hello): Server requires protocol version " <<
- GET_VERSION_MAJOR (packet.protoversion ()) << "." << GET_VERSION_MINOR (packet.protoversion ())
- << " we run " << PROTO_VERSION_MAJOR << "." << PROTO_VERSION_MINOR;
+ WriteLog (lsINFO, Peer) <<
+ "Recv(Hello): Server requires protocol version " << BuildInfo::Protocol (packet.protoversion()).toStdString () <<
+ ", we run " << BuildInfo::getCurrentProtocol().toStdString ();
}
else if (!mNodePublic.setNodePublic (packet.nodepublic ()))
{
@@ -991,9 +991,8 @@ void PeerImp::recvHello (protocol::TMHello& packet)
{
// Successful connection.
WriteLog (lsINFO, Peer) << "Recv(Hello): Connect: " << mNodePublic.humanNodePublic ();
- CondLog (packet.protoversion () != MAKE_VERSION_INT (PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR), lsINFO, Peer)
- << "Peer speaks version " <<
- (packet.protoversion () >> 16) << "." << (packet.protoversion () & 0xFF);
+ CondLog (BuildInfo::Protocol (packet.protoversion()) != BuildInfo::getCurrentProtocol(), lsINFO, Peer) <<
+ "Peer speaks version " << BuildInfo::Protocol (packet.protoversion()).toStdString ();
mHello = packet;
if (getApp().getUNL ().nodeInCluster (mNodePublic, mNodeName))
@@ -2239,9 +2238,9 @@ void PeerImp::sendHello ()
protocol::TMHello h;
- h.set_protoversion (MAKE_VERSION_INT (PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR));
- h.set_protoversionmin (MAKE_VERSION_INT (MIN_PROTO_MAJOR, MIN_PROTO_MINOR));
- h.set_fullversion (SERVER_VERSION);
+ h.set_protoversion (BuildInfo::getCurrentProtocol().toPacked ());
+ h.set_protoversionmin (BuildInfo::getMinimumProtocol().toPacked ());
+ h.set_fullversion (BuildInfo::getFullVersionString ());
h.set_nettime (getApp().getOPs ().getNetworkTimeNC ());
h.set_nodepublic (getApp().getLocalCredentials ().getNodePublic ().humanNodePublic ());
h.set_nodeproof (&vchSig[0], vchSig.size ());
@@ -2410,9 +2409,10 @@ Json::Value PeerImp::getJson ()
ret["version"] = mHello.fullversion ();
if (mHello.has_protoversion () &&
- (mHello.protoversion () != MAKE_VERSION_INT (PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR)))
- ret["protocol"] = lexicalCastThrow (GET_VERSION_MAJOR (mHello.protoversion ())) + "." +
- lexicalCastThrow (GET_VERSION_MINOR (mHello.protoversion ()));
+ (mHello.protoversion () != BuildInfo::getCurrentProtocol().toPacked ()))
+ {
+ ret["protocol"] = BuildInfo::Protocol (mHello.protoversion ()).toStdString ();
+ }
if (!!mClosedLedgerHash)
ret["ledger"] = mClosedLedgerHash.GetHex ();
diff --git a/modules/ripple_app/ripple_app.cpp b/modules/ripple_app/ripple_app.cpp
index 4b3631a3f..c6afd1ee7 100644
--- a/modules/ripple_app/ripple_app.cpp
+++ b/modules/ripple_app/ripple_app.cpp
@@ -195,8 +195,7 @@ namespace ripple
#include "contracts/ripple_Interpreter.h"
#include "contracts/ripple_Operation.h"
-#include "basics/ripple_Version.h" // VFALCO TODO Should this be private?
-#include "basics/ripple_BuildVersion.h" // private
+#include "basics/ripple_BuildInfo.h" // private
#include "basics/ripple_RPCServerHandler.h"
#include "rpc/RPCDoor.h" // needs RPCServer
@@ -244,6 +243,7 @@ static const uint64 tenTo17m1 = tenTo17 - 1;
#if ! defined (RIPPLE_MAIN_PART) || RIPPLE_MAIN_PART == 1
+#include "basics/ripple_BuildInfo.cpp"
#include "basics/ripple_RPCServerHandler.cpp"
#include "node/ripple_NodeObject.cpp"
#include "node/ripple_NodeStore.cpp"
diff --git a/modules/ripple_app/rpc/rpc.cpp b/modules/ripple_app/rpc/rpc.cpp
index 568b53782..042e4e67d 100644
--- a/modules/ripple_app/rpc/rpc.cpp
+++ b/modules/ripple_app/rpc/rpc.cpp
@@ -123,7 +123,8 @@ std::string HTTPReply (int nStatus, const std::string& strMsg)
rfc1123Time ().c_str (),
access.c_str (),
strMsg.size () + 2,
- SERVER_VERSION,
+ //SERVER_VERSION,
+ BuildInfo::getFullVersionString (),
strMsg.c_str ());
}