SHiNE-server/shine-server-blockchain/src/main/java/blockchain/body/ReactionBody.java
AidarKC b6b50557a7 29 12 25
добавил toString для классов Body
2025-12-29 15:31:20 +03:00

146 lines
5.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package blockchain.body;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;
/**
* ReactionBody — type=2, version=1.
*
* Сериализация bodyBytes:
* [2] type=2
* [2] ver=1
* [4] reactionCode (int32)
* [1] toBlockchainNameLen (uint8)
* [N] toBlockchainName UTF-8
* [4] toBlockGlobalNumber (int32)
* [32] toBlockHash (raw 32 bytes)
*
* ЛИНИЯ:
* - строго lineIndex=2
*
* ВАЖНО:
* - Здесь мы НЕ проверяем, существует ли цель реакции (MVP правило).
*/
public final class ReactionBody implements BodyRecord {
public static final short TYPE = 2;
public static final short VER = 1;
public final int reactionCode;
public final String toBlockchainName;
public final int toBlockGlobalNumber;
public final byte[] toBlockHash32;
public ReactionBody(byte[] bodyBytes) {
Objects.requireNonNull(bodyBytes, "bodyBytes == null");
if (bodyBytes.length < 4 + 4 + 1 + 1 + 4 + 32) {
throw new IllegalArgumentException("ReactionBody too short");
}
ByteBuffer bb = ByteBuffer.wrap(bodyBytes).order(ByteOrder.BIG_ENDIAN);
short type = bb.getShort();
short ver = bb.getShort();
if (type != TYPE || ver != VER)
throw new IllegalArgumentException("Not ReactionBody: type=" + type + " ver=" + ver);
this.reactionCode = bb.getInt();
int nameLen = Byte.toUnsignedInt(bb.get());
if (nameLen <= 0) throw new IllegalArgumentException("toBlockchainNameLen is 0");
if (bb.remaining() < nameLen + 4 + 32) throw new IllegalArgumentException("ReactionBody payload too short");
byte[] nameBytes = new byte[nameLen];
bb.get(nameBytes);
this.toBlockchainName = new String(nameBytes, StandardCharsets.UTF_8);
this.toBlockGlobalNumber = bb.getInt();
this.toBlockHash32 = new byte[32];
bb.get(this.toBlockHash32);
}
public ReactionBody(int reactionCode, String toBlockchainName, int toBlockGlobalNumber, byte[] toBlockHash32) {
Objects.requireNonNull(toBlockchainName, "toBlockchainName == null");
Objects.requireNonNull(toBlockHash32, "toBlockHash32 == null");
if (toBlockchainName.isBlank()) throw new IllegalArgumentException("toBlockchainName is blank");
if (toBlockHash32.length != 32) throw new IllegalArgumentException("toBlockHash32 != 32");
this.reactionCode = reactionCode;
this.toBlockchainName = toBlockchainName;
this.toBlockGlobalNumber = toBlockGlobalNumber;
this.toBlockHash32 = Arrays.copyOf(toBlockHash32, 32);
}
@Override public short type() { return TYPE; }
@Override public short version() { return VER; }
@Override
public short expectedLineIndex() {
return 2;
}
@Override
public ReactionBody check() {
if (toBlockchainName == null || toBlockchainName.isBlank())
throw new IllegalArgumentException("toBlockchainName is blank");
if (toBlockGlobalNumber < 0)
throw new IllegalArgumentException("toBlockGlobalNumber < 0");
if (toBlockHash32 == null || toBlockHash32.length != 32)
throw new IllegalArgumentException("toBlockHash32 invalid");
return this;
}
@Override
public byte[] toBytes() {
byte[] nameBytes = toBlockchainName.getBytes(StandardCharsets.UTF_8);
if (nameBytes.length == 0 || nameBytes.length > 255)
throw new IllegalArgumentException("toBlockchainName utf8 len must be 1..255");
int cap = 4 + 4 + 1 + nameBytes.length + 4 + 32;
ByteBuffer bb = ByteBuffer.allocate(cap).order(ByteOrder.BIG_ENDIAN);
bb.putShort(TYPE);
bb.putShort(VER);
bb.putInt(reactionCode);
bb.put((byte) nameBytes.length);
bb.put(nameBytes);
bb.putInt(toBlockGlobalNumber);
bb.put(toBlockHash32);
return bb.array();
}
@Override
public String toString() {
return """
ReactionBody {
тип записи : REACTION (type=2, ver=1)
ожидаемая линия : 2
код реакции : %d
целевой блокчейн : "%s"
globalNumber цели : %d
hash цели (hex) : %s
}
""".formatted(
reactionCode,
toBlockchainName,
toBlockGlobalNumber,
toBlockHashHex()
);
}
public String toBlockHashHex() {
char[] HEX = "0123456789abcdef".toCharArray();
char[] out = new char[64];
for (int i = 0; i < 32; i++) {
int v = toBlockHash32[i] & 0xFF;
out[i * 2] = HEX[v >>> 4];
out[i * 2 + 1] = HEX[v & 0x0F];
}
return new String(out);
}
}