X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fbitcoinrpc.cpp;h=a8ad00017272267f9128d33e3a23b7cb24730d55;hb=f1af842f0fd26cb19d6f1161f7b161ae5386b980;hp=147e6b10337ec96ba662fb203a1301da3979bfcb;hpb=83e34b29071b58d6578b197430d12c55d277a515;p=novacoin.git diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 147e6b1..a8ad000 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 The PPCoin developers -// Copyright (c) 2012-2013 The NovaCoin developers +// Copyright (c) 2011-2013 The PPCoin developers +// Copyright (c) 2013 NovaCoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -47,8 +47,6 @@ static CCriticalSection cs_nWalletUnlockTime; extern Value dumpprivkey(const Array& params, bool fHelp); extern Value importprivkey(const Array& params, bool fHelp); -extern CBigNum bnProofOfWorkLimit; - Object JSONRPCError(int code, const string& message) { Object error; @@ -156,6 +154,11 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPri result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); if (blockindex->pnext) result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); + result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": ""))); + result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex())); + result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit())); + result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier))); + result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum))); Array txinfo; BOOST_FOREACH (const CTransaction& tx, block.vtx) { @@ -1019,7 +1022,7 @@ Value addmultisigaddress(const Array& params, bool fHelp) { string msg = "addmultisigaddress <'[\"key\",\"key\"]'> [account]\n" "Add a nrequired-to-sign multisignature address to the wallet\"\n" - "each key is a novacoin address or hex-encoded public key\n" + "each key is a bitcoin address or hex-encoded public key\n" "If [account] is specified, assign address to [account]."; throw runtime_error(msg); } @@ -1803,6 +1806,50 @@ Value validateaddress(const Array& params, bool fHelp) return ret; } +Value validatepubkey(const Array& params, bool fHelp) +{ + if (fHelp || !params.size() || params.size() > 2) + throw runtime_error( + "validatepubkey \n" + "Return information about ."); + + std::vector vchPubKey = ParseHex(params[0].get_str()); + bool isValid; + + if(vchPubKey.size() == 33) // Compressed key + isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03); + else if(vchPubKey.size() == 65) // Uncompressed key + isValid = vchPubKey[0] == 0x04; + else + isValid = false; + + CBitcoinAddress address(vchPubKey); + isValid = isValid ? address.IsValid() : false; + + Object ret; + ret.push_back(Pair("isvalid", isValid)); + if (isValid) + { + // Call Hash160ToAddress() so we always return current ADDRESSVERSION + // version of the address: + string currentAddress = address.ToString(); + ret.push_back(Pair("address", currentAddress)); + if (pwalletMain->HaveKey(address)) + { + ret.push_back(Pair("ismine", true)); + CKey key; + key.SetPubKey(vchPubKey); + ret.push_back(Pair("iscompressed", key.IsCompressed())); + } + else + ret.push_back(Pair("ismine", false)); + if (pwalletMain->mapAddressBook.count(address)) + ret.push_back(Pair("account", pwalletMain->mapAddressBook[address])); + } + return ret; +} + + Value getwork(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) @@ -1909,6 +1956,190 @@ Value getwork(const Array& params, bool fHelp) } } +Value getblocktemplate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getblocktemplate [params]\n" + "Returns data needed to construct a block to work on:\n" + " \"version\" : block version\n" + " \"previousblockhash\" : hash of current highest block\n" + " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n" + " \"coinbaseaux\" : data that should be included in coinbase\n" + " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n" + " \"target\" : hash target\n" + " \"mintime\" : minimum timestamp appropriate for next block\n" + " \"curtime\" : current timestamp\n" + " \"mutable\" : list of ways the block template may be changed\n" + " \"noncerange\" : range of valid nonces\n" + " \"sigoplimit\" : limit of sigops in blocks\n" + " \"sizelimit\" : limit of block size\n" + " \"bits\" : compressed target of next block\n" + " \"height\" : height of the next block\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification."); + + std::string strMode = "template"; + if (params.size() > 0) + { + const Object& oparam = params[0].get_obj(); + const Value& modeval = find_value(oparam, "mode"); + if (modeval.type() == str_type) + strMode = modeval.get_str(); + else + throw JSONRPCError(-8, "Invalid mode"); + } + + if (strMode != "template") + throw JSONRPCError(-8, "Invalid mode"); + + if (vNodes.empty()) + throw JSONRPCError(-9, "NovaCoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(-10, "NovaCoin is downloading blocks..."); + + static CReserveKey reservekey(pwalletMain); + + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlock* pblock; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) + { + // Clear pindexPrev so future calls make a new block, despite any failures from here on + pindexPrev = NULL; + + // Store the pindexBest used before CreateNewBlock, to avoid races + nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrevNew = pindexBest; + nStart = GetTime(); + + // Create new block + if(pblock) + { + delete pblock; + pblock = NULL; + } + pblock = CreateNewBlock(pwalletMain); + if (!pblock) + throw JSONRPCError(-7, "Out of memory"); + + // Need to update only after we know CreateNewBlock succeeded + pindexPrev = pindexPrevNew; + } + + // Update nTime + pblock->UpdateTime(pindexPrev); + pblock->nNonce = 0; + + Array transactions; + map setTxIndex; + int i = 0; + CTxDB txdb("r"); + BOOST_FOREACH (CTransaction& tx, pblock->vtx) + { + uint256 txHash = tx.GetHash(); + setTxIndex[txHash] = i++; + + if (tx.IsCoinBase() || tx.IsCoinStake()) + continue; + + Object entry; + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << tx; + entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end()))); + + entry.push_back(Pair("hash", txHash.GetHex())); + + MapPrevTx mapInputs; + map mapUnused; + bool fInvalid = false; + if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) + { + entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut()))); + + Array deps; + BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs) + { + if (setTxIndex.count(inp.first)) + deps.push_back(setTxIndex[inp.first]); + } + entry.push_back(Pair("depends", deps)); + + int64_t nSigOps = tx.GetLegacySigOpCount(); + nSigOps += tx.GetP2SHSigOpCount(mapInputs); + entry.push_back(Pair("sigops", nSigOps)); + } + + transactions.push_back(entry); + } + + Object aux; + aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + static Array aMutable; + if (aMutable.empty()) + { + aMutable.push_back("time"); + aMutable.push_back("transactions"); + aMutable.push_back("prevblock"); + } + + Object result; + result.push_back(Pair("version", pblock->nVersion)); + result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); + result.push_back(Pair("transactions", transactions)); + result.push_back(Pair("coinbaseaux", aux)); + result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + result.push_back(Pair("target", hashTarget.GetHex())); + result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); + result.push_back(Pair("mutable", aMutable)); + result.push_back(Pair("noncerange", "00000000ffffffff")); + result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); + result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); + result.push_back(Pair("curtime", (int64_t)pblock->nTime)); + result.push_back(Pair("bits", HexBits(pblock->nBits))); + result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); + + return result; +} + +Value submitblock(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "submitblock [optional-params-obj]\n" + "[optional-params-obj] parameter is currently ignored.\n" + "Attempts to submit new block to network.\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification."); + + vector blockData(ParseHex(params[0].get_str())); + CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION); + CBlock block; + try { + ssBlock >> block; + } + catch (std::exception &e) { + throw JSONRPCError(-22, "Block decode failed"); + } + + static CReserveKey reservekey(pwalletMain); + + if(!block.SignBlock(*pwalletMain)) + throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); + + bool fAccepted = CheckWork(&block, *pwalletMain, reservekey); + if (!fAccepted) + return "rejected"; + + return Value::null; +} + Value getmemorypool(const Array& params, bool fHelp) { @@ -1992,10 +2223,42 @@ Value getmemorypool(const Array& params, bool fHelp) CBlock pblock; ssBlock >> pblock; - return ProcessBlock(NULL, &pblock); + static CReserveKey reservekey(pwalletMain); + + if(!pblock.SignBlock(*pwalletMain)) + throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); + + return CheckWork(&pblock, *pwalletMain, reservekey); } } +Value getnewpubkey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getnewpubkey [account]\n" + "Returns new public key for coinbase generation."); + + // Parse the account first so we don't generate a key if there's an error + string strAccount; + if (params.size() > 0) + strAccount = AccountFromValue(params[0]); + + if (!pwalletMain->IsLocked()) + pwalletMain->TopUpKeyPool(); + + // Generate a new key that is added to wallet + std::vector newKey = pwalletMain->GenerateNewKey(false); + + if(!newKey.size()) + throw JSONRPCError(-12, "Error: Unable to create key"); + + CBitcoinAddress address(newKey); + pwalletMain->SetAddressBookName(address, strAccount); + + return HexStr(newKey.begin(), newKey.end()); +} + Value getblockhash(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -2035,6 +2298,30 @@ Value getblock(const Array& params, bool fHelp) return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false); } +Value getblockbynumber(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getblock [txinfo]\n" + "txinfo optional to print more detailed tx info\n" + "Returns details of a block with given block-number."); + + int nHeight = params[0].get_int(); + if (nHeight < 0 || nHeight > nBestHeight) + throw runtime_error("Block number out of range."); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hashBestChain]; + while (pblockindex->nHeight > nHeight) + pblockindex = pblockindex->pprev; + + uint256 hash = *pblockindex->phashBlock; + + pblockindex = mapBlockIndex[hash]; + block.ReadFromDisk(pblockindex, true); + + return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false); +} // ppcoin: get information of sync-checkpoint Value getcheckpoint(const Array& params, bool fHelp) @@ -2145,6 +2432,21 @@ Value repairwallet(const Array& params, bool fHelp) return result; } +// NovaCoin: resend unconfirmed wallet transactions +Value resendtx(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "resendtx\n" + "Re-send unconfirmed transactions.\n" + ); + + ResendWalletTransactions(); + + return Value::null; +} + + // ppcoin: make a public-private key pair Value makekeypair(const Array& params, bool fHelp) { @@ -2264,6 +2566,7 @@ static const CRPCCommand vRPCCommands[] = { "getinfo", &getinfo, true }, { "getmininginfo", &getmininginfo, true }, { "getnewaddress", &getnewaddress, true }, + { "getnewpubkey", &getnewpubkey, true }, { "getaccountaddress", &getaccountaddress, true }, { "setaccount", &setaccount, true }, { "getaccount", &getaccount, false }, @@ -2280,6 +2583,7 @@ static const CRPCCommand vRPCCommands[] = { "walletlock", &walletlock, true }, { "encryptwallet", &encryptwallet, false }, { "validateaddress", &validateaddress, true }, + { "validatepubkey", &validatepubkey, true }, { "getbalance", &getbalance, false }, { "move", &movecmd, false }, { "sendfrom", &sendfrom, false }, @@ -2287,6 +2591,7 @@ static const CRPCCommand vRPCCommands[] = { "addmultisigaddress", &addmultisigaddress, false }, { "getblock", &getblock, false }, { "getblockhash", &getblockhash, false }, + { "getblockbynumber", &getblockbynumber, false }, { "gettransaction", &gettransaction, false }, { "listtransactions", &listtransactions, false }, { "signmessage", &signmessage, false }, @@ -2295,6 +2600,8 @@ static const CRPCCommand vRPCCommands[] = { "listaccounts", &listaccounts, false }, { "settxfee", &settxfee, false }, { "getmemorypool", &getmemorypool, true }, + { "getblocktemplate", &getblocktemplate, true }, + { "submitblock", &submitblock, false }, { "listsinceblock", &listsinceblock, false }, { "dumpprivkey", &dumpprivkey, false }, { "importprivkey", &importprivkey, false }, @@ -2302,6 +2609,7 @@ static const CRPCCommand vRPCCommands[] = { "reservebalance", &reservebalance, false}, { "checkwallet", &checkwallet, false}, { "repairwallet", &repairwallet, false}, + { "resendtx", &resendtx, false}, { "makekeypair", &makekeypair, false}, { "sendalert", &sendalert, false}, }; @@ -2617,7 +2925,7 @@ void ThreadRPCServer2(void* parg) ThreadSafeMessageBox(strprintf( _("%s, you must set a rpcpassword in the configuration file:\n %s\n" "It is recommended you use the following random password:\n" - "rpcuser=bitcoinrpc\n" + "rpcuser=novarpc\n" "rpcpassword=%s\n" "(you do not need to remember this password)\n" "If the file does not exist, create it with owner-readable-only file permissions.\n"), @@ -2907,6 +3215,8 @@ int CommandLineRPC(int argc, char *argv[]) if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo(params[1]); if (strMethod == "getbalance" && n > 1) ConvertTo(params[1]); if (strMethod == "getblockhash" && n > 0) ConvertTo(params[0]); + if (strMethod == "getblockbynumber" && n > 0) ConvertTo(params[0]); + if (strMethod == "getblockbynumber" && n > 1) ConvertTo(params[1]); if (strMethod == "getblock" && n > 1) ConvertTo(params[1]); if (strMethod == "move" && n > 2) ConvertTo(params[2]); if (strMethod == "move" && n > 3) ConvertTo(params[3]);