Major updates integration from all upstreams
This commit is contained in:
@@ -202,12 +202,12 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMer
|
||||
std::string CBlock::ToString() const
|
||||
{
|
||||
std::stringstream s;
|
||||
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashReserved=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n",
|
||||
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashFinalSaplingRoot=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n",
|
||||
GetHash().ToString(),
|
||||
nVersion,
|
||||
hashPrevBlock.ToString(),
|
||||
hashMerkleRoot.ToString(),
|
||||
hashReserved.ToString(),
|
||||
hashFinalSaplingRoot.ToString(),
|
||||
nTime, nBits, nNonce.ToString(),
|
||||
vtx.size());
|
||||
for (unsigned int i = 0; i < vtx.size(); i++)
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
int32_t nVersion;
|
||||
uint256 hashPrevBlock;
|
||||
uint256 hashMerkleRoot;
|
||||
uint256 hashReserved;
|
||||
uint256 hashFinalSaplingRoot;
|
||||
uint32_t nTime;
|
||||
uint32_t nBits;
|
||||
CPOSNonce nNonce;
|
||||
@@ -45,12 +45,11 @@ public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(this->nVersion);
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(hashPrevBlock);
|
||||
READWRITE(hashMerkleRoot);
|
||||
READWRITE(hashReserved);
|
||||
READWRITE(hashFinalSaplingRoot);
|
||||
READWRITE(nTime);
|
||||
READWRITE(nBits);
|
||||
READWRITE(nNonce);
|
||||
@@ -62,7 +61,7 @@ public:
|
||||
nVersion = CBlockHeader::CURRENT_VERSION;
|
||||
hashPrevBlock.SetNull();
|
||||
hashMerkleRoot.SetNull();
|
||||
hashReserved.SetNull();
|
||||
hashFinalSaplingRoot.SetNull();
|
||||
nTime = 0;
|
||||
nBits = 0;
|
||||
nNonce = uint256();
|
||||
@@ -156,7 +155,7 @@ class CNetworkBlockHeader : public CBlockHeader
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(*(CBlockHeader*)this);
|
||||
READWRITE(compatVec);
|
||||
}
|
||||
@@ -191,7 +190,7 @@ public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(*(CBlockHeader*)this);
|
||||
READWRITE(vtx);
|
||||
}
|
||||
@@ -209,7 +208,7 @@ public:
|
||||
block.nVersion = nVersion;
|
||||
block.hashPrevBlock = hashPrevBlock;
|
||||
block.hashMerkleRoot = hashMerkleRoot;
|
||||
block.hashReserved = hashReserved;
|
||||
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
|
||||
block.nTime = nTime;
|
||||
block.nBits = nBits;
|
||||
block.nNonce = nNonce;
|
||||
@@ -251,12 +250,11 @@ public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(this->nVersion);
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(hashPrevBlock);
|
||||
READWRITE(hashMerkleRoot);
|
||||
READWRITE(hashReserved);
|
||||
READWRITE(hashFinalSaplingRoot);
|
||||
READWRITE(nTime);
|
||||
READWRITE(nBits);
|
||||
}
|
||||
@@ -281,8 +279,9 @@ struct CBlockLocator
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
if (!(nType & SER_GETHASH))
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
READWRITE(vHave);
|
||||
}
|
||||
|
||||
@@ -9,26 +9,31 @@
|
||||
#include "tinyformat.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
JSDescription::JSDescription(ZCJoinSplit& params,
|
||||
const uint256& pubKeyHash,
|
||||
const uint256& anchor,
|
||||
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||
const boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
|
||||
CAmount vpub_old,
|
||||
CAmount vpub_new,
|
||||
bool computeProof,
|
||||
uint256 *esk // payment disclosure
|
||||
) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor)
|
||||
#include "librustzcash.h"
|
||||
|
||||
JSDescription::JSDescription(
|
||||
bool makeGrothProof,
|
||||
ZCJoinSplit& params,
|
||||
const uint256& joinSplitPubKey,
|
||||
const uint256& anchor,
|
||||
const std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||
const std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
|
||||
CAmount vpub_old,
|
||||
CAmount vpub_new,
|
||||
bool computeProof,
|
||||
uint256 *esk // payment disclosure
|
||||
) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor)
|
||||
{
|
||||
boost::array<libzcash::Note, ZC_NUM_JS_OUTPUTS> notes;
|
||||
std::array<libzcash::SproutNote, ZC_NUM_JS_OUTPUTS> notes;
|
||||
|
||||
proof = params.prove(
|
||||
makeGrothProof,
|
||||
inputs,
|
||||
outputs,
|
||||
notes,
|
||||
ciphertexts,
|
||||
ephemeralKey,
|
||||
pubKeyHash,
|
||||
joinSplitPubKey,
|
||||
randomSeed,
|
||||
macs,
|
||||
nullifiers,
|
||||
@@ -42,24 +47,20 @@ JSDescription::JSDescription(ZCJoinSplit& params,
|
||||
}
|
||||
|
||||
JSDescription JSDescription::Randomized(
|
||||
ZCJoinSplit& params,
|
||||
const uint256& pubKeyHash,
|
||||
const uint256& anchor,
|
||||
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
|
||||
#ifdef __LP64__
|
||||
boost::array<uint64_t, ZC_NUM_JS_INPUTS>& inputMap,
|
||||
boost::array<uint64_t, ZC_NUM_JS_OUTPUTS>& outputMap,
|
||||
#else
|
||||
boost::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
|
||||
boost::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
|
||||
#endif
|
||||
CAmount vpub_old,
|
||||
CAmount vpub_new,
|
||||
bool computeProof,
|
||||
uint256 *esk, // payment disclosure
|
||||
std::function<int(int)> gen
|
||||
)
|
||||
bool makeGrothProof,
|
||||
ZCJoinSplit& params,
|
||||
const uint256& joinSplitPubKey,
|
||||
const uint256& anchor,
|
||||
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
|
||||
std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
|
||||
std::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
|
||||
CAmount vpub_old,
|
||||
CAmount vpub_new,
|
||||
bool computeProof,
|
||||
uint256 *esk, // payment disclosure
|
||||
std::function<int(int)> gen
|
||||
)
|
||||
{
|
||||
// Randomize the order of the inputs and outputs
|
||||
inputMap = {0, 1};
|
||||
@@ -71,34 +72,76 @@ JSDescription JSDescription::Randomized(
|
||||
MappedShuffle(outputs.begin(), outputMap.begin(), ZC_NUM_JS_OUTPUTS, gen);
|
||||
|
||||
return JSDescription(
|
||||
params, pubKeyHash, anchor, inputs, outputs,
|
||||
makeGrothProof,
|
||||
params, joinSplitPubKey, anchor, inputs, outputs,
|
||||
vpub_old, vpub_new, computeProof,
|
||||
esk // payment disclosure
|
||||
);
|
||||
}
|
||||
|
||||
class SproutProofVerifier : public boost::static_visitor<bool>
|
||||
{
|
||||
ZCJoinSplit& params;
|
||||
libzcash::ProofVerifier& verifier;
|
||||
const uint256& joinSplitPubKey;
|
||||
const JSDescription& jsdesc;
|
||||
|
||||
public:
|
||||
SproutProofVerifier(
|
||||
ZCJoinSplit& params,
|
||||
libzcash::ProofVerifier& verifier,
|
||||
const uint256& joinSplitPubKey,
|
||||
const JSDescription& jsdesc
|
||||
) : params(params), jsdesc(jsdesc), verifier(verifier), joinSplitPubKey(joinSplitPubKey) {}
|
||||
|
||||
bool operator()(const libzcash::PHGRProof& proof) const
|
||||
{
|
||||
return params.verify(
|
||||
proof,
|
||||
verifier,
|
||||
joinSplitPubKey,
|
||||
jsdesc.randomSeed,
|
||||
jsdesc.macs,
|
||||
jsdesc.nullifiers,
|
||||
jsdesc.commitments,
|
||||
jsdesc.vpub_old,
|
||||
jsdesc.vpub_new,
|
||||
jsdesc.anchor
|
||||
);
|
||||
}
|
||||
|
||||
bool operator()(const libzcash::GrothProof& proof) const
|
||||
{
|
||||
uint256 h_sig = params.h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey);
|
||||
|
||||
return librustzcash_sprout_verify(
|
||||
proof.begin(),
|
||||
jsdesc.anchor.begin(),
|
||||
h_sig.begin(),
|
||||
jsdesc.macs[0].begin(),
|
||||
jsdesc.macs[1].begin(),
|
||||
jsdesc.nullifiers[0].begin(),
|
||||
jsdesc.nullifiers[1].begin(),
|
||||
jsdesc.commitments[0].begin(),
|
||||
jsdesc.commitments[1].begin(),
|
||||
jsdesc.vpub_old,
|
||||
jsdesc.vpub_new
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
bool JSDescription::Verify(
|
||||
ZCJoinSplit& params,
|
||||
libzcash::ProofVerifier& verifier,
|
||||
const uint256& pubKeyHash
|
||||
const uint256& joinSplitPubKey
|
||||
) const {
|
||||
return params.verify(
|
||||
proof,
|
||||
verifier,
|
||||
pubKeyHash,
|
||||
randomSeed,
|
||||
macs,
|
||||
nullifiers,
|
||||
commitments,
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
anchor
|
||||
);
|
||||
auto pv = SproutProofVerifier(params, verifier, joinSplitPubKey, *this);
|
||||
return boost::apply_visitor(pv, proof);
|
||||
}
|
||||
|
||||
uint256 JSDescription::h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const
|
||||
uint256 JSDescription::h_sig(ZCJoinSplit& params, const uint256& joinSplitPubKey) const
|
||||
{
|
||||
return params.h_sig(randomSeed, nullifiers, pubKeyHash);
|
||||
return params.h_sig(randomSeed, nullifiers, joinSplitPubKey);
|
||||
}
|
||||
|
||||
std::string COutPoint::ToString() const
|
||||
@@ -106,6 +149,11 @@ std::string COutPoint::ToString() const
|
||||
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
|
||||
}
|
||||
|
||||
std::string SaplingOutPoint::ToString() const
|
||||
{
|
||||
return strprintf("SaplingOutPoint(%s, %u)", hash.ToString().substr(0, 10), n);
|
||||
}
|
||||
|
||||
CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
|
||||
{
|
||||
prevout = prevoutIn;
|
||||
@@ -128,7 +176,7 @@ std::string CTxIn::ToString() const
|
||||
if (prevout.IsNull())
|
||||
str += strprintf(", coinbase %s", HexStr(scriptSig));
|
||||
else
|
||||
str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24));
|
||||
str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24));
|
||||
if (nSequence != std::numeric_limits<unsigned int>::max())
|
||||
str += strprintf(", nSequence=%u", nSequence);
|
||||
str += ")";
|
||||
@@ -148,13 +196,15 @@ uint256 CTxOut::GetHash() const
|
||||
|
||||
std::string CTxOut::ToString() const
|
||||
{
|
||||
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
|
||||
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
|
||||
}
|
||||
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), nLockTime(0) {}
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), nLockTime(0), valueBalance(0) {}
|
||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight),
|
||||
vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
|
||||
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
|
||||
valueBalance(tx.valueBalance), vShieldedSpend(tx.vShieldedSpend), vShieldedOutput(tx.vShieldedOutput),
|
||||
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig),
|
||||
bindingSig(tx.bindingSig)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -169,11 +219,13 @@ void CTransaction::UpdateHash() const
|
||||
*const_cast<uint256*>(&hash) = SerializeHash(*this);
|
||||
}
|
||||
|
||||
CTransaction::CTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), vin(), vout(), nLockTime(0), vjoinsplit(), joinSplitPubKey(), joinSplitSig() { }
|
||||
CTransaction::CTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), vin(), vout(), nLockTime(0), valueBalance(0), vShieldedSpend(), vShieldedOutput(), vjoinsplit(), joinSplitPubKey(), joinSplitSig(), bindingSig() { }
|
||||
|
||||
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight),
|
||||
vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
|
||||
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
|
||||
valueBalance(tx.valueBalance), vShieldedSpend(tx.vShieldedSpend), vShieldedOutput(tx.vShieldedOutput),
|
||||
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig),
|
||||
bindingSig(tx.bindingSig)
|
||||
{
|
||||
UpdateHash();
|
||||
}
|
||||
@@ -184,11 +236,23 @@ CTransaction::CTransaction(
|
||||
const CMutableTransaction &tx,
|
||||
bool evilDeveloperFlag) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight),
|
||||
vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
|
||||
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
|
||||
valueBalance(tx.valueBalance), vShieldedSpend(tx.vShieldedSpend), vShieldedOutput(tx.vShieldedOutput),
|
||||
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig),
|
||||
bindingSig(tx.bindingSig)
|
||||
{
|
||||
assert(evilDeveloperFlag);
|
||||
}
|
||||
|
||||
CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId),
|
||||
vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), nExpiryHeight(tx.nExpiryHeight),
|
||||
valueBalance(tx.valueBalance),
|
||||
vShieldedSpend(std::move(tx.vShieldedSpend)), vShieldedOutput(std::move(tx.vShieldedOutput)),
|
||||
vjoinsplit(std::move(tx.vjoinsplit)),
|
||||
joinSplitPubKey(std::move(tx.joinSplitPubKey)), joinSplitSig(std::move(tx.joinSplitSig))
|
||||
{
|
||||
UpdateHash();
|
||||
}
|
||||
|
||||
CTransaction& CTransaction::operator=(const CTransaction &tx) {
|
||||
*const_cast<bool*>(&fOverwintered) = tx.fOverwintered;
|
||||
*const_cast<int*>(&nVersion) = tx.nVersion;
|
||||
@@ -197,9 +261,13 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
|
||||
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
|
||||
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
|
||||
*const_cast<uint32_t*>(&nExpiryHeight) = tx.nExpiryHeight;
|
||||
*const_cast<CAmount*>(&valueBalance) = tx.valueBalance;
|
||||
*const_cast<std::vector<SpendDescription>*>(&vShieldedSpend) = tx.vShieldedSpend;
|
||||
*const_cast<std::vector<OutputDescription>*>(&vShieldedOutput) = tx.vShieldedOutput;
|
||||
*const_cast<std::vector<JSDescription>*>(&vjoinsplit) = tx.vjoinsplit;
|
||||
*const_cast<uint256*>(&joinSplitPubKey) = tx.joinSplitPubKey;
|
||||
*const_cast<joinsplit_sig_t*>(&joinSplitSig) = tx.joinSplitSig;
|
||||
*const_cast<binding_sig_t*>(&bindingSig) = tx.bindingSig;
|
||||
*const_cast<uint256*>(&hash) = tx.hash;
|
||||
return *this;
|
||||
}
|
||||
@@ -214,9 +282,18 @@ CAmount CTransaction::GetValueOut() const
|
||||
throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
|
||||
}
|
||||
|
||||
if (valueBalance <= 0) {
|
||||
// NB: negative valueBalance "takes" money from the transparent value pool just as outputs do
|
||||
nValueOut += -valueBalance;
|
||||
|
||||
if (!MoneyRange(-valueBalance) || !MoneyRange(nValueOut)) {
|
||||
throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<JSDescription>::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it)
|
||||
{
|
||||
// NB: vpub_old "takes" money from the value pool just as outputs do
|
||||
// NB: vpub_old "takes" money from the transparent value pool just as outputs do
|
||||
nValueOut += it->vpub_old;
|
||||
|
||||
if (!MoneyRange(it->vpub_old) || !MoneyRange(nValueOut))
|
||||
@@ -225,31 +302,26 @@ CAmount CTransaction::GetValueOut() const
|
||||
return nValueOut;
|
||||
}
|
||||
|
||||
CAmount CTransaction::GetJoinSplitValueIn() const
|
||||
CAmount CTransaction::GetShieldedValueIn() const
|
||||
{
|
||||
CAmount nValue = 0;
|
||||
|
||||
if (valueBalance >= 0) {
|
||||
// NB: positive valueBalance "gives" money to the transparent value pool just as inputs do
|
||||
nValue += valueBalance;
|
||||
|
||||
if (!MoneyRange(valueBalance) || !MoneyRange(nValue)) {
|
||||
throw std::runtime_error("CTransaction::GetShieldedValueIn(): value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<JSDescription>::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it)
|
||||
{
|
||||
// NB: vpub_new "gives" money to the value pool just as inputs do
|
||||
// NB: vpub_new "gives" money to the transparent value pool just as inputs do
|
||||
nValue += it->vpub_new;
|
||||
|
||||
if (!MoneyRange(it->vpub_new) || !MoneyRange(nValue))
|
||||
throw std::runtime_error("CTransaction::GetJoinSplitValueIn(): value out of range");
|
||||
}
|
||||
|
||||
return nValue;
|
||||
}
|
||||
|
||||
CAmount CTransaction::GetJoinSplitValueOut() const
|
||||
{
|
||||
CAmount nValue = 0;
|
||||
for (std::vector<JSDescription>::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it)
|
||||
{
|
||||
// NB: vpub_new "gives" money to the value pool just as inputs do
|
||||
nValue += it->vpub_old;
|
||||
|
||||
if (!MoneyRange(it->vpub_old) || !MoneyRange(nValue))
|
||||
throw std::runtime_error("CTransaction::GetJoinSplitValueOut(): value out of range");
|
||||
throw std::runtime_error("CTransaction::GetShieldedValueIn(): value out of range");
|
||||
}
|
||||
|
||||
return nValue;
|
||||
@@ -321,6 +393,19 @@ std::string CTransaction::ToString() const
|
||||
vin.size(),
|
||||
vout.size(),
|
||||
nLockTime);
|
||||
} else if (nVersion >= SAPLING_MIN_TX_VERSION) {
|
||||
str += strprintf("CTransaction(hash=%s, ver=%d, fOverwintered=%d, nVersionGroupId=%08x, vin.size=%u, vout.size=%u, nLockTime=%u, nExpiryHeight=%u, valueBalance=%u, vShieldedSpend.size=%u, vShieldedOutput.size=%u)\n",
|
||||
GetHash().ToString().substr(0,10),
|
||||
nVersion,
|
||||
fOverwintered,
|
||||
nVersionGroupId,
|
||||
vin.size(),
|
||||
vout.size(),
|
||||
nLockTime,
|
||||
nExpiryHeight,
|
||||
valueBalance,
|
||||
vShieldedSpend.size(),
|
||||
vShieldedOutput.size());
|
||||
} else if (nVersion >= 3) {
|
||||
str += strprintf("CTransaction(hash=%s, ver=%d, fOverwintered=%d, nVersionGroupId=%08x, vin.size=%u, vout.size=%u, nLockTime=%u, nExpiryHeight=%u)\n",
|
||||
GetHash().ToString().substr(0,10),
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "random.h"
|
||||
#include "script/script.h"
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
#include "uint256.h"
|
||||
#include "arith_uint256.h"
|
||||
#include "consensus/consensus.h"
|
||||
@@ -20,7 +21,9 @@
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <array>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include "zcash/NoteEncryption.hpp"
|
||||
#include "zcash/Zcash.h"
|
||||
@@ -29,6 +32,159 @@
|
||||
|
||||
extern uint32_t ASSETCHAINS_MAGIC;
|
||||
|
||||
// Overwinter transaction version
|
||||
static const int32_t OVERWINTER_TX_VERSION = 3;
|
||||
static_assert(OVERWINTER_TX_VERSION >= OVERWINTER_MIN_TX_VERSION,
|
||||
"Overwinter tx version must not be lower than minimum");
|
||||
static_assert(OVERWINTER_TX_VERSION <= OVERWINTER_MAX_TX_VERSION,
|
||||
"Overwinter tx version must not be higher than maximum");
|
||||
|
||||
// Sapling transaction version
|
||||
static const int32_t SAPLING_TX_VERSION = 4;
|
||||
static_assert(SAPLING_TX_VERSION >= SAPLING_MIN_TX_VERSION,
|
||||
"Sapling tx version must not be lower than minimum");
|
||||
static_assert(SAPLING_TX_VERSION <= SAPLING_MAX_TX_VERSION,
|
||||
"Sapling tx version must not be higher than maximum");
|
||||
|
||||
/**
|
||||
* A shielded input to a transaction. It contains data that describes a Spend transfer.
|
||||
*/
|
||||
class SpendDescription
|
||||
{
|
||||
public:
|
||||
typedef std::array<unsigned char, 64> spend_auth_sig_t;
|
||||
|
||||
uint256 cv; //!< A value commitment to the value of the input note.
|
||||
uint256 anchor; //!< A Merkle root of the Sapling note commitment tree at some block height in the past.
|
||||
uint256 nullifier; //!< The nullifier of the input note.
|
||||
uint256 rk; //!< The randomized public key for spendAuthSig.
|
||||
libzcash::GrothProof zkproof; //!< A zero-knowledge proof using the spend circuit.
|
||||
spend_auth_sig_t spendAuthSig; //!< A signature authorizing this spend.
|
||||
|
||||
SpendDescription() { }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(cv);
|
||||
READWRITE(anchor);
|
||||
READWRITE(nullifier);
|
||||
READWRITE(rk);
|
||||
READWRITE(zkproof);
|
||||
READWRITE(spendAuthSig);
|
||||
}
|
||||
|
||||
friend bool operator==(const SpendDescription& a, const SpendDescription& b)
|
||||
{
|
||||
return (
|
||||
a.cv == b.cv &&
|
||||
a.anchor == b.anchor &&
|
||||
a.nullifier == b.nullifier &&
|
||||
a.rk == b.rk &&
|
||||
a.zkproof == b.zkproof &&
|
||||
a.spendAuthSig == b.spendAuthSig
|
||||
);
|
||||
}
|
||||
|
||||
friend bool operator!=(const SpendDescription& a, const SpendDescription& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A shielded output to a transaction. It contains data that describes an Output transfer.
|
||||
*/
|
||||
class OutputDescription
|
||||
{
|
||||
public:
|
||||
uint256 cv; //!< A value commitment to the value of the output note.
|
||||
uint256 cm; //!< The note commitment for the output note.
|
||||
uint256 ephemeralKey; //!< A Jubjub public key.
|
||||
libzcash::SaplingEncCiphertext encCiphertext; //!< A ciphertext component for the encrypted output note.
|
||||
libzcash::SaplingOutCiphertext outCiphertext; //!< A ciphertext component for the encrypted output note.
|
||||
libzcash::GrothProof zkproof; //!< A zero-knowledge proof using the output circuit.
|
||||
|
||||
OutputDescription() { }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(cv);
|
||||
READWRITE(cm);
|
||||
READWRITE(ephemeralKey);
|
||||
READWRITE(encCiphertext);
|
||||
READWRITE(outCiphertext);
|
||||
READWRITE(zkproof);
|
||||
}
|
||||
|
||||
friend bool operator==(const OutputDescription& a, const OutputDescription& b)
|
||||
{
|
||||
return (
|
||||
a.cv == b.cv &&
|
||||
a.cm == b.cm &&
|
||||
a.ephemeralKey == b.ephemeralKey &&
|
||||
a.encCiphertext == b.encCiphertext &&
|
||||
a.outCiphertext == b.outCiphertext &&
|
||||
a.zkproof == b.zkproof
|
||||
);
|
||||
}
|
||||
|
||||
friend bool operator!=(const OutputDescription& a, const OutputDescription& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Stream>
|
||||
class SproutProofSerializer : public boost::static_visitor<>
|
||||
{
|
||||
Stream& s;
|
||||
bool useGroth;
|
||||
|
||||
public:
|
||||
SproutProofSerializer(Stream& s, bool useGroth) : s(s), useGroth(useGroth) {}
|
||||
|
||||
void operator()(const libzcash::PHGRProof& proof) const
|
||||
{
|
||||
if (useGroth) {
|
||||
throw std::ios_base::failure("Invalid Sprout proof for transaction format (expected GrothProof, found PHGRProof)");
|
||||
}
|
||||
::Serialize(s, proof);
|
||||
}
|
||||
|
||||
void operator()(const libzcash::GrothProof& proof) const
|
||||
{
|
||||
if (!useGroth) {
|
||||
throw std::ios_base::failure("Invalid Sprout proof for transaction format (expected PHGRProof, found GrothProof)");
|
||||
}
|
||||
::Serialize(s, proof);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Stream, typename T>
|
||||
inline void SerReadWriteSproutProof(Stream& s, const T& proof, bool useGroth, CSerActionSerialize ser_action)
|
||||
{
|
||||
auto ps = SproutProofSerializer<Stream>(s, useGroth);
|
||||
boost::apply_visitor(ps, proof);
|
||||
}
|
||||
|
||||
template<typename Stream, typename T>
|
||||
inline void SerReadWriteSproutProof(Stream& s, T& proof, bool useGroth, CSerActionUnserialize ser_action)
|
||||
{
|
||||
if (useGroth) {
|
||||
libzcash::GrothProof grothProof;
|
||||
::Unserialize(s, grothProof);
|
||||
proof = grothProof;
|
||||
} else {
|
||||
libzcash::PHGRProof pghrProof;
|
||||
::Unserialize(s, pghrProof);
|
||||
proof = pghrProof;
|
||||
}
|
||||
}
|
||||
|
||||
class JSDescription
|
||||
{
|
||||
public:
|
||||
@@ -47,14 +203,14 @@ public:
|
||||
// are derived from the secrets placed in the note
|
||||
// and the secret spend-authority key known by the
|
||||
// spender.
|
||||
boost::array<uint256, ZC_NUM_JS_INPUTS> nullifiers;
|
||||
std::array<uint256, ZC_NUM_JS_INPUTS> nullifiers;
|
||||
|
||||
// Note commitments are introduced into the commitment
|
||||
// tree, blinding the public about the values and
|
||||
// destinations involved in the JoinSplit. The presence of
|
||||
// a commitment in the note commitment tree is required
|
||||
// to spend it.
|
||||
boost::array<uint256, ZC_NUM_JS_OUTPUTS> commitments;
|
||||
std::array<uint256, ZC_NUM_JS_OUTPUTS> commitments;
|
||||
|
||||
// Ephemeral key
|
||||
uint256 ephemeralKey;
|
||||
@@ -63,7 +219,7 @@ public:
|
||||
// These contain trapdoors, values and other information
|
||||
// that the recipient needs, including a memo field. It
|
||||
// is encrypted using the scheme implemented in crypto/NoteEncryption.cpp
|
||||
boost::array<ZCNoteEncryption::Ciphertext, ZC_NUM_JS_OUTPUTS> ciphertexts = {{ {{0}} }};
|
||||
std::array<ZCNoteEncryption::Ciphertext, ZC_NUM_JS_OUTPUTS> ciphertexts = {{ {{0}} }};
|
||||
|
||||
// Random seed
|
||||
uint256 randomSeed;
|
||||
@@ -71,19 +227,21 @@ public:
|
||||
// MACs
|
||||
// The verification of the JoinSplit requires these MACs
|
||||
// to be provided as an input.
|
||||
boost::array<uint256, ZC_NUM_JS_INPUTS> macs;
|
||||
std::array<uint256, ZC_NUM_JS_INPUTS> macs;
|
||||
|
||||
// JoinSplit proof
|
||||
// This is a zk-SNARK which ensures that this JoinSplit is valid.
|
||||
libzcash::ZCProof proof;
|
||||
libzcash::SproutProof proof;
|
||||
|
||||
JSDescription(): vpub_old(0), vpub_new(0) { }
|
||||
|
||||
JSDescription(ZCJoinSplit& params,
|
||||
const uint256& pubKeyHash,
|
||||
JSDescription(
|
||||
bool makeGrothProof,
|
||||
ZCJoinSplit& params,
|
||||
const uint256& joinSplitPubKey,
|
||||
const uint256& rt,
|
||||
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||
const boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
|
||||
const std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||
const std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
|
||||
CAmount vpub_old,
|
||||
CAmount vpub_new,
|
||||
bool computeProof = true, // Set to false in some tests
|
||||
@@ -91,18 +249,14 @@ public:
|
||||
);
|
||||
|
||||
static JSDescription Randomized(
|
||||
bool makeGrothProof,
|
||||
ZCJoinSplit& params,
|
||||
const uint256& pubKeyHash,
|
||||
const uint256& joinSplitPubKey,
|
||||
const uint256& rt,
|
||||
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
|
||||
#ifdef __LP64__
|
||||
boost::array<uint64_t, ZC_NUM_JS_INPUTS>& inputMap,
|
||||
boost::array<uint64_t, ZC_NUM_JS_OUTPUTS>& outputMap,
|
||||
#else
|
||||
boost::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
|
||||
boost::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
|
||||
#endif
|
||||
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
|
||||
std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
|
||||
std::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
|
||||
CAmount vpub_old,
|
||||
CAmount vpub_new,
|
||||
bool computeProof = true, // Set to false in some tests
|
||||
@@ -114,16 +268,22 @@ public:
|
||||
bool Verify(
|
||||
ZCJoinSplit& params,
|
||||
libzcash::ProofVerifier& verifier,
|
||||
const uint256& pubKeyHash
|
||||
const uint256& joinSplitPubKey
|
||||
) const;
|
||||
|
||||
// Returns the calculated h_sig
|
||||
uint256 h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const;
|
||||
uint256 h_sig(ZCJoinSplit& params, const uint256& joinSplitPubKey) const;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
// nVersion is set by CTransaction and CMutableTransaction to
|
||||
// (tx.fOverwintered << 31) | tx.nVersion
|
||||
bool fOverwintered = s.GetVersion() >> 31;
|
||||
int32_t txVersion = s.GetVersion() & 0x7FFFFFFF;
|
||||
bool useGroth = fOverwintered && txVersion >= SAPLING_TX_VERSION;
|
||||
|
||||
READWRITE(vpub_old);
|
||||
READWRITE(vpub_new);
|
||||
READWRITE(anchor);
|
||||
@@ -132,7 +292,7 @@ public:
|
||||
READWRITE(ephemeralKey);
|
||||
READWRITE(randomSeed);
|
||||
READWRITE(macs);
|
||||
READWRITE(proof);
|
||||
::SerReadWriteSproutProof(s, proof, useGroth, ser_action);
|
||||
READWRITE(ciphertexts);
|
||||
}
|
||||
|
||||
@@ -158,20 +318,19 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
class COutPoint
|
||||
class BaseOutPoint
|
||||
{
|
||||
public:
|
||||
uint256 hash;
|
||||
uint32_t n;
|
||||
|
||||
COutPoint() { SetNull(); }
|
||||
COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
|
||||
BaseOutPoint() { SetNull(); }
|
||||
BaseOutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(hash);
|
||||
READWRITE(n);
|
||||
}
|
||||
@@ -179,21 +338,38 @@ public:
|
||||
void SetNull() { hash.SetNull(); n = (uint32_t) -1; }
|
||||
bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); }
|
||||
|
||||
friend bool operator<(const COutPoint& a, const COutPoint& b)
|
||||
friend bool operator<(const BaseOutPoint& a, const BaseOutPoint& b)
|
||||
{
|
||||
return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
|
||||
}
|
||||
|
||||
friend bool operator==(const COutPoint& a, const COutPoint& b)
|
||||
friend bool operator==(const BaseOutPoint& a, const BaseOutPoint& b)
|
||||
{
|
||||
return (a.hash == b.hash && a.n == b.n);
|
||||
}
|
||||
|
||||
friend bool operator!=(const COutPoint& a, const COutPoint& b)
|
||||
friend bool operator!=(const BaseOutPoint& a, const BaseOutPoint& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
};
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
class COutPoint : public BaseOutPoint
|
||||
{
|
||||
public:
|
||||
COutPoint() : BaseOutPoint() {};
|
||||
COutPoint(uint256 hashIn, uint32_t nIn) : BaseOutPoint(hashIn, nIn) {};
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its sapling
|
||||
* output description (vShieldedOutput) */
|
||||
class SaplingOutPoint : public BaseOutPoint
|
||||
{
|
||||
public:
|
||||
SaplingOutPoint() : BaseOutPoint() {};
|
||||
SaplingOutPoint(uint256 hashIn, uint32_t nIn) : BaseOutPoint(hashIn, nIn) {};
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
@@ -219,9 +395,9 @@ public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(prevout);
|
||||
READWRITE(scriptSig);
|
||||
READWRITE(*(CScriptBase*)(&scriptSig));
|
||||
READWRITE(nSequence);
|
||||
}
|
||||
|
||||
@@ -264,9 +440,9 @@ public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(nValue);
|
||||
READWRITE(scriptPubKey);
|
||||
READWRITE(*(CScriptBase*)(&scriptPubKey));
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
@@ -295,7 +471,7 @@ public:
|
||||
if (scriptPubKey.IsUnspendable())
|
||||
return 0;
|
||||
|
||||
size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
|
||||
size_t nSize = GetSerializeSize(*this, SER_DISK, 0) + 148u;
|
||||
return 3*minRelayTxFee.GetFee(nSize);
|
||||
}
|
||||
|
||||
@@ -321,6 +497,10 @@ public:
|
||||
static constexpr uint32_t OVERWINTER_VERSION_GROUP_ID = 0x03C48270;
|
||||
static_assert(OVERWINTER_VERSION_GROUP_ID != 0, "version group id must be non-zero as specified in ZIP 202");
|
||||
|
||||
// Sapling version group id
|
||||
static constexpr uint32_t SAPLING_VERSION_GROUP_ID = 0x892F2085;
|
||||
static_assert(SAPLING_VERSION_GROUP_ID != 0, "version group id must be non-zero as specified in ZIP 202");
|
||||
|
||||
struct CMutableTransaction;
|
||||
|
||||
/** The basic transaction that is broadcasted on the network and contained in
|
||||
@@ -340,13 +520,16 @@ protected:
|
||||
CTransaction(const CMutableTransaction &tx, bool evilDeveloperFlag);
|
||||
|
||||
public:
|
||||
typedef boost::array<unsigned char, 64> joinsplit_sig_t;
|
||||
typedef std::array<unsigned char, 64> joinsplit_sig_t;
|
||||
typedef std::array<unsigned char, 64> binding_sig_t;
|
||||
|
||||
// Transactions that include a list of JoinSplits are >= version 2.
|
||||
static const int32_t SPROUT_MIN_CURRENT_VERSION = 1;
|
||||
static const int32_t SPROUT_MAX_CURRENT_VERSION = 2;
|
||||
static const int32_t OVERWINTER_MIN_CURRENT_VERSION = 3;
|
||||
static const int32_t OVERWINTER_MAX_CURRENT_VERSION = 3;
|
||||
static const int32_t SAPLING_MIN_CURRENT_VERSION = 4;
|
||||
static const int32_t SAPLING_MAX_CURRENT_VERSION = 4;
|
||||
|
||||
static_assert(SPROUT_MIN_CURRENT_VERSION >= SPROUT_MIN_TX_VERSION,
|
||||
"standard rule for tx version should be consistent with network rule");
|
||||
@@ -358,6 +541,13 @@ public:
|
||||
OVERWINTER_MAX_CURRENT_VERSION >= OVERWINTER_MIN_CURRENT_VERSION),
|
||||
"standard rule for tx version should be consistent with network rule");
|
||||
|
||||
static_assert(SAPLING_MIN_CURRENT_VERSION >= SAPLING_MIN_TX_VERSION,
|
||||
"standard rule for tx version should be consistent with network rule");
|
||||
|
||||
static_assert( (SAPLING_MAX_CURRENT_VERSION <= SAPLING_MAX_TX_VERSION &&
|
||||
SAPLING_MAX_CURRENT_VERSION >= SAPLING_MIN_CURRENT_VERSION),
|
||||
"standard rule for tx version should be consistent with network rule");
|
||||
|
||||
// The local variables are made const to prevent unintended modification
|
||||
// without updating the cached hash value. However, CTransaction is not
|
||||
// actually immutable; deserialization and assignment are implemented,
|
||||
@@ -370,61 +560,82 @@ public:
|
||||
const std::vector<CTxOut> vout;
|
||||
const uint32_t nLockTime;
|
||||
const uint32_t nExpiryHeight;
|
||||
const CAmount valueBalance;
|
||||
const std::vector<SpendDescription> vShieldedSpend;
|
||||
const std::vector<OutputDescription> vShieldedOutput;
|
||||
const std::vector<JSDescription> vjoinsplit;
|
||||
const uint256 joinSplitPubKey;
|
||||
const joinsplit_sig_t joinSplitSig = {{0}};
|
||||
const binding_sig_t bindingSig = {{0}};
|
||||
|
||||
/** Construct a CTransaction that qualifies as IsNull() */
|
||||
CTransaction();
|
||||
|
||||
/** Convert a CMutableTransaction into a CTransaction. */
|
||||
CTransaction(const CMutableTransaction &tx);
|
||||
CTransaction(CMutableTransaction &&tx);
|
||||
|
||||
CTransaction& operator=(const CTransaction& tx);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
uint32_t header;
|
||||
if (ser_action.ForRead()) {
|
||||
// When deserializing, unpack the 4 byte header to extract fOverwintered and nVersion.
|
||||
uint32_t header;
|
||||
READWRITE(header);
|
||||
*const_cast<bool*>(&fOverwintered) = header >> 31;
|
||||
*const_cast<int32_t*>(&this->nVersion) = header & 0x7FFFFFFF;
|
||||
} else {
|
||||
uint32_t header = GetHeader();
|
||||
header = GetHeader();
|
||||
READWRITE(header);
|
||||
}
|
||||
nVersion = this->nVersion;
|
||||
if (fOverwintered) {
|
||||
READWRITE(*const_cast<uint32_t*>(&this->nVersionGroupId));
|
||||
}
|
||||
|
||||
bool isOverwinterV3 = fOverwintered &&
|
||||
nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
|
||||
nVersion == 3;
|
||||
if (fOverwintered && !isOverwinterV3) {
|
||||
bool isOverwinterV3 =
|
||||
fOverwintered &&
|
||||
nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
|
||||
nVersion == OVERWINTER_TX_VERSION;
|
||||
bool isSaplingV4 =
|
||||
fOverwintered &&
|
||||
nVersionGroupId == SAPLING_VERSION_GROUP_ID &&
|
||||
nVersion == SAPLING_TX_VERSION;
|
||||
if (fOverwintered && !(isOverwinterV3 || isSaplingV4)) {
|
||||
throw std::ios_base::failure("Unknown transaction format");
|
||||
}
|
||||
|
||||
READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
|
||||
READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
|
||||
READWRITE(*const_cast<uint32_t*>(&nLockTime));
|
||||
if (isOverwinterV3) {
|
||||
if (isOverwinterV3 || isSaplingV4) {
|
||||
READWRITE(*const_cast<uint32_t*>(&nExpiryHeight));
|
||||
}
|
||||
if (isSaplingV4) {
|
||||
READWRITE(*const_cast<CAmount*>(&valueBalance));
|
||||
READWRITE(*const_cast<std::vector<SpendDescription>*>(&vShieldedSpend));
|
||||
READWRITE(*const_cast<std::vector<OutputDescription>*>(&vShieldedOutput));
|
||||
}
|
||||
if (nVersion >= 2) {
|
||||
READWRITE(*const_cast<std::vector<JSDescription>*>(&vjoinsplit));
|
||||
auto os = WithVersion(&s, static_cast<int>(header));
|
||||
::SerReadWrite(os, *const_cast<std::vector<JSDescription>*>(&vjoinsplit), ser_action);
|
||||
if (vjoinsplit.size() > 0) {
|
||||
READWRITE(*const_cast<uint256*>(&joinSplitPubKey));
|
||||
READWRITE(*const_cast<joinsplit_sig_t*>(&joinSplitSig));
|
||||
}
|
||||
}
|
||||
if (isSaplingV4 && !(vShieldedSpend.empty() && vShieldedOutput.empty())) {
|
||||
READWRITE(*const_cast<binding_sig_t*>(&bindingSig));
|
||||
}
|
||||
if (ser_action.ForRead())
|
||||
UpdateHash();
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}
|
||||
|
||||
bool IsNull() const {
|
||||
return vin.empty() && vout.empty();
|
||||
}
|
||||
@@ -443,15 +654,24 @@ public:
|
||||
return header;
|
||||
}
|
||||
|
||||
// Return sum of txouts.
|
||||
/*
|
||||
* Context for the two methods below:
|
||||
* As at most one of vpub_new and vpub_old is non-zero in every JoinSplit,
|
||||
* we can think of a JoinSplit as an input or output according to which one
|
||||
* it is (e.g. if vpub_new is non-zero the joinSplit is "giving value" to
|
||||
* the outputs in the transaction). Similarly, we can think of the Sapling
|
||||
* shielded part of the transaction as an input or output according to
|
||||
* whether valueBalance - the sum of shielded input values minus the sum of
|
||||
* shielded output values - is positive or negative.
|
||||
*/
|
||||
|
||||
// Return sum of txouts, (negative valueBalance or zero) and JoinSplit vpub_old.
|
||||
CAmount GetValueOut() const;
|
||||
// GetValueIn() is a method on CCoinsViewCache, because
|
||||
// inputs must be known to compute value in.
|
||||
|
||||
// Return sum of JoinSplit vpub_new
|
||||
CAmount GetJoinSplitValueIn() const;
|
||||
// Return sum of JoinSplit vpub_old
|
||||
CAmount GetJoinSplitValueOut() const;
|
||||
// Return sum of (positive valueBalance or zero) and JoinSplit vpub_new
|
||||
CAmount GetShieldedValueIn() const;
|
||||
|
||||
// Compute priority, given priority of inputs and (optionally) tx size
|
||||
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
|
||||
@@ -535,9 +755,13 @@ struct CMutableTransaction
|
||||
std::vector<CTxOut> vout;
|
||||
uint32_t nLockTime;
|
||||
uint32_t nExpiryHeight;
|
||||
CAmount valueBalance;
|
||||
std::vector<SpendDescription> vShieldedSpend;
|
||||
std::vector<OutputDescription> vShieldedOutput;
|
||||
std::vector<JSDescription> vjoinsplit;
|
||||
uint256 joinSplitPubKey;
|
||||
CTransaction::joinsplit_sig_t joinSplitSig = {{0}};
|
||||
CTransaction::binding_sig_t bindingSig = {{0}};
|
||||
|
||||
CMutableTransaction();
|
||||
CMutableTransaction(const CTransaction& tx);
|
||||
@@ -545,47 +769,65 @@ struct CMutableTransaction
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
uint32_t header;
|
||||
if (ser_action.ForRead()) {
|
||||
// When deserializing, unpack the 4 byte header to extract fOverwintered and nVersion.
|
||||
uint32_t header;
|
||||
READWRITE(header);
|
||||
fOverwintered = header >> 31;
|
||||
this->nVersion = header & 0x7FFFFFFF;
|
||||
} else {
|
||||
// When serializing v1 and v2, the 4 byte header is nVersion
|
||||
uint32_t header = this->nVersion;
|
||||
header = this->nVersion;
|
||||
// When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion
|
||||
if (fOverwintered) {
|
||||
header |= 1 << 31;
|
||||
}
|
||||
READWRITE(header);
|
||||
}
|
||||
nVersion = this->nVersion;
|
||||
if (fOverwintered) {
|
||||
READWRITE(nVersionGroupId);
|
||||
}
|
||||
|
||||
bool isOverwinterV3 = fOverwintered &&
|
||||
nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
|
||||
nVersion == 3;
|
||||
if (fOverwintered && !isOverwinterV3) {
|
||||
bool isOverwinterV3 =
|
||||
fOverwintered &&
|
||||
nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
|
||||
nVersion == OVERWINTER_TX_VERSION;
|
||||
bool isSaplingV4 =
|
||||
fOverwintered &&
|
||||
nVersionGroupId == SAPLING_VERSION_GROUP_ID &&
|
||||
nVersion == SAPLING_TX_VERSION;
|
||||
if (fOverwintered && !(isOverwinterV3 || isSaplingV4)) {
|
||||
throw std::ios_base::failure("Unknown transaction format");
|
||||
}
|
||||
|
||||
READWRITE(vin);
|
||||
READWRITE(vout);
|
||||
READWRITE(nLockTime);
|
||||
if (isOverwinterV3) {
|
||||
if (isOverwinterV3 || isSaplingV4) {
|
||||
READWRITE(nExpiryHeight);
|
||||
}
|
||||
if (isSaplingV4) {
|
||||
READWRITE(valueBalance);
|
||||
READWRITE(vShieldedSpend);
|
||||
READWRITE(vShieldedOutput);
|
||||
}
|
||||
if (nVersion >= 2) {
|
||||
READWRITE(vjoinsplit);
|
||||
auto os = WithVersion(&s, static_cast<int>(header));
|
||||
::SerReadWrite(os, vjoinsplit, ser_action);
|
||||
if (vjoinsplit.size() > 0) {
|
||||
READWRITE(joinSplitPubKey);
|
||||
READWRITE(joinSplitSig);
|
||||
}
|
||||
}
|
||||
if (isSaplingV4 && !(vShieldedSpend.empty() && vShieldedOutput.empty())) {
|
||||
READWRITE(bindingSig);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
CMutableTransaction(deserialize_type, Stream& s) {
|
||||
Unserialize(s);
|
||||
}
|
||||
|
||||
/** Compute the hash of this CMutableTransaction. This is computed on the
|
||||
|
||||
Reference in New Issue
Block a user