changeset 23707:35da5672bd61

BUIP005: Add coinbase transaction message
author Andrew Stone <g.andrew.stone@gmail.com>
date Fri, 04 Mar 2016 15:24:33 -0500
parents 66da629c59d2
children f5eb5416e1e0
files src/main.cpp src/miner.cpp src/rpcserver.cpp src/test/miner_tests.cpp src/unlimited.cpp src/unlimited.h
diffstat 6 files changed, 93 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/main.cpp	Thu Feb 04 21:00:18 2016 -0500
+++ b/src/main.cpp	Fri Mar 04 15:24:33 2016 -0500
@@ -39,6 +39,7 @@
 #include <sstream>
 
 #include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/hex.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
 #include <boost/math/distributions/poisson.hpp>
@@ -780,7 +781,7 @@
 
     if (tx.IsCoinBase())
     {
-        if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
+        if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > MAX_COINBASE_SCRIPTSIG_SIZE) // BU convert 100 to a constant so we can use it during generation
             return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
     }
     else
--- a/src/miner.cpp	Thu Feb 04 21:00:18 2016 -0500
+++ b/src/miner.cpp	Fri Mar 04 15:24:33 2016 -0500
@@ -278,7 +278,22 @@
 
         // Compute final coinbase transaction.
         txNew.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
-        txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
+        txNew.vin[0].scriptSig = CScript() << nHeight << CScriptNum(0);
+
+        // BU005 add block size settings to the coinbase
+        std::string cbmsg = FormatCoinbaseMessage(BUComments, minerComment);
+        const char* cbcstr = cbmsg.c_str();
+        vector<unsigned char> vec(cbcstr, cbcstr+cbmsg.size());
+        COINBASE_FLAGS = CScript() << vec;
+        // Chop off any extra data in the COINBASE_FLAGS so the sig does not exceed the max.  
+        // we can do this because the coinbase is not a "real" script...
+        if (txNew.vin[0].scriptSig.size() + COINBASE_FLAGS.size() > MAX_COINBASE_SCRIPTSIG_SIZE)
+          {
+          COINBASE_FLAGS.resize(MAX_COINBASE_SCRIPTSIG_SIZE - txNew.vin[0].scriptSig.size());
+          }
+        txNew.vin[0].scriptSig = txNew.vin[0].scriptSig + COINBASE_FLAGS;
+        // BU005 END
+
         pblock->vtx[0] = txNew;
         pblocktemplate->vTxFees[0] = -nFees;
 
@@ -310,7 +325,13 @@
     ++nExtraNonce;
     unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
     CMutableTransaction txCoinbase(pblock->vtx[0]);
-    txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
+ 
+    CScript script = (CScript() << nHeight << CScriptNum(nExtraNonce));
+    if (script.size() + COINBASE_FLAGS.size() > MAX_COINBASE_SCRIPTSIG_SIZE)
+      {
+	COINBASE_FLAGS.resize(MAX_COINBASE_SCRIPTSIG_SIZE - script.size());
+      }
+    txCoinbase.vin[0].scriptSig = script + COINBASE_FLAGS;
     assert(txCoinbase.vin[0].scriptSig.size() <= 100);
 
     pblock->vtx[0] = txCoinbase;
--- a/src/rpcserver.cpp	Thu Feb 04 21:00:18 2016 -0500
+++ b/src/rpcserver.cpp	Fri Mar 04 15:24:33 2016 -0500
@@ -308,6 +308,8 @@
     { "mining",             "submitblock",            &submitblock,            true  },
     { "mining",             "getminingmaxblock",      &getminingmaxblock,      true  },  // BU
     { "mining",             "setminingmaxblock",      &setminingmaxblock,      true  },  // BU
+    { "mining",             "getminercomment",        &getminercomment,        true  },  // BU
+    { "mining",             "setminercomment",        &setminercomment,        true  },  // BU
 
     /* Coin generation */
     { "generating",         "getgenerate",            &getgenerate,            true  },
--- a/src/test/miner_tests.cpp	Thu Feb 04 21:00:18 2016 -0500
+++ b/src/test/miner_tests.cpp	Fri Mar 04 15:24:33 2016 -0500
@@ -77,6 +77,18 @@
     // Simple block creation, nothing special yet:
     BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
 
+    // Simple block creation, with coinbase message
+    settingsToUserAgentString();
+    BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
+
+    // Simple block creation, with coinbase message and miner message
+    settingsToUserAgentString();
+    minerComment = "I am a meat popsicle.";
+    BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
+
+    minerComment = "flying is throwing yourself against the ground and missing.  This comment is WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY too long.";
+    BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
+
     // We can't make transactions until we have inputs
     // Therefore, load 100 blocks :)
     std::vector<CTransaction*>txFirst;
