Refactors in anticipation of blinded values

This commit is contained in:
Luke Dashjr 2016-02-15 15:19:28 -08:00 committed by Gregory Sanders
parent 743081a205
commit b5f1b6dd38
34 changed files with 262 additions and 133 deletions

View file

@ -292,10 +292,12 @@ libbitcoin_consensus_a_SOURCES = \
script/script_error.cpp \
script/script_error.h \
support/events.cpp \
script/sign.cpp \
serialize.h \
tinyformat.h \
uint256.cpp \
uint256.h \
utilmoneystr.cpp \
utilstrencodings.cpp \
utilstrencodings.h \
version.h

View file

@ -89,11 +89,17 @@ static void VerifyScriptBench(benchmark::State& state)
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << txSpend;
CDataStream streamVal1(SER_NETWORK, PROTOCOL_VERSION);
streamVal1 << txCredit.vout[0].nValue;
CDataStream streamVal2(SER_NETWORK, PROTOCOL_VERSION);
streamVal2 << CTxOutValue(0);
int csuccess = bitcoinconsensus_verify_script_with_amount(
txCredit.vout[0].scriptPubKey.data(),
txCredit.vout[0].scriptPubKey.size(),
txCredit.vout[0].nValue,
-1,
(const unsigned char*)&streamVal1[0],
streamVal1.size(),
(const unsigned char*)&streamVal2[0],
streamVal2.size(),
(const unsigned char*)stream.data(), stream.size(), 0, flags, nullptr);
assert(csuccess == 1);
#endif

View file

@ -617,7 +617,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
continue;
}
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
const CTxOutValue& amount = coins->vout[txin.prevout.n].nValue;
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:

View file

@ -332,8 +332,11 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
return 0;
CAmount nResult = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
nResult += GetOutputFor(tx.vin[i]).nValue;
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxOutValue& val = GetOutputFor(tx.vin[i]).nValue;
assert(val.IsAmount());
nResult += val.GetAmount();
}
return nResult;
}
@ -345,8 +348,9 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces
CAmount nInAmount = GetValueIn(tx);
for (std::vector<CTxOut>::const_iterator it(tx.vout.begin()); it != tx.vout.end(); ++it)
{
nInAmount -= it->nValue;
if (!MoneyRange(it->nValue) || (!MoneyRange(nInAmount) && !MoneyRange(-nInAmount)))
assert(it->nValue.IsAmount());
nInAmount -= it->nValue.GetAmount();;
if (!MoneyRange(it->nValue.GetAmount()) || (!MoneyRange(nInAmount) && !MoneyRange(-nInAmount)))
return false;
}
return excess == nInAmount;
@ -378,8 +382,12 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount
assert(coins);
if (!coins->IsAvailable(txin.prevout.n)) continue;
if (coins->nHeight <= nHeight) {
dResult += (double)(coins->vout[txin.prevout.n].nValue) * (nHeight-coins->nHeight);
inChainInputValue += coins->vout[txin.prevout.n].nValue;
const CTxOutValue& val = coins->vout[txin.prevout.n].nValue;
CAmount nAmount = COIN;
if (val.IsAmount())
nAmount = val.GetAmount();
dResult += nAmount * (nHeight-coins->nHeight);
inChainInputValue += nAmount;
}
}
return tx.ComputePriority(dResult);

View file

@ -106,7 +106,8 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
if (!ser_action.ForRead()) {
uint64_t nVal = CompressAmount(txout.nValue);
assert(txout.nValue.IsAmount());
uint64_t nVal = CompressAmount(txout.nValue.GetAmount());
READWRITE(VARINT(nVal));
} else {
uint64_t nVal = 0;

View file

@ -192,8 +192,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
UniValue out(UniValue::VOBJ);
UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue));
out.pushKV("value", outValue);
if (txout.nValue.IsAmount()) {
UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue.GetAmount()));
out.pushKV("value", outValue);
}
out.pushKV("n", (int64_t)i);
UniValue o(UniValue::VOBJ);

View file

