Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/maven/io.github.openfeign-feign-b…
Browse files Browse the repository at this point in the history
…om-13.2.1
  • Loading branch information
sappenin authored Dec 3, 2024
2 parents 792cbdd + 9cc99a3 commit 47fc96c
Show file tree
Hide file tree
Showing 48 changed files with 26,388 additions and 248 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ and address generation, transaction serialization and signing, provides useful J
- Example usage can be found in the `xrpl4j-integration-tests`
module [here](https://github.com/XRPLF/xrpl4j/tree/main/xrpl4j-integration-tests/src/test/java/org/xrpl/xrpl4j/tests).

## Usage
## Usage

### Requirements

Expand All @@ -33,7 +33,7 @@ current [BOM](https://howtodoinjava.com/maven/maven-bom-bill-of-materials-depend
<dependency>
<groupId>org.xrpl</groupId>
<artifactId>xrpl4j-bom</artifactId>
<version>3.3.0</version>
<version>4.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down Expand Up @@ -225,7 +225,7 @@ canonical JSON encoding). Read more about each here:

Xrpl4j is structured as a Maven multi-module project, with the following modules:

- **xrpl4j-core**: [![javadoc](https://javadoc.io/badge2/org.xrpl/xrpl4j-binary-codec/javadoc.svg?color=blue)](https://javadoc.io/doc/org.xrpl/xrpl4j-binary-codec)
- **xrpl4j-core**: [![javadoc](https://javadoc.io/badge2/org.xrpl/xrpl4j-core/javadoc.svg?color=blue)](https://javadoc.io/doc/org.xrpl/xrpl4j-core)
- Provides core primitives like seeds, public/private keys definitions (supports secp256k1 and ed25519 key types
and signing algorithms), signature interfaces, address and binary codecs etc. Also provides Java objects which model XRP Ledger objects,
as well as request parameters and response results for the `rippled` websocket and JSON RPC APIs.
Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.75</version>
<version>1.78.1</version>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
Expand Down Expand Up @@ -293,7 +293,7 @@
<jackson.version>2.14.2</jackson.version>
<feign.version>13.2.1</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 @@ -27,6 +27,7 @@
import com.google.common.annotations.Beta;
import feign.Feign;
import feign.Headers;
import feign.Request.Options;
import feign.RequestLine;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
Expand Down Expand Up @@ -71,18 +72,34 @@ public interface JsonRpcClient {
/**
* Constructs a new client for the given url.
*
* @param rippledUrl url for the faucet server.
* @param rippledUrl The {@link HttpUrl} of the node to connect to.
*
* @return A {@link JsonRpcClient} that can make request to {@code rippledUrl}
*/
static JsonRpcClient construct(final HttpUrl rippledUrl) {
Objects.requireNonNull(rippledUrl);

return construct(rippledUrl, new Options());
}

/**
* Constructs a new client for the given url with the given client options.
*
* @param rippledUrl The {@link HttpUrl} of the node to connect to.
* @param options An {@link Options}.
*
* @return A {@link JsonRpcClient}.
*/
static JsonRpcClient construct(HttpUrl rippledUrl, Options options) {
Objects.requireNonNull(rippledUrl);
Objects.requireNonNull(options);

return Feign.builder()
.encoder(new JacksonEncoder(objectMapper))
// rate limiting will return a 503 status that can be retried
.errorDecoder(new RetryStatusDecoder(RETRY_INTERVAL, SERVICE_UNAVAILABLE_STATUS))
.decode404()
.options(options)
.decoder(new OptionalDecoder(new JacksonDecoder(objectMapper)))
.target(JsonRpcClient.class, rippledUrl.toString());
}
Expand Down
29 changes: 29 additions & 0 deletions xrpl4j-client/src/main/java/org/xrpl/xrpl4j/client/XrplClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import com.google.common.collect.Range;
import com.google.common.primitives.UnsignedInteger;
import com.google.common.primitives.UnsignedLong;
import feign.Request;
import feign.Request.Options;
import okhttp3.HttpUrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -99,8 +101,10 @@
import org.xrpl.xrpl4j.model.transactions.Transaction;
import org.xrpl.xrpl4j.model.transactions.TransactionMetadata;

import java.time.Duration;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
* <p>A client which wraps a rippled network client and is responsible for higher order functionality such as signing
Expand All @@ -127,6 +131,31 @@ public XrplClient(final HttpUrl rippledUrl) {
this(JsonRpcClient.construct(rippledUrl));
}

/**
* Public constructor that allows for configuration of connect and read timeouts.
*
* <p>Note that any {@link Duration} passed in that is less than one millisecond will result in the actual timeout
* being zero milliseconds. It is therefore advised to never set {@code connectTimeout} or {@code readTimeout} to a
* {@link Duration} less than one millisecond.
*
* @param rippledUrl The {@link HttpUrl} of the node to connect to.
* @param connectTimeout A {@link Duration} indicating the client's connect timeout.
* @param readTimeout A {@link Duration} indicating the client's read timeout.
*/
public XrplClient(
HttpUrl rippledUrl,
Duration connectTimeout,
Duration readTimeout
) {
this(
JsonRpcClient.construct(
rippledUrl,
new Options(connectTimeout.toMillis(), TimeUnit.MILLISECONDS, readTimeout.toMillis(), TimeUnit.MILLISECONDS,
true)
)
);
}

/**
* Required-args constructor (exists for testing purposes only).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,11 @@
import org.xrpl.xrpl4j.model.transactions.XrpCurrencyAmount;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
Expand Down Expand Up @@ -599,6 +601,18 @@ public void getXrplClientTest() {
assertThat(new XrplClient(rippledUrl) instanceof JsonRpcClient).isFalse();
}

@Test
void createXrplClientWithDurationTimeouts() {
HttpUrl rippledUrl = HttpUrl.parse("https://s.altnet.rippletest.net:51234");
XrplClient client = new XrplClient(
rippledUrl,
Duration.ofSeconds(1),
Duration.ofMinutes(2)
);

assertThat(client).isInstanceOf(XrplClient.class);
}

@Test
public void submitSingleSignedTransaction() {
BcSignatureService bcSignatureService = new BcSignatureService();
Expand Down
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 @@ -31,6 +31,7 @@
import org.xrpl.xrpl4j.codec.binary.BinaryCodecObjectMapperFactory;
import org.xrpl.xrpl4j.codec.binary.math.MathUtils;
import org.xrpl.xrpl4j.codec.binary.serdes.BinaryParser;
import org.xrpl.xrpl4j.model.immutables.FluentCompareTo;

import java.math.BigDecimal;
import java.math.BigInteger;
Expand All @@ -41,7 +42,9 @@
class AmountType extends SerializedType<AmountType> {

public static final BigDecimal MAX_DROPS = new BigDecimal("1e17");
public static final BigDecimal MIN_DROPS = new BigDecimal("-1e17");
public static final BigDecimal MIN_XRP = new BigDecimal("1e-6");
public static final BigDecimal MAX_NEGATIVE_XRP = new BigDecimal("-1e-6");

public static final String DEFAULT_AMOUNT_HEX = "4000000000000000";
public static final String ZERO_CURRENCY_AMOUNT_HEX = "8000000000000000";
Expand All @@ -50,18 +53,18 @@ class AmountType extends SerializedType<AmountType> {
private static final int MAX_IOU_PRECISION = 16;

/**
* According to <a href=https://xrpl.org/currency-formats.html#currency-formats>xrpl.org</a>,
* the minimum token value exponent is -96. However, because the value field is converted from a {@link String}
* to a {@link BigDecimal} when encoding/decoding, and because {@link BigDecimal} defaults to using single
* digit number, the minimum exponent in this context is -96 + 15, as XRPL amounts have a precision of 15 digits.
* According to <a href=https://xrpl.org/currency-formats.html#currency-formats>xrpl.org</a>, the minimum token value
* exponent is -96. However, because the value field is converted from a {@link String} to a {@link BigDecimal} when
* encoding/decoding, and because {@link BigDecimal} defaults to using single digit number, the minimum exponent in
* this context is -96 + 15, as XRPL amounts have a precision of 15 digits.
*/
private static final int MIN_IOU_EXPONENT = -81;

/**
* According to <a href=https://xrpl.org/currency-formats.html#currency-formats>xrpl.org</a>,
* the maximum token value exponent is 80. However, because the value field is converted from a {@link String}
* to a {@link BigDecimal} when encoding/decoding, and because {@link BigDecimal} defaults to using single
* digit number, the maximum exponent in this context is 80 + 15, as XRPL amounts have a precision of 15 digits.
* According to <a href=https://xrpl.org/currency-formats.html#currency-formats>xrpl.org</a>, the maximum token value
* exponent is 80. However, because the value field is converted from a {@link String} to a {@link BigDecimal} when
* encoding/decoding, and because {@link BigDecimal} defaults to using single digit number, the maximum exponent in
* this context is 80 + 15, as XRPL amounts have a precision of 15 digits.
*/
private static final int MAX_IOU_EXPONENT = 95;

Expand All @@ -88,8 +91,15 @@ private static void assertXrpIsValid(String amount) {
}
BigDecimal value = new BigDecimal(amount);
if (!value.equals(BigDecimal.ZERO)) {
if (value.compareTo(MIN_XRP) < 0 || value.compareTo(MAX_DROPS) > 0) {
throw new IllegalArgumentException(amount + " is an illegal amount");
final FluentCompareTo<BigDecimal> fluentValue = FluentCompareTo.is(value);
if (value.signum() < 0) { // `value` is negative
if (fluentValue.greaterThan(MAX_NEGATIVE_XRP) || fluentValue.lessThan(MIN_DROPS)) {
throw new IllegalArgumentException(String.format("%s is an illegal amount", amount));
}
} else { // `value` is positive
if (fluentValue.lessThan(MIN_XRP) || fluentValue.greaterThan(MAX_DROPS)) {
throw new IllegalArgumentException(String.format("%s is an illegal amount", amount));
}
}
}
}
Expand Down Expand Up @@ -142,14 +152,19 @@ public AmountType fromJson(JsonNode value) throws JsonProcessingException {
if (value.isValueNode()) {
assertXrpIsValid(value.asText());

UnsignedByteArray number = UnsignedByteArray.fromHex(
final boolean isValueNegative = value.asText().startsWith("-");
final UnsignedByteArray number = UnsignedByteArray.fromHex(
ByteUtils.padded(
UnsignedLong.valueOf(value.asText()).toString(16),
64 / 4
UnsignedLong
.valueOf(isValueNegative ? value.asText().substring(1) : value.asText())
.toString(16),
16 // <-- 64 / 4
)
);
byte[] rawBytes = number.toByteArray();
rawBytes[0] |= 0x40;
final byte[] rawBytes = number.toByteArray();
if (!isValueNegative) {
rawBytes[0] |= 0x40;
}
return new AmountType(UnsignedByteArray.of(rawBytes));
}

Expand All @@ -172,7 +187,7 @@ public AmountType fromJson(JsonNode value) throws JsonProcessingException {
private UnsignedByteArray getAmountBytes(BigDecimal number) {
BigInteger paddedNumber = MathUtils.toPaddedBigInteger(number, 16);
byte[] amountBytes = ByteUtils.toByteArray(paddedNumber, 8);
amountBytes[0] |= 0x80;
amountBytes[0] |= (byte) 0x80;
if (number.compareTo(BigDecimal.ZERO) > 0) {
amountBytes[0] |= 0x40;
}
Expand All @@ -182,8 +197,8 @@ private UnsignedByteArray getAmountBytes(BigDecimal number) {
throw new IllegalArgumentException("exponent out of range");
}
UnsignedByte exponentByte = UnsignedByte.of(97 + exponent - 15);
amountBytes[0] |= exponentByte.asInt() >>> 2;
amountBytes[1] |= (exponentByte.asInt() & 0x03) << 6;
amountBytes[0] |= (byte) (exponentByte.asInt() >>> 2);
amountBytes[1] |= (byte) ((exponentByte.asInt() & 0x03) << 6);

return UnsignedByteArray.of(amountBytes);
}
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 @@ -239,6 +239,14 @@ default LedgerEntryType ledgerEntryType() {
@JsonProperty("AMMID")
Optional<Hash256> ammId();

/**
* An arbitrary 256-bit value that users can set.
*
* @return An {@link Optional} {@link String}.
*/
@JsonProperty("WalletLocator")
Optional<String> walletLocator();

/**
* The unique ID of this {@link AccountRootObject} ledger object.
*
Expand Down
Loading

0 comments on commit 47fc96c

Please sign in to comment.