Не работающая версия в странном состоянии
This commit is contained in:
AidarKC 2025-12-23 11:32:26 +03:00
parent 935ffecbb0
commit 03b6ff3c32
4 changed files with 52 additions and 1507 deletions

View File

@ -3,12 +3,6 @@ package blockchain.body;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
/**
* BodyRecordParser_new общий фабричный парсер body для нового формата.
*
* Правило совместимости (строгое):
* - если (type, version) неизвестны кидаем IllegalArgumentException
*/
public final class BodyRecordParser { public final class BodyRecordParser {
private BodyRecordParser() {} private BodyRecordParser() {}
@ -21,7 +15,6 @@ public final class BodyRecordParser {
short type = bb.getShort(); short type = bb.getShort();
short ver = bb.getShort(); short ver = bb.getShort();
// Строгое сопоставление type+version класс
int key = ((type & 0xFFFF) << 16) | (ver & 0xFFFF); int key = ((type & 0xFFFF) << 16) | (ver & 0xFFFF);
return switch (key) { return switch (key) {

View File

@ -3,27 +3,17 @@ package blockchain.body;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
/** /**
* HeaderBody_new type=0, version=1. * HeaderBody type=0, version=1.
* *
* Полный bodyBytes: * Полный bodyBytes:
* [2] type=0 * [2] type=0
* [2] version=1 * [2] version=1
* [payload...]
*
* Payload (как у текущего HeaderBody):
* [8] tag ASCII "SHiNE001" * [8] tag ASCII "SHiNE001"
* [8] blockchainId (long BE)
* [1] loginLength=N (uint8) * [1] loginLength=N (uint8)
* [N] userLogin UTF-8 * [N] login UTF-8
* [4] blockchainType (int BE) (резерв)
* [4] blockchainNumber (int BE) (резерв)
* [2] versionUserBch (short BE) (резерв)
* [8] prevUserBchId (long BE) (резерв)
* [32] publicKey32 (raw)
*/ */
public final class HeaderBody implements BodyRecord { public final class HeaderBody implements BodyRecord {
@ -31,32 +21,22 @@ public final class HeaderBody implements BodyRecord {
public static final short VER = 1; public static final short VER = 1;
public static final String TAG = "SHiNE001"; public static final String TAG = "SHiNE001";
public static final int PUBKEY_LEN = 32;
public final String tag; // "SHiNE001" public final String tag; // "SHiNE001"
public final long blockchainId; public final String login;
public final String userLogin;
public final int blockchainType;
public final int blockchainNumber;
public final short versionUserBch;
public final long prevUserBchId;
public final byte[] publicKey32;
/** /** Десериализация из полного bodyBytes (включая type/version). */
* Десериализация из полного bodyBytes (ВКЛЮЧАЯ первые 4 байта type/version).
*/
public HeaderBody(byte[] bodyBytes) { public HeaderBody(byte[] bodyBytes) {
Objects.requireNonNull(bodyBytes, "bodyBytes == null"); Objects.requireNonNull(bodyBytes, "bodyBytes == null");
if (bodyBytes.length < 4) throw new IllegalArgumentException("HeaderBody_new too short"); if (bodyBytes.length < 4) throw new IllegalArgumentException("HeaderBody too short (<4)");
ByteBuffer bb = ByteBuffer.wrap(bodyBytes).order(ByteOrder.BIG_ENDIAN); ByteBuffer bb = ByteBuffer.wrap(bodyBytes).order(ByteOrder.BIG_ENDIAN);
short type = bb.getShort(); short type = bb.getShort();
short ver = bb.getShort(); short ver = bb.getShort();
if (type != TYPE || ver != VER) if (type != TYPE || ver != VER)
throw new IllegalArgumentException("Not HeaderBody_new: type=" + type + " ver=" + ver); throw new IllegalArgumentException("Not HeaderBody: type=" + type + " ver=" + ver);
// Теперь bb стоит на payload if (bb.remaining() < 8 + 1)
if (bb.remaining() < 8 + 8 + 1 + 4 + 4 + 2 + 8 + 32)
throw new IllegalArgumentException("Header payload too short"); throw new IllegalArgumentException("Header payload too short");
byte[] tagBytes = new byte[8]; byte[] tagBytes = new byte[8];
@ -65,49 +45,20 @@ public final class HeaderBody implements BodyRecord {
if (!TAG.equals(t)) throw new IllegalArgumentException("Bad tag: " + t); if (!TAG.equals(t)) throw new IllegalArgumentException("Bad tag: " + t);
this.tag = t; this.tag = t;
this.blockchainId = bb.getLong();
int loginLen = Byte.toUnsignedInt(bb.get()); int loginLen = Byte.toUnsignedInt(bb.get());
if (loginLen <= 0 || bb.remaining() < loginLen + 4 + 4 + 2 + 8 + 32) if (loginLen <= 0 || bb.remaining() < loginLen)
throw new IllegalArgumentException("Bad login length"); throw new IllegalArgumentException("Bad login length");
byte[] loginBytes = new byte[loginLen]; byte[] loginBytes = new byte[loginLen];
bb.get(loginBytes); bb.get(loginBytes);
this.userLogin = new String(loginBytes, StandardCharsets.UTF_8); this.login = new String(loginBytes, StandardCharsets.UTF_8);
this.blockchainType = bb.getInt();
this.blockchainNumber = bb.getInt();
this.versionUserBch = bb.getShort();
this.prevUserBchId = bb.getLong();
this.publicKey32 = new byte[PUBKEY_LEN];
bb.get(this.publicKey32);
} }
/** /** Создание “вручную” (для генерации первого блока). */
* Создание вручную (для генерации первого блока). public HeaderBody(String login) {
*/ Objects.requireNonNull(login, "login == null");
public HeaderBody(long blockchainId,
String userLogin,
int blockchainType,
int blockchainNumber,
short versionUserBch,
long prevUserBchId,
byte[] publicKey32) {
Objects.requireNonNull(userLogin, "userLogin == null");
Objects.requireNonNull(publicKey32, "publicKey32 == null");
if (publicKey32.length != PUBKEY_LEN)
throw new IllegalArgumentException("publicKey32 must be 32 bytes");
this.tag = TAG; this.tag = TAG;
this.blockchainId = blockchainId; this.login = login;
this.userLogin = userLogin;
this.blockchainType = blockchainType;
this.blockchainNumber = blockchainNumber;
this.versionUserBch = versionUserBch;
this.prevUserBchId = prevUserBchId;
this.publicKey32 = Arrays.copyOf(publicKey32, PUBKEY_LEN);
} }
@Override public short type() { return TYPE; } @Override public short type() { return TYPE; }
@ -115,40 +66,29 @@ public final class HeaderBody implements BodyRecord {
@Override @Override
public HeaderBody check() { public HeaderBody check() {
if (userLogin == null || userLogin.isBlank()) if (login == null || login.isBlank())
throw new IllegalArgumentException("Login is blank"); throw new IllegalArgumentException("Login is blank");
if (!userLogin.matches("^[A-Za-z0-9_]+$")) if (!login.matches("^[A-Za-z0-9_]+$"))
throw new IllegalArgumentException("Login must match ^[A-Za-z0-9_]+$"); throw new IllegalArgumentException("Login must match ^[A-Za-z0-9_]+$");
if (publicKey32 == null || publicKey32.length != PUBKEY_LEN)
throw new IllegalArgumentException("publicKey32 must be 32 bytes");
return this; return this;
} }
@Override @Override
public byte[] toBytes() { public byte[] toBytes() {
byte[] loginUtf8 = userLogin.getBytes(StandardCharsets.UTF_8); byte[] loginUtf8 = login.getBytes(StandardCharsets.UTF_8);
if (loginUtf8.length > 255) if (loginUtf8.length > 255)
throw new IllegalArgumentException("Login too long (>255 bytes)"); throw new IllegalArgumentException("Login too long (>255 bytes)");
int payloadCap = 8 + 8 + 1 + loginUtf8.length + 4 + 4 + 2 + 8 + 32; int cap = 4 + 8 + 1 + loginUtf8.length;
int cap = 4 + payloadCap;
ByteBuffer bb = ByteBuffer.allocate(cap).order(ByteOrder.BIG_ENDIAN); ByteBuffer bb = ByteBuffer.allocate(cap).order(ByteOrder.BIG_ENDIAN);
// [type/version]
bb.putShort(TYPE); bb.putShort(TYPE);
bb.putShort(VER); bb.putShort(VER);
// payload
bb.put(TAG.getBytes(StandardCharsets.US_ASCII)); // [8] bb.put(TAG.getBytes(StandardCharsets.US_ASCII)); // [8]
bb.putLong(blockchainId); // [8]
bb.put((byte) loginUtf8.length); // [1] bb.put((byte) loginUtf8.length); // [1]
bb.put(loginUtf8); // [N] bb.put(loginUtf8); // [N]
bb.putInt(blockchainType); // [4]
bb.putInt(blockchainNumber); // [4]
bb.putShort(versionUserBch); // [2]
bb.putLong(prevUserBchId); // [8]
bb.put(publicKey32); // [32]
return bb.array(); return bb.array();
} }

View File

@ -7,17 +7,6 @@ import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Objects; import java.util.Objects;
/**
* TextBody_new type=1, version=1.
*
* Полный bodyBytes:
* [2] type=1
* [2] version=1
* [payload...]
*
* Payload:
* UTF-8 bytes (N>0)
*/
public final class TextBody implements BodyRecord { public final class TextBody implements BodyRecord {
public static final short TYPE = 1; public static final short TYPE = 1;
@ -25,22 +14,20 @@ public final class TextBody implements BodyRecord {
public final String message; public final String message;
/** Десериализация из полного bodyBytes (включая type/version). */
public TextBody(byte[] bodyBytes) { public TextBody(byte[] bodyBytes) {
Objects.requireNonNull(bodyBytes, "bodyBytes == null"); Objects.requireNonNull(bodyBytes, "bodyBytes == null");
if (bodyBytes.length < 5) // минимум: 4 байта type/ver + 1 байт текста if (bodyBytes.length < 5)
throw new IllegalArgumentException("TextBody_new too short"); throw new IllegalArgumentException("TextBody too short");
ByteBuffer bb = ByteBuffer.wrap(bodyBytes).order(ByteOrder.BIG_ENDIAN); ByteBuffer bb = ByteBuffer.wrap(bodyBytes).order(ByteOrder.BIG_ENDIAN);
short type = bb.getShort(); short type = bb.getShort();
short ver = bb.getShort(); short ver = bb.getShort();
if (type != TYPE || ver != VER) if (type != TYPE || ver != VER)
throw new IllegalArgumentException("Not TextBody_new: type=" + type + " ver=" + ver); throw new IllegalArgumentException("Not TextBody: type=" + type + " ver=" + ver);
byte[] payload = new byte[bb.remaining()]; byte[] payload = new byte[bb.remaining()];
bb.get(payload); bb.get(payload);
// строгая проверка UTF-8
var decoder = StandardCharsets.UTF_8 var decoder = StandardCharsets.UTF_8
.newDecoder() .newDecoder()
.onMalformedInput(CodingErrorAction.REPORT) .onMalformedInput(CodingErrorAction.REPORT)
@ -56,7 +43,6 @@ public final class TextBody implements BodyRecord {
throw new IllegalArgumentException("Text message is blank"); throw new IllegalArgumentException("Text message is blank");
} }
/** Создание из строки. */
public TextBody(String message) { public TextBody(String message) {
Objects.requireNonNull(message, "message == null"); Objects.requireNonNull(message, "message == null");
if (message.isBlank()) if (message.isBlank())