Merge branch 'beta' into mergemaster

# Conflicts:
#	src/main.cpp
This commit is contained in:
jl777
2018-04-16 10:16:01 +03:00
parent 9226f69ef1
commit e73b2055c6
910 changed files with 112009 additions and 11364 deletions

View File

@@ -1,15 +1,30 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "crypto/common.h"
#include "pubkey.h"
#include "zcash/JoinSplit.hpp"
#include "util.h"
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
struct ECCryptoClosure
{
ECCVerifyHandle handle;
};
ECCryptoClosure instance_of_eccryptoclosure;
ZCJoinSplit* params;
int main(int argc, char **argv) {
assert(init_and_check_sodium() != -1);
libsnark::default_r1cs_ppzksnark_pp::init_public_params();
libsnark::inhibit_profiling_info = true;
libsnark::inhibit_profiling_counters = true;
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
params = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -33,6 +33,40 @@ TEST(CheckBlock, VersionTooLow) {
EXPECT_FALSE(CheckBlock(0,0,block, state, verifier, false, false));
}
// Test that a Sprout tx with negative version is still rejected
// by CheckBlock under Sprout consensus rules.
TEST(CheckBlock, BlockSproutRejectsBadVersion) {
SelectParams(CBaseChainParams::MAIN);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
mtx.fOverwintered = false;
mtx.nVersion = -1;
mtx.nVersionGroupId = 0;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
auto verifier = libzcash::ProofVerifier::Strict();
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1);
EXPECT_FALSE(CheckBlock(block, state, verifier, false, false));
}
TEST(ContextualCheckBlock, BadCoinbaseHeight) {
SelectParams(CBaseChainParams::MAIN);
@@ -75,3 +109,125 @@ TEST(ContextualCheckBlock, BadCoinbaseHeight) {
block.vtx[0] = tx4;
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
}
// Test that a block evaluated under Sprout rules cannot contain Overwinter transactions.
// This test assumes that mainnet Overwinter activation is at least height 2.
TEST(ContextualCheckBlock, BlockSproutRulesRejectOverwinterTx) {
SelectParams(CBaseChainParams::MAIN);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1);
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
}
// Test block evaluated under Sprout rules will accept Sprout transactions
TEST(ContextualCheckBlock, BlockSproutRulesAcceptSproutTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
mtx.fOverwintered = false;
mtx.nVersion = 1;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test block evaluated under Overwinter rules will accept Overwinter transactions
TEST(ContextualCheckBlock, BlockOverwinterRulesAcceptOverwinterTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test block evaluated under Overwinter rules will reject Sprout transactions
TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSproutTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.nVersion = 2;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-active", false)).Times(1);
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}

View File

@@ -45,6 +45,8 @@ public:
CMutableTransaction GetValidTransaction() {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CMutableTransaction mtx;
mtx.vin.resize(2);
mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
@@ -74,7 +76,7 @@ CMutableTransaction GetValidTransaction() {
// Empty output script.
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
if (dataToBeSigned == one) {
throw std::runtime_error("SignatureHash failed");
}
@@ -352,23 +354,27 @@ TEST(checktransaction_tests, bad_txns_prevout_null) {
}
TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction();
mtx.joinSplitSig[0] += 1;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
ContextualCheckTransaction(tx, state, 0, 100);
}
TEST(checktransaction_tests, non_canonical_ed25519_signature) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction();
// Check that the signature is valid before we add L
{
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
EXPECT_TRUE(ContextualCheckTransaction(tx, state, 0, 100));
}
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c
@@ -389,5 +395,380 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) {
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
ContextualCheckTransaction(tx, state, 0, 100);
}
TEST(checktransaction_tests, OverwinterConstructors) {
CMutableTransaction mtx;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 20;
// Check constructor with overwinter fields
CTransaction tx(mtx);
EXPECT_EQ(tx.nVersion, mtx.nVersion);
EXPECT_EQ(tx.fOverwintered, mtx.fOverwintered);
EXPECT_EQ(tx.nVersionGroupId, mtx.nVersionGroupId);
EXPECT_EQ(tx.nExpiryHeight, mtx.nExpiryHeight);
// Check constructor of mutable transaction struct
CMutableTransaction mtx2(tx);
EXPECT_EQ(mtx2.nVersion, mtx.nVersion);
EXPECT_EQ(mtx2.fOverwintered, mtx.fOverwintered);
EXPECT_EQ(mtx2.nVersionGroupId, mtx.nVersionGroupId);
EXPECT_EQ(mtx2.nExpiryHeight, mtx.nExpiryHeight);
EXPECT_TRUE(mtx2.GetHash() == mtx.GetHash());
// Check assignment of overwinter fields
CTransaction tx2 = tx;
EXPECT_EQ(tx2.nVersion, mtx.nVersion);
EXPECT_EQ(tx2.fOverwintered, mtx.fOverwintered);
EXPECT_EQ(tx2.nVersionGroupId, mtx.nVersionGroupId);
EXPECT_EQ(tx2.nExpiryHeight, mtx.nExpiryHeight);
EXPECT_TRUE(tx2 == tx);
}
TEST(checktransaction_tests, OverwinterSerialization) {
CMutableTransaction mtx;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 99;
// Check round-trip serialization and deserialization from mtx to tx.
{
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << mtx;
CTransaction tx;
ss >> tx;
EXPECT_EQ(mtx.nVersion, tx.nVersion);
EXPECT_EQ(mtx.fOverwintered, tx.fOverwintered);
EXPECT_EQ(mtx.nVersionGroupId, tx.nVersionGroupId);
EXPECT_EQ(mtx.nExpiryHeight, tx.nExpiryHeight);
EXPECT_EQ(mtx.GetHash(), CMutableTransaction(tx).GetHash());
EXPECT_EQ(tx.GetHash(), CTransaction(mtx).GetHash());
}
// Also check mtx to mtx
{
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << mtx;
CMutableTransaction mtx2;
ss >> mtx2;
EXPECT_EQ(mtx.nVersion, mtx2.nVersion);
EXPECT_EQ(mtx.fOverwintered, mtx2.fOverwintered);
EXPECT_EQ(mtx.nVersionGroupId, mtx2.nVersionGroupId);
EXPECT_EQ(mtx.nExpiryHeight, mtx2.nExpiryHeight);
EXPECT_EQ(mtx.GetHash(), mtx2.GetHash());
}
// Also check tx to tx
{
CTransaction tx(mtx);
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << tx;
CTransaction tx2;
ss >> tx2;
EXPECT_EQ(tx.nVersion, tx2.nVersion);
EXPECT_EQ(tx.fOverwintered, tx2.fOverwintered);
EXPECT_EQ(tx.nVersionGroupId, tx2.nVersionGroupId);
EXPECT_EQ(tx.nExpiryHeight, tx2.nExpiryHeight);
EXPECT_EQ(mtx.GetHash(), CMutableTransaction(tx).GetHash());
EXPECT_EQ(tx.GetHash(), tx2.GetHash());
}
}
TEST(checktransaction_tests, OverwinterDefaultValues) {
// Check default values (this will fail when defaults change; test should then be updated)
CTransaction tx;
EXPECT_EQ(tx.nVersion, 1);
EXPECT_EQ(tx.fOverwintered, false);
EXPECT_EQ(tx.nVersionGroupId, 0);
EXPECT_EQ(tx.nExpiryHeight, 0);
}
// A valid v3 transaction with no joinsplits
TEST(checktransaction_tests, OverwinterValidTx) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
TEST(checktransaction_tests, OverwinterExpiryHeight) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
{
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
{
mtx.nExpiryHeight = TX_EXPIRY_HEIGHT_THRESHOLD - 1;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
{
mtx.nExpiryHeight = TX_EXPIRY_HEIGHT_THRESHOLD;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-expiry-height-too-high", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
{
mtx.nExpiryHeight = std::numeric_limits<uint32_t>::max();
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-expiry-height-too-high", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
}
// Test that a Sprout tx with a negative version number is detected
// given the new Overwinter logic
TEST(checktransaction_tests, SproutTxVersionTooLow) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = false;
mtx.nVersion = -1;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
// Subclass of CTransaction which doesn't call UpdateHash when constructing
// from a CMutableTransaction. This enables us to create a CTransaction
// with bad values which normally trigger an exception during construction.
class UNSAFE_CTransaction : public CTransaction {
public:
UNSAFE_CTransaction(const CMutableTransaction &tx) : CTransaction(tx, true) {}
};
// Test bad Overwinter version number in CheckTransactionWithoutProofVerification
TEST(checktransaction_tests, OverwinterVersionNumberLow) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = OVERWINTER_MIN_TX_VERSION - 1;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
UNSAFE_CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-overwinter-version-too-low", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
// Test bad Overwinter version number in ContextualCheckTransaction
TEST(checktransaction_tests, OverwinterVersionNumberHigh) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = OVERWINTER_MAX_TX_VERSION + 1;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
UNSAFE_CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-overwinter-version-too-high", false)).Times(1);
ContextualCheckTransaction(tx, state, 1, 100);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test bad Overwinter version group id
TEST(checktransaction_tests, OverwinterBadVersionGroupId) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nExpiryHeight = 0;
mtx.nVersionGroupId = 0x12345678;
UNSAFE_CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-version-group-id", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
// This tests an Overwinter transaction checked against Sprout
TEST(checktransaction_tests, OverwinterNotActive) {
SelectParams(CBaseChainParams::TESTNET);
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1);
ContextualCheckTransaction(tx, state, 1, 100);
}
// This tests a transaction without the fOverwintered flag set, against the Overwinter consensus rule set.
TEST(checktransaction_tests, OverwinterFlagNotSet) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = false;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-flag-not-set", false)).Times(1);
ContextualCheckTransaction(tx, state, 1, 100);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Overwinter (NU0) does not allow soft fork to version 4 Overwintered tx.
TEST(checktransaction_tests, OverwinterInvalidSoftForkVersion) {
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = true;
mtx.nVersion = 4; // This is not allowed
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
try {
ss << mtx;
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format'";
}
catch(std::ios_base::failure & err) {
EXPECT_THAT(err.what(), testing::HasSubstr(std::string("Unknown transaction format")));
}
catch(...) {
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format', got some other exception";
}
}
// Test CreateNewContextualCMutableTransaction sets default values based on height
TEST(checktransaction_tests, OverwinteredContextualCreateTx) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& consensusParams = Params().GetConsensus();
int activationHeight = 5;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, activationHeight);
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, activationHeight - 1);
EXPECT_EQ(mtx.nVersion, 1);
EXPECT_EQ(mtx.fOverwintered, false);
EXPECT_EQ(mtx.nVersionGroupId, 0);
EXPECT_EQ(mtx.nExpiryHeight, 0);
}
// Overwinter activates
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, activationHeight );
EXPECT_EQ(mtx.nVersion, 3);
EXPECT_EQ(mtx.fOverwintered, true);
EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID);
EXPECT_EQ(mtx.nExpiryHeight, 0);
}
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test a v1 transaction which has a malformed header, perhaps modified in-flight
TEST(checktransaction_tests, BadTxReceivedOverNetwork)
{
// First four bytes <01 00 00 00> have been modified to be <FC FF FF FF> (-4 as an int32)
std::string goodPrefix = "01000000";
std::string badPrefix = "fcffffff";
std::string hexTx = "0176c6541939b95f8d8b7779a77a0863b2a0267e281a050148326f0ea07c3608fb000000006a47304402207c68117a6263486281af0cc5d3bee6db565b6dce19ffacc4cb361906eece82f8022007f604382dee2c1fde41c4e6e7c1ae36cfa28b5b27350c4bfaa27f555529eace01210307ff9bef60f2ac4ceb1169a9f7d2c773d6c7f4ab6699e1e5ebc2e0c6d291c733feffffff02c0d45407000000001976a9145eaaf6718517ec8a291c6e64b16183292e7011f788ac5ef44534000000001976a91485e12fb9967c96759eae1c6b1e9c07ce977b638788acbe000000";
// Good v1 tx
{
std::vector<unsigned char> txData(ParseHex(goodPrefix + hexTx ));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
ssData >> tx;
EXPECT_EQ(tx.nVersion, 1);
EXPECT_EQ(tx.fOverwintered, false);
}
// Good v1 mutable tx
{
std::vector<unsigned char> txData(ParseHex(goodPrefix + hexTx ));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CMutableTransaction mtx;
ssData >> mtx;
EXPECT_EQ(mtx.nVersion, 1);
}
// Bad tx
{
std::vector<unsigned char> txData(ParseHex(badPrefix + hexTx ));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
try {
CTransaction tx;
ssData >> tx;
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format'";
}
catch(std::ios_base::failure & err) {
EXPECT_THAT(err.what(), testing::HasSubstr(std::string("Unknown transaction format")));
}
catch(...) {
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format', got some other exception";
}
}
// Bad mutable tx
{
std::vector<unsigned char> txData(ParseHex(badPrefix + hexTx ));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
try {
CMutableTransaction mtx;
ssData >> mtx;
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format'";
}
catch(std::ios_base::failure & err) {
EXPECT_THAT(err.what(), testing::HasSubstr(std::string("Unknown transaction format")));
}
catch(...) {
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format', got some other exception";
}
}
}

