static bool Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err) { // Create dummy to/from transactions: CMutableTransaction txFrom; txFrom.vout.resize(1); txFrom.vout[0].scriptPubKey = scriptPubKey; CMutableTransaction txTo; txTo.vin.resize(1); txTo.vout.resize(1); txTo.vin[0].prevout.n = 0; txTo.vin[0].prevout.hash = txFrom.GetHash(); txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err); }
/** * Builds a creationTx from scriptPubKey and a spendingTx from scriptSig * and witness such that spendingTx spends output zero of creationTx. * Also inserts creationTx's output into the coins view. */ void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CTxInWitness& witness) { creationTx.nVersion = 1; creationTx.vin.resize(1); creationTx.vin[0].prevout.SetNull(); creationTx.vin[0].scriptSig = CScript(); creationTx.wit.vtxinwit.resize(1); creationTx.vout.resize(1); creationTx.vout[0].nValue = 1; creationTx.vout[0].scriptPubKey = scriptPubKey; spendingTx.nVersion = 1; spendingTx.vin.resize(1); spendingTx.vin[0].prevout.hash = creationTx.GetHash(); spendingTx.vin[0].prevout.n = 0; spendingTx.vin[0].scriptSig = scriptSig; spendingTx.wit.vtxinwit.resize(1); spendingTx.wit.vtxinwit[0] = witness; spendingTx.vout.resize(1); spendingTx.vout[0].nValue = 1; spendingTx.vout[0].scriptPubKey = CScript(); coins.ModifyCoins(creationTx.GetHash())->FromTx(creationTx, 0); }
// FIXME: Dedup with BuildSpendingTransaction in test/script_tests.cpp. static CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit) { CMutableTransaction txSpend; txSpend.nVersion = 1; txSpend.nLockTime = 0; txSpend.vin.resize(1); txSpend.vout.resize(1); txSpend.vin[0].prevout.hash = txCredit.GetHash(); txSpend.vin[0].prevout.n = 0; txSpend.vin[0].scriptSig = scriptSig; txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txSpend.vout[0].scriptPubKey = CScript(); txSpend.vout[0].nValue = txCredit.vout[0].nValue; return txSpend; }
CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit) { CMutableTransaction txSpend; txSpend.nVersion = 1; txSpend.nLockTime = 0; txSpend.vin.resize(1); txSpend.vout.resize(1); txSpend.vin[0].prevout.hash = txCredit.GetHash(); txSpend.vin[0].prevout.n = 0; txSpend.vin[0].scriptSig = scriptSig; txSpend.vin[0].nSequence = std::numeric_limits<unsigned int>::max(); txSpend.vout[0].scriptPubKey = CScript(); txSpend.vout[0].nValue = 0; return txSpend; }
/** * Implement the rawtx name operation feature. This routine interprets * the given JSON object describing the desired name operation and then * modifies the transaction accordingly. * @param tx The transaction to extend. * @param obj The name operation "description" as given to the call. */ void AddRawTxNameOperation (CMutableTransaction& tx, const UniValue& obj) { UniValue val = find_value (obj, "op"); if (!val.isStr ()) throw JSONRPCError (RPC_INVALID_PARAMETER, "missing op key"); const std::string op = val.get_str (); if (op != "name_update") throw JSONRPCError (RPC_INVALID_PARAMETER, "only name_update is implemented for the rawtx API"); val = find_value (obj, "name"); if (!val.isStr ()) throw JSONRPCError (RPC_INVALID_PARAMETER, "missing name key"); const valtype name = ValtypeFromString (val.get_str ()); val = find_value (obj, "value"); if (!val.isStr ()) throw JSONRPCError (RPC_INVALID_PARAMETER, "missing value key"); const valtype value = ValtypeFromString (val.get_str ()); val = find_value (obj, "address"); if (!val.isStr ()) throw JSONRPCError (RPC_INVALID_PARAMETER, "missing address key"); const CBitcoinAddress toAddress(val.get_str ()); if (!toAddress.IsValid ()) throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, "invalid address"); const CScript addr = GetScriptForDestination (toAddress.Get ()); tx.SetNamecoin (); /* We do not add the name input. This has to be done explicitly, but is easy from the name_show output. That way, createrawtransaction doesn't depend on the chainstate at all. */ const CScript outScript = CNameScript::buildNameUpdate (addr, name, value); tx.vout.push_back (CTxOut (NAME_LOCKED_AMOUNT, outScript)); }
/*** *private helper functions */ QString MultisigDialog::buildMultisigTxStatusString(bool fComplete, const CMutableTransaction& tx) { string sTxHex = EncodeHexTx(tx); if(fComplete){ ui->commitButton->setEnabled(true); string sTxId = tx.GetHash().GetHex(); string sTxComplete = "Complete: true!\n" "The commit button has now been enabled for you to finalize the transaction.\n" "Once the commit button is clicked, the transaction will be published and coins transferred " "to their destinations.\nWARNING: THE ACTIONS OF THE COMMIT BUTTON ARE FINAL AND CANNOT BE REVERSED."; return QString(strprintf("%s\nTx Id:\n%s\nTx Hex:\n%s",sTxComplete, sTxId, sTxHex).c_str()); } else { string sTxIncomplete = "Complete: false.\n" "You may now send the hex below to another owner to sign.\n" "Keep in mind the transaction must be passed from one owner to the next for signing.\n" "Ensure all owners have imported the redeem before trying to sign. (besides creator)"; return QString(strprintf("%s\nTx Hex: %s", sTxIncomplete, sTxHex).c_str()); } }
/** * Builds a creationTx from scriptPubKey and a spendingTx from scriptSig * and witness such that spendingTx spends output zero of creationTx. * Also inserts creationTx's output into the coins view. */ static void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& witness) { creationTx.nVersion = 1; creationTx.vin.resize(1); creationTx.vin[0].prevout.SetNull(); creationTx.vin[0].scriptSig = CScript(); creationTx.vout.resize(1); creationTx.vout[0].nValue = 1; creationTx.vout[0].scriptPubKey = scriptPubKey; spendingTx.nVersion = 1; spendingTx.vin.resize(1); spendingTx.vin[0].prevout.hash = creationTx.GetHash(); spendingTx.vin[0].prevout.n = 0; spendingTx.vin[0].scriptSig = scriptSig; spendingTx.vin[0].scriptWitness = witness; spendingTx.vout.resize(1); spendingTx.vout[0].nValue = 1; spendingTx.vout[0].scriptPubKey = CScript(); AddCoins(coins, creationTx, 0); }
// Test suite for ancestor feerate transaction selection. // Implemented as an additional function, rather than a separate test case, // to allow reusing the blockchain created in CreateNewBlock_validity. // Note that this test assumes blockprioritysize is 0. void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransaction *>& txFirst) { // Test the ancestor feerate transaction selection. TestMemPoolEntryHelper entry; // Test that a medium fee transaction will be selected after a higher fee // rate package with a low fee rate parent. CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].scriptSig = CScript() << OP_1; tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.n = 0; tx.vout.resize(1); tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use mempool.addUnchecked(hashParentTx, entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); mempool.addUnchecked(hashMediumFeeTx, entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a high fee, but depends on the first transaction tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee uint256 hashHighFeeTx = tx.GetHash(); mempool.addUnchecked(hashHighFeeTx, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); CBlockTemplate *pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[1].GetHash() == hashParentTx); BOOST_CHECK(pblocktemplate->block.vtx[2].GetHash() == hashHighFeeTx); BOOST_CHECK(pblocktemplate->block.vtx[3].GetHash() == hashMediumFeeTx); // Test that a package below the min relay fee doesn't get included tx.vin[0].prevout.hash = hashHighFeeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee uint256 hashFreeTx = tx.GetHash(); mempool.addUnchecked(hashFreeTx, entry.Fee(0).FromTx(tx)); size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); // Calculate a fee on child transaction that will put the package just // below the min relay fee (assuming 1 child tx of the same size). CAmount feeToUse = minRelayTxFee.GetFee(2*freeTxSize) - 1; tx.vin[0].prevout.hash = hashFreeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; uint256 hashLowFeeTx = tx.GetHash(); mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx)); pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashLowFeeTx); } // Test that packages above the min relay fee do get included, even if one // of the transactions is below the min relay fee // Remove the low fee transaction and replace with a higher fee transaction std::list<CTransaction> dummy; mempool.removeRecursive(tx, dummy); tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee hashLowFeeTx = tx.GetHash(); mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse+2).FromTx(tx)); pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[4].GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5].GetHash() == hashLowFeeTx); // Test that transaction selection properly updates ancestor fee // calculations as ancestor transactions get included in a block. // Add a 0-fee transaction that has 2 outputs. tx.vin[0].prevout.hash = txFirst[2]->GetHash(); tx.vout.resize(2); tx.vout[0].nValue = 5000000000LL - 100000000; tx.vout[1].nValue = 100000000; // 1BTC output uint256 hashFreeTx2 = tx.GetHash(); mempool.addUnchecked(hashFreeTx2, entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); // This tx can't be mined by itself tx.vin[0].prevout.hash = hashFreeTx2; tx.vout.resize(1); feeToUse = minRelayTxFee.GetFee(freeTxSize); tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; uint256 hashLowFeeTx2 = tx.GetHash(); mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashFreeTx2); BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashLowFeeTx2); } // This tx will be mineable, and should cause hashLowFeeTx2 to be selected // as well. tx.vin[0].prevout.n = 1; tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx)); pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[8].GetHash() == hashLowFeeTx2); }
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,const int nHeightIn) { // Create new block auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); if(!pblocktemplate.get()) return NULL; CBlock *pblock = &pblocktemplate->block; // pointer for convenience CBlockIndex* pindexPrev; if(nHeightIn<=0) { pindexPrev = chainActive.Tip(); } else pindexPrev = chainActive[nHeightIn-1]; int nHeight = pindexPrev->nBlockHeight + 1; pblock->nBlockHeight=nHeight; UpdateTime(pblock, pindexPrev); // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (Params().MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); // Create coinbase tx CMutableTransaction txNew; txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); txNew.vin[0].prevout.n=nHeight; txNew.vin[0].scriptSig=CScript()<<0; txNew.vout.resize(1); txNew.vout[0].scriptPubKey = scriptPubKeyIn; txNew.vout[0].nLockTime=nHeight +COINBASE_MATURITY; // Add dummy coinbase tx as first transaction pblock->vtx.push_back(CTransaction()); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); // Minimum block size you want to create; block will be filled with free transactions // until there are no more or the block reaches this size: unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); //min tx size to judge finish of block.set this a little bit higher so as to make mining faster unsigned int nMinTxSize=200; // Collect memory pool transactions into the block CAmount nFees = 0; uint64_t nBlockSize = 1000; uint64_t nBlockTx = 0; int nBlockSigOps = 100; { LOCK2(cs_main, mempool.cs); if(nHeightIn<=0) { CCoinsViewCache view(pcoinsTip); // Priority order to process transactions list<COrphan> vOrphan; // list memory doesn't move map<uint256, vector<COrphan*> > mapDependers; // Collect transactions into block for (int i=0;i<(int)mempool.queue.size();i++) { const CTransaction& tx = mempool.mapTx[mempool.queue[i]].GetTx(); if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight)) continue; COrphan* porphan = NULL; CAmount nTotalIn = 0; bool fMissingInputs = false; BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Read prev transaction if (!view.HaveCoins(txin.prevout.hash)) { //don't take in transactions with prevout in mempool,because txs are queued by fee, not sequence, we can't guarantee it's //previous tx can be included in this block fMissingInputs = true; break; // This should never happen; all transactions in the memory // pool should connect to either transactions in the chain // or other transactions in the memory pool. if (!mempool.mapTx.count(txin.prevout.hash)) { LogPrintf("ERROR: mempool transaction missing input\n"); if (fDebug) assert("mempool transaction missing input" == 0); fMissingInputs = true; if (porphan) vOrphan.pop_back(); break; } // Has to wait for dependencies if (!porphan) { // Use list for automatic deletion vOrphan.push_back(COrphan(&tx)); porphan = &vOrphan.back(); } mapDependers[txin.prevout.hash].push_back(porphan); porphan->setDependsOn.insert(txin.prevout.hash); nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue; continue; } const CCoins* coins = view.AccessCoins(txin.prevout.hash); assert(coins); if ((int64_t)coins->vout[txin.prevout.n].nLockTime >= ((int64_t)coins->vout[txin.prevout.n].nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nHeight : std::min((int64_t)pindexPrev->nTime,std::max((int64_t)pindexPrev->GetMedianTimePast()+1, (int64_t)GetAdjustedTime())))) fMissingInputs = true; CAmount nValueIn = coins->vout[txin.prevout.n].nValue; nTotalIn += nValueIn; } if (fMissingInputs) continue; // Size limits unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); if (nBlockSize + nTxSize >= nBlockMaxSize) continue; // Legacy limits on sigOps: unsigned int nTxSigOps = GetLegacySigOpCount(tx); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; if (!view.HaveInputs(tx)) continue; CAmount nTxFees = tx.GetFee(); nTxSigOps += GetP2SHSigOpCount(tx, view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; // Note that flags: we don't want to set mempool/IsStandard() // policy here, but we still have to ensure that the block we // create only contains transactions that are valid in new blocks. CValidationState state; if (!CheckInputs(tx, tx,state, view, pblock,true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) continue; CTxUndo txundo; UpdateCoins(tx, state, view, txundo, nHeight); // Added pblock->vtx.push_back(tx); pblocktemplate->vTxFees.push_back(nTxFees); pblocktemplate->vTxSigOps.push_back(nTxSigOps); nBlockSize += nTxSize; ++nBlockTx; nBlockSigOps += nTxSigOps; nFees += nTxFees; if (nBlockSize+nMinTxSize>nBlockMaxSize) break; } } CBlock prevBlock; ReadBlockFromDisk(prevBlock, pindexPrev); CAmount prevCoinbaseFee=prevBlock.vtx[0].GetFee(); nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; // Compute final coinbase transaction. CAmount coinbaseInput=GetBlockValue(nHeight, nFees)+prevCoinbaseFee; txNew.vin[0].prevout.nValue = coinbaseInput; txNew.vout[0].nValue = 0; CAmount coinbaseFee=CFeeRate(DEFAULT_TRANSACTION_FEE).GetFee(txNew.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)+10); CAmount coinbaseOutput=coinbaseInput-coinbaseFee; if(nHeightIn<=0&&coinbaseOutput<=minRelayTxFee.GetFee(DUST_THRESHOLD)) return NULL; txNew.vout[0].nValue =coinbaseOutput; pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; if (nHeightIn<=0&&!TestBlockValidity(state, *pblock, pindexPrev, false, false)) { LogPrintf("CreateNewBlock() : TestBlockValidity failed \n" ); return NULL; } }
void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet, std::vector<CTxOut>& voutSuperblockRet) { // only create superblocks if spork is enabled AND if superblock is actually triggered // (height should be validated inside) if(sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED) && CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) { LogPrint("gobject", "FillBlockPayments -- triggered superblock creation at height %d\n", nBlockHeight); CSuperblockManager::CreateSuperblock(txNew, nBlockHeight, voutSuperblockRet); return; } // FILL BLOCK PAYEE WITH MASTERNODE PAYMENT OTHERWISE mnpayments.FillBlockPayee(txNew, nBlockHeight, blockReward, txoutMasternodeRet); LogPrint("mnpayments", "FillBlockPayments -- nBlockHeight %d blockReward %lld txoutMasternodeRet %s txNew %s", nBlockHeight, blockReward, txoutMasternodeRet.ToString(), txNew.ToString()); }
bool MultisigDialog::createMultisigTransaction(vector<CTxIn> vUserIn, vector<CTxOut> vUserOut, string& feeStringRet, string& errorRet) { try{ //attempt to access the given inputs CCoinsViewCache view = getInputsCoinsViewCache(vUserIn); //retrieve total input val and change dest CAmount totalIn = 0; vector<CAmount> vInputVals; CScript changePubKey; bool fFirst = true; for(CTxIn in : vUserIn){ const CCoins* coins = view.AccessCoins(in.prevout.hash); if(!coins->IsAvailable(in.prevout.n) || coins == NULL){ continue; } CTxOut prevout = coins->vout[in.prevout.n]; CScript privKey = prevout.scriptPubKey; vInputVals.push_back(prevout.nValue); totalIn += prevout.nValue; if(!fFirst){ if(privKey != changePubKey){ throw runtime_error("Address mismatch! Inputs must originate from the same multisignature address."); } }else{ fFirst = false; changePubKey = privKey; } } CAmount totalOut = 0; //retrieve total output val for(CTxOut out : vUserOut){ totalOut += out.nValue; } if(totalIn < totalOut){ throw runtime_error("Not enough PIV provided as input to complete transaction (including fee)."); } //calculate change amount CAmount changeAmount = totalIn - totalOut; CTxOut change(changeAmount, changePubKey); //generate random position for change unsigned int changeIndex = rand() % (vUserOut.size() + 1); //insert change into random position if(changeIndex < vUserOut.size()){ vUserOut.insert(vUserOut.begin() + changeIndex, change); }else{ vUserOut.emplace_back(change); } //populate tx CMutableTransaction tx; tx.vin = vUserIn; tx.vout = vUserOut; const CCoins* coins = view.AccessCoins(tx.vin[0].prevout.hash); if(coins == NULL || !coins->IsAvailable(tx.vin[0].prevout.n)){ throw runtime_error("Coins unavailable (unconfirmed/spent)"); } CScript prevPubKey = coins->vout[tx.vin[0].prevout.n].scriptPubKey; //get payment destination CTxDestination address; if(!ExtractDestination(prevPubKey, address)){ throw runtime_error("Could not find address for destination."); } CScriptID hash = boost::get<CScriptID>(address); CScript redeemScript; if (!pwalletMain->GetCScript(hash, redeemScript)){ throw runtime_error("could not redeem"); } txnouttype type; vector<CTxDestination> addresses; int nReq; if(!ExtractDestinations(redeemScript, type, addresses, nReq)){ throw runtime_error("Could not extract destinations from redeem script."); } for(CTxIn& in : tx.vin){ in.scriptSig.clear(); //scale estimate to account for multisig scriptSig for(unsigned int i = 0; i < 50*(nReq+addresses.size()); i++){ in.scriptSig << INT64_MAX; } } //calculate fee unsigned int nBytes = tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION); CAmount fee = ::minRelayTxFee.GetFee(nBytes); if(tx.vout.at(changeIndex).nValue > fee){ tx.vout.at(changeIndex).nValue -= fee; feeStringRet = strprintf("%d",((double)fee)/COIN).c_str(); }else{ throw runtime_error("Not enough PIV provided to cover fee"); } //clear junk from script sigs for(CTxIn& in : tx.vin){ in.scriptSig.clear(); } multisigTx = tx; }catch(const runtime_error& e){ errorRet = e.what(); return false; } return true; }
{ LOCK(mempool.cs); return CheckSequenceLocks(tx, flags); } // Test suite for ancestor feerate transaction selection. // Implemented as an additional function, rather than a separate test case, // to allow reusing the blockchain created in CreateNewBlock_validity. static void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::mempool.cs) { // Test the ancestor feerate transaction selection. TestMemPoolEntryHelper entry; // Test that a medium fee transaction will be selected after a higher fee // rate package with a low fee rate parent. CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].scriptSig = CScript() << OP_1; tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.n = 0; tx.vout.resize(1); tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
bool CreateGameTransactions (const CCoinsView& view, unsigned nHeight, const StepResult& stepResult, std::vector<CTransaction>& vGameTx) { vGameTx.clear (); /* Destroy name-coins of killed players. */ bool haveTxKills = false; CMutableTransaction txKills; txKills.SetGameTx (); const PlayerSet& killedPlayers = stepResult.GetKilledPlayers (); const KilledByMap& killedBy = stepResult.GetKilledBy (); txKills.vin.reserve (killedPlayers.size ()); BOOST_FOREACH(const PlayerID &victim, killedPlayers) { const valtype vchName = ValtypeFromString (victim); CNameData data; if (!view.GetName (vchName, data)) return error ("Game engine killed a non-existing player %s", victim.c_str ()); CTxIn txin(data.getUpdateOutpoint ()); /* List all killers, if player was simultaneously killed by several other players. If the reason was not KILLED_DESTRUCT, handle it also. If multiple reasons apply, the game tx is constructed for the first reason according to the ordering inside of KilledByMap. (Which in turn is determined by the enum values for KILLED_*.) */ typedef KilledByMap::const_iterator Iter; const std::pair<Iter, Iter> iters = killedBy.equal_range (victim); if (iters.first == iters.second) return error ("No reason for killed player %s", victim.c_str ()); const KilledByInfo::Reason reason = iters.first->second.reason; /* Unless we have destruct, there should be exactly one entry with the "first" reason. There may be multiple entries for different reasons, for instance, killed by poison and staying in spawn area at the same time. */ { Iter it = iters.first; ++it; if (reason != KilledByInfo::KILLED_DESTRUCT && it != iters.second && reason == it->second.reason) return error ("Multiple same-reason, non-destruct killed-by" " entries for %s", victim.c_str ()); } switch (reason) { case KilledByInfo::KILLED_DESTRUCT: txin.scriptSig << vchName << GAMEOP_KILLED_BY; for (Iter it = iters.first; it != iters.second; ++it) { if (it->second.reason != KilledByInfo::KILLED_DESTRUCT) { assert (it != iters.first); break; } txin.scriptSig << ValtypeFromString (it->second.killer.ToString ()); } break; case KilledByInfo::KILLED_SPAWN: txin.scriptSig << vchName << GAMEOP_KILLED_BY; break; case KilledByInfo::KILLED_POISON: txin.scriptSig << vchName << GAMEOP_KILLED_POISON; break; default: assert (false); } txKills.vin.push_back (txin); haveTxKills = true; } if (haveTxKills) { const CTransaction tx(txKills); assert (tx.IsGameTx () && !tx.IsBountyTx ()); vGameTx.push_back (tx); } /* Pay bounties to the players who collected them. The transaction inputs are just "dummy" containing informational messages. */ bool haveTxBounties = false; CMutableTransaction txBounties; txBounties.SetGameTx (); txBounties.vin.reserve (stepResult.bounties.size ()); txBounties.vout.reserve (stepResult.bounties.size ()); BOOST_FOREACH(const CollectedBounty& bounty, stepResult.bounties) { const valtype vchName = ValtypeFromString (bounty.character.player); CNameData data; if (!view.GetName (vchName, data)) return error ("Game engine created bounty for non-existing player"); CTxOut txout; txout.nValue = bounty.loot.nAmount; if (!bounty.address.empty ()) { /* Player-provided addresses are validated before accepting them, so failing here is ok. */ CBitcoinAddress addr(bounty.address); if (!addr.IsValid ()) return error ("Failed to set player-provided address for bounty"); txout.scriptPubKey = GetScriptForDestination (addr.Get ()); } else txout.scriptPubKey = data.getAddress (); txBounties.vout.push_back (txout); CTxIn txin; if (bounty.loot.IsRefund ()) txin.scriptSig << vchName << GAMEOP_REFUND << bounty.character.index << bounty.loot.GetRefundHeight (); else txin.scriptSig << vchName << GAMEOP_COLLECTED_BOUNTY << bounty.character.index << bounty.loot.firstBlock << bounty.loot.lastBlock << bounty.loot.collectedFirstBlock << bounty.loot.collectedLastBlock; txBounties.vin.push_back (txin); haveTxBounties = true; } if (haveTxBounties) { const CTransaction tx(txBounties); assert (tx.IsGameTx () && tx.IsBountyTx ()); vGameTx.push_back (tx); } /* Print log chatter. */ if (haveTxKills || haveTxBounties) { LogPrint ("game", "Game transactions @%d:\n", nHeight); if (haveTxKills) LogPrint ("game", " kills: %s\n", txKills.GetHash ().ToString ()); if (haveTxBounties) LogPrint ("game", " bounties: %s\n", txBounties.GetHash ().ToString ()); } return true; }