Skip to content

[FPDecimal] Handling sdk.Dec <nil> case  #29

Description

@albertchon

The Cosmos-SDK's empty sdk.Dec (e.g. sdk.Dec{}) string form is represented as "<nil>" (proof below).

However, FPDecimals' from_str method won't be able to convert this value.

/// Converts the decimal string to a FPDecimal
/// Possible inputs: "1.23", "1", "000012", "1.123000000"
/// Disallowed: "", ".23"
///
/// This never performs any kind of rounding.
/// More than 18 fractional digits, even zeros, result in an error.
fn from_str(input: &str) -> Result<Self, Self::Err> {
let sign = if input.starts_with('-') { 0 } else { 1 };
let parts: Vec<&str> = input.trim_start_matches('-').split('.').collect();
match parts.len() {
1 => {
let integer = U256::from_dec_str(parts[0]).map_err(|_| StdError::generic_err("Error parsing integer"))?;
Ok(FPDecimal {
num: integer * FPDecimal::ONE.num,
sign,
})
}
2 => {
let integer = U256::from_dec_str(parts[0]).map_err(|_| StdError::generic_err("Error parsing integer"))?;
let fraction = U256::from_dec_str(parts[1]).map_err(|_| StdError::generic_err("Error parsing fraction"))?;
let exp = FPDecimal::DIGITS
.checked_sub(parts[1].len())
.ok_or_else(|| StdError::generic_err(format!("Cannot parse more than {} fractional digits", FPDecimal::DIGITS)))?;
Ok(FPDecimal {
num: integer * FPDecimal::ONE.num + fraction * U256::exp10(exp),
sign,
})
}
_ => Err(StdError::generic_err("Unexpected number of dots")),
}
//Ok(FPDecimal {num: num * FPDecimal::ONE.num, sign: sign})
}
}

Should we handle this case? If so, how? @DrunkRandomWalker @gorgos

Proof:

type Dec struct {
	i *big.Int
}

func (d Dec) String() string {
	if d.i == nil {
		return d.i.String()
	}
	...
}

and big.Int's String method is simply

// String returns the decimal representation of x as generated by
// x.Text(10).
func (x *Int) String() string {
	return x.Text(10)
}

// Text returns the string representation of x in the given base.
// Base must be between 2 and 62, inclusive. The result uses the
// lower-case letters 'a' to 'z' for digit values 10 to 35, and
// the upper-case letters 'A' to 'Z' for digit values 36 to 61.
// No prefix (such as "0x") is added to the string. If x is a nil
// pointer it returns "<nil>".
func (x *Int) Text(base int) string {
	if x == nil {
		return "<nil>"
	}
	return string(x.abs.itoa(x.neg, base))
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions