@@ -131,7 +131,7 @@ static bool VerifyIssuanceAmount(secp256k1_pedersen_commitment& value_commit, se
131
131
return true ;
132
132
}
133
133
134
- bool VerifyAmounts (const std::vector<CTxOut>& inputs, const CTransaction& tx, std::vector<CCheck*>* checks, const bool store_result) {
134
+ const std::string VerifyAmounts (const std::vector<CTxOut>& inputs, const CTransaction& tx, std::vector<CCheck*>* checks, const bool store_result) {
135
135
assert (!tx.IsCoinBase ());
136
136
assert (inputs.size () == tx.vin .size ());
137
137
@@ -161,34 +161,34 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
161
161
const CConfidentialAsset& asset = inputs[i].nAsset ;
162
162
163
163
if (val.IsNull () || asset.IsNull ())
164
- return false ;
164
+ return " input val.IsNull or asset.IsNull " ;
165
165
166
166
if (asset.IsExplicit ()) {
167
167
ret = secp256k1_generator_generate (secp256k1_ctx_verify_amounts, &gen, asset.GetAsset ().begin ());
168
168
assert (ret != 0 );
169
169
}
170
170
else if (asset.IsCommitment ()) {
171
171
if (secp256k1_generator_parse (secp256k1_ctx_verify_amounts, &gen, &asset.vchCommitment [0 ]) != 1 )
172
- return false ;
172
+ return " input commitment parse failed " ;
173
173
}
174
174
else {
175
- return false ;
175
+ return " input asset not explicit not commitment " ;
176
176
}
177
177
178
178
target_generators.push_back (gen);
179
179
180
180
if (val.IsExplicit ()) {
181
181
if (!MoneyRange (val.GetAmount ()))
182
- return false ;
182
+ return " input value not in moneyrange " ;
183
183
184
184
// Fails if val.GetAmount() == 0
185
185
if (secp256k1_pedersen_commit (secp256k1_ctx_verify_amounts, &commit, explicit_blinds, val.GetAmount (), &gen) != 1 )
186
- return false ;
186
+ return " input explicit value pedersen commit failed " ;
187
187
} else if (val.IsCommitment ()) {
188
188
if (secp256k1_pedersen_commitment_parse (secp256k1_ctx_verify_amounts, &commit, &val.vchCommitment [0 ]) != 1 )
189
- return false ;
189
+ return " input commitment pedersen commit failed " ;
190
190
} else {
191
- return false ;
191
+ return " input value not explicit not commitment " ;
192
192
}
193
193
194
194
vData.push_back (commit);
@@ -228,37 +228,38 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
228
228
// Must check that prevout is the blinded issuance token
229
229
// prevout's asset tag = assetTokenID + assetBlindingNonce
230
230
if (secp256k1_generator_generate_blinded (secp256k1_ctx_verify_amounts, &gen, assetTokenID.begin (), issuance.assetBlindingNonce .begin ()) != 1 ) {
231
- return false ;
231
+ return " reissuance generate blinded generator failed " ;
232
232
}
233
233
// Serialize the generator for direct comparison
234
234
unsigned char derived_generator[33 ];
235
235
secp256k1_generator_serialize (secp256k1_ctx_verify_amounts, derived_generator, &gen);
236
236
237
237
// Belt-and-suspenders: Check that asset commitment from issuance input is correct size
238
238
if (asset.vchCommitment .size () != sizeof (derived_generator)) {
239
- return false ;
239
+ return " reissuance asset commitment size is not derived generator size " ;
240
240
}
241
241
242
- // We have already checked the outputs' generator commitment for general validity, so directly compare serialized bytes
242
+ // We have already checked the outputs' generator commitment for general validity,
243
+ // so directly compare serialized bytes
243
244
if (memcmp (asset.vchCommitment .data (), derived_generator, sizeof (derived_generator))) {
244
- return false ;
245
+ return " reissuance asset commitment not equal to derived generator " ;
245
246
}
246
247
}
247
248
248
249
// Process issuance of asset
249
250
250
251
if (!issuance.nAmount .IsValid ()) {
251
- return false ;
252
+ return " issuance amount not valid " ;
252
253
}
253
254
if (!issuance.nAmount .IsNull ()) {
254
255
// Note: This check disallows issuances in transactions with *no* witness data.
255
256
// This can be relaxed in a future update as a HF by passing in an empty rangeproof
256
257
// to `VerifyIssuanceAmount` instead.
257
258
if (i >= tx.witness .vtxinwit .size ()) {
258
- return false ;
259
+ return " no witness for issuance input " ;
259
260
}
260
261
if (!VerifyIssuanceAmount (commit, gen, assetID, issuance.nAmount , tx.witness .vtxinwit [i].vchIssuanceAmountRangeproof , checks, store_result)) {
261
- return false ;
262
+ return " VerifyIssuanceAmount failed " ;
262
263
}
263
264
target_generators.push_back (gen);
264
265
vData.push_back (commit);
@@ -269,22 +270,22 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
269
270
// Process issuance of reissuance tokens
270
271
271
272
if (!issuance.nInflationKeys .IsValid ()) {
272
- return false ;
273
+ return " issuance of reissuance tokens: inflatioinskeys invalid " ;
273
274
}
274
275
if (!issuance.nInflationKeys .IsNull ()) {
275
276
// Only initial issuance can have reissuance tokens
276
277
if (!issuance.assetBlindingNonce .IsNull ()) {
277
- return false ;
278
+ return " only initial issuance can have reissuance tokens " ;
278
279
}
279
280
280
281
// Note: This check disallows issuances in transactions with *no* witness data.
281
282
// This can be relaxed in a future update as a HF by passing in an empty rangeproof
282
283
// to `VerifyIssuanceAmount` instead.
283
284
if (i >= tx.witness .vtxinwit .size ()) {
284
- return false ;
285
+ return " no witness for reissuance input " ;
285
286
}
286
287
if (!VerifyIssuanceAmount (commit, gen, assetTokenID, issuance.nInflationKeys , tx.witness .vtxinwit [i].vchInflationKeysRangeproof , checks, store_result)) {
287
- return false ;
288
+ return " reissuance VerifyIssuanceAmount failed " ;
288
289
}
289
290
target_generators.push_back (gen);
290
291
vData.push_back (commit);
@@ -298,35 +299,35 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
298
299
const CConfidentialValue& val = tx.vout [i].nValue ;
299
300
const CConfidentialAsset& asset = tx.vout [i].nAsset ;
300
301
if (!asset.IsValid ())
301
- return false ;
302
+ return " output asset invalid " ;
302
303
if (!val.IsValid ())
303
- return false ;
304
+ return " output value invalid " ;
304
305
if (!tx.vout [i].nNonce .IsValid ())
305
- return false ;
306
+ return " output nonce invalid " ;
306
307
307
308
if (asset.IsExplicit ()) {
308
309
ret = secp256k1_generator_generate (secp256k1_ctx_verify_amounts, &gen, asset.GetAsset ().begin ());
309
310
assert (ret != 0 );
310
311
}
311
312
else if (asset.IsCommitment ()) {
312
313
if (secp256k1_generator_parse (secp256k1_ctx_verify_amounts, &gen, &asset.vchCommitment [0 ]) != 1 )
313
- return false ;
314
+ return " output asset commitment parse failed " ;
314
315
}
315
316
else {
316
- return false ;
317
+ return " output asset is not explicit not commitment " ;
317
318
}
318
319
319
320
if (val.IsExplicit ()) {
320
321
if (!MoneyRange (val.GetAmount ()))
321
- return false ;
322
+ return " output value out of money range " ;
322
323
323
324
if (val.GetAmount () == 0 ) {
324
325
if (tx.vout [i].scriptPubKey .IsUnspendable ()) {
325
326
continue ;
326
327
} else {
327
328
// No spendable 0-value outputs
328
329
// Reason: A spendable output of 0 reissuance tokens would allow reissuance without reissuance tokens.
329
- return false ;
330
+ return " attempted spendable 0-value output " ;
330
331
}
331
332
}
332
333
@@ -336,9 +337,9 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
336
337
}
337
338
else if (val.IsCommitment ()) {
338
339
if (secp256k1_pedersen_commitment_parse (secp256k1_ctx_verify_amounts, &commit, &val.vchCommitment [0 ]) != 1 )
339
- return false ;
340
+ return " output value pedersen commit parse failed " ;
340
341
} else {
341
- return false ;
342
+ return " output value is not explicit not commitment " ;
342
343
}
343
344
344
345
vData.push_back (commit);
@@ -348,7 +349,7 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
348
349
349
350
// Check balance
350
351
if (QueueCheck (checks, new CBalanceCheck (vData, vpCommitsIn, vpCommitsOut)) != SCRIPT_ERR_OK) {
351
- return false ;
352
+ return " CBalanceCheck failed " ;
352
353
}
353
354
354
355
// Range proofs
@@ -360,7 +361,7 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
360
361
if (val.IsExplicit ())
361
362
{
362
363
if (ptxoutwit && !ptxoutwit->vchRangeproof .empty ())
363
- return false ;
364
+ return " explicit output value non-empty range proof " ;
364
365
continue ;
365
366
}
366
367
if (asset.IsExplicit ()) {
@@ -369,10 +370,10 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
369
370
secp256k1_generator_serialize (secp256k1_ctx_verify_amounts, &vchAssetCommitment[0 ], &gen);
370
371
}
371
372
if (!ptxoutwit) {
372
- return false ;
373
+ return " blinded output value without output witness " ;
373
374
}
374
375
if (QueueCheck (checks, new CRangeCheck (&val, ptxoutwit->vchRangeproof , vchAssetCommitment, tx.vout [i].scriptPubKey , store_result)) != SCRIPT_ERR_OK) {
375
- return false ;
376
+ return " CRangeCheck failed " ;
376
377
}
377
378
}
378
379
@@ -384,25 +385,25 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
384
385
// No need for surjection proof
385
386
if (asset.IsExplicit ()) {
386
387
if (ptxoutwit && !ptxoutwit->vchSurjectionproof .empty ()) {
387
- return false ;
388
+ return " explicit output asset non-empty surjection proof " ;
388
389
}
389
390
continue ;
390
391
}
391
392
if (!ptxoutwit)
392
- return false ;
393
+ return " blinded output value without output witness " ;
393
394
if (secp256k1_generator_parse (secp256k1_ctx_verify_amounts, &gen, &asset.vchCommitment [0 ]) != 1 )
394
- return false ;
395
+ return " output asset generator parse failed " ;
395
396
396
397
secp256k1_surjectionproof proof;
397
398
if (secp256k1_surjectionproof_parse (secp256k1_ctx_verify_amounts, &proof, &ptxoutwit->vchSurjectionproof [0 ], ptxoutwit->vchSurjectionproof .size ()) != 1 )
398
- return false ;
399
+ return " output asset surjection proof failed " ;
399
400
400
401
if (QueueCheck (checks, new CSurjectionCheck (proof, target_generators, gen, wtxid, store_result)) != SCRIPT_ERR_OK) {
401
- return false ;
402
+ return " CSurjectionCheck failed " ;
402
403
}
403
404
}
404
405
405
- return true ;
406
+ return " " ;
406
407
}
407
408
408
409
bool VerifyCoinbaseAmount (const CTransaction& tx, const CAmountMap& mapFees) {
0 commit comments