X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fbitcoinrpc.cpp;h=f149dd2af0777a57517cfa711d8d4334315a94fb;hb=65abc2081496fed54e01b6f3b43db2df6d52a665;hp=d6268956ae99a5509742ef6610f4e6679d8d5a77;hpb=4c67b566465449fea8ff964ee2179dca51c2e2d4;p=novacoin.git diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index d626895..f149dd2 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,53 @@ 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 TxToJSON(const CTransaction &tx, Object& entry) +{ + entry.push_back(Pair("version", tx.nVersion)); + entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); + entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); + Array vin; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + Object in; + if (tx.IsCoinBase()) + in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + else + { + Object prevout; + prevout.push_back(Pair("hash", txin.prevout.hash.GetHex())); + prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n)); + in.push_back(Pair("prevout", prevout)); + in.push_back(Pair("scriptSig", txin.scriptSig.ToString())); + } + in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence)); + vin.push_back(in); + } + entry.push_back(Pair("vin", vin)); + Array vout; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + Object out; + out.push_back(Pair("value", ValueFromAmount(txout.nValue))); + out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString())); + vout.push_back(out); + } + entry.push_back(Pair("vout", vout)); +} + void WalletTxToJSON(const CWalletTx& wtx, Object& entry) { int confirms = wtx.GetDepthInMainChain(); @@ -156,22 +201,31 @@ 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) { 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()); + Object entry; + + entry.push_back(Pair("txid", tx.GetHash().GetHex())); + TxToJSON(tx, entry); + entry.push_back(Pair("time", DateTimeStrFormat(tx.nTime))); + + txinfo.push_back(entry); } else txinfo.push_back(tx.GetHash().GetHex()); } + result.push_back(Pair("tx", txinfo)); + result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end()))); + return result; } @@ -845,6 +899,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 +1095,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); } @@ -1508,24 +1584,58 @@ Value gettransaction(const Array& params, bool fHelp) Object entry; - if (!pwalletMain->mapWallet.count(hash)) - throw JSONRPCError(-5, "Invalid or non-wallet transaction id"); - const CWalletTx& wtx = pwalletMain->mapWallet[hash]; + if (pwalletMain->mapWallet.count(hash)) + { + const CWalletTx& wtx = pwalletMain->mapWallet[hash]; - int64 nCredit = wtx.GetCredit(); - int64 nDebit = wtx.GetDebit(); - int64 nNet = nCredit - nDebit; - int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0); + TxToJSON(wtx, entry); - entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); - if (wtx.IsFromMe()) - entry.push_back(Pair("fee", ValueFromAmount(nFee))); + int64 nCredit = wtx.GetCredit(); + int64 nDebit = wtx.GetDebit(); + int64 nNet = nCredit - nDebit; + int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0); - WalletTxToJSON(pwalletMain->mapWallet[hash], entry); + entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); + if (wtx.IsFromMe()) + entry.push_back(Pair("fee", ValueFromAmount(nFee))); - Array details; - ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details); - entry.push_back(Pair("details", details)); + WalletTxToJSON(wtx, entry); + + Array details; + ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details); + entry.push_back(Pair("details", details)); + } + else + { + CTransaction tx; + uint256 hashBlock = 0; + if (GetTransaction(hash, tx, hashBlock)) + { + entry.push_back(Pair("txid", hash.GetHex())); + TxToJSON(tx, entry); + if (hashBlock == 0) + entry.push_back(Pair("confirmations", 0)); + else + { + entry.push_back(Pair("blockhash", hashBlock.GetHex())); + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end() && (*mi).second) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + { + entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight)); + entry.push_back(Pair("txntime", (boost::int64_t)tx.nTime)); + entry.push_back(Pair("time", (boost::int64_t)pindex->nTime)); + } + else + entry.push_back(Pair("confirmations", 0)); + } + } + } + else + throw JSONRPCError(-5, "No information available about transaction"); + } return entry; } @@ -1803,6 +1913,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,98 +2063,6 @@ Value getwork(const Array& params, bool fHelp) } } -Value getmemorypool(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getmemorypool [data]\n" - "If [data] is not specified, 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" - " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n" - " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n" - " \"time\" : timestamp appropriate for next block\n" - " \"mintime\" : minimum timestamp appropriate for next block\n" - " \"curtime\" : current timestamp\n" - " \"bits\" : compressed target of next block\n" - "If [data] is specified, tries to solve the block and returns true if it was successful."); - - if (params.size() == 0) - { - 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)) - { - nTransactionsUpdatedLast = nTransactionsUpdated; - pindexPrev = pindexBest; - nStart = GetTime(); - - // Create new block - if(pblock) - delete pblock; - pblock = CreateNewBlock(pwalletMain); - if (!pblock) - throw JSONRPCError(-7, "Out of memory"); - } - - // Update nTime - pblock->UpdateTime(pindexPrev); - pblock->nNonce = 0; - - Array transactions; - BOOST_FOREACH(CTransaction tx, pblock->vtx) { - if(tx.IsCoinBase() || tx.IsCoinStake()) - continue; - - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); - ssTx << tx; - - transactions.push_back(HexStr(ssTx.begin(), ssTx.end())); - } - - 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("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); - result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); - result.push_back(Pair("time", (int64_t)pblock->nTime)); - result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); - result.push_back(Pair("curtime", (int64_t)GetAdjustedTime())); - result.push_back(Pair("bits", HexBits(pblock->nBits))); - - return result; - } - else - { - // Parse parameters - CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION); - CBlock pblock; - ssBlock >> pblock; - - static CReserveKey reservekey(pwalletMain); - - if(!pblock.SignBlock(*pwalletMain)) - throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); - - return CheckWork(&pblock, *pwalletMain, reservekey); - } -} - - Value getblocktemplate(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) @@ -2185,6 +2247,98 @@ Value submitblock(const Array& params, bool fHelp) return Value::null; } + +Value getmemorypool(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getmemorypool [data]\n" + "If [data] is not specified, 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" + " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n" + " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n" + " \"time\" : timestamp appropriate for next block\n" + " \"mintime\" : minimum timestamp appropriate for next block\n" + " \"curtime\" : current timestamp\n" + " \"bits\" : compressed target of next block\n" + "If [data] is specified, tries to solve the block and returns true if it was successful."); + + if (params.size() == 0) + { + 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)) + { + nTransactionsUpdatedLast = nTransactionsUpdated; + pindexPrev = pindexBest; + nStart = GetTime(); + + // Create new block + if(pblock) + delete pblock; + pblock = CreateNewBlock(pwalletMain); + if (!pblock) + throw JSONRPCError(-7, "Out of memory"); + } + + // Update nTime + pblock->UpdateTime(pindexPrev); + pblock->nNonce = 0; + + Array transactions; + BOOST_FOREACH(CTransaction tx, pblock->vtx) { + if(tx.IsCoinBase() || tx.IsCoinStake()) + continue; + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << tx; + + transactions.push_back(HexStr(ssTx.begin(), ssTx.end())); + } + + 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("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); + result.push_back(Pair("time", (int64_t)pblock->nTime)); + result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); + result.push_back(Pair("curtime", (int64_t)GetAdjustedTime())); + result.push_back(Pair("bits", HexBits(pblock->nBits))); + + return result; + } + else + { + // Parse parameters + CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION); + CBlock pblock; + ssBlock >> 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) @@ -2201,7 +2355,7 @@ Value getnewpubkey(const Array& params, bool fHelp) pwalletMain->TopUpKeyPool(); // Generate a new key that is added to wallet - std::vector newKey = pwalletMain->GenerateNewKey(false); + std::vector newKey = pwalletMain->GenerateNewKey(true); if(!newKey.size()) throw JSONRPCError(-12, "Error: Unable to create key"); @@ -2212,7 +2366,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) @@ -2252,6 +2405,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) @@ -2362,6 +2539,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) { @@ -2475,6 +2667,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 }, @@ -2498,6 +2691,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 }, @@ -2505,6 +2699,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 }, @@ -2522,6 +2717,7 @@ static const CRPCCommand vRPCCommands[] = { "reservebalance", &reservebalance, false}, { "checkwallet", &checkwallet, false}, { "repairwallet", &repairwallet, false}, + { "resendtx", &resendtx, false}, { "makekeypair", &makekeypair, false}, { "sendalert", &sendalert, false}, }; @@ -2837,7 +3033,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"), @@ -3127,6 +3323,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]);