@ -43,7 +43,48 @@ std::string CTxIn::ToString() const
return str;
}
CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
CTxOutValue::CTxOutValue()
: nAmount(-1)
{
}
CTxOutValue::CTxOutValue(CAmount nAmountIn)
: nAmount(nAmountIn)
{
}
bool CTxOutValue::IsValid() const
{
return MoneyRange(nAmount);
}
bool CTxOutValue::IsNull() const
{
return nAmount == -1;
}
bool CTxOutValue::IsAmount() const
{
return nAmount != -1;
}
CAmount CTxOutValue::GetAmount() const
{
assert(IsAmount());
return nAmount;
}
bool operator==(const CTxOutValue& a, const CTxOutValue& b)
{
return a.nAmount == b.nAmount;
}
bool operator!=(const CTxOutValue& a, const CTxOutValue& b) {
return !(a == b);
}
CTxOut::CTxOut(const CTxOutValue& nValueIn, CScript scriptPubKeyIn)
{
nValue = nValueIn;
scriptPubKey = scriptPubKeyIn;
@ -51,7 +92,7 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
std::string CTxOut::ToString() const
{
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", (nValue.IsAmount() ? strprintf("%d.%08d", nValue.GetAmount() / COIN, nValue.GetAmount() % COIN) : std::string("UNKNOWN")), HexStr(scriptPubKey).substr(0, 30));
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTxFee(0), vin(), vout(), nLockTime(0) {}

View file

@ -127,13 +127,38 @@ public:
std::string ToString() const;
};
class CTxOutValue
{
CAmount nAmount;
public:
CTxOutValue();
CTxOutValue(CAmount);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nAmount);
}
bool IsValid() const;
bool IsNull() const;
bool IsAmount() const;
CAmount GetAmount() const;
friend bool operator==(const CTxOutValue& a, const CTxOutValue& b);
friend bool operator!=(const CTxOutValue& a, const CTxOutValue& b);
};
/** An output of a transaction. It contains the public key that the next input
* must be able to sign with to claim it.
*/
class CTxOut
{
public:
CAmount nValue;
CTxOutValue nValue;
CScript scriptPubKey;
CTxOut()
@ -141,7 +166,7 @@ public:
SetNull();
}
CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
CTxOut(const CTxOutValue& nValueIn, CScript scriptPubKeyIn);
ADD_SERIALIZE_METHODS;
@ -196,7 +221,9 @@ public:
bool IsDust(const CFeeRate &minRelayTxFee) const
{
return (nValue < GetDustThreshold(minRelayTxFee));
if (!nValue.IsAmount())
return false; // FIXME
return (nValue.GetAmount() < GetDustThreshold(minRelayTxFee));
}
friend bool operator==(const CTxOut& a, const CTxOut& b)

View file

@ -471,10 +471,10 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nQuantity++;
// Amount
nAmount += out.tx->tx->vout[out.i].nValue;
nAmount += out.tx->tx->vout[out.i].nValue.GetAmount();
// Priority
dPriorityInputs += (double)out.tx->tx->vout[out.i].nValue * (out.nDepth+1);
dPriorityInputs += (double)out.tx->tx->vout[out.i].nValue.GetAmount() * (out.nDepth+1);
// Bytes
CTxDestination address;
@ -676,7 +676,7 @@ void CoinControlDialog::updateView()
CAmount nSum = 0;
int nChildren = 0;
BOOST_FOREACH(const COutput& out, coins.second) {
nSum += out.tx->tx->vout[out.i].nValue;
nSum += out.tx->tx->vout[out.i].nValue.GetAmount();
nChildren++;
CCoinControlWidgetItem *itemOutput;
@ -713,8 +713,8 @@ void CoinControlDialog::updateView()
}
// amount
itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->tx->vout[out.i].nValue));
itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->tx->vout[out.i].nValue)); // padding so that sorting works correctly
itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->tx->vout[out.i].nValue.GetAmount()));
itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->tx->vout[out.i].nValue.GetAmount())); // padding so that sorting works correctly
// date
itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));

View file

@ -198,9 +198,9 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
}
}
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "<br>";
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue.GetAmount()) + "<br>";
if(toSelf)
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "<br>";
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue.GetAmount()) + "<br>";
}
if (fAllToMe)
@ -307,7 +307,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
}
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue.GetAmount());
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
strHTML = strHTML + " IsWatchOnly=" + (wallet->IsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>";
}

View file

@ -56,7 +56,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
TransactionRecord sub(hash, nTime);
CTxDestination address;
sub.idx = i; // vout index
sub.credit = txout.nValue;
sub.credit = txout.nValue.GetAmount();
sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
{
@ -143,7 +143,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
sub.address = mapValue["to"];
}
CAmount nValue = txout.nValue;
CAmount nValue = txout.nValue.GetAmount();
/* Add fee to first output */
if (nTxFee > 0)
{

View file

@ -67,7 +67,7 @@ CAmount WalletModel::getBalance(const CCoinControl *coinControl) const
wallet->AvailableCoins(vCoins, true, coinControl);
BOOST_FOREACH(const COutput& out, vCoins)
if(out.fSpendable)
nBalance += out.tx->tx->vout[out.i].nValue;
nBalance = out.tx->tx->vout[out.i].nValue.GetAmount();
return nBalance;
}

