Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Handle serialization and deserialization of bigint/bytestring when length > 64 #398

Merged
merged 4 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.bloxbean.cardano.client.plutus.spec;

import co.nstant.in.cbor.model.DataItem;
import co.nstant.in.cbor.model.NegativeInteger;
import co.nstant.in.cbor.model.*;
import co.nstant.in.cbor.model.Number;
import co.nstant.in.cbor.model.UnsignedInteger;
import com.bloxbean.cardano.client.exception.CborDeserializationException;
import com.bloxbean.cardano.client.exception.CborSerializationException;
import com.bloxbean.cardano.client.plutus.spec.serializers.BigIntDataJsonDeserializer;
import com.bloxbean.cardano.client.plutus.spec.serializers.BigIntDataJsonSerializer;
Expand All @@ -24,13 +21,33 @@
public class BigIntPlutusData implements PlutusData {
private BigInteger value;

public static BigIntPlutusData deserialize(Number numberDI) throws CborDeserializationException {
public static BigIntPlutusData deserialize(Number numberDI) {
if (numberDI == null)
return null;

return new BigIntPlutusData(numberDI.getValue());
}

public static BigIntPlutusData deserialize(ByteString byteString) {
if (byteString == null)
return null;

var tag = byteString.getTag();
if (tag != null) {
switch ((int) tag.getValue()) {
case BIG_UINT_TAG:
return BigIntPlutusData.of(new BigInteger(1, byteString.getBytes()));
case BIG_NINT_TAG:
return BigIntPlutusData.of(MINUS_ONE.subtract(new BigInteger(1, byteString.getBytes())));
default:
throw new IllegalArgumentException("Invalid tag for BigIntPlutusData");
}
} else {
throw new IllegalArgumentException("Missing tag for BigIntPlutusData");
}
}


public static BigIntPlutusData of(int i) {
return new BigIntPlutusData(BigInteger.valueOf(i));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.NonNull;

import java.math.BigInteger;

public interface PlutusData {
int BIG_UINT_TAG = 2;
int BIG_NINT_TAG = 3;
BigInteger MINUS_ONE = BigInteger.valueOf(-1);

// plutus_data = ; New
// constr<plutus_data>
Expand Down Expand Up @@ -41,7 +46,13 @@ static PlutusData deserialize(DataItem dataItem) throws CborDeserializationExcep
if (dataItem instanceof Number) {
return BigIntPlutusData.deserialize((Number) dataItem);
} else if (dataItem instanceof ByteString) {
return BytesPlutusData.deserialize((ByteString) dataItem);
var tag = dataItem.getTag();
if (tag != null &&
(tag.getValue() == BIG_UINT_TAG || tag.getValue() == BIG_NINT_TAG)){
return BigIntPlutusData.deserialize((ByteString) dataItem);
} else {
return BytesPlutusData.deserialize((ByteString) dataItem);
}
} else if (dataItem instanceof UnicodeString) {
return BytesPlutusData.deserialize(((UnicodeString) dataItem));
} else if (dataItem instanceof Array) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.bloxbean.cardano.client.plutus.spec;

import co.nstant.in.cbor.model.ByteString;
import co.nstant.in.cbor.model.NegativeInteger;
import co.nstant.in.cbor.model.Number;
import co.nstant.in.cbor.model.UnsignedInteger;
import com.bloxbean.cardano.client.common.cbor.CborSerializationUtil;
import org.junit.jupiter.api.Test;

import java.math.BigInteger;

import static org.assertj.core.api.Assertions.assertThat;

class BigIntPlutusDataTest {

@Test
void deserialize_overLongNegative() throws Exception {
NegativeInteger negativeInteger = new NegativeInteger(new BigInteger("-10000000000000000020000003000000004000000"));
var bytes = CborSerializationUtil.serialize(negativeInteger);

BigIntPlutusData bigIntPlutusData = BigIntPlutusData.deserialize((ByteString) CborSerializationUtil.deserialize(bytes));
assertThat(bigIntPlutusData.getValue()).isEqualTo(new BigInteger("-10000000000000000020000003000000004000000"));
}

@Test
void deserialize_longNegative() throws Exception {
NegativeInteger negativeInteger = new NegativeInteger(BigInteger.valueOf(Long.MAX_VALUE).negate());
var bytes = CborSerializationUtil.serialize(negativeInteger);

BigIntPlutusData bigIntPlutusData = BigIntPlutusData.deserialize((Number) CborSerializationUtil.deserialize(bytes));
assertThat(bigIntPlutusData.getValue()).isEqualTo(BigInteger.valueOf(Long.MAX_VALUE).negate());
}

@Test
void deserialize_overLong() throws Exception {
UnsignedInteger integer = new UnsignedInteger(new BigInteger("10000000000000000020000003000000004000000"));
var bytes = CborSerializationUtil.serialize(integer);

BigIntPlutusData bigIntPlutusData = BigIntPlutusData.deserialize((ByteString) CborSerializationUtil.deserialize(bytes));
assertThat(bigIntPlutusData.getValue()).isEqualTo(new BigInteger("10000000000000000020000003000000004000000"));
}

@Test
void deserialize_long() throws Exception {
UnsignedInteger integer = new UnsignedInteger(BigInteger.valueOf(Long.MAX_VALUE));
var bytes = CborSerializationUtil.serialize(integer);

BigIntPlutusData bigIntPlutusData = BigIntPlutusData.deserialize((Number) CborSerializationUtil.deserialize(bytes));
assertThat(bigIntPlutusData.getValue()).isEqualTo(BigInteger.valueOf(Long.MAX_VALUE));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import co.nstant.in.cbor.CborDecoder;
import co.nstant.in.cbor.CborException;
import co.nstant.in.cbor.model.ByteString;
import co.nstant.in.cbor.model.DataItem;
import com.bloxbean.cardano.client.common.cbor.CborSerializationUtil;
import com.bloxbean.cardano.client.exception.CborDeserializationException;
Expand Down Expand Up @@ -192,4 +193,71 @@ void unitPlutusDataSerialization() {
assertThat(((ConstrPlutusData)plutusData).getData().getPlutusDataList()).hasSize(0);
}

@Test
void bigIntAsByteString() throws Exception {
String datumCbor = "d8798b581c217a7bf7a6494a0165ae2cb77aabeadb865d33d5be5f9f57b9b0e8f6581c276ba8bb7fe700d0d21b7da11edeb650729efe0b1595af0e643e31844b4e656f6e50756e6b3033311a3b9aca005563687447785a454339663038514d504b6970773073d87980d87980c2410040c241005820dee0b6f2b41b1a75244ec7b83c77c45d5cda5ad4ff3a4964340bb6089d5256e5";
byte[] datumBytes = HexUtil.decodeHexString(datumCbor);

var constrPlutusData = ConstrPlutusData.deserialize(CborSerializationUtil.deserialize(datumBytes));

// assertThat(constrPlutusData.getDatumHash()).isEqualTo("d350694acac39f6951f3e4ce2344d321d0cb1b3fa398759a72250b3f0732e16f");

assertThat(constrPlutusData.getData().getPlutusDataList().get(7)).isInstanceOf(BigIntPlutusData.class);
assertThat(constrPlutusData.getData().getPlutusDataList().get(8)).isInstanceOf(BytesPlutusData.class);
assertThat(constrPlutusData.getData().getPlutusDataList().get(9)).isInstanceOf(BigIntPlutusData.class);
assertThat(constrPlutusData.getData().getPlutusDataList().get(10)).isInstanceOf(BytesPlutusData.class);
}

@Test
void bigIntAsByteString_withNegativeValues() throws Exception {
var constrData = ConstrPlutusData.builder()
.alternative(0)
.data(ListPlutusData.builder()
.plutusDataList(Arrays.asList(
BigIntPlutusData.of(new BigInteger("18446744073709551615")),
BigIntPlutusData.of(new BigInteger("18446744073709551616")),
BigIntPlutusData.of(new BigInteger("-18446744073709551618")),
BigIntPlutusData.of(new BigInteger("100100000000200000900000004000000").negate()),
BigIntPlutusData.of(new BigInteger("20010000000020000090000000000")),
BigIntPlutusData.of(BigInteger.valueOf(Long.MAX_VALUE)),
BigIntPlutusData.of(BigInteger.valueOf(Long.MAX_VALUE).negate()),
BigIntPlutusData.of(BigInteger.valueOf(Integer.MAX_VALUE)),
BigIntPlutusData.of(BigInteger.valueOf(6700))
))
.build())
.build();

var serializedBytes = constrData.serializeToBytes();

var deserConstrData = ConstrPlutusData.deserialize(CborSerializationUtil.deserialize(serializedBytes));

assertThat(deserConstrData.getData().getPlutusDataList().get(0)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(0)).getValue()).isEqualTo(new BigInteger("18446744073709551615"));

assertThat(deserConstrData.getData().getPlutusDataList().get(1)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(1)).getValue()).isEqualTo(new BigInteger("18446744073709551616"));

assertThat(deserConstrData.getData().getPlutusDataList().get(2)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(2)).getValue()).isEqualTo(new BigInteger("18446744073709551618").negate());

assertThat(deserConstrData.getData().getPlutusDataList().get(3)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(3)).getValue()).isEqualTo(new BigInteger("100100000000200000900000004000000").negate());

assertThat(deserConstrData.getData().getPlutusDataList().get(4)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(4)).getValue()).isEqualTo(new BigInteger("20010000000020000090000000000"));

assertThat(deserConstrData.getData().getPlutusDataList().get(5)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(5)).getValue()).isEqualTo(BigInteger.valueOf(Long.MAX_VALUE));

assertThat(deserConstrData.getData().getPlutusDataList().get(6)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(6)).getValue()).isEqualTo(BigInteger.valueOf(Long.MAX_VALUE).negate());

assertThat(deserConstrData.getData().getPlutusDataList().get(7)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(7)).getValue()).isEqualTo(BigInteger.valueOf(Integer.MAX_VALUE));

assertThat(deserConstrData.getData().getPlutusDataList().get(8)).isInstanceOf(BigIntPlutusData.class);
assertThat(((BigIntPlutusData)deserConstrData.getData().getPlutusDataList().get(8)).getValue()).isEqualTo(new BigInteger("6700"));

}

}
Loading