Skip to content

Commit

Permalink
Merge branch 'main' into df/add-unit-test-for-sig
Browse files Browse the repository at this point in the history
  • Loading branch information
sappenin authored Oct 22, 2024
2 parents 548bcd5 + eaf05aa commit 9294a84
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 84 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@
<jackson.version>2.14.2</jackson.version>
<feign.version>12.3</feign.version>
<slf4j.version>2.0.7</slf4j.version>
<junit-jupiter.version>5.10.0</junit-jupiter.version>
<junit-jupiter.version>5.10.1</junit-jupiter.version>
<guava.version>32.1.1-jre</guava.version>
</properties>

Expand Down Expand Up @@ -375,7 +375,7 @@
<!-- org.apache.maven.plugins:maven-source-plugin -->
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public interface LedgerEntryResult<T extends LedgerObject> extends XrplResult {
/**
* Construct a {@code LedgerEntryResult} builder.
*
* @param <T> The type of {@link LedgerObject}.
*
* @return An {@link ImmutableLedgerEntryResult.Builder}.
*/
static <T extends LedgerObject> ImmutableLedgerEntryResult.Builder<T> builder() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.xrpl.xrpl4j.model.jackson.modules;

/*-
* ========================LICENSE_START=================================
* xrpl4j :: model
* %%
* Copyright (C) 2020 - 2022 XRPL Foundation and its contributors
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =========================LICENSE_END==================================
*/

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.google.common.primitives.UnsignedLong;
import org.xrpl.xrpl4j.model.transactions.SetFee;
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;

import java.io.IOException;

/**
* Custom Jackson deserializer for {@link XrpCurrencyAmount} instances found in {@link SetFee}.
*
* <p>Before the <a href="https://xrpl.org/resources/known-amendments/#xrpfees">XRPFees amendment</a>, a {@link SetFee}
* transaction serializes its `BaseFee` to a hex string. After the
* <a href="https://xrpl.org/resources/known-amendments/#xrpfees">XRPFees amendment</a>, a {@link SetFee} transaction
* serializes its `BaseFee` to a decimal string.
*
* @see "https://xrpl.org/resources/known-amendments/#xrpfees"
*/
public class BaseFeeDropsDeserializer extends StdDeserializer<XrpCurrencyAmount> {

/**
* No-args constructor.
*/
public BaseFeeDropsDeserializer() {
super(XrpCurrencyAmount.class);
}

@Override
public XrpCurrencyAmount deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
// Pre-XRPFees, SetFee transactions serialize `BaseFee` to a hex string. Post XRPFees SetFee transactions
// have a `BaseFeeDrops` field which is a decimal string.
if (jsonParser.currentName().equals("BaseFee")) {
return XrpCurrencyAmount.of(UnsignedLong.valueOf(jsonParser.getText(), 16));
} else {
return XrpCurrencyAmount.ofDrops(jsonParser.getValueAsLong());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -20,12 +20,15 @@
* =========================LICENSE_END==================================
*/

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.primitives.UnsignedInteger;
import org.immutables.value.Value;
import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
import org.xrpl.xrpl4j.model.jackson.modules.BaseFeeDropsDeserializer;

import java.util.Optional;

Expand Down Expand Up @@ -53,34 +56,92 @@ static ImmutableSetFee.Builder builder() {
* The charge, in drops of XRP, for the reference transaction, as hex. (This is the transaction cost before scaling
* for load.)
*
* @return A hex {@link String} basefee value.
* <p>This method only exists for historical purposes. When deserialized from a {@link SetFee} transaction from
* ledgers prior to the {@code XRPFees} amendment, this field will still be set based on {@link #baseFeeDrops()}.
*
* @return A hex {@link String} baseFee value.
*/
@Value.Derived
@JsonIgnore
default String baseFee() {
return baseFeeDrops().value().toString(16);
}

/**
* The charge, in drops of XRP, for the reference transaction (This is the transaction cost before scaling for load).
*
* <p>This field will also be populated with the {@code BaseFee} value from any {@link SetFee} transactions
* that occurred before the XRPFees amendment took effect.</p>
*
* @return An {@link XrpCurrencyAmount}.
*/
@JsonProperty("BaseFee")
String baseFee();
@JsonProperty("BaseFeeDrops")
@JsonAlias("BaseFee")
@JsonDeserialize(using = BaseFeeDropsDeserializer.class)
XrpCurrencyAmount baseFeeDrops();

/**
* The cost, in fee units, of the reference transaction.
* The cost, in fee units, of the reference transaction. {@link SetFee} transactions deserialized from ledgers prior
* to the {@code XRPFees} amendment will always have this field, but transactions deserialized from ledgers post
* {@code XRPFees} activation will never have this field.
*
* @return An {@link UnsignedInteger} cost of ref transaction.
*/
@JsonProperty("ReferenceFeeUnits")
UnsignedInteger referenceFeeUnits();
Optional<UnsignedInteger> referenceFeeUnits();

/**
* The base reserve, in drops.
*
* @return An {@link UnsignedInteger} base reverse value in {@link org.xrpl.xrpl4j.model.client.fees.FeeDrops}.
* <p>This method only exists for historical purposes. When deserialized from a {@link SetFee} transaction from
* ledgers prior to the {@code XRPFees} amendment, this field will still be set based on {@link #reserveBaseDrops()}}.
*
* @return An {@link UnsignedInteger} base reserve value in {@link org.xrpl.xrpl4j.model.client.fees.FeeDrops}.
*/
@JsonProperty("ReserveBase")
UnsignedInteger reserveBase();
@Value.Derived
@JsonIgnore
default UnsignedInteger reserveBase() {
return UnsignedInteger.valueOf(reserveBaseDrops().value().longValue());
}

/**
* The base reserve, as an {@link XrpCurrencyAmount}.
*
* <p>This field will also be populated with the {@code ReserveBase} value from any {@link SetFee} transactions
* that occurred before the XRPFees amendment took effect.</p>
*
* @return An {@link XrpCurrencyAmount}.
*/
@JsonProperty("ReserveBaseDrops")
@JsonAlias("ReserveBase")
XrpCurrencyAmount reserveBaseDrops();

/**
* The incremental reserve, in drops.
*
* <p>This method only exists for historical purposes. When deserialized from a {@link SetFee} transaction from
* ledgers prior to the {@code XRPFees} amendment, this field will still be set based on
* {@link #reserveIncrementDrops()}.
*
* @return An {@link UnsignedInteger} incremental reserve in {@link org.xrpl.xrpl4j.model.client.fees.FeeDrops}.
*/
@JsonProperty("ReserveIncrement")
UnsignedInteger reserveIncrement();
@Value.Derived
@JsonIgnore
default UnsignedInteger reserveIncrement() {
return UnsignedInteger.valueOf(reserveIncrementDrops().value().longValue());
}

/**
* The incremental reserve, as an {@link XrpCurrencyAmount}.
*
* <p>This field will also be populated with the {@code ReserveIncrement} value from any {@link SetFee} transactions
* that occurred before the XRPFees amendment took effect.</p>
*
* @return An {@link XrpCurrencyAmount}.
*/
@JsonProperty("ReserveIncrementDrops")
@JsonAlias("ReserveIncrement")
XrpCurrencyAmount reserveIncrementDrops();

/**
* The index of the ledger version where this pseudo-transaction appears. This distinguishes the pseudo-transaction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,57 @@

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

import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.primitives.UnsignedInteger;
import com.google.common.primitives.UnsignedLong;
import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.xrpl.xrpl4j.model.AbstractJsonTest;
import org.xrpl.xrpl4j.model.client.common.LedgerIndex;

import java.util.Optional;

public class SetFeeTest {
/**
* Unit tests for {@link SetFee}.
*/
public class SetFeeTest extends AbstractJsonTest {

@Test
public void testConstructWithNoFeeUnits() {
SetFee setFee = SetFee.builder()
.account(Address.of("rrrrrrrrrrrrrrrrrrrrrhoLvTp"))
.fee(XrpCurrencyAmount.ofDrops(12))
.sequence(UnsignedInteger.valueOf(2470665))
.baseFeeDrops(XrpCurrencyAmount.ofDrops(10))
.reserveBaseDrops(XrpCurrencyAmount.ofDrops(20000000))
.reserveIncrementDrops(XrpCurrencyAmount.ofDrops(5000000))
.ledgerSequence(Optional.of(LedgerIndex.of(UnsignedInteger.valueOf(67850752))))
.build();

assertThat(setFee.transactionType()).isEqualTo(TransactionType.SET_FEE);
assertThat(setFee.account()).isEqualTo(Address.of("rrrrrrrrrrrrrrrrrrrrrhoLvTp"));
assertThat(setFee.fee().value()).isEqualTo(UnsignedLong.valueOf(12));
assertThat(setFee.sequence()).isEqualTo(UnsignedInteger.valueOf(2470665));
assertThat(setFee.ledgerSequence()).isNotEmpty().get().isEqualTo(LedgerIndex.of(UnsignedInteger.valueOf(67850752)));
assertThat(setFee.baseFee()).isEqualTo("a");
assertThat(setFee.baseFeeDrops()).isEqualTo(XrpCurrencyAmount.ofDrops(10));
assertThat(setFee.referenceFeeUnits()).isEmpty();
assertThat(setFee.reserveIncrement()).isEqualTo(UnsignedInteger.valueOf(5000000));
assertThat(setFee.reserveIncrementDrops()).isEqualTo(XrpCurrencyAmount.ofDrops(5000000));
assertThat(setFee.reserveBase()).isEqualTo(UnsignedInteger.valueOf(20000000));
assertThat(setFee.reserveBaseDrops()).isEqualTo(XrpCurrencyAmount.ofDrops(20000000));
}

@Test
public void testBuilder() {
public void testConstructWithFeeUnits() {
SetFee setFee = SetFee.builder()
.account(Address.of("rrrrrrrrrrrrrrrrrrrrrhoLvTp"))
.fee(XrpCurrencyAmount.ofDrops(12))
.sequence(UnsignedInteger.valueOf(2470665))
.baseFee("000000000000000A")
.baseFeeDrops(XrpCurrencyAmount.ofDrops(10))
.reserveBaseDrops(XrpCurrencyAmount.ofDrops(20000000))
.reserveIncrementDrops(XrpCurrencyAmount.ofDrops(5000000))
.referenceFeeUnits(UnsignedInteger.valueOf(10))
.reserveBase(UnsignedInteger.valueOf(20000000))
.reserveIncrement(UnsignedInteger.valueOf(5000000))
.ledgerSequence(Optional.of(LedgerIndex.of(UnsignedInteger.valueOf(67850752))))
.build();

Expand All @@ -49,8 +81,78 @@ public void testBuilder() {
assertThat(setFee.fee().value()).isEqualTo(UnsignedLong.valueOf(12));
assertThat(setFee.sequence()).isEqualTo(UnsignedInteger.valueOf(2470665));
assertThat(setFee.ledgerSequence()).isNotEmpty().get().isEqualTo(LedgerIndex.of(UnsignedInteger.valueOf(67850752)));
assertThat(setFee.referenceFeeUnits()).isEqualTo(UnsignedInteger.valueOf(10));
assertThat(setFee.baseFee()).isEqualTo("a");
assertThat(setFee.baseFeeDrops()).isEqualTo(XrpCurrencyAmount.ofDrops(10));
assertThat(setFee.referenceFeeUnits()).isNotEmpty().get().isEqualTo(UnsignedInteger.valueOf(10));
assertThat(setFee.reserveIncrement()).isEqualTo(UnsignedInteger.valueOf(5000000));
assertThat(setFee.reserveIncrementDrops()).isEqualTo(XrpCurrencyAmount.ofDrops(5000000));
assertThat(setFee.reserveBase()).isEqualTo(UnsignedInteger.valueOf(20000000));
assertThat(setFee.reserveBaseDrops()).isEqualTo(XrpCurrencyAmount.ofDrops(20000000));
}

@Test
public void testDeserializePreXrpFeesTransaction() throws JsonProcessingException {
SetFee expected = SetFee.builder()
.account(Address.of("rrrrrrrrrrrrrrrrrrrrrhoLvTp"))
.fee(XrpCurrencyAmount.ofDrops(12))
.sequence(UnsignedInteger.valueOf(2470665))
.baseFeeDrops(XrpCurrencyAmount.ofDrops(10))
.referenceFeeUnits(UnsignedInteger.valueOf(10))
.reserveBaseDrops(XrpCurrencyAmount.ofDrops(20000000))
.reserveIncrementDrops(XrpCurrencyAmount.ofDrops(5000000))
.ledgerSequence(Optional.of(LedgerIndex.of(UnsignedInteger.valueOf(67850752))))
.build();

String json = "{" +
"\"Account\":\"rrrrrrrrrrrrrrrrrrrrrhoLvTp\"," +
"\"Fee\":\"12\"," +
"\"LedgerSequence\":67850752," +
"\"Sequence\":2470665," +
"\"SigningPubKey\":\"\"," +
"\"TransactionType\":\"SetFee\"," +
"\"ReserveIncrement\":5000000," +
"\"ReserveBase\":20000000," +
"\"ReferenceFeeUnits\":10," +
"\"BaseFee\":\"a\"}";

Transaction actual = objectMapper.readValue(json, Transaction.class);
assertThat(actual).isEqualTo(expected);

String reserialized = objectMapper.writeValueAsString(actual);
Transaction redeserialized = objectMapper.readValue(reserialized, Transaction.class);

assertThat(redeserialized).isEqualTo(expected);
}

@Test
public void testDeserializePostXrpFeesTransaction() throws JsonProcessingException {
SetFee expected = SetFee.builder()
.account(Address.of("rrrrrrrrrrrrrrrrrrrrrhoLvTp"))
.fee(XrpCurrencyAmount.ofDrops(0))
.sequence(UnsignedInteger.valueOf(0))
.baseFeeDrops(XrpCurrencyAmount.ofDrops(10))
.reserveBaseDrops(XrpCurrencyAmount.ofDrops(10000000))
.reserveIncrementDrops(XrpCurrencyAmount.ofDrops(2000000))
.ledgerSequence(Optional.of(LedgerIndex.of(UnsignedInteger.valueOf(66462465))))
.build();

String json = "{\n" +
" \"Account\": \"rrrrrrrrrrrrrrrrrrrrrhoLvTp\",\n" +
" \"BaseFeeDrops\": \"10\",\n" +
" \"Fee\": \"0\",\n" +
" \"LedgerSequence\": 66462465,\n" +
" \"ReserveBaseDrops\": \"10000000\",\n" +
" \"ReserveIncrementDrops\": \"2000000\",\n" +
" \"Sequence\": 0,\n" +
" \"SigningPubKey\": \"\",\n" +
" \"TransactionType\": \"SetFee\"}";

Transaction actual = objectMapper.readValue(json, Transaction.class);
assertThat(actual).isEqualTo(expected);

String reserialized = objectMapper.writeValueAsString(actual);
Transaction redeserialized = objectMapper.readValue(reserialized, Transaction.class);

assertThat(redeserialized).isEqualTo(expected);
}
}
Loading

0 comments on commit 9294a84

Please sign in to comment.