// Copyright (c) 2017-2026 Lethean (https://lt.hn) // // Licensed under the European Union Public Licence (EUPL) version 1.2. // SPDX-License-Identifier: EUPL-1.2 package consensus import ( "fmt" "math" coreerr "dappco.re/go/core/log" "dappco.re/go/core/blockchain/types" ) // TxFee calculates the transaction fee for pre-HF4 (v0/v1) transactions. // Coinbase transactions return 0. For standard transactions, fee equals // the difference between total input amounts and total output amounts. // // fee, err := consensus.TxFee(&tx) func TxFee(tx *types.Transaction) (uint64, error) { if isCoinbase(tx) { return 0, nil } inputSum, err := sumInputs(tx) if err != nil { return 0, err } outputSum, err := sumOutputs(tx) if err != nil { return 0, err } if outputSum > inputSum { return 0, coreerr.E("TxFee", fmt.Sprintf("inputs=%d, outputs=%d", inputSum, outputSum), ErrNegativeFee) } return inputSum - outputSum, nil } // isCoinbase returns true if the transaction's first input is TxInputGenesis. func isCoinbase(tx *types.Transaction) bool { if len(tx.Vin) == 0 { return false } _, ok := tx.Vin[0].(types.TxInputGenesis) return ok } // sumInputs totals all transparent input amounts, checking for overflow. // Covers TxInputToKey, TxInputHTLC, and TxInputMultisig. func sumInputs(tx *types.Transaction) (uint64, error) { var total uint64 for _, vin := range tx.Vin { var amount uint64 switch v := vin.(type) { case types.TxInputToKey: amount = v.Amount case types.TxInputHTLC: amount = v.Amount case types.TxInputMultisig: amount = v.Amount default: continue } if total > math.MaxUint64-amount { return 0, ErrInputOverflow } total += amount } return total, nil } // sumOutputs totals all TxOutputBare amounts, checking for overflow. func sumOutputs(tx *types.Transaction) (uint64, error) { var total uint64 for _, vout := range tx.Vout { bare, ok := vout.(types.TxOutputBare) if !ok { continue } if total > math.MaxUint64-bare.Amount { return 0, ErrOutputOverflow } total += bare.Amount } return total, nil }