// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
-// Copyright (c) 2011-2012 The PPCoin 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.
return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
}
+unsigned int BitsHex(std::string HexBits)
+{
+ union {
+ int32_t nBits;
+ char cBits[4];
+ } uBits;
+
+ vector<unsigned char> 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();
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()));
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()));
+ 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());
+ }
+ else
+ txinfo.push_back(tx.GetHash().GetHex());
+ }
+ result.push_back(Pair("tx", txinfo));
return result;
}
if (fHelp || params.size() != 0)
throw runtime_error(
"stop\n"
- "Stop ppcoin server.");
+ "Stop novacoin server.");
// Shutdown will take long enough that the response should get back
StartShutdown();
- return "ppcoin server stopping";
+ return "novacoin server stopping";
}
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;
}
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()));
if (fHelp || params.size() > 1)
throw runtime_error(
"getnewaddress [account]\n"
- "Returns a new ppcoin address for receiving payments. "
+ "Returns a new novacoin address for receiving payments. "
"If [account] is specified (recommended), it is added to the address book "
"so payments received with the address will be credited to [account].");
if (fHelp || params.size() != 1)
throw runtime_error(
"getaccountaddress <account>\n"
- "Returns the current ppcoin address for receiving payments to this account.");
+ "Returns the current novacoin address for receiving payments to this account.");
// Parse the account first so we don't generate a key if there's an error
string strAccount = AccountFromValue(params[0]);
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
- "setaccount <ppcoinaddress> <account>\n"
+ "setaccount <novacoinaddress> <account>\n"
"Sets the account associated with the given address.");
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
- throw JSONRPCError(-5, "Invalid ppcoin address");
+ throw JSONRPCError(-5, "Invalid novacoin address");
string strAccount;
{
if (fHelp || params.size() != 1)
throw runtime_error(
- "getaccount <ppcoinaddress>\n"
+ "getaccount <novacoinaddress>\n"
"Returns the account associated with the given address.");
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
- throw JSONRPCError(-5, "Invalid ppcoin address");
+ throw JSONRPCError(-5, "Invalid novacoin address");
string strAccount;
map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
- "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
+ "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.000001\n"
"requires wallet passphrase to be set with walletpassphrase first");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
- "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
+ "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.000001");
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
- throw JSONRPCError(-5, "Invalid ppcoin address");
+ throw JSONRPCError(-5, "Invalid novacoin address");
// Amount
int64 nAmount = AmountFromValue(params[1]);
+ if (nAmount < MIN_TXOUT_AMOUNT)
+ throw JSONRPCError(-101, "Send amount too small");
// Wallet comments
CWalletTx wtx;
{
if (fHelp || params.size() != 2)
throw runtime_error(
- "signmessage <ppcoinaddress> <message>\n"
+ "signmessage <novacoinaddress> <message>\n"
"Sign a message with the private key of an address");
if (pwalletMain->IsLocked())
{
if (fHelp || params.size() != 3)
throw runtime_error(
- "verifymessage <ppcoinaddress> <signature> <message>\n"
+ "verifymessage <novacoinaddress> <signature> <message>\n"
"Verify a signed message");
string strAddress = params[0].get_str();
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
- "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
- "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
+ "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
+ "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
// Bitcoin address
CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
CScript scriptPubKey;
if (!address.IsValid())
- throw JSONRPCError(-5, "Invalid ppcoin address");
+ throw JSONRPCError(-5, "Invalid novacoin address");
scriptPubKey.SetBitcoinAddress(address);
if (!IsMine(*pwalletMain,scriptPubKey))
return (double)0.0;
}
+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)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
throw runtime_error(
- "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
+ "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.000001\n"
"requires wallet passphrase to be set with walletpassphrase first");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
throw runtime_error(
- "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
+ "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.000001");
string strAccount = AccountFromValue(params[0]);
CBitcoinAddress address(params[1].get_str());
if (!address.IsValid())
- throw JSONRPCError(-5, "Invalid ppcoin address");
+ throw JSONRPCError(-5, "Invalid novacoin 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();
{
CBitcoinAddress address(s.name_);
if (!address.IsValid())
- throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
+ throw JSONRPCError(-5, string("Invalid novacoin address:")+s.name_);
if (setAddress.count(address))
throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
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));
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);
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];
+
+ TxToJSON(wtx, entry);
- int64 nCredit = wtx.GetCredit();
- int64 nDebit = wtx.GetDebit();
- int64 nNet = nCredit - nDebit;
- int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
+ int64 nCredit = wtx.GetCredit();
+ int64 nDebit = wtx.GetDebit();
+ int64 nNet = nCredit - nDebit;
+ int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
- entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
- if (wtx.IsFromMe())
- entry.push_back(Pair("fee", ValueFromAmount(nFee)));
+ entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
+ if (wtx.IsFromMe())
+ entry.push_back(Pair("fee", ValueFromAmount(nFee)));
- WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
+ WalletTxToJSON(wtx, entry);
- Array details;
- ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
- entry.push_back(Pair("details", details));
+ 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<uint256, CBlockIndex*>::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("time", (boost::int64_t)pindex->nTime));
+ }
+ else
+ entry.push_back(Pair("confirmations", 0));
+ }
+ }
+ }
+ else
+ throw JSONRPCError(-5, "No information available about transaction");
+ }
return entry;
}
{
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())
// 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;
}
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
StartShutdown();
- return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
+ return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
}
{
if (fHelp || params.size() != 1)
throw runtime_error(
- "validateaddress <ppcoinaddress>\n"
- "Return information about <ppcoinaddress>.");
+ "validateaddress <novacoinaddress>\n"
+ "Return information about <novacoinaddress>.");
CBitcoinAddress address(params[0].get_str());
bool isValid = address.IsValid();
return ret;
}
+Value validatepubkey(const Array& params, bool fHelp)
+{
+ if (fHelp || !params.size() || params.size() > 2)
+ throw runtime_error(
+ "validatepubkey <novacoinpubkey>\n"
+ "Return information about <novacoinpubkey>.");
+
+ std::vector<unsigned char> 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 getworkex(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 2)
+ throw runtime_error(
+ "getworkex [data, coinbase]\n"
+ "If [data, coinbase] is not specified, returns extended work data.\n"
+ );
+
+ if (vNodes.empty())
+ throw JSONRPCError(-9, "NovaCoin is not connected!");
+
+ if (IsInitialBlockDownload())
+ throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
+
+ typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
+ static mapNewBlock_t mapNewBlock;
+ static vector<CBlock*> vNewBlock;
+ static CReserveKey reservekey(pwalletMain);
+
+ if (params.size() == 0)
+ {
+ // Update block
+ static unsigned int nTransactionsUpdatedLast;
+ static CBlockIndex* pindexPrev;
+ static int64 nStart;
+ static CBlock* pblock;
+ if (pindexPrev != pindexBest ||
+ (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
+ {
+ if (pindexPrev != pindexBest)
+ {
+ // Deallocate old blocks since they're obsolete now
+ mapNewBlock.clear();
+ BOOST_FOREACH(CBlock* pblock, vNewBlock)
+ delete pblock;
+ vNewBlock.clear();
+ }
+ nTransactionsUpdatedLast = nTransactionsUpdated;
+ pindexPrev = pindexBest;
+ nStart = GetTime();
+
+ // Create new block
+ pblock = CreateNewBlock(pwalletMain);
+ if (!pblock)
+ throw JSONRPCError(-7, "Out of memory");
+ vNewBlock.push_back(pblock);
+ }
+
+ // Update nTime
+ pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ pblock->nNonce = 0;
+
+ // Update nExtraNonce
+ static unsigned int nExtraNonce = 0;
+ IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
+
+ // Save
+ mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
+
+ // Prebuild hash buffers
+ char pmidstate[32];
+ char pdata[128];
+ char phash1[64];
+ FormatHashBuffers(pblock, pmidstate, pdata, phash1);
+
+ uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
+
+ CTransaction coinbaseTx = pblock->vtx[0];
+ std::vector<uint256> merkle = pblock->GetMerkleBranch(0);
+
+ Object result;
+ result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
+ result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
+
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ ssTx << coinbaseTx;
+ result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end())));
+
+ Array merkle_arr;
+ printf("DEBUG: merkle size %i\n", merkle.size());
+
+ BOOST_FOREACH(uint256 merkleh, merkle) {
+ printf("%s\n", merkleh.ToString().c_str());
+ merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
+ }
+
+ result.push_back(Pair("merkle", merkle_arr));
+
+
+ return result;
+ }
+ else
+ {
+ // Parse parameters
+ vector<unsigned char> vchData = ParseHex(params[0].get_str());
+ vector<unsigned char> coinbase;
+
+ if(params.size() == 2)
+ coinbase = ParseHex(params[1].get_str());
+
+ if (vchData.size() != 128)
+ throw JSONRPCError(-8, "Invalid parameter");
+
+ CBlock* pdata = (CBlock*)&vchData[0];
+
+ // Byte reverse
+ for (int i = 0; i < 128/4; i++)
+ ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
+
+ // Get saved block
+ if (!mapNewBlock.count(pdata->hashMerkleRoot))
+ return false;
+ CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
+
+ pblock->nTime = pdata->nTime;
+ pblock->nNonce = pdata->nNonce;
+
+ if(coinbase.size() == 0)
+ pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
+ else
+ CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK!
+
+ pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+
+ if (!pblock->SignBlock(*pwalletMain))
+ throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
+
+ return CheckWork(pblock, *pwalletMain, reservekey);
+ }
+}
+
+
Value getwork(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
"If [data] is specified, tries to solve the block and returns true if it was successful.");
if (vNodes.empty())
- throw JSONRPCError(-9, "PPCoin is not connected!");
+ throw JSONRPCError(-9, "NovaCoin is not connected!");
if (IsInitialBlockDownload())
- throw JSONRPCError(-10, "PPCoin is downloading blocks...");
+ throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
static mapNewBlock_t mapNewBlock;
nStart = GetTime();
// Create new block
- pblock = CreateNewBlock(pwalletMain, true);
+ pblock = CreateNewBlock(pwalletMain);
if (!pblock)
throw JSONRPCError(-7, "Out of memory");
vNewBlock.push_back(pblock);
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);
}
}
+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<uint256, int64_t> 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<uint256, CTxIndex> 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 <hex data> [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<unsigned char> 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)
{
if (params.size() == 0)
{
if (vNodes.empty())
- throw JSONRPCError(-9, "PPCoin is not connected!");
+ throw JSONRPCError(-9, "NovaCoin is not connected!");
if (IsInitialBlockDownload())
- throw JSONRPCError(-10, "PPCoin is downloading blocks...");
+ throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
static CReserveKey reservekey(pwalletMain);
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<unsigned char> 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)
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();
CBlockIndex* pblockindex = mapBlockIndex[hash];
block.ReadFromDisk(pblockindex, true);
- return blockToJSON(block, pblockindex);
+ 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 <number> [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)
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;
}
int nMismatchSpent;
int64 nBalanceInQuestion;
- if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
+ pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
+ Object result;
+ if (nMismatchSpent == 0)
+ 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;
}
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));
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)
{
// 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;
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;
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: set checkpoint key
-Value setcheckpointkey(const Array& params, bool fHelp)
-{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "setcheckpointkey <privatekey>\n"
- "<privatekey> is hex string of checkpoint master private key\n");
-
- CSyncCheckpoint checkpoint;
- checkpoint.hashCheckpoint = hashGenesisBlock;
- 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());
- CKey key;
- 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");
-
- CSyncCheckpoint::strMasterPrivKey = params[0].get_str();
-
- return "checkpoint master key has been set.";
-}
//
{ "getblocknumber", &getblocknumber, true },
{ "getconnectioncount", &getconnectioncount, true },
{ "getdifficulty", &getdifficulty, true },
+ { "getpowreward", &getpowreward, true },
{ "getgenerate", &getgenerate, true },
{ "setgenerate", &setgenerate, true },
{ "gethashespersec", &gethashespersec, true },
{ "getinfo", &getinfo, true },
{ "getmininginfo", &getmininginfo, true },
{ "getnewaddress", &getnewaddress, true },
+ { "getnewpubkey", &getnewpubkey, true },
{ "getaccountaddress", &getaccountaddress, true },
{ "setaccount", &setaccount, true },
{ "getaccount", &getaccount, false },
{ "walletlock", &walletlock, true },
{ "encryptwallet", &encryptwallet, false },
{ "validateaddress", &validateaddress, true },
+ { "validatepubkey", &validatepubkey, true },
{ "getbalance", &getbalance, false },
{ "move", &movecmd, false },
{ "sendfrom", &sendfrom, false },
{ "addmultisigaddress", &addmultisigaddress, false },
{ "getblock", &getblock, false },
{ "getblockhash", &getblockhash, false },
+ { "getblockbynumber", &getblockbynumber, false },
{ "gettransaction", &gettransaction, false },
{ "listtransactions", &listtransactions, false },
{ "signmessage", &signmessage, false },
{ "verifymessage", &verifymessage, false },
{ "getwork", &getwork, true },
+ { "getworkex", &getworkex, true },
{ "listaccounts", &listaccounts, false },
{ "settxfee", &settxfee, false },
{ "getmemorypool", &getmemorypool, true },
+ { "getblocktemplate", &getblocktemplate, true },
+ { "submitblock", &submitblock, false },
{ "listsinceblock", &listsinceblock, false },
{ "dumpprivkey", &dumpprivkey, false },
{ "importprivkey", &importprivkey, false },
{ "reservebalance", &reservebalance, false},
{ "checkwallet", &checkwallet, false},
{ "repairwallet", &repairwallet, false},
+ { "resendtx", &resendtx, false},
{ "makekeypair", &makekeypair, false},
{ "sendalert", &sendalert, false},
- { "setcheckpointkey", &setcheckpointkey, false},
};
CRPCTable::CRPCTable()
{
ostringstream s;
s << "POST / HTTP/1.1\r\n"
- << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
+ << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
<< "Host: 127.0.0.1\r\n"
<< "Content-Type: application/json\r\n"
<< "Content-Length: " << strMsg.size() << "\r\n"
if (nStatus == 401)
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
"Date: %s\r\n"
- "Server: ppcoin-json-rpc/%s\r\n"
+ "Server: novacoin-json-rpc/%s\r\n"
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 296\r\n"
"Connection: close\r\n"
"Content-Length: %d\r\n"
"Content-Type: application/json\r\n"
- "Server: ppcoin-json-rpc/%s\r\n"
+ "Server: novacoin-json-rpc/%s\r\n"
"\r\n"
"%s",
nStatus,
{
unsigned char rand_pwd[32];
RAND_bytes(rand_pwd, 32);
- string strWhatAmI = "To use ppcoind";
+ string strWhatAmI = "To use novacoind";
if (mapArgs.count("-server"))
strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
else if (mapArgs.count("-daemon"))
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"),
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 == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
+ 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]);
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();