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

Issues/253 - Refactor for defects in byte serialization and desieralization of AbstractCLTypeWithChildren #254

Merged
merged 7 commits into from
Mar 13, 2024
65 changes: 41 additions & 24 deletions src/main/java/com/casper/sdk/helper/CasperDeployHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CasperDeployHelper {

public static DeployHeader buildDeployHeader(PublicKey fromPublicKey, String chainName,
Long gasPrice, Ttl ttl, Date date,
List<Digest> dependencies, byte[] bodyHash) {
public static DeployHeader buildDeployHeader(final PublicKey fromPublicKey,
final String chainName,
final Long gasPrice,
final Ttl ttl,
final Date date,
final List<Digest> dependencies,
final byte[] bodyHash) {
return DeployHeader
.builder()
.account(fromPublicKey)
Expand All @@ -54,28 +58,29 @@ public static DeployHeader buildDeployHeader(PublicKey fromPublicKey, String cha
.build();
}

public static HashAndSignature signDeployHeader(AbstractPrivateKey privateKey, DeployHeader deployHeader)
public static HashAndSignature signDeployHeader(final AbstractPrivateKey privateKey, final DeployHeader deployHeader)
throws GeneralSecurityException, NoSuchTypeException, ValueSerializationException {
SerializerBuffer serializerBuffer = new SerializerBuffer();

final SerializerBuffer serializerBuffer = new SerializerBuffer();
deployHeader.serialize(serializerBuffer, Target.BYTE);
byte[] headerHash = Blake2b.digest(serializerBuffer.toByteArray(), 32);
Signature signature = Signature.sign(privateKey, headerHash);
final byte[] headerHash = Blake2b.digest(serializerBuffer.toByteArray(), 32);
final Signature signature = Signature.sign(privateKey, headerHash);
return new HashAndSignature(headerHash, signature);
}

public static byte[] getDeployItemAndModuleBytesHash(ExecutableDeployItem deployItem, ModuleBytes moduleBytes)
public static byte[] getDeployItemAndModuleBytesHash(final ExecutableDeployItem deployItem, final ModuleBytes moduleBytes)
throws NoSuchTypeException, ValueSerializationException {
SerializerBuffer ser = new SerializerBuffer();
final SerializerBuffer ser = new SerializerBuffer();
moduleBytes.serialize(ser, Target.BYTE);
deployItem.serialize(ser, Target.BYTE);
return Blake2b.digest(ser.toByteArray(), 32);
}

public static ModuleBytes getPaymentModuleBytes(BigInteger paymentAmount) throws ValueSerializationException {
List<NamedArg<?>> paymentArgs = new LinkedList<>();
NamedArg<CLTypeU512> paymentArg = new NamedArg<>("amount",
new CLValueU512(paymentAmount));
public static ModuleBytes getPaymentModuleBytes(final BigInteger paymentAmount) throws ValueSerializationException {
final List<NamedArg<?>> paymentArgs = new LinkedList<>();
final NamedArg<CLTypeU512> paymentArg = new NamedArg<>(
"amount",
new CLValueU512(paymentAmount)
);
paymentArgs.add(paymentArg);
return ModuleBytes
.builder()
Expand All @@ -96,26 +101,38 @@ public static ModuleBytes getPaymentModuleBytes(BigInteger paymentAmount) throws
* ms (30 minutes))
* @param date deploy date
* @param dependencies list of digest dependencies
* @return
* @return the built deploy
* @throws NoSuchTypeException
* @throws GeneralSecurityException
* @throws ValueSerializationException
*/
public static Deploy buildDeploy(AbstractPrivateKey fromPrivateKey, String chainName,
ExecutableDeployItem session, ModuleBytes payment,
Long gasPrice, Ttl ttl, Date date, List<Digest> dependencies)
public static Deploy buildDeploy(final AbstractPrivateKey fromPrivateKey,
final String chainName,
final ExecutableDeployItem session,
final ModuleBytes payment,
final Long gasPrice,
final Ttl ttl,
final Date date,
final List<Digest> dependencies)
throws NoSuchTypeException, GeneralSecurityException, ValueSerializationException {

byte[] sessionAnPaymentHash = getDeployItemAndModuleBytesHash(session, payment);
final byte[] sessionAnPaymentHash = getDeployItemAndModuleBytesHash(session, payment);

PublicKey fromPublicKey = PublicKey.fromAbstractPublicKey(fromPrivateKey.derivePublicKey());
final PublicKey fromPublicKey = PublicKey.fromAbstractPublicKey(fromPrivateKey.derivePublicKey());

DeployHeader deployHeader = buildDeployHeader(fromPublicKey, chainName, gasPrice, ttl,
date, dependencies, sessionAnPaymentHash);
final DeployHeader deployHeader = buildDeployHeader(
fromPublicKey,
chainName,
gasPrice,
ttl,
date,
dependencies,
sessionAnPaymentHash
);

HashAndSignature hashAndSignature = signDeployHeader(fromPrivateKey, deployHeader);
final HashAndSignature hashAndSignature = signDeployHeader(fromPrivateKey, deployHeader);

List<Approval> approvals = new LinkedList<>();
final List<Approval> approvals = new LinkedList<>();
approvals.add(Approval.builder()
.signer(PublicKey.fromAbstractPublicKey(fromPrivateKey.derivePublicKey()))
.signature(hashAndSignature.getSignature())
Expand Down
27 changes: 16 additions & 11 deletions src/main/java/com/casper/sdk/model/clvalue/AbstractCLValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.jackson.resolver.CLValueResolver;
import com.casper.sdk.model.clvalue.cltype.AbstractCLType;
import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren;
import com.casper.sdk.model.clvalue.cltype.CLTypeData;
import com.casper.sdk.model.clvalue.serde.CasperDeserializableObject;
import com.casper.sdk.model.clvalue.serde.CasperSerializableObject;
Expand Down Expand Up @@ -58,15 +59,27 @@ public void setValue(final T value) throws ValueSerializationException {
final int length = deser.readI32();
final byte[] bytes = deser.readByteArray(length);
final byte clType = deser.readU8();

try {
final AbstractCLValue<?, ?> clValue = CLTypeData.getTypeBySerializationTag(clType).getClazz().getDeclaredConstructor().newInstance();
CLTypeData clTypeData = CLTypeData.getTypeBySerializationTag(clType);
final AbstractCLValue<?, ?> clValue = clTypeData.getClazz().getDeclaredConstructor().newInstance();
if (clValue instanceof AbstractCLValueWithChildren) {
// We have only obtained the parent type from the buffer now we need to read the child types
((AbstractCLTypeWithChildren) clValue.getClType()).deserializeChildTypes(deser);
}

clValue.deserializeCustom(new DeserializerBuffer(Hex.encode(bytes)));
return clValue;
} catch (Exception e) {
throw new ValueDeserializationException("Error while instantiating CLValue", e);
}
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@SneakyThrows({ValueSerializationException.class, NoSuchTypeException.class})
@JsonGetter(value = "bytes")
@ExcludeFromJacocoGeneratedReport
Expand All @@ -84,10 +97,7 @@ protected String getJsonBytes() {
@ExcludeFromJacocoGeneratedReport
protected void setJsonBytes(final String bytes) {
this.bytes = bytes;

final DeserializerBuffer deser = new DeserializerBuffer(this.bytes);

this.deserialize(deser);
this.deserialize(new DeserializerBuffer(this.bytes));
}

@JsonIgnore
Expand Down Expand Up @@ -124,7 +134,7 @@ public void serialize(final SerializerBuffer ser, final Target target) throws Va
serializeValue(ser);

if (Target.BYTE.equals(target)) {
this.encodeType(ser);
getClType().serialize(ser);
}
}

Expand All @@ -140,9 +150,4 @@ public void deserialize(final DeserializerBuffer deserializerBuffer) throws Valu
throw new ValueDeserializationException("Error deserializing value", e);
}
}

protected void encodeType(final SerializerBuffer ser) throws NoSuchTypeException {
final byte typeTag = (getClType().getClTypeData().getSerializationTag());
ser.writeU8(typeTag);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.casper.sdk.model.clvalue;

import com.casper.sdk.annotation.ExcludeFromJacocoGeneratedReport;
import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren;
import com.casper.sdk.model.clvalue.cltype.CLTypeData;
import com.fasterxml.jackson.annotation.JsonSetter;
import dev.oak3.sbs4j.DeserializerBuffer;
import dev.oak3.sbs4j.SerializerBuffer;
import dev.oak3.sbs4j.exception.ValueDeserializationException;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
Expand All @@ -32,8 +29,7 @@ public abstract class AbstractCLValueWithChildren<T, P extends AbstractCLTypeWit
@SneakyThrows({ValueDeserializationException.class})
protected void childTypesSet() {
if (!getBytes().isEmpty()) {
DeserializerBuffer deser = new DeserializerBuffer(this.getBytes());
this.deserialize(deser);
this.deserialize(new DeserializerBuffer(this.getBytes()));
}
}

Expand All @@ -50,36 +46,7 @@ protected void setJsonBytes(String bytes) {
this.setBytes(bytes);

if (!getClType().getChildTypes().isEmpty() && getClType().isDeserializable()) {
DeserializerBuffer deser = new DeserializerBuffer(this.getBytes());
this.deserialize(deser);
}
}

protected void encodeType(final SerializerBuffer ser) throws NoSuchTypeException {
super.encodeType(ser);
encodeChildTypes(ser);
}

protected abstract void encodeChildTypes(final SerializerBuffer ser) throws NoSuchTypeException;

/**
* Encodes the bytes of the child type, if the child value is not present but the type is known from the parent type
* info, the childDataType is used to encode the bytes of the child rather than the child value.
*
* @param ser the serializer buffer
* @param child the child value whose type is to be encoded
* @param childDataType the data type of the child
* @throws NoSuchTypeException if the child type is not found
*/
protected void encodeChildType(final SerializerBuffer ser,
final AbstractCLValue<?, ?> child,
final CLTypeData childDataType) throws NoSuchTypeException {
if (child instanceof AbstractCLValueWithChildren) {
child.encodeType(ser);
} else {
// If there are no AbstractCLValueWithChildren as children we just need a simple tag
byte element0TypeTag = childDataType.getSerializationTag();
ser.writeU8(element0TypeTag);
this.deserialize(new DeserializerBuffer(this.getBytes()));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.casper.sdk.model.clvalue;

import com.casper.sdk.annotation.ExcludeFromJacocoGeneratedReport;
import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.cltype.CLTypeByteArray;
import com.fasterxml.jackson.annotation.JsonProperty;
import dev.oak3.sbs4j.DeserializerBuffer;
Expand Down Expand Up @@ -42,12 +41,6 @@ protected void serializeValue(final SerializerBuffer ser) throws ValueSerializat
this.setBytes(Hex.toHexString(getValue()));
}

@Override
protected void encodeType(final SerializerBuffer ser) throws NoSuchTypeException {
super.encodeType(ser);
ser.writeI32(this.getClType().getLength());
}

@Override
public void deserializeCustom(final DeserializerBuffer deser) throws Exception {
this.setValue(deser.readByteArray(this.getClType().getLength()));
Expand Down
6 changes: 0 additions & 6 deletions src/main/java/com/casper/sdk/model/clvalue/CLValueList.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.casper.sdk.model.clvalue;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren;
import com.casper.sdk.model.clvalue.cltype.CLTypeData;
import com.casper.sdk.model.clvalue.cltype.CLTypeList;
Expand Down Expand Up @@ -67,11 +66,6 @@ protected void serializeValue(final SerializerBuffer ser) throws ValueSerializat
this.setBytes(Hex.toHexString(bytes));
}

@Override
protected void encodeChildTypes(final SerializerBuffer ser) throws NoSuchTypeException {
final byte val = (getClType().getListType().getClTypeData().getSerializationTag());
ser.writeU8(val);
}

@Override
public void deserializeCustom(final DeserializerBuffer deser) throws Exception {
Expand Down
37 changes: 23 additions & 14 deletions src/main/java/com/casper/sdk/model/clvalue/CLValueMap.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.casper.sdk.model.clvalue;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren;
import com.casper.sdk.model.clvalue.cltype.CLTypeData;
import com.casper.sdk.model.clvalue.cltype.CLTypeMap;
Expand Down Expand Up @@ -70,18 +69,13 @@ protected void serializeValue(final SerializerBuffer ser) throws ValueSerializat
this.setBytes(Hex.toHexString(bytes));
}

@Override
protected void encodeChildTypes(final SerializerBuffer ser) throws NoSuchTypeException {

final byte keyTypeTag = (getClType().getKeyValueTypes().getKeyType().getClTypeData().getSerializationTag());
ser.writeU8(keyTypeTag);

final byte valueTypeTag = (getClType().getKeyValueTypes().getValueType().getClTypeData().getSerializationTag());
ser.writeU8(valueTypeTag);
}

@Override
public void deserializeCustom(final DeserializerBuffer deser) throws Exception {
if (this.clType.getChildTypes().isEmpty()) {
this.clType.deserializeChildTypes(deser);
}

final CLTypeData keyType = clType.getKeyValueTypes().getKeyType().getClTypeData();
final CLTypeData valType = clType.getKeyValueTypes().getValueType().getClTypeData();

Expand Down Expand Up @@ -116,6 +110,7 @@ public void deserializeCustom(final DeserializerBuffer deser) throws Exception {
setValue(map);
}


@Override
@JsonIgnore
protected void setChildTypes(final Map<? extends AbstractCLValue<?, ?>, ? extends AbstractCLValue<?, ?>> value) {
Expand All @@ -127,9 +122,14 @@ protected void setChildTypes(final Map<? extends AbstractCLValue<?, ?>, ? extend
}
}

// This needed to be customized to ensure equality is being checked correctly.
// The java Map equals method tries to get the "other" map entry's value by using "this" key object,
// which then fails to find the object since they are "different" and returns always null.
/**
* This needed to be customized to ensure equality is being checked correctly.
* The java Map equals method tries to get the "other" map entry's value by using "this" key object,
* which then fails to find the object since they are "different" and returns always null.
*
* @param o the object to compare
* @return true if the objects are equal, false otherwise
*/
@Override
public boolean equals(final Object o) {
if (o == this) return true;
Expand Down Expand Up @@ -180,6 +180,15 @@ public int hashCode() {

@Override
public String toString() {
return getValue() != null ? getValue().keySet().stream().map(key -> key.getValue().toString() + "=" + key.getValue().toString()).collect(Collectors.joining(", ")) : null;
if (getValue() == null) {
return null;
} else {
return getValue()
.entrySet()
.stream()
.map(entry ->
entry.getKey().toString() + "=" + entry.getValue().toString()).collect(Collectors.joining(", ")
);
}
}
}
9 changes: 0 additions & 9 deletions src/main/java/com/casper/sdk/model/clvalue/CLValueOption.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.casper.sdk.model.clvalue;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.cltype.*;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
Expand Down Expand Up @@ -92,14 +91,6 @@ public void deserializeCustom(final DeserializerBuffer deser) throws Exception {
setValue(Optional.of(child));
}

@Override
protected void encodeChildTypes(final SerializerBuffer ser) throws NoSuchTypeException {
final Optional<AbstractCLValue<?, ?>> child = getValue();
if (child.isPresent()) {
encodeChildType(ser, child.get(), this.getClType().getOptionType().getClTypeData());
}
}

@Override
protected void setChildTypes(final Optional<AbstractCLValue<?, ?>> value) {
if (value.isPresent()) {
Expand Down
6 changes: 0 additions & 6 deletions src/main/java/com/casper/sdk/model/clvalue/CLValueTuple1.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.casper.sdk.model.clvalue;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.cltype.AbstractCLTypeWithChildren;
import com.casper.sdk.model.clvalue.cltype.CLTypeData;
import com.casper.sdk.model.clvalue.cltype.CLTypeTuple1;
Expand Down Expand Up @@ -56,11 +55,6 @@ protected void serializeValue(final SerializerBuffer ser) throws ValueSerializat
this.setBytes(Hex.toHexString(bytes));
}

@Override
protected void encodeChildTypes(final SerializerBuffer ser) throws NoSuchTypeException {
encodeChildType(ser, this.getValue().getValue0(), getClType().getChildClTypeData(0));
}

@Override
public void deserializeCustom(final DeserializerBuffer deser) throws Exception {
CLTypeData childTypeData1 = clType.getChildClTypeData(0);
Expand Down
Loading
Loading