Сделал что бы в базу писался msgSubType и поля to (to login, toBlockchainName и т.д.)
This commit is contained in:
AidarKC 2026-01-02 20:15:59 +03:00
parent eef760d776
commit dd49c4de00
8 changed files with 129 additions and 22 deletions

View File

@ -0,0 +1,32 @@
package blockchain.body;
/**
* BodyToFields дополнительный интерфейс для body, которые "ссылаются" на цель (to-поля).
*
* Идея:
* - Не все body имеют "to".
* - Но для индексации и удобства запросов в БД мы хотим единообразно доставать:
* toLogin, toBchName, toBlockGlobalNumber, toBlockHashe
*
* Важно:
* - Все методы могут возвращать null.
* - toLogin может отсутствовать в самом формате body (например, ReactionBody, TextBody reply/repost),
* но в БД мы пишем toLogin "про запас".
* Поэтому writer может:
* - взять toLogin из body (если есть),
* - либо попытаться вычислить из toBchName.
*/
public interface BodyHasTarget {
/** login цели (nullable). */
String toLogin();
/** blockchainName цели (nullable). */
String toBchName();
/** globalNumber цели (nullable). */
Integer toBlockGlobalNumber();
/** hash цели в HEX(64) (nullable). */
String toBlockHashe();
}

View File

@ -42,7 +42,7 @@ import java.util.Objects;
* ЛИНИЯ: * ЛИНИЯ:
* - строго lineIndex=3 (выделяем отдельную линию под связи). * - строго lineIndex=3 (выделяем отдельную линию под связи).
*/ */
public final class ConnectionBody implements BodyRecord { public final class ConnectionBody implements BodyRecord, BodyHasTarget {
public static final short TYPE = 3; public static final short TYPE = 3;
public static final short VER = 1; public static final short VER = 1;
@ -279,4 +279,16 @@ public final class ConnectionBody implements BodyRecord {
} }
return new String(out); return new String(out);
} }
/* ===================================================================== */
/* ====================== BodyToFields контракт ========================= */
/* ===================================================================== */
@Override public String toLogin() { return toLogin; }
@Override public String toBchName() { return toBlockchainName; }
@Override public Integer toBlockGlobalNumber() { return toBlockGlobalNumber; }
@Override public String toBlockHashe() { return toBlockHashHex(); }
} }

View File

@ -31,7 +31,7 @@ import java.util.Objects;
* - Здесь мы НЕ проверяем, существует ли цель реакции. * - Здесь мы НЕ проверяем, существует ли цель реакции.
* - Мы проверяем только корректность формата и целостность полей. * - Мы проверяем только корректность формата и целостность полей.
*/ */
public final class ReactionBody implements BodyRecord { public final class ReactionBody implements BodyRecord, BodyHasTarget {
public static final short TYPE = 2; public static final short TYPE = 2;
public static final short VER = 1; public static final short VER = 1;
@ -172,11 +172,11 @@ public final class ReactionBody implements BodyRecord {
hash цели (hex) : %s hash цели (hex) : %s
} }
""".formatted( """.formatted(
st, st,
toBlockchainName, toBlockchainName,
toBlockGlobalNumber, toBlockGlobalNumber,
toBlockHashHex() toBlockHashHex()
); );
} }
public String toBlockHashHex() { public String toBlockHashHex() {
@ -189,4 +189,17 @@ public final class ReactionBody implements BodyRecord {
} }
return new String(out); return new String(out);
} }
/* ===================================================================== */
/* ====================== BodyToFields контракт ========================= */
/* ===================================================================== */
/** В самом формате ReactionBody login цели не хранится => null. */
@Override public String toLogin() { return null; }
@Override public String toBchName() { return toBlockchainName; }
@Override public Integer toBlockGlobalNumber() { return toBlockGlobalNumber; }
@Override public String toBlockHashe() { return toBlockHashHex(); }
} }

View File

@ -41,7 +41,7 @@ import java.util.Objects;
* - для subType=NEW запрещены поля ссылки и запрещены любые лишние байты в хвосте * - для subType=NEW запрещены поля ссылки и запрещены любые лишние байты в хвосте
* - для subType=REPLY/REPOST хвост обязан быть ровно по формату и без мусора в конце * - для subType=REPLY/REPOST хвост обязан быть ровно по формату и без мусора в конце
*/ */
public final class TextBody implements BodyRecord { public final class TextBody implements BodyRecord, BodyHasTarget {
public static final short TYPE = 1; public static final short TYPE = 1;
public static final short VER = 1; public static final short VER = 1;
@ -219,8 +219,6 @@ public final class TextBody implements BodyRecord {
@Override public short type() { return TYPE; } @Override public short type() { return TYPE; }
@Override public short version() { return VER; } @Override public short version() { return VER; }
/** ✅ ВАЖНО: теперь BodyRecord требует subType() */
@Override public short subType() { return subType; } @Override public short subType() { return subType; }
@Override @Override
@ -363,4 +361,26 @@ public final class TextBody implements BodyRecord {
} }
return new String(out); return new String(out);
} }
/* ===================================================================== */
/* ====================== BodyToFields контракт ========================= */
/* ===================================================================== */
/** В формате TextBody login цели не хранится => null. */
@Override public String toLogin() { return null; }
@Override
public String toBchName() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockchainName : null;
}
@Override
public Integer toBlockGlobalNumber() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockGlobalNumber : null;
}
@Override
public String toBlockHashe() {
return (subType == SUB_REPLY || subType == SUB_REPOST) ? toBlockHashHex() : null;
}
} }

