@@ -11,7 +11,9 @@ use std::ops::Div;
1111use std:: {
1212 collections:: HashMap ,
1313 io:: { BufRead , Seek , Write } ,
14+ ops:: { Rem , Sub } ,
1415} ;
16+ use itertools:: Itertools ;
1517
1618use super :: * ;
1719use crate :: error:: { DeserializeError , DeserializeFailure } ;
@@ -248,6 +250,10 @@ impl BigNum {
248250 pub fn less_than ( & self , rhs_value : & BigNum ) -> bool {
249251 self . compare ( rhs_value) < 0
250252 }
253+
254+ pub fn max ( a : & BigNum , b : & BigNum ) -> BigNum {
255+ if a. less_than ( b) { b. clone ( ) } else { a. clone ( ) }
256+ }
251257}
252258
253259impl TryFrom < BigNum > for u32 {
@@ -1343,6 +1349,84 @@ pub fn get_deposit(
13431349 internal_get_deposit ( & txbody. certs , & pool_deposit, & key_deposit)
13441350}
13451351
1352+ // <TODO:REMOVE_AFTER_BABBAGE>
1353+ struct OutputSizeConstants {
1354+ k0 : usize ,
1355+ k1 : usize ,
1356+ k2 : usize ,
1357+ }
1358+
1359+ // <TODO:REMOVE_AFTER_BABBAGE>
1360+ fn quot < T > ( a : T , b : T ) -> T
1361+ where T : Sub < Output =T > + Rem < Output =T > + Div < Output =T > + Copy + Clone + std:: fmt:: Display {
1362+ ( a - ( a % b) ) / b
1363+ }
1364+
1365+ // <TODO:REMOVE_AFTER_BABBAGE>
1366+ fn bundle_size (
1367+ assets : & Value ,
1368+ constants : & OutputSizeConstants ,
1369+ ) -> usize {
1370+ // based on https://github.com/input-output-hk/cardano-ledger-specs/blob/master/doc/explanations/min-utxo-alonzo.rst
1371+ match & assets. multiasset {
1372+ None => 2 , // coinSize according the minimum value function
1373+ Some ( assets) => {
1374+ let num_assets = assets. 0
1375+ . values ( )
1376+ . fold (
1377+ 0 ,
1378+ | acc, next| acc + next. len ( )
1379+ ) ;
1380+ let sum_asset_name_lengths = assets. 0
1381+ . values ( )
1382+ . flat_map ( |assets| assets. 0 . keys ( ) )
1383+ . unique_by ( |asset| asset. name ( ) )
1384+ . fold (
1385+ 0 ,
1386+ | acc, next| acc + next. 0 . len ( )
1387+ ) ;
1388+ let sum_policy_id_lengths = assets. 0
1389+ . keys ( )
1390+ . fold (
1391+ 0 ,
1392+ | acc, next| acc + next. 0 . len ( )
1393+ ) ;
1394+ // converts bytes to 8-byte long words, rounding up
1395+ fn roundup_bytes_to_words ( b : usize ) -> usize {
1396+ quot ( b + 7 , 8 )
1397+ }
1398+ constants. k0 + roundup_bytes_to_words (
1399+ ( num_assets * constants. k1 ) + sum_asset_name_lengths +
1400+ ( constants. k2 * sum_policy_id_lengths)
1401+ )
1402+ }
1403+ }
1404+ }
1405+
1406+ // <TODO:REMOVE_AFTER_BABBAGE>
1407+ fn _min_ada_required_legacy (
1408+ assets : & Value ,
1409+ has_data_hash : bool , // whether the output includes a data hash
1410+ coins_per_utxo_word : & BigNum , // protocol parameter (in lovelace)
1411+ ) -> Result < BigNum , JsError > {
1412+ // based on https://github.com/input-output-hk/cardano-ledger-specs/blob/master/doc/explanations/min-utxo-alonzo.rst
1413+ let data_hash_size = if has_data_hash { 10 } else { 0 } ; // in words
1414+ let utxo_entry_size_without_val = 27 ; // in words
1415+
1416+ let size = bundle_size (
1417+ & assets,
1418+ & OutputSizeConstants {
1419+ k0 : 6 ,
1420+ k1 : 12 ,
1421+ k2 : 1 ,
1422+ } ,
1423+ ) ;
1424+ let words = to_bignum ( utxo_entry_size_without_val)
1425+ . checked_add ( & to_bignum ( size as u64 ) ) ?
1426+ . checked_add ( & to_bignum ( data_hash_size) ) ?;
1427+ coins_per_utxo_word. checked_mul ( & words)
1428+ }
1429+
13461430#[ derive( Debug , Clone , Eq , Ord , PartialEq , PartialOrd ) ]
13471431pub struct MinOutputAdaCalculator {
13481432 output : TransactionOutput ,
@@ -1391,16 +1475,19 @@ impl MinOutputAdaCalculator {
13911475 output : & TransactionOutput ,
13921476 coins_per_byte : & Coin ,
13931477 ) -> Result < Coin , JsError > {
1394- // Adding extra words to the estimate
1395- // <TODO:REMOVE_AFTER_BABBAGE>
1396- let compatibility_extra_bytes =
1397- ( output. amount ( ) . count_assets ( ) as u64 * 15 )
1398- + if output. has_data_hash ( ) { 80 } else { 0 } ;
1478+ let legacy_coin = _min_ada_required_legacy (
1479+ & output. amount ( ) ,
1480+ output. has_data_hash ( ) ,
1481+ & coins_per_byte
1482+ . checked_add ( & BigNum :: one ( ) ) ?
1483+ . checked_mul ( & BigNum :: from_str ( "8" ) ?) ?
1484+ ) ?;
13991485 //according to https://hydra.iohk.io/build/15339994/download/1/babbage-changes.pdf
14001486 //See on the page 9 getValue txout
1401- BigNum :: from ( output. to_bytes ( ) . len ( ) )
1402- . checked_add ( & to_bignum ( 160 + compatibility_extra_bytes) ) ?
1403- . checked_mul ( & coins_per_byte)
1487+ let result = BigNum :: from ( output. to_bytes ( ) . len ( ) )
1488+ . checked_add ( & to_bignum ( 160 ) ) ?
1489+ . checked_mul ( & coins_per_byte) ?;
1490+ Ok ( BigNum :: max ( & result, & legacy_coin) )
14041491 }
14051492 for _ in 0 ..3 {
14061493 let required_coin = calc_required_coin ( & output, & coins_per_byte) ?;
0 commit comments