View File

@@ -7,10 +7,11 @@
#include <boost/format.hpp>
#include <boost/optional.hpp>
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp"
#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp>
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
#include "zcash/IncrementalMerkleTree.hpp"
using namespace libsnark;

View File

@@ -0,0 +1,122 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "clientversion.h"
#include "deprecation.h"
#include "init.h"
#include "ui_interface.h"
#include "util.h"
#include "chainparams.h"
using ::testing::StrictMock;
static const std::string CLIENT_VERSION_STR = FormatVersion(CLIENT_VERSION);
extern std::atomic<bool> fRequestShutdown;
class MockUIInterface {
public:
MOCK_METHOD3(ThreadSafeMessageBox, bool(const std::string& message,
const std::string& caption,
unsigned int style));
};
static bool ThreadSafeMessageBox(MockUIInterface *mock,
const std::string& message,
const std::string& caption,
unsigned int style)
{
return mock->ThreadSafeMessageBox(message, caption, style);
}
class DeprecationTest : public ::testing::Test {
protected:
virtual void SetUp() {
uiInterface.ThreadSafeMessageBox.disconnect_all_slots();
uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, &mock_, _1, _2, _3));
SelectParams(CBaseChainParams::MAIN);
}
virtual void TearDown() {
fRequestShutdown = false;
mapArgs.clear();
}
StrictMock<MockUIInterface> mock_;
};
TEST_F(DeprecationTest, NonDeprecatedNodeKeepsRunning) {
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT - 1);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, NodeNearDeprecationIsWarned) {
EXPECT_FALSE(ShutdownRequested());
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_WARNING));
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, NodeNearDeprecationWarningIsNotDuplicated) {
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT + 1);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, NodeNearDeprecationWarningIsRepeatedOnStartup) {
EXPECT_FALSE(ShutdownRequested());
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_WARNING));
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT + 1, true);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeShutsDown) {
EXPECT_FALSE(ShutdownRequested());
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR));
EnforceNodeDeprecation(DEPRECATION_HEIGHT);
EXPECT_TRUE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeErrorIsNotDuplicated) {
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT + 1);
EXPECT_TRUE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeErrorIsRepeatedOnStartup) {
EXPECT_FALSE(ShutdownRequested());
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR));
EnforceNodeDeprecation(DEPRECATION_HEIGHT + 1, true);
EXPECT_TRUE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeShutsDownIfOldVersionDisabled) {
EXPECT_FALSE(ShutdownRequested());
mapArgs["-disabledeprecation"] = "1.0.0";
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR));
EnforceNodeDeprecation(DEPRECATION_HEIGHT);
EXPECT_TRUE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeKeepsRunningIfCurrentVersionDisabled) {
EXPECT_FALSE(ShutdownRequested());
mapArgs["-disabledeprecation"] = CLIENT_VERSION_STR;
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR));
EnforceNodeDeprecation(DEPRECATION_HEIGHT);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeIgnoredOnRegtest) {
SelectParams(CBaseChainParams::REGTEST);
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT+1);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeIgnoredOnTestnet) {
SelectParams(CBaseChainParams::TESTNET);
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT+1);
EXPECT_FALSE(ShutdownRequested());
}

