1

I'm a newbie to Monero. My question is how Monero does the amount checking logic (the input amount should be larger than the output amount in a transaction) when a node receives a raw transaction.

I found there is some checking logic in wallet implementation wallet2::create_transactions_2.

THROW_WALLET_EXCEPTION_IF(needed_money + min_fee > balance_subtotal, error::not_enough_money, balance_subtotal, needed_money, 0);
THROW_WALLET_EXCEPTION_IF(needed_money + min_fee > unlocked_balance_subtotal, error::not_enough_unlocked_money, unlocked_balance_subtotal, needed_money, 0);

And tx_memory_pool::add_tx also has some checking logic when tx.version == 1

if (tx.version == 1)
  {
    uint64_t inputs_amount = 0;
    if(!get_inputs_money_amount(tx, inputs_amount))                                                                                                                      
    {
      tvc.m_verifivation_failed = true;
      return false;
    }

    uint64_t outputs_amount = get_outs_money_amount(tx);
    if(outputs_amount > inputs_amount)
    {
      LOG_PRINT_L1("transaction use more money than it has: use " << print_money(outputs_amount) << ", have " << print_money(inputs_amount));
      tvc.m_verifivation_failed = true;
      tvc.m_overspend = true;
      return false;
    }
    else if(outputs_amount == inputs_amount)
    {
      LOG_PRINT_L1("transaction fee is zero: outputs_amount == inputs_amount, rejecting.");
      tvc.m_verifivation_failed = true;
      tvc.m_fee_too_low = true;
      return false;
    }

    fee = inputs_amount - outputs_amount;
  }
  else
  {
    fee = tx.rct_signatures.txnFee;
  } 

But I don't think we use version 1 in transaction right now.

Could somebody give me a hint? Or is it impossible to do this kind of check in the raw transaction?

0

Firstly, the current transaction version used is 2.

Second, you found the check in create_transactions_2 which ensures there is enough money to fund the transaction.

Lastly, the reason you are not seeing an explicit monetary value check in the mempool addition is because the amounts are Confidential Transactions (RingCT) - the amounts are masked. If you continue down in add_tx method, you'll find various other calls to blockchain.cpp to check the inputs and outputs of a tx. With RingCT, one of the checks needed is on the range proof: bulletproof_VERIFY. This ensures all inputs minus all outputs in the tx is within a range and positive. If you search back through the code from there, you'll find various places that call through to that check, such as core::handle_incoming_tx_accumulated_batch

  • I thought the rangeproof just ensured that the outputs were within a certain range, and had nothing to do with the inputs? – WeCanBeFriends Apr 20 at 13:10
  • Inputs and outputs are used in the range proof. You need to know money is not being created out of thin air and you need to ensure the sum of all inputs minus the sum of all outputs is positive (or zero). See this answer. – jtgrassie Apr 20 at 15:54
  • If I understand: ProveRange(Sum(in)-Sum(out)) ? I was understand the impression that there was a rangeproof for each output, so the output amount could not be negative. Is there a link or article on this? – WeCanBeFriends Apr 20 at 16:43
  • The proof proves that each committed value is positive and the sum of all inputs minus the sum of all outputs is greater-than or equal to 0. See Zero to Monero sections 4.2 & 4.3. – jtgrassie Apr 20 at 17:47
0

You already found the place for v1 transactions. For v2 (RingCT) transactions, since in/out amounts are masked, the check is done in src/ringct/rctSigs.cpp, in either verRctSemanticsSimple or verRct (depending on the signature type):

          //check pseudoOuts vs Outs..
          if (!equalKeys(sumPseudoOuts, sumOutpks)) {
            LOG_PRINT_L1("Sum check failed");
            return false;
          }

This compares the sum of (masked) inputs to the sum of (masked) outputs plus the masked fee (the fee is not masked in the actual transaction, so the verification code masks it at that time). The dozen lines above perform these sums.

  • This is incorrect. equalKeys is checking if the keys match, not the sum of masked amounts. The ultimate check of amounts is the range proof check per my answer. – jtgrassie Feb 22 at 23:14
  • Not quite. Range proofs aren't about checking outputs <= inputs, they're about checking they're in valid range. They also have nothing to do with inputs, so cannot be used for checking outputs <= inputs by deduction :) – user36303 Feb 23 at 16:14
  • The range proof is specifically used to prove the total value of inputs is greater than or equal to the total value of outputs (so it's positive) and within a range. This is so money cannot be created from thin air. – jtgrassie Feb 23 at 18:10
  • And it's this range proof the OP is asking about: "(the input amount should be larger than the output amount in a transaction)". – jtgrassie Feb 23 at 18:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.