Skip to content

Commit a7c8845

Browse files
committed
Test UTXO hasher in PoSTransactionCreator.
This adds basic unit tests for PoSTransactionCreator, with a fake environment that allows a real PoSTransactionCreator to create staking transactions. In particular, we use that to unit test that it uses the UTXO hasher of the wallet properly.
1 parent 8cdd491 commit a7c8845

File tree

8 files changed

+170
-2
lines changed

8 files changed

+170
-2
lines changed

divi/src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ BITCOIN_TESTS =\
101101
test/ProofOfStake_tests.cpp \
102102
test/IsMine_tests.cpp \
103103
test/PoSStakeModifierService_tests.cpp \
104+
test/PoSTransactionCreator_tests.cpp \
104105
test/LegacyPoSStakeModifierService_tests.cpp \
105106
test/LotteryWinnersCalculatorTests.cpp \
106107
test/UtxoCheckingAndUpdating_tests.cpp \

divi/src/ProofOfStakeModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ ProofOfStakeModule::~ProofOfStakeModule()
2525
const I_ProofOfStakeGenerator& ProofOfStakeModule::proofOfStakeGenerator() const
2626
{
2727
return *proofGenerator_;
28-
}
28+
}

divi/src/ProofOfStakeModule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ class ProofOfStakeModule
2121
~ProofOfStakeModule();
2222
const I_ProofOfStakeGenerator& proofOfStakeGenerator() const;
2323
};
24-
#endif// PROOF_OF_STAKE_MODULE_H
24+
#endif// PROOF_OF_STAKE_MODULE_H

divi/src/test/FakeWallet.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ void FakeWallet::AddBlock()
115115
fakeChain.addBlocks(1, version);
116116
}
117117

