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?

jtgrassie
  • 19,601
  • 4
  • 17
  • 54
Jay Pan
  • 11
  • 2

2 Answers2

1

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.

user36303
  • 34,928
  • 2
  • 58
  • 123
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

jtgrassie
  • 19,601
  • 4
  • 17
  • 54