View File

@@ -81,6 +81,8 @@ TEST(founders_reward_test, create_testnet_2of3multisig) {
std::cout << s << std::endl;
pWallet->Flush(true);
ECC_Stop();
}
#endif

View File

@@ -0,0 +1,62 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "httprpc.cpp"
#include "httpserver.h"
using ::testing::Return;
class MockHTTPRequest : public HTTPRequest {
public:
MOCK_METHOD0(GetPeer, CService());
MOCK_METHOD0(GetRequestMethod, HTTPRequest::RequestMethod());
MOCK_METHOD1(GetHeader, std::pair<bool, std::string>(const std::string& hdr));
MOCK_METHOD2(WriteHeader, void(const std::string& hdr, const std::string& value));
MOCK_METHOD2(WriteReply, void(int nStatus, const std::string& strReply));
MockHTTPRequest() : HTTPRequest(nullptr) {}
void CleanUp() {
// So the parent destructor doesn't try to send a reply
replySent = true;
}
};
TEST(HTTPRPC, FailsOnGET) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::GET));
EXPECT_CALL(req, WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests"))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}
TEST(HTTPRPC, FailsWithoutAuthHeader) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::POST));
EXPECT_CALL(req, GetHeader("authorization"))
.WillRepeatedly(Return(std::make_pair(false, "")));
EXPECT_CALL(req, WriteHeader("WWW-Authenticate", "Basic realm=\"jsonrpc\""))
.Times(1);
EXPECT_CALL(req, WriteReply(HTTP_UNAUTHORIZED, ""))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}
TEST(HTTPRPC, FailsWithBadAuth) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::POST));
EXPECT_CALL(req, GetHeader("authorization"))
.WillRepeatedly(Return(std::make_pair(true, "Basic spam:eggs")));
EXPECT_CALL(req, GetPeer())
.WillRepeatedly(Return(CService("127.0.0.1:1337")));
EXPECT_CALL(req, WriteHeader("WWW-Authenticate", "Basic realm=\"jsonrpc\""))
.Times(1);
EXPECT_CALL(req, WriteReply(HTTP_UNAUTHORIZED, ""))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}

View File

