@ -51,8 +51,9 @@ public:
void IncrementNoteWitnesses ( const CBlockIndex * pindex ,
const CBlock * pblock ,
ZCIncrementalMerkleTree & tree ) {
CWallet : : IncrementNoteWitnesses ( pindex , pblock , tree ) ;
ZCIncrementalMerkleTree & sproutTree ,
ZCSaplingIncrementalMerkleTree & saplingTree ) {
CWallet : : IncrementNoteWitnesses ( pindex , pblock , sproutTree , saplingTree ) ;
}
void DecrementNoteWitnesses ( const CBlockIndex * pindex ) {
CWallet : : DecrementNoteWitnesses ( pindex ) ;
@ -68,8 +69,8 @@ public:
}
} ;
CWalletTx GetValidReceive ( const libzcash : : SproutSpendingKey & sk , CAmount value , bool randomInputs ) {
return GetValidReceive ( * params , sk , value , randomInputs ) ;
CWalletTx GetValidReceive ( const libzcash : : SproutSpendingKey & sk , CAmount value , bool randomInputs , int32_t version = 2 ) {
return GetValidReceive ( * params , sk , value , randomInputs , version ) ;
}
libzcash : : SproutNote GetNote ( const libzcash : : SproutSpendingKey & sk ,
@ -82,26 +83,52 @@ CWalletTx GetValidSpend(const libzcash::SproutSpendingKey& sk,
return GetValidSpend ( * params , sk , note , value ) ;
}
JSOutPoint CreateValidBlock ( TestWallet & wallet ,
std : : vector < SaplingOutPoint > SetSaplingNoteData ( CWalletTx & wtx ) {
mapSaplingNoteData_t saplingNoteData ;
SaplingOutPoint saplingOutPoint = { wtx . GetHash ( ) , 0 } ;
SaplingNoteData saplingNd ;
saplingNoteData [ saplingOutPoint ] = saplingNd ;
wtx . SetSaplingNoteData ( saplingNoteData ) ;
std : : vector < SaplingOutPoint > saplingNotes { saplingOutPoint } ;
return saplingNotes ;
}
std : : pair < JSOutPoint , SaplingOutPoint > CreateValidBlock ( TestWallet & wallet ,
const libzcash : : SproutSpendingKey & sk ,
const CBlockIndex & index ,
CBlock & block ,
ZCIncrementalMerkleTree & tree ) {
auto wtx = GetValidReceive ( sk , 50 , true ) ;
ZCIncrementalMerkleTree & sproutTree ,
ZCSaplingIncrementalMerkleTree & saplingTree ) {
auto wtx = GetValidReceive ( sk , 50 , true , 4 ) ;
auto note = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSproutNoteData ( noteData ) ;
auto saplingNotes = SetSaplingNoteData ( wtx ) ;
wallet . AddToWallet ( wtx , true , NULL ) ;
block . vtx . push_back ( wtx ) ;
wallet . IncrementNoteWitnesses ( & index , & block , tree ) ;
wallet . IncrementNoteWitnesses ( & index , & block , sproutTree , saplingTree ) ;
return std : : make_pair ( jsoutpt , saplingNotes [ 0 ] ) ;
}
return jsoutpt ;
std : : pair < uint256 , uint256 > GetWitnessesAndAnchors ( TestWallet & wallet ,
std : : vector < JSOutPoint > & sproutNotes ,
std : : vector < SaplingOutPoint > & saplingNotes ,
std : : vector < boost : : optional < ZCIncrementalWitness > > & sproutWitnesses ,
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > & saplingWitnesses ) {
sproutWitnesses . clear ( ) ;
saplingWitnesses . clear ( ) ;
uint256 sproutAnchor ;
uint256 saplingAnchor ;
wallet . GetSproutNoteWitnesses ( sproutNotes , sproutWitnesses , sproutAnchor ) ;
wallet . GetSaplingNoteWitnesses ( saplingNotes , saplingWitnesses , saplingAnchor ) ;
return std : : make_pair ( sproutAnchor , saplingAnchor ) ;
}
TEST ( wallet_tests , setup_datadir_location_run_as_first_test ) {
@ -117,9 +144,9 @@ TEST(wallet_tests, note_data_serialisation) {
auto note = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
ZCIncrementalMerkleTree tree ;
nd . witnesses . push_front ( tree . witness ( ) ) ;
noteData [ jsoutpt ] = nd ;
@ -127,7 +154,7 @@ TEST(wallet_tests, note_data_serialisation) {
CDataStream ss ( SER_DISK , CLIENT_VERSION ) ;
ss < < noteData ;
mapNoteData_t noteData2 ;
mapSprout NoteData_t noteData2 ;
ss > > noteData2 ;
EXPECT_EQ ( noteData , noteData2 ) ;
@ -145,12 +172,12 @@ TEST(wallet_tests, find_unspent_notes) {
auto note = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSprout NoteData ( noteData ) ;
wallet . AddToWallet ( wtx , true , NULL ) ;
EXPECT_FALSE ( wallet . IsSpent ( nullifier ) ) ;
@ -240,12 +267,12 @@ TEST(wallet_tests, find_unspent_notes) {
auto note = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSprout NoteData ( noteData ) ;
wallet . AddToWallet ( wtx , true , NULL ) ;
EXPECT_FALSE ( wallet . IsSpent ( nullifier ) ) ;
@ -299,28 +326,28 @@ TEST(wallet_tests, set_note_addrs_in_cwallettx) {
auto wtx = GetValidReceive ( sk , 10 , true ) ;
auto note = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
EXPECT_EQ ( 0 , wtx . mapNoteData . size ( ) ) ;
EXPECT_EQ ( 0 , wtx . mapSprout NoteData . size ( ) ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
EXPECT_EQ ( noteData , wtx . mapNoteData ) ;
wtx . SetSprout NoteData ( noteData ) ;
EXPECT_EQ ( noteData , wtx . mapSprout NoteData ) ;
}
TEST ( wallet_tests , set_invalid_note_addrs_in_cwallettx ) {
CWalletTx wtx ;
EXPECT_EQ ( 0 , wtx . mapNoteData . size ( ) ) ;
EXPECT_EQ ( 0 , wtx . mapSprout NoteData . size ( ) ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
auto sk = libzcash : : SproutSpendingKey : : random ( ) ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , uint256 ( ) } ;
Sprout NoteData nd { sk . address ( ) , uint256 ( ) } ;
noteData [ jsoutpt ] = nd ;
EXPECT_THROW ( wtx . SetNoteData ( noteData ) , std : : logic_error ) ;
EXPECT_THROW ( wtx . SetSprout NoteData ( noteData ) , std : : logic_error ) ;
}
TEST ( wallet_tests , GetNoteNullifier ) {
@ -374,7 +401,7 @@ TEST(wallet_tests, FindMyNotes) {
EXPECT_EQ ( 2 , noteMap . size ( ) ) ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
EXPECT_EQ ( 1 , noteMap . count ( jsoutpt ) ) ;
EXPECT_EQ ( nd , noteMap [ jsoutpt ] ) ;
}
@ -397,7 +424,7 @@ TEST(wallet_tests, FindMyNotesInEncryptedWallet) {
EXPECT_EQ ( 2 , noteMap . size ( ) ) ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
EXPECT_EQ ( 1 , noteMap . count ( jsoutpt ) ) ;
EXPECT_NE ( nd , noteMap [ jsoutpt ] ) ;
@ -490,12 +517,12 @@ TEST(wallet_tests, navigate_from_nullifier_to_note) {
auto note = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSprout NoteData ( noteData ) ;
EXPECT_EQ ( 0 , wallet . mapNullifiersToNotes . count ( nullifier ) ) ;
@ -520,12 +547,12 @@ TEST(wallet_tests, spent_note_is_from_me) {
EXPECT_FALSE ( wallet . IsFromMe ( wtx ) ) ;
EXPECT_FALSE ( wallet . IsFromMe ( wtx2 ) ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSprout NoteData ( noteData ) ;
EXPECT_FALSE ( wallet . IsFromMe ( wtx ) ) ;
EXPECT_FALSE ( wallet . IsFromMe ( wtx2 ) ) ;
@ -540,44 +567,53 @@ TEST(wallet_tests, cached_witnesses_empty_chain) {
auto sk = libzcash : : SproutSpendingKey : : random ( ) ;
wallet . AddSpendingKey ( sk ) ;
auto wtx = GetValidReceive ( sk , 10 , true ) ;
auto wtx = GetValidReceive ( sk , 10 , true , 4 ) ;
auto note = GetNote ( sk , wtx , 0 , 0 ) ;
auto note2 = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
auto nullifier2 = note2 . nullifier ( sk ) ;
mapNoteData_t n oteData ;
mapSproutNoteData_t sproutN oteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 0 } ;
JSOutPoint jsoutpt2 { wtx . GetHash ( ) , 0 , 1 } ;
CNoteData nd { sk . address ( ) , nullifier } ;
CNoteData nd2 { sk . address ( ) , nullifier2 } ;
noteData [ jsoutpt ] = nd ;
noteData [ jsoutpt2 ] = nd2 ;
wtx . SetNoteData ( noteData ) ;
SproutNoteData nd { sk . address ( ) , nullifier } ;
SproutNoteData nd2 { sk . address ( ) , nullifier2 } ;
sproutNoteData [ jsoutpt ] = nd ;
sproutNoteData [ jsoutpt2 ] = nd2 ;
wtx . SetSproutNoteData ( sproutNoteData ) ;
std : : vector < JSOutPoint > sproutNotes { jsoutpt , jsoutpt2 } ;
std : : vector < SaplingOutPoint > saplingNotes = SetSaplingNoteData ( wtx ) ;
std : : vector < boost : : optional < ZCIncrementalWitness > > sproutWitnesses ;
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > saplingWitnesses ;
std : : vector < JSOutPoint > notes { jsoutpt , jsoutpt2 } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > witnesses ;
uint256 anchor ;
: : GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 1 ] ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 1 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 0 ] ) ;
wallet . AddToWallet ( wtx , true , NULL ) ;
witnesses . clear ( ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 1 ] ) ;
: : GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 1 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 0 ] ) ;
CBlock block ;
block . vtx . push_back ( wtx ) ;
CBlockIndex index ( block ) ;
ZCIncrementalMerkleTree tree ;
wallet . IncrementNoteWitnesses ( & index , & block , tree ) ;
witnesses . clear ( ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor ) ;
EXPECT_TRUE ( ( bool ) witnesses [ 0 ] ) ;
EXPECT_TRUE ( ( bool ) witnesses [ 1 ] ) ;
ZCIncrementalMerkleTree sproutTree ;
ZCSaplingIncrementalMerkleTree saplingTree ;
wallet . IncrementNoteWitnesses ( & index , & block , sproutTree , saplingTree ) ;
: : GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ 1 ] ) ;
EXPECT_TRUE ( ( bool ) saplingWitnesses [ 0 ] ) ;
// Until #1302 is implemented, this should triggger an assertion
EXPECT_DEATH ( wallet . DecrementNoteWitnesses ( & index ) ,
@ -586,9 +622,10 @@ TEST(wallet_tests, cached_witnesses_empty_chain) {
TEST ( wallet_tests , cached_witnesses_chain_tip ) {
TestWallet wallet ;
uint256 anchor1 ;
std : : pair < uint256 , uint256 > anchors 1 ;
CBlock block1 ;
ZCIncrementalMerkleTree tree ;
ZCIncrementalMerkleTree sproutTree ;
ZCSaplingIncrementalMerkleTree saplingTree ;
auto sk = libzcash : : SproutSpendingKey : : random ( ) ;
wallet . AddSpendingKey ( sk ) ;
@ -597,33 +634,40 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
// First block (case tested in _empty_chain)
CBlockIndex index1 ( block1 ) ;
index1 . nHeight = 1 ;
auto js outpt = CreateValidBlock ( wallet , sk , index1 , block1 , tree ) ;
auto outpts = CreateValidBlock ( wallet , sk , index1 , block1 , sprou tTree , saplingT ree) ;
// Called to fetch anchor
std : : vector < JSOutPoint > notes { jsoutpt } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > witnesses ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor1 ) ;
std : : vector < JSOutPoint > sproutNotes { outpts . first } ;
std : : vector < SaplingOutPoint > saplingNotes { outpts . second } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > sproutWitnesses ;
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > saplingWitnesses ;
anchors1 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_NE ( anchors1 . first , anchors1 . second ) ;
}
{
// Second transaction
auto wtx = GetValidReceive ( sk , 50 , true ) ;
auto wtx = GetValidReceive ( sk , 50 , true , 4 ) ;
auto note = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
mapNoteData_t n oteData ;
mapSproutNoteData_t sproutN oteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
CNoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
SproutNoteData nd { sk . address ( ) , nullifier } ;
sproutNoteData [ jsoutpt ] = nd ;
wtx . SetSproutNoteData ( sproutNoteData ) ;
std : : vector < SaplingOutPoint > saplingNotes = SetSaplingNoteData ( wtx ) ;
wallet . AddToWallet ( wtx , true , NULL ) ;
std : : vector < JSOutPoint > n otes { jsoutpt } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > w itnesses;
uint256 anchor2 ;
std : : vector < JSOutPoint > sproutN otes { jsoutpt } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > sproutW itnesses;
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > saplingWitnesses ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor2 ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 0 ] ) ;
GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 0 ] ) ;
// Second block
CBlock block2 ;
@ -631,46 +675,57 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
block2 . vtx . push_back ( wtx ) ;
CBlockIndex index2 ( block2 ) ;
index2 . nHeight = 2 ;
ZCIncrementalMerkleTree tree2 { tree } ;
wallet . IncrementNoteWitnesses ( & index2 , & block2 , tree2 ) ;
witnesses . clear ( ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor2 ) ;
EXPECT_TRUE ( ( bool ) witnesses [ 0 ] ) ;
EXPECT_NE ( anchor1 , anchor2 ) ;
ZCIncrementalMerkleTree sproutTree2 { sproutTree } ;
ZCSaplingIncrementalMerkleTree saplingTree2 { saplingTree } ;
wallet . IncrementNoteWitnesses ( & index2 , & block2 , sproutTree2 , saplingTree2 ) ;
auto anchors2 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_NE ( anchors2 . first , anchors2 . second ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_TRUE ( ( bool ) saplingWitnesses [ 0 ] ) ;
EXPECT_NE ( anchors1 . first , anchors2 . first ) ;
EXPECT_NE ( anchors1 . second , anchors2 . second ) ;
// Decrementing should give us the previous anchor
uint256 anchor3 ;
wallet . DecrementNoteWitnesses ( & index2 ) ;
witnesses . clear ( ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor3 ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 0 ] ) ;
auto anchors3 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 0 ] ) ;
// Should not equal first anchor because none of these notes had witnesses
EXPECT_NE ( anchor1 , anchor3 ) ;
EXPECT_NE ( anchors1 . first , anchors3 . first ) ;
EXPECT_NE ( anchors1 . second , anchors3 . second ) ;
// Re-incrementing with the same block should give the same result
uint256 anchor4 ;
wallet . IncrementNoteWitnesses ( & index2 , & block2 , tree ) ;
witnesses . clear ( ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor4 ) ;
EXPECT_TRUE ( ( bool ) witnesses [ 0 ] ) ;
EXPECT_EQ ( anchor2 , anchor4 ) ;
wallet . IncrementNoteWitnesses ( & index2 , & block2 , sproutTree , saplingTree ) ;
auto anchors4 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_NE ( anchors4 . first , anchors4 . second ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_TRUE ( ( bool ) saplingWitnesses [ 0 ] ) ;
EXPECT_EQ ( anchors2 . first , anchors4 . first ) ;
EXPECT_EQ ( anchors2 . second , anchors4 . second ) ;
// Incrementing with the same block again should not change the cache
uint256 anchor5 ;
wallet . IncrementNoteWitnesses ( & index2 , & block2 , tree ) ;
std : : vector < boost : : optional < ZCIncrementalWitness > > witnesses5 ;
wallet . GetNoteWitnesses ( notes , witnesses5 , anchor5 ) ;
EXPECT_EQ ( witnesses , witnesses5 ) ;
EXPECT_EQ ( anchor4 , anchor5 ) ;
wallet . IncrementNoteWitnesses ( & index2 , & block2 , sproutTree , saplingTree ) ;
std : : vector < boost : : optional < ZCIncrementalWitness > > sproutWitnesses5 ;
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > saplingWitnesses5 ;
auto anchors5 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses5 , saplingWitnesses5 ) ;
EXPECT_NE ( anchors5 . first , anchors5 . second ) ;
EXPECT_EQ ( sproutWitnesses , sproutWitnesses5 ) ;
EXPECT_EQ ( saplingWitnesses , saplingWitnesses5 ) ;
EXPECT_EQ ( anchors4 . first , anchors5 . first ) ;
EXPECT_EQ ( anchors4 . second , anchors5 . second ) ;
}
}
TEST ( wallet_tests , CachedWitnessesDecrementFirst ) {
TestWallet wallet ;
uint256 anchor2 ;
CBlock block2 ;
CBlockIndex index2 ( block2 ) ;
ZCIncrementalMerkleTree tree ;
ZCIncrementalMerkleTree sproutTree ;
ZCSaplingIncrementalMerkleTree saplingTree ;
auto sk = libzcash : : SproutSpendingKey : : random ( ) ;
wallet . AddSpendingKey ( sk ) ;
@ -680,57 +735,70 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) {
CBlock block1 ;
CBlockIndex index1 ( block1 ) ;
index1 . nHeight = 1 ;
CreateValidBlock ( wallet , sk , index1 , block1 , tree ) ;
CreateValidBlock ( wallet , sk , index1 , block1 , sprou tTree , saplingT ree) ;
}
std : : pair < uint256 , uint256 > anchors2 ;
CBlock block2 ;
CBlockIndex index2 ( block2 ) ;
{
// Second block (case tested in _chain_tip)
index2 . nHeight = 2 ;
auto jsoutpt = CreateValidBlock ( wallet , sk , index2 , block2 , tree ) ;
auto outpts = CreateValidBlock ( wallet , sk , index2 , block2 , sprou tTree , saplingT ree) ;
// Called to fetch anchor
std : : vector < JSOutPoint > notes { jsoutpt } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > witnesses ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor2 ) ;
std : : vector < JSOutPoint > sproutNotes { outpts . first } ;
std : : vector < SaplingOutPoint > saplingNotes { outpts . second } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > sproutWitnesses ;
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > saplingWitnesses ;
anchors2 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
}
{
{
// Third transaction - never mined
auto wtx = GetValidReceive ( sk , 20 , true ) ;
auto wtx = GetValidReceive ( sk , 20 , true , 4 ) ;
auto note = GetNote ( sk , wtx , 0 , 1 ) ;
auto nullifier = note . nullifier ( sk ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSproutNoteData ( noteData ) ;
std : : vector < SaplingOutPoint > saplingNotes = SetSaplingNoteData ( wtx ) ;
wallet . AddToWallet ( wtx , true , NULL ) ;
std : : vector < JSOutPoint > notes { jsoutpt } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > witnesses ;
uint256 anchor3 ;
std : : vector < JSOutPoint > sproutNotes { jsoutpt } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > sproutWitnesses ;
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > saplingWitnesses ;
auto anchors3 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor3 ) ;
EXPECT_FALSE ( ( bool ) w itnesses[ 0 ] ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) saplingW itnesses[ 0 ] ) ;
// Decrementing (before the transaction has ever seen an increment)
// should give us the previous anchor
uint256 anchor4 ;
wallet . DecrementNoteWitnesses ( & index2 ) ;
witnesses . clear ( ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor4 ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 0 ] ) ;
auto anchors4 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 0 ] ) ;
// Should not equal second anchor because none of these notes had witnesses
EXPECT_NE ( anchor2 , anchor4 ) ;
EXPECT_NE ( anchors2 . first , anchors4 . first ) ;
EXPECT_NE ( anchors2 . second , anchors4 . second ) ;
// Re-incrementing with the same block should give the same result
uint256 anchor5 ;
wallet . IncrementNoteWitnesses ( & index2 , & block2 , tree ) ;
witnesses . clear ( ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor5 ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 0 ] ) ;
EXPECT_EQ ( anchor3 , anchor5 ) ;
wallet . IncrementNoteWitnesses ( & index2 , & block2 , sproutTree , saplingTree ) ;
auto anchors5 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 0 ] ) ;
EXPECT_EQ ( anchors3 . first , anchors5 . first ) ;
EXPECT_EQ ( anchors3 . second , anchors5 . second ) ;
}
}
@ -738,11 +806,16 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) {
TestWallet wallet ;
std : : vector < CBlock > blocks ;
std : : vector < CBlockIndex > indices ;
std : : vector < JSOutPoint > notes ;
std : : vector < uint256 > anchors ;
ZCIncrementalMerkleTree tree ;
ZCIncrementalMerkleTree riTree = tree ;
std : : vector < boost : : optional < ZCIncrementalWitness > > witnesses ;
std : : vector < JSOutPoint > sproutNotes ;
std : : vector < SaplingOutPoint > saplingNotes ;
std : : vector < uint256 > sproutAnchors ;
std : : vector < uint256 > saplingAnchors ;
ZCIncrementalMerkleTree sproutTree ;
ZCIncrementalMerkleTree sproutRiTree = sproutTree ;
ZCSaplingIncrementalMerkleTree saplingTree ;
ZCSaplingIncrementalMerkleTree saplingRiTree = saplingTree ;
std : : vector < boost : : optional < ZCIncrementalWitness > > sproutWitnesses ;
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > saplingWitnesses ;
auto sk = libzcash : : SproutSpendingKey : : random ( ) ;
wallet . AddSpendingKey ( sk ) ;
@ -753,58 +826,64 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) {
indices . resize ( numBlocks ) ;
for ( size_t i = 0 ; i < numBlocks ; i + + ) {
indices [ i ] . nHeight = i ;
auto old = tree . root ( ) ;
auto jsoutpt = CreateValidBlock ( wallet , sk , indices [ i ] , blocks [ i ] , tree ) ;
EXPECT_NE ( old , tree . root ( ) ) ;
notes . push_back ( jsoutpt ) ;
witnesses . clear ( ) ;
uint256 anchor ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor ) ;
auto oldSproutRoot = sproutTree . root ( ) ;
auto oldSaplingRoot = saplingTree . root ( ) ;
auto outpts = CreateValidBlock ( wallet , sk , indices [ i ] , blocks [ i ] , sproutTree , saplingTree ) ;
EXPECT_NE ( oldSproutRoot , sproutTree . root ( ) ) ;
EXPECT_NE ( oldSaplingRoot , saplingTree . root ( ) ) ;
sproutNotes . push_back ( outpts . first ) ;
saplingNotes . push_back ( outpts . second ) ;
auto anchors = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
for ( size_t j = 0 ; j < = i ; j + + ) {
EXPECT_TRUE ( ( bool ) witnesses [ j ] ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ j ] ) ;
EXPECT_TRUE ( ( bool ) saplingWitnesses [ j ] ) ;
}
anchors . push_back ( anchor ) ;
sproutAnchors . push_back ( anchors . first ) ;
saplingAnchors . push_back ( anchors . second ) ;
}
// Now pretend we are reindexing: the chain is cleared, and each block is
// used to increment witnesses again.
for ( size_t i = 0 ; i < numBlocks ; i + + ) {
ZCIncrementalMerkleTree riPrevTree { riTree } ;
wallet . IncrementNoteWitnesses ( & ( indices [ i ] ) , & ( blocks [ i ] ) , riTree ) ;
witnesses . clear ( ) ;
uint256 anchor ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor ) ;
ZCIncrementalMerkleTree sp routR iPrevTree { sp routR iTree} ;
ZCSaplingIncrementalMerkleTree saplingRiPrevTree { saplingRiTree } ;
wallet . IncrementNoteWitnesses ( & ( indices [ i ] ) , & ( blocks [ i ] ) , sproutRiTree , saplingRiTree ) ;
auto anchors = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
for ( size_t j = 0 ; j < numBlocks ; j + + ) {
EXPECT_TRUE ( ( bool ) witnesses [ j ] ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ j ] ) ;
EXPECT_TRUE ( ( bool ) saplingWitnesses [ j ] ) ;
}
// Should equal final anchor because witness cache unaffected
EXPECT_EQ ( anchors . back ( ) , anchor ) ;
EXPECT_EQ ( sproutAnchors . back ( ) , anchors . first ) ;
EXPECT_EQ ( saplingAnchors . back ( ) , anchors . second ) ;
if ( ( i = = 5 ) | | ( i = = 50 ) ) {
// Pretend a reorg happened that was recorded in the block files
{
wallet . DecrementNoteWitnesses ( & ( indices [ i ] ) ) ;
witnesses . clear ( ) ;
uint256 anchor ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor ) ;
auto anchors = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
for ( size_t j = 0 ; j < numBlocks ; j + + ) {
EXPECT_TRUE ( ( bool ) witnesses [ j ] ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ j ] ) ;
EXPECT_TRUE ( ( bool ) saplingWitnesses [ j ] ) ;
}
// Should equal final anchor because witness cache unaffected
EXPECT_EQ ( anchors . back ( ) , anchor ) ;
EXPECT_EQ ( sproutAnchors . back ( ) , anchors . first ) ;
EXPECT_EQ ( saplingAnchors . back ( ) , anchors . second ) ;
}
{
wallet . IncrementNoteWitnesses ( & ( indices [ i ] ) , & ( blocks [ i ] ) , riPrevTree ) ;
witnesses . clear ( ) ;
uint256 anchor ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor ) ;
wallet . IncrementNoteWitnesses ( & ( indices [ i ] ) , & ( blocks [ i ] ) , sproutRiPrevTree , saplingRiPrevTree ) ;
auto anchors = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
for ( size_t j = 0 ; j < numBlocks ; j + + ) {
EXPECT_TRUE ( ( bool ) witnesses [ j ] ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ j ] ) ;
EXPECT_TRUE ( ( bool ) saplingWitnesses [ j ] ) ;
}
// Should equal final anchor because witness cache unaffected
EXPECT_EQ ( anchors . back ( ) , anchor ) ;
EXPECT_EQ ( sproutAnchors . back ( ) , anchors . first ) ;
EXPECT_EQ ( saplingAnchors . back ( ) , anchors . second ) ;
}
}
}
@ -816,44 +895,55 @@ TEST(wallet_tests, ClearNoteWitnessCache) {
auto sk = libzcash : : SproutSpendingKey : : random ( ) ;
wallet . AddSpendingKey ( sk ) ;
auto wtx = GetValidReceive ( sk , 10 , true ) ;
auto wtx = GetValidReceive ( sk , 10 , true , 4 ) ;
auto hash = wtx . GetHash ( ) ;
auto note = GetNote ( sk , wtx , 0 , 0 ) ;
auto nullifier = note . nullifier ( sk ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 0 } ;
JSOutPoint jsoutpt2 { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSproutNoteData ( noteData ) ;
auto saplingNotes = SetSaplingNoteData ( wtx ) ;
// Pretend we mined the tx by adding a fake witness
ZCIncrementalMerkleTree tree ;
wtx . mapNoteData [ jsoutpt ] . witnesses . push_front ( tree . witness ( ) ) ;
wtx . mapNoteData [ jsoutpt ] . witnessHeight = 1 ;
ZCIncrementalMerkleTree sprou tT ree;
wtx . mapSprout NoteData [ jsoutpt ] . witnesses . push_front ( sprou tT ree. witness ( ) ) ;
wtx . mapSprout NoteData [ jsoutpt ] . witnessHeight = 1 ;
wallet . nWitnessCacheSize = 1 ;
ZCSaplingIncrementalMerkleTree saplingTree ;
wtx . mapSaplingNoteData [ saplingNotes [ 0 ] ] . witnesses . push_front ( saplingTree . witness ( ) ) ;
wtx . mapSaplingNoteData [ saplingNotes [ 0 ] ] . witnessHeight = 1 ;
wallet . nWitnessCacheSize = 2 ;
wallet . AddToWallet ( wtx , true , NULL ) ;
std : : vector < JSOutPoint > notes { jsoutpt , jsoutpt2 } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > witnesses ;
uint256 anchor2 ;
std : : vector < JSOutPoint > sproutN otes { jsoutpt , jsoutpt2 } ;
std : : vector < boost : : optional < ZCIncrementalWitness > > sproutW itnesses;
std : : vector < boost : : optional < ZCSaplingIncrementalWitness > > saplingWitnesses ;
// Before clearing, we should have a witness for one note
wallet . GetNoteWitnesses ( notes , witnesses , anchor2 ) ;
EXPECT_TRUE ( ( bool ) witnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 1 ] ) ;
EXPECT_EQ ( 1 , wallet . mapWallet [ hash ] . mapNoteData [ jsoutpt ] . witnessHeight ) ;
EXPECT_EQ ( 1 , wallet . nWitnessCacheSize ) ;
GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_TRUE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 1 ] ) ;
EXPECT_TRUE ( ( bool ) saplingWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 1 ] ) ;
EXPECT_EQ ( 1 , wallet . mapWallet [ hash ] . mapSproutNoteData [ jsoutpt ] . witnessHeight ) ;
EXPECT_EQ ( 1 , wallet . mapWallet [ hash ] . mapSaplingNoteData [ saplingNotes [ 0 ] ] . witnessHeight ) ;
EXPECT_EQ ( 2 , wallet . nWitnessCacheSize ) ;
// After clearing, we should not have a witness for either note
wallet . ClearNoteWitnessCache ( ) ;
witnesses . clear ( ) ;
wallet . GetNoteWitnesses ( notes , witnesses , anchor2 ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) witnesses [ 1 ] ) ;
EXPECT_EQ ( - 1 , wallet . mapWallet [ hash ] . mapNoteData [ jsoutpt ] . witnessHeight ) ;
auto anchros2 = GetWitnessesAndAnchors ( wallet , sproutNotes , saplingNotes , sproutWitnesses , saplingWitnesses ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) sproutWitnesses [ 1 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 0 ] ) ;
EXPECT_FALSE ( ( bool ) saplingWitnesses [ 1 ] ) ;
EXPECT_EQ ( - 1 , wallet . mapWallet [ hash ] . mapSproutNoteData [ jsoutpt ] . witnessHeight ) ;
EXPECT_EQ ( - 1 , wallet . mapWallet [ hash ] . mapSaplingNoteData [ saplingNotes [ 0 ] ] . witnessHeight ) ;
EXPECT_EQ ( 0 , wallet . nWitnessCacheSize ) ;
}
@ -949,11 +1039,11 @@ TEST(wallet_tests, UpdateNullifierNoteMap) {
auto nullifier = note . nullifier ( sk ) ;
// Pretend that we called FindMyNotes while the wallet was locked
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 1 } ;
C NoteData nd { sk . address ( ) } ;
Sprout NoteData nd { sk . address ( ) } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSprout NoteData ( noteData ) ;
wallet . AddToWallet ( wtx , true , NULL ) ;
EXPECT_EQ ( 0 , wallet . mapNullifiersToNotes . count ( nullifier ) ) ;
@ -984,35 +1074,35 @@ TEST(wallet_tests, UpdatedNoteData) {
// First pretend we added the tx to the wallet and
// we don't have the key for the second note
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { wtx . GetHash ( ) , 0 , 0 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSprout NoteData ( noteData ) ;
// Pretend we mined the tx by adding a fake witness
ZCIncrementalMerkleTree tree ;
wtx . mapNoteData [ jsoutpt ] . witnesses . push_front ( tree . witness ( ) ) ;
wtx . mapNoteData [ jsoutpt ] . witnessHeight = 100 ;
wtx . mapSprout NoteData [ jsoutpt ] . witnesses . push_front ( tree . witness ( ) ) ;
wtx . mapSprout NoteData [ jsoutpt ] . witnessHeight = 100 ;
// Now pretend we added the key for the second note, and
// the tx was "added" to the wallet again to update it.
// This happens via the 'z_importkey' RPC method.
JSOutPoint jsoutpt2 { wtx2 . GetHash ( ) , 0 , 1 } ;
C NoteData nd2 { sk . address ( ) , nullifier2 } ;
Sprout NoteData nd2 { sk . address ( ) , nullifier2 } ;
noteData [ jsoutpt2 ] = nd2 ;
wtx2 . SetNoteData ( noteData ) ;
wtx2 . SetSprout NoteData ( noteData ) ;
// The txs should initially be different
EXPECT_NE ( wtx . mapNoteData , wtx2 . mapNoteData ) ;
EXPECT_EQ ( 1 , wtx . mapNoteData [ jsoutpt ] . witnesses . size ( ) ) ;
EXPECT_EQ ( 100 , wtx . mapNoteData [ jsoutpt ] . witnessHeight ) ;
EXPECT_NE ( wtx . mapSprout NoteData , wtx2 . mapSprout NoteData ) ;
EXPECT_EQ ( 1 , wtx . mapSprout NoteData [ jsoutpt ] . witnesses . size ( ) ) ;
EXPECT_EQ ( 100 , wtx . mapSprout NoteData [ jsoutpt ] . witnessHeight ) ;
// After updating, they should be the same
EXPECT_TRUE ( wallet . UpdatedNoteData ( wtx2 , wtx ) ) ;
EXPECT_EQ ( wtx . mapNoteData , wtx2 . mapNoteData ) ;
EXPECT_EQ ( 1 , wtx . mapNoteData [ jsoutpt ] . witnesses . size ( ) ) ;
EXPECT_EQ ( 100 , wtx . mapNoteData [ jsoutpt ] . witnessHeight ) ;
EXPECT_EQ ( wtx . mapSprout NoteData , wtx2 . mapSprout NoteData ) ;
EXPECT_EQ ( 1 , wtx . mapSprout NoteData [ jsoutpt ] . witnesses . size ( ) ) ;
EXPECT_EQ ( 100 , wtx . mapSprout NoteData [ jsoutpt ] . witnessHeight ) ;
// TODO: The new note should get witnessed (but maybe not here) (#1350)
}
@ -1028,12 +1118,12 @@ TEST(wallet_tests, MarkAffectedTransactionsDirty) {
auto nullifier = note . nullifier ( sk ) ;
auto wtx2 = GetValidSpend ( sk , note , 5 ) ;
mapNoteData_t noteData ;
mapSprout NoteData_t noteData ;
JSOutPoint jsoutpt { hash , 0 , 1 } ;
C NoteData nd { sk . address ( ) , nullifier } ;
Sprout NoteData nd { sk . address ( ) , nullifier } ;
noteData [ jsoutpt ] = nd ;
wtx . SetNoteData ( noteData ) ;
wtx . SetSprout NoteData ( noteData ) ;
wallet . AddToWallet ( wtx , true , NULL ) ;
wallet . MarkAffectedTransactionsDirty ( wtx ) ;