13 01 25
мелкие исправления. Убрал оставшиеся странные связи линии
This commit is contained in:
parent
9cf6fabe64
commit
5fe41c7656
@ -1,17 +1,17 @@
|
||||
package blockchain;
|
||||
|
||||
/**
|
||||
* LineIndex — канонические номера линий блокчейна.
|
||||
*
|
||||
* Линия = независимая последовательность блоков внутри одного блокчейна.
|
||||
*/
|
||||
public final class LineIndex {
|
||||
|
||||
private LineIndex() {}
|
||||
|
||||
public static final short HEADER = 0; // genesis / идентификация
|
||||
public static final short TEXT = 1; // сообщения да надо
|
||||
public static final short REACTION = 2; // реакции не надо
|
||||
public static final short CONNECTION = 3; // связи (friend/contact/follow) да надо
|
||||
public static final short USER_PARAM = 4; // параметры профиля да надо
|
||||
}
|
||||
//package blockchain;
|
||||
//
|
||||
///**
|
||||
// * LineIndex — канонические номера линий блокчейна.
|
||||
// *
|
||||
// * Линия = независимая последовательность блоков внутри одного блокчейна.
|
||||
// */
|
||||
//public final class LineIndex {
|
||||
//
|
||||
// private LineIndex() {}
|
||||
//
|
||||
// public static final short HEADER = 0; // genesis / идентификация
|
||||
// public static final short TEXT = 1; // сообщения да надо
|
||||
// public static final short REACTION = 2; // реакции не надо
|
||||
// public static final short CONNECTION = 3; // связи (friend/contact/follow) да надо
|
||||
// public static final short USER_PARAM = 4; // параметры профиля да надо
|
||||
//}
|
||||
@ -19,6 +19,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
* - block хранит только preimage + signature
|
||||
* - hash32 вычисляется как sha256(preimage)
|
||||
* - signature = Ed25519.sign(hash32)
|
||||
*
|
||||
* ВАЖНО:
|
||||
* - Линии (prevLine/thisLine) по ТЗ нужны только для TEXT/CONNECTION/USER_PARAM.
|
||||
* - Здесь НЕТ обращения к blockchain.LineIndex.
|
||||
*/
|
||||
public final class AddBlockSender {
|
||||
|
||||
@ -38,6 +42,7 @@ public final class AddBlockSender {
|
||||
this.blockchainName = blockchainName;
|
||||
this.loginPrivKey = (loginPrivKey == null ? null : loginPrivKey.clone());
|
||||
if (this.ws == null) throw new IllegalArgumentException("ws == null");
|
||||
if (this.state == null) throw new IllegalArgumentException("state == null");
|
||||
if (this.loginPrivKey == null) throw new IllegalArgumentException("loginPrivKey == null");
|
||||
}
|
||||
|
||||
@ -97,7 +102,7 @@ public final class AddBlockSender {
|
||||
|
||||
String serverLastHash = JsonMini.extractPayloadString(resp, "serverLastBlockHash");
|
||||
if (serverLastHash == null) {
|
||||
// на случай старого имени, но по твоей просьбе мы на это больше не опираемся
|
||||
// на всякий случай, но ты говорил старое не поддерживаем — оставил мягко
|
||||
serverLastHash = JsonMini.extractPayloadString(resp, "serverLastGlobalHash");
|
||||
}
|
||||
|
||||
@ -113,13 +118,13 @@ public final class AddBlockSender {
|
||||
|
||||
assertEquals(localHashHex, serverLastHash, op + ": serverLastBlockHash must match local hash");
|
||||
|
||||
// фиксируем в state глобальную цепочку + (если нужно) line-state по TYPE
|
||||
state.applyAppendedBlock(blockNumber, entry.getHash32(), isHeader, type);
|
||||
|
||||
// если это line-body — обновим thisLineNumber в state (для nextLine())
|
||||
// если это line-body — обновим thisLineNumber в state (для nextLineByType())
|
||||
if (body instanceof BodyHasLine hl) {
|
||||
short lineIndex = lineIndexByType(type);
|
||||
if (lineIndex != -1) {
|
||||
state.applyThisLineNumber(lineIndex, hl.thisLineNumber());
|
||||
if (ChainState.isLineType(type)) {
|
||||
state.applyThisLineNumberByType(type, hl.thisLineNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,15 +224,4 @@ public final class AddBlockSender {
|
||||
|
||||
return bb.array();
|
||||
}
|
||||
|
||||
private static short lineIndexByType(short type) {
|
||||
int t = type & 0xFFFF;
|
||||
return switch (t) {
|
||||
case 0 -> blockchain.LineIndex.HEADER;
|
||||
case 1 -> blockchain.LineIndex.TEXT;
|
||||
case 3 -> blockchain.LineIndex.CONNECTION;
|
||||
case 4 -> blockchain.LineIndex.USER_PARAM;
|
||||
default -> (short) -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,29 +1,36 @@
|
||||
package test.it.blockchain;
|
||||
|
||||
import blockchain.LineIndex;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ChainState — состояние цепочки + состояние линий (только тех, где они нужны):
|
||||
* ChainState — состояние глобальной цепочки + состояние линий (только тех, где они нужны).
|
||||
*
|
||||
* Глобальная цепочка:
|
||||
* - lastBlockNumber / lastBlockHashHex
|
||||
* - map blockNumber -> hash32 (для ссылок reply/edit/reaction)
|
||||
*
|
||||
* Линии (по ТЗ нужны):
|
||||
* - TEXT (1)
|
||||
* - CONNECTION (3)
|
||||
* - USER_PARAM (4)
|
||||
* Линии по ТЗ нужны только для:
|
||||
* - TEXT (type=1)
|
||||
* - CONNECTION (type=3)
|
||||
* - USER_PARAM (type=4)
|
||||
*
|
||||
* prevLineNumber по ТЗ — это GLOBAL blockNumber предыдущего блока линии.
|
||||
* thisLineNumber — внутренний номер линии (мы ведём локально: 1,2,3...)
|
||||
*
|
||||
* ВАЖНО:
|
||||
* - Здесь НЕТ обращения к blockchain.LineIndex.
|
||||
* - Линии адресуются по msg_type (type).
|
||||
*/
|
||||
public final class ChainState {
|
||||
|
||||
public static final int LINES_MAX = 8;
|
||||
// какие msg_type имеют линейную цепочку по ТЗ
|
||||
public static final short TYPE_HEADER = 0;
|
||||
public static final short TYPE_TEXT = 1;
|
||||
public static final short TYPE_REACTION = 2;
|
||||
public static final short TYPE_CONNECTION = 3;
|
||||
public static final short TYPE_USER_PARAM = 4;
|
||||
|
||||
private static final byte[] ZERO32 = new byte[32];
|
||||
private static final String ZERO64 = "0".repeat(64);
|
||||
@ -35,17 +42,34 @@ public final class ChainState {
|
||||
// header (block#0)
|
||||
private byte[] headerHash32 = null;
|
||||
|
||||
// per-line state (только для LineIndex.TEXT/CONNECTION/USER_PARAM)
|
||||
private final int[] lineLastGlobalNumber = new int[LINES_MAX]; // последний GLOBAL номер блока в линии
|
||||
private final String[] lineLastHashHex = new String[LINES_MAX]; // hash последнего блока линии
|
||||
private final int[] lineLastThisLineNumber = new int[LINES_MAX]; // последний thisLineNumber (внутренний)
|
||||
/**
|
||||
* line state per TYPE (только для TEXT/CONNECTION/USER_PARAM):
|
||||
* - lastGlobalNumber: последний GLOBAL blockNumber в линии
|
||||
* - lastHashHex: hash последнего блока линии
|
||||
* - lastThisLineNumber: последний thisLineNumber (внутренний)
|
||||
*/
|
||||
private static final class LineState {
|
||||
int lastGlobalNumber = -1;
|
||||
String lastHashHex = "";
|
||||
int lastThisLineNumber = 0;
|
||||
|
||||
void reset() {
|
||||
lastGlobalNumber = -1;
|
||||
lastHashHex = "";
|
||||
lastThisLineNumber = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final LineState textLine = new LineState();
|
||||
private final LineState connectionLine = new LineState();
|
||||
private final LineState userParamLine = new LineState();
|
||||
|
||||
private final Map<Integer, byte[]> hash32ByNumber = new HashMap<>();
|
||||
|
||||
public ChainState() {
|
||||
Arrays.fill(lineLastGlobalNumber, -1);
|
||||
Arrays.fill(lineLastHashHex, "");
|
||||
Arrays.fill(lineLastThisLineNumber, 0);
|
||||
textLine.reset();
|
||||
connectionLine.reset();
|
||||
userParamLine.reset();
|
||||
}
|
||||
|
||||
// -------------------- global getters --------------------
|
||||
@ -89,30 +113,33 @@ public final class ChainState {
|
||||
}
|
||||
}
|
||||
|
||||
/** Следующие line-поля для указанной линии (только TEXT/CONNECTION/USER_PARAM). */
|
||||
public NextLine nextLine(short lineIndex) {
|
||||
checkLine(lineIndex);
|
||||
if (!isLineUsed(lineIndex)) {
|
||||
throw new IllegalArgumentException("Line " + lineIndex + " не используется для BodyHasLine по ТЗ");
|
||||
/** Является ли type "линейным" по ТЗ (т.е. нужно вести prevLine/thisLine). */
|
||||
public static boolean isLineType(short type) {
|
||||
int t = type & 0xFFFF;
|
||||
return t == TYPE_TEXT || t == TYPE_CONNECTION || t == TYPE_USER_PARAM;
|
||||
}
|
||||
|
||||
/** Следующие line-поля для указанного TYPE (только TEXT/CONNECTION/USER_PARAM). */
|
||||
public NextLine nextLineByType(short type) {
|
||||
if (!isLineType(type)) {
|
||||
throw new IllegalArgumentException("Type " + (type & 0xFFFF) + " не использует line-поля по ТЗ");
|
||||
}
|
||||
if (!hasHeader()) {
|
||||
throw new IllegalStateException("Нельзя формировать line-поля до HEADER (нет headerHash32)");
|
||||
}
|
||||
|
||||
int lastGlobal = lineLastGlobalNumber[lineIndex];
|
||||
int lastThis = lineLastThisLineNumber[lineIndex];
|
||||
LineState ls = lineStateByType(type);
|
||||
|
||||
if (lastGlobal == -1) {
|
||||
if (ls.lastGlobalNumber == -1) {
|
||||
// первый блок линии ссылается на HEADER (block#0)
|
||||
return new NextLine(0, headerHash32.clone(), 1);
|
||||
}
|
||||
|
||||
String lastHex = lineLastHashHex[lineIndex];
|
||||
if (lastHex == null || lastHex.isBlank()) {
|
||||
throw new IllegalStateException("lineLastHashHex[" + lineIndex + "] пуст, но lastGlobal!=-1");
|
||||
if (ls.lastHashHex == null || ls.lastHashHex.isBlank()) {
|
||||
throw new IllegalStateException("LineState.lastHashHex пуст, но lastGlobalNumber!=-1 (type=" + (type & 0xFFFF) + ")");
|
||||
}
|
||||
|
||||
return new NextLine(lastGlobal, hexToBytes32(lastHex), lastThis + 1);
|
||||
return new NextLine(ls.lastGlobalNumber, hexToBytes32(ls.lastHashHex), ls.lastThisLineNumber + 1);
|
||||
}
|
||||
|
||||
// -------------------- apply --------------------
|
||||
@ -140,52 +167,32 @@ public final class ChainState {
|
||||
|
||||
hash32ByNumber.put(blockNumber, hash32.clone());
|
||||
|
||||
// обновляем line-state только для линий, которые "надо" по ТЗ
|
||||
short lineIndex = lineIndexByType(type);
|
||||
if (lineIndex != -1 && isLineUsed(lineIndex)) {
|
||||
lineLastGlobalNumber[lineIndex] = blockNumber;
|
||||
lineLastHashHex[lineIndex] = hex64;
|
||||
|
||||
// thisLineNumber мы берём из тела, но здесь его нет.
|
||||
// Поэтому thisLineNumber должен обновляться там, где формируются тела (в тестах),
|
||||
// либо AddBlockSender может прокинуть его отдельно.
|
||||
// Чтобы не дублировать контракт — здесь оставляем как есть.
|
||||
// обновляем line-state только если этот type по ТЗ линейный
|
||||
if (isLineType(type)) {
|
||||
LineState ls = lineStateByType(type);
|
||||
ls.lastGlobalNumber = blockNumber;
|
||||
ls.lastHashHex = hex64;
|
||||
// thisLineNumber обновляется отдельным вызовом (см. applyThisLineNumberByType)
|
||||
}
|
||||
}
|
||||
|
||||
/** В тестах удобно явно обновлять thisLineNumber после успешной отправки line-body. */
|
||||
public void applyThisLineNumber(short lineIndex, int thisLineNumber) {
|
||||
checkLine(lineIndex);
|
||||
if (!isLineUsed(lineIndex)) return;
|
||||
lineLastThisLineNumber[lineIndex] = thisLineNumber;
|
||||
public void applyThisLineNumberByType(short type, int thisLineNumber) {
|
||||
if (!isLineType(type)) return;
|
||||
LineState ls = lineStateByType(type);
|
||||
ls.lastThisLineNumber = thisLineNumber;
|
||||
}
|
||||
|
||||
// -------------------- mapping --------------------
|
||||
|
||||
/** По type блока определяем lineIndex. Reaction line по твоему ТЗ "не надо". */
|
||||
private static short lineIndexByType(short type) {
|
||||
private LineState lineStateByType(short type) {
|
||||
int t = type & 0xFFFF;
|
||||
return switch (t) {
|
||||
case 0 -> LineIndex.HEADER;
|
||||
case 1 -> LineIndex.TEXT;
|
||||
case 3 -> LineIndex.CONNECTION;
|
||||
case 4 -> LineIndex.USER_PARAM;
|
||||
default -> (short) -1; // reaction/unknown => line state not used
|
||||
case TYPE_TEXT -> textLine;
|
||||
case TYPE_CONNECTION -> connectionLine;
|
||||
case TYPE_USER_PARAM -> userParamLine;
|
||||
default -> throw new IllegalArgumentException("Type " + t + " не имеет LineState по ТЗ");
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isLineUsed(short lineIndex) {
|
||||
return lineIndex == LineIndex.TEXT
|
||||
|| lineIndex == LineIndex.CONNECTION
|
||||
|| lineIndex == LineIndex.USER_PARAM;
|
||||
}
|
||||
|
||||
private static void checkLine(short lineIndex) {
|
||||
if (lineIndex < 0 || lineIndex >= LINES_MAX) {
|
||||
throw new IllegalArgumentException("lineIndex must be 0.." + (LINES_MAX - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- utils --------------------
|
||||
|
||||
private static byte[] hexToBytes32(String hex) {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package test.it.cases;
|
||||
|
||||
import blockchain.LineIndex;
|
||||
import blockchain.body.*;
|
||||
import blockchain.MsgSubType;
|
||||
import test.it.blockchain.AddBlockSender;
|
||||
@ -16,6 +15,10 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* IT_03_AddBlock_NoAuth — обновлён под новый формат блоков (ТЗ).
|
||||
*
|
||||
* ВАЖНО:
|
||||
* - НЕТ обращения к blockchain.LineIndex (можно удалить LineIndex.java).
|
||||
* - Линии берём через ChainState.nextLineByType(TYPE_...).
|
||||
*/
|
||||
public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
@ -59,7 +62,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// TEXT_NEW x3 (с line)
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.TEXT);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_TEXT);
|
||||
sender1.send(new TextBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.TEXT_NEW,
|
||||
"Hello #1 (NEW) from IT_03 test",
|
||||
@ -67,7 +70,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
), t);
|
||||
}
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.TEXT);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_TEXT);
|
||||
sender1.send(new TextBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.TEXT_NEW,
|
||||
"Hello #2 (NEW) from IT_03 test",
|
||||
@ -75,7 +78,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
), t);
|
||||
}
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.TEXT);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_TEXT);
|
||||
sender1.send(new TextBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.TEXT_NEW,
|
||||
"Hello #3 (NEW) from IT_03 test",
|
||||
@ -92,7 +95,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// TEXT_REPLY x2 (с line + target)
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.TEXT);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_TEXT);
|
||||
sender1.send(new TextBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.TEXT_REPLY,
|
||||
"Reply to TEXT#1",
|
||||
@ -100,7 +103,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
), t);
|
||||
}
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.TEXT);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_TEXT);
|
||||
sender1.send(new TextBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.TEXT_REPLY,
|
||||
"Reply to TEXT#3",
|
||||
@ -114,7 +117,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// TEXT_EDIT x3 (с line + target)
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.TEXT);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_TEXT);
|
||||
sender1.send(new TextBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.TEXT_EDIT,
|
||||
"Hello #2 (EDIT#1) from IT_03 test",
|
||||
@ -122,7 +125,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
), t);
|
||||
}
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.TEXT);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_TEXT);
|
||||
sender1.send(new TextBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.TEXT_EDIT,
|
||||
"Hello #2 (EDIT#2) from IT_03 test",
|
||||
@ -130,7 +133,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
), t);
|
||||
}
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.TEXT);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_TEXT);
|
||||
sender1.send(new TextBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.TEXT_EDIT,
|
||||
"Hello #3 (EDIT#1) from IT_03 test",
|
||||
@ -149,7 +152,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// USER_PARAM (с line)
|
||||
{
|
||||
var ln = st2.nextLine(LineIndex.USER_PARAM);
|
||||
var ln = st2.nextLineByType(ChainState.TYPE_USER_PARAM);
|
||||
sender2.send(new UserParamBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
"Anya", "Amsterdam, Example street 10"
|
||||
), t);
|
||||
@ -171,7 +174,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// u1 -> follow u2
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.CONNECTION);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_CONNECTION);
|
||||
sender1.send(new ConnectionBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.CONNECTION_FOLLOW,
|
||||
u2, bch2, 0, new byte[32]
|
||||
@ -180,7 +183,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// u1 -> follow u3
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.CONNECTION);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_CONNECTION);
|
||||
sender1.send(new ConnectionBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.CONNECTION_FOLLOW,
|
||||
u3, bch3, 0, new byte[32]
|
||||
@ -189,7 +192,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// u2 -> follow u1
|
||||
{
|
||||
var ln = st2.nextLine(LineIndex.CONNECTION);
|
||||
var ln = st2.nextLineByType(ChainState.TYPE_CONNECTION);
|
||||
sender2.send(new ConnectionBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.CONNECTION_FOLLOW,
|
||||
u1, bch1, 0, new byte[32]
|
||||
@ -198,7 +201,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// friend/unfriend как было, но тоже по CONNECTION линии
|
||||
{
|
||||
var ln = st2.nextLine(LineIndex.CONNECTION);
|
||||
var ln = st2.nextLineByType(ChainState.TYPE_CONNECTION);
|
||||
sender2.send(new ConnectionBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.CONNECTION_FRIEND,
|
||||
u1, bch1, 0, new byte[32]
|
||||
@ -207,13 +210,13 @@ public class IT_03_AddBlock_NoAuth {
|
||||
|
||||
// user1 param + friend to u2
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.USER_PARAM);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_USER_PARAM);
|
||||
sender1.send(new UserParamBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
"Anna", "Gareeva"
|
||||
), t);
|
||||
}
|
||||
{
|
||||
var ln = st1.nextLine(LineIndex.CONNECTION);
|
||||
var ln = st1.nextLineByType(ChainState.TYPE_CONNECTION);
|
||||
sender1.send(new ConnectionBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.CONNECTION_FRIEND,
|
||||
u2, bch2, 0, new byte[32]
|
||||
@ -221,7 +224,7 @@ public class IT_03_AddBlock_NoAuth {
|
||||
}
|
||||
|
||||
{
|
||||
var ln = st2.nextLine(LineIndex.CONNECTION);
|
||||
var ln = st2.nextLineByType(ChainState.TYPE_CONNECTION);
|
||||
sender2.send(new ConnectionBody(ln.prevLineNumber, ln.prevLineHash32, ln.thisLineNumber,
|
||||
MsgSubType.CONNECTION_UNFRIEND,
|
||||
u1, bch1, 0, new byte[32]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user