@@ -5,6 +5,7 @@
#include <boost/foreach.hpp>
#include "zcash/prf.h"
#include "util.h"
#include "zcash/JoinSplit.hpp"
#include "zcash/Note.hpp"
@@ -13,6 +14,8 @@
using namespace libzcash;
extern ZCJoinSplit* params;
void test_full_api(ZCJoinSplit* js)
{
// Create verification context.
@@ -86,7 +89,7 @@ void test_full_api(ZCJoinSplit* js)
// Recipient should decrypt
// Now the recipient should spend the money again
auto h_sig = js->h_sig(randomSeed, nullifiers, pubKeyHash);
ZCNoteDecryption decryptor(recipient_key.viewing_key());
ZCNoteDecryption decryptor(recipient_key.receiving_key());
auto note_pt = NotePlaintext::decrypt(
decryptor,
@@ -219,8 +222,6 @@ void invokeAPIFailure(
TEST(joinsplit, h_sig)
{
auto js = ZCJoinSplit::Unopened();
/*
// by Taylor Hornby
@@ -284,7 +285,7 @@ for test_input in TEST_VECTORS:
};
BOOST_FOREACH(std::vector<std::string>& v, tests) {
auto expected = js->h_sig(
auto expected = ZCJoinSplit::h_sig(
uint256S(v[0]),
{uint256S(v[1]), uint256S(v[2])},
uint256S(v[3])
@@ -292,8 +293,6 @@ for test_input in TEST_VECTORS:
EXPECT_EQ(expected, uint256S(v[4]));
}
delete js;
}
void increment_note_witnesses(
@@ -311,8 +310,6 @@ void increment_note_witnesses(
TEST(joinsplit, full_api_test)
{
auto js = ZCJoinSplit::Generate();
{
std::vector<ZCIncrementalWitness> witnesses;
ZCIncrementalMerkleTree tree;
@@ -331,7 +328,7 @@ TEST(joinsplit, full_api_test)
increment_note_witnesses(note5.cm(), witnesses, tree);
// Should work
invokeAPI(js,
invokeAPI(params,
{
JSInput(),
JSInput()
@@ -345,7 +342,7 @@ TEST(joinsplit, full_api_test)
tree.root());
// lhs > MAX_MONEY
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -360,7 +357,7 @@ TEST(joinsplit, full_api_test)
"nonsensical vpub_old value");
// rhs > MAX_MONEY
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -375,7 +372,7 @@ TEST(joinsplit, full_api_test)
"nonsensical vpub_new value");
// input witness for the wrong element
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[0], note1, sk),
JSInput()
@@ -391,7 +388,7 @@ TEST(joinsplit, full_api_test)
// input witness doesn't match up with
// real root
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[1], note1, sk),
JSInput()
@@ -406,7 +403,7 @@ TEST(joinsplit, full_api_test)
"joinsplit not anchored to the correct root");
// input is in the tree now! this should work
invokeAPI(js,
invokeAPI(params,
{
JSInput(witnesses[1], note1, sk),
JSInput()
@@ -420,7 +417,7 @@ TEST(joinsplit, full_api_test)
tree.root());
// Wrong secret key
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[1], note1, SpendingKey::random()),
JSInput()
@@ -435,7 +432,7 @@ TEST(joinsplit, full_api_test)
"input note not authorized to spend with given key");
// Absurd input value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[3], note3, sk),
JSInput()
@@ -450,7 +447,7 @@ TEST(joinsplit, full_api_test)
"nonsensical input note value");
// Absurd total input value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[4], note4, sk),
JSInput(witnesses[5], note5, sk)
@@ -465,7 +462,7 @@ TEST(joinsplit, full_api_test)
"nonsensical left hand size of joinsplit balance");
// Absurd output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -480,7 +477,7 @@ TEST(joinsplit, full_api_test)
"nonsensical output value");
// Absurd total output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -495,7 +492,7 @@ TEST(joinsplit, full_api_test)
"nonsensical right hand side of joinsplit balance");
// Absurd total output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -510,22 +507,7 @@ TEST(joinsplit, full_api_test)
"invalid joinsplit balance");
}
test_full_api(js);
js->saveProvingKey("./zcashTest.pk");
js->saveVerifyingKey("./zcashTest.vk");
delete js;
js = ZCJoinSplit::Unopened();
js->setProvingKeyPath("./zcashTest.pk");
js->loadProvingKey();
js->loadVerifyingKey("./zcashTest.vk");
test_full_api(js);
delete js;
test_full_api(params);
}
TEST(joinsplit, note_plaintexts)

View File

@@ -43,7 +43,64 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) {
keyStore.AddSpendingKey(sk);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
}
TEST(keystore_tests, StoreAndRetrieveViewingKey) {
CBasicKeyStore keyStore;
libzcash::ViewingKey vkOut;
libzcash::SpendingKey skOut;
ZCNoteDecryption decOut;
auto sk = libzcash::SpendingKey::random();
auto vk = sk.viewing_key();
auto addr = sk.address();
// Sanity-check: we can't get a viewing key we haven't added
EXPECT_FALSE(keyStore.HaveViewingKey(addr));
EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut));
// and we shouldn't have a spending key or decryptor either
EXPECT_FALSE(keyStore.HaveSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut));
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
// and we can't find it in our list of addresses
std::set<libzcash::PaymentAddress> addresses;
keyStore.GetPaymentAddresses(addresses);
EXPECT_FALSE(addresses.count(addr));
keyStore.AddViewingKey(vk);
EXPECT_TRUE(keyStore.HaveViewingKey(addr));
EXPECT_TRUE(keyStore.GetViewingKey(addr, vkOut));
EXPECT_EQ(vk, vkOut);
// We should still not have the spending key...
EXPECT_FALSE(keyStore.HaveSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut));
// ... but we should have a decryptor
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
// ... and we should find it in our list of addresses
addresses.clear();
keyStore.GetPaymentAddresses(addresses);
EXPECT_TRUE(addresses.count(addr));
keyStore.RemoveViewingKey(vk);
EXPECT_FALSE(keyStore.HaveViewingKey(addr));
EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut));
EXPECT_FALSE(keyStore.HaveSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut));
addresses.clear();
keyStore.GetPaymentAddresses(addresses);
EXPECT_FALSE(addresses.count(addr));
// We still have a decryptor because those are cached in memory
// (and also we only remove viewing keys when adding a spending key)
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
}
#ifdef ENABLE_WALLET
@@ -72,13 +129,13 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut));
ASSERT_EQ(sk, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey));
ASSERT_TRUE(keyStore.HaveSpendingKey(addr));
ASSERT_FALSE(keyStore.GetSpendingKey(addr, keyOut));
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
// Unlocking with a random key should fail
uint256 r2 {GetRandHash()};
@@ -109,19 +166,19 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut));
ASSERT_EQ(sk2, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
ASSERT_TRUE(keyStore.Lock());
ASSERT_TRUE(keyStore.HaveSpendingKey(addr2));
ASSERT_FALSE(keyStore.GetSpendingKey(addr2, keyOut));
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
ASSERT_TRUE(keyStore.Unlock(vMasterKey));
ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut));
ASSERT_EQ(sk2, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
keyStore.GetPaymentAddresses(addrs);
ASSERT_EQ(2, addrs.size());

View File

@@ -1,89 +1,263 @@
#include <gtest/gtest.h>
#include <gtest/gtest-spi.h>
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "main.h"
#include "primitives/transaction.h"
#include "txmempool.h"
#include "policy/fees.h"
#include "util.h"
// Implementation is in test_checktransaction.cpp
extern CMutableTransaction GetValidTransaction();
// Fake the input of transaction 5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364
// - 532639cc6bebed47c1c69ae36dd498c68a012e74ad12729adbd3dbb56f8f3f4a, 0
class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf) const {
return false;
}
bool GetCoins(const uint256 &txid, CCoins &coins) const {
CTxOut txOut;
txOut.nValue = 4288035;
CCoins newCoins;
newCoins.vout.resize(2);
newCoins.vout[0] = txOut;
newCoins.nHeight = 92045;
coins.swap(newCoins);
return true;
}
bool HaveCoins(const uint256 &txid) const {
return true;
}
uint256 GetBestBlock() const {
uint256 a;
return a;
}
uint256 GetBestAnchor() const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
return false;
}
bool GetStats(CCoinsStats &stats) const {
return false;
}
};
TEST(Mempool, PriorityStatsDoNotCrash) {
// Test for security issue 2017-04-11.a
// https://z.cash/blog/security-announcement-2017-04-12.html
// Trigger transaction in block 92046
std::string triggerTx = "02000000014a3f8f6fb5dbd3db9a7212ad742e018ac698d46de39ac6c147edeb6bcc392653000000006b483045022100da0514afd80d3bbd0743458efe3b2abd18f727b4268b124c3885094c26ea09cd02207d37d7934ec90618fc5a345cb2a6d1755d8b1a432ea1df517a85e36628449196012103e9b41072e9d2cbe04e6b22a6ac4862ec3f5a76b3823b071ded0dfd5455a0803fffffffff000000000001236e4100000000000000000000000000cf592f6776810cf9fb961d80e683f5529a6b34894b00446c396022512a02dc2e96918294bffdc988a2627d9b12a9f3176b671e286fc62e3c7441cf35ea5e03d561bd5817ca5827cb2761f88dde280a6da5281af2cc69053816f31abd2170722f72c258c7c6b865c97ff8ae53b697f3b77c239a73e1d0296c2c73d21c3b50059d82866cf9f6e2f5dbbf9b4de9caa3cf836080373311978e1f1b1150ce564336ebf0fd502c2e783ff23252fba4efbb110c28c4fbe31efb6a67bc24c0ad8fd8346c5c9ed1791b555b3e43a309aa8d855a294847368ebdf30365d4dfa9b25dd8ed7adf272ecc08f4756fb9d93b8e20d45548dd4aeab6abb76a2081b6e36a9af9d38ebae378df422f40589769c07a3c12e5da253330314cbc4beaa863fac7ab10055d0310089a44c45179a39b2c4e210cec2e053f54983d744abed49f66959f45785ea90325a310fba15f946e245a0e64caec303f2a3e1d457e3e3ca5d892956c1a93b05e0b0373cf862d7bbb5908148b475c03eec96c9b9ecc7d2d78716d2c2e8ccf96175b25738dfb5b0d356a7e30604ee014c6be1db5e43af0fa6ad3f4e917a9f84b4d6f030cad0ffe0738e1effe570b0552b407ca9c26023b74b99f431cc28b79116f717703158404e343b1b47a0556f593441dc64758930f19e84d5ee468fd9a7958c6c63503054f60680f7147e88bf6da65415450230ef7437481023fc5d94872d5aa18bf3b0212b4c0d938e6c84debb8a4e65f99970c59193873a72b2440f19a652073abd960021bfef4e1e52b8f353c6e517bb97053afd4c8035defc27c3fd16faba5bc924a4179f69cfdcdb82253b5f6472a99d4b78ad2c6c18c45ed4dda5bf2adc019c99b55702f4e7b3fcaeb6f3b84ad411d36e901cba9d49ac1d6b916aa88794fb23501aeb0c585cbc2bed952846f41a03bd5c74dfe004e7ac21f7a20d32b009ccf6f70b3e577d25c679421225522b6290d5fa00a5d9a02b97a62aab60e040a03efa946d87c5e65dbf10d66df5b0834c262c31c23f3c2643451e614695003fb3a95bf21444bebb45cdcb8169245e34a76f754c89c3a90f36598a71ef4645eef4c82f1fb322536097fcf0cbe061e80ae887dbb88d8ed910be9ef18b8794930addab1a140b16c4b50f93926b1e5df03ee6e4b5ec6d7f0ed49fbbae50330ae94c5ae9182f4b58870022e423e7d80adccdb90680f7a7fe11a4ed4fe005a0af2d22bf9e7d1bef7caf4f37f5777e4aa6c9b9ea44f5973575c20fb3482fe357c19fc0c20594f492f5694e3e8eb3599e968fd23b5bdd6c4bf5aee1374b38aafe59dd5af83011e642a9427b5ff03e7a4cce92ee201a0fac0acb69d6ad3b7e4c26dfefaa53a737889e759c4b5695c1a7fd5d988e531acf66dae5067f252a25a102d92916b2d84c730645e15a78d3dce1c787634f6f7323cb949a5b6ad004e208cb8c6b734761629c13b9974dc80b082f83357f3bc703d835acbbf72aba225ffe69396c151d2646fac9bd1acc184dd047ebfaadc6b60a9185ce80c7bc8ac5dbb2219cbc0d35af91673b95d28335f0ee2774b8084871d54ca8eab3a285e4b4adf3f34b4263d67474bb5de2e1e37aa7a4ecbd5b49575caaa9e7208c2b9871946b11f2c54cd1ca7660dff44cf206e7da46ab57dd49ec0aa06ded7980f1557cc7c84023690b4df77f26d6b4eff7553b9a8628c28e8e5c38c6170bc61af0969b072586fa740f68ab33c0f62d0507cc8fe41c680b2f077e49cc2691048006311b46cd5ed18e63089f11c115b797ed5fbcd86836a4da2ab90a00745077f2f13bc9e390fc2f92b941d4fb70a3f098548953566141670317fc17e0ba81e98b8a94919992fb008c5480f4018f3a1ea673fe94a6ba3363656a944855d7c799ccb73d95d4ed6ce04c26f79c4cf79f883f0f810519f28eabe8cf6d833f24227f5074763c7b80f1431e5463cc07eff2f1d6cbfaf0411d38e62528a39b093ed7b51fa8c1008e5c1ce4bf39e67b1703554cefef44b71457bfddf43d23a54fa0145fa0e716d02a5304d85345a2b4ebf98c5010d0df468c8cbfc2db22083b0f5a74d4324ee74b46daa5ab70f2575ef5390e6aa2acb8d3b3eb2065e8c06fd6276aca283f5850e7a8b4da37455430df55621e4af59bb355ba2db0ac6cae6ceed2f538ec8c928ee895bd190fd9c1dff4956bad27d567023bc847dd64d83bac399f8d10248a077c9b2f50d5dda4789e09eae4ed8609da085b6370f6529f3c7b8b13442f9a1cc93565734a81c38c6360235ba23ddf87d1b44413c24b363552a322b01d88d1cae6c5ccd88f8cef15776035934fd24adce913282983d9b55181b382ed61242fb4a5e459c3cad8d38626ef8ccdccb9899d5962dec3f3cc2422f109d902e764186cf166ed88c383f428f195dd5fec4f781bcd2308dec66927f41c9e06369c6806ed8ec9a59c096b29b2a74dc85f4f7cd77a23650c0662b5c2602ef5e41cdc13d16074500aac461f823e3bba7178bcffa000db4ffc9b1618395824ffbee1cad1d9c138a20e0b8bbea2d9a07fade932f81c3daf2d64c4991daf4a1b8b531f9b958a252c6c38cd463342aef3e03e3dae3370581d6cddf5af3ef1585780cf83db1909a1daca156018cd2f7483e53a5fccda49640de60b24523617c7ae84ec5fa987ba8a108";
CTransaction tx;
ASSERT_TRUE(DecodeHexTx(tx, triggerTx));
ASSERT_EQ(tx.GetHash().GetHex(), "5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364");
// Fake its inputs
FakeCoinsViewDB fakeDB;
CCoinsViewCache view(&fakeDB);
CTxMemPool testPool(CFeeRate(0));
// Values taken from core dump (parameters of entry)
CAmount nFees = 0;
int64_t nTime = 0x58e5fed9;
unsigned int nHeight = 92045;
double dPriority = view.GetPriority(tx, nHeight);
CTxMemPoolEntry entry(tx, nFees, nTime, dPriority, nHeight, true, false, SPROUT_BRANCH_ID);
// Check it does not crash (ie. the death test fails)
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(testPool.addUnchecked(tx.GetHash(), entry), ""), "");
// Fake the input of transaction 5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364
// - 532639cc6bebed47c1c69ae36dd498c68a012e74ad12729adbd3dbb56f8f3f4a, 0
class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf) const {
return false;
}
bool GetCoins(const uint256 &txid, CCoins &coins) const {
CTxOut txOut;
txOut.nValue = 4288035;
CCoins newCoins;
newCoins.vout.resize(2);
newCoins.vout[0] = txOut;
newCoins.nHeight = 92045;
coins.swap(newCoins);
return true;
}
bool HaveCoins(const uint256 &txid) const {
return true;
}
uint256 GetBestBlock() const {
uint256 a;
return a;
}
uint256 GetBestAnchor() const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
return false;
}
bool GetStats(CCoinsStats &stats) const {
return false;
}
};
TEST(Mempool, PriorityStatsDoNotCrash) {
// Test for security issue 2017-04-11.a
// https://z.cash/blog/security-announcement-2017-04-12.html
// Trigger transaction in block 92046
std::string triggerTx = "02000000014a3f8f6fb5dbd3db9a7212ad742e018ac698d46de39ac6c147edeb6bcc392653000000006b483045022100da0514afd80d3bbd0743458efe3b2abd18f727b4268b124c3885094c26ea09cd02207d37d7934ec90618fc5a345cb2a6d1755d8b1a432ea1df517a85e36628449196012103e9b41072e9d2cbe04e6b22a6ac4862ec3f5a76b3823b071ded0dfd5455a0803fffffffff000000000001236e4100000000000000000000000000cf592f6776810cf9fb961d80e683f5529a6b34894b00446c396022512a02dc2e96918294bffdc988a2627d9b12a9f3176b671e286fc62e3c7441cf35ea5e03d561bd5817ca5827cb2761f88dde280a6da5281af2cc69053816f31abd2170722f72c258c7c6b865c97ff8ae53b697f3b77c239a73e1d0296c2c73d21c3b50059d82866cf9f6e2f5dbbf9b4de9caa3cf836080373311978e1f1b1150ce564336ebf0fd502c2e783ff23252fba4efbb110c28c4fbe31efb6a67bc24c0ad8fd8346c5c9ed1791b555b3e43a309aa8d855a294847368ebdf30365d4dfa9b25dd8ed7adf272ecc08f4756fb9d93b8e20d45548dd4aeab6abb76a2081b6e36a9af9d38ebae378df422f40589769c07a3c12e5da253330314cbc4beaa863fac7ab10055d0310089a44c45179a39b2c4e210cec2e053f54983d744abed49f66959f45785ea90325a310fba15f946e245a0e64caec303f2a3e1d457e3e3ca5d892956c1a93b05e0b0373cf862d7bbb5908148b475c03eec96c9b9ecc7d2d78716d2c2e8ccf96175b25738dfb5b0d356a7e30604ee014c6be1db5e43af0fa6ad3f4e917a9f84b4d6f030cad0ffe0738e1effe570b0552b407ca9c26023b74b99f431cc28b79116f717703158404e343b1b47a0556f593441dc64758930f19e84d5ee468fd9a7958c6c63503054f60680f7147e88bf6da65415450230ef7437481023fc5d94872d5aa18bf3b0212b4c0d938e6c84debb8a4e65f99970c59193873a72b2440f19a652073abd960021bfef4e1e52b8f353c6e517bb97053afd4c8035defc27c3fd16faba5bc924a4179f69cfdcdb82253b5f6472a99d4b78ad2c6c18c45ed4dda5bf2adc019c99b55702f4e7b3fcaeb6f3b84ad411d36e901cba9d49ac1d6b916aa88794fb23501aeb0c585cbc2bed952846f41a03bd5c74dfe004e7ac21f7a20d32b009ccf6f70b3e577d25c679421225522b6290d5fa00a5d9a02b97a62aab60e040a03efa946d87c5e65dbf10d66df5b0834c262c31c23f3c2643451e614695003fb3a95bf21444bebb45cdcb8169245e34a76f754c89c3a90f36598a71ef4645eef4c82f1fb322536097fcf0cbe061e80ae887dbb88d8ed910be9ef18b8794930addab1a140b16c4b50f93926b1e5df03ee6e4b5ec6d7f0ed49fbbae50330ae94c5ae9182f4b58870022e423e7d80adccdb90680f7a7fe11a4ed4fe005a0af2d22bf9e7d1bef7caf4f37f5777e4aa6c9b9ea44f5973575c20fb3482fe357c19fc0c20594f492f5694e3e8eb3599e968fd23b5bdd6c4bf5aee1374b38aafe59dd5af83011e642a9427b5ff03e7a4cce92ee201a0fac0acb69d6ad3b7e4c26dfefaa53a737889e759c4b5695c1a7fd5d988e531acf66dae5067f252a25a102d92916b2d84c730645e15a78d3dce1c787634f6f7323cb949a5b6ad004e208cb8c6b734761629c13b9974dc80b082f83357f3bc703d835acbbf72aba225ffe69396c151d2646fac9bd1acc184dd047ebfaadc6b60a9185ce80c7bc8ac5dbb2219cbc0d35af91673b95d28335f0ee2774b8084871d54ca8eab3a285e4b4adf3f34b4263d67474bb5de2e1e37aa7a4ecbd5b49575caaa9e7208c2b9871946b11f2c54cd1ca7660dff44cf206e7da46ab57dd49ec0aa06ded7980f1557cc7c84023690b4df77f26d6b4eff7553b9a8628c28e8e5c38c6170bc61af0969b072586fa740f68ab33c0f62d0507cc8fe41c680b2f077e49cc2691048006311b46cd5ed18e63089f11c115b797ed5fbcd86836a4da2ab90a00745077f2f13bc9e390fc2f92b941d4fb70a3f098548953566141670317fc17e0ba81e98b8a94919992fb008c5480f4018f3a1ea673fe94a6ba3363656a944855d7c799ccb73d95d4ed6ce04c26f79c4cf79f883f0f810519f28eabe8cf6d833f24227f5074763c7b80f1431e5463cc07eff2f1d6cbfaf0411d38e62528a39b093ed7b51fa8c1008e5c1ce4bf39e67b1703554cefef44b71457bfddf43d23a54fa0145fa0e716d02a5304d85345a2b4ebf98c5010d0df468c8cbfc2db22083b0f5a74d4324ee74b46daa5ab70f2575ef5390e6aa2acb8d3b3eb2065e8c06fd6276aca283f5850e7a8b4da37455430df55621e4af59bb355ba2db0ac6cae6ceed2f538ec8c928ee895bd190fd9c1dff4956bad27d567023bc847dd64d83bac399f8d10248a077c9b2f50d5dda4789e09eae4ed8609da085b6370f6529f3c7b8b13442f9a1cc93565734a81c38c6360235ba23ddf87d1b44413c24b363552a322b01d88d1cae6c5ccd88f8cef15776035934fd24adce913282983d9b55181b382ed61242fb4a5e459c3cad8d38626ef8ccdccb9899d5962dec3f3cc2422f109d902e764186cf166ed88c383f428f195dd5fec4f781bcd2308dec66927f41c9e06369c6806ed8ec9a59c096b29b2a74dc85f4f7cd77a23650c0662b5c2602ef5e41cdc13d16074500aac461f823e3bba7178bcffa000db4ffc9b1618395824ffbee1cad1d9c138a20e0b8bbea2d9a07fade932f81c3daf2d64c4991daf4a1b8b531f9b958a252c6c38cd463342aef3e03e3dae3370581d6cddf5af3ef1585780cf83db1909a1daca156018cd2f7483e53a5fccda49640de60b24523617c7ae84ec5fa987ba8a108";
CTransaction tx;
ASSERT_TRUE(DecodeHexTx(tx, triggerTx));
ASSERT_EQ(tx.GetHash().GetHex(), "5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364");
// Fake its inputs
FakeCoinsViewDB fakeDB;
CCoinsViewCache view(&fakeDB);
CTxMemPool testPool(CFeeRate(0));
// Values taken from core dump (parameters of entry)
CAmount nFees = 0;
int64_t nTime = 0x58e5fed9;
unsigned int nHeight = 92045;
double dPriority = view.GetPriority(tx, nHeight);
CTxMemPoolEntry entry(tx, nFees, nTime, dPriority, nHeight, true);
// Check it does not crash (ie. the death test fails)
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(testPool.addUnchecked(tx.GetHash(), entry), ""), "");
EXPECT_EQ(dPriority, MAX_PRIORITY);
}
TEST(Mempool, TxInputLimit) {
SelectParams(CBaseChainParams::TESTNET);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
// Create an obviously-invalid transaction
// We intentionally set tx.nVersion = 0 to reliably trigger an error, as
// it's the first check that occurs after the -mempooltxinputlimit check,
// and it means that we don't have to mock out a lot of global state.
CMutableTransaction mtx;
mtx.nVersion = 0;
mtx.vin.resize(10);
// Check it fails as expected
CValidationState state1;
CTransaction tx1(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low");
// Set a limit
mapArgs["-mempooltxinputlimit"] = "10";
// Check it still fails as expected
CValidationState state2;
EXPECT_FALSE(AcceptToMemoryPool(pool, state2, tx1, false, &missingInputs));
EXPECT_EQ(state2.GetRejectReason(), "bad-txns-version-too-low");
// Resize the transaction
mtx.vin.resize(11);
// Check it now fails due to exceeding the limit
CValidationState state3;
CTransaction tx3(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state3, tx3, false, &missingInputs));
// The -mempooltxinputlimit check doesn't set a reason
EXPECT_EQ(state3.GetRejectReason(), "");
// Clear the limit
mapArgs.erase("-mempooltxinputlimit");
// Check it no longer fails due to exceeding the limit
CValidationState state4;
EXPECT_FALSE(AcceptToMemoryPool(pool, state4, tx3, false, &missingInputs));
EXPECT_EQ(state4.GetRejectReason(), "bad-txns-version-too-low");
}
// Valid overwinter v3 format tx gets rejected because overwinter hasn't activated yet.
TEST(Mempool, OverwinterNotActiveYet) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CValidationState state1;
CTransaction tx1(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "tx-overwinter-not-active");
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Sprout transaction version 3 when Overwinter is not active:
// 1. pass CheckTransaction (and CheckTransactionWithoutProofVerification)
// 2. pass ContextualCheckTransaction
// 3. fail IsStandardTx
TEST(Mempool, SproutV3TxFailsAsExpected) {
SelectParams(CBaseChainParams::TESTNET);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = false;
mtx.nVersion = 3;
CValidationState state1;
CTransaction tx1(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "version");
}
// Sprout transaction version 3 when Overwinter is always active:
// 1. pass CheckTransaction (and CheckTransactionWithoutProofVerification)
// 2. fails ContextualCheckTransaction
TEST(Mempool, SproutV3TxWhenOverwinterActive) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = false;
mtx.nVersion = 3;
CValidationState state1;
CTransaction tx1(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "tx-overwinter-flag-not-set");
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Sprout transaction with negative version, rejected by the mempool in CheckTransaction
// under Sprout consensus rules, should still be rejected under Overwinter consensus rules.
// 1. fails CheckTransaction (specifically CheckTransactionWithoutProofVerification)
TEST(Mempool, SproutNegativeVersionTxWhenOverwinterActive) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = false;
// A Sprout transaction with version -3 is created using Sprout code (as found in Zcashd <= 1.0.14).
// First four bytes of transaction, parsed as an uint32_t, has the value: 0xfffffffd
// This test simulates an Overwinter node receiving this transaction, but incorrectly deserializing the
// transaction due to a (pretend) bug of not detecting the most significant bit, which leads
// to not setting fOverwintered and not masking off the most significant bit of the header field.
// The resulting Sprout tx with nVersion -3 should be rejected by the Overwinter node's mempool.
{
mtx.nVersion = -3;
EXPECT_EQ(mtx.nVersion, static_cast<int32_t>(0xfffffffd));
CTransaction tx1(mtx);
EXPECT_EQ(tx1.nVersion, -3);
CValidationState state1;
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low");
}
// A Sprout transaction with version -3 created using Overwinter code (as found in Zcashd >= 1.0.15).
// First four bytes of transaction, parsed as an uint32_t, has the value: 0x80000003
// This test simulates the same pretend bug described above.
// The resulting Sprout tx with nVersion -2147483645 should be rejected by the Overwinter node's mempool.
{
mtx.nVersion = static_cast<int32_t>((1 << 31) | 3);
EXPECT_EQ(mtx.nVersion, static_cast<int32_t>(0x80000003));
CTransaction tx1(mtx);
EXPECT_EQ(tx1.nVersion, -2147483645);
CValidationState state1;
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low");
}
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}

View File

@@ -19,10 +19,10 @@
#include "zcash/IncrementalMerkleTree.hpp"
#include "zcash/util.h"
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp"
#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp>
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
#include <boost/foreach.hpp>

View File

@@ -92,3 +92,44 @@ TEST(Metrics, GetLocalSolPS) {
SetMockTime(104);
EXPECT_EQ(1, GetLocalSolPS());
}
TEST(Metrics, EstimateNetHeightInner) {
// Ensure that the (rounded) current height is returned if the tip is current
SetMockTime(15000);
EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150));
SetMockTime(15150);
EXPECT_EQ(100, EstimateNetHeightInner(101, 14250, 50, 7500, 0, 150));
// Ensure that correct estimates are returned if the tip is in the past
SetMockTime(15300); // Tip is 2 blocks behind
EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150));
SetMockTime(15900); // Tip is 6 blocks behind
EXPECT_EQ(110, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150));
// Check estimates during resync
SetMockTime(15000);
EXPECT_EQ(100, EstimateNetHeightInner( 0, 0, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner( 7, 600, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner( 8, 600, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(10, 750, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(11, 900, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(20, 2100, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(49, 6450, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(50, 6600, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(51, 6750, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(55, 7350, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(56, 7500, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(57, 7650, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(75, 10350, 50, 7500, 0, 150));
// More complex calculations:
SetMockTime(20000);
// - Checkpoint spacing: 200
// -> Average spacing: 175
// -> estimated height: 127 -> 130
EXPECT_EQ(130, EstimateNetHeightInner(100, 14100, 50, 5250, 0, 150));
// - Checkpoint spacing: 50
// -> Average spacing: 100
// -> estimated height: 153 -> 150
EXPECT_EQ(150, EstimateNetHeightInner(100, 14100, 50, 12000, 0, 150));
}

View File

@@ -0,0 +1,212 @@
#include <gtest/gtest.h>
#include "main.h"
#include "utilmoneystr.h"
#include "chainparams.h"
#include "utilstrencodings.h"
#include "zcash/Address.hpp"
#include "wallet/wallet.h"
#include "amount.h"
#include <memory>
#include <string>
#include <set>
#include <vector>
#include <boost/filesystem.hpp>
#include <iostream>
#include "util.h"
#include "paymentdisclosure.h"
#include "paymentdisclosuredb.h"
#include "sodium.h"
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
using namespace std;
/*
To run tests:
./zcash-gtest --gtest_filter="paymentdisclosure.*"
Note: As an experimental feature, writing your own tests may require option flags to be set.
mapArgs["-experimentalfeatures"] = true;
mapArgs["-paymentdisclosure"] = true;
*/
#define NUM_TRIES 10000
#define DUMP_DATABASE_TO_STDOUT false
static boost::uuids::random_generator uuidgen;
static uint256 random_uint256()
{
uint256 ret;
randombytes_buf(ret.begin(), 32);
return ret;
}
// Subclass of PaymentDisclosureDB to add debugging methods
class PaymentDisclosureDBTest : public PaymentDisclosureDB {
public:
PaymentDisclosureDBTest(const boost::filesystem::path& dbPath) : PaymentDisclosureDB(dbPath) {}
void DebugDumpAllStdout() {
ASSERT_NE(db, nullptr);
std::lock_guard<std::mutex> guard(lock_);
// Iterate over each item in the database and print them
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
cout << it->key().ToString() << " : ";
// << it->value().ToString() << endl;
try {
std::string strValue = it->value().ToString();
PaymentDisclosureInfo info;
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
ssValue >> info;
cout << info.ToString() << std::endl;
} catch (const std::exception& e) {
cout << e.what() << std::endl;
}
}
if (false == it->status().ok()) {
cerr << "An error was found iterating over the database" << endl;
cerr << it->status().ToString() << endl;
}
delete it;
}
};
// This test creates random payment disclosure blobs and checks that they can be
// 1. inserted and retrieved from a database
// 2. serialized and deserialized without corruption
// Note that the zpd: prefix is not part of the payment disclosure blob itself. It is only
// used as convention to improve the user experience when sharing payment disclosure blobs.
TEST(paymentdisclosure, mainnet) {
ECC_Start();
SelectParams(CBaseChainParams::MAIN);
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
boost::filesystem::create_directories(pathTemp);
mapArgs["-datadir"] = pathTemp.string();
std::cout << "Test payment disclosure database created in folder: " << pathTemp.native() << std::endl;
PaymentDisclosureDBTest mydb(pathTemp);
for (int i=0; i<NUM_TRIES; i++) {
// Generate an ephemeral keypair for joinsplit sig.
uint256 joinSplitPubKey;
unsigned char buffer[crypto_sign_SECRETKEYBYTES] = {0};
crypto_sign_keypair(joinSplitPubKey.begin(), &buffer[0]);
// First 32 bytes contain private key, second 32 bytes contain public key.
ASSERT_EQ(0, memcmp(joinSplitPubKey.begin(), &buffer[0]+32, 32));
std::vector<unsigned char> vch(&buffer[0], &buffer[0] + 32);
uint256 joinSplitPrivKey = uint256(vch);
// Create payment disclosure key and info data to store in test database
size_t js = random_uint256().GetCheapHash() % std::numeric_limits<size_t>::max();
uint8_t n = random_uint256().GetCheapHash() % std::numeric_limits<uint8_t>::max();
PaymentDisclosureKey key { random_uint256(), js, n};
PaymentDisclosureInfo info;
info.esk = random_uint256();
info.joinSplitPrivKey = joinSplitPrivKey;
info.zaddr = libzcash::SpendingKey::random().address();
ASSERT_TRUE(mydb.Put(key, info));
// Retrieve info from test database into new local variable and test it matches
PaymentDisclosureInfo info2;
ASSERT_TRUE(mydb.Get(key, info2));
ASSERT_EQ(info, info2);
// Modify this local variable and confirm it no longer matches
info2.esk = random_uint256();
info2.joinSplitPrivKey = random_uint256();
info2.zaddr = libzcash::SpendingKey::random().address();
ASSERT_NE(info, info2);
// Using the payment info object, let's create a dummy payload
PaymentDisclosurePayload payload;
payload.version = PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL;
payload.esk = info.esk;
payload.txid = key.hash;
payload.js = key.js;
payload.n = key.n;
payload.message = "random-" + boost::uuids::to_string(uuidgen()); // random message
payload.zaddr = info.zaddr;
// Serialize and hash the payload to generate a signature
uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0);
// Compute the payload signature
unsigned char payloadSig[64];
if (!(crypto_sign_detached(&payloadSig[0], NULL,
dataToBeSigned.begin(), 32,
&buffer[0] // buffer containing both private and public key required
) == 0))
{
throw std::runtime_error("crypto_sign_detached failed");
}
// Sanity check
if (!(crypto_sign_verify_detached(&payloadSig[0],
dataToBeSigned.begin(), 32,
joinSplitPubKey.begin()
) == 0))
{
throw std::runtime_error("crypto_sign_verify_detached failed");
}
// Convert signature buffer to boost array
boost::array<unsigned char, 64> arrayPayloadSig;
memcpy(arrayPayloadSig.data(), &payloadSig[0], 64);
// Payment disclosure blob to pass around
PaymentDisclosure pd = {payload, arrayPayloadSig};
// Test payment disclosure constructors
PaymentDisclosure pd2(payload, arrayPayloadSig);
ASSERT_EQ(pd, pd2);
PaymentDisclosure pd3(joinSplitPubKey, key, info, payload.message);
ASSERT_EQ(pd, pd3);
// Verify serialization and deserialization works
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << pd;
std::string ssHexString = HexStr(ss.begin(), ss.end());
PaymentDisclosure pdTmp;
CDataStream ssTmp(ParseHex(ssHexString), SER_NETWORK, PROTOCOL_VERSION);
ssTmp >> pdTmp;
ASSERT_EQ(pd, pdTmp);
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
ss2 << pdTmp;
std::string ss2HexString = HexStr(ss2.begin(), ss2.end());
ASSERT_EQ(ssHexString, ss2HexString);
// Verify marker
ASSERT_EQ(pd.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES);
ASSERT_EQ(pdTmp.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES);
ASSERT_EQ(0, ssHexString.find("706462ff")); // Little endian encoding of PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES value
// Sanity check
PaymentDisclosure pdDummy;
ASSERT_NE(pd, pdDummy);
}
#if DUMP_DATABASE_TO_STDOUT == true
mydb.DebugDumpAllStdout();
#endif
ECC_Stop();
}

View File

@@ -3,10 +3,9 @@
#include <iostream>
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
using namespace libzcash;
@@ -22,6 +21,51 @@ typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
#include "version.h"
#include "utilstrencodings.h"
TEST(proofs, g1_pairing_at_infinity)
{
for (size_t i = 0; i < 100; i++) {
auto r1 = curve_G1::random_element();
auto r2 = curve_G2::random_element();
ASSERT_TRUE(
curve_pp::reduced_pairing(curve_G1::zero(), r2) ==
curve_GT::one()
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2)
)
) ==
curve_GT::one()
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(r1),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2)
)
) ==
curve_pp::reduced_pairing(r1, r2)
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(r1),
curve_pp::precompute_G2(r2)
)
) ==
curve_pp::reduced_pairing(r1, r2)
);
}
}
TEST(proofs, g2_subgroup_check)
{
// all G2 elements are order r

View File

@@ -77,7 +77,7 @@ TEST(Transaction, JSDescriptionRandomized) {
*params, pubKeyHash, rt,
inputs, outputs,
inputMap, outputMap,
0, 0, false, GenZero);
0, 0, false, nullptr, GenZero);
#ifdef __LP64__ // required for building on MacOS
boost::array<uint64_t, ZC_NUM_JS_INPUTS> expectedInputMap {1, 0};
@@ -95,7 +95,7 @@ TEST(Transaction, JSDescriptionRandomized) {
*params, pubKeyHash, rt,
inputs, outputs,
inputMap, outputMap,
0, 0, false, GenMax);
0, 0, false, nullptr, GenMax);
#ifdef __LP64__ // required for building on MacOS
boost::array<uint64_t, ZC_NUM_JS_INPUTS> expectedInputMap {0, 1};

