mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Consensus support for blinded amounts
This commit is contained in:
parent
b05e98bc9c
commit
bf009e4ba1
16 changed files with 177 additions and 98 deletions
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
|
||||
/**
|
||||
* calculate number of bytes for the bitmask, and its number of non-zero bytes
|
||||
* each bit in the bitmask represents the availability of one output, but the
|
||||
|
|
@ -250,41 +252,78 @@ const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const
|
|||
return coins->vout[input.prevout.n];
|
||||
}
|
||||
|
||||
CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
|
||||
{
|
||||
if (tx.IsCoinBase())
|
||||
return 0;
|
||||
|
||||
CAmount nResult = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
CAmount CCoinsViewCache::GetValueInExcess(const CTransaction& tx) const
|
||||
{
|
||||
const CAmount nValueIn = GetValueIn(tx);
|
||||
const CAmount nValueOut = tx.GetValueOut();
|
||||
return nValueIn - nValueOut;
|
||||
}
|
||||
extern secp256k1_context_t* secp256k1_bitcoin_verify_context;
|
||||
|
||||
bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& excess) const
|
||||
{
|
||||
CAmount nInAmount = GetValueIn(tx);
|
||||
if (nInAmount < excess)
|
||||
CAmount nPlainAmount = excess;
|
||||
std::vector<unsigned char> vchData;
|
||||
std::vector<unsigned char *> vpchCommitsIn, vpchCommitsOut;
|
||||
bool fNullRangeproof = false;
|
||||
vchData.resize(CTxOutValue::nCommitmentSize * (tx.vin.size() + tx.vout.size()));
|
||||
unsigned char *p = vchData.data();
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
for (size_t i = 0; i < tx.vin.size(); ++i)
|
||||
{
|
||||
const CTxOutValue& val = GetOutputFor(tx.vin[i]).nValue;
|
||||
if (val.IsAmount())
|
||||
nPlainAmount -= val.GetAmount();
|
||||
else
|
||||
{
|
||||
assert(val.vchCommitment.size() == CTxOutValue::nCommitmentSize);
|
||||
memcpy(p, &val.vchCommitment[0], CTxOutValue::nCommitmentSize);
|
||||
vpchCommitsIn.push_back(p);
|
||||
p += CTxOutValue::nCommitmentSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i)
|
||||
{
|
||||
const CTxOutValue& val = tx.vout[i].nValue;
|
||||
assert(val.vchCommitment.size() == CTxOutValue::nCommitmentSize);
|
||||
if (val.vchNonceCommitment.size() > CTxOutValue::nCommitmentSize || val.vchRangeproof.size() > 5000)
|
||||
return false;
|
||||
if (val.IsAmount())
|
||||
nPlainAmount += val.GetAmount();
|
||||
else
|
||||
{
|
||||
memcpy(p, &val.vchCommitment[0], CTxOutValue::nCommitmentSize);
|
||||
vpchCommitsOut.push_back(p);
|
||||
p += CTxOutValue::nCommitmentSize;
|
||||
|
||||
if (val.vchRangeproof.empty())
|
||||
fNullRangeproof = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no encrypted input or output values, we can do simple math
|
||||
if (vpchCommitsIn.size() + vpchCommitsOut.size() == 0)
|
||||
return (nPlainAmount == 0);
|
||||
|
||||
if (!secp256k1_pedersen_verify_tally(secp256k1_bitcoin_verify_context, vpchCommitsIn.data(), vpchCommitsIn.size(), vpchCommitsOut.data(), vpchCommitsOut.size(), nPlainAmount))
|
||||
return false;
|
||||
nInAmount -= excess;
|
||||
return nInAmount == tx.GetValueOut();
|
||||
|
||||
// Rangeproof is optional in this case
|
||||
if ((!vpchCommitsIn.empty()) && vpchCommitsOut.size() == 1 && nPlainAmount <= 0 && fNullRangeproof)
|
||||
return true;
|
||||
|
||||
uint64_t min_value, max_value;
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i)
|
||||
{
|
||||
const CTxOutValue& val = tx.vout[i].nValue;
|
||||
if (val.IsAmount())
|
||||
continue;
|
||||
if (!secp256k1_rangeproof_verify(secp256k1_bitcoin_verify_context, &min_value, &max_value, &val.vchCommitment[0], val.vchRangeproof.data(), val.vchRangeproof.size()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx) const
|
||||
{
|
||||
const CAmount excess = GetValueInExcess(tx);
|
||||
const CAmount& excess = tx.nTxFee;
|
||||
return VerifyAmounts(tx, excess);
|
||||
}
|
||||
|
||||
|
|
@ -322,6 +361,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
|
|||
int nCoinsHeight = coins->nHeight == 0x7fffffff ? nHeight + 1 : coins->nHeight;
|
||||
if (nCoinsHeight < nHeight + nOffset) {
|
||||
const CTxOutValue& val = coins->vout[txin.prevout.n].nValue;
|
||||
// FIXME: This assumes all blinded values are COIN
|
||||
CAmount nAmount = COIN;
|
||||
if (val.IsAmount())
|
||||
nAmount = val.GetAmount();
|
||||
|
|
|
|||
12
src/coins.h
12
src/coins.h
|
|
@ -429,18 +429,6 @@ public:
|
|||
//! Calculate the size of the cache (in number of transactions)
|
||||
unsigned int GetCacheSize() const;
|
||||
|
||||
/**
|
||||
* Amount of bitcoins coming in to a transaction
|
||||
* Note that lightweight clients may not know anything besides the hash of previous transactions,
|
||||
* so may not be able to calculate this.
|
||||
*
|
||||
* @param[in] tx transaction for which we are checking input total
|
||||
* @return Sum of value of all inputs (scriptSigs)
|
||||
*/
|
||||
CAmount GetValueIn(const CTransaction& tx) const;
|
||||
|
||||
CAmount GetValueInExcess(const CTransaction& tx) const;
|
||||
|
||||
/**
|
||||
* Verify the transaction's outputs spend exactly what its inputs provide, plus some excess amount.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ public:
|
|||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
#if 0 // TODO: Actually compress numeric values at least
|
||||
if (!ser_action.ForRead()) {
|
||||
assert(txout.nValue.IsAmount()); // FIXME
|
||||
uint64_t nVal = CompressAmount(txout.nValue.GetAmount());
|
||||
|
|
@ -116,6 +117,9 @@ public:
|
|||
READWRITE(VARINT(nVal));
|
||||
txout.nValue = DecompressAmount(nVal);
|
||||
}
|
||||
#else
|
||||
READWRITE(txout.nValue);
|
||||
#endif
|
||||
CScriptCompressor cscript(REF(txout.scriptPubKey));
|
||||
READWRITE(cscript);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
|
|||
UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue.GetAmount()));
|
||||
out.pushKV("value", outValue);
|
||||
}
|
||||
// TODO: Non-Amount values
|
||||
out.pushKV("n", (int64_t)i);
|
||||
|
||||
UniValue o(UniValue::VOBJ);
|
||||
|
|
|
|||
|
|
@ -1096,7 +1096,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
// Bring the best block into scope
|
||||
view.GetBestBlock();
|
||||
|
||||
nFees = view.GetValueInExcess(tx);
|
||||
nFees = tx.nTxFee;
|
||||
if (!view.VerifyAmounts(tx, nFees))
|
||||
return state.DoS(0,
|
||||
error("AcceptToMemoryPool : input amounts do not match output amounts %s",
|
||||
|
|
@ -1576,7 +1576,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||
}
|
||||
}
|
||||
|
||||
const CAmount nTxFee = inputs.GetValueInExcess(tx);
|
||||
const CAmount& nTxFee = tx.nTxFee;
|
||||
if (nTxFee < 0)
|
||||
return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()),
|
||||
REJECT_INVALID, "bad-txns-fee-negative");
|
||||
|
|
@ -1598,7 +1598,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||
// before the last block chain checkpoint. This is safe because block merkle hashes are
|
||||
// still computed and checked, and any change will be caught at the next checkpoint.
|
||||
if (fScriptChecks) {
|
||||
CAmount prevValueIn = -1;
|
||||
CTxOutValue prevValueIn = -1;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const CCoins* coins = inputs.AccessCoins(prevout.hash);
|
||||
|
|
@ -1880,7 +1880,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
REJECT_INVALID, "bad-blk-sigops");
|
||||
}
|
||||
|
||||
nFees += view.GetValueInExcess(tx);
|
||||
nFees += tx.nTxFee;
|
||||
|
||||
std::vector<CScriptCheck> vChecks;
|
||||
if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL))
|
||||
|
|
|
|||
|
|
@ -354,8 +354,8 @@ private:
|
|||
CScript scriptPubKey;
|
||||
const CTransaction *ptxTo;
|
||||
unsigned int nIn;
|
||||
CAmount nValueIn;
|
||||
CAmount nValueInPreviousIn;
|
||||
CTxOutValue nValueIn;
|
||||
CTxOutValue nValueInPreviousIn;
|
||||
CAmount nTxFee;
|
||||
int nSpendHeight;
|
||||
unsigned int nFlags;
|
||||
|
|
@ -364,7 +364,7 @@ private:
|
|||
|
||||
public:
|
||||
CScriptCheck(): ptxTo(0), nIn(0), nValueIn(-1), nValueInPreviousIn(-1), nTxFee(-1), nSpendHeight(-1), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
|
||||
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, CAmount nValueInPreviousInIn, CAmount nTxFeeIn, int nSpendHeightIn, unsigned int nFlagsIn, bool cacheIn) :
|
||||
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, CTxOutValue nValueInPreviousInIn, CAmount nTxFeeIn, int nSpendHeightIn, unsigned int nFlagsIn, bool cacheIn) :
|
||||
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
|
||||
ptxTo(&txToIn), nIn(nInIn), nValueIn(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
|
||||
nValueInPreviousIn(nValueInPreviousInIn), nTxFee(nTxFeeIn), nSpendHeight(nSpendHeightIn),
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ int64_t UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev)
|
|||
|
||||
static CFeeRate CalculateSubjectiveFeeRateAndPriority(const CCoinsViewCache& view, const CTransaction& tx, const unsigned int& nTxSize, double& dPriority) {
|
||||
const uint256& hash = tx.GetHash();
|
||||
CAmount nTxFees = view.GetValueInExcess(tx);
|
||||
CAmount nTxFees = tx.nTxFee;
|
||||
mempool.ApplyDeltas(hash, dPriority, nTxFees);
|
||||
|
||||
return CFeeRate(nTxFees, nTxSize);
|
||||
|
|
@ -281,7 +281,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
|||
if (!view.HaveInputs(tx))
|
||||
continue;
|
||||
|
||||
CAmount nTxFees = view.GetValueInExcess(tx);
|
||||
const CAmount& nTxFees = tx.nTxFee;
|
||||
|
||||
nTxSigOps += GetP2SHSigOpCount(tx, view);
|
||||
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
|
||||
|
|
|
|||
|
|
@ -10,39 +10,72 @@
|
|||
#include "utilstrencodings.h"
|
||||
|
||||
CTxOutValue::CTxOutValue()
|
||||
: nAmount(-1)
|
||||
{
|
||||
vchCommitment.resize(nCommitmentSize);
|
||||
memset(&vchCommitment[0], 0xff, nCommitmentSize);
|
||||
}
|
||||
|
||||
CTxOutValue::CTxOutValue(CAmount nAmountIn)
|
||||
: nAmount(nAmountIn)
|
||||
{
|
||||
vchCommitment.resize(nCommitmentSize);
|
||||
assert(vchCommitment.size() > sizeof(nAmountIn) + 1);
|
||||
memset(&vchCommitment[0], 0, vchCommitment.size() - sizeof(nAmountIn));
|
||||
for (size_t i = 0; i < sizeof(nAmountIn); ++i)
|
||||
vchCommitment[vchCommitment.size() - (i + 1)] = ((nAmountIn >> (i * 8)) & 0xff);
|
||||
}
|
||||
|
||||
CTxOutValue::CTxOutValue(const std::vector<unsigned char>& vchValueCommitmentIn, const std::vector<unsigned char>& vchRangeproofIn)
|
||||
: vchCommitment(vchValueCommitmentIn), vchRangeproof(vchRangeproofIn)
|
||||
{
|
||||
assert(vchCommitment.size() == nCommitmentSize);
|
||||
assert(vchCommitment[0] == 2 || vchCommitment[0] == 3);
|
||||
}
|
||||
|
||||
bool CTxOutValue::IsValid() const
|
||||
{
|
||||
return nAmount >= 0;
|
||||
switch (vchCommitment[0])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// Ensure all but the last sizeof(CAmount) bytes are zero
|
||||
for (size_t i = vchCommitment.size() - sizeof(CAmount); --i > 0; )
|
||||
if (vchCommitment[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case 2:
|
||||
case 3:
|
||||
// FIXME: Additional checks?
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CTxOutValue::IsNull() const
|
||||
{
|
||||
return nAmount == -1;
|
||||
return vchCommitment[0] == 0xff;
|
||||
}
|
||||
|
||||
bool CTxOutValue::IsAmount() const
|
||||
{
|
||||
return nAmount != -1;
|
||||
return !vchCommitment[0];
|
||||
}
|
||||
|
||||
CAmount CTxOutValue::GetAmount() const
|
||||
{
|
||||
assert(IsAmount());
|
||||
CAmount nAmount = 0;
|
||||
for (size_t i = 0; i < sizeof(nAmount); ++i)
|
||||
nAmount |= CAmount(vchCommitment[vchCommitment.size() - (i + 1)]) << (i * 8);
|
||||
return nAmount;
|
||||
}
|
||||
|
||||
bool operator==(const CTxOutValue& a, const CTxOutValue& b)
|
||||
{
|
||||
return a.nAmount == b.nAmount;
|
||||
return a.vchRangeproof == b.vchRangeproof &&
|
||||
a.vchCommitment == b.vchCommitment &&
|
||||
a.vchNonceCommitment == b.vchNonceCommitment;
|
||||
}
|
||||
|
||||
bool operator!=(const CTxOutValue& a, const CTxOutValue& b) {
|
||||
|
|
@ -94,8 +127,8 @@ std::string CTxOut::ToString() const
|
|||
return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", (nValue.IsAmount() ? strprintf("%d.%08d", nValue.GetAmount() / COIN, nValue.GetAmount() % COIN) : std::string("UNKNOWN")), scriptPubKey.ToString().substr(0,30));
|
||||
}
|
||||
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTxFee(0), nLockTime(0) {}
|
||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), nTxFee(tx.nTxFee), vout(tx.vout), nLockTime(tx.nLockTime) {}
|
||||
|
||||
uint256 CMutableTransaction::GetHash() const
|
||||
{
|
||||
|
|
@ -107,14 +140,15 @@ void CTransaction::UpdateHash() const
|
|||
*const_cast<uint256*>(&hash) = SerializeHash(*this);
|
||||
}
|
||||
|
||||
CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { }
|
||||
CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), nTxFee(0), vout(), nLockTime(0) { }
|
||||
|
||||
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {
|
||||
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), nTxFee(tx.nTxFee), vout(tx.vout), nLockTime(tx.nLockTime) {
|
||||
UpdateHash();
|
||||
}
|
||||
|
||||
CTransaction& CTransaction::operator=(const CTransaction &tx) {
|
||||
*const_cast<int*>(&nVersion) = tx.nVersion;
|
||||
*const_cast<CAmount*>(&nTxFee) = tx.nTxFee;
|
||||
*const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
|
||||
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
|
||||
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
|
||||
|
|
@ -122,20 +156,6 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
CAmount CTransaction::GetValueOut() const
|
||||
{
|
||||
CAmount nValueOut = 0;
|
||||
for (std::vector<CTxOut>::const_iterator it(vout.begin()); it != vout.end(); ++it)
|
||||
{
|
||||
assert(it->nValue.IsAmount());
|
||||
const CAmount nAmount = it->nValue.GetAmount();
|
||||
nValueOut += nAmount;
|
||||
if (!MoneyRange(nAmount) || !MoneyRange(nValueOut))
|
||||
throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
|
||||
}
|
||||
return nValueOut;
|
||||
}
|
||||
|
||||
double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
|
||||
{
|
||||
nTxSize = CalculateModifiedSize(nTxSize);
|
||||
|
|
|
|||
|
|
@ -13,16 +13,25 @@
|
|||
|
||||
class CTxOutValue
|
||||
{
|
||||
CAmount nAmount;
|
||||
public:
|
||||
static const size_t nCommitmentSize = 33;
|
||||
|
||||
std::vector<unsigned char> vchCommitment;
|
||||
std::vector<unsigned char> vchRangeproof;
|
||||
std::vector<unsigned char> vchNonceCommitment;
|
||||
|
||||
CTxOutValue();
|
||||
CTxOutValue(CAmount);
|
||||
CTxOutValue(const std::vector<unsigned char>& vchValueCommitment, const std::vector<unsigned char>& vchRangeproofIn);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(nAmount);
|
||||
template<typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
READWRITE(REF(CFlatData(&vchCommitment[0], &vchCommitment[nCommitmentSize])));
|
||||
READWRITE(vchRangeproof);
|
||||
READWRITE(vchNonceCommitment);
|
||||
}
|
||||
|
||||
bool IsValid() const;
|
||||
|
|
@ -130,7 +139,7 @@ public:
|
|||
SetNull();
|
||||
}
|
||||
|
||||
CTxOut(const CTxOutValue& nValueIn, CScript scriptPubKeyIn);
|
||||
CTxOut(const CTxOutValue& valueIn, CScript scriptPubKeyIn);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
|
|
@ -142,13 +151,13 @@ public:
|
|||
|
||||
void SetNull()
|
||||
{
|
||||
nValue = -1;
|
||||
nValue = CTxOutValue();
|
||||
scriptPubKey.clear();
|
||||
}
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
return (nValue == -1);
|
||||
return nValue.IsNull() && scriptPubKey.empty();
|
||||
}
|
||||
|
||||
bool IsDust(CFeeRate minRelayTxFee) const
|
||||
|
|
@ -204,6 +213,7 @@ public:
|
|||
// structure, including the hash.
|
||||
const int32_t nVersion;
|
||||
const std::vector<CTxIn> vin;
|
||||
const CAmount nTxFee;
|
||||
const std::vector<CTxOut> vout;
|
||||
const uint32_t nLockTime;
|
||||
|
||||
|
|
@ -222,6 +232,7 @@ public:
|
|||
READWRITE(*const_cast<int32_t*>(&this->nVersion));
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
|
||||
READWRITE(*const_cast<CAmount*>(&nTxFee));
|
||||
READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
|
||||
READWRITE(*const_cast<uint32_t*>(&nLockTime));
|
||||
if (ser_action.ForRead())
|
||||
|
|
@ -236,11 +247,6 @@ public:
|
|||
return hash;
|
||||
}
|
||||
|
||||
// Return sum of txouts.
|
||||
CAmount GetValueOut() const;
|
||||
// GetValueIn() is a method on CCoinsViewCache, because
|
||||
// inputs must be known to compute value in.
|
||||
|
||||
// Compute priority, given priority of inputs and (optionally) tx size
|
||||
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
|
||||
|
||||
|
|
@ -270,6 +276,7 @@ struct CMutableTransaction
|
|||
{
|
||||
int32_t nVersion;
|
||||
std::vector<CTxIn> vin;
|
||||
CAmount nTxFee;
|
||||
std::vector<CTxOut> vout;
|
||||
uint32_t nLockTime;
|
||||
|
||||
|
|
@ -283,6 +290,7 @@ struct CMutableTransaction
|
|||
READWRITE(this->nVersion);
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(vin);
|
||||
READWRITE(nTxFee);
|
||||
READWRITE(vout);
|
||||
READWRITE(nLockTime);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
#include <secp256k1.h>
|
||||
|
||||
static secp256k1_context_t* secp256k1_context = NULL;
|
||||
secp256k1_context_t* secp256k1_bitcoin_verify_context = NULL;
|
||||
static secp256k1_context_t*& secp256k1_context = secp256k1_bitcoin_verify_context;
|
||||
|
||||
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
|
||||
if (!IsValid())
|
||||
|
|
@ -87,7 +88,7 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
|
|||
void ECC_Verify_Start() {
|
||||
assert(secp256k1_context == NULL);
|
||||
|
||||
secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_COMMIT | SECP256K1_CONTEXT_RANGEPROOF);
|
||||
assert(ctx != NULL);
|
||||
|
||||
secp256k1_context = ctx;
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ Value gettxout(const Array& params, bool fHelp)
|
|||
ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
|
||||
if (coins.vout[n].nValue.IsAmount())
|
||||
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue.GetAmount())));
|
||||
// TODO: Non-Amount values
|
||||
Object o;
|
||||
ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
|
||||
ret.push_back(Pair("scriptPubKey", o));
|
||||
|
|
|
|||
|
|
@ -661,7 +661,9 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
|
||||
result.push_back(Pair("transactions", transactions));
|
||||
result.push_back(Pair("coinbaseaux", aux));
|
||||
#if 0 // FIXME: GBT won't work with non-Bitcoin transaction formats! at the very least, we'll need to change to coinbasetxn
|
||||
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue.GetAmount()));
|
||||
#endif
|
||||
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));
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
|
|||
Object out;
|
||||
if (txout.nValue.IsAmount())
|
||||
out.push_back(Pair("value", ValueFromAmount(txout.nValue.GetAmount())));
|
||||
// TODO: Non-Amount values
|
||||
out.push_back(Pair("n", (int64_t)i));
|
||||
Object o;
|
||||
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
||||
|
|
|
|||
|
|
@ -35,13 +35,26 @@ typedef vector<unsigned char> valtype;
|
|||
//! anonymous namespace
|
||||
namespace {
|
||||
|
||||
static secp256k1_context_t* secp256k1_context = NULL;
|
||||
|
||||
class CSecp256k1Init {
|
||||
public:
|
||||
CSecp256k1Init() {
|
||||
secp256k1_start(SECP256K1_START_VERIFY);
|
||||
assert(secp256k1_context == NULL);
|
||||
|
||||
secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
assert(ctx != NULL);
|
||||
|
||||
secp256k1_context = ctx;
|
||||
}
|
||||
|
||||
~CSecp256k1Init() {
|
||||
secp256k1_stop();
|
||||
secp256k1_context_t *ctx = secp256k1_context;
|
||||
secp256k1_context = NULL;
|
||||
|
||||
if (ctx) {
|
||||
secp256k1_context_destroy(ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
static CSecp256k1Init instance_of_csecp256k1;
|
||||
|
|
@ -1703,7 +1716,7 @@ COutPoint TransactionSignatureChecker::GetPrevOut() const
|
|||
return txTo->vin[nIn].prevout;
|
||||
}
|
||||
|
||||
CAmount TransactionSignatureChecker::GetValueIn() const
|
||||
CTxOutValue TransactionSignatureChecker::GetValueIn() const
|
||||
{
|
||||
return nInValue;
|
||||
}
|
||||
|
|
@ -1713,7 +1726,7 @@ CAmount TransactionSignatureChecker::GetTransactionFee() const
|
|||
return nTransactionFee;
|
||||
}
|
||||
|
||||
CAmount TransactionSignatureChecker::GetValueInPrevIn() const
|
||||
CTxOutValue TransactionSignatureChecker::GetValueInPrevIn() const
|
||||
{
|
||||
return nInMinusOneValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,12 +105,12 @@ public:
|
|||
virtual CTxOut GetOutputOffsetFromCurrent(const int offset) const;
|
||||
virtual COutPoint GetPrevOut() const;
|
||||
|
||||
virtual CAmount GetValueIn() const
|
||||
virtual CTxOutValue GetValueIn() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual CAmount GetValueInPrevIn() const
|
||||
virtual CTxOutValue GetValueInPrevIn() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -156,17 +156,17 @@ public:
|
|||
class TransactionSignatureChecker : public TransactionNoWithdrawsSignatureChecker
|
||||
{
|
||||
private:
|
||||
const CAmount nInValue;
|
||||
const CAmount nInMinusOneValue;
|
||||
const CTxOutValue nInValue;
|
||||
const CTxOutValue nInMinusOneValue;
|
||||
const CAmount nTransactionFee;
|
||||
const int nSpendHeight;
|
||||
|
||||
public:
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, CAmount nInValueIn, CAmount nInMinusOneValueIn, CAmount nTransactionFeeIn, int nSpendHeightIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn), nInValue(nInValueIn), nInMinusOneValue(nInMinusOneValueIn), nTransactionFee(nTransactionFeeIn), nSpendHeight(nSpendHeightIn) {}
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, CTxOutValue nInValueIn, CTxOutValue nInMinusOneValueIn, CAmount nTransactionFeeIn, int nSpendHeightIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn), nInValue(nInValueIn), nInMinusOneValue(nInMinusOneValueIn), nTransactionFee(nTransactionFeeIn), nSpendHeight(nSpendHeightIn) {}
|
||||
CTxOut GetOutputOffsetFromCurrent(const int offset) const;
|
||||
COutPoint GetPrevOut() const;
|
||||
CAmount GetValueIn() const;
|
||||
CAmount GetValueInPrevIn() const;
|
||||
CTxOutValue GetValueIn() const;
|
||||
CTxOutValue GetValueInPrevIn() const;
|
||||
CAmount GetTransactionFee() const;
|
||||
#ifdef FEDERATED_PEG_SIDECHAIN_ONLY
|
||||
bool IsConfirmedBitcoinBlock(const uint256& hash, bool fConservativeConfirmationRequirements) const;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ private:
|
|||
bool store;
|
||||
|
||||
public:
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, CAmount nInValueIn, CAmount nInMinusOneValueIn, CAmount nTransactionFeeIn, int nSpendHeightIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn, nInValueIn, nInMinusOneValueIn, nTransactionFeeIn, nSpendHeightIn), store(storeIn) {}
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, CTxOutValue nInValueIn, CTxOutValue nInMinusOneValueIn, CAmount nTransactionFeeIn, int nSpendHeightIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn, nInValueIn, nInMinusOneValueIn, nTransactionFeeIn, nSpendHeightIn), store(storeIn) {}
|
||||
|
||||
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue