@@ -160,6 +160,23 @@ where
160160 }
161161 }
162162
163+ /// Returns the sum of all value pool balances.
164+ pub fn total ( self ) -> Result < Amount < C > , amount:: Error > {
165+ let total: i128 = [
166+ self . transparent ,
167+ self . sprout ,
168+ self . sapling ,
169+ self . orchard ,
170+ self . deferred ,
171+ self . ironwood ,
172+ ]
173+ . into_iter ( )
174+ . map ( |amount| i128:: from ( amount. zatoshis ( ) ) )
175+ . sum ( ) ;
176+
177+ Amount :: try_from ( total)
178+ }
179+
163180 /// Convert this value balance to a different ValueBalance type,
164181 /// if it satisfies the new constraint
165182 pub fn constrain < C2 > ( self ) -> Result < ValueBalance < C2 > , ValueBalanceError >
@@ -318,26 +335,35 @@ impl ValueBalance<NonNegative> {
318335 . expect ( "conversion from NonNegative to NegativeAllowed is always valid" ) ;
319336 chain_value_pool = ( chain_value_pool + chain_value_pool_change) ?;
320337
321- chain_value_pool. constrain ( )
338+ let chain_value_pool = chain_value_pool. constrain :: < NonNegative > ( ) ?;
339+
340+ // The sum of all chain value pools is the total monetary base, which consensus caps at
341+ // `MAX_MONEY`. Reject any change that would push the chain value pool total over that cap.
342+ chain_value_pool. total ( ) . map_err ( ValueBalanceError :: Total ) ?;
343+
344+ Ok ( chain_value_pool)
322345 }
323346
324347 /// Create a fake value pool for testing purposes.
325348 ///
326- /// The resulting [`ValueBalance`] will have half of the MAX_MONEY amount on each pool.
349+ /// The resulting [`ValueBalance`] has `MAX_MONEY / 8` on the transparent, Sprout, Sapling,
350+ /// Orchard, and Ironwood pools; the deferred pool is zero. This keeps the total within the
351+ /// valid `Amount` range (see [`ValueBalance::total`]), while leaving headroom for value pool
352+ /// changes that tests commit on top of it.
327353 #[ cfg( any( test, feature = "proptest-impl" ) ) ]
328354 pub fn fake_populated_pool ( ) -> ValueBalance < NonNegative > {
329355 let mut fake_value_pool = ValueBalance :: zero ( ) ;
330356
331357 let fake_transparent_value_balance =
332- ValueBalance :: from_transparent_amount ( Amount :: try_from ( MAX_MONEY / 2 ) . unwrap ( ) ) ;
358+ ValueBalance :: from_transparent_amount ( Amount :: try_from ( MAX_MONEY / 8 ) . unwrap ( ) ) ;
333359 let fake_sprout_value_balance =
334- ValueBalance :: from_sprout_amount ( Amount :: try_from ( MAX_MONEY / 2 ) . unwrap ( ) ) ;
360+ ValueBalance :: from_sprout_amount ( Amount :: try_from ( MAX_MONEY / 8 ) . unwrap ( ) ) ;
335361 let fake_sapling_value_balance =
336- ValueBalance :: from_sapling_amount ( Amount :: try_from ( MAX_MONEY / 2 ) . unwrap ( ) ) ;
362+ ValueBalance :: from_sapling_amount ( Amount :: try_from ( MAX_MONEY / 8 ) . unwrap ( ) ) ;
337363 let fake_orchard_value_balance =
338- ValueBalance :: from_orchard_amount ( Amount :: try_from ( MAX_MONEY / 2 ) . unwrap ( ) ) ;
364+ ValueBalance :: from_orchard_amount ( Amount :: try_from ( MAX_MONEY / 8 ) . unwrap ( ) ) ;
339365 let fake_ironwood_value_balance =
340- ValueBalance :: from_ironwood_amount ( Amount :: try_from ( MAX_MONEY / 2 ) . unwrap ( ) ) ;
366+ ValueBalance :: from_ironwood_amount ( Amount :: try_from ( MAX_MONEY / 8 ) . unwrap ( ) ) ;
341367
342368 fake_value_pool. set_transparent_value_balance ( fake_transparent_value_balance) ;
343369 fake_value_pool. set_sprout_value_balance ( fake_sprout_value_balance) ;
@@ -468,6 +494,9 @@ pub enum ValueBalanceError {
468494 /// ironwood amount error {0}
469495 Ironwood ( amount:: Error ) ,
470496
497+ /// total amount error {0}
498+ Total ( amount:: Error ) ,
499+
471500 /// ValueBalance is unparsable
472501 Unparsable ,
473502}
@@ -481,6 +510,7 @@ impl fmt::Display for ValueBalanceError {
481510 Orchard ( e) => format ! ( "orchard amount err: {e}" ) ,
482511 Deferred ( e) => format ! ( "deferred amount err: {e}" ) ,
483512 Ironwood ( e) => format ! ( "ironwood amount err: {e}" ) ,
513+ Total ( e) => format ! ( "total amount err: {e}" ) ,
484514 Unparsable => "value balance is unparsable" . to_string ( ) ,
485515 } )
486516 }
0 commit comments