Skip to content
Snippets Groups Projects
Commit e0e62d37 authored by mio's avatar mio
Browse files

Add get asset by universe index request and response handling to node

parent 7862c05c
No related branches found
No related tags found
No related merge requests found
Pipeline #1688060930 passed
Showing
with 152 additions and 6 deletions
......@@ -30,6 +30,7 @@ public enum MessageType {
RESPOND_CONTRACT_FUNCTION(43),
TRY_AGAIN(46),
REQUEST_ASSETS(52),
RESPOND_ASSETS(53),
PROCESS_SPECIAL_COMMAND(255),
UNKNOWN(Byte.MIN_VALUE);
......
......@@ -12,7 +12,6 @@ public class RequestAssetsByIndex extends RequestAssets {
private static final int SIZE = 112;
private final short flags; // unsigned short
private final int universeIndex; // unsigned int
@Override
......@@ -20,7 +19,7 @@ public class RequestAssetsByIndex extends RequestAssets {
return ByteBuffer.allocate(SIZE)
.order(ByteOrder.LITTLE_ENDIAN)
.putShort(REQUEST_BY_UNIVERSE_INDEX.asShort())
.putShort(flags)
.putShort((short) 0) // no flags
.putInt(universeIndex)
.array();
}
......
package at.qubic.api.domain.std.response;
import at.qubic.api.util.AssetUtil;
import at.qubic.api.util.BufferUtil;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import at.qubic.api.util.AssetUtil;
import at.qubic.api.util.BufferUtil;
import java.nio.ByteBuffer;
import java.util.Arrays;
......
package at.qubic.api.domain.std.response;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@Builder
@Getter
@EqualsAndHashCode
@ToString
public class RespondIssuedAssets {
private final AssetIssuance asset;
private final int tick; // unsigned int - 4 bytes
private final int universeIndex; // unsigned int - 4 bytes
public static RespondIssuedAssets fromBytes(byte[] bytes) {
ByteBuffer buf = ByteBuffer.wrap(bytes);
buf.order(ByteOrder.LITTLE_ENDIAN);
RespondIssuedAssets assets = RespondIssuedAssets.builder()
.asset(AssetIssuance.fromByteBuffer(buf))
.tick(buf.getInt())
.universeIndex(buf.getInt())
.build();
assert buf.remaining() == 0 : buf.remaining();
return assets;
}
}
......@@ -146,6 +146,14 @@ public class Node {
.map(message -> SignedTransaction.fromBytes(message.getPayload()));
}
public Mono<RespondIssuedAssets> getAssetByUniverseIndex(int index) {
// attention: node returns a list but by index there should only be one
final Mono<QubicRequest> request = Mono.just(RequestAssetsByIndex.builder().universeIndex(index).build());
return sendAndReceiveNext(request, MessageType.RESPOND_ASSETS)
.map(response -> RespondIssuedAssets.fromBytes(response.getPayload()))
.doOnNext(r -> log.debug("[{}]: {}", name, r));
}
/**
* Get all owned assets of an entity.
* @param publicKey The public key of the entity to get the owned assets of.
......
......@@ -22,6 +22,20 @@ public class AssetUtil {
*/
public static byte[] nameTo8Bytes(String name) {
byte[] assetName = new byte[8];
return toNameBytes(name, assetName);
}
/**
* Return input string as byte[8]. The last byte is zero (null terminated string).
* @param name The input string. Shouldn't be more than 7 bytes. Other bytes are ignored.
* @return The name as null terminated byte array of length 8.
*/
public static byte[] nameTo7Bytes(String name) {
byte[] assetName = new byte[7];
return toNameBytes(name, assetName);
}
private static byte[] toNameBytes(String name, byte[] assetName) {
for (int i = 0; i < Math.min(StringUtils.length(name), 7); i++) {
assetName[i] = (byte) name.charAt(i);
}
......@@ -36,10 +50,26 @@ public class AssetUtil {
*/
public static byte[] unitOfMeasurementTo8Bytes(String unitOfMeasurement) {
byte[] units = new byte[8];
toUnitOfMeasurementBytes(unitOfMeasurement, units);
return units;
}
/**
* Converts a unit of measurement string to bytes. Letters are mapped to their corresponding byte value.
* "00000020" is converted to byte {0,0,0,0,0,0,2} for example.
* @param unitOfMeasurement String describing the units of measurement for an asset.
* @return The units of measurement in byte array format.
*/
public static byte[] unitOfMeasurementTo7Bytes(String unitOfMeasurement) {
byte[] units = new byte[7];
toUnitOfMeasurementBytes(unitOfMeasurement, units);
return units;
}
private static void toUnitOfMeasurementBytes(String unitOfMeasurement, byte[] units) {
for (int i = 0; i < Math.min(7, StringUtils.length(unitOfMeasurement)); i++) {
units[i] = (byte) (unitOfMeasurement.charAt(i) - 48);
}
return units;
}
/**
......
package at.qubic.api.network;
import at.qubic.api.domain.std.response.AssetIssuance;
import at.qubic.api.exception.InvalidResponseException;
import at.qubic.api.util.AssetUtil;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Hex;
import org.awaitility.Awaitility;
......@@ -308,6 +310,30 @@ class NodeIT {
.verifyComplete();
}
@Test
void getAssetByUniverseIndex() {
final QubicMessage exchangePublicPeers = getExchangePublicPeers();
byte[] bids = TestFileUtil.loadHexFile("/testdata/domain/respond-assets-by-universe-index.hex");
tcpServer.respond(exchangePublicPeers.toBytes(), bids);
AssetIssuance expectedAssetIssuance = AssetIssuance.builder()
.name(AssetUtil.nameTo7Bytes("RANDOM"))
.publicKey(new byte[32])
.type((byte) 1)
.numberOfDecimalPlaces((byte) 0)
.unitOfMeasurement(AssetUtil.unitOfMeasurementTo7Bytes("0000000"))
.build();
StepVerifier.create(node.getAssetByUniverseIndex(3))
.assertNext(ria -> {
assertThat(ria.getAsset()).isEqualTo(expectedAssetIssuance);
assertThat(ria.getUniverseIndex()).isEqualTo(3);
assertThat(ria.getTick()).isEqualTo(20117803);
})
.verifyComplete();
}
@Test
void broadcastTransaction() {
TcpTestServer.ExchangeThread exchange = this.tcpServer.respond(getExchangePublicPeers().toBytes()); // dummy we only send
......
package at.qubic.api.network;
import at.qubic.api.domain.qearn.request.*;
import at.qubic.api.domain.std.response.AssetIssuance;
import at.qubic.api.util.AssetUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
......@@ -201,7 +203,7 @@ class NodeSIT {
}
@Test
public void getQearnBurnedAndBoostedStatsForEpoch() {
void getQearnBurnedAndBoostedStatsForEpoch() {
GetBurnedAndBoostedStatsForEpoch request = GetBurnedAndBoostedStatsForEpoch.builder().build();
StepVerifier.create(nodes.getNode().flatMap(n -> n.getQearnBurnedAndBoostedStatsForEpoch(request))
.doOnNext(stats -> log.info("Stats: {} {} {} {}", stats,
......@@ -212,4 +214,23 @@ class NodeSIT {
.verifyComplete();
}
@Test
public void getAssetByUniverseIndex() {
AssetIssuance expectedAssetIssuance = AssetIssuance.builder()
.name(AssetUtil.nameTo7Bytes("RANDOM"))
.publicKey(new byte[32])
.type((byte) 1)
.numberOfDecimalPlaces((byte) 0)
.unitOfMeasurement(AssetUtil.unitOfMeasurementTo7Bytes("0000000"))
.build();
StepVerifier.create(nodes.getNode().flatMap(n -> n.getAssetByUniverseIndex(3)))
.assertNext(ria -> {
assertThat(ria.getAsset()).isEqualTo(expectedAssetIssuance);
assertThat(ria.getUniverseIndex()).isEqualTo(3);
assertThat(ria.getTick()).isPositive();
})
.verifyComplete();
}
}
\ No newline at end of file
package at.qubic.api.network;
import at.qubic.api.domain.std.response.AssetIssuance;
import at.qubic.api.util.AssetUtil;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.junit.jupiter.api.Test;
import at.qubic.api.domain.MessageType;
import at.qubic.api.domain.std.SignedTransaction;
......@@ -229,6 +233,30 @@ class NodeTest {
.verifyComplete();
}
@Test
void getAssetByUniverseIndex() throws DecoderException {
byte[] respondAssetsPayload = Hex.decodeHex("00000000000000000000000000000000000000000000000000000000000000000152414e444f4d000000000000000000f3fa320103000000");
mockConnection(mockInbound(MessageType.RESPOND_ASSETS, ByteBuffer.wrap(respondAssetsPayload)), mockOutbound());
AssetIssuance expectedAssetIssuance = AssetIssuance.builder()
.name(AssetUtil.nameTo7Bytes("RANDOM"))
.publicKey(new byte[32])
.type((byte) 1)
.numberOfDecimalPlaces((byte) 0)
.unitOfMeasurement(AssetUtil.unitOfMeasurementTo7Bytes("0000000"))
.build();
StepVerifier.create(node.getAssetByUniverseIndex(3))
.assertNext(ria -> {
assertThat(ria.getAsset()).isEqualTo(expectedAssetIssuance);
assertThat(ria.getUniverseIndex()).isEqualTo(3);
assertThat(ria.getTick()).isEqualTo(20118259);
})
.verifyComplete();
}
private Node createNode() {
TcpClientConfig config = mock();
when(tcpClient.configuration()).thenReturn(config);
......
18000000612cd88b2e11656d2d98a012d5a34086b2ed3ad14000003568b0069a00000000000000000000000000000000000000000000000000000000000000000152414e444f4d0000000000000000002bf9320103000000
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment