1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
crate::ix!();

//-------------------------------------------[.cpp/bitcoin/src/policy/packages.h]
//-------------------------------------------[.cpp/bitcoin/src/policy/packages.cpp]

/**
  | Default maximum number of transactions
  | in a package.
  |
  */
pub const MAX_PACKAGE_COUNT: usize = 25;

/**
  | Default maximum total virtual size
  | of transactions in a package in KvB.
  |
  */
pub const MAX_PACKAGE_SIZE: usize = 101;

const_assert!{
    MAX_PACKAGE_SIZE * WITNESS_SCALE_FACTOR * 1000 >= MAX_STANDARD_TX_WEIGHT
}

/**
  | A "reason" why a package was invalid.
  | It may be that one or more of the included
  | transactions is invalid or the package
  | itself violates our rules.
  | 
  | We don't distinguish between consensus
  | and policy violations right now.
  |
  */
pub enum PackageValidationResult {

    /**
      | Initial value. The package has not yet
      | been rejected.
      |
      */
    PCKG_RESULT_UNSET = 0,        

    /**
      | The package itself is invalid (e.g.
      | too many transactions).
      |
      */
    PCKG_POLICY,                  

    /**
      | At least one tx is invalid.
      |
      */
    PCKG_TX,                      
}

/**
  | A package is an ordered list of transactions.
  | The transactions cannot conflict with
  | (spend the same inputs as) one another.
  |
  */
pub type Package = Vec<TransactionRef>;

pub struct PackageValidationState {
    base: ValidationState<PackageValidationResult>,
}

/**
  | Context-free package policy checks:
  | 
  | 1. The number of transactions cannot
  | exceed MAX_PACKAGE_COUNT.
  | 
  | 2. The total virtual size cannot exceed
  | MAX_PACKAGE_SIZE.
  | 
  | 3. If any dependencies exist between
  | transactions, parents must appear
  | before children.
  | 
  | 4. Transactions cannot conflict,
  | i.e., spend the same inputs.
  |
  */
pub fn check_package(
        txns:  &Package,
        state: &mut PackageValidationState) -> bool {
    
    todo!();
        /*
            const unsigned int package_count = txns.size();

        if (package_count > MAX_PACKAGE_COUNT) {
            return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-many-transactions");
        }

        const int64_t total_size = std::accumulate(txns.cbegin(), txns.cend(), 0,
                                   [](int64_t sum, const auto& tx) { return sum + GetVirtualTransactionSize(*tx); });
        // If the package only contains 1 tx, it's better to report the policy violation on individual tx size.
        if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000) {
            return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-large");
        }

        // Require the package to be sorted in order of dependency, i.e. parents appear before children.
        // An unsorted package will fail anyway on missing-inputs, but it's better to quit earlier and
        // fail on something less ambiguous (missing-inputs could also be an orphan or trying to
        // spend nonexistent coins).
        std::unordered_set<uint256, SaltedTxidHasher> later_txids;
        std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()),
                       [](const auto& tx) { return tx->GetHash(); });
        for (const auto& tx : txns) {
            for (const auto& input : tx->vin) {
                if (later_txids.find(input.prevout.hash) != later_txids.end()) {
                    // The parent is a subsequent transaction in the package.
                    return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-sorted");
                }
            }
            later_txids.erase(tx->GetHash());
        }

        // Don't allow any conflicting transactions, i.e. spending the same inputs, in a package.
        std::unordered_set<OutPoint, SaltedOutpointHasher> inputs_seen;
        for (const auto& tx : txns) {
            for (const auto& input : tx->vin) {
                if (inputs_seen.find(input.prevout) != inputs_seen.end()) {
                    // This input is also present in another tx in the package.
                    return state.Invalid(PackageValidationResult::PCKG_POLICY, "conflict-in-package");
                }
            }
            // Batch-add all the inputs for a tx at a time. If we added them 1 at a time, we could
            // catch duplicate inputs within a single tx.  This is a more severe, consensus error,
            // and we want to report that from CheckTransaction instead.
            std::transform(tx->vin.cbegin(), tx->vin.cend(), std::inserter(inputs_seen, inputs_seen.end()),
                           [](const auto& input) { return input.prevout; });
        }
        return true;
        */
}