diff options
Diffstat (limited to 'src/mint/mint_db.c')
-rw-r--r-- | src/mint/mint_db.c | 211 |
1 files changed, 210 insertions, 1 deletions
diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 786d04ac7..91d6705c3 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c | |||
@@ -13,11 +13,13 @@ | |||
13 | You should have received a copy of the GNU General Public License along with | 13 | You should have received a copy of the GNU General Public License along with |
14 | TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> | 14 | TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> |
15 | */ | 15 | */ |
16 | |||
16 | /** | 17 | /** |
17 | * @file mint_db.c | 18 | * @file mint_db.c |
18 | * @brief Low-level (statement-level) database access for the mint | 19 | * @brief Low-level (statement-level) database access for the mint |
19 | * @author Florian Dold | 20 | * @author Florian Dold |
20 | * @author Christian Grothoff | 21 | * @author Christian Grothoff |
22 | * @author Sree Harsha Totakura | ||
21 | * | 23 | * |
22 | * TODO: | 24 | * TODO: |
23 | * - The mint_db.h-API should ideally be what we need to port | 25 | * - The mint_db.h-API should ideally be what we need to port |
@@ -32,6 +34,7 @@ | |||
32 | #include "mint_db.h" | 34 | #include "mint_db.h" |
33 | #include <pthread.h> | 35 | #include <pthread.h> |
34 | 36 | ||
37 | |||
35 | /** | 38 | /** |
36 | * Thread-local database connection. | 39 | * Thread-local database connection. |
37 | * Contains a pointer to PGconn or NULL. | 40 | * Contains a pointer to PGconn or NULL. |
@@ -45,7 +48,6 @@ static pthread_key_t db_conn_threadlocal; | |||
45 | */ | 48 | */ |
46 | static char *TALER_MINT_db_connection_cfg_str; | 49 | static char *TALER_MINT_db_connection_cfg_str; |
47 | 50 | ||
48 | |||
49 | #define break_db_err(result) do { \ | 51 | #define break_db_err(result) do { \ |
50 | GNUNET_break(0); \ | 52 | GNUNET_break(0); \ |
51 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ | 53 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ |
@@ -60,6 +62,213 @@ static char *TALER_MINT_db_connection_cfg_str; | |||
60 | } while (0) | 62 | } while (0) |
61 | 63 | ||
62 | 64 | ||
65 | #define SQLEXEC_(conn, sql, result) \ | ||
66 | do { \ | ||
67 | result = PQexec (conn, sql); \ | ||
68 | if (PGRES_COMMAND_OK != PQresultStatus (result)) \ | ||
69 | { \ | ||
70 | break_db_err (result); \ | ||
71 | PQclear (result); result = NULL; \ | ||
72 | goto SQLEXEC_fail; \ | ||
73 | } \ | ||
74 | PQclear (result); result = NULL; \ | ||
75 | } while (0) | ||
76 | |||
77 | |||
78 | /** | ||
79 | * Set the given connection to use a temporary schema | ||
80 | * | ||
81 | * @param db the database connection | ||
82 | * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon error | ||
83 | */ | ||
84 | static int | ||
85 | set_temporary_schema (PGconn *db) | ||
86 | { | ||
87 | PGresult *result; | ||
88 | |||
89 | SQLEXEC_(db, | ||
90 | "CREATE SCHEMA IF NOT EXISTS " TALER_TEMP_SCHEMA_NAME ";" | ||
91 | "SET search_path to " TALER_TEMP_SCHEMA_NAME ";", | ||
92 | result); | ||
93 | return GNUNET_OK; | ||
94 | SQLEXEC_fail: | ||
95 | return GNUNET_SYSERR; | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Drop the temporary taler schema. This is only useful for testcases | ||
101 | * | ||
102 | * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure | ||
103 | */ | ||
104 | int | ||
105 | TALER_MINT_DB_drop_temporary (PGconn *db) | ||
106 | { | ||
107 | PGresult *result; | ||
108 | |||
109 | SQLEXEC_ (db, | ||
110 | "DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;", | ||
111 | result); | ||
112 | return GNUNET_OK; | ||
113 | SQLEXEC_fail: | ||
114 | return GNUNET_SYSERR; | ||
115 | } | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Create the necessary tables if they are not present | ||
120 | * | ||
121 | * @param temporary should we use a temporary schema | ||
122 | * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure | ||
123 | */ | ||
124 | int | ||
125 | TALER_MINT_DB_create_tables (int temporary) | ||
126 | { | ||
127 | PGresult *result; | ||
128 | PGconn *conn; | ||
129 | |||
130 | result = NULL; | ||
131 | conn = PQconnectdb (TALER_MINT_db_connection_cfg_str); | ||
132 | if (CONNECTION_OK != PQstatus (conn)) | ||
133 | { | ||
134 | LOG_ERROR ("Database connection failed: %s\n", | ||
135 | PQerrorMessage (conn)); | ||
136 | GNUNET_break (0); | ||
137 | return GNUNET_SYSERR; | ||
138 | } | ||
139 | if ((GNUNET_YES == temporary) | ||
140 | && (GNUNET_SYSERR == set_temporary_schema (conn))) | ||
141 | { | ||
142 | PQfinish (conn); | ||
143 | return GNUNET_SYSERR; | ||
144 | } | ||
145 | #define SQLEXEC(sql) SQLEXEC_(conn, sql, result); | ||
146 | /* reserves table is for summarization of a reserve. It is updated when new | ||
147 | funds are added and existing funds are withdrawn */ | ||
148 | SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves" | ||
149 | "(" | ||
150 | " reserve_pub BYTEA PRIMARY KEY" | ||
151 | ",current_balance_value INT4 NOT NULL" | ||
152 | ",current_balance_fraction INT4 NOT NULL" | ||
153 | ",balance_currency VARCHAR(4) NOT NULL" | ||
154 | ",expiration_date INT8 NOT NULL" | ||
155 | ")"); | ||
156 | /* reserves_in table collects the transactions which transfer funds into the | ||
157 | reserve. The amount and expiration date for the corresponding reserve are | ||
158 | updated when new transfer funds are added. The rows of this table | ||
159 | correspond to each incoming transaction. */ | ||
160 | SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_in" | ||
161 | "(" | ||
162 | " reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE" | ||
163 | ",balance_value INT4 NOT NULL" | ||
164 | ",balance_fraction INT4 NOT NULL" | ||
165 | ",expiration_date INT8 NOT NULL" | ||
166 | ");"); | ||
167 | result = PQexec (conn, | ||
168 | "CREATE INDEX reserves_in_index ON reserves_in (reserve_pub);"); | ||
169 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
170 | { | ||
171 | ExecStatusType status = PQresultStatus (result); | ||
172 | PQclear (result); | ||
173 | result = NULL; | ||
174 | goto SQLEXEC_fail; | ||
175 | } | ||
176 | PQclear (result); | ||
177 | SQLEXEC ("CREATE TABLE IF NOT EXISTS collectable_blindcoins" | ||
178 | "(" | ||
179 | "blind_ev BYTEA PRIMARY KEY" | ||
180 | ",blind_ev_sig BYTEA NOT NULL" | ||
181 | ",denom_pub BYTEA NOT NULL" | ||
182 | ",reserve_sig BYTEA NOT NULL" | ||
183 | ",reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE" | ||
184 | ");" | ||
185 | "CREATE INDEX collectable_blindcoins_index ON" | ||
186 | " collectable_blindcoins(reserve_pub)"); | ||
187 | SQLEXEC("CREATE TABLE IF NOT EXISTS known_coins " | ||
188 | "(" | ||
189 | " coin_pub BYTEA NOT NULL PRIMARY KEY" | ||
190 | ",denom_pub BYTEA NOT NULL" | ||
191 | ",denom_sig BYTEA NOT NULL" | ||
192 | ",expended_value INT4 NOT NULL" | ||
193 | ",expended_fraction INT4 NOT NULL" | ||
194 | ",expended_currency VARCHAR(4) NOT NULL" | ||
195 | ",refresh_session_pub BYTEA" | ||
196 | ")"); | ||
197 | SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions " | ||
198 | "(" | ||
199 | " session_pub BYTEA PRIMARY KEY CHECK (length(session_pub) = 32)" | ||
200 | ",session_melt_sig BYTEA" | ||
201 | ",session_commit_sig BYTEA" | ||
202 | ",noreveal_index INT2 NOT NULL" | ||
203 | // non-zero if all reveals were ok | ||
204 | // and the new coin signatures are ready | ||
205 | ",reveal_ok BOOLEAN NOT NULL DEFAULT false" | ||
206 | ") "); | ||
207 | SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order " | ||
208 | "( " | ||
209 | " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)" | ||
210 | ",newcoin_index INT2 NOT NULL " | ||
211 | ",denom_pub BYTEA NOT NULL " | ||
212 | ",PRIMARY KEY (session_pub, newcoin_index)" | ||
213 | ") "); | ||
214 | SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_link" | ||
215 | "(" | ||
216 | " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)" | ||
217 | ",transfer_pub BYTEA NOT NULL" | ||
218 | ",link_secret_enc BYTEA NOT NULL" | ||
219 | // index of the old coin in the customer's request | ||
220 | ",oldcoin_index INT2 NOT NULL" | ||
221 | // index for cut and choose, | ||
222 | // ranges from 0 to kappa-1 | ||
223 | ",cnc_index INT2 NOT NULL" | ||
224 | ")"); | ||
225 | SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin" | ||
226 | "(" | ||
227 | " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " | ||
228 | ",link_vector_enc BYTEA NOT NULL" | ||
229 | // index of the new coin in the customer's request | ||
230 | ",newcoin_index INT2 NOT NULL" | ||
231 | // index for cut and choose, | ||
232 | ",cnc_index INT2 NOT NULL" | ||
233 | ",coin_ev BYTEA NOT NULL" | ||
234 | ")"); | ||
235 | SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_melt" | ||
236 | "(" | ||
237 | " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " | ||
238 | ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) " | ||
239 | ",denom_pub BYTEA NOT NULL " | ||
240 | ",oldcoin_index INT2 NOT NULL" | ||
241 | ")"); | ||
242 | SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_collectable" | ||
243 | "(" | ||
244 | " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " | ||
245 | ",ev_sig BYTEA NOT NULL" | ||
246 | ",newcoin_index INT2 NOT NULL" | ||
247 | ")"); | ||
248 | SQLEXEC("CREATE TABLE IF NOT EXISTS deposits " | ||
249 | "( " | ||
250 | " coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)" | ||
251 | ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)" | ||
252 | ",transaction_id INT8 NOT NULL" | ||
253 | ",amount_currency VARCHAR(4) NOT NULL" | ||
254 | ",amount_value INT4 NOT NULL" | ||
255 | ",amount_fraction INT4 NOT NULL" | ||
256 | ",merchant_pub BYTEA NOT NULL" | ||
257 | ",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)" | ||
258 | ",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)" | ||
259 | ",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)" | ||
260 | ",wire TEXT NOT NULL" | ||
261 | ")"); | ||
262 | #undef SQLEXEC | ||
263 | PQfinish (conn); | ||
264 | return GNUNET_OK; | ||
265 | |||
266 | SQLEXEC_fail: | ||
267 | PQfinish (conn); | ||
268 | return GNUNET_SYSERR; | ||
269 | } | ||
270 | |||
271 | |||
63 | /** | 272 | /** |
64 | * Setup prepared statements. | 273 | * Setup prepared statements. |
65 | * | 274 | * |