15 01 25
Добавил мелких доп проверок (Все тесты тесты проходят)
This commit is contained in:
parent
bbca821dcd
commit
b69075cbac
@ -37,6 +37,18 @@ public final class BchBlockEntry {
|
|||||||
public static final int SIGNATURE_LEN = 64;
|
public static final int SIGNATURE_LEN = 64;
|
||||||
public static final int HASH_LEN = 32;
|
public static final int HASH_LEN = 32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Максимальный допустимый размер блока (preimage+signature), чтобы не уложить сервер по памяти/диску.
|
||||||
|
* 4 МБ — нормальный “потолок” под тексты/метаданные, и при этом защищает от мусора/атаки.
|
||||||
|
*/
|
||||||
|
public static final int MAX_BLOCK_FULL_BYTES = 4 * 1024 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Насколько блок может “обгонять” текущее время (защита от кривых часов/вбросов).
|
||||||
|
* Если timestamp больше now + 60 сек — блок считаем неверным.
|
||||||
|
*/
|
||||||
|
public static final long MAX_FUTURE_SECONDS = 60;
|
||||||
|
|
||||||
/** Размер фиксированного RAW-заголовка без body */
|
/** Размер фиксированного RAW-заголовка без body */
|
||||||
public static final int RAW_HEADER_SIZE =
|
public static final int RAW_HEADER_SIZE =
|
||||||
32 // prevHash32
|
32 // prevHash32
|
||||||
@ -80,6 +92,9 @@ public final class BchBlockEntry {
|
|||||||
if (fullBytes.length < RAW_HEADER_SIZE + SIGNATURE_LEN) {
|
if (fullBytes.length < RAW_HEADER_SIZE + SIGNATURE_LEN) {
|
||||||
throw new IllegalArgumentException("Block too short");
|
throw new IllegalArgumentException("Block too short");
|
||||||
}
|
}
|
||||||
|
if (fullBytes.length > MAX_BLOCK_FULL_BYTES) {
|
||||||
|
throw new IllegalArgumentException("Block too large: " + fullBytes.length + " > " + MAX_BLOCK_FULL_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
ByteBuffer bb = ByteBuffer.wrap(fullBytes).order(ByteOrder.BIG_ENDIAN);
|
ByteBuffer bb = ByteBuffer.wrap(fullBytes).order(ByteOrder.BIG_ENDIAN);
|
||||||
|
|
||||||
@ -93,10 +108,19 @@ public final class BchBlockEntry {
|
|||||||
if (blockSize + SIGNATURE_LEN != fullBytes.length) {
|
if (blockSize + SIGNATURE_LEN != fullBytes.length) {
|
||||||
throw new IllegalArgumentException("blockSize mismatch: blockSize=" + blockSize + " fullLen=" + fullBytes.length);
|
throw new IllegalArgumentException("blockSize mismatch: blockSize=" + blockSize + " fullLen=" + fullBytes.length);
|
||||||
}
|
}
|
||||||
|
if (blockSize + SIGNATURE_LEN > MAX_BLOCK_FULL_BYTES) {
|
||||||
|
throw new IllegalArgumentException("Block too large by blockSize: " + (blockSize + SIGNATURE_LEN) + " > " + MAX_BLOCK_FULL_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
this.blockNumber = bb.getInt();
|
this.blockNumber = bb.getInt();
|
||||||
this.timestamp = bb.getLong();
|
this.timestamp = bb.getLong();
|
||||||
|
|
||||||
|
// запрет “в будущее” больше чем на 1 минуту
|
||||||
|
long now = Instant.now().getEpochSecond();
|
||||||
|
if (this.timestamp > now + MAX_FUTURE_SECONDS) {
|
||||||
|
throw new IllegalArgumentException("timestamp is too far in future: ts=" + this.timestamp + " now=" + now + " maxFutureSec=" + MAX_FUTURE_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
this.type = bb.getShort();
|
this.type = bb.getShort();
|
||||||
this.subType = bb.getShort();
|
this.subType = bb.getShort();
|
||||||
this.version = bb.getShort();
|
this.version = bb.getShort();
|
||||||
@ -116,7 +140,7 @@ public final class BchBlockEntry {
|
|||||||
// hash32 = sha256(preimage)
|
// hash32 = sha256(preimage)
|
||||||
this.hash32 = BchCryptoVerifier.sha256(preimage);
|
this.hash32 = BchCryptoVerifier.sha256(preimage);
|
||||||
|
|
||||||
// parse body по header.type/subType/version
|
// parse body по header.type/subType/version + ОБЯЗАТЕЛЬНЫЙ check()
|
||||||
this.body = BodyRecordParser.parse(this.type, this.subType, this.version, this.bodyBytes);
|
this.body = BodyRecordParser.parse(this.type, this.subType, this.version, this.bodyBytes);
|
||||||
|
|
||||||
this.fullBytes = Arrays.copyOf(fullBytes, fullBytes.length);
|
this.fullBytes = Arrays.copyOf(fullBytes, fullBytes.length);
|
||||||
@ -147,6 +171,12 @@ public final class BchBlockEntry {
|
|||||||
if (prevHash32.length != 32) throw new IllegalArgumentException("prevHash32 != 32");
|
if (prevHash32.length != 32) throw new IllegalArgumentException("prevHash32 != 32");
|
||||||
if (signature64.length != SIGNATURE_LEN) throw new IllegalArgumentException("signature64 != 64");
|
if (signature64.length != SIGNATURE_LEN) throw new IllegalArgumentException("signature64 != 64");
|
||||||
|
|
||||||
|
// запрет “в будущее” больше чем на 1 минуту
|
||||||
|
long now = Instant.now().getEpochSecond();
|
||||||
|
if (timestamp > now + MAX_FUTURE_SECONDS) {
|
||||||
|
throw new IllegalArgumentException("timestamp is too far in future: ts=" + timestamp + " now=" + now + " maxFutureSec=" + MAX_FUTURE_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
this.prevHash32 = Arrays.copyOf(prevHash32, 32);
|
this.prevHash32 = Arrays.copyOf(prevHash32, 32);
|
||||||
this.blockNumber = blockNumber;
|
this.blockNumber = blockNumber;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
@ -158,7 +188,12 @@ public final class BchBlockEntry {
|
|||||||
|
|
||||||
this.blockSize = RAW_HEADER_SIZE + this.bodyBytes.length;
|
this.blockSize = RAW_HEADER_SIZE + this.bodyBytes.length;
|
||||||
|
|
||||||
// parse body по header
|
int fullLen = this.blockSize + SIGNATURE_LEN;
|
||||||
|
if (fullLen > MAX_BLOCK_FULL_BYTES) {
|
||||||
|
throw new IllegalArgumentException("Block too large: " + fullLen + " > " + MAX_BLOCK_FULL_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse body по header + ОБЯЗАТЕЛЬНЫЙ check()
|
||||||
this.body = BodyRecordParser.parse(this.type, this.subType, this.version, this.bodyBytes);
|
this.body = BodyRecordParser.parse(this.type, this.subType, this.version, this.bodyBytes);
|
||||||
|
|
||||||
// build preimage
|
// build preimage
|
||||||
|
|||||||
@ -17,7 +17,7 @@ public final class BodyRecordParser {
|
|||||||
// ключ = (type<<16)|version (как раньше по смыслу), но берём из HEADER
|
// ключ = (type<<16)|version (как раньше по смыслу), но берём из HEADER
|
||||||
int key = (t << 16) | v;
|
int key = (t << 16) | v;
|
||||||
|
|
||||||
return switch (key) {
|
BodyRecord r = switch (key) {
|
||||||
case HeaderBody.KEY -> new HeaderBody(subType, version, bodyBytes);
|
case HeaderBody.KEY -> new HeaderBody(subType, version, bodyBytes);
|
||||||
case TextBody.KEY -> new TextBody(subType, version, bodyBytes);
|
case TextBody.KEY -> new TextBody(subType, version, bodyBytes);
|
||||||
case ReactionBody.KEY -> new ReactionBody(subType, version, bodyBytes);
|
case ReactionBody.KEY -> new ReactionBody(subType, version, bodyBytes);
|
||||||
@ -28,5 +28,9 @@ public final class BodyRecordParser {
|
|||||||
t, v, (subType & 0xFFFF)
|
t, v, (subType & 0xFFFF)
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 1) “построили” объект
|
||||||
|
// 2) ОБЯЗАТЕЛЬНО прогнали валидацию
|
||||||
|
return r.check();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user