View file

@ -64,7 +64,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
if (out.amount() <= 0) continue;
if (i == nChangePosRet)
i++;
subtotal += walletTransaction->tx->vout[i].nValue;
subtotal += walletTransaction->tx->vout[i].nValue.GetAmount();
i++;
}
rcp.amount = subtotal;
@ -73,7 +73,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
{
if (i == nChangePosRet)
i++;
rcp.amount = walletTransaction->tx->vout[i].nValue;
rcp.amount = walletTransaction->tx->vout[i].nValue.GetAmount();
i++;
}
}

View file

@ -575,7 +575,8 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
UniValue utxo(UniValue::VOBJ);
utxo.push_back(Pair("txvers", (int32_t)coin.nTxVer));
utxo.push_back(Pair("height", (int32_t)coin.nHeight));
utxo.push_back(Pair("value", ValueFromAmount(coin.out.nValue)));
if (coin.out.nValue.IsAmount())
utxo.push_back(Pair("value", ValueFromAmount(coin.out.nValue.GetAmount())));
// include the script in a json output
UniValue o(UniValue::VOBJ);

View file

@ -783,7 +783,8 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
stats.nTransactionOutputs++;
ss << VARINT(i+1);
ss << out;
nTotalAmount += out.nValue;
if (out.nValue.IsAmount())
nTotalAmount += out.nValue.GetAmount();
}
}
stats.nSerializedSize += 32 + pcursor->GetValueSize();
@ -862,7 +863,6 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
" \"txouts\": n, (numeric) The number of output transactions\n"
" \"bytes_serialized\": n, (numeric) The serialized size\n"
" \"hash_serialized\": \"hash\", (string) The serialized hash\n"
" \"total_amount\": x.xxx (numeric) The total amount\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("gettxoutsetinfo", "")
@ -880,7 +880,6 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs));
ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
} else {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
}
@ -957,7 +956,8 @@ UniValue gettxout(const JSONRPCRequest& request)
ret.push_back(Pair("confirmations", 0));
else
ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
if (coins.vout[n].nValue.IsAmount())
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue.GetAmount())));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
ret.push_back(Pair("scriptPubKey", o));

View file

@ -632,7 +632,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
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("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue.GetAmount()));
result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
result.push_back(Pair("target", GetChallengeStrHex(*pblock)));
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));

View file

@ -99,7 +99,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
for (unsigned int i = 0; i < tx.vout.size(); i++) {
const CTxOut& txout = tx.vout[i];
UniValue out(UniValue::VOBJ);
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
if (txout.nValue.IsAmount())
out.push_back(Pair("value", ValueFromAmount(txout.nValue.GetAmount())));
out.push_back(Pair("n", (int64_t)i));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
@ -839,7 +840,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
continue;
}
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
const CTxOutValue& amount = coins->vout[txin.prevout.n].nValue;
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:

View file

@ -76,8 +76,8 @@ static bool verify_flags(unsigned int flags)
return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0;
}
static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
CAmount amountPreviousInput,
static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CTxOutValue amount,
CTxOutValue amountPreviousInput,
const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
{
@ -96,7 +96,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
set_error(err, bitcoinconsensus_ERR_OK);
PrecomputedTransactionData txdata(tx);
if (amountPreviousInput < -1 || (nIn != 0 && !MoneyRange(amountPreviousInput)))
if (amountPreviousInput.IsAmount() && (amountPreviousInput.GetAmount() < -1 || (nIn != 0 && !MoneyRange(amountPreviousInput.GetAmount()))))
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionNoWithdrawsSignatureChecker(&tx, nIn, amount, txdata), NULL);
else
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, amountPreviousInput, txdata), NULL);
@ -105,14 +105,25 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
}
}
int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
int64_t amountPreviousInput,
int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
const unsigned char* amount, unsigned int amountLen,
const unsigned char* amountPreviousInput, unsigned int amountPreviousInputLen,
const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
{
CAmount am(amount);
CAmount prevInAm(amountPreviousInput);
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, prevInAm, txTo, txToLen, nIn, flags, err);
try {
TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, amount, amountLen);
CTxOutValue am;
stream >> am;
TxInputStream stream2(SER_NETWORK, PROTOCOL_VERSION, amountPreviousInput, amountPreviousInputLen);
CTxOutValue prevInAm;
stream >> prevInAm;
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, prevInAm, txTo, txToLen, nIn, flags, err);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
}
@ -124,8 +135,8 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i
return set_error(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
}
CAmount am(0);
CAmount prevInAm(-2);
CTxOutValue am(0);
CTxOutValue prevInAm(-2);
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, prevInAm, txTo, txToLen, nIn, flags, err);
}

