]> Git Repo - VerusCoin.git/blob - src/wallet/gtest/test_paymentdisclosure.cpp
Merge pull request #97 from miketout/dev
[VerusCoin.git] / src / wallet / gtest / test_paymentdisclosure.cpp
1 #include <gtest/gtest.h>
2
3 #include "main.h"
4 #include "utilmoneystr.h"
5 #include "chainparams.h"
6 #include "utilstrencodings.h"
7 #include "zcash/Address.hpp"
8 #include "wallet/wallet.h"
9 #include "amount.h"
10
11 #include <array>
12 #include <memory>
13 #include <string>
14 #include <set>
15 #include <vector>
16 #include <boost/filesystem.hpp>
17 #include <iostream>
18 #include "util.h"
19
20 #include "wallet/paymentdisclosure.h"
21 #include "wallet/paymentdisclosuredb.h"
22
23 #include "sodium.h"
24
25 #include <boost/uuid/uuid.hpp>
26 #include <boost/uuid/uuid_generators.hpp>
27 #include <boost/uuid/uuid_io.hpp>
28
29 using namespace std;
30
31 /*
32     To run tests:
33     ./zcash-gtest --gtest_filter="paymentdisclosure.*"
34
35     Note: As an experimental feature, writing your own tests may require option flags to be set.
36     mapArgs["-experimentalfeatures"] = true;
37     mapArgs["-paymentdisclosure"] = true;
38 */
39
40 #define NUM_TRIES 10000
41
42 #define DUMP_DATABASE_TO_STDOUT false
43
44 static boost::uuids::random_generator uuidgen;
45
46 static uint256 random_uint256()
47 {
48     uint256 ret;
49     randombytes_buf(ret.begin(), 32);
50     return ret;
51 }
52
53 // Subclass of PaymentDisclosureDB to add debugging methods
54 class PaymentDisclosureDBTest : public PaymentDisclosureDB {
55 public:
56     PaymentDisclosureDBTest(const boost::filesystem::path& dbPath) : PaymentDisclosureDB(dbPath) {}
57
58     void DebugDumpAllStdout() {
59         ASSERT_NE(db, nullptr);
60         std::lock_guard<std::mutex> guard(lock_);
61
62         // Iterate over each item in the database and print them
63         leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
64
65         for (it->SeekToFirst(); it->Valid(); it->Next()) {
66             cout << it->key().ToString() << " : ";
67             // << it->value().ToString() << endl;
68             try {
69                 std::string strValue = it->value().ToString();
70                 PaymentDisclosureInfo info;
71                 CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
72                 ssValue >> info;
73                 cout << info.ToString() << std::endl;
74             } catch (const std::exception& e) {
75                 cout << e.what() << std::endl;
76             }
77         }
78
79         if (false == it->status().ok()) {
80             cerr << "An error was found iterating over the database" << endl;
81             cerr << it->status().ToString() << endl;
82         }
83
84         delete it;
85     }
86 };
87
88
89
90 // This test creates random payment disclosure blobs and checks that they can be
91 // 1. inserted and retrieved from a database
92 // 2. serialized and deserialized without corruption
93 // Note that the zpd: prefix is not part of the payment disclosure blob itself.  It is only
94 // used as convention to improve the user experience when sharing payment disclosure blobs.
95 TEST(paymentdisclosure, mainnet) {
96     SelectParams(CBaseChainParams::MAIN);
97
98     boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
99     boost::filesystem::create_directories(pathTemp);
100     mapArgs["-datadir"] = pathTemp.string();
101
102     std::cout << "Test payment disclosure database created in folder: " << pathTemp.string() << std::endl;
103
104     PaymentDisclosureDBTest mydb(pathTemp);
105
106     for (int i=0; i<NUM_TRIES; i++) {
107         // Generate an ephemeral keypair for joinsplit sig.
108         uint256 joinSplitPubKey;
109         unsigned char buffer[crypto_sign_SECRETKEYBYTES] = {0};
110         crypto_sign_keypair(joinSplitPubKey.begin(), &buffer[0]);
111
112         // First 32 bytes contain private key, second 32 bytes contain public key.
113         ASSERT_EQ(0, memcmp(joinSplitPubKey.begin(), &buffer[0]+32, 32));
114         std::vector<unsigned char> vch(&buffer[0], &buffer[0] + 32);
115         uint256 joinSplitPrivKey = uint256(vch);
116
117         // Create payment disclosure key and info data to store in test database
118         size_t js = random_uint256().GetCheapHash() % std::numeric_limits<size_t>::max();
119         uint8_t n = random_uint256().GetCheapHash() % std::numeric_limits<uint8_t>::max();
120         PaymentDisclosureKey key { random_uint256(), js, n};
121         PaymentDisclosureInfo info;
122         info.esk = random_uint256();
123         info.joinSplitPrivKey = joinSplitPrivKey;
124         info.zaddr = libzcash::SproutSpendingKey::random().address();
125         ASSERT_TRUE(mydb.Put(key, info));
126
127         // Retrieve info from test database into new local variable and test it matches
128         PaymentDisclosureInfo info2;
129         ASSERT_TRUE(mydb.Get(key, info2));
130         ASSERT_EQ(info, info2);
131
132         // Modify this local variable and confirm it no longer matches
133         info2.esk = random_uint256();
134         info2.joinSplitPrivKey = random_uint256();
135         info2.zaddr = libzcash::SproutSpendingKey::random().address();        
136         ASSERT_NE(info, info2);
137
138         // Using the payment info object, let's create a dummy payload
139         PaymentDisclosurePayload payload;
140         payload.version = PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL;
141         payload.esk = info.esk;
142         payload.txid = key.hash;
143         payload.js = key.js;
144         payload.n = key.n;
145         payload.message = "random-" + boost::uuids::to_string(uuidgen());   // random message
146         payload.zaddr = info.zaddr;
147
148         // Serialize and hash the payload to generate a signature
149         uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0);
150
151         // Compute the payload signature
152         unsigned char payloadSig[64];
153         if (!(crypto_sign_detached(&payloadSig[0], NULL,
154             dataToBeSigned.begin(), 32,
155             &buffer[0] // buffer containing both private and public key required
156             ) == 0))
157         {
158             throw std::runtime_error("crypto_sign_detached failed");
159         }
160
161         // Sanity check
162         if (!(crypto_sign_verify_detached(&payloadSig[0],
163             dataToBeSigned.begin(), 32,
164             joinSplitPubKey.begin()
165             ) == 0))
166         {
167             throw std::runtime_error("crypto_sign_verify_detached failed");
168         }
169
170         // Convert signature buffer to boost array
171         std::array<unsigned char, 64> arrayPayloadSig;
172         memcpy(arrayPayloadSig.data(), &payloadSig[0], 64);
173
174         // Payment disclosure blob to pass around
175         PaymentDisclosure pd = {payload, arrayPayloadSig};
176
177         // Test payment disclosure constructors
178         PaymentDisclosure pd2(payload, arrayPayloadSig);
179         ASSERT_EQ(pd, pd2);
180         PaymentDisclosure pd3(joinSplitPubKey, key, info, payload.message);
181         ASSERT_EQ(pd, pd3);
182
183         // Verify serialization and deserialization works
184         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
185         ss << pd;
186         std::string ssHexString = HexStr(ss.begin(), ss.end());
187
188         PaymentDisclosure pdTmp;
189         CDataStream ssTmp(ParseHex(ssHexString), SER_NETWORK, PROTOCOL_VERSION);
190         ssTmp >> pdTmp;
191         ASSERT_EQ(pd, pdTmp);
192
193         CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
194         ss2 << pdTmp;
195         std::string ss2HexString = HexStr(ss2.begin(), ss2.end());
196         ASSERT_EQ(ssHexString, ss2HexString);
197
198         // Verify marker
199         ASSERT_EQ(pd.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES);
200         ASSERT_EQ(pdTmp.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES);
201         ASSERT_EQ(0, ssHexString.find("706462ff")); // Little endian encoding of PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES value
202
203         // Sanity check
204         PaymentDisclosure pdDummy;
205         ASSERT_NE(pd, pdDummy);
206     }
207
208 #if DUMP_DATABASE_TO_STDOUT == true
209     mydb.DebugDumpAllStdout();
210 #endif
211 }
This page took 0.036295 seconds and 4 git commands to generate.