Skip to content

Commit

Permalink
problem: error-prone approach with manual serialization, a field can …
Browse files Browse the repository at this point in the history
…easily be missed in one of the places

solution: use Jackson annotations
  • Loading branch information
splix committed Aug 31, 2023
1 parent f42fd11 commit 2e6ae0d
Show file tree
Hide file tree
Showing 17 changed files with 307 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ChainId {
public static final ChainId RINKEBY_TESTNET = new ChainId(4);
public static final ChainId KOVAN_TESTNET = new ChainId(42);

private int value;
private final int value;

public ChainId(int value) {
if (!ChainId.isValid(value)) {
Expand All @@ -40,7 +40,7 @@ public ChainId(int value) {
}

public static boolean isValid(int value) {
return value >= 0 && value <= 255;
return value >= 0;
}

public int getValue() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public class TransactionSignature {

private ChainId chainId;

private HexData publicKey;
private HexData r;
private HexData s;
private Integer v;
Expand All @@ -44,14 +43,6 @@ public void setChainId(ChainId chainId) {
this.chainId = chainId;
}

public HexData getPublicKey() {
return publicKey;
}

public void setPublicKey(HexData publicKey) {
this.publicKey = publicKey;
}

public HexData getR() {
return r;
}
Expand Down Expand Up @@ -105,7 +96,7 @@ public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TransactionSignature)) return false;
TransactionSignature that = (TransactionSignature) o;
return Objects.equals(chainId, that.chainId) && Objects.equals(publicKey, that.publicKey) && Objects.equals(r, that.r) && Objects.equals(s, that.s) && Objects.equals(v, that.v);
return Objects.equals(chainId, that.chainId) && Objects.equals(r, that.r) && Objects.equals(s, that.s) && Objects.equals(v, that.v);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,19 @@ class ChainIdSpec extends Specification {
x << (0..255)
}

def "Decline non-byte numbers"() {
def "Decline negative numbers"() {
expect:
!ChainId.isValid(x)
where:
x << [-1, -100, -250, 256, 1024, 6161, 6819571, Integer.MAX_VALUE, Integer.MIN_VALUE]
x << [-1, -100, -250]
}

def "Doesn't allow to create invalid id"() {
when:
new ChainId(1024)
then:
thrown(IllegalArgumentException)
def "Accept standard chains"() {
// see https://chainlist.org/
expect:
ChainId.isValid(x)
where:
x << [1, 56, 42161, 137, 10, 43114, 25, 2222, 8453, 8217, 32659, 369, 66, 42220, 30, 250, 100]
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ public HexDataDeserializer() {
public HexData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonToken token = p.currentToken();
if (token == JsonToken.VALUE_STRING) {
String value = p.getValueAsString();
if ("0x".equals(value)) {
return null;
}
try {
return HexData.from(p.getValueAsString());
return HexData.from(value);
} catch (Throwable t) {
throw JsonMappingException.from(p,"Invalid HexData value: " + p.getValueAsString(), t);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.emeraldpay.etherjar.rpc.json;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import io.emeraldpay.etherjar.hex.HexQuantity;

import java.io.IOException;

/**
* Deserialize Long from Hex Quantity
*/
public class HexIntDeserializer extends StdDeserializer<Integer> {

public HexIntDeserializer() {
super(Integer.class);
}

@Override
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonToken token = p.currentToken();
if (token == JsonToken.VALUE_STRING) {
try {
return HexQuantity.from(p.getValueAsString()).getValue().intValueExact();
} catch (Throwable t) {
throw JsonMappingException.from(p,"Invalid HexQuantity value: " + p.getValueAsString(), t);
}
}
if (token == JsonToken.VALUE_NUMBER_INT) {
return p.getValueAsInt();
}
if (token == JsonToken.VALUE_NULL) {
return null;
}
throw JsonMappingException.from(p,"Invalid HexQuantity type: " + token);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.emeraldpay.etherjar.rpc.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import io.emeraldpay.etherjar.hex.HexQuantity;

import java.io.IOException;

/**
* Serialize Long as Hex Quantity
*/
public class HexIntSerializer extends StdSerializer<Integer> {

public HexIntSerializer() {
super(Integer.class);
}

@Override
public void serialize(Integer value, JsonGenerator gen, SerializerProvider provider) throws IOException {
if (value == null) {
gen.writeNull();
} else {
gen.writeString(HexQuantity.from(value.longValue()).toHex());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOExce
JsonToken token = p.currentToken();
if (token == JsonToken.VALUE_STRING) {
try {
return HexQuantity.from(p.getValueAsString()).getValue().longValue();
return HexQuantity.from(p.getValueAsString()).getValue().longValueExact();
} catch (Throwable t) {
throw JsonMappingException.from(p,"Invalid HexQuantity value: " + p.getValueAsString(), t);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

package io.emeraldpay.etherjar.rpc.json;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.emeraldpay.etherjar.domain.*;
Expand All @@ -29,13 +32,15 @@
import java.util.List;
import java.util.Objects;

@JsonDeserialize(using = TransactionJsonDeserializer.class)
@JsonSerialize(using = TransactionJsonSerializer.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransactionJson extends TransactionRefJson implements TransactionRef, Serializable {

/**
* the number of transactions made by the sender prior to this one.
*/
@JsonDeserialize(using = HexLongDeserializer.class)
@JsonSerialize(using = HexLongSerializer.class)
private Long nonce;

/**
Expand All @@ -46,11 +51,15 @@ public class TransactionJson extends TransactionRefJson implements TransactionRe
/**
* block number where this transaction was in. null when its pending.
*/
@JsonDeserialize(using = HexLongDeserializer.class)
@JsonSerialize(using = HexLongSerializer.class)
private Long blockNumber;

/**
* position in the block. null when its pending.
* position in the block. null when it's pending.
*/
@JsonDeserialize(using = HexLongDeserializer.class)
@JsonSerialize(using = HexLongSerializer.class)
private Long transactionIndex;

/**
Expand All @@ -61,6 +70,7 @@ public class TransactionJson extends TransactionRefJson implements TransactionRe
/**
* address of the receiver. null when its a contract creation transaction.
*/
@JsonInclude(JsonInclude.Include.ALWAYS)
private Address to;

/**
Expand All @@ -83,24 +93,43 @@ public class TransactionJson extends TransactionRefJson implements TransactionRe
/**
* gas provided by the sender.
*/
@JsonDeserialize(using = HexLongDeserializer.class)
@JsonSerialize(using = HexLongSerializer.class)
private Long gas;

/**
* the data send along with the transaction.
*/
private HexData input;

private TransactionSignature signature;

/**
* Transaction type
*
* @see <a href="https://eips.ethereum.org/EIPS/eip-2718">EIP-2718: Typed Transaction Envelope</a>
*/
@JsonDeserialize(using = HexIntDeserializer.class)
@JsonSerialize(using = HexIntSerializer.class)
private int type = 0;

@JsonDeserialize(using = HexIntDeserializer.class)
@JsonSerialize(using = HexIntSerializer.class)
private Integer chainId;

@JsonDeserialize(using = HexIntDeserializer.class)
@JsonSerialize(using = HexIntSerializer.class)
private Integer v;

@JsonDeserialize
@JsonSerialize
private HexData r;

@JsonDeserialize
@JsonSerialize
private HexData s;

@JsonIgnore
private transient TransactionSignature signature;

private List<Access> accessList;

public Long getNonce() {
Expand Down Expand Up @@ -208,7 +237,19 @@ public void setInput(HexData input) {
}

public TransactionSignature getSignature() {
return signature;
if (signature != null) {
return signature;
}
if (v == null || r == null || s == null) {
return null;
}
TransactionSignature created = new TransactionSignature();
created.setV(v);
created.setR(r);
created.setS(s);
created.setChainId(chainId != null ? new ChainId(chainId) : null);
this.signature = created;
return created;
}

public void setSignature(TransactionSignature signature) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public TransactionJson deserialize(JsonNode node) {
signature.setR(getData(node, "r"));
signature.setS(getData(node, "s"));
signature.setV(getLong(node, "v").intValue());
signature.setPublicKey(getData(node, "publicKey"));
// signature.setPublicKey(getData(node, "publicKey"));

tx.setSignature(signature);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public void serialize(TransactionJson value, JsonGenerator gen, SerializerProvid
if (signature.getV() != null) {
writeField(gen, "v", signature.getV().longValue());
}
writeField(gen, "publicKey", signature.getPublicKey());
// writeField(gen, "publicKey", signature.getPublicKey());
}
List<TransactionJson.Access> accessList = value.getAccessList();
if (accessList != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class EtherjarModuleSpec extends Specification {
when:
def obj = objectMapper.readValue(json, TestObject.class)
then:
obj.hexData == HexData.empty()
obj.hexData == null
}

def "Fails to decode HexData invalid string value"() {
Expand Down
Loading

0 comments on commit 2e6ae0d

Please sign in to comment.