View file

@ -72,8 +72,9 @@ EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubK
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
// Use -1 for amountPreviousInput if there is no previous input (ie nIn == 0)
EXPORT_SYMBOL int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
int64_t amountPreviousInput,
EXPORT_SYMBOL int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
const unsigned char* amount, unsigned int amountLen,
const unsigned char* amountPreviousInput, unsigned int amountPreviousInputLen,
const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);

View file

@ -1097,13 +1097,19 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
CScript relockScript = CScript() << vgenesisHash << OP_WITHDRAWPROOFVERIFY;
if (stack.size() == 1) { // increasing value of locked coins
CAmount minValue = checker.GetValueIn();
if (!checker.GetValueIn().IsAmount())
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
CAmount minValue = checker.GetValueIn().GetAmount();
CTxOut newOutput = checker.GetOutputOffsetFromCurrent(0);
if (newOutput.IsNull()) {
newOutput = checker.GetOutputOffsetFromCurrent(-1);
minValue += checker.GetValueInPrevIn();
if (!checker.GetValueInPrevIn().IsAmount())
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
minValue += checker.GetValueInPrevIn().GetAmount();
}
if (newOutput.scriptPubKey != relockScript || newOutput.nValue < minValue)
if (!newOutput.nValue.IsAmount())
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
if (newOutput.scriptPubKey != relockScript || newOutput.nValue.GetAmount() < minValue)
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT);
} else { // stack.size() >= 7...ie regular withdraw
int stackReadPos = -2;
@ -1193,16 +1199,24 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// We check values by doing the following:
// * Tx must relock at least <unlocked coins> - <locked-on-bitcoin coins>
// * Tx must send at least the withdraw value to its P2SH withdraw, but may send more
CAmount withdrawVal = locktx->vout[nlocktxOut].nValue;
CAmount lockValueRequired = checker.GetValueIn() - withdrawVal;
assert(locktx->vout[nlocktxOut].nValue.IsAmount()); // Its a SERIALIZE_BITCOIN_BLOCK_OR_TX
CAmount withdrawVal = locktx->vout[nlocktxOut].nValue.GetAmount();
if (!checker.GetValueIn().IsAmount()) // Heh, you just destroyed coins
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
CAmount lockValueRequired = checker.GetValueIn().GetAmount() - withdrawVal;
if (lockValueRequired > 0) {
const CTxOut newLockOutput = checker.GetOutputOffsetFromCurrent(1);
if (newLockOutput.IsNull() || newLockOutput.scriptPubKey != relockScript || newLockOutput.nValue < lockValueRequired)
if (!newLockOutput.nValue.IsAmount())
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
if (newLockOutput.IsNull() || newLockOutput.scriptPubKey != relockScript || newLockOutput.nValue.GetAmount() < lockValueRequired)
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT);
}
const CTxOut withdrawOutput = checker.GetOutputOffsetFromCurrent(0);
if (withdrawOutput.nValue < withdrawVal)
if (!withdrawOutput.nValue.IsAmount())
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
if (withdrawOutput.nValue.GetAmount() < withdrawVal)
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT);
CScript expectedWithdrawScriptPubKey;
@ -1379,7 +1393,7 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
hashOutputs = GetOutputsHash(txTo);
}
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CTxOutValue& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
if (sigversion == SIGVERSION_WITNESS_V0) {
uint256 hashPrevouts;
@ -1580,12 +1594,12 @@ COutPoint TransactionSignatureChecker::GetPrevOut() const
return txTo->vin[nIn].prevout;
}
CAmount TransactionSignatureChecker::GetValueIn() const
CTxOutValue TransactionSignatureChecker::GetValueIn() const
{
return amount;
}
CAmount TransactionSignatureChecker::GetValueInPrevIn() const
CTxOutValue TransactionSignatureChecker::GetValueInPrevIn() const
{
return amountPreviousInput;
}

View file