173
src/gtest/test_upgrades.cpp Normal file
View File

@@ -0,0 +1,173 @@
#include <gtest/gtest.h>
#include "chainparams.h"
#include "consensus/upgrades.h"
#include <boost/optional.hpp>
class UpgradesTest : public ::testing::Test {
protected:
virtual void SetUp() {
}
virtual void TearDown() {
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
};
TEST_F(UpgradesTest, NetworkUpgradeState) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_EQ(
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_DISABLED);
EXPECT_EQ(
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_DISABLED);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_EQ(
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_ACTIVE);
EXPECT_EQ(
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_ACTIVE);
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_EQ(
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_PENDING);
EXPECT_EQ(
NetworkUpgradeState(nActivationHeight - 1, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_PENDING);
EXPECT_EQ(
NetworkUpgradeState(nActivationHeight, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_ACTIVE);
EXPECT_EQ(
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_ACTIVE);
}
TEST_F(UpgradesTest, CurrentEpoch) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
auto nBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_TESTDUMMY].nBranchId;
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_EQ(CurrentEpoch(0, params), Consensus::BASE_SPROUT);
EXPECT_EQ(CurrentEpochBranchId(0, params), 0);
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::BASE_SPROUT);
EXPECT_EQ(CurrentEpochBranchId(1000000, params), 0);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_EQ(CurrentEpoch(0, params), Consensus::UPGRADE_TESTDUMMY);
EXPECT_EQ(CurrentEpochBranchId(0, params), nBranchId);
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::UPGRADE_TESTDUMMY);
EXPECT_EQ(CurrentEpochBranchId(1000000, params), nBranchId);
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_EQ(CurrentEpoch(0, params), Consensus::BASE_SPROUT);
EXPECT_EQ(CurrentEpochBranchId(0, params), 0);
EXPECT_EQ(CurrentEpoch(nActivationHeight - 1, params), Consensus::BASE_SPROUT);
EXPECT_EQ(CurrentEpochBranchId(nActivationHeight - 1, params), 0);
EXPECT_EQ(CurrentEpoch(nActivationHeight, params), Consensus::UPGRADE_TESTDUMMY);
EXPECT_EQ(CurrentEpochBranchId(nActivationHeight, params), nBranchId);
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::UPGRADE_TESTDUMMY);
EXPECT_EQ(CurrentEpochBranchId(1000000, params), nBranchId);
}
TEST_F(UpgradesTest, IsActivationHeight) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY));
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_TRUE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY));
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(nActivationHeight - 1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_TRUE(IsActivationHeight(nActivationHeight, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(nActivationHeight + 1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY));
}
TEST_F(UpgradesTest, IsActivationHeightForAnyUpgrade) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(0, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params));
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params));
EXPECT_TRUE(IsActivationHeightForAnyUpgrade(0, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params));
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(0, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(nActivationHeight - 1, params));
EXPECT_TRUE(IsActivationHeightForAnyUpgrade(nActivationHeight, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(nActivationHeight + 1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params));
}
TEST_F(UpgradesTest, NextActivationHeight) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_EQ(NextActivationHeight(-1, params), boost::none);
EXPECT_EQ(NextActivationHeight(0, params), boost::none);
EXPECT_EQ(NextActivationHeight(1, params), boost::none);
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_EQ(NextActivationHeight(-1, params), boost::none);
EXPECT_EQ(NextActivationHeight(0, params), boost::none);
EXPECT_EQ(NextActivationHeight(1, params), boost::none);
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none);
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_EQ(NextActivationHeight(-1, params), boost::none);
EXPECT_EQ(NextActivationHeight(0, params), nActivationHeight);
EXPECT_EQ(NextActivationHeight(1, params), nActivationHeight);
EXPECT_EQ(NextActivationHeight(nActivationHeight - 1, params), nActivationHeight);
EXPECT_EQ(NextActivationHeight(nActivationHeight, params), boost::none);
EXPECT_EQ(NextActivationHeight(nActivationHeight + 1, params), boost::none);
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none);
}