--- a/src/unlimited.cpp	Thu Feb 04 21:00:18 2016 -0500
+++ b/src/unlimited.cpp	Fri Mar 04 15:24:33 2016 -0500
@@ -30,6 +30,7 @@
 unsigned int maxMessageSizeMultiplier = DEFAULT_MAX_MESSAGE_SIZE_MULTIPLIER;
 
 std::vector<std::string> BUComments = std::vector<std::string>();
+std::string minerComment;
 
 // Variables for traffic shaping
 CLeakyBucket receiveShaper(DEFAULT_MAX_RECV_BURST, DEFAULT_AVE_RECV);
@@ -51,6 +52,21 @@
     return strUsage;
 }
 
+std::string FormatCoinbaseMessage(const std::vector<std::string>& comments,const std::string& customComment)
+{
+    std::ostringstream ss;
+    if (!comments.empty())
+    {
+        std::vector<std::string>::const_iterator it(comments.begin());
+        ss << "/" << *it;
+        for(++it; it != comments.end(); ++it)
+            ss << "/" << *it;
+        ss << "/";
+    }
+    std::string ret = ss.str() + minerComment;
+    return ret;
+}
+
 UniValue pushtx(const UniValue& params, bool fHelp)
 {
     string strCommand;
@@ -203,6 +219,33 @@
     return false;
 }
 
+extern UniValue getminercomment(const UniValue& params, bool fHelp)
+{
+  if (fHelp || params.size() != 0)
+        throw runtime_error(
+            "getminercomment\n"
+            "\nReturn the comment that will be put into each mined block's coinbase\n transaction after the Bitcoin Unlimited parameters."
+            "\nResult\n"
+            "  minerComment (string) miner comment\n"
+            "\nExamples:\n" +
+            HelpExampleCli("getminercomment", "") + HelpExampleRpc("getminercomment", ""));
+  
+  return minerComment;
+}
+
+extern UniValue setminercomment(const UniValue& params, bool fHelp)
+{
+  if (fHelp || params.size() != 1)
+        throw runtime_error(
+            "setminercomment\n"
+            "\nSet the comment that will be put into each mined block's coinbase\n transaction after the Bitcoin Unlimited parameters.\n Comments that are too long will be truncated."
+            "\nExamples:\n" +
+            HelpExampleCli("setminercomment", "\"bitcoin is fundamentally emergent consensus\"") + HelpExampleRpc("setminercomment", "\"bitcoin is fundamentally emergent consensus\""));
+
+  minerComment = params[0].getValStr();
+  return NullUniValue;
+}
+
 UniValue getexcessiveblock(const UniValue& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
--- a/src/unlimited.h	Thu Feb 04 21:00:18 2016 -0500
+++ b/src/unlimited.h	Fri Mar 04 15:24:33 2016 -0500
@@ -12,7 +12,8 @@
     DEFAULT_MAX_GENERATED_BLOCK_SIZE = 1000000,
     DEFAULT_EXCESSIVE_ACCEPT_DEPTH = 4,
     DEFAULT_EXCESSIVE_BLOCK_SIZE = 16000000,
-    DEFAULT_MAX_MESSAGE_SIZE_MULTIPLIER = 10
+    DEFAULT_MAX_MESSAGE_SIZE_MULTIPLIER = 10,
+    MAX_COINBASE_SCRIPTSIG_SIZE = 100
 };
 
 class CBlock;
@@ -25,8 +26,13 @@
 extern unsigned int excessiveAcceptDepth;
 extern unsigned int maxMessageSizeMultiplier;
 
-extern std::vector<std::string> BUComments;
+extern std::vector<std::string> BUComments;  // BU005: Strings specific to the config of this client that should be communicated to other clients
+extern std::string minerComment;  // An arbitrary field that miners can change to annotate their blocks
+// Convert the BUComments to the string client's "subversion" string
 extern void settingsToUserAgentString();
+// Convert a list of client comments (typically BUcomments) and a custom comment into a string appropriate for the coinbase txn
+// The coinbase size restriction is NOT enforced
+extern std::string FormatCoinbaseMessage(const std::vector<std::string>& comments,const std::string& customComment);  
 
 extern void UnlimitedSetup(void);
 extern std::string UnlimitedCmdLineHelp();
@@ -53,6 +59,9 @@
 extern UniValue getexcessiveblock(const UniValue& params, bool fHelp);
 extern UniValue setexcessiveblock(const UniValue& params, bool fHelp);
 
+extern UniValue getminercomment(const UniValue& params, bool fHelp);
+extern UniValue setminercomment(const UniValue& params, bool fHelp);
+
 // These variables for traffic shaping need to be globally scoped so the GUI and CLI can adjust the parameters
 extern CLeakyBucket receiveShaper;
 extern CLeakyBucket sendShaper;