diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 85e5bb314..1ce12de65 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -20,7 +20,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, const uint256& nNonce, const std::vector& nSolution, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { // To create a genesis block for a new chain which is Overwintered: - // txNew.nVersion = 3 + // txNew.nVersion = OVERWINTER_TX_VERSION // txNew.fOverwintered = true // txNew.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID // txNew.nExpiryHeight = diff --git a/src/gtest/test_checkblock.cpp b/src/gtest/test_checkblock.cpp index 225f8ef3b..1c48046ef 100644 --- a/src/gtest/test_checkblock.cpp +++ b/src/gtest/test_checkblock.cpp @@ -154,7 +154,7 @@ TEST(ContextualCheckBlock, BlockSproutRulesRejectOverwinterTx) { mtx.vout[0].nValue = 0; mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; CTransaction tx {mtx}; @@ -251,7 +251,7 @@ TEST(ContextualCheckBlock, BlockOverwinterRulesAcceptOverwinterTx) { GetBlockSubsidy(1, Params().GetConsensus())/5, Params().GetFoundersRewardScriptAtHeight(1))); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; CTransaction tx {mtx}; @@ -350,7 +350,7 @@ TEST(ContextualCheckBlock, BlockSaplingRulesRejectOverwinterTx) { GetBlockSubsidy(1, Params().GetConsensus())/5, Params().GetFoundersRewardScriptAtHeight(1))); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; CTransaction tx {mtx}; diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index bec9cdd6f..d7527dbac 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -401,7 +401,7 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) { TEST(checktransaction_tests, OverwinterConstructors) { CMutableTransaction mtx; mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 20; @@ -432,7 +432,7 @@ TEST(checktransaction_tests, OverwinterConstructors) { TEST(checktransaction_tests, OverwinterSerialization) { CMutableTransaction mtx; mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 99; @@ -496,7 +496,7 @@ TEST(checktransaction_tests, OverwinterValidTx) { CMutableTransaction mtx = GetValidTransaction(); mtx.vjoinsplit.resize(0); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; CTransaction tx(mtx); @@ -508,7 +508,7 @@ TEST(checktransaction_tests, OverwinterExpiryHeight) { CMutableTransaction mtx = GetValidTransaction(); mtx.vjoinsplit.resize(0); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; @@ -610,7 +610,7 @@ TEST(checktransaction_tests, OverwinterBadVersionGroupId) { CMutableTransaction mtx = GetValidTransaction(); mtx.vjoinsplit.resize(0); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nExpiryHeight = 0; mtx.nVersionGroupId = 0x12345678; @@ -626,7 +626,7 @@ TEST(checktransaction_tests, OverwinterNotActive) { CMutableTransaction mtx = GetValidTransaction(); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; @@ -643,7 +643,7 @@ TEST(checktransaction_tests, OverwinterFlagNotSet) { CMutableTransaction mtx = GetValidTransaction(); mtx.fOverwintered = false; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; diff --git a/src/gtest/test_mempool.cpp b/src/gtest/test_mempool.cpp index 34bc204fa..6ee3eb1b1 100644 --- a/src/gtest/test_mempool.cpp +++ b/src/gtest/test_mempool.cpp @@ -169,7 +169,7 @@ TEST(Mempool, OverwinterNotActiveYet) { CMutableTransaction mtx = GetValidTransaction(); mtx.vjoinsplit.resize(0); // no joinsplits mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; CValidationState state1; diff --git a/src/main.cpp b/src/main.cpp index 07ed8c592..fb6196c70 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6058,7 +6058,7 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para if (isOverwintered) { mtx.fOverwintered = true; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; // Expiry height is not set. Only fields required for a parser to treat as a valid Overwinter V3 tx. // TODO: In future, when moving from Overwinter to Sapling, it will be useful diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index fb15ffeeb..74e76858a 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -22,6 +22,13 @@ #include "zcash/JoinSplit.hpp" #include "zcash/Proof.hpp" +// 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, @@ -33,26 +40,118 @@ static constexpr size_t GROTH_PROOF_SIZE = ( 48 + // π_A 96 + // π_B 48); // π_C -static constexpr size_t SPEND_DESCRIPTION_SIZE = ( - 32 + // cv - 32 + // anchor - 32 + // nullifier - 32 + // rk - GROTH_PROOF_SIZE + - 64); // spendAuthSig -static constexpr size_t OUTPUT_DESCRIPTION_SIZE = ( - 32 + // cv - 32 + // cm - 32 + // ephemeralKey - 580 + // encCiphertext - 80 + // outCiphertext - GROTH_PROOF_SIZE); namespace libzcash { typedef boost::array GrothProof; } -typedef boost::array SpendDescription; -typedef boost::array OutputDescription; + +/** + * A shielded input to a transaction. It contains data that describes a Spend transfer. + */ +class SpendDescription +{ +public: + typedef boost::array 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 + 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); + } +}; + +static constexpr size_t SAPLING_ENC_CIPHERTEXT_SIZE = ( + 1 + // leading byte + 11 + // d + 8 + // value + 32 + // rcm + ZC_MEMO_SIZE + // memo + NOTEENCRYPTION_AUTH_BYTES); + +static constexpr size_t SAPLING_OUT_CIPHERTEXT_SIZE = ( + 32 + // pkd_new + 32 + // esk + NOTEENCRYPTION_AUTH_BYTES); + +/** + * A shielded output to a transaction. It contains data that describes an Output transfer. + */ +class OutputDescription +{ +public: + typedef boost::array sapling_enc_ct_t; // TODO: Replace with actual type + typedef boost::array sapling_out_ct_t; // TODO: Replace with actual type + + 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. + sapling_enc_ct_t encCiphertext; //!< A ciphertext component for the encrypted output note. + sapling_out_ct_t 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 + 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 class SproutProofSerializer : public boost::static_visitor<> @@ -493,9 +592,10 @@ public: READWRITE(*const_cast(&this->nVersionGroupId)); } - bool isOverwinterV3 = fOverwintered && - nVersionGroupId == OVERWINTER_VERSION_GROUP_ID && - nVersion == 3; + bool isOverwinterV3 = + fOverwintered && + nVersionGroupId == OVERWINTER_VERSION_GROUP_ID && + nVersion == OVERWINTER_TX_VERSION; bool isSaplingV4 = fOverwintered && nVersionGroupId == SAPLING_VERSION_GROUP_ID && @@ -627,9 +727,10 @@ struct CMutableTransaction READWRITE(nVersionGroupId); } - bool isOverwinterV3 = fOverwintered && - nVersionGroupId == OVERWINTER_VERSION_GROUP_ID && - nVersion == 3; + bool isOverwinterV3 = + fOverwintered && + nVersionGroupId == OVERWINTER_VERSION_GROUP_ID && + nVersion == OVERWINTER_TX_VERSION; bool isSaplingV4 = fOverwintered && nVersionGroupId == SAPLING_VERSION_GROUP_ID && diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 094cd5a90..1b0b26ee7 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -542,7 +542,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity_driver) { CMutableTransaction mtx; mtx.fOverwintered = true; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); test_simple_joinsplit_invalidity(NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId, mtx); @@ -594,7 +594,7 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) { uint32_t consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId; CMutableTransaction mtx; mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; CKey key; diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 2c7e99a67..c268e6e12 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -243,7 +243,7 @@ double benchmark_large_tx(size_t nInputs) CMutableTransaction spending_tx; spending_tx.fOverwintered = true; - spending_tx.nVersion = 3; + spending_tx.nVersion = OVERWINTER_TX_VERSION; spending_tx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; auto input_hash = orig_tx.GetHash();