@ -132,7 +132,7 @@ enum SigVersion
SIGVERSION_WITNESS_V0 = 1,
};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CTxOutValue& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);
class BaseSignatureChecker
{
@ -150,7 +150,7 @@ public:
virtual CTxOut GetOutputOffsetFromCurrent(const int offset) const;
virtual COutPoint GetPrevOut() const;
virtual CAmount GetValueIn() const
virtual CTxOutValue GetValueIn() const
{
return -1;
}
@ -160,7 +160,7 @@ public:
return false;
}
virtual CAmount GetValueInPrevIn() const
virtual CTxOutValue GetValueInPrevIn() const
{
return -1;
}
@ -178,14 +178,14 @@ class TransactionNoWithdrawsSignatureChecker : public BaseSignatureChecker
protected:
const CTransaction* txTo;
const unsigned int nIn;
const CAmount amount;
const CTxOutValue amount;
const PrecomputedTransactionData* txdata;
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
TransactionNoWithdrawsSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
TransactionNoWithdrawsSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
TransactionNoWithdrawsSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
TransactionNoWithdrawsSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
bool CheckSequence(const CScriptNum& nSequence) const;
@ -197,21 +197,21 @@ private:
const CTransaction txTo;
public:
MutableTransactionNoWithdrawsSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionNoWithdrawsSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
MutableTransactionNoWithdrawsSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amount) : TransactionNoWithdrawsSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
};
class TransactionSignatureChecker : public TransactionNoWithdrawsSignatureChecker
{
private:
const CAmount amountPreviousInput;
const CTxOutValue amountPreviousInput;
public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const CAmount& amountPreviousInputIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn, amountIn), amountPreviousInput(amountPreviousInputIn) {}
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const CAmount& amountPreviousInputIn, const PrecomputedTransactionData& txdataIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn, amountIn, txdataIn), amountPreviousInput(amountPreviousInputIn) {}
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amountIn, const CTxOutValue& amountPreviousInputIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn, amountIn), amountPreviousInput(amountPreviousInputIn) {}
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amountIn, const CTxOutValue& amountPreviousInputIn, const PrecomputedTransactionData& txdataIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn, amountIn, txdataIn), amountPreviousInput(amountPreviousInputIn) {}
CTxOut GetOutputOffsetFromCurrent(const int offset) const;
COutPoint GetPrevOut() const;
CAmount GetValueIn() const;
CAmount GetValueInPrevIn() const;
CTxOutValue GetValueIn() const;
CTxOutValue GetValueInPrevIn() const;
bool IsConfirmedBitcoinBlock(const uint256& genesishash, const uint256& hash, bool fConservativeConfirmationRequirements) const;
};

View file

@ -97,6 +97,8 @@ const char* ScriptErrorString(const ScriptError serror)
return "Withdraw proof validation failed - output does not match expected";
case SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED:
return "Withdraw proof validation failed - lock block was not sufficiently confirmed on sending chain";
case SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS:
return "Withdraw proof validation failed - amounts in outputs were blinded";
case SCRIPT_ERR_UNKNOWN_ERROR:
case SCRIPT_ERR_ERROR_COUNT:
default: break;

View file

@ -70,6 +70,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_WITHDRAW_VERIFY_LOCKTX,
SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT,
SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED,
SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS,
SCRIPT_ERR_ERROR_COUNT
} ScriptError;

View file

@ -25,7 +25,7 @@ private:
bool store;
public:
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, const CAmount& amountPreviousInput, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, amountPreviousInput), store(storeIn) {}
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amount, const CTxOutValue& amountPreviousInput, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, amountPreviousInput), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};

View file

@ -18,7 +18,7 @@ using namespace std;
typedef std::vector<unsigned char> valtype;
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
{
@ -206,7 +206,7 @@ void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const Signatur
tx.vin[nIn].scriptWitness = data.scriptWitness;
}
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CTxOutValue& amount, int nHashType)
{
assert(nIn < txTo.vin.size());

View file

@ -35,11 +35,11 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
const CTransaction* txTo;
unsigned int nIn;
int nHashType;
CAmount amount;
CTxOutValue amount;
const TransactionNoWithdrawsSignatureChecker checker;
public:
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amountIn, int nHashTypeIn=SIGHASH_ALL);
const BaseSignatureChecker& Checker() const { return checker; }
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const;
};
@ -48,7 +48,7 @@ class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
CTransaction tx;
public:
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CTxOutValue& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
};
/** A signature creator that just produces 72-byte empty signatures. */
@ -71,7 +71,7 @@ struct SignatureData {
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
/** Produce a script signature for a transaction. */
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CTxOutValue& amount, int nHashType);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */

View file