118+
void FakeWallet::AddConfirmations(const unsigned numConf, const int64_t minAge)
119+
{
120+
fakeChain.addBlocks(numConf, version, fakeChain.activeChain->Tip()->nTime + minAge);
121+
}
122+
118123
const CWalletTx& FakeWallet::AddDefaultTx(const CScript& scriptToPayTo, unsigned& outputIndex,
119124
const CAmount amount)
120125
{

divi/src/test/FakeWallet.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class FakeWallet : public CWallet
3939
/** Adds a new block to our fake chain. */
4040
void AddBlock();
4141

42+
/** Adds a couple of new blocks and bumps the time at least
43+
* the given amount. This can be used to make sure some
44+
* coins fake added to the chain have at least a given age
45+
* and number of confirmations. */
46+
void AddConfirmations(unsigned numConf, int64_t minAge = 0);
47+
4248
/** Adds a new ordinary transaction to the wallet, paying a given amount
4349
* to a given script. The transaction is returned, and the output index
4450
* with the output to the requested script is set. */
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// Copyright (c) 2021 The Divi developers
2+
// Distributed under the MIT/X11 software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include "PoSTransactionCreator.h"
6+
7+
#include "chain.h"
8+
#include "chainparams.h"
9+
#include "ProofOfStakeModule.h"
10+
#include "script/standard.h"
11+
#include "Settings.h"
12+
#include "WalletTx.h"
13+
14+
#include "test/FakeBlockIndexChain.h"
15+
#include "test/FakeWallet.h"
16+
#include "test/MockBlockIncentivesPopulator.h"
17+
#include "test/MockBlockSubsidyProvider.h"
18+
#include "test/MockUtxoHasher.h"
19+
20+
#include <boost/test/unit_test.hpp>
21+
#include "test/test_only.h"
22+
23+
#include <gmock/gmock.h>
24+
25+
#include <map>
26+
27+
extern Settings& settings;
28+
29+
namespace
30+
{
31+
32+
using testing::_;
33+
using testing::AtLeast;
34+
using testing::Return;
35+
36+
class PoSTransactionCreatorTestFixture
37+
{
38+
39+
protected:
40+
41+
FakeBlockIndexWithHashes fakeChain;
42+
FakeWallet wallet;
43+
44+
private:
45+
46+
const CChainParams& chainParams;
47+
48+
MockBlockIncentivesPopulator blockIncentivesPopulator;
49+
MockBlockSubsidyProvider blockSubsidyProvider;
50+
ProofOfStakeModule posModule;
51+
52+
std::map<unsigned, unsigned> hashedBlockTimestamps;
53+
54+
PoSTransactionCreator txCreator;
55+
56+
protected:
57+
58+
/** A script from the wallet for convenience. */
59+
const CScript walletScript;
60+
61+
/** UTXO hasher used in the wallet. The instance is owned by the wallet,
62+
* and a reference is kept here. */
63+
MockUtxoHasher* utxoHasher;
64+
65+
/* Convenience variables for tests to use in calls to CreatePoS. */
66+
CMutableTransaction mtx;
67+
unsigned txTime;
68+
69+
/* Convenience variable for the wallet's AddDefaultTx. */
70+
unsigned outputIndex;
71+
72+
PoSTransactionCreatorTestFixture()
73+
: fakeChain(1, 1600000000, 1),
74+
wallet(fakeChain),
75+
chainParams(Params(CBaseChainParams::REGTEST)),
76+
posModule(chainParams, *fakeChain.activeChain, *fakeChain.blockIndexByHash),
77+
txCreator(settings, chainParams, *fakeChain.activeChain, *fakeChain.blockIndexByHash,
78+
blockSubsidyProvider, blockIncentivesPopulator,
79+
posModule.proofOfStakeGenerator(), wallet, hashedBlockTimestamps),
80+
walletScript(GetScriptForDestination(wallet.getNewKey().GetID()))
81+
{
82+
std::unique_ptr<MockUtxoHasher> hasher(new MockUtxoHasher());
83+
utxoHasher = hasher.get();
84+
wallet.SetUtxoHasherForTesting(std::move (hasher));
85+
86+
/* Set up a default block reward if we don't need anything else. */
87+
EXPECT_CALL(blockSubsidyProvider, GetFullBlockValue(_))
88+
.WillRepeatedly(Return(11 * COIN));
89+
EXPECT_CALL(blockSubsidyProvider, GetBlockSubsidity(_))
90+
.WillRepeatedly(Return(CBlockRewards(10 * COIN, COIN, 0, 0, 0, 0)));
91+
92+
/* We don't care about the block payments. */
93+
EXPECT_CALL(blockIncentivesPopulator, FillBlockPayee(_, _, _, _)).Times(AtLeast(0));
94+
EXPECT_CALL(blockIncentivesPopulator, IsBlockValueValid(_, _, _))
95+
.WillRepeatedly(Return(true));
96+
EXPECT_CALL(blockIncentivesPopulator, HasValidPayees(_, _))
97+
.WillRepeatedly(Return(true));
98+
}
99+
100+
/** Calls CreateProofOfStake on our PoSTransactionCreator with the
101+
* fake wallet's chain tip and regtest difficulty. */
102+
bool CreatePoS(CMutableTransaction& txCoinStake, unsigned& nTxNewTime)
103+
{
104+
return txCreator.CreateProofOfStake(fakeChain.activeChain->Tip(), 0x207fffff, txCoinStake, nTxNewTime);
105+
}
106+
107+
bool CreatePoS()
108+
{
109+
return CreatePoS(mtx, txTime);
110+
}
111+
112+
};
113+
114+
BOOST_FIXTURE_TEST_SUITE(PoSTransactionCreator_tests, PoSTransactionCreatorTestFixture)
115+
116+
BOOST_AUTO_TEST_CASE(failsWithoutCoinsInWallet)
117+
{
118+
BOOST_CHECK(!CreatePoS());
119+
}
120+
121+
BOOST_AUTO_TEST_CASE(checksForConfirmationsAndAge)
122+
{
123+
const auto& tx = wallet.AddDefaultTx(walletScript, outputIndex, 1000 * COIN);
124+
wallet.FakeAddToChain(tx);
125+
126+
BOOST_CHECK(!CreatePoS());
127+
128+
wallet.AddConfirmations(20, 1000);
129+
BOOST_CHECK(CreatePoS());
130+
}
131+
132+
BOOST_AUTO_TEST_CASE(usesUtxoHashForInputs)
133+
{
134+
const auto& tx = wallet.AddDefaultTx(walletScript, outputIndex, 1000 * COIN);
135+
wallet.FakeAddToChain(tx);
136+
wallet.AddConfirmations(20, 1000);
137+
138+
const auto hash = utxoHasher->Add(tx);
139+
BOOST_CHECK(CreatePoS());
140+
141+
BOOST_CHECK_EQUAL(mtx.vin.size(), 1);
142+
BOOST_CHECK_EQUAL(mtx.vin[0].prevout.n, outputIndex);
143+
BOOST_CHECK(mtx.vin[0].prevout.hash == hash);
144+
}
145+
146+
BOOST_AUTO_TEST_SUITE_END()
147+
148+
} // anonymous namespace

divi/src/wallet.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2341,6 +2341,11 @@ uint256 CWallet::GetUtxoHash(const CMerkleTx& tx) const
23412341
return utxoHasher->GetUtxoHash(tx);
23422342
}
23432343

2344+
void CWallet::SetUtxoHasherForTesting(std::unique_ptr<TransactionUtxoHasher> hasher)
2345+
{
2346+
utxoHasher = std::move(hasher);
2347+
}
2348+
23442349
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
23452350
{
23462351
if (!fFileBacked)

divi/src/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ class CWallet : public CCryptoKeyStore, public NotificationInterface, public I_K
228228
* from the given transaction (which should be part of the wallet). */
229229
uint256 GetUtxoHash(const CMerkleTx& tx) const;
230230

231+
/** Replaces the UTXO hasher used in the wallet, for testing purposes. */
232+
void SetUtxoHasherForTesting(std::unique_ptr<TransactionUtxoHasher> hasher);
233+
231234
// keystore implementation
232235
// Generate a new key
233236
CPubKey GenerateNewKey(uint32_t nAccountIndex, bool fInternal);

0 commit comments

Comments
 (0)