diff --git a/src/Makefile.am b/src/Makefile.am index 034856579..9477cd033 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -393,6 +393,7 @@ libbitcoin_common_a_SOURCES = \ netbase.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ + primitives/tx_version_info.cpp \ proof_verifier.cpp \ protocol.cpp \ pubkey.cpp \ @@ -558,6 +559,7 @@ libzcash_script_la_SOURCES = \ crypto/sha512.cpp \ hash.cpp \ primitives/transaction.cpp \ + primitives/tx_version_info.cpp \ pubkey.cpp \ script/zcash_script.cpp \ script/interpreter.cpp \ diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 8239cfc98..2263ab91b 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -425,45 +425,3 @@ std::string CTransaction::ToString() const str += " " + vout[i].ToString() + "\n"; return str; } - -/** - * Returns the most recent supported transaction version and version group id, - * as of the specified activation height and active features. - */ -TxVersionInfo CurrentTxVersionInfo( - const Consensus::Params& consensus, - int nHeight, - bool requireSprout) -{ - if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_ZFUTURE)) { - return { - .fOverwintered = true, - .nVersionGroupId = ZFUTURE_VERSION_GROUP_ID, - .nVersion = ZFUTURE_TX_VERSION - }; - } else if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_NU5) && !requireSprout) { - return { - .fOverwintered = true, - .nVersionGroupId = ZIP225_VERSION_GROUP_ID, - .nVersion = ZIP225_TX_VERSION - }; - } else if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING)) { - return { - .fOverwintered = true, - .nVersionGroupId = SAPLING_VERSION_GROUP_ID, - .nVersion = SAPLING_TX_VERSION - }; - } else if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER)) { - return { - .fOverwintered = true, - .nVersionGroupId = OVERWINTER_VERSION_GROUP_ID, - .nVersion = OVERWINTER_TX_VERSION - }; - } else { - return { - .fOverwintered = false, - .nVersionGroupId = 0, - .nVersion = CTransaction::SPROUT_MIN_CURRENT_VERSION - }; - } -} diff --git a/src/primitives/tx_version_info.cpp b/src/primitives/tx_version_info.cpp new file mode 100644 index 000000000..bdcabcb1e --- /dev/null +++ b/src/primitives/tx_version_info.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2021 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php . + +#include "primitives/transaction.h" + +/** + * Returns the most recent supported transaction version and version group id, + * as of the specified activation height and active features. + */ +TxVersionInfo CurrentTxVersionInfo( + const Consensus::Params& consensus, + int nHeight, + bool requireSprout) +{ + if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_ZFUTURE)) { + return { + .fOverwintered = true, + .nVersionGroupId = ZFUTURE_VERSION_GROUP_ID, + .nVersion = ZFUTURE_TX_VERSION + }; + } else if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_NU5) && !requireSprout) { + return { + .fOverwintered = true, + .nVersionGroupId = ZIP225_VERSION_GROUP_ID, + .nVersion = ZIP225_TX_VERSION + }; + } else if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING)) { + return { + .fOverwintered = true, + .nVersionGroupId = SAPLING_VERSION_GROUP_ID, + .nVersion = SAPLING_TX_VERSION + }; + } else if (consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER)) { + return { + .fOverwintered = true, + .nVersionGroupId = OVERWINTER_VERSION_GROUP_ID, + .nVersion = OVERWINTER_TX_VERSION + }; + } else { + return { + .fOverwintered = false, + .nVersionGroupId = 0, + .nVersion = CTransaction::SPROUT_MIN_CURRENT_VERSION + }; + } +} diff --git a/src/rust/src/orchard_ffi/incremental_sinsemilla_tree_ffi.rs b/src/rust/src/incremental_sinsemilla_tree_ffi.rs similarity index 98% rename from src/rust/src/orchard_ffi/incremental_sinsemilla_tree_ffi.rs rename to src/rust/src/incremental_sinsemilla_tree_ffi.rs index 370ae521c..37fc07c78 100644 --- a/src/rust/src/orchard_ffi/incremental_sinsemilla_tree_ffi.rs +++ b/src/rust/src/incremental_sinsemilla_tree_ffi.rs @@ -6,13 +6,13 @@ use std::mem::size_of_val; use std::ptr; use orchard::{bundle::Authorized, tree::MerkleHashOrchard}; - +use tracing::error; use zcash_primitives::{ merkle_tree::incremental::{read_frontier_v1, read_tree, write_frontier_v1, write_tree}, transaction::components::Amount, }; -use crate::orchard_ffi::{error, CppStreamReader, CppStreamWriter, ReadCb, StreamObj, WriteCb}; +use crate::streams_ffi::{CppStreamReader, CppStreamWriter, ReadCb, StreamObj, WriteCb}; pub const MERKLE_DEPTH: u8 = 32; pub const MAX_CHECKPOINTS: usize = 100; diff --git a/src/rust/src/orchard_ffi.rs b/src/rust/src/orchard_ffi.rs index 7bfea4080..dbc6649c6 100644 --- a/src/rust/src/orchard_ffi.rs +++ b/src/rust/src/orchard_ffi.rs @@ -19,8 +19,6 @@ use zcash_primitives::transaction::{ use crate::streams_ffi::{CppStreamReader, CppStreamWriter, ReadCb, StreamObj, WriteCb}; -mod incremental_sinsemilla_tree_ffi; - #[no_mangle] pub extern "C" fn orchard_bundle_clone( bundle: *const Bundle, diff --git a/src/rust/src/rustzcash.rs b/src/rust/src/rustzcash.rs index c4b1e6125..e4879d0c4 100644 --- a/src/rust/src/rustzcash.rs +++ b/src/rust/src/rustzcash.rs @@ -70,6 +70,7 @@ mod tracing_ffi; mod address_ffi; mod history_ffi; +mod incremental_sinsemilla_tree_ffi; mod orchard_ffi; mod transaction_ffi; mod zip339_ffi; diff --git a/src/script/zcash_script.cpp b/src/script/zcash_script.cpp index 9ea67fcc5..aed1e99a9 100644 --- a/src/script/zcash_script.cpp +++ b/src/script/zcash_script.cpp @@ -69,6 +69,22 @@ struct ECCryptoClosure }; ECCryptoClosure instance_of_eccryptoclosure; + +// Copy of GetLegacySigOpCount from main.cpp commit c4b2ef7c4. +// Replace with the copy from src/consensus/tx_verify.{cpp,h} after backporting that refactor. +unsigned int GetLegacySigOpCount(const CTransaction& tx) +{ + unsigned int nSigOps = 0; + for (const CTxIn& txin : tx.vin) + { + nSigOps += txin.scriptSig.GetSigOpCount(false); + } + for (const CTxOut& txout : tx.vout) + { + nSigOps += txout.scriptPubKey.GetSigOpCount(false); + } + return nSigOps; +} } struct PrecomputedTransaction { @@ -92,7 +108,7 @@ void* zcash_script_new_precomputed_tx( return nullptr; } - // Regardless of the verification result, the tx did not error. + // Deserializing the tx did not error. set_error(err, zcash_script_ERR_OK); auto preTx = new PrecomputedTransaction(tx); return preTx; @@ -166,6 +182,42 @@ int zcash_script_verify( } } +unsigned int zcash_script_legacy_sigop_count_precomputed( + const void* pre_preTx, + zcash_script_error* err) +{ + const PrecomputedTransaction* preTx = static_cast(pre_preTx); + + // The current implementation of this method never errors. + set_error(err, zcash_script_ERR_OK); + + return GetLegacySigOpCount(preTx->tx); +} + +unsigned int zcash_script_legacy_sigop_count( + const unsigned char *txTo, + unsigned int txToLen, + zcash_script_error* err) +{ + try { + TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen); + CTransaction tx; + stream >> tx; + if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen) { + set_error(err, zcash_script_ERR_TX_SIZE_MISMATCH); + return UINT_MAX; + } + + // Deserializing the tx did not error. + set_error(err, zcash_script_ERR_OK); + + return GetLegacySigOpCount(tx); + } catch (const std::exception&) { + set_error(err, zcash_script_ERR_TX_DESERIALIZE); // Error deserializing + return UINT_MAX; + } +} + unsigned int zcash_script_version() { // Just use the API version for now diff --git a/src/script/zcash_script.h b/src/script/zcash_script.h index a34963cba..d2c52b0ea 100644 --- a/src/script/zcash_script.h +++ b/src/script/zcash_script.h @@ -33,7 +33,7 @@ extern "C" { #endif -#define ZCASH_SCRIPT_API_VER 1 +#define ZCASH_SCRIPT_API_VER 2 typedef enum zcash_script_error_t { @@ -99,6 +99,28 @@ EXPORT_SYMBOL int zcash_script_verify( uint32_t consensusBranchId, zcash_script_error* err); +/// Returns the number of transparent signature operations in the +/// transparent inputs and outputs of the precomputed transaction +/// pointed to by preTx. +/// +/// Returns UINT_MAX on error, so that invalid transactions don't pass the Zcash consensus rules. +/// If not NULL, err will contain an error/success code for the operation. +EXPORT_SYMBOL unsigned int zcash_script_legacy_sigop_count_precomputed( + const void* preTx, + zcash_script_error* err); + +/// Returns the number of transparent signature operations in the +/// transparent inputs and outputs of the serialized transaction +/// pointed to by txTo. +/// +/// Returns UINT_MAX on error. +/// If not NULL, err will contain an error/success code for the operation. +EXPORT_SYMBOL unsigned int zcash_script_legacy_sigop_count( + const unsigned char *txTo, + unsigned int txToLen, + zcash_script_error* err); + +/// Returns the current version of the zcash_script library. EXPORT_SYMBOL unsigned int zcash_script_version(); #ifdef __cplusplus