@ -142,7 +142,7 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
// of the transactions is below the min relay fee
// Remove the low fee transaction and replace with a higher fee transaction
mempool.removeRecursive(tx);
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
tx.vout[0].nValue = CTxOutValue(tx.vout[0].nValue.GetAmount()- 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);
@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 1001; ++i)
{
tx.vout[0].nValue -= LOWFEE;
tx.vout[0].nValue = CTxOutValue(tx.vout[0].nValue.GetAmount() - LOWFEE);
hash = tx.GetHash();
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
// If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
@ -266,7 +266,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 1001; ++i)
{
tx.vout[0].nValue -= LOWFEE;
tx.vout[0].nValue = CTxOutValue(tx.vout[0].nValue.GetAmount() - LOWFEE);
hash = tx.GetHash();
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
// If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
@ -287,7 +287,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 128; ++i)
{
tx.vout[0].nValue -= LOWFEE;
tx.vout[0].nValue = CTxOutValue(tx.vout[0].nValue.GetAmount() - LOWFEE);
hash = tx.GetHash();
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
@ -313,7 +313,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[1].scriptSig = CScript() << OP_1;
tx.vin[1].prevout.hash = txFirst[0]->GetHash();
tx.vin[1].prevout.n = 0;
tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
tx.vout[0].nValue = CTxOutValue(tx.vout[0].nValue.GetAmount()+BLOCKSUBSIDY-HIGHERFEE); //First txn output + fresh coinbase - new txn fee
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
@ -341,7 +341,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout.hash = hash;
tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
tx.vout[0].nValue -= LOWFEE;
tx.vout[0].nValue = CTxOutValue(tx.vout[0].nValue.GetAmount() - LOWFEE);
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);

View file

@ -171,12 +171,16 @@ return;
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << tx2;
CDataStream streamVal1(SER_NETWORK, PROTOCOL_VERSION);
streamVal1 << txCredit.vout[0].nValue;
CDataStream streamVal2(SER_NETWORK, PROTOCOL_VERSION);
streamVal2 << CTxOutValue();
int libconsensus_flags = flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL;
if (libconsensus_flags == flags) {
if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, -1, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&streamVal1[0], streamVal1.size(), (const unsigned char*)&streamVal2[0], streamVal2.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
} else {
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, -1, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&streamVal2[0], streamVal2.size(), (const unsigned char*)&streamVal2[0], streamVal2.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect,message);
}
}

View file

@ -156,7 +156,7 @@ TestChain100Setup::~TestChain100Setup()
CAmount TotalValueOut(const CMutableTransaction& tx) {
CAmount nTotal = 0;
BOOST_FOREACH(const CTxOut& txo, tx.vout)
nTotal += txo.nValue;
nTotal += txo.nValue.GetAmount();
return nTotal;
}

View file

@ -46,7 +46,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
spends[i].vout.resize(1);
spends[i].vout[0].nValue = 11*CENT;
spends[i].vout[0].scriptPubKey = scriptPubKey;
spends[i].nTxFee = coinbaseTxns[0].vout[0].nValue - 11*CENT;
spends[i].nTxFee = coinbaseTxns[0].vout[0].nValue.GetAmount() - 11*CENT;
// Sign:
std::vector<unsigned char> vchSig;

View file

@ -504,11 +504,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
CAmount nValueOut = 0;
for (const auto& txout : tx.vout)
{
if (txout.nValue < 0)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
if (txout.nValue > MAX_MONEY)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
nValueOut += txout.nValue;
if (!txout.nValue.IsValid())
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-amount-invalid");
if (!txout.nValue.IsAmount())
continue;
nValueOut += txout.nValue.GetAmount();
if (!MoneyRange(nValueOut))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
}
@ -1432,9 +1432,12 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
}
// Check for negative or overflow input values
nValueIn += coins->vout[prevout.n].nValue;
if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
const CTxOutValue& value = coins->vout[prevout.n].nValue;
if (value.IsAmount()) {
nValueIn += value.GetAmount();
if (!MoneyRange(value.GetAmount()) || !MoneyRange(nValueIn))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
}
if (coins->vout[prevout.n].scriptPubKey.IsWithdrawLock() && tx.vin[i].scriptSig.IsWithdrawProof()) {
uint256 genesisHash(coins->vout[prevout.n].scriptPubKey.GetWithdrawLockGenesisHash());
@ -1518,7 +1521,11 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// super-majority signaling has occurred.
return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
}
prevValueIn = coins->vout[tx.vin[i].prevout.n].nValue;
const CTxOutValue& value = coins->vout[tx.vin[i].prevout.n].nValue;
if (value.IsAmount())
prevValueIn = value.GetAmount();
else
prevValueIn = -1;
}
}
}

View file

@ -449,8 +449,8 @@ class CScriptCheck
{
private:
CScript scriptPubKey;
CAmount amount;
CAmount amountPreviousInput;
CTxOutValue amount;
CTxOutValue amountPreviousInput;
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
@ -460,7 +460,7 @@ private:
public:
CScriptCheck(): amount(0), amountPreviousInput(-1), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, CAmount amountPreviousInputIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, const CTxOutValue& amountPreviousInputIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
amountPreviousInput(amountPreviousInputIn),
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }

View file

@ -592,7 +592,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
if (txout.scriptPubKey == scriptPubKey)
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
nAmount += txout.nValue.GetAmount();
}
return ValueFromAmount(nAmount);
@ -648,7 +648,7 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
CTxDestination address;
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
nAmount += txout.nValue.GetAmount();
}
}
@ -1187,7 +1187,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
continue;
tallyitem& item = mapTally[address];
item.nAmount += txout.nValue;
item.nAmount += txout.nValue.GetAmount();
item.nConf = min(item.nConf, nDepth);
item.txids.push_back(wtx.GetHash());
if (mine & ISMINE_WATCH_ONLY)
@ -2503,7 +2503,7 @@ UniValue listunspent(const JSONRPCRequest& request)
}
entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
entry.push_back(Pair("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue)));
entry.push_back(Pair("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue.GetAmount())));
entry.push_back(Pair("confirmations", out.nDepth));
entry.push_back(Pair("spendable", out.fSpendable));
entry.push_back(Pair("solvable", out.fSolvable));
@ -2910,15 +2910,15 @@ UniValue bumpfee(const JSONRPCRequest& request)
assert(nDelta > 0);
CMutableTransaction tx(*(wtx.tx));
CTxOut* poutput = &(tx.vout[nOutput]);
if (poutput->nValue < nDelta) {
if (poutput->nValue.GetAmount() < nDelta) {
throw JSONRPCError(RPC_MISC_ERROR, "Change output is too small to bump the fee");
}
// If the output would become dust, discard it (converting the dust to fee)
poutput->nValue -= nDelta;
if (poutput->nValue <= poutput->GetDustThreshold(::dustRelayFee)) {
poutput->nValue = CTxOutValue(poutput->nValue.GetAmount() - nDelta);
if (poutput->nValue.GetAmount() <= poutput->GetDustThreshold(::dustRelayFee)) {
LogPrint("rpc", "Bumping fee and discarding dust output\n");
nNewFee += poutput->nValue;
nNewFee += poutput->nValue.GetAmount();
tx.vout.erase(tx.vout.begin() + nOutput);
}
@ -2936,7 +2936,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
std::map<uint256, CWalletTx>::const_iterator mi = pwalletMain->mapWallet.find(input.prevout.hash);
assert(mi != pwalletMain->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
const CScript& scriptPubKey = mi->second.tx->vout[input.prevout.n].scriptPubKey;
const CAmount& amount = mi->second.tx->vout[input.prevout.n].nValue;
const CAmount& amount = mi->second.tx->vout[input.prevout.n].nValue.GetAmount();
SignatureData sigdata;
if (!ProduceSignature(TransactionSignatureCreator(pwalletMain, &txNewConst, nIn, amount, SIGHASH_ALL), scriptPubKey, sigdata)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");

View file

@ -75,7 +75,7 @@ struct CompareValueOnly
std::string COutput::ToString() const
{
return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue));
return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue.GetAmount()));
}
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
@ -1226,7 +1226,7 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.tx->vout.size())
if (IsMine(prev.tx->vout[txin.prevout.n]) & filter)
return prev.tx->vout[txin.prevout.n].nValue;
return prev.tx->vout[txin.prevout.n].nValue.GetAmount();
}
}
return 0;
@ -1239,9 +1239,9 @@ isminetype CWallet::IsMine(const CTxOut& txout) const
CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
{
if (!MoneyRange(txout.nValue))
if (!MoneyRange(txout.nValue.GetAmount()))
throw std::runtime_error(std::string(__func__) + ": value out of range");
return ((IsMine(txout) & filter) ? txout.nValue : 0);
return ((IsMine(txout) & filter) ? txout.nValue.GetAmount() : 0);
}
bool CWallet::IsChange(const CTxOut& txout) const
@ -1268,9 +1268,9 @@ bool CWallet::IsChange(const CTxOut& txout) const
CAmount CWallet::GetChange(const CTxOut& txout) const
{
if (!MoneyRange(txout.nValue))
if (!MoneyRange(txout.nValue.GetAmount()))
throw std::runtime_error(std::string(__func__) + ": value out of range");
return (IsChange(txout) ? txout.nValue : 0);
return (IsChange(txout) ? txout.nValue.GetAmount() : 0);
}
bool CWallet::IsMine(const CTransaction& tx) const
@ -1492,7 +1492,7 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
address = CNoDestination();
}
COutputEntry output = {address, txout.nValue, (int)i};
COutputEntry output = {address, txout.nValue.GetAmount(), (int)i};
// If we are debited by the transaction, add the output as a "sent" entry
if (nDebit > 0)
@ -2081,7 +2081,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
isminetype mine = IsMine(pcoin->tx->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && (pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) &&
!IsLockedCoin((*it).first, i) && (pcoin->tx->vout[i].nValue.GetAmount() > 0 || fIncludeZeroValue) &&
(!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i))))
vCoins.push_back(COutput(pcoin, i, nDepth,
((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
@ -2167,7 +2167,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
continue;
int i = output.i;
CAmount n = pcoin->tx->vout[i].nValue;
CAmount n = pcoin->tx->vout[i].nValue.GetAmount();
pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
@ -2254,7 +2254,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
{
if (!out.fSpendable)
continue;
nValueRet += out.tx->tx->vout[out.i].nValue;
nValueRet += out.tx->tx->vout[out.i].nValue.GetAmount();
setCoinsRet.insert(make_pair(out.tx, out.i));
}
return (nValueRet >= nTargetValue);
@ -2276,7 +2276,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
// Clearly invalid input, fail
if (pcoin->tx->vout.size() <= outpoint.n)
return false;
nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue.GetAmount();
setPresetCoins.insert(make_pair(pcoin, outpoint.n));
} else
return false; // TODO: Allow non-wallet inputs
@ -2320,7 +2320,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
for (size_t idx = 0; idx < tx.vout.size(); idx++)
{
const CTxOut& txOut = tx.vout[idx];
CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1};
CRecipient recipient = {txOut.scriptPubKey, txOut.nValue.GetAmount(), setSubtractFeeFromOutputs.count(idx) == 1};
vecSend.push_back(recipient);
}
@ -2456,12 +2456,12 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (recipient.fSubtractFeeFromAmount)
{
txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
txout.nValue = CTxOutValue(txout.nValue.GetAmount() - (nFeeRet / nSubtractFeeFromAmount)); // Subtract fee equally from each selected recipient
if (fFirst) // first receiver pays the remainder not divisible by output count
{
fFirst = false;
txout.nValue -= nFeeRet % nSubtractFeeFromAmount;
txout.nValue = CTxOutValue(txout.nValue.GetAmount() - (nFeeRet % nSubtractFeeFromAmount));
}
}
@ -2469,7 +2469,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
{
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{
if (txout.nValue < 0)
if (txout.nValue.GetAmount() < 0)
strFailReason = _("The transaction amount is too small to pay the fee");
else
strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
@ -2491,7 +2491,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
for (const auto& pcoin : setCoins)
{
CAmount nCredit = pcoin.first->tx->vout[pcoin.second].nValue;
CAmount nCredit = pcoin.first->tx->vout[pcoin.second].nValue.GetAmount();
//The coin age after the next block (depth+1) is used instead of the current,
//reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction.
@ -2545,13 +2545,13 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// So instead we raise the change and deduct from the recipient.
if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(dustRelayFee))
{
CAmount nDust = newTxOut.GetDustThreshold(dustRelayFee) - newTxOut.nValue;
newTxOut.nValue += nDust; // raise change until no more dust
CAmount nDust = newTxOut.GetDustThreshold(dustRelayFee) - newTxOut.nValue.GetAmount();
newTxOut.nValue = CTxOutValue(newTxOut.nValue.GetAmount() + nDust); // raise change until no more dust
for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient
{
if (vecSend[i].fSubtractFeeFromAmount)
{
txNew.vout[i].nValue -= nDust;
txNew.vout[i].nValue = CTxOutValue(txNew.vout[i].nValue.GetAmount() - nDust);
if (txNew.vout[i].IsDust(dustRelayFee))
{
strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
@ -2667,7 +2667,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
CAmount extraFeePaid = nFeeRet - nFeeNeeded;
vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
change_position->nValue += extraFeePaid;
change_position->nValue = CTxOutValue(change_position->nValue.GetAmount() + extraFeePaid);
nFeeRet -= extraFeePaid;
}
break; // Done, enough fee included.
@ -2678,8 +2678,8 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet;
vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
// Only reduce change if remaining amount is still a large enough output.
if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) {
change_position->nValue -= additionalFeeNeeded;
if (change_position->nValue.GetAmount() >= MIN_FINAL_CHANGE + additionalFeeNeeded) {
change_position->nValue = CTxOutValue(change_position->nValue.GetAmount() - additionalFeeNeeded);
nFeeRet += additionalFeeNeeded;
break; // Done, able to increase fee from change
}
@ -3146,7 +3146,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr))
continue;
CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue;
CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue.GetAmount();
if (!balances.count(addr))
balances[addr] = 0;