feat: fix errors and add tests for BigInt changes

This commit is contained in:
rvcas 2023-02-09 15:01:30 -05:00
parent bd4aeb779c
commit c1d67e95e1
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
9 changed files with 291 additions and 109 deletions

1
Cargo.lock generated vendored
View File

@ -2669,6 +2669,7 @@ dependencies = [
"itertools", "itertools",
"k256", "k256",
"num-bigint", "num-bigint",
"num-integer",
"num-traits", "num-traits",
"pallas-addresses", "pallas-addresses",
"pallas-codec", "pallas-codec",

View File

@ -8,8 +8,11 @@ use uplc::{
Constant as UplcConstant, Name, Term, Type as UplcType, Constant as UplcConstant, Name, Term, Type as UplcType,
}, },
builtins::DefaultFunction, builtins::DefaultFunction,
machine::runtime::{convert_constr_to_tag, ANY_TAG}, machine::{
BigInt, Constr, KeyValuePairs, PlutusData, runtime::{convert_constr_to_tag, ANY_TAG},
to_pallas_bigint,
},
Constr, KeyValuePairs, PlutusData,
}; };
use crate::{ use crate::{
@ -332,7 +335,7 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
apply_wrap( apply_wrap(
apply_wrap( apply_wrap(
DefaultFunction::EqualsInteger.into(), DefaultFunction::EqualsInteger.into(),
Term::Constant(UplcConstant::Integer(1).into()), Term::Constant(UplcConstant::Integer(1.into()).into()),
), ),
apply_wrap( apply_wrap(
Term::Builtin(DefaultFunction::FstPair) Term::Builtin(DefaultFunction::FstPair)
@ -998,9 +1001,7 @@ pub fn convert_constants_to_data(constants: Vec<Rc<UplcConstant>>) -> Vec<UplcCo
let mut new_constants = vec![]; let mut new_constants = vec![];
for constant in constants { for constant in constants {
let constant = match constant.as_ref() { let constant = match constant.as_ref() {
UplcConstant::Integer(i) => { UplcConstant::Integer(i) => UplcConstant::Data(PlutusData::BigInt(to_pallas_bigint(i))),
UplcConstant::Data(PlutusData::BigInt(BigInt::Int((*i).try_into().unwrap())))
}
UplcConstant::ByteString(b) => { UplcConstant::ByteString(b) => {
UplcConstant::Data(PlutusData::BoundedBytes(b.clone().try_into().unwrap())) UplcConstant::Data(PlutusData::BoundedBytes(b.clone().try_into().unwrap()))
} }

View File

@ -4417,7 +4417,7 @@ impl<'a> CodeGenerator<'a> {
apply_wrap( apply_wrap(
apply_wrap( apply_wrap(
DefaultFunction::EqualsInteger.into(), DefaultFunction::EqualsInteger.into(),
Term::Constant(UplcConstant::Integer(constr_index as i128).into()), Term::Constant(UplcConstant::Integer(constr_index.into()).into()),
), ),
constr_index_exposer(constr), constr_index_exposer(constr),
), ),
@ -4975,7 +4975,7 @@ impl<'a> CodeGenerator<'a> {
term = apply_wrap( term = apply_wrap(
apply_wrap( apply_wrap(
DefaultFunction::ConstrData.into(), DefaultFunction::ConstrData.into(),
Term::Constant(UplcConstant::Integer(constr_index as i128).into()), Term::Constant(UplcConstant::Integer(constr_index.into()).into()),
), ),
term, term,
); );
@ -5234,7 +5234,7 @@ impl<'a> CodeGenerator<'a> {
term = apply_wrap( term = apply_wrap(
apply_wrap( apply_wrap(
Term::Builtin(DefaultFunction::ConstrData), Term::Builtin(DefaultFunction::ConstrData),
Term::Constant(UplcConstant::Integer(0).into()), Term::Constant(UplcConstant::Integer(0.into()).into()),
), ),
term, term,
); );
@ -5342,7 +5342,7 @@ impl<'a> CodeGenerator<'a> {
UnOp::Negate => apply_wrap( UnOp::Negate => apply_wrap(
apply_wrap( apply_wrap(
DefaultFunction::SubtractInteger.into(), DefaultFunction::SubtractInteger.into(),
Term::Constant(UplcConstant::Integer(0).into()), Term::Constant(UplcConstant::Integer(0.into()).into()),
), ),
value, value,
), ),
@ -5391,7 +5391,7 @@ impl<'a> CodeGenerator<'a> {
), ),
term, term,
), ),
Term::Constant(UplcConstant::Integer(tuple_index as i128).into()), Term::Constant(UplcConstant::Integer(tuple_index.into()).into()),
), ),
&tipo.get_inner_types()[tuple_index], &tipo.get_inner_types()[tuple_index],
); );

View File

@ -35,6 +35,7 @@ secp256k1 = { version = "0.26.0", optional = true }
k256 = { version = "0.12.0", optional = true } k256 = { version = "0.12.0", optional = true }
num-bigint = "0.4.3" num-bigint = "0.4.3"
num-traits = "0.2.15" num-traits = "0.2.15"
num-integer = "0.1.45"
[dev-dependencies] [dev-dependencies]
hex = "0.4.3" hex = "0.4.3"

View File

@ -391,6 +391,9 @@ impl Encode for Constant {
match self { match self {
Constant::Integer(i) => { Constant::Integer(i) => {
encode_constant(&[0], e)?; encode_constant(&[0], e)?;
let i: i128 = i.try_into().unwrap();
i.encode(e)?; i.encode(e)?;
} }
@ -444,7 +447,11 @@ impl Encode for Constant {
fn encode_constant_value(x: &Constant, e: &mut Encoder) -> Result<(), en::Error> { fn encode_constant_value(x: &Constant, e: &mut Encoder) -> Result<(), en::Error> {
match x { match x {
Constant::Integer(x) => x.encode(e), Constant::Integer(x) => {
let x: i128 = x.try_into().unwrap();
x.encode(e)
}
Constant::ByteString(b) => b.encode(e), Constant::ByteString(b) => b.encode(e),
Constant::String(s) => s.encode(e), Constant::String(s) => s.encode(e),
Constant::Unit => Ok(()), Constant::Unit => Ok(()),
@ -491,7 +498,7 @@ fn encode_type(typ: &Type, bytes: &mut Vec<u8>) {
impl<'b> Decode<'b> for Constant { impl<'b> Decode<'b> for Constant {
fn decode(d: &mut Decoder) -> Result<Self, de::Error> { fn decode(d: &mut Decoder) -> Result<Self, de::Error> {
match &decode_constant(d)?[..] { match &decode_constant(d)?[..] {
[0] => Ok(Constant::Integer(i128::decode(d)?)), [0] => Ok(Constant::Integer(i128::decode(d)?.into())),
[1] => Ok(Constant::ByteString(Vec::<u8>::decode(d)?)), [1] => Ok(Constant::ByteString(Vec::<u8>::decode(d)?)),
[2] => Ok(Constant::String(String::decode(d)?)), [2] => Ok(Constant::String(String::decode(d)?)),
[3] => Ok(Constant::Unit), [3] => Ok(Constant::Unit),
@ -534,7 +541,7 @@ impl<'b> Decode<'b> for Constant {
fn decode_constant_value(typ: Rc<Type>, d: &mut Decoder) -> Result<Constant, de::Error> { fn decode_constant_value(typ: Rc<Type>, d: &mut Decoder) -> Result<Constant, de::Error> {
match typ.as_ref() { match typ.as_ref() {
Type::Integer => Ok(Constant::Integer(i128::decode(d)?)), Type::Integer => Ok(Constant::Integer(i128::decode(d)?.into())),
Type::ByteString => Ok(Constant::ByteString(Vec::<u8>::decode(d)?)), Type::ByteString => Ok(Constant::ByteString(Vec::<u8>::decode(d)?)),
Type::String => Ok(Constant::String(String::decode(d)?)), Type::String => Ok(Constant::String(String::decode(d)?)),
Type::Unit => Ok(Constant::Unit), Type::Unit => Ok(Constant::Unit),
@ -813,7 +820,7 @@ mod test {
fn flat_encode_integer() { fn flat_encode_integer() {
let program = Program::<Name> { let program = Program::<Name> {
version: (11, 22, 33), version: (11, 22, 33),
term: Term::Constant(Constant::Integer(11).into()), term: Term::Constant(Constant::Integer(11.into()).into()),
}; };
let expected_bytes = vec![ let expected_bytes = vec![
@ -833,8 +840,8 @@ mod test {
Constant::ProtoList( Constant::ProtoList(
Type::List(Type::Integer.into()), Type::List(Type::Integer.into()),
vec![ vec![
Constant::ProtoList(Type::Integer, vec![Constant::Integer(7)]), Constant::ProtoList(Type::Integer, vec![Constant::Integer(7.into())]),
Constant::ProtoList(Type::Integer, vec![Constant::Integer(5)]), Constant::ProtoList(Type::Integer, vec![Constant::Integer(5.into())]),
], ],
) )
.into(), .into(),
@ -862,11 +869,11 @@ mod test {
Constant::ProtoPair( Constant::ProtoPair(
Type::Integer, Type::Integer,
Type::Bool, Type::Bool,
Constant::Integer(11).into(), Constant::Integer(11.into()).into(),
Constant::Bool(true).into(), Constant::Bool(true).into(),
) )
.into(), .into(),
Constant::Integer(11).into(), Constant::Integer(11.into()).into(),
) )
.into(), .into(),
), ),
@ -895,8 +902,8 @@ mod test {
Constant::ProtoList( Constant::ProtoList(
Type::List(Type::Integer.into()), Type::List(Type::Integer.into()),
vec![ vec![
Constant::ProtoList(Type::Integer, vec![Constant::Integer(7)]), Constant::ProtoList(Type::Integer, vec![Constant::Integer(7.into())]),
Constant::ProtoList(Type::Integer, vec![Constant::Integer(5)]), Constant::ProtoList(Type::Integer, vec![Constant::Integer(5.into())]),
], ],
) )
.into(), .into(),
@ -924,11 +931,11 @@ mod test {
Constant::ProtoPair( Constant::ProtoPair(
Type::Integer, Type::Integer,
Type::Bool, Type::Bool,
Constant::Integer(11).into(), Constant::Integer(11.into()).into(),
Constant::Bool(true).into(), Constant::Bool(true).into(),
) )
.into(), .into(),
Constant::Integer(11).into(), Constant::Integer(11.into()).into(),
) )
.into(), .into(),
), ),
@ -947,7 +954,7 @@ mod test {
let expected_program = Program { let expected_program = Program {
version: (11, 22, 33), version: (11, 22, 33),
term: Term::Constant(Constant::Integer(11).into()), term: Term::Constant(Constant::Integer(11.into()).into()),
}; };
let actual_program: Program<Name> = Program::unflat(&bytes).unwrap(); let actual_program: Program<Name> = Program::unflat(&bytes).unwrap();

View File

@ -541,6 +541,29 @@ fn integer_log2(i: BigInt) -> i64 {
} }
} }
pub fn from_pallas_bigint(n: &pallas::BigInt) -> BigInt {
match n {
pallas::BigInt::Int(i) => i128::from(*i).into(),
pallas::BigInt::BigUInt(bytes) => BigInt::from_bytes_be(num_bigint::Sign::Plus, bytes),
pallas::BigInt::BigNInt(bytes) => BigInt::from_bytes_be(num_bigint::Sign::Minus, bytes),
}
}
pub fn to_pallas_bigint(n: &BigInt) -> pallas::BigInt {
if n.bits() <= 64 {
let regular_int: i64 = n.try_into().unwrap();
let pallas_int: pallas_codec::utils::Int = regular_int.into();
pallas::BigInt::Int(pallas_int)
} else if n.is_positive() {
let (_, bytes) = n.to_bytes_be();
pallas::BigInt::BigUInt(bytes.into())
} else {
let (_, bytes) = n.to_bytes_be();
pallas::BigInt::BigNInt(bytes.into())
}
}
impl Value { impl Value {
pub fn is_integer(&self) -> bool { pub fn is_integer(&self) -> bool {
matches!(self, Value::Con(i) if matches!(i.as_ref(), Constant::Integer(_))) matches!(self, Value::Con(i) if matches!(i.as_ref(), Constant::Integer(_)))
@ -558,7 +581,7 @@ impl Value {
if *i == 0.into() { if *i == 0.into() {
1 1
} else { } else {
(i.abs().log2().floor() as i64 / 64) + 1 (integer_log2(i.abs()) / 64) + 1
} }
} }
Constant::ByteString(b) => { Constant::ByteString(b) => {
@ -617,12 +640,9 @@ impl Value {
stack = new_stack; stack = new_stack;
} }
PlutusData::BigInt(i) => { PlutusData::BigInt(i) => {
if let pallas::BigInt::Int(g) = i { let i = from_pallas_bigint(i);
let numb: i128 = (*g).try_into().unwrap();
total += Value::Con(Constant::Integer(numb).into()).to_ex_mem(); total += Value::Con(Constant::Integer(i).into()).to_ex_mem();
} else {
unreachable!()
};
} }
PlutusData::BoundedBytes(b) => { PlutusData::BoundedBytes(b) => {
let byte_string: Vec<u8> = b.deref().clone(); let byte_string: Vec<u8> = b.deref().clone();
@ -742,14 +762,14 @@ impl From<&Constant> for Type {
} }
#[cfg(test)] #[cfg(test)]
mod test { mod tests {
use super::{cost_model::ExBudget, integer_log2}; use num_bigint::BigInt;
use super::{cost_model::ExBudget, integer_log2, Value};
use crate::{ use crate::{
ast::{Constant, NamedDeBruijn, Program, Term}, ast::{Constant, NamedDeBruijn, Program, Term},
builtins::DefaultFunction, builtins::DefaultFunction,
machine::Error,
}; };
use num_bigint::BigInt;
#[test] #[test]
fn add_big_ints() { fn add_big_ints() {
@ -767,7 +787,152 @@ mod test {
let (eval_result, _, _) = program.eval(ExBudget::default()); let (eval_result, _, _) = program.eval(ExBudget::default());
assert!(!matches!(eval_result, Err(Error::OverflowError))); let term = eval_result.unwrap();
assert_eq!(
term,
Term::Constant(
Constant::Integer(
Into::<BigInt>::into(i128::MAX) + Into::<BigInt>::into(i128::MAX)
)
.into()
)
);
}
#[test]
fn divide_integer() {
let make_program = |fun: DefaultFunction, n: i32, m: i32| Program::<NamedDeBruijn> {
version: (0, 0, 0),
term: Term::Apply {
function: Term::Apply {
function: Term::Builtin(fun).into(),
argument: Term::Constant(Constant::Integer(n.into()).into()).into(),
}
.into(),
argument: Term::Constant(Constant::Integer(m.into()).into()).into(),
},
};
let test_data = vec![
(DefaultFunction::DivideInteger, 8, 3, 2),
(DefaultFunction::DivideInteger, 8, -3, -3),
(DefaultFunction::DivideInteger, -8, 3, -3),
(DefaultFunction::DivideInteger, -8, -3, 2),
(DefaultFunction::QuotientInteger, 8, 3, 2),
(DefaultFunction::QuotientInteger, 8, -3, -2),
(DefaultFunction::QuotientInteger, -8, 3, -2),
(DefaultFunction::QuotientInteger, -8, -3, 2),
(DefaultFunction::RemainderInteger, 8, 3, 2),
(DefaultFunction::RemainderInteger, 8, -3, 2),
(DefaultFunction::RemainderInteger, -8, 3, -2),
(DefaultFunction::RemainderInteger, -8, -3, -2),
(DefaultFunction::ModInteger, 8, 3, 2),
(DefaultFunction::ModInteger, 8, -3, -1),
(DefaultFunction::ModInteger, -8, 3, 1),
(DefaultFunction::ModInteger, -8, -3, -2),
];
for (fun, n, m, result) in test_data {
let (eval_result, _, _) = make_program(fun, n, m).eval(ExBudget::default());
assert_eq!(
eval_result.unwrap(),
Term::Constant(Constant::Integer(result.into()).into())
);
}
}
#[test]
fn to_ex_mem_bigint() {
let value = Value::Con(Constant::Integer(1.into()).into());
assert_eq!(value.to_ex_mem(), 1);
let value = Value::Con(Constant::Integer(42.into()).into());
assert_eq!(value.to_ex_mem(), 1);
let value = Value::Con(
Constant::Integer(BigInt::parse_bytes("18446744073709551615".as_bytes(), 10).unwrap())
.into(),
);
assert_eq!(value.to_ex_mem(), 1);
let value = Value::Con(
Constant::Integer(
BigInt::parse_bytes("999999999999999999999999999999".as_bytes(), 10).unwrap(),
)
.into(),
);
assert_eq!(value.to_ex_mem(), 2);
let value = Value::Con(
Constant::Integer(
BigInt::parse_bytes("170141183460469231731687303715884105726".as_bytes(), 10)
.unwrap(),
)
.into(),
);
assert_eq!(value.to_ex_mem(), 2);
let value = Value::Con(
Constant::Integer(
BigInt::parse_bytes("170141183460469231731687303715884105727".as_bytes(), 10)
.unwrap(),
)
.into(),
);
assert_eq!(value.to_ex_mem(), 2);
let value = Value::Con(
Constant::Integer(
BigInt::parse_bytes("170141183460469231731687303715884105728".as_bytes(), 10)
.unwrap(),
)
.into(),
);
assert_eq!(value.to_ex_mem(), 2);
let value = Value::Con(
Constant::Integer(
BigInt::parse_bytes("170141183460469231731687303715884105729".as_bytes(), 10)
.unwrap(),
)
.into(),
);
assert_eq!(value.to_ex_mem(), 2);
let value = Value::Con(
Constant::Integer(
BigInt::parse_bytes("340282366920938463463374607431768211458".as_bytes(), 10)
.unwrap(),
)
.into(),
);
assert_eq!(value.to_ex_mem(), 3);
let value = Value::Con(
Constant::Integer(
BigInt::parse_bytes("999999999999999999999999999999999999999999".as_bytes(), 10)
.unwrap(),
)
.into(),
);
assert_eq!(value.to_ex_mem(), 3);
let value =
Value::Con(Constant::Integer(BigInt::parse_bytes("999999999999999999999999999999999999999999999999999999999999999999999999999999999999".as_bytes(), 10).unwrap()).into());
assert_eq!(value.to_ex_mem(), 5);
} }
#[test] #[test]

View File

@ -1,5 +1,7 @@
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
use num_bigint::BigInt;
use crate::ast::{NamedDeBruijn, Term, Type}; use crate::ast::{NamedDeBruijn, Term, Type};
use super::{ExBudget, Value}; use super::{ExBudget, Value};
@ -37,9 +39,9 @@ pub enum Error {
#[error("Decoding utf8")] #[error("Decoding utf8")]
Utf8(#[from] FromUtf8Error), Utf8(#[from] FromUtf8Error),
#[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)] #[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)]
ByteStringOutOfBounds(i128, Vec<u8>), ByteStringOutOfBounds(BigInt, Vec<u8>),
#[error("Divide By Zero\n\n{0} / {1}")] #[error("Divide By Zero\n\n{0} / {1}")]
DivideByZero(i128, i128), DivideByZero(BigInt, BigInt),
#[error("Ed25519S PublicKey should be 32 bytes but it was {0}")] #[error("Ed25519S PublicKey should be 32 bytes but it was {0}")]
UnexpectedEd25519PublicKeyLength(usize), UnexpectedEd25519PublicKeyLength(usize),
#[error("Ed25519S Signature should be 64 bytes but it was {0}")] #[error("Ed25519S Signature should be 64 bytes but it was {0}")]

View File

@ -1,6 +1,7 @@
use std::{ops::Deref, rc::Rc}; use std::{ops::Deref, rc::Rc};
use pallas_primitives::babbage::{BigInt, Constr, PlutusData}; use num_integer::Integer;
use pallas_primitives::babbage::{Constr, PlutusData};
use crate::{ use crate::{
ast::{Constant, Type}, ast::{Constant, Type},
@ -10,7 +11,7 @@ use crate::{
use super::{ use super::{
cost_model::{BuiltinCosts, ExBudget}, cost_model::{BuiltinCosts, ExBudget},
Error, Value, from_pallas_bigint, to_pallas_bigint, Error, Value,
}; };
//#[derive(std::cmp::PartialEq)] //#[derive(std::cmp::PartialEq)]
@ -330,10 +331,9 @@ impl DefaultFunction {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
match arg1.checked_add(*arg2) { let result = arg1 + arg2;
Some(res) => Ok(Value::Con(Constant::Integer(res).into()).into()),
None => Err(Error::OverflowError), Ok(Value::Con(Constant::Integer(result).into()).into())
}
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -344,10 +344,9 @@ impl DefaultFunction {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
match arg1.checked_sub(*arg2) { let result = arg1 - arg2;
Some(res) => Ok(Value::Con(Constant::Integer(res).into()).into()),
None => Err(Error::OverflowError), Ok(Value::Con(Constant::Integer(result).into()).into())
}
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -358,9 +357,25 @@ impl DefaultFunction {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
match arg1.checked_mul(*arg2) { let result = arg1 * arg2;
Some(res) => Ok(Value::Con(Constant::Integer(res).into()).into()),
None => Err(Error::OverflowError), Ok(Value::Con(Constant::Integer(result).into()).into())
}
_ => unreachable!(),
}
}
_ => unreachable!(),
},
DefaultFunction::DivideInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => {
if *arg2 != 0.into() {
let (result, _) = arg1.div_mod_floor(arg2);
Ok(Value::Con(Constant::Integer(result).into()).into())
} else {
Err(Error::DivideByZero(arg1.clone(), arg2.clone()))
} }
} }
_ => unreachable!(), _ => unreachable!(),
@ -368,38 +383,16 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::DivideInteger => {
match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => {
if *arg2 != 0 {
let ret = (*arg1 as f64) / (*arg2 as f64);
Ok(Value::Con(Constant::Integer(ret.floor() as i128).into())
.into())
} else {
Err(Error::DivideByZero(*arg1, *arg2))
}
}
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}
DefaultFunction::QuotientInteger => match (args[0].as_ref(), args[1].as_ref()) { DefaultFunction::QuotientInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
if *arg2 != 0 { if *arg2 != 0.into() {
let ret = (*arg1 as f64) / (*arg2 as f64); let (result, _) = arg1.div_rem(arg2);
let ret = if ret < 0. { ret.ceil() } else { ret.floor() }; Ok(Value::Con(Constant::Integer(result).into()).into())
Ok(Value::Con(Constant::Integer(ret as i128).into()).into())
} else { } else {
Err(Error::DivideByZero(*arg1, *arg2)) Err(Error::DivideByZero(arg1.clone(), arg2.clone()))
} }
} }
_ => unreachable!(), _ => unreachable!(),
@ -411,12 +404,12 @@ impl DefaultFunction {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
if *arg2 != 0 { if *arg2 != 0.into() {
let ret = arg1 % arg2; let (_, result) = arg1.div_rem(arg2);
Ok(Value::Con(Constant::Integer(ret).into()).into()) Ok(Value::Con(Constant::Integer(result).into()).into())
} else { } else {
Err(Error::DivideByZero(*arg1, *arg2)) Err(Error::DivideByZero(arg1.clone(), arg2.clone()))
} }
} }
_ => unreachable!(), _ => unreachable!(),
@ -428,12 +421,12 @@ impl DefaultFunction {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
if *arg2 != 0 { if *arg2 != 0.into() {
let ret = arg1 % arg2; let (_, result) = arg1.div_mod_floor(arg2);
Ok(Value::Con(Constant::Integer(ret.abs()).into()).into()) Ok(Value::Con(Constant::Integer(result).into()).into())
} else { } else {
Err(Error::DivideByZero(*arg1, *arg2)) Err(Error::DivideByZero(arg1.clone(), arg2.clone()))
} }
} }
_ => unreachable!(), _ => unreachable!(),
@ -493,7 +486,12 @@ impl DefaultFunction {
(Value::Con(integer), Value::Con(byte_string)) => { (Value::Con(integer), Value::Con(byte_string)) => {
match (integer.as_ref(), byte_string.as_ref()) { match (integer.as_ref(), byte_string.as_ref()) {
(Constant::Integer(arg1), Constant::ByteString(arg2)) => { (Constant::Integer(arg1), Constant::ByteString(arg2)) => {
let mut ret = vec![(arg1 % 256) as u8]; let wrap = arg1.mod_floor(&256.into());
let byte: u8 = wrap.try_into().unwrap();
let mut ret = vec![byte];
ret.extend(arg2.clone()); ret.extend(arg2.clone());
Ok(Value::Con(Constant::ByteString(ret).into()).into()) Ok(Value::Con(Constant::ByteString(ret).into()).into())
@ -512,8 +510,16 @@ impl DefaultFunction {
Constant::Integer(arg2), Constant::Integer(arg2),
Constant::ByteString(arg3), Constant::ByteString(arg3),
) => { ) => {
let skip = if 0 > *arg1 { 0 } else { *arg1 as usize }; let skip: usize = if arg1.lt(&0.into()) {
let take = if 0 > *arg2 { 0 } else { *arg2 as usize }; 0
} else {
arg1.try_into().unwrap()
};
let take: usize = if arg2.lt(&0.into()) {
0
} else {
arg2.try_into().unwrap()
};
let ret: Vec<u8> = let ret: Vec<u8> =
arg3.iter().skip(skip).take(take).cloned().collect(); arg3.iter().skip(skip).take(take).cloned().collect();
@ -529,7 +535,7 @@ impl DefaultFunction {
DefaultFunction::LengthOfByteString => match args[0].as_ref() { DefaultFunction::LengthOfByteString => match args[0].as_ref() {
Value::Con(byte_string) => match byte_string.as_ref() { Value::Con(byte_string) => match byte_string.as_ref() {
Constant::ByteString(arg1) => { Constant::ByteString(arg1) => {
Ok(Value::Con(Constant::Integer(arg1.len() as i128).into()).into()) Ok(Value::Con(Constant::Integer(arg1.len().into()).into()).into())
} }
_ => unreachable!(), _ => unreachable!(),
}, },
@ -539,14 +545,14 @@ impl DefaultFunction {
(Value::Con(byte_string), Value::Con(integer)) => { (Value::Con(byte_string), Value::Con(integer)) => {
match (byte_string.as_ref(), integer.as_ref()) { match (byte_string.as_ref(), integer.as_ref()) {
(Constant::ByteString(arg1), Constant::Integer(arg2)) => { (Constant::ByteString(arg1), Constant::Integer(arg2)) => {
let index = *arg2 as usize; let index: i128 = arg2.try_into().unwrap();
if 0 <= *arg2 && index < arg1.len() { if 0 <= index && index < arg1.len() as i128 {
let ret = arg1[index] as i128; let ret = arg1[index as usize];
Ok(Value::Con(Constant::Integer(ret).into()).into()) Ok(Value::Con(Constant::Integer(ret.into()).into()).into())
} else { } else {
Err(Error::ByteStringOutOfBounds(*arg2, arg1.to_vec())) Err(Error::ByteStringOutOfBounds(arg2.clone(), arg1.to_vec()))
} }
} }
_ => unreachable!(), _ => unreachable!(),
@ -879,10 +885,11 @@ impl DefaultFunction {
}) })
.collect(); .collect();
let i: u64 = i.try_into().unwrap();
let constr_data = PlutusData::Constr(Constr { let constr_data = PlutusData::Constr(Constr {
tag: convert_constr_to_tag(*i as u64).unwrap_or(ANY_TAG), tag: convert_constr_to_tag(i).unwrap_or(ANY_TAG),
any_constructor: convert_constr_to_tag(*i as u64) any_constructor: convert_constr_to_tag(i).map_or(Some(i), |_| None),
.map_or(Some(*i as u64), |_| None),
fields: data_list, fields: data_list,
}); });
@ -938,8 +945,7 @@ impl DefaultFunction {
DefaultFunction::IData => match args[0].as_ref() { DefaultFunction::IData => match args[0].as_ref() {
Value::Con(integer) => match integer.as_ref() { Value::Con(integer) => match integer.as_ref() {
Constant::Integer(i) => Ok(Value::Con( Constant::Integer(i) => Ok(Value::Con(
Constant::Data(PlutusData::BigInt(BigInt::Int((*i).try_into().unwrap()))) Constant::Data(PlutusData::BigInt(to_pallas_bigint(i))).into(),
.into(),
) )
.into()), .into()),
_ => unreachable!(), _ => unreachable!(),
@ -966,7 +972,7 @@ impl DefaultFunction {
Constant::Integer( Constant::Integer(
convert_tag_to_constr(c.tag) convert_tag_to_constr(c.tag)
.unwrap_or_else(|| c.any_constructor.unwrap()) .unwrap_or_else(|| c.any_constructor.unwrap())
as i128, .into(),
) )
.into(), .into(),
Constant::ProtoList( Constant::ProtoList(
@ -1048,13 +1054,7 @@ impl DefaultFunction {
DefaultFunction::UnIData => match args[0].as_ref() { DefaultFunction::UnIData => match args[0].as_ref() {
Value::Con(data) => match data.as_ref() { Value::Con(data) => match data.as_ref() {
Constant::Data(PlutusData::BigInt(b)) => { Constant::Data(PlutusData::BigInt(b)) => {
if let BigInt::Int(i) = b { Ok(Value::Con(Constant::Integer(from_pallas_bigint(b)).into()).into())
let x: i128 = (*i).try_into().unwrap();
Ok(Value::Con(Constant::Integer(x).into()).into())
} else {
unreachable!()
}
} }
v => Err(Error::DeserialisationError( v => Err(Error::DeserialisationError(
"UnMapData".to_string(), "UnMapData".to_string(),

View File

@ -159,7 +159,7 @@ peg::parser! {
= n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) } = n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) }
rule big_number() -> BigInt rule big_number() -> BigInt
= n:$("-"* ['0'..='9']+) {? (if n.starts_with("-") { BigInt::parse_bytes(&n.as_bytes()[1..], 10).map(|i| i.neg()) } else { BigInt::parse_bytes(n.as_bytes(), 10) }).ok_or("BigInt") } = n:$("-"* ['0'..='9']+) {? (if n.starts_with('-') { BigInt::parse_bytes(&n.as_bytes()[1..], 10).map(|i| i.neg()) } else { BigInt::parse_bytes(n.as_bytes(), 10) }).ok_or("BigInt") }
rule boolean() -> bool rule boolean() -> bool
= b:$("True" / "False") { b == "True" } = b:$("True" / "False") { b == "True" }
@ -258,6 +258,8 @@ peg::parser! {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use num_bigint::BigInt;
use crate::ast::{Constant, Name, Program, Term, Type, Unique}; use crate::ast::{Constant, Name, Program, Term, Type, Unique};
use crate::builtins::DefaultFunction; use crate::builtins::DefaultFunction;
use std::rc::Rc; use std::rc::Rc;
@ -554,7 +556,10 @@ mod test {
argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00]).into())) argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00]).into()))
}), }),
argument: Rc::new(Term::Constant( argument: Rc::new(Term::Constant(
Constant::Integer(9223372036854775808.into()).into() Constant::Integer(
BigInt::parse_bytes("9223372036854775808".as_bytes(), 10).unwrap()
)
.into()
)), )),
} }
} }