PPCoin: Track coinstake search interval in RPC command 'getdifficulty'
[novacoin.git] / src / bitcoinrpc.cpp
index 6c7f425..63375fe 100644 (file)
@@ -136,7 +136,7 @@ string AccountFromValue(const Value& value)
     return strAccount;
 }
 
-Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
+Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
 {
     Object result;
     result.push_back(Pair("hash", block.GetHash().GetHex()));
@@ -144,19 +144,31 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
     result.push_back(Pair("height", blockindex->nHeight));
     result.push_back(Pair("version", block.nVersion));
     result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
-    result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
+    result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
     result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
     result.push_back(Pair("bits", HexBits(block.nBits)));
     result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
-    Array txhashes;
-    BOOST_FOREACH (const CTransaction&tx, block.vtx)
-        txhashes.push_back(tx.GetHash().GetHex());
-    result.push_back(Pair("tx", txhashes));
-
+    result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
     if (blockindex->pprev)
         result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
     if (blockindex->pnext)
         result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
+    Array txinfo;
+    BOOST_FOREACH (const CTransaction& tx, block.vtx)
+    {
+        if (fPrintTransactionDetail)
+        {
+            txinfo.push_back(tx.ToStringShort());
+            txinfo.push_back(DateTimeStrFormat(tx.nTime));
+            BOOST_FOREACH(const CTxIn& txin, tx.vin)
+                txinfo.push_back(txin.ToStringShort());
+            BOOST_FOREACH(const CTxOut& txout, tx.vout)
+                txinfo.push_back(txout.ToStringShort());
+        }
+        else
+            txinfo.push_back(tx.GetHash().GetHex());
+    }
+    result.push_back(Pair("tx", txinfo));
     return result;
 }
 
@@ -271,9 +283,13 @@ Value getdifficulty(const Array& params, bool fHelp)
     if (fHelp || params.size() != 0)
         throw runtime_error(
             "getdifficulty\n"
-            "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
+            "Returns difficulty as a multiple of the minimum difficulty.");
 
-    return GetDifficulty();
+    Object obj;
+    obj.push_back(Pair("proof-of-work",        GetDifficulty()));
+    obj.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
+    obj.push_back(Pair("search-interval",      (int)nLastCoinStakeSearchInterval));
+    return obj;
 }
 
 
@@ -342,6 +358,7 @@ Value getinfo(const Array& params, bool fHelp)
     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("moneysupply",   ValueFromAmount(pindexBest->nMoneySupply)));
     obj.push_back(Pair("connections",   (int)vNodes.size()));
     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
     obj.push_back(Pair("ip",            addrSeenByPeer.ToStringIP()));
@@ -566,6 +583,8 @@ Value sendtoaddress(const Array& params, bool fHelp)
 
     // Amount
     int64 nAmount = AmountFromValue(params[1]);
+    if (nAmount < MIN_TXOUT_AMOUNT)
+        throw JSONRPCError(-101, "Send amount too small");
 
     // Wallet comments
     CWalletTx wtx;
@@ -888,6 +907,8 @@ Value sendfrom(const Array& params, bool fHelp)
     if (!address.IsValid())
         throw JSONRPCError(-5, "Invalid ppcoin address");
     int64 nAmount = AmountFromValue(params[2]);
+    if (nAmount < MIN_TXOUT_AMOUNT)
+        throw JSONRPCError(-101, "Send amount too small");
     int nMinDepth = 1;
     if (params.size() > 3)
         nMinDepth = params[3].get_int();
@@ -956,6 +977,8 @@ Value sendmany(const Array& params, bool fHelp)
         CScript scriptPubKey;
         scriptPubKey.SetBitcoinAddress(address);
         int64 nAmount = AmountFromValue(s.value_); 
+        if (nAmount < MIN_TXOUT_AMOUNT)
+            throw JSONRPCError(-101, "Send amount too small");
         totalAmount += nAmount;
 
         vecSend.push_back(make_pair(scriptPubKey, nAmount));
@@ -963,8 +986,8 @@ Value sendmany(const Array& params, bool fHelp)
 
     if (pwalletMain->IsLocked())
         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
-    if (fWalletUnlockStakeOnly)
-        throw JSONRPCError(-13, "Error: Wallet unlocked for coinstake only.");
+    if (fWalletUnlockMintOnly)
+        throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
 
     // Check funds
     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
@@ -1592,9 +1615,9 @@ Value walletpassphrase(const Array& params, bool fHelp)
 {
     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
         throw runtime_error(
-            "walletpassphrase <passphrase> <timeout> [stakeonly]\n"
+            "walletpassphrase <passphrase> <timeout> [mintonly]\n"
             "Stores the wallet decryption key in memory for <timeout> seconds.\n"
-            "stakeonly is optional true/false allowing only stake creation.");
+            "mintonly is optional true/false allowing only block minting.");
     if (fHelp)
         return true;
     if (!pwalletMain->IsCrypted())
@@ -1626,9 +1649,9 @@ Value walletpassphrase(const Array& params, bool fHelp)
 
     // ppcoin: if user OS account compromised prevent trivial sendmoney commands
     if (params.size() > 2)
-        fWalletUnlockStakeOnly = params[2].get_bool();
+        fWalletUnlockMintOnly = params[2].get_bool();
     else
-        fWalletUnlockStakeOnly = false;
+        fWalletUnlockMintOnly = false;
 
     return Value::null;
 }
@@ -1823,7 +1846,7 @@ Value getwork(const Array& params, bool fHelp)
             nStart = GetTime();
 
             // Create new block
-            pblock = CreateNewBlock(pwalletMain, true);
+            pblock = CreateNewBlock(pwalletMain);
             if (!pblock)
                 throw JSONRPCError(-7, "Out of memory");
             vNewBlock.push_back(pblock);
@@ -1877,7 +1900,7 @@ Value getwork(const Array& params, bool fHelp)
         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");
+            throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
 
         return CheckWork(pblock, *pwalletMain, reservekey);
     }
@@ -1990,9 +2013,10 @@ Value getblockhash(const Array& params, bool fHelp)
 
 Value getblock(const Array& params, bool fHelp)
 {
-    if (fHelp || params.size() != 1)
+    if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
-            "getblock <hash>\n"
+            "getblock <hash> [txinfo]\n"
+            "txinfo optional to print more detailed tx info\n"
             "Returns details of a block with given block-hash.");
 
     std::string strHash = params[0].get_str();
@@ -2005,7 +2029,7 @@ Value getblock(const Array& params, bool fHelp)
     CBlockIndex* pblockindex = mapBlockIndex[hash];
     block.ReadFromDisk(pblockindex, true);
 
-    return blockToJSON(block, pblockindex);
+    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
 }
 
 
@@ -2023,8 +2047,10 @@ Value getcheckpoint(const Array& params, bool fHelp)
     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()));
-    
+    result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
+    if (mapArgs.count("-checkpointkey"))
+        result.push_back(Pair("checkpointmaster", true));
+
     return result;
 }
 
@@ -2081,14 +2107,15 @@ Value checkwallet(const Array& params, bool fHelp)
 
     int nMismatchSpent;
     int64 nBalanceInQuestion;
-    if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
+    Object result;
+    if (pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
+        result.push_back(Pair("wallet check passed", true));
+    else
     {
-        Object result;
         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
         result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
-        return result;
     }
-    return Value::null;
+    return result;
 }
 
 
@@ -2105,9 +2132,7 @@ Value repairwallet(const Array& params, bool fHelp)
     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
     Object result;
     if (nMismatchSpent == 0)
-    {
         result.push_back(Pair("wallet check passed", true));
-    }
     else
     {
         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
@@ -2156,16 +2181,17 @@ extern map<uint256, CAlert> mapAlerts;
 // 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)
+    if (fHelp || params.size() < 6)
        throw runtime_error(
-            "sendalert <message> <privatekey> <minver> <maxver> <id> [cancelupto]\n"
+            "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
             "<message> is the alert text message\n"
             "<privatekey> is hex string of alert master private key\n"
-            "<minver> is the minimum applicable client version\n"
-            "<maxver> is the maximum applicable client version\n"
+            "<minver> is the minimum applicable internal client version\n"
+            "<maxver> is the maximum applicable internal client version\n"
+            "<priority> is integer priority number\n"
             "<id> is the alert id\n"
             "[cancelupto] cancels all alert id's up to this number\n"
-            "Returns true or false.");    
+            "Returns true or false.");
 
     CAlert alert;
     CKey key;
@@ -2173,13 +2199,13 @@ Value sendalert(const Array& params, bool fHelp)
     alert.strStatusBar = params[0].get_str();
     alert.nMinVer = params[2].get_int();
     alert.nMaxVer = params[3].get_int();
-    alert.nID = params[4].get_int();
-    if (params.size() > 5)
-        alert.nCancel = params[5].get_int();
+    alert.nPriority = params[4].get_int();
+    alert.nID = params[5].get_int();
+    if (params.size() > 6)
+        alert.nCancel = params[6].get_int();
     alert.nVersion = PROTOCOL_VERSION;
     alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
     alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
-    alert.nPriority = 1;
 
     CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
     sMsg << (CUnsignedAlert)alert;
@@ -2205,66 +2231,13 @@ Value sendalert(const Array& params, bool fHelp)
     result.push_back(Pair("nVersion", alert.nVersion));
     result.push_back(Pair("nMinVer", alert.nMinVer));
     result.push_back(Pair("nMaxVer", alert.nMaxVer));
+    result.push_back(Pair("nPriority", alert.nPriority));
     result.push_back(Pair("nID", alert.nID));
     if (alert.nCancel > 0)
         result.push_back(Pair("nCancel", alert.nCancel));
     return result;
 }
 
-// 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;
-
-    // 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(SER_NETWORK, PROTOCOL_VERSION);
-    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
-    {
-        LOCK(cs_vNodes);
-        BOOST_FOREACH(CNode* pnode, vNodes)
-            checkpoint.RelayTo(pnode);
-    }
-
-    Object result;
-    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;
-}
 
 
 //
@@ -2327,7 +2300,6 @@ static const CRPCCommand vRPCCommands[] =
     { "repairwallet",           &repairwallet,           false},
     { "makekeypair",            &makekeypair,            false},
     { "sendalert",              &sendalert,              false},
-    { "sendcheckpoint",         &sendcheckpoint,         false},
 };
 
 CRPCTable::CRPCTable()
@@ -2931,6 +2903,7 @@ int CommandLineRPC(int argc, char *argv[])
         if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
         if (strMethod == "getblockhash"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
+        if (strMethod == "getblock"               && n > 1) ConvertTo<bool>(params[1]);
         if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
         if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
@@ -2945,6 +2918,7 @@ int CommandLineRPC(int argc, char *argv[])
         if (strMethod == "sendalert"              && n > 3) ConvertTo<boost::int64_t>(params[3]);
         if (strMethod == "sendalert"              && n > 4) ConvertTo<boost::int64_t>(params[4]);
         if (strMethod == "sendalert"              && n > 5) ConvertTo<boost::int64_t>(params[5]);
+        if (strMethod == "sendalert"              && n > 6) ConvertTo<boost::int64_t>(params[6]);
         if (strMethod == "sendmany"               && n > 1)
         {
             string s = params[1].get_str();