This commit is contained in:
Christian Grothoff 2015-06-11 13:02:57 +02:00
parent 95f4cdc6df
commit babeff1968
4 changed files with 123 additions and 108 deletions

View File

@ -744,9 +744,9 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*get_withdraw_info) (void *cls, (*get_withdraw_info) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *sesssion,
const struct GNUNET_HashCode *h_blind, const struct GNUNET_HashCode *h_blind,
struct TALER_MINTDB_CollectableBlindcoin *collectable); struct TALER_MINTDB_CollectableBlindcoin *collectable);
/** /**
@ -755,11 +755,6 @@ struct TALER_MINTDB_Plugin
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection to use * @param sesssion database connection to use
* @param h_blind hash of the blinded message which is (blindly) signed by the
* signature in @a collectable
* @param withdraw amount by which the reserve will be withdrawn with this
* transaction (based on the value of the denomination key
* used for the signature); coin value plus fee.
* @param collectable corresponding collectable coin (blind signature) * @param collectable corresponding collectable coin (blind signature)
* if a coin is found * if a coin is found
* @return #GNUNET_SYSERR on internal error * @return #GNUNET_SYSERR on internal error
@ -768,10 +763,8 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*insert_withdraw_info) (void *cls, (*insert_withdraw_info) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *sesssion,
const struct GNUNET_HashCode *h_blind, const struct TALER_MINTDB_CollectableBlindcoin *collectable);
struct TALER_Amount withdraw,
const struct TALER_MINTDB_CollectableBlindcoin *collectable);
/** /**

View File

@ -294,9 +294,9 @@ TMH_DB_execute_withdraw_sign (struct MHD_Connection *connection,
return TMH_RESPONSE_reply_internal_db_error (connection); return TMH_RESPONSE_reply_internal_db_error (connection);
} }
res = TMH_plugin->get_withdraw_info (TMH_plugin->cls, res = TMH_plugin->get_withdraw_info (TMH_plugin->cls,
session, session,
&h_blind, &h_blind,
&collectable); &collectable);
if (GNUNET_SYSERR == res) if (GNUNET_SYSERR == res)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -446,17 +446,15 @@ TMH_DB_execute_withdraw_sign (struct MHD_Connection *connection,
} }
collectable.sig.rsa_signature = sig; collectable.sig.rsa_signature = sig;
collectable.denom_pub = *denomination_pub; collectable.denom_pub = *denomination_pub;
collectable.amount_with_fee = amount_required;
collectable.withdraw_fee = fee_withdraw;
collectable.reserve_pub = *reserve; collectable.reserve_pub = *reserve;
GNUNET_CRYPTO_hash (blinded_msg, collectable.h_coin_envelope = h_blind;
blinded_msg_len,
&collectable.h_coin_envelope);
collectable.reserve_sig = *signature; collectable.reserve_sig = *signature;
if (GNUNET_OK != if (GNUNET_OK !=
TMH_plugin->insert_withdraw_info (TMH_plugin->cls, TMH_plugin->insert_withdraw_info (TMH_plugin->cls,
session, session,
&h_blind, &collectable))
amount_required,
&collectable))
{ {
GNUNET_break (0); GNUNET_break (0);
GNUNET_CRYPTO_rsa_signature_free (sig); GNUNET_CRYPTO_rsa_signature_free (sig);
@ -871,7 +869,7 @@ check_commitment (struct MHD_Connection *connection,
&transfer_privs[j], &transfer_privs[j],
&melts[j].coin.coin_pub, &melts[j].coin.coin_pub,
&shared_secret)) &shared_secret))
{ {
GNUNET_free (commit_links); GNUNET_free (commit_links);
return (MHD_YES == return (MHD_YES ==
TMH_RESPONSE_reply_internal_error (connection, TMH_RESPONSE_reply_internal_error (connection,

View File

@ -266,19 +266,21 @@ postgres_create_tables (void *cls,
key, as (broken) clients that use a non-random coin and blinding factor key, as (broken) clients that use a non-random coin and blinding factor
should fail to even withdraw, as otherwise the coins will fail to deposit should fail to even withdraw, as otherwise the coins will fail to deposit
(as they really must be unique). */ (as they really must be unique). */
/* TODO: maybe add withdraw fee and amount_with_fee explicitly to table, SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves_out"
so we can init those fields on select? #3825
TODO: maybe add timestamp of when the operation was performed, so we
can influence the reserves' expiration_date not just based on
incoming but also based on outgoing transactions? */
SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves_out"
"(h_blind_ev BYTEA PRIMARY KEY" "(h_blind_ev BYTEA PRIMARY KEY"
",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)"
",denom_sig BYTEA NOT NULL" ",denom_sig BYTEA NOT NULL"
",reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32) REFERENCES reserves (reserve_pub) ON DELETE CASCADE" ",reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32) REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
",reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)" ",reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)"
",execution_date INT8 NOT NULL"
",amount_with_fee_val INT8 NOT NULL"
",amount_with_fee_frac INT4 NOT NULL"
",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
",withdraw_fee_val INT8 NOT NULL"
",withdraw_fee_frac INT4 NOT NULL"
",withdraw_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
");"); ");");
/* Index blindcoins(reserve_pub) for get_reserves_blindcoins statement */ /* Index blindcoins(reserve_pub) for get_reserves_out statement */
SQLEXEC_INDEX ("CREATE INDEX reserves_out_reserve_pub_index ON" SQLEXEC_INDEX ("CREATE INDEX reserves_out_reserve_pub_index ON"
" reserves_out (reserve_pub)"); " reserves_out (reserve_pub)");
/* Table with coins that have been (partially) spent, used to track /* Table with coins that have been (partially) spent, used to track
@ -529,9 +531,16 @@ postgres_prepare (PGconn *db_conn)
",denom_sig" ",denom_sig"
",reserve_pub" ",reserve_pub"
",reserve_sig" ",reserve_sig"
",execution_date"
",amount_with_fee_val"
",amount_with_fee_frac"
",amount_with_fee_curr"
",withdraw_fee_val"
",withdraw_fee_frac"
",withdraw_fee_curr"
") VALUES " ") VALUES "
"($1, $2, $3, $4, $5);", "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);",
5, NULL); 12, NULL);
/* Used in #postgres_get_withdraw_info() to /* Used in #postgres_get_withdraw_info() to
locate the response for a /withdraw/sign request locate the response for a /withdraw/sign request
using the hash of the blinded message. Used to using the hash of the blinded message. Used to
@ -542,6 +551,13 @@ postgres_prepare (PGconn *db_conn)
",denom_sig" ",denom_sig"
",reserve_sig" ",reserve_sig"
",reserve_pub" ",reserve_pub"
",execution_date"
",amount_with_fee_val"
",amount_with_fee_frac"
",amount_with_fee_curr"
",withdraw_fee_val"
",withdraw_fee_frac"
",withdraw_fee_curr"
" FROM reserves_out" " FROM reserves_out"
" WHERE h_blind_ev=$1", " WHERE h_blind_ev=$1",
1, NULL); 1, NULL);
@ -549,12 +565,19 @@ postgres_prepare (PGconn *db_conn)
obtain all of the /withdraw/sign operations that obtain all of the /withdraw/sign operations that
have been performed on a given reserve. (i.e. to have been performed on a given reserve. (i.e. to
demonstrate double-spending) */ demonstrate double-spending) */
PREPARE ("get_reserves_blindcoins", PREPARE ("get_reserves_out",
"SELECT" "SELECT"
" h_blind_ev" " h_blind_ev"
",denom_pub" ",denom_pub"
",denom_sig" ",denom_sig"
",reserve_sig" ",reserve_sig"
",execution_date"
",amount_with_fee_val"
",amount_with_fee_frac"
",amount_with_fee_curr"
",withdraw_fee_val"
",withdraw_fee_frac"
",withdraw_fee_curr"
" FROM reserves_out" " FROM reserves_out"
" WHERE reserve_pub=$1;", " WHERE reserve_pub=$1;",
1, NULL); 1, NULL);
@ -1273,17 +1296,15 @@ postgres_reserves_in_insert (void *cls,
*/ */
static int static int
postgres_get_withdraw_info (void *cls, postgres_get_withdraw_info (void *cls,
struct TALER_MINTDB_Session *session, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *h_blind, const struct GNUNET_HashCode *h_blind,
struct TALER_MINTDB_CollectableBlindcoin *collectable) struct TALER_MINTDB_CollectableBlindcoin *collectable)
{ {
PGresult *result; PGresult *result;
struct TALER_PQ_QueryParam params[] = { struct TALER_PQ_QueryParam params[] = {
TALER_PQ_query_param_auto_from_type (h_blind), TALER_PQ_query_param_auto_from_type (h_blind),
TALER_PQ_query_param_end TALER_PQ_query_param_end
}; };
struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
struct GNUNET_CRYPTO_rsa_Signature *denom_sig;
int ret; int ret;
ret = GNUNET_SYSERR; ret = GNUNET_SYSERR;
@ -1301,31 +1322,35 @@ postgres_get_withdraw_info (void *cls,
ret = GNUNET_NO; ret = GNUNET_NO;
goto cleanup; goto cleanup;
} }
struct TALER_PQ_ResultSpec rs[] = {
TALER_PQ_result_spec_rsa_public_key("denom_pub", &denom_pub),
TALER_PQ_result_spec_rsa_signature("denom_sig", &denom_sig),
TALER_PQ_result_spec_auto_from_type("reserve_sig", &collectable->reserve_sig),
TALER_PQ_result_spec_auto_from_type("reserve_pub", &collectable->reserve_pub),
/* FIXME: collectable->amount_with_fee and
collectable->withdraw_fee not initialized! (#3825) */
TALER_PQ_result_spec_end
};
if (GNUNET_OK != TALER_PQ_extract_result (result, rs, 0))
{ {
GNUNET_break (0); struct TALER_PQ_ResultSpec rs[] = {
goto cleanup; TALER_PQ_result_spec_rsa_public_key ("denom_pub",
&collectable->denom_pub.rsa_public_key),
TALER_PQ_result_spec_rsa_signature ("denom_sig",
&collectable->sig.rsa_signature),
TALER_PQ_result_spec_auto_from_type ("reserve_sig",
&collectable->reserve_sig),
TALER_PQ_result_spec_auto_from_type ("reserve_pub",
&collectable->reserve_pub),
TALER_PQ_result_spec_amount ("amount_with_fee",
&collectable->amount_with_fee),
TALER_PQ_result_spec_amount ("withdraw_fee",
&collectable->withdraw_fee),
TALER_PQ_result_spec_end
};
if (GNUNET_OK !=
TALER_PQ_extract_result (result, rs, 0))
{
GNUNET_break (0);
goto cleanup;
}
} }
/* FIXME: why do we bother with the temporary variables? */
collectable->denom_pub.rsa_public_key = denom_pub;
collectable->sig.rsa_signature = denom_sig;
collectable->h_coin_envelope = *h_blind; collectable->h_coin_envelope = *h_blind;
ret = GNUNET_YES; ret = GNUNET_YES;
cleanup: cleanup:
PQclear (result); PQclear (result);
if (GNUNET_YES != ret)
TALER_PQ_cleanup_result (rs);
return ret; return ret;
} }
@ -1336,11 +1361,6 @@ postgres_get_withdraw_info (void *cls,
* *
* @param cls the `struct PostgresClosure` with the plugin-specific state * @param cls the `struct PostgresClosure` with the plugin-specific state
* @param session database connection to use * @param session database connection to use
* @param h_blind hash of the blinded message. FIXME:
* redundant information given @a collectable's h_coin_envelope, right? #3825
* @param withdraw amount by which the reserve will be reduced with this
* transaction (coin value plus fee). FIXME:
* redundant information given @a collectable's amount_with_fee! #3825
* @param collectable corresponding collectable coin (blind signature) * @param collectable corresponding collectable coin (blind signature)
* if a coin is found * if a coin is found
* @return #GNUNET_SYSERR on internal error * @return #GNUNET_SYSERR on internal error
@ -1349,21 +1369,22 @@ postgres_get_withdraw_info (void *cls,
*/ */
static int static int
postgres_insert_withdraw_info (void *cls, postgres_insert_withdraw_info (void *cls,
struct TALER_MINTDB_Session *session, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *h_blind, const struct TALER_MINTDB_CollectableBlindcoin *collectable)
struct TALER_Amount withdraw,
const struct TALER_MINTDB_CollectableBlindcoin *collectable)
{ {
PGresult *result; PGresult *result;
struct TALER_MINTDB_Reserve reserve; struct TALER_MINTDB_Reserve reserve;
int ret = GNUNET_SYSERR; int ret = GNUNET_SYSERR;
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
struct TALER_PQ_QueryParam params[] = { struct TALER_PQ_QueryParam params[] = {
TALER_PQ_query_param_auto_from_type (h_blind), TALER_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
TALER_PQ_query_param_rsa_public_key (collectable->denom_pub.rsa_public_key), TALER_PQ_query_param_rsa_public_key (collectable->denom_pub.rsa_public_key),
TALER_PQ_query_param_rsa_signature (collectable->sig.rsa_signature), TALER_PQ_query_param_rsa_signature (collectable->sig.rsa_signature),
TALER_PQ_query_param_auto_from_type (&collectable->reserve_pub), TALER_PQ_query_param_auto_from_type (&collectable->reserve_pub),
TALER_PQ_query_param_auto_from_type (&collectable->reserve_sig), TALER_PQ_query_param_auto_from_type (&collectable->reserve_sig),
/* FIXME: store fees? #3825 */ TALER_PQ_query_param_absolute_time (&now),
TALER_PQ_query_param_amount (&collectable->amount_with_fee),
TALER_PQ_query_param_amount (&collectable->withdraw_fee),
TALER_PQ_query_param_end TALER_PQ_query_param_end
}; };
@ -1392,7 +1413,7 @@ postgres_insert_withdraw_info (void *cls,
if (GNUNET_SYSERR == if (GNUNET_SYSERR ==
TALER_amount_subtract (&reserve.balance, TALER_amount_subtract (&reserve.balance,
&reserve.balance, &reserve.balance,
&withdraw)) &collectable->amount_with_fee))
{ {
/* Should have been checked before we got here... */ /* Should have been checked before we got here... */
GNUNET_break (0); GNUNET_break (0);
@ -1501,11 +1522,6 @@ postgres_get_reserve_history (void *cls,
PQclear (result); PQclear (result);
} }
{ {
struct GNUNET_HashCode h_blind_ev;
struct TALER_ReserveSignatureP reserve_sig;
struct TALER_MINTDB_CollectableBlindcoin *cbc;
struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
struct GNUNET_CRYPTO_rsa_Signature *denom_sig;
struct TALER_PQ_QueryParam params[] = { struct TALER_PQ_QueryParam params[] = {
TALER_PQ_query_param_auto_from_type (reserve_pub), TALER_PQ_query_param_auto_from_type (reserve_pub),
TALER_PQ_query_param_end TALER_PQ_query_param_end
@ -1515,7 +1531,7 @@ postgres_get_reserve_history (void *cls,
GNUNET_assert (NULL != rh_tail); GNUNET_assert (NULL != rh_tail);
GNUNET_assert (NULL == rh_tail->next); GNUNET_assert (NULL == rh_tail->next);
result = TALER_PQ_exec_prepared (session->conn, result = TALER_PQ_exec_prepared (session->conn,
"get_reserves_blindcoins", "get_reserves_out",
params); params);
if (PGRES_TUPLES_OK != PQresultStatus (result)) if (PGRES_TUPLES_OK != PQresultStatus (result))
{ {
@ -1526,28 +1542,35 @@ postgres_get_reserve_history (void *cls,
rows = PQntuples (result); rows = PQntuples (result);
while (0 < rows) while (0 < rows)
{ {
struct TALER_PQ_ResultSpec rs[] = { struct TALER_MINTDB_CollectableBlindcoin *cbc;
TALER_PQ_result_spec_auto_from_type ("h_blind_ev", &h_blind_ev),
TALER_PQ_result_spec_rsa_public_key ("denom_pub", &denom_pub),
TALER_PQ_result_spec_rsa_signature ("denom_sig", &denom_sig),
TALER_PQ_result_spec_auto_from_type ("reserve_sig", &reserve_sig),
TALER_PQ_result_spec_end
};
if (GNUNET_YES !=
TALER_PQ_extract_result (result, rs, --rows))
{
GNUNET_break (0);
PQclear (result);
goto cleanup;
}
cbc = GNUNET_new (struct TALER_MINTDB_CollectableBlindcoin); cbc = GNUNET_new (struct TALER_MINTDB_CollectableBlindcoin);
cbc->sig.rsa_signature = denom_sig; {
cbc->denom_pub.rsa_public_key = denom_pub; struct TALER_PQ_ResultSpec rs[] = {
/* FIXME: amount_with_fee and withdraw_fee not initialized! #3825 */ TALER_PQ_result_spec_auto_from_type ("h_blind_ev",
cbc->h_coin_envelope = h_blind_ev; &cbc->h_coin_envelope),
cbc->reserve_pub = *reserve_pub; TALER_PQ_result_spec_rsa_public_key ("denom_pub",
cbc->reserve_sig = reserve_sig; &cbc->denom_pub.rsa_public_key),
TALER_PQ_result_spec_rsa_signature ("denom_sig",
&cbc->sig.rsa_signature),
TALER_PQ_result_spec_auto_from_type ("reserve_sig",
&cbc->reserve_sig),
TALER_PQ_result_spec_amount ("amount_with_fee",
&cbc->amount_with_fee),
TALER_PQ_result_spec_amount ("withdraw_fee",
&cbc->withdraw_fee),
TALER_PQ_result_spec_end
};
if (GNUNET_YES !=
TALER_PQ_extract_result (result, rs, --rows))
{
GNUNET_break (0);
GNUNET_free (cbc);
PQclear (result);
goto cleanup;
}
cbc->reserve_pub = *reserve_pub;
}
rh_tail->next = GNUNET_new (struct TALER_MINTDB_ReserveHistory); rh_tail->next = GNUNET_new (struct TALER_MINTDB_ReserveHistory);
rh_tail = rh_tail->next; rh_tail = rh_tail->next;
rh_tail->type = TALER_MINTDB_RO_WITHDRAW_COIN; rh_tail->type = TALER_MINTDB_RO_WITHDRAW_COIN;

View File

@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/ */
/** /**
* @file mint/test_mint_db.c * @file mint/test_mintdb.c
* @brief test cases for DB interaction functions * @brief test cases for DB interaction functions
* @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Sree Harsha Totakura <sreeharsha@totakura.in>
*/ */
@ -239,7 +239,6 @@ run (void *cls,
struct GNUNET_TIME_Absolute expiry; struct GNUNET_TIME_Absolute expiry;
struct TALER_Amount amount; struct TALER_Amount amount;
struct DenomKeyPair *dkp; struct DenomKeyPair *dkp;
struct GNUNET_HashCode h_blind;
struct TALER_MINTDB_CollectableBlindcoin cbc; struct TALER_MINTDB_CollectableBlindcoin cbc;
struct TALER_MINTDB_CollectableBlindcoin cbc2; struct TALER_MINTDB_CollectableBlindcoin cbc2;
struct TALER_MINTDB_ReserveHistory *rh; struct TALER_MINTDB_ReserveHistory *rh;
@ -321,24 +320,25 @@ run (void *cls,
amount.currency, amount.currency,
expiry.abs_value_us)); expiry.abs_value_us));
dkp = create_denom_key_pair (1024, session); dkp = create_denom_key_pair (1024, session);
RND_BLK(&h_blind); RND_BLK(&cbc.h_coin_envelope);
RND_BLK(&cbc.reserve_sig); RND_BLK(&cbc.reserve_sig);
cbc.denom_pub = dkp->pub; cbc.denom_pub = dkp->pub;
cbc.sig.rsa_signature cbc.sig.rsa_signature
= GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key, = GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key,
&h_blind, &cbc.h_coin_envelope,
sizeof (h_blind)); sizeof (cbc.h_coin_envelope));
(void) memcpy (&cbc.reserve_pub, (void) memcpy (&cbc.reserve_pub,
&reserve_pub, &reserve_pub,
sizeof (reserve_pub)); sizeof (reserve_pub));
amount.value--; amount.value--;
amount.fraction--; amount.fraction--;
cbc.amount_with_fee = amount;
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (CURRENCY, &cbc.withdraw_fee));
FAILIF (GNUNET_OK != FAILIF (GNUNET_OK !=
plugin->insert_withdraw_info (plugin->cls, plugin->insert_withdraw_info (plugin->cls,
session, session,
&h_blind, &cbc));
amount,
&cbc));
FAILIF (GNUNET_OK != FAILIF (GNUNET_OK !=
check_reserve (session, check_reserve (session,
&reserve_pub, &reserve_pub,
@ -348,9 +348,9 @@ run (void *cls,
expiry.abs_value_us)); expiry.abs_value_us));
FAILIF (GNUNET_YES != FAILIF (GNUNET_YES !=
plugin->get_withdraw_info (plugin->cls, plugin->get_withdraw_info (plugin->cls,
session, session,
&h_blind, &cbc.h_coin_envelope,
&cbc2)); &cbc2));
FAILIF (NULL == cbc2.denom_pub.rsa_public_key); FAILIF (NULL == cbc2.denom_pub.rsa_public_key);
FAILIF (0 != memcmp (&cbc2.reserve_sig, FAILIF (0 != memcmp (&cbc2.reserve_sig,
&cbc.reserve_sig, &cbc.reserve_sig,
@ -359,7 +359,7 @@ run (void *cls,
&cbc.reserve_pub, &cbc.reserve_pub,
sizeof (cbc2.reserve_pub))); sizeof (cbc2.reserve_pub)));
FAILIF (GNUNET_OK != FAILIF (GNUNET_OK !=
GNUNET_CRYPTO_rsa_verify (&h_blind, GNUNET_CRYPTO_rsa_verify (&cbc.h_coin_envelope,
cbc2.sig.rsa_signature, cbc2.sig.rsa_signature,
dkp->pub.rsa_public_key)); dkp->pub.rsa_public_key));
rh = plugin->get_reserve_history (plugin->cls, rh = plugin->get_reserve_history (plugin->cls,
@ -387,7 +387,8 @@ run (void *cls,
&reserve_pub, &reserve_pub,
sizeof (reserve_pub))); sizeof (reserve_pub)));
FAILIF (0 != memcmp (&withdraw->h_coin_envelope, FAILIF (0 != memcmp (&withdraw->h_coin_envelope,
&h_blind, sizeof (h_blind))); &cbc.h_coin_envelope,
sizeof (cbc.h_coin_envelope)));
break; break;
} }
} }