PPCoin: Sign block when communicating with miners via RPC 'getwork'
[novacoin.git] / src / bitcoinrpc.cpp
index 21963c7..e68f1fe 100644 (file)
@@ -216,10 +216,11 @@ double GetDifficulty()
 
     if (pindexBest == NULL)
         return 1.0;
-    int nShift = (pindexBest->nBits >> 24) & 0xff;
+    const CBlockIndex* pindexLastProofOfWork = GetLastBlockIndex(pindexBest, false);
+    int nShift = (pindexLastProofOfWork->nBits >> 24) & 0xff;
 
     double dDiff =
-        (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
+        (double)0x0000ffff / (double)(pindexLastProofOfWork->nBits & 0x00ffffff);
 
     while (nShift < 29)
     {
@@ -308,6 +309,7 @@ Value getinfo(const Array& params, bool fHelp)
     Object obj;
     obj.push_back(Pair("version",       (int)VERSION));
     obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
+    obj.push_back(Pair("newmint",       ValueFromAmount(pwalletMain->GetNewMint())));
     obj.push_back(Pair("stake",         ValueFromAmount(pwalletMain->GetStake())));
     obj.push_back(Pair("blocks",        (int)nBestHeight));
     obj.push_back(Pair("connections",   (int)vNodes.size()));
@@ -1655,14 +1657,14 @@ Value getwork(const Array& params, bool fHelp)
             nStart = GetTime();
 
             // Create new block
-            pblock = CreateNewBlock(pwalletMain);
+            pblock = CreateNewBlock(pwalletMain, true);
             if (!pblock)
                 throw JSONRPCError(-7, "Out of memory");
             vNewBlock.push_back(pblock);
         }
 
         // Update nTime
-        pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+        pblock->nTime = max(pblock->GetBlockTime(), GetAdjustedTime());
         pblock->nNonce = 0;
 
         // Update nExtraNonce
@@ -1708,6 +1710,8 @@ Value getwork(const Array& params, bool fHelp)
         pblock->nNonce = pdata->nNonce;
         pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+        if (!pblock->SignBlock(*pwalletMain))
+            throw JSONRPCError(-100, "Unable to sign block");
 
         return CheckWork(pblock, *pwalletMain, reservekey);
     }
@@ -1801,47 +1805,22 @@ Value getmemorypool(const Array& params, bool fHelp)
 }
 
 
-// ppcoin: reset auto checkpoint
-Value resetcheckpoint(const Array& params, bool fHelp)
-{
-    if (fHelp || params.size() < 1 || params.size() > 1)
-        throw runtime_error(
-            "resetcheckpoint <checkpointheight>\n"
-            "Reset automatic checkpoint to specified height.\n"
-            "<checkpointheight> is the height of the new checkpoint block.\n");
-
-    int nCheckpoint = params[0].get_int();
-    if (nCheckpoint <= 0 || nCheckpoint >= nBestHeight)
-        throw runtime_error(
-            "invalid checkpoint height.\n"
-        );
-    if (nCheckpoint >= Checkpoints::nAutoCheckpoint)
-        throw runtime_error(
-            "new checkpoint must be earlier than current auto checkpoint.\n"
-        );
-    if (!Checkpoints::ResetAutoCheckpoint(nCheckpoint))
-        throw runtime_error(
-            "internal error - reset checkpoint failed.\n"
-        );
-
-    return Value::null;
-}
-
-
-// ppcoin: get branch point of alternative branch
-Value getbranchpoint(const Array& params, bool fHelp)
+// ppcoin: get information of sync-checkpoint
+Value getcheckpoint(const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
-            "getbranchpoint\n"
-            "Returns height of branch point of alternative branch.\n");
+            "getcheckpoint\n"
+            "Show info of synchronized checkpoint.\n");
 
     Object result;
-    if (Checkpoints::nBranchPoint > 0)
-        result.push_back(Pair("branchpoint", Checkpoints::nBranchPoint));
-    else
-        result.push_back(Pair("branchpoint", "none"));
-    result.push_back(Pair("checkpoint", Checkpoints::nAutoCheckpoint));
+    CBlockIndex* pindexCheckpoint;
+    
+    result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
+    pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];        
+    result.push_back(Pair("height", pindexCheckpoint->nHeight));
+    result.push_back(Pair("timestamp", DateTimeStrFormat("%x %H:%M:%S", pindexCheckpoint->GetBlockTime()).c_str()));
+    
     return result;
 }
 
@@ -1930,10 +1909,39 @@ Value repairwallet(const Array& params, bool fHelp)
     return result;
 }
 
