// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_PRIMITIVES_TRANSACTION_H #define BITCOIN_PRIMITIVES_TRANSACTION_H #include "amount.h" #include "random.h" #include "script/script.h" #include "serialize.h" #include "uint256.h" #include "consensus/consensus.h" #ifndef __APPLE__ #include #endif #include #include "zcash/NoteEncryption.hpp" #include "zcash/Zcash.h" #include "zcash/JoinSplit.hpp" #include "zcash/Proof.hpp" class JSDescription { public: // These values 'enter from' and 'exit to' the value // pool, respectively. CAmount vpub_old; CAmount vpub_new; // JoinSplits are always anchored to a root in the note // commitment tree at some point in the blockchain // history or in the history of the current // transaction. uint256 anchor; // Nullifiers are used to prevent double-spends. They // are derived from the secrets placed in the note // and the secret spend-authority key known by the // spender. boost::array 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 commitments; // Ephemeral key uint256 ephemeralKey; // Ciphertexts // 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 ciphertexts = {{ {{0}} }}; // Random seed uint256 randomSeed; // MACs // The verification of the JoinSplit requires these MACs // to be provided as an input. boost::array macs; // JoinSplit proof // This is a zk-SNARK which ensures that this JoinSplit is valid. libzcash::ZCProof proof; JSDescription(): vpub_old(0), vpub_new(0) { } JSDescription(ZCJoinSplit& params, const uint256& pubKeyHash, const uint256& rt, const boost::array& inputs, const boost::array& outputs, CAmount vpub_old, CAmount vpub_new, bool computeProof = true // Set to false in some tests ); static JSDescription Randomized( ZCJoinSplit& params, const uint256& pubKeyHash, const uint256& rt, boost::array& inputs, boost::array& outputs, #ifdef __LP64__ boost::array& inputMap, boost::array& outputMap, #else boost::array& inputMap, boost::array& outputMap, #endif CAmount vpub_old, CAmount vpub_new, bool computeProof = true, // Set to false in some tests std::function gen = GetRandInt ); // Verifies that the JoinSplit proof is correct. bool Verify( ZCJoinSplit& params, libzcash::ProofVerifier& verifier, const uint256& pubKeyHash ) const; // Returns the calculated h_sig uint256 h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(vpub_old); READWRITE(vpub_new); READWRITE(anchor); READWRITE(nullifiers); READWRITE(commitments); READWRITE(ephemeralKey); READWRITE(randomSeed); READWRITE(macs); READWRITE(proof); READWRITE(ciphertexts); } friend bool operator==(const JSDescription& a, const JSDescription& b) { return ( a.vpub_old == b.vpub_old && a.vpub_new == b.vpub_new && a.anchor == b.anchor && a.nullifiers == b.nullifiers && a.commitments == b.commitments && a.ephemeralKey == b.ephemeralKey && a.ciphertexts == b.ciphertexts && a.randomSeed == b.randomSeed && a.macs == b.macs && a.proof == b.proof ); } friend bool operator!=(const JSDescription& a, const JSDescription& b) { return !(a == b); } }; /** An outpoint - a combination of a transaction hash and an index n into its vout */ class COutPoint { public: uint256 hash; uint32_t n; COutPoint() { SetNull(); } COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(hash); READWRITE(n); } 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) { return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); } friend bool operator==(const COutPoint& a, const COutPoint& b) { return (a.hash == b.hash && a.n == b.n); } friend bool operator!=(const COutPoint& a, const COutPoint& b) { return !(a == b); } std::string ToString() const; }; /** An input of a transaction. It contains the location of the previous * transaction's output that it claims and a signature that matches the * output's public key. */ class CTxIn { public: COutPoint prevout; CScript scriptSig; uint32_t nSequence; CTxIn() { nSequence = std::numeric_limits::max(); } explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits::max()); CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits::max()); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(prevout); READWRITE(scriptSig); READWRITE(nSequence); } bool IsFinal() const { return (nSequence == std::numeric_limits::max()); } friend bool operator==(const CTxIn& a, const CTxIn& b) { return (a.prevout == b.prevout && a.scriptSig == b.scriptSig && a.nSequence == b.nSequence); } friend bool operator!=(const CTxIn& a, const CTxIn& b) { return !(a == b); } std::string ToString() const; }; /** 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; CScript scriptPubKey; uint64_t interest; CTxOut() { SetNull(); } CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(nValue); READWRITE(scriptPubKey); } void SetNull() { nValue = -1; scriptPubKey.clear(); } bool IsNull() const { return (nValue == -1); } uint256 GetHash() const; CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const { // "Dust" is defined in terms of CTransaction::minRelayTxFee, // which has units satoshis-per-kilobyte. // If you'd pay more than 1/3 in fees // to spend something, then we consider it dust. // A typical spendable txout is 34 bytes big, and will // need a CTxIn of at least 148 bytes to spend: // so dust is a spendable txout less than 54 satoshis // with default minRelayTxFee. if (scriptPubKey.IsUnspendable()) return 0; size_t nSize = GetSerializeSize(SER_DISK,0)+148u; return 3*minRelayTxFee.GetFee(nSize); } bool IsDust(const CFeeRate &minRelayTxFee) const { return (nValue < GetDustThreshold(minRelayTxFee)); } friend bool operator==(const CTxOut& a, const CTxOut& b) { return (a.nValue == b.nValue && a.scriptPubKey == b.scriptPubKey); } friend bool operator!=(const CTxOut& a, const CTxOut& b) { return !(a == b); } std::string ToString() const; }; struct CMutableTransaction; /** The basic transaction that is broadcasted on the network and contained in * blocks. A transaction can contain multiple inputs and outputs. */ class CTransaction { private: /** Memory only. */ const uint256 hash; void UpdateHash() const; public: typedef boost::array joinsplit_sig_t; // Transactions that include a list of JoinSplits are version 2. static const int32_t MIN_CURRENT_VERSION = 1; static const int32_t MAX_CURRENT_VERSION = 2; static_assert(MIN_CURRENT_VERSION >= MIN_TX_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, // and bypass the constness. This is safe, as they update the entire // structure, including the hash. const int32_t nVersion; const std::vector vin; const std::vector vout; const uint32_t nLockTime; const std::vector vjoinsplit; const uint256 joinSplitPubKey; const joinsplit_sig_t joinSplitSig = {{0}}; /** Construct a CTransaction that qualifies as IsNull() */ CTransaction(); /** Convert a CMutableTransaction into a CTransaction. */ CTransaction(const CMutableTransaction &tx); CTransaction& operator=(const CTransaction& tx); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(*const_cast(&this->nVersion)); nVersion = this->nVersion; READWRITE(*const_cast*>(&vin)); READWRITE(*const_cast*>(&vout)); READWRITE(*const_cast(&nLockTime)); if (nVersion >= 2) { READWRITE(*const_cast*>(&vjoinsplit)); if (vjoinsplit.size() > 0) { READWRITE(*const_cast(&joinSplitPubKey)); READWRITE(*const_cast(&joinSplitSig)); } } if (ser_action.ForRead()) UpdateHash(); } bool IsNull() const { return vin.empty() && vout.empty(); } const uint256& GetHash() const { return hash; } // Return sum of txouts. 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; // Compute priority, given priority of inputs and (optionally) tx size double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const; // Compute modified tx size for priority calculation (optionally given tx size) unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; bool IsCoinBase() const { return (vin.size() == 1 && vin[0].prevout.IsNull()); } friend bool operator==(const CTransaction& a, const CTransaction& b) { return a.hash == b.hash; } friend bool operator!=(const CTransaction& a, const CTransaction& b) { return a.hash != b.hash; } std::string ToString() const; }; /** A mutable version of CTransaction. */ struct CMutableTransaction { int32_t nVersion; std::vector vin; std::vector vout; uint32_t nLockTime; std::vector vjoinsplit; uint256 joinSplitPubKey; CTransaction::joinsplit_sig_t joinSplitSig = {{0}}; CMutableTransaction(); CMutableTransaction(const CTransaction& tx); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(vin); READWRITE(vout); READWRITE(nLockTime); if (nVersion >= 2) { READWRITE(vjoinsplit); if (vjoinsplit.size() > 0) { READWRITE(joinSplitPubKey); READWRITE(joinSplitSig); } } } /** Compute the hash of this CMutableTransaction. This is computed on the * fly, as opposed to GetHash() in CTransaction, which uses a cached result. */ uint256 GetHash() const; }; #endif // BITCOIN_PRIMITIVES_TRANSACTION_H