Myriadcoin 0.11 port

This commit is contained in:
nzsquirrell
2016-02-24 20:34:22 +13:00
parent 5e70510c51
commit 5efd59f935
991 changed files with 109184 additions and 168045 deletions
+238 -226
View File
@@ -1,18 +1,25 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "core.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
#include "keystore.h"
#include "main.h"
#include "merkleblock.h"
#include "net.h"
#include "primitives/transaction.h"
#include "rpcserver.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "script/standard.h"
#include "uint256.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#include "wallet/wallet.h"
#endif
#include <stdint.h>
@@ -21,10 +28,8 @@
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"
using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
using namespace std;
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
{
@@ -36,8 +41,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeH
if (fIncludeHex)
out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
{
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
out.push_back(Pair("type", GetTxnOutputType(type)));
return;
}
@@ -57,13 +61,11 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
entry.push_back(Pair("version", tx.nVersion));
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
Array vin;
BOOST_FOREACH(const CTxIn& txin, tx.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
{
else {
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
Object o;
@@ -76,8 +78,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
}
entry.push_back(Pair("vin", vin));
Array vout;
for (unsigned int i = 0; i < tx.vout.size(); i++)
{
for (unsigned int i = 0; i < tx.vout.size(); i++) {
const CTxOut& txout = tx.vout[i];
Object out;
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
@@ -89,18 +90,15 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
}
entry.push_back(Pair("vout", vout));
if (hashBlock != 0)
{
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second)
{
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex))
{
if (chainActive.Contains(pindex)) {
entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
entry.push_back(Pair("time", (int64_t)pindex->nTime));
entry.push_back(Pair("blocktime", (int64_t)pindex->nTime));
entry.push_back(Pair("time", pindex->GetBlockTime()));
entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
}
else
entry.push_back(Pair("confirmations", 0));
@@ -113,6 +111,9 @@ Value getrawtransaction(const Array& params, bool fHelp)
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getrawtransaction \"txid\" ( verbose )\n"
"\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
"or there is an unspent output in the utxo for this transaction. To make it always work,\n"
"you need to maintain a transaction index, using the -txindex command line option.\n"
"\nReturn the raw transaction data.\n"
"\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n"
"If verbose is non-zero, returns an Object with information about 'txid'.\n"
@@ -144,7 +145,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
" \"value\" : x.xxx, (numeric) The value in btc\n"
" \"value\" : x.xxx, (numeric) The value in myr\n"
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
@@ -152,7 +153,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
" \"myriadcoinaddress\" (string) myriadcoin address\n"
" \"myriadcoinaddress\" (string) myriadcoin address\n"
" ,...\n"
" ]\n"
" }\n"
@@ -171,6 +172,8 @@ Value getrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
);
LOCK(cs_main);
uint256 hash = ParseHashV(params[0], "parameter 1");
bool fVerbose = false;
@@ -178,13 +181,11 @@ Value getrawtransaction(const Array& params, bool fHelp)
fVerbose = (params[1].get_int() != 0);
CTransaction tx;
uint256 hashBlock = 0;
uint256 hashBlock;
if (!GetTransaction(hash, tx, hashBlock, true))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
string strHex = HexStr(ssTx.begin(), ssTx.end());
string strHex = EncodeHexTx(tx);
if (!fVerbose)
return strHex;
@@ -195,121 +196,118 @@ Value getrawtransaction(const Array& params, bool fHelp)
return result;
}
#ifdef ENABLE_WALLET
Value listunspent(const Array& params, bool fHelp)
Value gettxoutproof(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 3)
if (fHelp || (params.size() != 1 && params.size() != 2))
throw runtime_error(
"listunspent ( minconf maxconf [\"address\",...] )\n"
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n"
"Results are an array of Objects, each of which has:\n"
"{txid, vout, scriptPubKey, amount, confirmations}\n"
"gettxoutproof [\"txid\",...] ( blockhash )\n"
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
"unspent output in the utxo for this transaction. To make it always work,\n"
"you need to maintain a transaction index, using the -txindex command line option or\n"
"specify the block in which the transaction is included in manually (by blockhash).\n"
"\nReturn the raw transaction data.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum confirmationsi to filter\n"
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
"3. \"addresses\" (string) A json array of myriadcoin addresses to filter\n"
"1. \"txids\" (string) A json array of txids to filter\n"
" [\n"
" \"address\" (string) myriadcoin address\n"
" \"txid\" (string) A transaction hash\n"
" ,...\n"
" ]\n"
"\nResult\n"
"[ (array of json object)\n"
" {\n"
" \"txid\" : \"txid\", (string) the transaction id \n"
" \"vout\" : n, (numeric) the vout value\n"
" \"address\" : \"address\", (string) the myriadcoin address\n"
" \"account\" : \"account\", (string) The associated account, or \"\" for the default account\n"
" \"scriptPubKey\" : \"key\", (string) the script key\n"
" \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
" \"confirmations\" : n (numeric) The number of confirmations\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples\n"
+ HelpExampleCli("listunspent", "")
+ HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
"2. \"block hash\" (string, optional) If specified, looks for txid in the block with this hash\n"
"\nResult:\n"
"\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
);
RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
set<uint256> setTxids;
uint256 oneTxid;
Array txids = params[0].get_array();
BOOST_FOREACH(Value& txid, txids) {
if (txid.get_str().length() != 64 || !IsHex(txid.get_str()))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str());
uint256 hash(uint256S(txid.get_str()));
if (setTxids.count(hash))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str());
setTxids.insert(hash);
oneTxid = hash;
}
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
LOCK(cs_main);
int nMaxDepth = 9999999;
CBlockIndex* pblockindex = NULL;
uint256 hashBlock;
if (params.size() > 1)
nMaxDepth = params[1].get_int();
set<CBitcoinAddress> setAddress;
if (params.size() > 2)
{
Array inputs = params[2].get_array();
BOOST_FOREACH(Value& input, inputs)
{
CBitcoinAddress address(input.get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Myriadcoin address: ")+input.get_str());
if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
setAddress.insert(address);
}
hashBlock = uint256S(params[1].get_str());
if (!mapBlockIndex.count(hashBlock))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
pblockindex = mapBlockIndex[hashBlock];
} else {
CCoins coins;
if (pcoinsTip->GetCoins(oneTxid, coins) && coins.nHeight > 0 && coins.nHeight <= chainActive.Height())
pblockindex = chainActive[coins.nHeight];
}
Array results;
vector<COutput> vecOutputs;
assert(pwalletMain != NULL);
pwalletMain->AvailableCoins(vecOutputs, false);
BOOST_FOREACH(const COutput& out, vecOutputs)
if (pblockindex == NULL)
{
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue;
if (setAddress.size())
{
CTxDestination address;
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
continue;
if (!setAddress.count(address))
continue;
}
int64_t nValue = out.tx->vout[out.i].nValue;
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
Object entry;
entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
entry.push_back(Pair("vout", out.i));
CTxDestination address;
if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
{
entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
if (pwalletMain->mapAddressBook.count(address))
entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
}
entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
if (pk.IsPayToScriptHash())
{
CTxDestination address;
if (ExtractDestination(pk, address))
{
const CScriptID& hash = boost::get<const CScriptID&>(address);
CScript redeemScript;
if (pwalletMain->GetCScript(hash, redeemScript))
entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
}
}
entry.push_back(Pair("amount",ValueFromAmount(nValue)));
entry.push_back(Pair("confirmations",out.nDepth));
results.push_back(entry);
CTransaction tx;
if (!GetTransaction(oneTxid, tx, hashBlock, false) || hashBlock.IsNull())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
if (!mapBlockIndex.count(hashBlock))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
pblockindex = mapBlockIndex[hashBlock];
}
return results;
CBlock block;
if(!ReadBlockFromDisk(block, pblockindex))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
unsigned int ntxFound = 0;
BOOST_FOREACH(const CTransaction&tx, block.vtx)
if (setTxids.count(tx.GetHash()))
ntxFound++;
if (ntxFound != setTxids.size())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "(Not all) transactions not found in specified block");
CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock mb(block, setTxids);
ssMB << mb;
std::string strHex = HexStr(ssMB.begin(), ssMB.end());
return strHex;
}
Value verifytxoutproof(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"verifytxoutproof \"proof\"\n"
"\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
"and throwing an RPC error if the block is not in our best chain\n"
"\nArguments:\n"
"1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n"
"\nResult:\n"
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n"
);
CDataStream ssMB(ParseHexV(params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
Array res;
vector<uint256> vMatch;
if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot)
return res;
LOCK(cs_main);
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
BOOST_FOREACH(const uint256& hash, vMatch)
res.push_back(hash.GetHex());
return res;
}
#endif
Value createrawtransaction(const Array& params, bool fHelp)
{
@@ -332,7 +330,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
" ]\n"
"2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n"
" {\n"
" \"address\": x.xxx (numeric, required) The key is the myriadcoin address, the value is the btc amount\n"
" \"address\": x.xxx (numeric, required) The key is the myriadcoin address, the value is the myr amount\n"
" ,...\n"
" }\n"
@@ -344,15 +342,15 @@ Value createrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
);
RPCTypeCheck(params, list_of(array_type)(obj_type));
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type));
Array inputs = params[0].get_array();
Object sendTo = params[1].get_obj();
CTransaction rawTx;
CMutableTransaction rawTx;
BOOST_FOREACH(const Value& input, inputs)
{
BOOST_FOREACH(const Value& input, inputs) {
const Object& o = input.get_obj();
uint256 txid = ParseHashO(o, "txid");
@@ -369,27 +367,23 @@ Value createrawtransaction(const Array& params, bool fHelp)
}
set<CBitcoinAddress> setAddress;
BOOST_FOREACH(const Pair& s, sendTo)
{
BOOST_FOREACH(const Pair& s, sendTo) {
CBitcoinAddress address(s.name_);
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Myriadcoin address: ")+s.name_);
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid myriadcoin address: ")+s.name_);
if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
setAddress.insert(address);
CScript scriptPubKey;
scriptPubKey.SetDestination(address.Get());
int64_t nAmount = AmountFromValue(s.value_);
CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(s.value_);
CTxOut out(nAmount, scriptPubKey);
rawTx.vout.push_back(out);
}
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << rawTx;
return HexStr(ss.begin(), ss.end());
return EncodeHexTx(rawTx);
}
Value decoderawtransaction(const Array& params, bool fHelp)
@@ -421,7 +415,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
" \"value\" : x.xxx, (numeric) The value in btc\n"
" \"value\" : x.xxx, (numeric) The value in myr\n"
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
@@ -443,18 +437,16 @@ Value decoderawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
);
vector<unsigned char> txData(ParseHexV(params[0], "argument"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type));
CTransaction tx;
try {
ssData >> tx;
}
catch (std::exception &e) {
if (!DecodeHexTx(tx, params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
Object result;
TxToJSON(tx, 0, result);
TxToJSON(tx, uint256(), result);
return result;
}
@@ -484,7 +476,8 @@ Value decodescript(const Array& params, bool fHelp)
+ HelpExampleRpc("decodescript", "\"hexstring\"")
);
RPCTypeCheck(params, list_of(str_type));
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type));
Object r;
CScript script;
@@ -496,10 +489,22 @@ Value decodescript(const Array& params, bool fHelp)
}
ScriptPubKeyToJSON(script, r, false);
r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
return r;
}
/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
static void TxInErrorToJSON(const CTxIn& txin, Array& vErrorsRet, const std::string& strMessage)
{
Object entry;
entry.push_back(Pair("txid", txin.prevout.hash.ToString()));
entry.push_back(Pair("vout", (uint64_t)txin.prevout.n));
entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
entry.push_back(Pair("sequence", (uint64_t)txin.nSequence));
entry.push_back(Pair("error", strMessage));
vErrorsRet.push_back(entry);
}
Value signrawtransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 4)
@@ -522,7 +527,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
" \"txid\":\"id\", (string, required) The transaction id\n"
" \"vout\":n, (numeric, required) The output number\n"
" \"scriptPubKey\": \"hex\", (string, required) script key\n"
" \"redeemScript\": \"hex\" (string, required) redeem script\n"
" \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n"
" }\n"
" ,...\n"
" ]\n"
@@ -541,8 +546,18 @@ Value signrawtransaction(const Array& params, bool fHelp)
"\nResult:\n"
"{\n"
" \"hex\": \"value\", (string) The raw transaction with signature(s) (hex-encoded string)\n"
" \"complete\": n (numeric) if transaction has a complete set of signature (0 if not)\n"
" \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n"
" \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n"
" \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n"
" {\n"
" \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n"
" \"vout\" : n, (numeric) The index of the output to spent and used as input\n"
" \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n"
" \"sequence\" : n, (numeric) Script sequence number\n"
" \"error\" : \"text\" (string) Verification or signing error related to the input\n"
" }\n"
" ,...\n"
" ]\n"
"}\n"
"\nExamples:\n"
@@ -550,19 +565,23 @@ Value signrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
);
RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
RPCTypeCheck(params, boost::assign::list_of(str_type)(array_type)(array_type)(str_type), true);
vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
vector<CTransaction> txVariants;
while (!ssData.empty())
{
vector<CMutableTransaction> txVariants;
while (!ssData.empty()) {
try {
CTransaction tx;
CMutableTransaction tx;
ssData >> tx;
txVariants.push_back(tx);
}
catch (std::exception &e) {
catch (const std::exception&) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
}
@@ -572,22 +591,21 @@ Value signrawtransaction(const Array& params, bool fHelp)
// mergedTx will end up with all the signatures; it
// starts as a clone of the rawtx:
CTransaction mergedTx(txVariants[0]);
bool fComplete = true;
CMutableTransaction mergedTx(txVariants[0]);
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
CCoinsViewCache view(viewDummy);
CCoinsViewCache view(&viewDummy);
{
LOCK(mempool.cs);
CCoinsViewCache &viewChain = *pcoinsTip;
CCoinsViewMemPool viewMempool(viewChain, mempool);
CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
const uint256& prevHash = txin.prevout.hash;
CCoins coins;
view.GetCoins(prevHash, coins); // this is certainly allowed to fail
view.AccessCoins(prevHash); // this is certainly allowed to fail
}
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
@@ -595,37 +613,35 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
if (params.size() > 2 && params[2].type() != null_type)
{
if (params.size() > 2 && params[2].type() != null_type) {
fGivenKeys = true;
Array keys = params[2].get_array();
BOOST_FOREACH(Value k, keys)
{
BOOST_FOREACH(Value k, keys) {
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(k.get_str());
if (!fGood)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
CKey key = vchSecret.GetKey();
if (!key.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
tempKeystore.AddKey(key);
}
}
#ifdef ENABLE_WALLET
else
else if (pwalletMain)
EnsureWalletIsUnlocked();
#endif
// Add previous txouts given in the RPC call:
if (params.size() > 1 && params[1].type() != null_type)
{
if (params.size() > 1 && params[1].type() != null_type) {
Array prevTxs = params[1].get_array();
BOOST_FOREACH(Value& p, prevTxs)
{
BOOST_FOREACH(Value& p, prevTxs) {
if (p.type() != obj_type)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
Object prevOut = p.get_obj();
RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
RPCTypeCheck(prevOut, boost::assign::map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
uint256 txid = ParseHashO(prevOut, "txid");
@@ -636,30 +652,26 @@ Value signrawtransaction(const Array& params, bool fHelp)
vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
CCoins coins;
if (view.GetCoins(txid, coins)) {
if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
{
CCoinsModifier coins = view.ModifyCoins(txid);
if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
string err("Previous output scriptPubKey mismatch:\n");
err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
scriptPubKey.ToString();
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
}
// what todo if txid is known, but the actual output isn't?
if ((unsigned int)nOut >= coins->vout.size())
coins->vout.resize(nOut+1);
coins->vout[nOut].scriptPubKey = scriptPubKey;
coins->vout[nOut].nValue = 0; // we don't know the actual output value
}
if ((unsigned int)nOut >= coins.vout.size())
coins.vout.resize(nOut+1);
coins.vout[nOut].scriptPubKey = scriptPubKey;
coins.vout[nOut].nValue = 0; // we don't know the actual output value
view.SetCoins(txid, coins);
// if redeemScript given and not using the local wallet (private keys
// given), add redeemScript to the tempKeystore so it can be signed:
if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
{
RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) {
RPCTypeCheck(prevOut, boost::assign::map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
Value v = find_value(prevOut, "redeemScript");
if (!(v == Value::null))
{
if (!(v == Value::null)) {
vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
@@ -675,8 +687,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
#endif
int nHashType = SIGHASH_ALL;
if (params.size() > 3 && params[3].type() != null_type)
{
if (params.size() > 3 && params[3].type() != null_type) {
static map<string, int> mapSigHashValues =
boost::assign::map_list_of
(string("ALL"), int(SIGHASH_ALL))
@@ -695,17 +706,18 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Script verification errors
Array vErrors;
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
{
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
CCoins coins;
if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
{
fComplete = false;
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) {
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
continue;
}
const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
txin.scriptSig.clear();
// Only sign SIGHASH_SINGLE if there's a corresponding output:
@@ -713,19 +725,22 @@ Value signrawtransaction(const Array& params, bool fHelp)
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
// ... and merge in other signatures:
BOOST_FOREACH(const CTransaction& txv, txVariants)
{
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0))
fComplete = false;
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}
bool fComplete = vErrors.empty();
Object result;
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << mergedTx;
result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
result.push_back(Pair("hex", EncodeHexTx(mergedTx)));
result.push_back(Pair("complete", fComplete));
if (!vErrors.empty()) {
result.push_back(Pair("errors", vErrors));
}
return result;
}
@@ -753,44 +768,41 @@ Value sendrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type));
// parse hex string from parameter
vector<unsigned char> txData(ParseHexV(params[0], "parameter"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
if (!DecodeHexTx(tx, params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
bool fOverrideFees = false;
if (params.size() > 1)
fOverrideFees = params[1].get_bool();
// deserialize binary data stream
try {
ssData >> tx;
}
catch (std::exception &e) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
uint256 hashTx = tx.GetHash();
CCoinsViewCache &view = *pcoinsTip;
CCoins existingCoins;
const CCoins* existingCoins = view.AccessCoins(hashTx);
bool fHaveMempool = mempool.exists(hashTx);
bool fHaveChain = view.GetCoins(hashTx, existingCoins) && existingCoins.nHeight < 1000000000;
bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
CValidationState state;
if (AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees))
SyncWithWallets(hashTx, tx, NULL);
else {
if(state.IsInvalid())
bool fMissingInputs;
if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
else
} else {
if (fMissingInputs) {
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
}
throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason());
}
}
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
RelayTransaction(tx, hashTx);
RelayTransaction(tx);
return hashTx.GetHex();
}