aboutsummaryrefslogtreecommitdiff
path: root/src/mint/mint_db.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mint/mint_db.c')
-rw-r--r--src/mint/mint_db.c932
1 files changed, 452 insertions, 480 deletions
diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c
index 0f233a5ae..dcde03dc1 100644
--- a/src/mint/mint_db.c
+++ b/src/mint/mint_db.c
@@ -54,127 +54,49 @@ static char *TALER_MINT_db_connection_cfg_str;
54 } while (0) 54 } while (0)
55 55
56 56
57/**
58 * Locate the response for a /withdraw request under the
59 * key of the hash of the blinded message.
60 *
61 * @param db_conn database connection to use
62 * @param h_blind hash of the blinded message
63 * @param collectable corresponding collectable coin (blind signature)
64 * if a coin is found
65 * @return #GNUNET_SYSERR on internal error
66 * #GNUNET_NO if the collectable was not found
67 * #GNUNET_YES on success
68 */
69int
70TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
71 const struct GNUNET_HashCode *h_blind,
72 struct CollectableBlindcoin *collectable)
73{
74 PGresult *result;
75 struct TALER_DB_QueryParam params[] = {
76 TALER_DB_QUERY_PARAM_PTR (h_blind),
77 TALER_DB_QUERY_PARAM_END
78 };
79 char *sig_buf;
80 size_t sig_buf_size;
81 57
82 result = TALER_DB_exec_prepared (db_conn,
83 "get_collectable_blindcoins",
84 params);
85
86 if (PGRES_TUPLES_OK != PQresultStatus (result))
87 {
88 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
89 "Query failed: %s\n",
90 PQresultErrorMessage (result));
91 PQclear (result);
92 return GNUNET_SYSERR;
93 }
94 if (0 == PQntuples (result))
95 {
96 PQclear (result);
97 return GNUNET_NO;
98 }
99 58
100 struct TALER_DB_ResultSpec rs[] = {
101 TALER_DB_RESULT_SPEC_VAR("blind_sig", &sig_buf, &sig_buf_size),
102 TALER_DB_RESULT_SPEC("denom_pub", &collectable->denom_pub),
103 TALER_DB_RESULT_SPEC("reserve_sig", &collectable->reserve_sig),
104 TALER_DB_RESULT_SPEC("reserve_pub", &collectable->reserve_pub),
105 TALER_DB_RESULT_SPEC_END
106 };
107 59
108 if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0)) 60int
109 { 61TALER_TALER_DB_extract_amount_nbo (PGresult *result,
110 GNUNET_break (0); 62 unsigned int row,
111 PQclear (result); 63 int indices[3],
64 struct TALER_AmountNBO *denom_nbo)
65{
66 if ((indices[0] < 0) || (indices[1] < 0) || (indices[2] < 0))
67 return GNUNET_NO;
68 if (sizeof (uint32_t) != PQgetlength (result, row, indices[0]))
112 return GNUNET_SYSERR; 69 return GNUNET_SYSERR;
113 } 70 if (sizeof (uint32_t) != PQgetlength (result, row, indices[1]))
114 PQclear (result); 71 return GNUNET_SYSERR;
72 if (PQgetlength (result, row, indices[2]) > TALER_CURRENCY_LEN)
73 return GNUNET_SYSERR;
74 denom_nbo->value = *(uint32_t *) PQgetvalue (result, row, indices[0]);
75 denom_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, indices[1]);
76 memset (denom_nbo->currency, 0, TALER_CURRENCY_LEN);
77 memcpy (denom_nbo->currency, PQgetvalue (result, row, indices[2]), PQgetlength (result, row, indices[2]));
115 return GNUNET_OK; 78 return GNUNET_OK;
116} 79}
117 80
118 81
119/**
120 * Store collectable bit coin under the corresponding
121 * hash of the blinded message.
122 *
123 * @param db_conn database connection to use
124 * @param h_blind hash of the blinded message
125 * @param collectable corresponding collectable coin (blind signature)
126 * if a coin is found
127 * @return #GNUNET_SYSERR on internal error
128 * #GNUNET_NO if the collectable was not found
129 * #GNUNET_YES on success
130 */
131int 82int
132TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, 83TALER_TALER_DB_extract_amount (PGresult *result,
133 const struct GNUNET_HashCode *h_blind, 84 unsigned int row,
134 const struct CollectableBlindcoin *collectable) 85 int indices[3],
86 struct TALER_Amount *denom)
135{ 87{
136 PGresult *result; 88 struct TALER_AmountNBO denom_nbo;
137 char *sig_buf; 89 int res;
138 size_t sig_buf_size;
139
140 sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig,
141 &sig_buf);
142 {
143 struct TALER_DB_QueryParam params[] = {
144 TALER_DB_QUERY_PARAM_PTR (&h_blind),
145 TALER_DB_QUERY_PARAM_PTR_SIZED (sig_buf, sig_buf_size),
146 TALER_DB_QUERY_PARAM_PTR (&collectable->denom_pub),
147 TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_pub),
148 TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_sig),
149 TALER_DB_QUERY_PARAM_END
150 };
151
152 result = TALER_DB_exec_prepared (db_conn,
153 "insert_collectable_blindcoins",
154 params);
155 if (PGRES_COMMAND_OK != PQresultStatus (result))
156 {
157 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
158 "Query failed: %s\n",
159 PQresultErrorMessage (result));
160 PQclear (result);
161 return GNUNET_SYSERR;
162 }
163 90
164 if (0 != strcmp ("1", PQcmdTuples (result))) 91 res = TALER_TALER_DB_extract_amount_nbo (result, row, indices, &denom_nbo);
165 { 92 if (GNUNET_OK != res)
166 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 93 return res;
167 "Insert failed (updated '%s' tupes instead of '1')\n", 94 *denom = TALER_amount_ntoh (denom_nbo);
168 PQcmdTuples (result));
169 PQclear (result);
170 return GNUNET_SYSERR;
171 }
172 PQclear (result);
173 }
174 return GNUNET_OK; 95 return GNUNET_OK;
175} 96}
176 97
177 98
99
178int 100int
179TALER_MINT_DB_get_reserve (PGconn *db_conn, 101TALER_MINT_DB_get_reserve (PGconn *db_conn,
180 const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, 102 const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub,
@@ -681,88 +603,51 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
681 } 603 }
682 PQclear (result); 604 PQclear (result);
683 605
684 if (GNUNET_OK != TALER_MINT_DB_prepare_deposits (db_conn)) 606 result = PQprepare (db_conn, "insert_deposit",
685 { 607 "INSERT INTO deposits ("
686 GNUNET_break (0); 608 "coin_pub,"
687 return GNUNET_SYSERR; 609 "denom_pub,"
688 } 610 "transaction_id,"
689 611 "amount_value,"
690 return GNUNET_OK; 612 "amount_fraction,"
691} 613 "amount_currency,"
692 614 "merchant_pub,"
693 615 "h_contract,"
694/** 616 "h_wire,"
695 * Roll back the current transaction of a database connection. 617 "coin_sig,"
696 * 618 "wire"
697 * @param db_conn the database connection 619 ") VALUES ("
698 * @return GNUNET_OK on success 620 "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11"
699 */ 621 ")",
700int 622 11, NULL);
701TALER_MINT_DB_rollback (PGconn *db_conn) 623 EXITIF (PGRES_COMMAND_OK != PQresultStatus(result));
702{
703 PGresult *result;
704
705 result = PQexec(db_conn, "ROLLBACK");
706 if (PGRES_COMMAND_OK != PQresultStatus (result))
707 {
708 PQclear (result);
709 GNUNET_break (0);
710 return GNUNET_SYSERR;
711 }
712
713 PQclear (result); 624 PQclear (result);
714 return GNUNET_OK;
715}
716
717
718/**
719 * Roll back the current transaction of a database connection.
720 *
721 * @param db_conn the database connection
722 * @return GNUNET_OK on success
723 */
724int
725TALER_MINT_DB_commit (PGconn *db_conn)
726{
727 PGresult *result;
728
729 result = PQexec(db_conn, "COMMIT");
730 if (PGRES_COMMAND_OK != PQresultStatus (result))
731 {
732 PQclear (result);
733 GNUNET_break (0);
734 return GNUNET_SYSERR;
735 }
736 625
626 result = PQprepare (db_conn, "get_deposit",
627 "SELECT "
628 "coin_pub,"
629 "denom_pub,"
630 "transaction_id,"
631 "amount_value,"
632 "amount_fraction,"
633 "amount_currency,"
634 "merchant_pub,"
635 "h_contract,"
636 "h_wire,"
637 "coin_sig"
638 " FROM deposits WHERE ("
639 "coin_pub = $1"
640 ")",
641 1, NULL);
642 EXITIF (PGRES_COMMAND_OK != PQresultStatus(result));
737 PQclear (result); 643 PQclear (result);
738 return GNUNET_OK;
739}
740 644
645 return GNUNET_OK;
741 646
742/** 647 EXITIF_exit:
743 * Start a transaction. 648 break_db_err (result);
744 *
745 * @param db_conn the database connection
746 * @return GNUNET_OK on success
747 */
748int
749TALER_MINT_DB_transaction (PGconn *db_conn)
750{
751 PGresult *result;
752
753 result = PQexec(db_conn, "BEGIN");
754 if (PGRES_COMMAND_OK != PQresultStatus (result))
755 {
756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757 "Can't start transaction: %s\n",
758 PQresultErrorMessage (result));
759 PQclear (result);
760 GNUNET_break (0);
761 return GNUNET_SYSERR;
762 }
763
764 PQclear (result); 649 PQclear (result);
765 return GNUNET_OK; 650 return GNUNET_SYSERR;
766} 651}
767 652
768 653
@@ -1495,91 +1380,6 @@ TALER_MINT_DB_get_refresh_collectable (PGconn *db_conn,
1495} 1380}
1496 1381
1497 1382
1498
1499int
1500TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
1501 const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
1502 uint16_t oldcoin_index,
1503 const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
1504 const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub)
1505{
1506 uint16_t oldcoin_index_nbo = htons (oldcoin_index);
1507 char *buf;
1508 size_t buf_size;
1509 PGresult *result;
1510
1511 buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pub,
1512 &buf);
1513 {
1514 struct TALER_DB_QueryParam params[] = {
1515 TALER_DB_QUERY_PARAM_PTR(session_pub),
1516 TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
1517 TALER_DB_QUERY_PARAM_PTR(coin_pub),
1518 TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size),
1519 TALER_DB_QUERY_PARAM_END
1520 };
1521 result = TALER_DB_exec_prepared (db_conn, "insert_refresh_melt", params);
1522 }
1523 GNUNET_free (buf);
1524 if (PGRES_COMMAND_OK != PQresultStatus (result))
1525 {
1526 break_db_err (result);
1527 PQclear (result);
1528 return GNUNET_SYSERR;
1529 }
1530 PQclear (result);
1531 return GNUNET_OK;
1532}
1533
1534
1535
1536int
1537TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
1538 const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
1539 uint16_t oldcoin_index,
1540 struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
1541{
1542 uint16_t oldcoin_index_nbo = htons (oldcoin_index);
1543 struct TALER_DB_QueryParam params[] = {
1544 TALER_DB_QUERY_PARAM_PTR(session_pub),
1545 TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
1546 TALER_DB_QUERY_PARAM_END
1547 };
1548
1549 PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_melt", params);
1550
1551 if (PGRES_TUPLES_OK != PQresultStatus (result))
1552 {
1553 break_db_err (result);
1554 PQclear (result);
1555 return GNUNET_SYSERR;
1556 }
1557
1558 if (0 == PQntuples (result))
1559 {
1560 PQclear (result);
1561 return GNUNET_NO;
1562 }
1563
1564 GNUNET_assert (1 == PQntuples (result));
1565
1566 struct TALER_DB_ResultSpec rs[] = {
1567 TALER_DB_RESULT_SPEC("coin_pub", coin_pub),
1568 TALER_DB_RESULT_SPEC_END
1569 };
1570
1571 if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0))
1572 {
1573 PQclear (result);
1574 GNUNET_break (0);
1575 return GNUNET_SYSERR;
1576 }
1577
1578 PQclear (result);
1579 return GNUNET_OK;
1580}
1581
1582
1583int 1383int
1584TALER_db_get_link (PGconn *db_conn, 1384TALER_db_get_link (PGconn *db_conn,
1585 const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, 1385 const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
@@ -1744,319 +1544,491 @@ TALER_db_get_transfer (PGconn *db_conn,
1744} 1544}
1745 1545
1746 1546
1547
1548
1549
1550// Chaos
1551////////////////////////////////////////////////////////////////
1552// Order
1553
1554
1555
1556
1557
1558
1559/**
1560 * Close thread-local database connection when a thread is destroyed.
1561 *
1562 * @param closure we get from pthreads (the db handle)
1563 */
1564static void
1565db_conn_destroy (void *cls)
1566{
1567 PGconn *db_conn = cls;
1568 if (NULL != db_conn)
1569 PQfinish (db_conn);
1570}
1571
1572
1573/**
1574 * Initialize database subsystem.
1575 *
1576 * @param connection_cfg configuration to use to talk to DB
1577 * @return #GNUNET_OK on success
1578 */
1747int 1579int
1748TALER_MINT_DB_init_deposits (PGconn *conn, int tmp) 1580TALER_MINT_DB_init (const char *connection_cfg)
1749{ 1581{
1750 const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; 1582 if (0 != pthread_key_create (&db_conn_threadlocal,
1751 char *sql; 1583 &db_conn_destroy))
1752 PGresult *res; 1584 {
1753 int ret; 1585 fprintf (stderr,
1586 "Can't create pthread key.\n");
1587 return GNUNET_SYSERR;
1588 }
1589 TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg);
1590 return GNUNET_OK;
1591}
1592
1593
1594/**
1595 * Get the thread-local database-handle.
1596 * Connect to the db if the connection does not exist yet.
1597 *
1598 * @return the database connection, or NULL on error
1599 */
1600PGconn *
1601TALER_MINT_DB_get_connection (void)
1602{
1603 PGconn *db_conn;
1604
1605 if (NULL != (db_conn = pthread_getspecific (db_conn_threadlocal)))
1606 return db_conn;
1607
1608 db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
1609
1610 if (CONNECTION_OK != PQstatus (db_conn))
1611 {
1612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1613 "db connection failed: %s\n",
1614 PQerrorMessage (db_conn));
1615 GNUNET_break (0);
1616 return NULL;
1617 }
1754 1618
1755 res = NULL; 1619 if (GNUNET_OK != TALER_MINT_DB_prepare (db_conn))
1756 (void) GNUNET_asprintf (&sql, 1620 {
1757 "CREATE %1$s TABLE IF NOT EXISTS deposits (" 1621 GNUNET_break (0);
1758 " coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)" 1622 return NULL;
1759 ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)"
1760 ",transaction_id INT8 NOT NULL"
1761 ",amount_value INT4 NOT NULL"
1762 ",amount_fraction INT4 NOT NULL"
1763 ",amount_currency VARCHAR(4) NOT NULL"
1764 ",merchant_pub BYTEA NOT NULL"
1765 ",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)"
1766 ",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)"
1767 ",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)"
1768 ",wire TEXT NOT NULL"
1769 ")",
1770 tmp_str);
1771 res = PQexec (conn, sql);
1772 GNUNET_free (sql);
1773 if (PGRES_COMMAND_OK != PQresultStatus (res))
1774 {
1775 break_db_err (res);
1776 ret = GNUNET_SYSERR;
1777 } 1623 }
1778 else 1624 if (0 != pthread_setspecific (db_conn_threadlocal,
1779 ret = GNUNET_OK; 1625 db_conn))
1780 PQclear (res); 1626 {
1781 return ret; 1627 GNUNET_break (0);
1628 return NULL;
1629 }
1630 return db_conn;
1782} 1631}
1783 1632
1633
1634/**
1635 * Start a transaction.
1636 *
1637 * @param db_conn the database connection
1638 * @return #GNUNET_OK on success
1639 */
1784int 1640int
1785TALER_MINT_DB_prepare_deposits (PGconn *db_conn) 1641TALER_MINT_DB_transaction (PGconn *db_conn)
1786{ 1642{
1787 PGresult *result; 1643 PGresult *result;
1788 1644
1789 result = PQprepare (db_conn, "insert_deposit", 1645 result = PQexec(db_conn, "BEGIN");
1790 "INSERT INTO deposits (" 1646 if (PGRES_COMMAND_OK != PQresultStatus (result))
1791 "coin_pub," 1647 {
1792 "denom_pub," 1648 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1793 "transaction_id," 1649 "Can't start transaction: %s\n",
1794 "amount_value," 1650 PQresultErrorMessage (result));
1795 "amount_fraction," 1651 PQclear (result);
1796 "amount_currency," 1652 GNUNET_break (0);
1797 "merchant_pub," 1653 return GNUNET_SYSERR;
1798 "h_contract," 1654 }
1799 "h_wire,"
1800 "coin_sig,"
1801 "wire"
1802 ") VALUES ("
1803 "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11"
1804 ")",
1805 11, NULL);
1806 EXITIF (PGRES_COMMAND_OK != PQresultStatus(result));
1807 PQclear (result);
1808 1655
1809 result = PQprepare (db_conn, "get_deposit",
1810 "SELECT "
1811 "coin_pub,"
1812 "denom_pub,"
1813 "transaction_id,"
1814 "amount_value,"
1815 "amount_fraction,"
1816 "amount_currency,"
1817 "merchant_pub,"
1818 "h_contract,"
1819 "h_wire,"
1820 "coin_sig"
1821 " FROM deposits WHERE ("
1822 "coin_pub = $1"
1823 ")",
1824 1, NULL);
1825 EXITIF (PGRES_COMMAND_OK != PQresultStatus(result));
1826 PQclear (result); 1656 PQclear (result);
1827
1828 return GNUNET_OK; 1657 return GNUNET_OK;
1658}
1659
1660
1661/**
1662 * Roll back the current transaction of a database connection.
1663 *
1664 * @param db_conn the database connection
1665 * @return #GNUNET_OK on success
1666 */
1667int
1668TALER_MINT_DB_rollback (PGconn *db_conn)
1669{
1670 PGresult *result;
1671
1672 result = PQexec(db_conn,
1673 "ROLLBACK");
1674 if (PGRES_COMMAND_OK != PQresultStatus (result))
1675 {
1676 PQclear (result);
1677 GNUNET_break (0);
1678 return GNUNET_SYSERR;
1679 }
1829 1680
1830 EXITIF_exit:
1831 break_db_err (result);
1832 PQclear (result); 1681 PQclear (result);
1833 return GNUNET_SYSERR; 1682 return GNUNET_OK;
1834} 1683}
1835 1684
1836 1685
1686/**
1687 * Commit the current transaction of a database connection.
1688 *
1689 * @param db_conn the database connection
1690 * @return #GNUNET_OK on success
1691 */
1837int 1692int
1838TALER_MINT_DB_insert_deposit (PGconn *db_conn, 1693TALER_MINT_DB_commit (PGconn *db_conn)
1839 const struct Deposit *deposit)
1840{ 1694{
1841 struct TALER_DB_QueryParam params[]= {
1842 TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
1843 TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME!
1844 TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_sig), // FIXME!
1845 TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id),
1846 TALER_DB_QUERY_PARAM_PTR (&deposit->purpose), // FIXME: enum Ok here?
1847 TALER_DB_QUERY_PARAM_PTR (&deposit->amount.value),
1848 TALER_DB_QUERY_PARAM_PTR (&deposit->amount.fraction),
1849 TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->amount.currency,
1850 strlen (deposit->amount.currency)),
1851 TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub),
1852 TALER_DB_QUERY_PARAM_PTR (&deposit->h_contract),
1853 TALER_DB_QUERY_PARAM_PTR (&deposit->h_wire),
1854 TALER_DB_QUERY_PARAM_PTR (&deposit->csig),
1855 TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->wire,
1856 strlen ("FIXME")), // FIXME! json!
1857 TALER_DB_QUERY_PARAM_END
1858 };
1859 PGresult *result; 1695 PGresult *result;
1860 1696
1861 result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params); 1697 result = PQexec(db_conn,
1698 "COMMIT");
1862 if (PGRES_COMMAND_OK != PQresultStatus (result)) 1699 if (PGRES_COMMAND_OK != PQresultStatus (result))
1863 { 1700 {
1864 break_db_err (result);
1865 PQclear (result); 1701 PQclear (result);
1702 GNUNET_break (0);
1866 return GNUNET_SYSERR; 1703 return GNUNET_SYSERR;
1867 } 1704 }
1705
1868 PQclear (result); 1706 PQclear (result);
1869 return GNUNET_OK; 1707 return GNUNET_OK;
1870} 1708}
1871 1709
1872 1710
1711/**
1712 * Locate the response for a /withdraw request under the
1713 * key of the hash of the blinded message.
1714 *
1715 * @param db_conn database connection to use
1716 * @param h_blind hash of the blinded message
1717 * @param collectable corresponding collectable coin (blind signature)
1718 * if a coin is found
1719 * @return #GNUNET_SYSERR on internal error
1720 * #GNUNET_NO if the collectable was not found
1721 * #GNUNET_YES on success
1722 */
1873int 1723int
1874TALER_MINT_DB_get_deposit (PGconn *db_conn, 1724TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
1875 const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, 1725 const struct GNUNET_HashCode *h_blind,
1876 struct Deposit *deposit) 1726 struct CollectableBlindcoin *collectable)
1877{ 1727{
1728 PGresult *result;
1878 struct TALER_DB_QueryParam params[] = { 1729 struct TALER_DB_QueryParam params[] = {
1879 TALER_DB_QUERY_PARAM_PTR (coin_pub), 1730 TALER_DB_QUERY_PARAM_PTR (h_blind),
1880 TALER_DB_QUERY_PARAM_END 1731 TALER_DB_QUERY_PARAM_END
1881 }; 1732 };
1882 PGresult *result; 1733 char *sig_buf;
1734 size_t sig_buf_size;
1883 1735
1884 memset (deposit, 0, sizeof (struct Deposit));
1885 result = TALER_DB_exec_prepared (db_conn, 1736 result = TALER_DB_exec_prepared (db_conn,
1886 "get_deposit", 1737 "get_collectable_blindcoins",
1887 params); 1738 params);
1739
1888 if (PGRES_TUPLES_OK != PQresultStatus (result)) 1740 if (PGRES_TUPLES_OK != PQresultStatus (result))
1889 { 1741 {
1890 break_db_err (result); 1742 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1891 goto EXITIF_exit; 1743 "Query failed: %s\n",
1744 PQresultErrorMessage (result));
1745 PQclear (result);
1746 return GNUNET_SYSERR;
1892 } 1747 }
1893
1894 if (0 == PQntuples (result)) 1748 if (0 == PQntuples (result))
1895 { 1749 {
1896 PQclear (result); 1750 PQclear (result);
1897 return GNUNET_NO; 1751 return GNUNET_NO;
1898 } 1752 }
1899 1753
1900 if (1 != PQntuples (result)) 1754 struct TALER_DB_ResultSpec rs[] = {
1901 { 1755 TALER_DB_RESULT_SPEC_VAR("blind_sig", &sig_buf, &sig_buf_size),
1902 GNUNET_break (0); 1756 TALER_DB_RESULT_SPEC("denom_pub", &collectable->denom_pub),
1903 goto EXITIF_exit; 1757 TALER_DB_RESULT_SPEC("reserve_sig", &collectable->reserve_sig),
1904 } 1758 TALER_DB_RESULT_SPEC("reserve_pub", &collectable->reserve_pub),
1759 TALER_DB_RESULT_SPEC_END
1760 };
1905 1761
1762 if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0))
1906 { 1763 {
1907 char *denom_sig_buf; 1764 GNUNET_break (0);
1908 size_t denom_sig_buf_size; 1765 PQclear (result);
1909 char *dk_buf; 1766 return GNUNET_SYSERR;
1910 size_t dk_buf_size;
1911
1912 struct TALER_DB_ResultSpec rs[] = {
1913 TALER_DB_RESULT_SPEC ("coin_pub", &deposit->coin.coin_pub),
1914 TALER_DB_RESULT_SPEC_VAR ("denom_pub", &dk_buf, &dk_buf_size),
1915 TALER_DB_RESULT_SPEC_VAR ("denom_sig", &denom_sig_buf, &denom_sig_buf_size),
1916 TALER_DB_RESULT_SPEC ("transaction_id", &deposit->transaction_id),
1917 TALER_DB_RESULT_SPEC ("merchant_pub", &deposit->merchant_pub),
1918 TALER_DB_RESULT_SPEC ("h_contract", &deposit->h_contract),
1919 TALER_DB_RESULT_SPEC ("h_wire", &deposit->h_wire),
1920 TALER_DB_RESULT_SPEC ("purpose", &deposit->purpose),
1921 // FIXME: many fields missing...
1922 TALER_DB_RESULT_SPEC_END
1923 };
1924 EXITIF (GNUNET_OK !=
1925 TALER_DB_extract_result (result, rs, 0));
1926 EXITIF (GNUNET_OK !=
1927 TALER_DB_extract_amount (result, 0,
1928 "amount_value",
1929 "amount_fraction",
1930 "amount_currency",
1931 &deposit->amount));
1932 deposit->coin.denom_sig
1933 = GNUNET_CRYPTO_rsa_signature_decode (denom_sig_buf,
1934 denom_sig_buf_size);
1935 deposit->coin.denom_pub
1936 = GNUNET_CRYPTO_rsa_public_key_decode (dk_buf,
1937 dk_buf_size);
1938 } 1767 }
1939
1940 PQclear (result); 1768 PQclear (result);
1941 return GNUNET_OK; 1769 return GNUNET_OK;
1942
1943EXITIF_exit:
1944 PQclear (result);
1945 GNUNET_free_non_null (deposit);
1946 deposit = NULL;
1947 return GNUNET_SYSERR;
1948} 1770}
1949 1771
1950 1772
1951
1952/** 1773/**
1953 * Get the thread-local database-handle. 1774 * Store collectable bit coin under the corresponding
1954 * Connect to the db if the connection does not exist yet. 1775 * hash of the blinded message.
1955 * 1776 *
1956 * @param the database connection, or NULL on error 1777 * @param db_conn database connection to use
1778 * @param h_blind hash of the blinded message
1779 * @param collectable corresponding collectable coin (blind signature)
1780 * if a coin is found
1781 * @return #GNUNET_SYSERR on internal error
1782 * #GNUNET_NO if the collectable was not found
1783 * #GNUNET_YES on success
1957 */ 1784 */
1958PGconn * 1785int
1959TALER_MINT_DB_get_connection (void) 1786TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
1787 const struct GNUNET_HashCode *h_blind,
1788 const struct CollectableBlindcoin *collectable)
1960{ 1789{
1961 PGconn *db_conn; 1790 PGresult *result;
1791 char *sig_buf;
1792 size_t sig_buf_size;
1962 1793
1963 if (NULL != (db_conn = pthread_getspecific (db_conn_threadlocal))) 1794 sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig,
1964 return db_conn; 1795 &sig_buf);
1796 {
1797 struct TALER_DB_QueryParam params[] = {
1798 TALER_DB_QUERY_PARAM_PTR (&h_blind),
1799 TALER_DB_QUERY_PARAM_PTR_SIZED (sig_buf, sig_buf_size),
1800 TALER_DB_QUERY_PARAM_PTR (&collectable->denom_pub),
1801 TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_pub),
1802 TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_sig),
1803 TALER_DB_QUERY_PARAM_END
1804 };
1965 1805
1966 db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str); 1806 result = TALER_DB_exec_prepared (db_conn,
1807 "insert_collectable_blindcoins",
1808 params);
1809 if (PGRES_COMMAND_OK != PQresultStatus (result))
1810 {
1811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1812 "Query failed: %s\n",
1813 PQresultErrorMessage (result));
1814 PQclear (result);
1815 return GNUNET_SYSERR;
1816 }
1967 1817
1968 if (CONNECTION_OK != PQstatus (db_conn)) 1818 if (0 != strcmp ("1", PQcmdTuples (result)))
1969 { 1819 {
1970 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1820 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1971 "db connection failed: %s\n", 1821 "Insert failed (updated '%s' tupes instead of '1')\n",
1972 PQerrorMessage (db_conn)); 1822 PQcmdTuples (result));
1973 GNUNET_break (0); 1823 PQclear (result);
1974 return NULL; 1824 return GNUNET_SYSERR;
1825 }
1826 PQclear (result);
1975 } 1827 }
1828 return GNUNET_OK;
1829}
1976 1830
1977 if (GNUNET_OK != TALER_MINT_DB_prepare (db_conn)) 1831
1832/**
1833 * Check if we have the specified deposit already in the database.
1834 *
1835 * @param db_conn database connection
1836 * @param deposit deposit to search for
1837 * @return #GNUNET_YES if we know this operation,
1838 * #GNUNET_NO if this deposit is unknown to us
1839 */
1840int
1841TALER_MINT_DB_have_deposit (PGconn *db_conn,
1842 const struct Deposit *deposit)
1843{
1844 struct TALER_DB_QueryParam params[] = {
1845 TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), // FIXME
1846 TALER_DB_QUERY_PARAM_END
1847 };
1848 PGresult *result;
1849
1850 result = TALER_DB_exec_prepared (db_conn,
1851 "get_deposit",
1852 params);
1853 if (PGRES_TUPLES_OK !=
1854 PQresultStatus (result))
1978 { 1855 {
1979 GNUNET_break (0); 1856 break_db_err (result);
1980 return NULL; 1857 PQclear (result);
1858 return GNUNET_SYSERR;
1981 } 1859 }
1982 if (0 != pthread_setspecific (db_conn_threadlocal, db_conn)) 1860
1861 if (0 == PQntuples (result))
1983 { 1862 {
1984 GNUNET_break (0); 1863 PQclear (result);
1985 return NULL; 1864 return GNUNET_NO;
1986 } 1865 }
1987 return db_conn; 1866 return GNUNET_YES;
1988} 1867}
1989 1868
1990 1869
1991/** 1870/**
1992 * Close thread-local database connection when a thread is destroyed. 1871 * Insert information about deposited coin into the
1872 * database.
1993 * 1873 *
1994 * @param closure we get from pthreads (the db handle) 1874 * @param db_conn connection to the database
1875 * @param deposit deposit information to store
1876 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1995 */ 1877 */
1996static void 1878int
1997db_conn_destroy (void *cls) 1879TALER_MINT_DB_insert_deposit (PGconn *db_conn,
1880 const struct Deposit *deposit)
1998{ 1881{
1999 PGconn *db_conn = cls; 1882 struct TALER_DB_QueryParam params[]= {
2000 if (NULL != db_conn) 1883 TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
2001 PQfinish (db_conn); 1884 TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME!
1885 TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_sig), // FIXME!
1886 TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id),
1887 TALER_DB_QUERY_PARAM_PTR (&deposit->amount.value),
1888 TALER_DB_QUERY_PARAM_PTR (&deposit->amount.fraction),
1889 TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->amount.currency,
1890 strlen (deposit->amount.currency)),
1891 TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub),
1892 TALER_DB_QUERY_PARAM_PTR (&deposit->h_contract),
1893 TALER_DB_QUERY_PARAM_PTR (&deposit->h_wire),
1894 TALER_DB_QUERY_PARAM_PTR (&deposit->csig),
1895 TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->wire,
1896 strlen ("FIXME")), // FIXME! json!
1897 TALER_DB_QUERY_PARAM_END
1898 };
1899 PGresult *result;
1900
1901 result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params);
1902 if (PGRES_COMMAND_OK != PQresultStatus (result))
1903 {
1904 break_db_err (result);
1905 PQclear (result);
1906 return GNUNET_SYSERR;
1907 }
1908 PQclear (result);
1909 return GNUNET_OK;
2002} 1910}
2003 1911
2004 1912
2005/** 1913/**
2006 * Initialize database subsystem. 1914 * Test if the given /refresh/melt request is known to us.
2007 * 1915 *
2008 * @param connection_cfg configuration to use to talk to DB 1916 * @param db_conn database connection
2009 * @return #GNUNET_OK on success 1917 * @param melt melt operation
1918 * @return #GNUNET_YES if known,
1919 * #GNUENT_NO if not,
1920 * #GNUNET_SYSERR on internal error
2010 */ 1921 */
2011int 1922int
2012TALER_MINT_DB_init (const char *connection_cfg) 1923TALER_MINT_DB_have_refresh_melt (PGconn *db_conn,
1924 const struct RefreshMelt *melt)
2013{ 1925{
1926 uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index);
1927 struct TALER_DB_QueryParam params[] = {
1928 TALER_DB_QUERY_PARAM_PTR(&melt->session_pub),
1929 TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
1930 TALER_DB_QUERY_PARAM_END
1931 };
2014 1932
2015 if (0 != pthread_key_create (&db_conn_threadlocal, &db_conn_destroy)) 1933 PGresult *result = TALER_DB_exec_prepared (db_conn,
1934 "get_refresh_melt",
1935 params);
1936 if (PGRES_TUPLES_OK != PQresultStatus (result))
2016 { 1937 {
2017 fprintf (stderr, 1938 break_db_err (result);
2018 "Can't create pthread key.\n"); 1939 PQclear (result);
2019 return GNUNET_SYSERR; 1940 return GNUNET_SYSERR;
2020 } 1941 }
2021 TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg); 1942
2022 return GNUNET_OK; 1943 if (0 == PQntuples (result))
1944 {
1945 PQclear (result);
1946 return GNUNET_NO;
1947 }
1948 GNUNET_break (1 == PQntuples (result));
1949 PQclear (result);
1950 return GNUNET_YES;
2023} 1951}
2024 1952
2025 1953
1954
1955/**
1956 * Store the given /refresh/melt request in the database.
1957 *
1958 * @param db_conn database connection
1959 * @param melt melt operation
1960 * @return #GNUNET_OK on success
1961 * #GNUNET_SYSERR on internal error
1962 */
2026int 1963int
2027TALER_TALER_DB_extract_amount_nbo (PGresult *result, 1964TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
2028 unsigned int row, 1965 const struct RefreshMelt *melt)
2029 int indices[3],
2030 struct TALER_AmountNBO *denom_nbo)
2031{ 1966{
2032 if ((indices[0] < 0) || (indices[1] < 0) || (indices[2] < 0)) 1967 uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index);
2033 return GNUNET_NO; 1968 char *buf;
2034 if (sizeof (uint32_t) != PQgetlength (result, row, indices[0])) 1969 size_t buf_size;
2035 return GNUNET_SYSERR; 1970 PGresult *result;
2036 if (sizeof (uint32_t) != PQgetlength (result, row, indices[1])) 1971
2037 return GNUNET_SYSERR; 1972 buf_size = GNUNET_CRYPTO_rsa_public_key_encode (melt->coin.denom_pub,
2038 if (PQgetlength (result, row, indices[2]) > TALER_CURRENCY_LEN) 1973 &buf);
1974 {
1975 struct TALER_DB_QueryParam params[] = {
1976 TALER_DB_QUERY_PARAM_PTR(&melt->session_pub),
1977 TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
1978 TALER_DB_QUERY_PARAM_PTR(&melt->coin.coin_pub),
1979 TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size),
1980 TALER_DB_QUERY_PARAM_END
1981 };
1982 result = TALER_DB_exec_prepared (db_conn, "insert_refresh_melt", params);
1983 }
1984 GNUNET_free (buf);
1985 if (PGRES_COMMAND_OK != PQresultStatus (result))
1986 {
1987 break_db_err (result);
1988 PQclear (result);
2039 return GNUNET_SYSERR; 1989 return GNUNET_SYSERR;
2040 denom_nbo->value = *(uint32_t *) PQgetvalue (result, row, indices[0]); 1990 }
2041 denom_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, indices[1]); 1991 PQclear (result);
2042 memset (denom_nbo->currency, 0, TALER_CURRENCY_LEN);
2043 memcpy (denom_nbo->currency, PQgetvalue (result, row, indices[2]), PQgetlength (result, row, indices[2]));
2044 return GNUNET_OK; 1992 return GNUNET_OK;
2045} 1993}
2046 1994
2047 1995
1996/**
1997 * Get information about melted coin details from the database.
1998 *
1999 * @param db_conn database connection
2000 * @param session session key of the melt operation
2001 * @param oldcoin_index index of the coin to retrieve
2002 * @param melt melt data to fill in
2003 * @return #GNUNET_OK on success
2004 * #GNUNET_SYSERR on internal error
2005 */
2048int 2006int
2049TALER_TALER_DB_extract_amount (PGresult *result, 2007TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
2050 unsigned int row, 2008 const struct GNUNET_CRYPTO_EddsaPublicKey *session,
2051 int indices[3], 2009 uint16_t oldcoin_index,
2052 struct TALER_Amount *denom) 2010 struct RefreshMelt *melt)
2053{ 2011{
2054 struct TALER_AmountNBO denom_nbo; 2012 GNUNET_break (0);
2055 int res; 2013 return GNUNET_SYSERR;
2014}
2056 2015
2057 res = TALER_TALER_DB_extract_amount_nbo (result, row, indices, &denom_nbo); 2016
2058 if (GNUNET_OK != res) 2017/**
2059 return res; 2018 * Compile a list of all (historic) transactions performed
2060 *denom = TALER_amount_ntoh (denom_nbo); 2019 * with the given coin (/refresh/melt and /deposit operations).
2061 return GNUNET_OK; 2020 *
2021 * @param db_conn database connection
2022 * @param coin_pub coin to investigate
2023 * @return list of transactions, NULL if coin is fresh
2024 */
2025struct TALER_MINT_DB_TransactionList *
2026TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
2027 const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
2028{
2029 GNUNET_break (0); // FIXME: implement!
2030 return NULL;
2062} 2031}
2032
2033
2034/* end of mint_db.c */