From fded438a3f2cc63872fae514c4f3fb5f813f7f3c Mon Sep 17 00:00:00 2001 From: Neil Date: Wed, 5 Apr 2017 11:22:26 +0800 Subject: [PATCH 1/2] Reimplement createcontract previous version --- src/primitives/transaction.h | 2 +- src/rpc/client.cpp | 2 + src/validation.cpp | 2 +- src/validation.h | 3 + src/wallet/rpcwallet.cpp | 151 +++++++++++++++++++++++++++++++++++ src/wallet/wallet.cpp | 28 +++++-- src/wallet/wallet.h | 6 +- 7 files changed, 184 insertions(+), 10 deletions(-) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 98a63854bc1d4..9d1acc71c3988 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -205,7 +205,7 @@ class CTxOut bool IsDust(const CFeeRate &minRelayTxFee) const { - return (nValue < GetDustThreshold(minRelayTxFee)); + return (nValue < GetDustThreshold(minRelayTxFee) && !this->scriptPubKey.HasOpCreate() && !this->scriptPubKey.HasOpCall()); } friend bool operator==(const CTxOut& a, const CTxOut& b) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 5bdd84e555116..5340cce1f9314 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -129,6 +129,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "echojson", 7, "arg7" }, { "echojson", 8, "arg8" }, { "echojson", 9, "arg9" }, + { "createcontract", 2 }, + { "createcontract", 3 }, }; class CRPCConvertTable diff --git a/src/validation.cpp b/src/validation.cpp index a1f7f56caa208..53b49438d0cb7 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -787,7 +787,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C dFreeCount += nSize; } - if (nAbsurdFee && nFees > nAbsurdFee) + if (!tx.HasCreateOrCall() && nAbsurdFee && nFees > nAbsurdFee) return state.Invalid(false, REJECT_HIGHFEE, "absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee)); diff --git a/src/validation.h b/src/validation.h index 179e988273787..6e69ba30670fa 100644 --- a/src/validation.h +++ b/src/validation.h @@ -158,6 +158,9 @@ static const int MAX_UNCONNECTING_HEADERS = 10; static const bool DEFAULT_PEERBLOOMFILTERS = true; +static const uint64_t DEFAULT_GAS_LIMIT=100000; +static const CAmount DEFAULT_GAS_PRICE=0.00001*COIN; + struct BlockHasher { size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4879ba2a82479..a1b409705f4a4 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -432,7 +432,157 @@ UniValue sendtoaddress(const JSONRPCRequest& request) return wtx.GetHash().GetHex(); } +UniValue createcontract(const JSONRPCRequest& request){ + if (!EnsureWalletIsAvailable(request.fHelp)) + return NullUniValue; + if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) + throw runtime_error( + "createcontract \"senderaddress\" \"bytecode\" (gaslimit gasprice)" + "\nCreate a contract with bytcode.\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "1. \"senderaddress\" (string, required) The quantum address that will be used to create the contract.\n" + "2. \"bytecode\" (string, required) contract bytcode.\n" + "3. gasLimit (numeric or string, optional) gasLimit, default: "+i64tostr(DEFAULT_GAS_LIMIT)+"\n" + "4. gasPrice (numeric or string, optional) gasPrice QTUM price per gas unit, default: "+FormatMoney(DEFAULT_GAS_PRICE)+"\n" + "\nResult:\n" + "[\n" + " {\n" + " \"txid\" : (string) The transaction id.\n" + " \"sender\" : (string) " + CURRENCY_UNIT + " address of the sender.\n" + " \"hash160\" : (string) ripemd-160 hash of the sender.\n" + " \"address\" : (string) expected contract address.\n" + " }\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("createcontract", "\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256\"") + + HelpExampleCli("createcontract", "\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256\" 6000000 0.00000001") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CBitcoinAddress senderAddress(request.params[0].get_str()); + if (!senderAddress.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address to send from"); + + string bytecode=request.params[1].get_str(); + + uint64_t nGasLimit=DEFAULT_GAS_LIMIT; + if (request.params.size() > 2){ + nGasLimit = request.params[2].get_int64(); + if (nGasLimit <= 0) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasLimit"); + } + + CAmount nGasPrice = DEFAULT_GAS_PRICE; + if (request.params.size() > 3){ + nGasPrice = request.params[3].get_real()*COIN; + if (nGasPrice <= 0) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasPrice"); + } + + + + //find a UTXO with sender address + + UniValue results(UniValue::VARR); + vector vecOutputs; + CCoinControl coinControl; + coinControl.fAllowOtherInputs=true; + + assert(pwalletMain != NULL); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); + + BOOST_FOREACH(const COutput& out, vecOutputs) { + CTxDestination address; + const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey; + bool fValidAddress = ExtractDestination(scriptPubKey, address); + + if (!(fValidAddress && senderAddress.Get() == address)) + continue; + + coinControl.Select(COutPoint(out.tx->GetHash(),out.i)); + + break; + + } + + if(!coinControl.HasSelected()){ + throw JSONRPCError(RPC_TYPE_ERROR, "Sender address does not have any unspent outputs"); + } + + EnsureWalletIsUnlocked(); + + CWalletTx wtx; + + wtx.nTimeSmart = GetAdjustedTime(); + + CAmount nGasFee=nGasPrice*nGasLimit; + + CAmount curBalance = pwalletMain->GetBalance(); + + // Check amount + if (nGasFee <= 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); + + if (nGasFee > curBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); + + // Build OP_EXEC script + CScript scriptPubKey = CScript() << ParseHex("01") << CScriptNum(nGasLimit) << CScriptNum(nGasPrice) << ParseHex(bytecode) < vecSend; + int nChangePosRet = -1; + CRecipient recipient = {scriptPubKey, 0, false}; + vecSend.push_back(recipient); + + if (!pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRequired, nChangePosRet, strError, &coinControl, true, nGasFee, true)) { + if (nFeeRequired > pwalletMain->GetBalance()) + strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); + throw JSONRPCError(RPC_WALLET_ERROR, strError); + } + + CTxDestination txSenderDest; + ExtractDestination(pwalletMain->mapWallet[wtx.tx->vin[0].prevout.hash].tx->vout[wtx.tx->vin[0].prevout.n].scriptPubKey,txSenderDest); + if (!(senderAddress.Get() == txSenderDest)){ + throw JSONRPCError(RPC_TYPE_ERROR, "Sender could not be set, transaction was not commited!"); + } + CValidationState state; + if (!pwalletMain->CommitTransaction(wtx, reservekey, g_connman.get(), state)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here."); + + UniValue result(UniValue::VOBJ); + std::string txId=wtx.GetHash().GetHex(); + result.push_back(Pair("txid", txId)); + + CBitcoinAddress txSenderAdress(txSenderDest); + CKeyID keyid; + txSenderAdress.GetKeyID(keyid); + + result.push_back(Pair("sender", txSenderAdress.ToString())); + result.push_back(Pair("hash160", HexStr(valtype(keyid.begin(),keyid.end())))); + + std::vector SHA256TxVout(32); + vector contractAddress(20); + vector txIdAndVout(wtx.GetHash().begin(), wtx.GetHash().end()); + unsigned char nOut=0; + BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) { + if(txout.scriptPubKey.HasOpCreate()){ + txIdAndVout.push_back(nOut); + } + nOut++; + } + CSHA256().Write(txIdAndVout.data(), txIdAndVout.size()).Finalize(SHA256TxVout.data()); + CRIPEMD160().Write(SHA256TxVout.data(), SHA256TxVout.size()).Finalize(contractAddress.data()); + result.push_back(Pair("address", HexStr(contractAddress))); + + return result; +} UniValue listaddressgroupings(const JSONRPCRequest& request) { if (!EnsureWalletIsAvailable(request.fHelp)) @@ -3045,6 +3195,7 @@ static const CRPCCommand commands[] = { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, {"oldpassphrase","newpassphrase"} }, { "wallet", "walletpassphrase", &walletpassphrase, true, {"passphrase","timeout"} }, { "wallet", "removeprunedfunds", &removeprunedfunds, true, {"txid"} }, + { "wallet", "createcontract", &createcontract, false, {"gas-price", "gas-limit", "bytecode", "sender-address", "txfee", "broadcast"} }, }; void RegisterWalletRPCCommands(CRPCTable &t) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1b59c3cd80c15..07c17a3fcf17b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -8,7 +8,7 @@ #include "base58.h" #include "checkpoints.h" #include "chain.h" -#include "wallet/coincontrol.h" +//#include "wallet/coincontrol.h" #include "consensus/consensus.h" #include "consensus/validation.h" #include "key.h" @@ -2370,11 +2370,17 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov } bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, - int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign) + int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign, CAmount nGasFee, bool hasSender) { CAmount nValue = 0; int nChangePosRequest = nChangePosInOut; unsigned int nSubtractFeeFromAmount = 0; + COutPoint senderInput; + if(hasSender && coinControl && coinControl->HasSelected()){ + std::vector vSenderInputs; + coinControl->ListSelected(vSenderInputs); + senderInput=vSenderInputs[0]; + } for (const auto& recipient : vecSend) { if (nValue < 0 || recipient.nAmount < 0) @@ -2591,6 +2597,18 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt else reservekey.ReturnKey(); + // Move sender input to position 0 + vector> vCoins(setCoins.begin(),setCoins.end()); + if(hasSender && coinControl && coinControl->HasSelected()){ + for (std::vector>::size_type i = 0 ; i != vCoins.size(); i++){ + if(COutPoint(vCoins[i].first->GetHash(),vCoins[i].second)==senderInput){ + if(i==0)break; + iter_swap(vCoins.begin(),vCoins.begin()+i); + break; + } + } + } + // Fill vin // // Note how the sequence number is set to non-maxint so that @@ -2601,12 +2619,12 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt // to avoid conflicting with other possible uses of nSequence, // and in the spirit of "smallest possible change from prior // behavior." - for (const auto& coin : setCoins) + for (const auto& coin : vCoins) txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(), std::numeric_limits::max() - (fWalletRbf ? 2 : 1))); // Fill in dummy signatures for fee calculation. - if (!DummySignTx(txNew, setCoins)) { + if (!DummySignTx(txNew, vCoins)) { strFailReason = _("Signing transaction failed"); return false; } @@ -2637,7 +2655,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt break; } - CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool); + CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool)+nGasFee; if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) { nFeeNeeded = coinControl->nMinimumTotalFee; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 98e4fb87b9107..e48c77e57d48a 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -17,7 +17,7 @@ #include "wallet/crypter.h" #include "wallet/walletdb.h" #include "wallet/rpcwallet.h" - +#include "wallet/coincontrol.h" #include #include #include @@ -75,7 +75,7 @@ static const bool DEFAULT_USE_HD_WALLET = true; extern const char * DEFAULT_WALLET_DAT; class CBlockIndex; -class CCoinControl; +//class CCoinControl; class COutput; class CReserveKey; class CScript; @@ -811,7 +811,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface * @note passing nChangePosInOut as -1 will result in setting a random position */ bool CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, - std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true); + std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true, CAmount nGasFee=0, bool hasSender=false); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state); void ListAccountCreditDebit(const std::string& strAccount, std::list& entries); From 49717887085e1b4832314db863340ab3c06f329f Mon Sep 17 00:00:00 2001 From: Neil Date: Wed, 5 Apr 2017 15:06:50 +0800 Subject: [PATCH 2/2] createcontract implementation changes --- src/rpc/client.cpp | 5 ++- src/validation.h | 2 +- src/wallet/rpcwallet.cpp | 81 +++++++++++++++++++++++++--------------- 3 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 5340cce1f9314..f30c0ec35a4df 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -118,6 +118,9 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getmempoolancestors", 1, "verbose" }, { "getmempooldescendants", 1, "verbose" }, { "bumpfee", 1, "options" }, + { "createcontract", 1, "gasLimit" }, + { "createcontract", 2, "gasPrice" }, + { "createcontract", 4, "broadcast" }, // Echo with conversion (For testing only) { "echojson", 0, "arg0" }, { "echojson", 1, "arg1" }, @@ -129,8 +132,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { "echojson", 7, "arg7" }, { "echojson", 8, "arg8" }, { "echojson", 9, "arg9" }, - { "createcontract", 2 }, - { "createcontract", 3 }, }; class CRPCConvertTable diff --git a/src/validation.h b/src/validation.h index 6e69ba30670fa..da766c2a682e3 100644 --- a/src/validation.h +++ b/src/validation.h @@ -158,7 +158,7 @@ static const int MAX_UNCONNECTING_HEADERS = 10; static const bool DEFAULT_PEERBLOOMFILTERS = true; -static const uint64_t DEFAULT_GAS_LIMIT=100000; +static const uint64_t DEFAULT_GAS_LIMIT=10000; static const CAmount DEFAULT_GAS_PRICE=0.00001*COIN; struct BlockHasher diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a1b409705f4a4..63f0913ffaa18 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -436,16 +436,17 @@ UniValue createcontract(const JSONRPCRequest& request){ if (!EnsureWalletIsAvailable(request.fHelp)) return NullUniValue; - if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) + if (request.fHelp || request.params.size() < 1 || request.params.size() > 5) throw runtime_error( - "createcontract \"senderaddress\" \"bytecode\" (gaslimit gasprice)" + "createcontract \"bytecode\" (gaslimit gasprice \"senderaddress\" broadcast)" "\nCreate a contract with bytcode.\n" + HelpRequiringPassphrase() + "\nArguments:\n" - "1. \"senderaddress\" (string, required) The quantum address that will be used to create the contract.\n" - "2. \"bytecode\" (string, required) contract bytcode.\n" - "3. gasLimit (numeric or string, optional) gasLimit, default: "+i64tostr(DEFAULT_GAS_LIMIT)+"\n" - "4. gasPrice (numeric or string, optional) gasPrice QTUM price per gas unit, default: "+FormatMoney(DEFAULT_GAS_PRICE)+"\n" + "1. \"bytecode\" (string, required) contract bytcode.\n" + "2. gasLimit (numeric or string, optional) gasLimit, default: "+i64tostr(DEFAULT_GAS_LIMIT)+"\n" + "3. gasPrice (numeric or string, optional) gasPrice QTUM price per gas unit, default: "+FormatMoney(DEFAULT_GAS_PRICE)+"\n" + "4. \"senderaddress\" (string, optional) The quantum address that will be used to create the contract.\n" + "5. \"broadcast\" (bool, optional, default=true) Whether to broadcast the transaction or not.\n" "\nResult:\n" "[\n" " {\n" @@ -456,39 +457,51 @@ UniValue createcontract(const JSONRPCRequest& request){ " }\n" "]\n" "\nExamples:\n" - + HelpExampleCli("createcontract", "\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256\"") - + HelpExampleCli("createcontract", "\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256\" 6000000 0.00000001") + + HelpExampleCli("createcontract", "\"60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256\"") + + HelpExampleCli("createcontract", "\"60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256\" 6000000 0.00000001 \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" true") ); LOCK2(cs_main, pwalletMain->cs_wallet); - CBitcoinAddress senderAddress(request.params[0].get_str()); - if (!senderAddress.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address to send from"); - - string bytecode=request.params[1].get_str(); + string bytecode=request.params[0].get_str(); uint64_t nGasLimit=DEFAULT_GAS_LIMIT; - if (request.params.size() > 2){ - nGasLimit = request.params[2].get_int64(); + if (request.params.size() > 1){ + nGasLimit = request.params[1].get_int64(); if (nGasLimit <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasLimit"); } CAmount nGasPrice = DEFAULT_GAS_PRICE; - if (request.params.size() > 3){ - nGasPrice = request.params[3].get_real()*COIN; + if (request.params.size() > 2){ + nGasPrice = request.params[2].get_real()*COIN; if (nGasPrice <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasPrice"); } - + bool fHasSender=false; + CBitcoinAddress senderAddress; + if (request.params.size() > 3){ + senderAddress.SetString(request.params[3].get_str()); + if (!senderAddress.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Qtum address to send from"); + else + fHasSender=true; + } + + bool fBroadcast=true; + if (request.params.size() > 4){ + fBroadcast=request.params[4].get_bool(); + } + + CCoinControl coinControl; + if(fHasSender){ //find a UTXO with sender address - + UniValue results(UniValue::VARR); vector vecOutputs; - CCoinControl coinControl; + coinControl.fAllowOtherInputs=true; assert(pwalletMain != NULL); @@ -499,7 +512,9 @@ UniValue createcontract(const JSONRPCRequest& request){ const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey; bool fValidAddress = ExtractDestination(scriptPubKey, address); - if (!(fValidAddress && senderAddress.Get() == address)) + CBitcoinAddress destAdress(address); + + if (!fValidAddress || senderAddress.Get() != destAdress.Get()) continue; coinControl.Select(COutPoint(out.tx->GetHash(),out.i)); @@ -511,7 +526,7 @@ UniValue createcontract(const JSONRPCRequest& request){ if(!coinControl.HasSelected()){ throw JSONRPCError(RPC_TYPE_ERROR, "Sender address does not have any unspent outputs"); } - + } EnsureWalletIsUnlocked(); CWalletTx wtx; @@ -541,7 +556,7 @@ UniValue createcontract(const JSONRPCRequest& request){ CRecipient recipient = {scriptPubKey, 0, false}; vecSend.push_back(recipient); - if (!pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRequired, nChangePosRet, strError, &coinControl, true, nGasFee, true)) { + if (!pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRequired, nChangePosRet, strError, &coinControl, true, nGasFee, fHasSender)) { if (nFeeRequired > pwalletMain->GetBalance()) strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); @@ -549,14 +564,17 @@ UniValue createcontract(const JSONRPCRequest& request){ CTxDestination txSenderDest; ExtractDestination(pwalletMain->mapWallet[wtx.tx->vin[0].prevout.hash].tx->vout[wtx.tx->vin[0].prevout.n].scriptPubKey,txSenderDest); - if (!(senderAddress.Get() == txSenderDest)){ - throw JSONRPCError(RPC_TYPE_ERROR, "Sender could not be set, transaction was not commited!"); - } + + if (fHasSender && !(senderAddress.Get() == txSenderDest)){ + throw JSONRPCError(RPC_TYPE_ERROR, "Sender could not be set, transaction was not committed!"); + } + + UniValue result(UniValue::VOBJ); + if(fBroadcast){ CValidationState state; if (!pwalletMain->CommitTransaction(wtx, reservekey, g_connman.get(), state)) throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here."); - UniValue result(UniValue::VOBJ); std::string txId=wtx.GetHash().GetHex(); result.push_back(Pair("txid", txId)); @@ -580,7 +598,10 @@ UniValue createcontract(const JSONRPCRequest& request){ CSHA256().Write(txIdAndVout.data(), txIdAndVout.size()).Finalize(SHA256TxVout.data()); CRIPEMD160().Write(SHA256TxVout.data(), SHA256TxVout.size()).Finalize(contractAddress.data()); result.push_back(Pair("address", HexStr(contractAddress))); - + }else{ + string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags()); + result.push_back(Pair("raw transaction", strHex)); + } return result; } UniValue listaddressgroupings(const JSONRPCRequest& request) @@ -1943,7 +1964,7 @@ UniValue gettransaction(const JSONRPCRequest& request) " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n" " 'send' category of transactions.\n" " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n" - " 'send' category of transactions.\n" + " 'send' category of transactions.\n" " }\n" " ,...\n" " ],\n" @@ -3195,7 +3216,7 @@ static const CRPCCommand commands[] = { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, {"oldpassphrase","newpassphrase"} }, { "wallet", "walletpassphrase", &walletpassphrase, true, {"passphrase","timeout"} }, { "wallet", "removeprunedfunds", &removeprunedfunds, true, {"txid"} }, - { "wallet", "createcontract", &createcontract, false, {"gas-price", "gas-limit", "bytecode", "sender-address", "txfee", "broadcast"} }, + { "wallet", "createcontract", &createcontract, false, {"bytecode", "gasLimit", "gasPrice", "senderAddress", "broadcast"} }, }; void RegisterWalletRPCCommands(CRPCTable &t)