X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fbitcoinrpc.cpp;h=a973d37e72a94f4f794b06d842f806222ffed7b9;hb=0ef485c34dd98febcab3cfc237dc7e9f42128792;hp=e2f7d27c0df6706e29c331cbba44c75fcc37ab69;hpb=440991a0f8dbdd6147e56ec55e3423429cee6e90;p=novacoin.git diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index e2f7d27..a973d37 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; @@ -116,6 +114,19 @@ HexBits(unsigned int nBits) return HexStr(BEGIN(uBits.cBits), END(uBits.cBits)); } +unsigned int BitsHex(std::string HexBits) +{ + union { + int32_t nBits; + char cBits[4]; + } uBits; + + vector vchBits = ParseHex(HexBits); + copy(vchBits.begin(), vchBits.begin() + 4, uBits.cBits); + uBits.nBits = htonl((int32_t)uBits.nBits); + return uBits.nBits; +} + void WalletTxToJSON(const CWalletTx& wtx, Object& entry) { int confirms = wtx.GetDepthInMainChain(); @@ -156,6 +167,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) { @@ -845,6 +861,28 @@ Value getbalance(const Array& params, bool fHelp) } +Value getpowreward(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getpowreward [nBits]\n" + "Returns PoW reward for block with provided difficulty."); + + if (params.size() == 0) + throw JSONRPCError(-200, "no bits provided"); + + std::string sBits = params[0].get_str(); + + if (sBits.length() != 8) + throw JSONRPCError(-201, "incorrect bits provided"); + + unsigned int nBits = BitsHex(sBits); + + return (int)GetProofOfWorkReward(nBits); +} + + + Value movecmd(const Array& params, bool fHelp) { if (fHelp || params.size() < 3 || params.size() > 5) @@ -1019,7 +1057,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 +1841,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 +1991,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,7 +2258,12 @@ 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); } } @@ -2023,7 +2294,6 @@ Value getnewpubkey(const Array& params, bool fHelp) return HexStr(newKey.begin(), newKey.end()); } - Value getblockhash(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -2063,6 +2333,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) @@ -2173,6 +2467,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) { @@ -2286,6 +2595,7 @@ static const CRPCCommand vRPCCommands[] = { "getblocknumber", &getblocknumber, true }, { "getconnectioncount", &getconnectioncount, true }, { "getdifficulty", &getdifficulty, true }, + { "getpowreward", &getpowreward, true }, { "getgenerate", &getgenerate, true }, { "setgenerate", &setgenerate, true }, { "gethashespersec", &gethashespersec, true }, @@ -2309,6 +2619,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 }, @@ -2316,6 +2627,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 }, @@ -2324,6 +2636,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 }, @@ -2331,6 +2645,7 @@ static const CRPCCommand vRPCCommands[] = { "reservebalance", &reservebalance, false}, { "checkwallet", &checkwallet, false}, { "repairwallet", &repairwallet, false}, + { "resendtx", &resendtx, false}, { "makekeypair", &makekeypair, false}, { "sendalert", &sendalert, false}, }; @@ -2646,7 +2961,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"), @@ -2936,6 +3251,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]);