Заработало блок добавляется в файл и в статус блокчена в БД!!
Но ещё надо сделать таблицу с записями :)
This commit is contained in:
AidarKC 2025-12-17 18:35:34 +03:00
parent 2037ebaa8b
commit e9c11d6b75
2 changed files with 90 additions and 47 deletions

View File

@ -187,7 +187,13 @@ public final class BlockchainStateService_new {
s.setLastGlobalHash(ZERO64); s.setLastGlobalHash(ZERO64);
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
s.setLastLineNumber(i, 0); if (i == 0) {
// линия 0: заглавный блок имеет lineNumber=0
s.setLastLineNumber(i, -1);
} else {
// остальные линии: первый блок будет lineNumber=1
s.setLastLineNumber(i, 0);
}
s.setLastLineHash(i, ZERO64); s.setLastLineHash(i, ZERO64);
} }

View File

@ -13,7 +13,6 @@ import java.net.http.HttpClient;
import java.net.http.WebSocket; import java.net.http.WebSocket;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage; import java.util.concurrent.CompletionStage;
@ -24,7 +23,6 @@ public class Test_AddBlock_new_NoAuth {
private static final String WS_URI = "ws://localhost:7070/ws"; private static final String WS_URI = "ws://localhost:7070/ws";
private static final ObjectMapper JSON = new ObjectMapper(); private static final ObjectMapper JSON = new ObjectMapper();
// ======= ДАННЫЕ (взяты по аналогии с твоим тестом) =======
private static final String TEST_LOGIN = "anya24"; private static final String TEST_LOGIN = "anya24";
private static final long TEST_BCH_ID = 4222L; private static final long TEST_BCH_ID = 4222L;
@ -36,8 +34,8 @@ public class Test_AddBlock_new_NoAuth {
LOGIN_PUB_KEY = Ed25519Util.derivePublicKey(LOGIN_PRIV_KEY); LOGIN_PUB_KEY = Ed25519Util.derivePublicKey(LOGIN_PRIV_KEY);
} }
// Нулевой хэш (для первого блока)
private static final byte[] ZERO32 = new byte[32]; private static final byte[] ZERO32 = new byte[32];
private static final String ZERO64 = "0".repeat(64);
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
@ -48,26 +46,32 @@ public class Test_AddBlock_new_NoAuth {
private int step = 0; private int step = 0;
// сервер просил в request: blockchainId + globalNumber + prevGlobalHash + bytes блока // Эти значения обновим ПО ОТВЕТУ сервера на header
// prevLineHash сервер может не просить но для подписи нам он нужен private String lastGlobalHashHex = ZERO64;
private byte[] lastGlobalHash = ZERO32; private String lastLineHashHex = ZERO64;
private byte[] lastLineHash = ZERO32;
@Override @Override
public void onOpen(WebSocket ws) { public void onOpen(WebSocket ws) {
System.out.println("✅ WS connected: " + WS_URI); System.out.println("✅ WS connected: " + WS_URI);
ws.request(1); ws.request(1);
// 1) Header block // 1) HEADER (global=0, line=0, lineNumber=0)
byte[] headerFull = buildHeaderBlockFullBytes( byte[] headerFull = buildHeaderBlockFullBytes(
/*global*/0, /*global*/0,
/*lineIndex*/(short)0, /*lineIndex*/(short)0,
/*lineBlock*/0, /*lineBlock*/0,
lastGlobalHash, /*prevGlobal*/ZERO32,
lastLineHash /*prevLine*/ZERO32
);
String json = buildAddBlockJson(
"test-add-header",
TEST_BCH_ID,
0,
ZERO64, // prevGlobalHash для первого блока нули
base64(headerFull)
); );
String json = buildAddBlockJson("test-add-header", TEST_BCH_ID, 0, bytesToHex(lastGlobalHash), base64(headerFull));
System.out.println("\n📤 SEND #1 (HEADER):\n" + json); System.out.println("\n📤 SEND #1 (HEADER):\n" + json);
ws.sendText(json, true); ws.sendText(json, true);
} }
@ -80,6 +84,7 @@ public class Test_AddBlock_new_NoAuth {
try { try {
int status = extractStatus(msg); int status = extractStatus(msg);
if (step == 0) { if (step == 0) {
if (status != 200) { if (status != 200) {
System.out.println("❌ HEADER rejected, status=" + status); System.out.println("❌ HEADER rejected, status=" + status);
@ -87,32 +92,54 @@ public class Test_AddBlock_new_NoAuth {
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
// Обновляем prev-хэши для следующего блока: берём хэш из нашего же блока (как ожидаемую цепочку) // Берём ИМЕННО ТОТ хэш, который сервер сохранил в state
byte[] headerFull = lastSentBlockFullFromResponseOrLocalFallback(true); String serverLastGlobalHash = extractPayloadString(msg, "serverLastGlobalHash");
// Fallback: просто пересоберём ровно так же (надёжнее: хранить отправленные байты) String serverLastLineHash = extractPayloadString(msg, "serverLastLineHash");
headerFull = buildHeaderBlockFullBytes(0, (short)0, 0, ZERO32, ZERO32);
BchBlockEntry_new hb = new BchBlockEntry_new(headerFull); if (serverLastGlobalHash == null || serverLastGlobalHash.isBlank()) {
lastGlobalHash = hb.getHash32(); System.out.println("❌ No serverLastGlobalHash in response");
lastLineHash = hb.getHash32(); ws.sendClose(WebSocket.NORMAL_CLOSURE, "bad-response");
return CompletableFuture.completedFuture(null);
}
if (serverLastLineHash == null || serverLastLineHash.isBlank()) {
// fallback: пусть будет как global (если сервер так хранит)
serverLastLineHash = serverLastGlobalHash;
}
// 2) Text block lastGlobalHashHex = serverLastGlobalHash;
lastLineHashHex = serverLastLineHash;
byte[] prevGlobal32 = hexToBytes32(lastGlobalHashHex);
byte[] prevLine32 = hexToBytes32(lastLineHashHex);
// 2) TEXT (global=1, line=0, lineNumber=1)
byte[] textFull = buildTextBlockFullBytes( byte[] textFull = buildTextBlockFullBytes(
/*global*/1, /*global*/1,
/*lineIndex*/(short)0, /*lineIndex*/(short)0,
/*lineBlock*/1, /*lineBlock*/1,
lastGlobalHash, prevGlobal32,
lastLineHash, prevLine32,
"Hello from test client" "Hello from test client"
); );
String json2 = buildAddBlockJson("test-add-text", TEST_BCH_ID, 1, bytesToHex(lastGlobalHash), base64(textFull)); String json2 = buildAddBlockJson(
"test-add-text",
TEST_BCH_ID,
1,
lastGlobalHashHex, // prevGlobalHash = хэш header'а из ответа сервера
base64(textFull)
);
System.out.println("\n📤 SEND #2 (TEXT):\n" + json2); System.out.println("\n📤 SEND #2 (TEXT):\n" + json2);
step = 1; step = 1;
ws.sendText(json2, true); ws.sendText(json2, true);
} else if (step == 1) { } else if (step == 1) {
System.out.println("✅ Done. Closing."); if (status != 200) {
System.out.println("❌ TEXT rejected, status=" + status);
} else {
System.out.println("✅ Done. Closing.");
}
ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok"); ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
} }
@ -153,7 +180,6 @@ public class Test_AddBlock_new_NoAuth {
byte[] prevGlobalHash32, byte[] prevGlobalHash32,
byte[] prevLineHash32) { byte[] prevLineHash32) {
// bodyBytes (включая type+version внутри)
HeaderBody body = new HeaderBody( HeaderBody body = new HeaderBody(
TEST_BCH_ID, TEST_BCH_ID,
TEST_LOGIN, TEST_LOGIN,
@ -173,6 +199,7 @@ public class Test_AddBlock_new_NoAuth {
byte[] prevGlobalHash32, byte[] prevGlobalHash32,
byte[] prevLineHash32, byte[] prevLineHash32,
String text) { String text) {
TextBody body = new TextBody(text); TextBody body = new TextBody(text);
byte[] bodyBytes = body.toBytes(); byte[] bodyBytes = body.toBytes();
@ -188,13 +215,11 @@ public class Test_AddBlock_new_NoAuth {
long ts = System.currentTimeMillis() / 1000L; long ts = System.currentTimeMillis() / 1000L;
// Собираем rawBytes вручную в точности как BchBlockEntry_new RAW:
// [4]recordSize [4]recordNumber [8]ts [2]lineIndex [4]lineBlockNumber [body...]
int recordSize = int recordSize =
BchBlockEntry_new.RAW_HEADER_SIZE + BchBlockEntry_new.RAW_HEADER_SIZE +
bodyBytes.length + bodyBytes.length +
BchBlockEntry_new.SIGNATURE_LEN + BchBlockEntry_new.SIGNATURE_LEN +
BchBlockEntry_new.HASH_LEN; BchBlockEntry_new.HASH_LEN;
byte[] rawBytes = ByteBuffer.allocate(BchBlockEntry_new.RAW_HEADER_SIZE + bodyBytes.length) byte[] rawBytes = ByteBuffer.allocate(BchBlockEntry_new.RAW_HEADER_SIZE + bodyBytes.length)
.order(ByteOrder.BIG_ENDIAN) .order(ByteOrder.BIG_ENDIAN)
@ -215,10 +240,9 @@ public class Test_AddBlock_new_NoAuth {
byte[] hash32 = BchCryptoVerifier_new.sha256(preimage); byte[] hash32 = BchCryptoVerifier_new.sha256(preimage);
// ВАЖНО: если у тебя в протоколе подпись делается НЕ по hash32, а по preimage замени тут на preimage // если у тебя подпись должна быть по preimage меняй тут
byte[] signature64 = Ed25519Util.sign(hash32, LOGIN_PRIV_KEY); byte[] signature64 = Ed25519Util.sign(hash32, LOGIN_PRIV_KEY);
// FULL block
return new BchBlockEntry_new( return new BchBlockEntry_new(
globalNumber, globalNumber,
ts, ts,
@ -235,11 +259,10 @@ public class Test_AddBlock_new_NoAuth {
// ================================================================================= // =================================================================================
private static String buildAddBlockJson(String requestId, private static String buildAddBlockJson(String requestId,
long blockchainId, long blockchainId,
int globalNumber, int globalNumber,
String prevGlobalHashHex, String prevGlobalHashHex,
String blockBytesB64) { String blockBytesB64) {
// Если у тебя в Net_AddBlock_new_Request другие имена полей скажешь, подправлю.
return """ return """
{ {
"op": "AddBlock", "op": "AddBlock",
@ -267,18 +290,32 @@ public class Test_AddBlock_new_NoAuth {
return -1; return -1;
} }
private static String extractPayloadString(String json, String field) {
try {
JsonNode root = JSON.readTree(json);
JsonNode payload = root.get("payload");
if (payload != null && payload.has(field)) {
return payload.get(field).asText();
}
} catch (Exception ignore) {}
return null;
}
private static String base64(byte[] bytes) { private static String base64(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes); return Base64.getEncoder().encodeToString(bytes);
} }
private static String bytesToHex(byte[] b) { private static byte[] hexToBytes32(String hex) {
StringBuilder sb = new StringBuilder(b.length * 2); if (hex == null) throw new IllegalArgumentException("hex is null");
for (byte x : b) sb.append(String.format("%02x", x)); String s = hex.trim();
return sb.toString(); if (s.length() != 64) throw new IllegalArgumentException("hex must be 64 chars, got " + s.length());
byte[] out = new byte[32];
for (int i = 0; i < 32; i++) {
int hi = Character.digit(s.charAt(i * 2), 16);
int lo = Character.digit(s.charAt(i * 2 + 1), 16);
if (hi < 0 || lo < 0) throw new IllegalArgumentException("bad hex at pos " + (i * 2));
out[i] = (byte) ((hi << 4) | lo);
}
return out;
} }
}
// Заглушка: в этом тесте проще хранить отправленные байты локально.
private static byte[] lastSentBlockFullFromResponseOrLocalFallback(boolean header) {
return null;
}
}