using namespace boost::assign;
using namespace json_spirit;
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
+void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
{
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
out.push_back(Pair("asm", scriptPubKey.ToString()));
- out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
+
+ if (fIncludeHex)
+ out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
{
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
+ entry.push_back(Pair("metahash", tx.GetMetaHash().GetHex()));
entry.push_back(Pair("version", tx.nVersion));
entry.push_back(Pair("time", (boost::int64_t)tx.nTime));
entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
out.push_back(Pair("n", (boost::int64_t)i));
Object o;
- ScriptPubKeyToJSON(txout.scriptPubKey, o);
+ ScriptPubKeyToJSON(txout.scriptPubKey, o, false);
out.push_back(Pair("scriptPubKey", o));
vout.push_back(out);
}
fVerbose = (params[1].get_int() != 0);
CTransaction tx;
- uint256 hashBlock = 0;
- if (!GetTransaction(hash, tx, hashBlock))
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
+ uint256 hashBlock = 0; // trying to find transaction in the blockchain
+ if (!GetTransaction(hash, tx, hashBlock, true))
+ {
+ if (pwalletMain->mapWallet.count(hash))
+ tx = (CTransaction)pwalletMain->mapWallet[hash]; // get transaction from wallet
+ else
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
+ }
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
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]));
+ }
entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
entry.push_back(Pair("amount",ValueFromAmount(nValue)));
entry.push_back(Pair("confirmations",out.nDepth));
return results;
}
+Value decodescript(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "decodescript <hex string>\n"
+ "Decode a hex-encoded script.");
+
+ RPCTypeCheck(params, list_of(str_type));
+
+ Object r;
+ CScript script;
+ if (params[0].get_str().size() > 0){
+ vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
+ script = CScript(scriptData.begin(), scriptData.end());
+ } else {
+ // Empty scripts are valid
+ }
+ ScriptPubKeyToJSON(script, r, false);
+
+ r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
+ return r;
+}
+
Value createrawtransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 2)
{
CBitcoinAddress address(s.name_);
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
bool fComplete = true;
// Fetch previous transactions (inputs):
- map<COutPoint, CScript> mapPrevOut;
- for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
+ CCoinsView viewDummy;
+ CCoinsViewCache view(viewDummy);
{
- CTransaction tempTx;
- MapPrevTx mapPrevTx;
- CTxDB txdb("r");
- map<uint256, CTxIndex> unused;
- bool fInvalid;
-
- // FetchInputs aborts on failure, so we go one at a time.
- tempTx.vin.push_back(mergedTx.vin[i]);
- tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
-
- // Copy results into mapPrevOut:
- BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
- {
+ LOCK(mempool.cs);
+ CCoinsViewCache &viewChain = *pcoinsTip;
+ 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;
- if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
- mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
+ CCoins coins;
+ view.GetCoins(prevHash, coins); // this is certainly allowed to fail
}
+
+ view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
}
// Add previous txouts given in the RPC call:
vector<unsigned char> pkData(ParseHex(pkHex));
CScript scriptPubKey(pkData.begin(), pkData.end());
- COutPoint outpoint(txid, nOut);
- if (mapPrevOut.count(outpoint))
- {
- // Complain if scriptPubKey doesn't match
- if (mapPrevOut[outpoint] != scriptPubKey)
- {
+ CCoins coins;
+ if (view.GetCoins(txid, coins)) {
+ if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
string err("Previous output scriptPubKey mismatch:\n");
- err = err + mapPrevOut[outpoint].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?
}
- else
- mapPrevOut[outpoint] = scriptPubKey;
+ coins.vout[nOut].scriptPubKey = scriptPubKey;
+ coins.vout[nOut].nValue = 0; // we don't know the actual output value
+ view.SetCoins(txid, coins);
}
}
for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
{
CTxIn& txin = mergedTx.vin[i];
- if (mapPrevOut.count(txin.prevout) == 0)
+ CCoins coins;
+ if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
{
fComplete = false;
continue;
}
- const CScript& prevPubKey = mapPrevOut[txin.prevout];
+ const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
txin.scriptSig.clear();
// Only sign SIGHASH_SINGLE if there's a corresponding output:
{
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
- if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, 0))
+ if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, true, 0))
fComplete = false;
}
}
uint256 hashTx = tx.GetHash();
- // See if the transaction is already in a block
- // or in the memory pool:
- CTransaction existingTx;
- uint256 hashBlock = 0;
- if (GetTransaction(hashTx, existingTx, hashBlock))
+ bool fHave = false;
+ CCoinsViewCache &view = *pcoinsTip;
+ CCoins existingCoins;
{
- if (hashBlock != 0)
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
+ fHave = view.GetCoins(hashTx, existingCoins);
+ if (!fHave) {
+ // push to local node
+ if (!tx.AcceptToMemoryPool())
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
+ }
+ }
+ if (fHave) {
+ if (existingCoins.nHeight < 1000000000)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
// Not in block, but already in the memory pool; will drop
// through to re-relay it.
+ } else {
+ SyncWithWallets(hashTx, tx, NULL, true);
}
- else
- {
- // push to local node
- CTxDB txdb("r");
- if (!tx.AcceptToMemoryPool(txdb))
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
-
- SyncWithWallets(tx, NULL, true);
- }
- RelayMessage(CInv(MSG_TX, hashTx), tx);
+ RelayTransaction(tx, hashTx);
return hashTx.GetHex();
}