17 12 25
Ещё промежуточный комит верии - не работает :) 4
This commit is contained in:
parent
45a862b11f
commit
2037ebaa8b
@ -21,8 +21,14 @@ public final class BlockchainStateDAO {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Новый вариант: работа на переданном соединении ---
|
// старый метод оставим
|
||||||
public BlockchainStateEntry getByBlockchainId(Connection conn, long blockchainId) throws SQLException {
|
public BlockchainStateEntry getByBlockchainId(long blockchainId) throws SQLException {
|
||||||
|
try (Connection c = db.getConnection()) {
|
||||||
|
return getByBlockchainId(c, blockchainId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockchainStateEntry getByBlockchainId(Connection c, long blockchainId) throws SQLException {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT
|
SELECT
|
||||||
blockchain_id,
|
blockchain_id,
|
||||||
@ -45,7 +51,7 @@ public final class BlockchainStateDAO {
|
|||||||
WHERE blockchain_id = ?
|
WHERE blockchain_id = ?
|
||||||
""";
|
""";
|
||||||
|
|
||||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||||
ps.setLong(1, blockchainId);
|
ps.setLong(1, blockchainId);
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
if (!rs.next()) return null;
|
if (!rs.next()) return null;
|
||||||
@ -54,18 +60,14 @@ public final class BlockchainStateDAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Старый вариант: сам открывает/закрывает conn
|
// старый метод оставим
|
||||||
public BlockchainStateEntry getByBlockchainId(long blockchainId) throws SQLException {
|
public void upsert(BlockchainStateEntry e) throws SQLException {
|
||||||
try (Connection conn = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
return getByBlockchainId(conn, blockchainId);
|
upsert(c, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Новый вариант: UPSERT на переданном соединении ---
|
public void upsert(Connection c, BlockchainStateEntry e) throws SQLException {
|
||||||
public void upsert(Connection conn, BlockchainStateEntry e) throws SQLException {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (e.getUpdatedAtMs() <= 0) e.setUpdatedAtMs(now);
|
|
||||||
|
|
||||||
String sql = """
|
String sql = """
|
||||||
INSERT INTO blockchain_state (
|
INSERT INTO blockchain_state (
|
||||||
blockchain_id,
|
blockchain_id,
|
||||||
@ -104,7 +106,6 @@ public final class BlockchainStateDAO {
|
|||||||
size_bytes = excluded.size_bytes,
|
size_bytes = excluded.size_bytes,
|
||||||
last_global_number = excluded.last_global_number,
|
last_global_number = excluded.last_global_number,
|
||||||
last_global_hash = excluded.last_global_hash,
|
last_global_hash = excluded.last_global_hash,
|
||||||
|
|
||||||
line0_last_number = excluded.line0_last_number,
|
line0_last_number = excluded.line0_last_number,
|
||||||
line0_last_hash = excluded.line0_last_hash,
|
line0_last_hash = excluded.line0_last_hash,
|
||||||
line1_last_number = excluded.line1_last_number,
|
line1_last_number = excluded.line1_last_number,
|
||||||
@ -121,11 +122,10 @@ public final class BlockchainStateDAO {
|
|||||||
line6_last_hash = excluded.line6_last_hash,
|
line6_last_hash = excluded.line6_last_hash,
|
||||||
line7_last_number = excluded.line7_last_number,
|
line7_last_number = excluded.line7_last_number,
|
||||||
line7_last_hash = excluded.line7_last_hash,
|
line7_last_hash = excluded.line7_last_hash,
|
||||||
|
|
||||||
updated_at_ms = excluded.updated_at_ms
|
updated_at_ms = excluded.updated_at_ms
|
||||||
""";
|
""";
|
||||||
|
|
||||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
ps.setLong(i++, e.getBlockchainId());
|
ps.setLong(i++, e.getBlockchainId());
|
||||||
ps.setString(i++, nn(e.getUserLogin()));
|
ps.setString(i++, nn(e.getUserLogin()));
|
||||||
@ -145,13 +145,6 @@ public final class BlockchainStateDAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Старый вариант: сам открывает/закрывает conn
|
|
||||||
public void upsert(BlockchainStateEntry e) throws SQLException {
|
|
||||||
try (Connection conn = db.getConnection()) {
|
|
||||||
upsert(conn, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BlockchainStateEntry mapRow(ResultSet rs) throws SQLException {
|
private BlockchainStateEntry mapRow(ResultSet rs) throws SQLException {
|
||||||
BlockchainStateEntry e = new BlockchainStateEntry();
|
BlockchainStateEntry e = new BlockchainStateEntry();
|
||||||
e.setBlockchainId(rs.getLong("blockchain_id"));
|
e.setBlockchainId(rs.getLong("blockchain_id"));
|
||||||
@ -173,7 +166,5 @@ public final class BlockchainStateDAO {
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String nn(String s) {
|
private static String nn(String s) { return s == null ? "" : s; }
|
||||||
return s == null ? "" : s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -76,6 +76,23 @@ public final class SolanaUsersDAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// добавь рядом со старым методом
|
||||||
|
public SolanaUserEntry getByLogin(Connection c, String login) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
|
||||||
|
FROM solana_users
|
||||||
|
WHERE LOWER(login) = LOWER(?)
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||||
|
ps.setString(1, login);
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (!rs.next()) return null;
|
||||||
|
return mapRow(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public SolanaUserEntry getByLogin(String login) throws SQLException {
|
public SolanaUserEntry getByLogin(String login) throws SQLException {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
|
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
package server.logic.ws_protocol.JSON.handlers.blockchain;
|
package server.logic.ws_protocol.JSON.handlers.blockchain;
|
||||||
|
|
||||||
import blockchain_new.BchBlockEntry_new;
|
import blockchain_new.BchBlockEntry_new;
|
||||||
|
import shine.db.SqliteDbController;
|
||||||
import shine.db.dao.BlockchainStateDAO;
|
import shine.db.dao.BlockchainStateDAO;
|
||||||
import shine.db.dao.SolanaUsersDAO;
|
import shine.db.dao.SolanaUsersDAO;
|
||||||
import shine.db.entities.BlockchainStateEntry;
|
import shine.db.entities.BlockchainStateEntry;
|
||||||
import shine.db.entities.SolanaUserEntry;
|
import shine.db.entities.SolanaUserEntry;
|
||||||
import utils.files.FileStoreUtil;
|
import utils.files.FileStoreUtil;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public final class BlockchainStateService_new {
|
public final class BlockchainStateService_new {
|
||||||
@ -26,7 +29,6 @@ public final class BlockchainStateService_new {
|
|||||||
this.stateAfter = stateAfter;
|
this.stateAfter = stateAfter;
|
||||||
this.lineIndex = lineIndex;
|
this.lineIndex = lineIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOk() { return reasonCode == null && httpStatus == 200; }
|
public boolean isOk() { return reasonCode == null && httpStatus == 200; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,23 +36,16 @@ public final class BlockchainStateService_new {
|
|||||||
public static BlockchainStateService_new getInstance() { return INSTANCE; }
|
public static BlockchainStateService_new getInstance() { return INSTANCE; }
|
||||||
private BlockchainStateService_new() {}
|
private BlockchainStateService_new() {}
|
||||||
|
|
||||||
// ===== locks per blockchainId (MVP: один сервер) =====
|
|
||||||
private static final ConcurrentHashMap<Long, ReentrantLock> LOCKS = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private static ReentrantLock lockFor(long blockchainId) {
|
|
||||||
return LOCKS.computeIfAbsent(blockchainId, id -> new ReentrantLock());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== constants =====
|
|
||||||
private static final String ZERO64 = "0".repeat(64);
|
private static final String ZERO64 = "0".repeat(64);
|
||||||
|
|
||||||
// MVP: “заглавный блок”
|
// Локи по blockchainId (MVP, один сервер)
|
||||||
// (пока без парсинга тела, просто по номеру)
|
private final ConcurrentMap<Long, ReentrantLock> locks = new ConcurrentHashMap<>();
|
||||||
private static boolean isHeaderBlock(int globalNumber, int lineNumber) {
|
|
||||||
return globalNumber == 0 && lineNumber == 0;
|
private ReentrantLock lockFor(long blockchainId) {
|
||||||
|
return locks.computeIfAbsent(blockchainId, k -> new ReentrantLock());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result addBlock(
|
public Result addBlockAtomically(
|
||||||
String login,
|
String login,
|
||||||
long blockchainId,
|
long blockchainId,
|
||||||
int globalNumber,
|
int globalNumber,
|
||||||
@ -81,101 +76,90 @@ public final class BlockchainStateService_new {
|
|||||||
return new Result(400, "BAD_BLOCK_FORMAT", null, -1);
|
return new Result(400, "BAD_BLOCK_FORMAT", null, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lineIndex = block.line; // short -> int
|
int lineIndex = block.line;
|
||||||
if (lineIndex < 0 || lineIndex > 7)
|
if (lineIndex < 0 || lineIndex > 7)
|
||||||
return new Result(400, "BAD_LINE_INDEX", null, lineIndex);
|
return new Result(400, "BAD_LINE_INDEX", null, lineIndex);
|
||||||
|
|
||||||
ReentrantLock lock = lockFor(blockchainId);
|
ReentrantLock lock = lockFor(blockchainId);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try (Connection conn = SqliteDbController.getInstance().getConnection()) {
|
||||||
BlockchainStateEntry state = BlockchainStateDAO.getInstance().getByBlockchainId(blockchainId);
|
|
||||||
|
BlockchainStateDAO stateDao = BlockchainStateDAO.getInstance();
|
||||||
|
SolanaUsersDAO usersDao = SolanaUsersDAO.getInstance();
|
||||||
|
|
||||||
|
// читаем state В ЭТОМ ЖЕ conn
|
||||||
|
BlockchainStateEntry state = stateDao.getByBlockchainId(conn, blockchainId);
|
||||||
|
|
||||||
|
boolean isHeaderBlock = (globalNumber == 0 && lineIndex == 0 && block.lineNumber == 0);
|
||||||
|
|
||||||
// ===== GENESIS ветка: state ещё нет =====
|
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
// разрешаем только заглавный блок
|
// state отсутствует — разрешаем ТОЛЬКО header-блок
|
||||||
if (!isHeaderBlock(globalNumber, block.lineNumber)) {
|
if (!isHeaderBlock) {
|
||||||
return new Result(404, "UNKNOWN_BLOCKCHAIN", null, lineIndex);
|
return new Result(404, "UNKNOWN_BLOCKCHAIN", null, lineIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// создаём первичное состояние (last_global=-1, hash=ZERO64, lines=0/ZERO64)
|
// Проверяем пользователя и соответствие bchId
|
||||||
state = createInitialStateFromUser(login, blockchainId);
|
SolanaUserEntry u = usersDao.getByLogin(conn, login);
|
||||||
if (state == null) {
|
if (u == null) {
|
||||||
// нет такого юзера / не его bchId
|
return new Result(404, "UNKNOWN_USER", null, lineIndex);
|
||||||
return new Result(404, "UNKNOWN_BLOCKCHAIN", null, lineIndex);
|
}
|
||||||
|
if (u.getBchId() != blockchainId) {
|
||||||
|
return new Result(403, "BCHID_MISMATCH", null, lineIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// сохраняем стартовую строку
|
// prevGlobalHash для header должен быть нулевой
|
||||||
BlockchainStateDAO.getInstance().upsert(state);
|
if (!eqHash(prevGlobalHashHex, ZERO64)) {
|
||||||
|
return new Result(409, "GLOBAL_HASH_MISMATCH", null, lineIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создаём “нулевой” state ДО записи header (last_global_number = -1)
|
||||||
|
state = createInitialState(blockchainId, login, u.getLoginKey(), safeLimit(u.getBchLimit()));
|
||||||
|
// stateDao.upsert(conn, state); //TODO так здесь наверное его в БД сохранять не надо если всё верно то потом дополненный сохраниться
|
||||||
|
} else {
|
||||||
|
// state есть — обычная проверка login
|
||||||
|
if (!login.equals(state.getUserLogin())) {
|
||||||
|
return new Result(403, "LOGIN_MISMATCH", state, lineIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1) защита от подмены логина
|
// Перечитывать не надо, state актуален в переменной.
|
||||||
if (!login.equals(state.getUserLogin())) {
|
|
||||||
return new Result(403, "LOGIN_MISMATCH", state, lineIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) expected global: last_global + 1 (у нас last_global стартует -1)
|
// expected global
|
||||||
int expectedGlobal = state.getLastGlobalNumber() + 1;
|
int expectedGlobal = state.getLastGlobalNumber() + 1;
|
||||||
if (globalNumber != expectedGlobal) {
|
if (globalNumber != expectedGlobal) {
|
||||||
return new Result(409, "OUT_OF_SEQUENCE_GLOBAL", state, lineIndex);
|
return new Result(409, "OUT_OF_SEQUENCE_GLOBAL", state, lineIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) prev global hash
|
// prev global hash сверяем
|
||||||
String dbPrevGlobalHash = nn(state.getLastGlobalHash());
|
String dbPrevGlobalHash = nn(state.getLastGlobalHash());
|
||||||
if (!eqHash(prevGlobalHashHex, dbPrevGlobalHash)) {
|
if (!eqHash(prevGlobalHashHex, dbPrevGlobalHash)) {
|
||||||
return new Result(409, "GLOBAL_HASH_MISMATCH", state, lineIndex);
|
return new Result(409, "GLOBAL_HASH_MISMATCH", state, lineIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4) lineNumber
|
// expected line number
|
||||||
// Нормально: первый “обычный” блок по линии должен быть lineNumber=1 при lastLine=0
|
|
||||||
// Исключение: заглавный блок имеет lineNumber=0
|
|
||||||
int expectedLineNumber = state.getLastLineNumber(lineIndex) + 1;
|
int expectedLineNumber = state.getLastLineNumber(lineIndex) + 1;
|
||||||
boolean header = isHeaderBlock(globalNumber, block.lineNumber);
|
if (block.lineNumber != expectedLineNumber) {
|
||||||
|
return new Result(409, "OUT_OF_SEQUENCE_LINE", state, lineIndex);
|
||||||
if (!header) {
|
|
||||||
if (block.lineNumber != expectedLineNumber) {
|
|
||||||
return new Result(409, "OUT_OF_SEQUENCE_LINE", state, lineIndex);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// заглавный блок допускаем только если текущий lastLineNumber == 0 и пришёл 0
|
|
||||||
if (state.getLastLineNumber(lineIndex) != 0 || block.lineNumber != 0) {
|
|
||||||
return new Result(409, "BAD_HEADER_LINE_NUMBER", state, lineIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5) prevLineHash берём из БД (пока просто читаем)
|
// TODO: крипто-проверка (потом подключим)
|
||||||
String dbPrevLineHashHex = nn(state.getLastLineHash(lineIndex));
|
|
||||||
// (можешь позже сравнивать с тем, что внутри блока, если там есть prevLineHash)
|
|
||||||
|
|
||||||
// 6) крипто-проверка (позже)
|
// 1) запись блока в файл
|
||||||
// TODO:
|
|
||||||
// - восстановить preimage
|
|
||||||
// - sha256(preimage) == block.hash32
|
|
||||||
// - Ed25519 verify signature
|
|
||||||
// если не ок: return new Result(422, "CRYPTO_INVALID", state, lineIndex);
|
|
||||||
|
|
||||||
// 7) запись блока в файл
|
|
||||||
FileStoreUtil.getInstance().addDataToBlockchain(blockchainId, block.toBytes());
|
FileStoreUtil.getInstance().addDataToBlockchain(blockchainId, block.toBytes());
|
||||||
|
|
||||||
// 8) апдейт состояния
|
// 2) апдейт state
|
||||||
|
String newHashHex = bytesToHex(block.getHash32());
|
||||||
|
|
||||||
state.setLastGlobalNumber(globalNumber);
|
state.setLastGlobalNumber(globalNumber);
|
||||||
state.setLastGlobalHash(bytesToHex(block.getHash32()));
|
state.setLastGlobalHash(newHashHex);
|
||||||
|
|
||||||
// line number:
|
state.setLastLineNumber(lineIndex, block.lineNumber);
|
||||||
// - для заглавного блока оставляем 0
|
state.setLastLineHash(lineIndex, newHashHex);
|
||||||
// - для остальных двигаем как обычно
|
|
||||||
if (!header) {
|
|
||||||
state.setLastLineNumber(lineIndex, block.lineNumber);
|
|
||||||
} else {
|
|
||||||
state.setLastLineNumber(lineIndex, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// line hash обновляем в любом случае (так проще для цепочки)
|
|
||||||
state.setLastLineHash(lineIndex, bytesToHex(block.getHash32()));
|
|
||||||
|
|
||||||
state.setSizeBytes(state.getSizeBytes() + fullBytes.length);
|
state.setSizeBytes(state.getSizeBytes() + fullBytes.length);
|
||||||
state.setUpdatedAtMs(System.currentTimeMillis());
|
state.setUpdatedAtMs(System.currentTimeMillis());
|
||||||
|
|
||||||
BlockchainStateDAO.getInstance().upsert(state);
|
stateDao.upsert(conn, state);
|
||||||
|
|
||||||
return new Result(200, null, state, lineIndex);
|
return new Result(200, null, state, lineIndex);
|
||||||
|
|
||||||
@ -186,30 +170,19 @@ public final class BlockchainStateService_new {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static BlockchainStateEntry createInitialState(long blockchainId,
|
||||||
* Создаёт стартовое состояние по данным пользователя:
|
String login,
|
||||||
* - проверяем, что login существует и что bchId совпадает с blockchainId
|
String loginKeyBase64,
|
||||||
* - public_key_base64 берём из loginKey
|
int sizeLimit) {
|
||||||
*/
|
|
||||||
private static BlockchainStateEntry createInitialStateFromUser(String login, long blockchainId) throws SQLException {
|
|
||||||
SolanaUserEntry u = SolanaUsersDAO.getInstance().getByLogin(login);
|
|
||||||
if (u == null) return null;
|
|
||||||
if (u.getBchId() != blockchainId) return null;
|
|
||||||
|
|
||||||
BlockchainStateEntry s = new BlockchainStateEntry();
|
BlockchainStateEntry s = new BlockchainStateEntry();
|
||||||
s.setBlockchainId(blockchainId);
|
s.setBlockchainId(blockchainId);
|
||||||
s.setUserLogin(login);
|
s.setUserLogin(login);
|
||||||
|
s.setPublicKeyBase64(nn(loginKeyBase64));
|
||||||
|
|
||||||
// публичный ключ для блокчейна = loginKey (как ты и хочешь)
|
s.setSizeLimit(sizeLimit);
|
||||||
s.setPublicKeyBase64(nn(u.getLoginKey()));
|
|
||||||
|
|
||||||
// лимит (пока тестовый / из пользователя)
|
|
||||||
int limit = (u.getBchLimit() != null) ? u.getBchLimit() : 1_000_000;
|
|
||||||
s.setSizeLimit(limit);
|
|
||||||
|
|
||||||
s.setSizeBytes(0);
|
s.setSizeBytes(0);
|
||||||
|
|
||||||
// ВАЖНО: стартовые значения
|
// как ты хочешь:
|
||||||
s.setLastGlobalNumber(-1);
|
s.setLastGlobalNumber(-1);
|
||||||
s.setLastGlobalHash(ZERO64);
|
s.setLastGlobalHash(ZERO64);
|
||||||
|
|
||||||
@ -222,6 +195,11 @@ public final class BlockchainStateService_new {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int safeLimit(Integer limit) {
|
||||||
|
if (limit == null || limit <= 0) return 1_000_000; // fallback (test)
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
private static String nn(String s) { return s == null ? "" : s; }
|
private static String nn(String s) { return s == null ? "" : s; }
|
||||||
|
|
||||||
private static boolean eqHash(String a, String b) {
|
private static boolean eqHash(String a, String b) {
|
||||||
|
|||||||
@ -14,7 +14,7 @@ public final class Net_AddBlock_new_Handler implements JsonMessageHandler {
|
|||||||
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
|
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
|
||||||
Net_AddBlock_new_Request req = (Net_AddBlock_new_Request) baseReq;
|
Net_AddBlock_new_Request req = (Net_AddBlock_new_Request) baseReq;
|
||||||
|
|
||||||
var r = BlockchainStateService_new.getInstance().addBlock(
|
var r = BlockchainStateService_new.getInstance().addBlockAtomically(
|
||||||
req.getLogin(),
|
req.getLogin(),
|
||||||
req.getBlockchainId(),
|
req.getBlockchainId(),
|
||||||
req.getGlobalNumber(),
|
req.getGlobalNumber(),
|
||||||
@ -25,7 +25,6 @@ public final class Net_AddBlock_new_Handler implements JsonMessageHandler {
|
|||||||
Net_AddBlock_new_Response resp = new Net_AddBlock_new_Response();
|
Net_AddBlock_new_Response resp = new Net_AddBlock_new_Response();
|
||||||
resp.setOp(req.getOp());
|
resp.setOp(req.getOp());
|
||||||
resp.setRequestId(req.getRequestId());
|
resp.setRequestId(req.getRequestId());
|
||||||
|
|
||||||
resp.setLineIndex(r.lineIndex);
|
resp.setLineIndex(r.lineIndex);
|
||||||
|
|
||||||
if (r.isOk()) {
|
if (r.isOk()) {
|
||||||
|
|||||||
@ -10,9 +10,7 @@ import server.logic.ws_protocol.JSON.entyties.tempToTest.Net_AddUser_Response;
|
|||||||
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
|
||||||
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
|
||||||
import server.logic.ws_protocol.WireCodes;
|
import server.logic.ws_protocol.WireCodes;
|
||||||
import shine.db.dao.BlockchainStateDAO;
|
|
||||||
import shine.db.dao.SolanaUsersDAO;
|
import shine.db.dao.SolanaUsersDAO;
|
||||||
import shine.db.entities.BlockchainStateEntry;
|
|
||||||
import shine.db.entities.SolanaUserEntry;
|
import shine.db.entities.SolanaUserEntry;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@ -21,34 +19,32 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
|
|||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(Net_AddUser_Handler.class);
|
private static final Logger log = LoggerFactory.getLogger(Net_AddUser_Handler.class);
|
||||||
|
|
||||||
// ====== TEST CONST (пока так) ======
|
/** TEST ONLY: лимит блокчейна по умолчанию. Потом заменишь на норм логику. */
|
||||||
private static final int TEST_BCH_LIMIT = 1_000_000;
|
private static final int TEST_BCH_LIMIT = 1_000_000;
|
||||||
|
|
||||||
private static final String ZERO64 = "0".repeat(64);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) throws Exception {
|
public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) throws Exception {
|
||||||
Net_AddUser_Request req = (Net_AddUser_Request) baseRequest;
|
Net_AddUser_Request req = (Net_AddUser_Request) baseRequest;
|
||||||
|
|
||||||
if (req.getLogin() == null || req.getLogin().isBlank()
|
if (req.getLogin() == null || req.getLogin().isBlank()
|
||||||
|| req.getLoginKey() == null || req.getLoginKey().isBlank()
|
|| req.getLoginKey() == null || req.getLoginKey().isBlank()
|
||||||
|| req.getDeviceKey() == null || req.getDeviceKey().isBlank()) {
|
|| req.getDeviceKey() == null || req.getDeviceKey().isBlank()
|
||||||
|
|| req.getLoginId() <= 0
|
||||||
|
|| req.getBchId() <= 0) {
|
||||||
|
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.BAD_REQUEST,
|
WireCodes.Status.BAD_REQUEST,
|
||||||
"BAD_FIELDS",
|
"BAD_FIELDS",
|
||||||
"Некорректные или пустые поля: login, loginKey, deviceKey"
|
"Некорректные поля: login/loginId/bchId/loginKey/deviceKey"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bchLimit: если клиент не прислал — ставим тестовую константу
|
|
||||||
Integer limit = req.getBchLimit();
|
Integer limit = req.getBchLimit();
|
||||||
if (limit == null || limit <= 0) limit = TEST_BCH_LIMIT;
|
if (limit == null || limit <= 0) limit = TEST_BCH_LIMIT;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SolanaUsersDAO users = SolanaUsersDAO.getInstance();
|
SolanaUsersDAO dao = SolanaUsersDAO.getInstance();
|
||||||
BlockchainStateDAO stateDao = BlockchainStateDAO.getInstance();
|
|
||||||
|
|
||||||
SolanaUserEntry user = new SolanaUserEntry(
|
SolanaUserEntry user = new SolanaUserEntry(
|
||||||
req.getLoginId(),
|
req.getLoginId(),
|
||||||
@ -59,31 +55,7 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
|
|||||||
limit
|
limit
|
||||||
);
|
);
|
||||||
|
|
||||||
users.insert(user);
|
dao.insert(user);
|
||||||
|
|
||||||
// Создаём стартовую запись blockchain_state
|
|
||||||
BlockchainStateEntry s = new BlockchainStateEntry();
|
|
||||||
s.setBlockchainId(req.getBchId());
|
|
||||||
s.setUserLogin(req.getLogin());
|
|
||||||
|
|
||||||
// В блокчейн-стейте храним loginKey как основной pubkey
|
|
||||||
s.setPublicKeyBase64(req.getLoginKey());
|
|
||||||
|
|
||||||
s.setSizeLimit(limit);
|
|
||||||
s.setSizeBytes(0);
|
|
||||||
|
|
||||||
// ВАЖНО: твои стартовые значения
|
|
||||||
s.setLastGlobalNumber(-1);
|
|
||||||
s.setLastGlobalHash(ZERO64);
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
s.setLastLineNumber(i, 0);
|
|
||||||
s.setLastLineHash(i, ZERO64);
|
|
||||||
}
|
|
||||||
|
|
||||||
s.setUpdatedAtMs(System.currentTimeMillis());
|
|
||||||
|
|
||||||
stateDao.upsert(s);
|
|
||||||
|
|
||||||
Net_AddUser_Response resp = new Net_AddUser_Response();
|
Net_AddUser_Response resp = new Net_AddUser_Response();
|
||||||
resp.setOp(req.getOp());
|
resp.setOp(req.getOp());
|
||||||
@ -96,7 +68,7 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
|
|||||||
return resp;
|
return resp;
|
||||||
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
log.error("❌ DB error in AddUser", e);
|
log.error("❌ DB error AddUser", e);
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.SERVER_DATA_ERROR,
|
WireCodes.Status.SERVER_DATA_ERROR,
|
||||||
@ -104,7 +76,7 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
|
|||||||
"Ошибка доступа к базе данных"
|
"Ошибка доступа к базе данных"
|
||||||
);
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("❌ Internal error in AddUser", e);
|
log.error("❌ Internal error AddUser", e);
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.INTERNAL_ERROR,
|
WireCodes.Status.INTERNAL_ERROR,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user