Skip to content

Commit

Permalink
Merge pull request #331 from /issues/330
Browse files Browse the repository at this point in the history
Issues/330 - TransactionTarget  Stored json serialization and deserialization
  • Loading branch information
cnorburn authored Sep 4, 2024
2 parents c030fa9 + 956765f commit 48de573
Show file tree
Hide file tree
Showing 17 changed files with 441 additions and 141 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.casper.sdk.jackson.deserializer;

import com.casper.sdk.exception.DeserializationException;
import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.transaction.target.*;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.syntifi.crypto.key.encdec.Hex;

import java.io.IOException;
import java.util.Iterator;

import static com.casper.sdk.model.transaction.target.TargetConstants.*;

/**
* Deserializer for {@link TransactionTarget} types.
Expand All @@ -19,27 +22,52 @@
*/
public class TransactionTargetDeserializer extends JsonDeserializer<TransactionTarget> {

private static final String NATIVE_JSON = "\"Native\"";

@Override
public TransactionTarget deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
public TransactionTarget deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
if (p.getCurrentToken() == JsonToken.START_OBJECT) {
final ObjectNode treeNode = p.readValueAsTree();
final Iterator<String> stringIterator = treeNode.fieldNames();
final String next = stringIterator.next();
if (next != null && next.equals(Session.class.getSimpleName())) {
try {
return new Session(Hex.decode(treeNode.get(next).get("module_bytes").asText()),
TransactionRuntime.getJsonRuntime(treeNode.get(next).get("runtime").asText()));
} catch (NoSuchTypeException e) {
throw new RuntimeException(e);
}
final String fieldName = treeNode.fieldNames().next();
if (SESSION.equals(fieldName)) {
return createSession(treeNode.get(fieldName));
} else if (STORED.equals(fieldName)) {
return createStored(treeNode.get(fieldName), ctxt);
} else {
throw new IllegalArgumentException("Unknown transaction target type: " + next);
throw new IllegalArgumentException("Unknown transaction target type: " + fieldName);
}
} else if (p.getCurrentToken() == JsonToken.VALUE_STRING) {
} else if (p.getCurrentToken() == JsonToken.VALUE_STRING && NATIVE_JSON.equals(p.readValueAsTree().toString())) {
return new Native();
} else {
throw new IllegalArgumentException("Unknown transaction target type: " + p);
throw new IllegalArgumentException("Unknown transaction target type: " + p.readValueAsTree());
}
}

private Stored createStored(final JsonNode node, final DeserializationContext ctx) throws IOException {
try {
return new Stored(
createInvocationTarget(node, ctx),
TransactionRuntime.fromJson(node.get(RUNTIME).asText()));
} catch (NoSuchTypeException e) {
throw new DeserializationException("Unable to find 'runtime'", e);
}
}

private TransactionInvocationTarget createInvocationTarget(final JsonNode node, final DeserializationContext ctx) throws IOException {
try (final JsonParser parser = node.get(ID).traverse()) {
parser.setCodec(ctx.getParser().getCodec());
return parser.readValueAs(TransactionInvocationTarget.class);
}
}

private Session createSession(final JsonNode node) throws DeserializationException {
try {
return new Session(
Hex.decode(node.get(MODULE_BYTES).asText()),
TransactionRuntime.fromJson(node.get(RUNTIME).asText())
);
} catch (NoSuchTypeException e) {
throw new DeserializationException("Unable to find required fields", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import java.io.IOException;

import static com.casper.sdk.model.transaction.target.TargetConstants.*;

/**
* Serializes {@link TransactionTarget} objects.
*
Expand All @@ -19,21 +21,37 @@ public class TransactionTargetSerializer extends JsonSerializer<TransactionTarge
public void serialize(final TransactionTarget value, final JsonGenerator gen, final SerializerProvider serializers) throws IOException {

if (value instanceof Session) {
gen.writeStartObject();
gen.writeFieldName("Session");
gen.writeStartObject();
gen.writeStringField("module_bytes", Hex.encode(((Session) value).getModuleBytes()));
gen.writeStringField("runtime", TransactionRuntime.getJsonName(((Session) value).getRuntime()));
gen.writeEndObject();
gen.writeEndObject();
serializeSession((Session) value, gen);
} else if (value instanceof Native) {
gen.writeString("Native");
} else if (value instanceof Stored){
//TODO
throw new IllegalArgumentException("Stored is not yet implemented");
gen.writeString(NATIVE);
} else if (value instanceof Stored) {
serializeStored((Stored) value, gen);
} else {
throw new IllegalArgumentException("Unknown transaction target type: " + value.getClass().getName());
}
}

private static void serializeStored(final Stored value, final JsonGenerator gen) throws IOException {
gen.writeStartObject();
gen.writeFieldName(STORED);
gen.writeStartObject();
gen.writeFieldName(ID);
gen.writeObject(value.getId());
if (value.getRuntime() != null) {
gen.writeFieldName(RUNTIME);
gen.writeString(value.getRuntime().getJsonName());
}
gen.writeEndObject();
gen.writeEndObject();
}

private static void serializeSession(final Session value, final JsonGenerator gen) throws IOException {
gen.writeStartObject();
gen.writeFieldName(SESSION);
gen.writeStartObject();
gen.writeStringField(MODULE_BYTES, Hex.encode(value.getModuleBytes()));
gen.writeStringField(RUNTIME, TransactionRuntime.toJson(value.getRuntime()));
gen.writeEndObject();
gen.writeEndObject();
}
}
45 changes: 45 additions & 0 deletions src/main/java/com/casper/sdk/model/transaction/target/ByHash.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.casper.sdk.model.transaction.target;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.serde.Target;
import com.casper.sdk.model.common.Digest;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonValue;
import dev.oak3.sbs4j.SerializerBuffer;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
* The address identifying the invocable entity.
*
* @author ian@meywood.com
*/
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class ByHash implements TransactionInvocationTarget {
@JsonValue
private Digest hashAddress;

@JsonCreator
public ByHash(String hashAddress) {
this.hashAddress = new Digest(hashAddress);
}

@Override
public void serialize(final SerializerBuffer ser, final Target target) throws ValueSerializationException, NoSuchTypeException {
ser.writeU8(getByteTag());
ser.writeByteArray(hashAddress.getDigest());
}

@JsonIgnore
@Override
public byte getByteTag() {
return 0;
}
}
38 changes: 38 additions & 0 deletions src/main/java/com/casper/sdk/model/transaction/target/ByName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.casper.sdk.model.transaction.target;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.serde.Target;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonValue;
import dev.oak3.sbs4j.SerializerBuffer;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
* The alias identifying the invocable entity.
*
* @author ian@meywood.com
*/
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class ByName implements TransactionInvocationTarget {
@JsonValue
private String name;

@Override
public void serialize(final SerializerBuffer ser, final Target target) throws ValueSerializationException, NoSuchTypeException {
ser.writeU8(getByteTag());
ser.writeString(name);
}

@JsonIgnore
@Override
public byte getByteTag() {
return 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.casper.sdk.model.transaction.target;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.serde.Target;
import com.casper.sdk.model.common.Digest;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import dev.oak3.sbs4j.SerializerBuffer;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import lombok.*;

import java.util.Optional;

/**
* The address and optional version identifying the package.
*
* @author ian@meywood.com
*/
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class ByPackageHash implements TransactionInvocationTarget {
/** The package address. */
private Digest addr;
/** If `None`, the latest enabled version is implied. */
@Getter(AccessLevel.NONE)
@JsonProperty("version")
private Long version;

@JsonIgnore
public Optional<Long> getVersion() {
return Optional.ofNullable(version);
}

@Override
public void serialize(final SerializerBuffer ser, final Target target) throws ValueSerializationException, NoSuchTypeException {
ser.writeU8(getByteTag());
ser.writeByteArray(addr.getDigest());
if (getVersion().isPresent()) {
ser.writeBool(true);
ser.writeU32(version);
} else {
ser.writeBool(false);
}
}

@JsonIgnore
@Override
public byte getByteTag() {
return 2;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.casper.sdk.model.transaction.target;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.serde.Target;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import dev.oak3.sbs4j.SerializerBuffer;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import lombok.*;

import java.util.Optional;

/**
* The address and optional version identifying the package.
*
* @author ian@meywood.com
*/
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class ByPackageName implements TransactionInvocationTarget {
/** the package name */
private String name;
/** If `None`, the latest enabled version is implied. */
@Getter(AccessLevel.NONE)
@JsonProperty("version")
private Long version;

@JsonIgnore
public Optional<Long> getVersion() {
return Optional.ofNullable(version);
}

@Override
public void serialize(final SerializerBuffer ser, final Target target) throws ValueSerializationException, NoSuchTypeException {
ser.writeU8(getByteTag());
ser.writeString(name);
if (getVersion().isPresent()) {
ser.writeBool(true);
ser.writeU32(version);
} else {
ser.writeBool(false);
}
}

@JsonIgnore
@Override
public byte getByteTag() {
return 3;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.serde.Target;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import dev.oak3.sbs4j.SerializerBuffer;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import lombok.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
* The execution target is the included module bytes, i.e. compiled Wasm.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
@Builder
@JsonTypeName("Stored")
public class Stored implements TransactionTarget {
/** The identifier of the stored execution target. */
private TransactionInvocationTarget id;

/** The execution runtime to use. */
@JsonProperty("runtime")
Expand All @@ -29,6 +31,7 @@ public class Stored implements TransactionTarget {
@Override
public void serialize(final SerializerBuffer ser, final Target target) throws ValueSerializationException, NoSuchTypeException {
ser.writeU8(getByteTag());
id.serialize(ser, target);
ser.writeU8(runtime.getByteTag());
}

Expand Down
Loading

0 comments on commit 48de573

Please sign in to comment.