View File

@ -21,6 +21,10 @@ import java.sql.Statement;
* - ip_geo_cache * - ip_geo_cache
* - blockchain_state (MVP) * - blockchain_state (MVP)
* - blocks (login TEXT, bchName TEXT, PK убран) * - blocks (login TEXT, bchName TEXT, PK убран)
*
* ОБНОВЛЕНО:
* - blocks: добавлено поле msgSubType (сразу после msgType)
* - blocks: поля to* остаются nullable
*/ */
public class DatabaseInitializer { public class DatabaseInitializer {
@ -195,7 +199,7 @@ public class DatabaseInitializer {
ON blockchain_state (updated_at_ms); ON blockchain_state (updated_at_ms);
"""); """);
// 6. blocks PK удалён полностью, to* теперь nullable // 6. blocks PK удалён полностью, to* теперь nullable, добавлен msgSubType
st.executeUpdate(""" st.executeUpdate("""
CREATE TABLE IF NOT EXISTS blocks ( CREATE TABLE IF NOT EXISTS blocks (
login TEXT NOT NULL, login TEXT NOT NULL,
@ -208,6 +212,7 @@ public class DatabaseInitializer {
blockLinePreHashe TEXT NOT NULL, blockLinePreHashe TEXT NOT NULL,
msgType INTEGER NOT NULL, msgType INTEGER NOT NULL,
msgSubType INTEGER NOT NULL,
blockByte BLOB, blockByte BLOB,

View File

@ -45,12 +45,13 @@ public final class BlocksDAO {
blockLineNumber, blockLineNumber,
blockLinePreHashe, blockLinePreHashe,
msgType, msgType,
msgSubType,
blockByte, blockByte,
to_login, to_login,
toBchName, toBchName,
toBlockGlobalNumber, toBlockGlobalNumber,
toBlockHashe toBlockHashe
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""; """;
try (PreparedStatement ps = c.prepareStatement(sql)) { try (PreparedStatement ps = c.prepareStatement(sql)) {
@ -104,6 +105,7 @@ public final class BlocksDAO {
blockLineNumber, blockLineNumber,
blockLinePreHashe, blockLinePreHashe,
msgType, msgType,
msgSubType,
blockByte, blockByte,
to_login, to_login,
toBchName, toBchName,
@ -157,6 +159,7 @@ public final class BlocksDAO {
blockGlobalPreHashe = ?, blockGlobalPreHashe = ?,
blockLinePreHashe = ?, blockLinePreHashe = ?,
msgType = ?, msgType = ?,
msgSubType = ?,
blockByte = ?, blockByte = ?,
to_login = ?, to_login = ?,
toBchName = ?, toBchName = ?,
@ -176,6 +179,7 @@ public final class BlocksDAO {
ps.setString(i++, nn(e.getBlockGlobalPreHashe())); ps.setString(i++, nn(e.getBlockGlobalPreHashe()));
ps.setString(i++, nn(e.getBlockLinePreHashe())); ps.setString(i++, nn(e.getBlockLinePreHashe()));
ps.setInt(i++, e.getMsgType()); ps.setInt(i++, e.getMsgType());
ps.setInt(i++, e.getMsgSubType());
byte[] bytes = e.getBlockByte(); byte[] bytes = e.getBlockByte();
if (bytes != null) ps.setBytes(i++, bytes); if (bytes != null) ps.setBytes(i++, bytes);
@ -270,6 +274,7 @@ public final class BlocksDAO {
ps.setString(i++, nn(e.getBlockLinePreHashe())); ps.setString(i++, nn(e.getBlockLinePreHashe()));
ps.setInt(i++, e.getMsgType()); ps.setInt(i++, e.getMsgType());
ps.setInt(i++, e.getMsgSubType());
byte[] bytes = e.getBlockByte(); byte[] bytes = e.getBlockByte();
if (bytes != null) ps.setBytes(i++, bytes); if (bytes != null) ps.setBytes(i++, bytes);
@ -301,6 +306,7 @@ public final class BlocksDAO {
e.setBlockLinePreHashe(rs.getString("blockLinePreHashe")); e.setBlockLinePreHashe(rs.getString("blockLinePreHashe"));
e.setMsgType(rs.getInt("msgType")); e.setMsgType(rs.getInt("msgType"));
e.setMsgSubType(rs.getInt("msgSubType"));
e.setBlockByte(rs.getBytes("blockByte")); e.setBlockByte(rs.getBytes("blockByte"));

View File

@ -11,6 +11,9 @@ package shine.db.entities;
* - toBlockGlobalNumber INTEGER nullable * - toBlockGlobalNumber INTEGER nullable
* - toBlockHashe TEXT nullable * - toBlockHashe TEXT nullable
* *
* ДОБАВЛЕНО:
* - msgSubType INTEGER (uint16 по смыслу, храним как int)
*
* PRIMARY KEY пока убран вообще. * PRIMARY KEY пока убран вообще.
*/ */
public class BlockEntry { public class BlockEntry {
@ -26,6 +29,7 @@ public class BlockEntry {
private String blockLinePreHashe; // TEXT private String blockLinePreHashe; // TEXT
private int msgType; // int16 (храним как int) private int msgType; // int16 (храним как int)
private int msgSubType; // int16 (храним как int)
private byte[] blockByte; // BLOB private byte[] blockByte; // BLOB
@ -44,6 +48,7 @@ public class BlockEntry {
int blockLineNumber, int blockLineNumber,
String blockLinePreHashe, String blockLinePreHashe,
int msgType, int msgType,
int msgSubType,
byte[] blockByte, byte[] blockByte,
String toLogin, String toLogin,
String toBchName, String toBchName,
@ -57,6 +62,7 @@ public class BlockEntry {
this.blockLineNumber = blockLineNumber; this.blockLineNumber = blockLineNumber;
this.blockLinePreHashe = blockLinePreHashe; this.blockLinePreHashe = blockLinePreHashe;
this.msgType = msgType; this.msgType = msgType;
this.msgSubType = msgSubType;
this.blockByte = blockByte; this.blockByte = blockByte;
this.toLogin = toLogin; this.toLogin = toLogin;
this.toBchName = toBchName; this.toBchName = toBchName;
@ -88,6 +94,9 @@ public class BlockEntry {
public int getMsgType() { return msgType; } public int getMsgType() { return msgType; }
public void setMsgType(int msgType) { this.msgType = msgType; } public void setMsgType(int msgType) { this.msgType = msgType; }
public int getMsgSubType() { return msgSubType; }
public void setMsgSubType(int msgSubType) { this.msgSubType = msgSubType; }
public byte[] getBlockByte() { return blockByte; } public byte[] getBlockByte() { return blockByte; }
public void setBlockByte(byte[] blockByte) { this.blockByte = blockByte; } public void setBlockByte(byte[] blockByte) { this.blockByte = blockByte; }

View File

@ -1,7 +1,7 @@
package server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler_utils; package server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler_utils;
import blockchain.BchBlockEntry; import blockchain.BchBlockEntry;
import blockchain.body.ReactionBody; import blockchain.body.BodyHasTarget;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import shine.db.SqliteDbController; import shine.db.SqliteDbController;
@ -281,7 +281,12 @@ public final class BlockchainWriter {
* Важно: * Важно:
* - blockLinePreHashe = prevLineHashHex (а НЕ prevGlobalHashHex) * - blockLinePreHashe = prevLineHashHex (а НЕ prevGlobalHashHex)
* - msgType = body.type() * - msgType = body.type()
* - Для ReactionBody заполняем toBchName/toBlockGlobalNumber/toBlockHashe (+ to_login если можем). * - msgSubType = body.subType()
* - to* поля берём через BodyToFields (если body его поддерживает)
*
* Про toLogin:
* - если body сам даёт toLogin пишем его
* - иначе, если есть toBchName пробуем вычислить login из имени блокчейна (про запас)
*/ */
private void insertBlockRow( private void insertBlockRow(
Connection c, Connection c,
@ -311,6 +316,7 @@ public final class BlockchainWriter {
e.setBlockLinePreHashe(linePre); e.setBlockLinePreHashe(linePre);
e.setMsgType(block.body.type()); e.setMsgType(block.body.type());
e.setMsgSubType(block.body.subType());
e.setBlockByte(block.toBytes()); e.setBlockByte(block.toBytes());
@ -320,16 +326,20 @@ public final class BlockchainWriter {
e.setToBlockGlobalNumber(null); e.setToBlockGlobalNumber(null);
e.setToBlockHashe(null); e.setToBlockHashe(null);
// ReactionBody -> target fields // Универсально: если body поддерживает to-поля пишем их
if (block.body instanceof ReactionBody rb) { if (block.body instanceof BodyHasTarget tf) {
e.setToBchName(rb.toBlockchainName);
e.setToBlockGlobalNumber(rb.toBlockGlobalNumber); e.setToLogin(tf.toLogin());
e.setToBlockHashe(rb.toBlockHashHex()); e.setToBchName(tf.toBchName());
e.setToBlockGlobalNumber(tf.toBlockGlobalNumber());
e.setToBlockHashe(tf.toBlockHashe());
// optional: try compute to_login from target chain name (для индекса idx_blocks_to_target) // optional: try compute to_login from target chain name (для индекса idx_blocks_to_target)
String toLogin = BlockchainNameUtil.loginFromBlockchainName(rb.toBlockchainName); if (e.getToLogin() == null && e.getToBchName() != null) {
if (toLogin != null && !toLogin.isBlank()) { String toLogin = BlockchainNameUtil.loginFromBlockchainName(e.getToBchName());
e.setToLogin(toLogin); if (toLogin != null && !toLogin.isBlank()) {
e.setToLogin(toLogin);
}
} }
} }