+// ppcoin: make a public-private key pair
+Value makekeypair(const Array& params, bool fHelp)
+{
+    if (fHelp || params.size() > 1)
+        throw runtime_error(
+            "makekeypair [prefix]\n"
+            "Make a public/private key pair.\n"
+            "[prefix] is optional preferred prefix for the public key.\n");
+
+    string strPrefix = "";
+    if (params.size() > 0)
+        strPrefix = params[0].get_str();
+    CKey key;
+    do
+    {
+        key.MakeNewKey();
+    } while (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
+
+    CPrivKey vchPrivKey = key.GetPrivKey();
+    Object result;
+    result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
+    result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
+    return result;
+}
+
 extern CCriticalSection cs_mapAlerts;
 extern map<uint256, CAlert> mapAlerts;
 
-// ppcoin: send alert
+// ppcoin: send alert.  
+// There is a known deadlock situation with ThreadMessageHandler
+// ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
+// ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
 Value sendalert(const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 5)
@@ -1970,7 +1978,9 @@ Value sendalert(const Array& params, bool fHelp)
     if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
         throw runtime_error(
             "Unable to sign alert, check private key?\n");  
-    alert.ProcessAlert();
+    if(!alert.ProcessAlert()) 
+        throw runtime_error(
+            "Failed to process alert.\n");
     // Relay alert
     CRITICAL_BLOCK(cs_vNodes)
         BOOST_FOREACH(CNode* pnode, vNodes)
@@ -1987,18 +1997,60 @@ Value sendalert(const Array& params, bool fHelp)
     return result;
 }
 
-Value makekeypair(const Array& params, bool fHelp)
+// ppcoin: send checkpoint
+Value sendcheckpoint(const Array& params, bool fHelp)
 {
+    if (fHelp || params.size() > 2 || params.size() < 1 )
+        throw runtime_error(
+            "sendcheckpoint <privatekey> [checkpointhash]\n"
+            "<privatekey> is hex string of checkpoint master private key\n"
+            "<checkpointhash> is the hash of checkpoint block\n");
+
+    CSyncCheckpoint checkpoint;
     CKey key;
-    key.MakeNewKey();
-    CPrivKey vchPrivKey = key.GetPrivKey();
+
+    // TODO: omit checkpointhash parameter
+    if (params.size() > 1)
+    {
+        checkpoint.hashCheckpoint = uint256(params[1].get_str());
+        if (!mapBlockIndex.count(checkpoint.hashCheckpoint))
+            throw runtime_error(
+                "Provided checkpoint block is not on main chain\n");
+    }
+    else
+    {
+        checkpoint.hashCheckpoint = Checkpoints::AutoSelectSyncCheckpoint();
+        if (checkpoint.hashCheckpoint == Checkpoints::hashSyncCheckpoint)
+            throw runtime_error(
+                "Unable to select a more recent sync-checkpoint");
+    }
+
+    CDataStream sMsg;
+    sMsg << (CUnsignedSyncCheckpoint)checkpoint;
+    checkpoint.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
+
+    vector<unsigned char> vchPrivKey = ParseHex(params[0].get_str());
+    key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
+    if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
+        throw runtime_error(
+            "Unable to sign checkpoint, check private key?\n");
+
+    if(!checkpoint.ProcessSyncCheckpoint(NULL))
+        throw runtime_error(
+            "Failed to process checkpoint.\n");
+    // Relay checkpoint
+    CRITICAL_BLOCK(cs_vNodes)
+        BOOST_FOREACH(CNode* pnode, vNodes)
+            checkpoint.RelayTo(pnode);
 
     Object result;
-    result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
-    result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
+    result.push_back(Pair("checkpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
+    result.push_back(Pair("height", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->nHeight));
+    result.push_back(Pair("timestamp", DateTimeStrFormat("%x %H:%M:%S", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->GetBlockTime()).c_str()));
     return result;
 }
 
+
 //
 // Call Table
 //
@@ -2045,13 +2097,13 @@ pair<string, rpcfn_type> pCallTable[] =
     make_pair("settxfee",               &settxfee),
     make_pair("getmemorypool",          &getmemorypool),
     make_pair("listsinceblock",        &listsinceblock),
-    make_pair("resetcheckpoint",        &resetcheckpoint),
-    make_pair("getbranchpoint",         &getbranchpoint),
+    make_pair("getcheckpoint",         &getcheckpoint),
     make_pair("reservebalance",         &reservebalance),
     make_pair("checkwallet",            &checkwallet),
     make_pair("repairwallet",           &repairwallet),
-    make_pair("sendalert",              &sendalert),
     make_pair("makekeypair",            &makekeypair),
+    make_pair("sendalert",              &sendalert),
+    make_pair("sendcheckpoint",         &sendcheckpoint),
 };
 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
 
@@ -2078,8 +2130,7 @@ string pAllowInSafeMode[] =
     "validateaddress",
     "getwork",
     "getmemorypool",
-    "resetcheckpoint",
-    "getbranchpoint",
+    "getcheckpoint",
 };
 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
 
@@ -2691,7 +2742,6 @@ int CommandLineRPC(int argc, char *argv[])
             params[1] = v.get_obj();
         }
         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
-        if (strMethod == "resetcheckpoint"         && n > 0) ConvertTo<boost::int64_t>(params[0]);
         if (strMethod == "reservebalance"          && n > 0) ConvertTo<bool>(params[0]);
         if (strMethod == "reservebalance"          && n > 1) ConvertTo<double>(params[1]);