View File

@@ -0,0 +1,152 @@
#include <gtest/gtest.h>
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "main.h"
#include "utiltest.h"
extern ZCJoinSplit* params;
extern bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos);
void ExpectOptionalAmount(CAmount expected, boost::optional<CAmount> actual) {
EXPECT_TRUE((bool)actual);
if (actual) {
EXPECT_EQ(expected, *actual);
}
}
// Fake an empty view
class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf) const {
return false;
}
bool GetCoins(const uint256 &txid, CCoins &coins) const {
return false;
}
bool HaveCoins(const uint256 &txid) const {
return false;
}
uint256 GetBestBlock() const {
uint256 a;
return a;
}
uint256 GetBestAnchor() const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
return false;
}
bool GetStats(CCoinsStats &stats) const {
return false;
}
};
TEST(Validation, ContextualCheckInputsPassesWithCoinbase) {
// Create fake coinbase transaction
CMutableTransaction mtx;
mtx.vin.resize(1);
CTransaction tx(mtx);
ASSERT_TRUE(tx.IsCoinBase());
// Fake an empty view
FakeCoinsViewDB fakeDB;
CCoinsViewCache view(&fakeDB);
auto consensusBranchId = SPROUT_BRANCH_ID;
CValidationState state;
PrecomputedTransactionData txdata(tx);
EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus(), consensusBranchId));
}
TEST(Validation, ReceivedBlockTransactions) {
auto sk = libzcash::SpendingKey::random();
// Create a fake genesis block
CBlock block1;
block1.vtx.push_back(GetValidReceive(*params, sk, 5, true));
block1.hashMerkleRoot = block1.BuildMerkleTree();
CBlockIndex fakeIndex1 {block1};
// Create a fake child block
CBlock block2;
block2.hashPrevBlock = block1.GetHash();
block2.vtx.push_back(GetValidReceive(*params, sk, 10, true));
block2.hashMerkleRoot = block2.BuildMerkleTree();
CBlockIndex fakeIndex2 {block2};
fakeIndex2.pprev = &fakeIndex1;
CDiskBlockPos pos1;
CDiskBlockPos pos2;
// Set initial state of indices
ASSERT_TRUE(fakeIndex1.RaiseValidity(BLOCK_VALID_TREE));
ASSERT_TRUE(fakeIndex2.RaiseValidity(BLOCK_VALID_TREE));
EXPECT_TRUE(fakeIndex1.IsValid(BLOCK_VALID_TREE));
EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TREE));
EXPECT_FALSE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS));
EXPECT_FALSE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS));
// Sprout pool values should not be set
EXPECT_FALSE((bool)fakeIndex1.nSproutValue);
EXPECT_FALSE((bool)fakeIndex1.nChainSproutValue);
EXPECT_FALSE((bool)fakeIndex2.nSproutValue);
EXPECT_FALSE((bool)fakeIndex2.nChainSproutValue);
// Mark the second block's transactions as received first
CValidationState state;
EXPECT_TRUE(ReceivedBlockTransactions(block2, state, &fakeIndex2, pos2));
EXPECT_FALSE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS));
EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS));
// Sprout pool value delta should now be set for the second block,
// but not any chain totals
EXPECT_FALSE((bool)fakeIndex1.nSproutValue);
EXPECT_FALSE((bool)fakeIndex1.nChainSproutValue);
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(20, fakeIndex2.nSproutValue);
}
EXPECT_FALSE((bool)fakeIndex2.nChainSproutValue);
// Now mark the first block's transactions as received
EXPECT_TRUE(ReceivedBlockTransactions(block1, state, &fakeIndex1, pos1));
EXPECT_TRUE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS));
EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS));
// Sprout pool values should now be set for both blocks
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(10, fakeIndex1.nSproutValue);
}
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(10, fakeIndex1.nChainSproutValue);
}
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(20, fakeIndex2.nSproutValue);
}
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(30, fakeIndex2.nChainSproutValue);
}
}

View File

@@ -1,7 +1,3 @@
#include "zcash/JoinSplit.hpp"
ZCJoinSplit* params = ZCJoinSplit::Unopened();
int GenZero(int n)
{
return 0;