Skip to content

Conversation

@lu-pinto
Copy link
Member

@lu-pinto lu-pinto commented Mar 4, 2025

PR description

This PR simplifies the Tuweni class hierarchy of the bytes project and attempts to get some performance gains by reducing memory churn, specially for copying byte arrays and Bytes instances. Bytes have now a much flatter class hierarchy that will hopefully improve inlining and reduce time on itable lookups which was identified as one of the problems in Besu for low performance. The implementation of Bytes used at runtime is now highly biased towards ArrayWrappingBytes which makes it easier for JIT to inline and optimize.

Also mutable operations wil be moved into MutableBytes exclusively to show intention in copies. This avoids copies on sequences of logic operations, e.g. MutableBytes.create(10).or(Bytes.fromHex("0x11")).shiftRight(2) no further copies occur after initial instance creation.
Other Bytes subtypes should be immutable from now on to boost performance.


Note

Adds new v2 modules for DevP2P (incl. Discovery v5), RLP/SSZ encodings, IO/TLS utilities, and unsigned big-integer types with comprehensive tests.

  • New v2 libraries and protocols:
    • DevP2P (discv4/v5): Adds Endpoint, ENR parsing/validation (EthereumNodeRecord), packet/message types, peers/repository/routing table, and a Vert.x-based Discovery v5 service with handshake, session encryption (AES-GCM/HKDF), and topic table.
    • Encoding/Serialization: Introduces v2 RLP (reader/writer/bytes/bytebuffer) and SSZ (reader/writer, fixed/variable lists, hash tree root) implementations with comprehensive tests.
    • Crypto/IO Utilities: Adds Base32/Base58/Base64(URL-safe) helpers; TLS utilities with fingerprint repositories and trust managers.
    • Big integers: Adds v2 UInt32, UInt64, UInt256, UInt384 with arithmetic/bit ops and tests.
    • Extensive tests across new modules ensuring encode/decode, protocol messages, discovery interactions, and cryptographic primitives.

Written by Cursor Bugbot for commit ad67e19. This will update automatically on new commits. Configure here.

@github-actions
Copy link

github-actions bot commented Mar 4, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@lu-pinto
Copy link
Member Author

lu-pinto commented Mar 4, 2025

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Mar 4, 2025
@lu-pinto
Copy link
Member Author

lu-pinto commented Mar 4, 2025

recheck

@lu-pinto lu-pinto force-pushed the flatten-Bytes-class-hierarchy branch 2 times, most recently from 81cb3e2 to 46f5de9 Compare March 6, 2025 13:33
@lu-pinto lu-pinto force-pushed the flatten-Bytes-class-hierarchy branch from 0625d27 to 2dbda56 Compare March 12, 2025 16:36
@lu-pinto lu-pinto closed this Apr 4, 2025
@lu-pinto lu-pinto reopened this Apr 4, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Apr 4, 2025
@lu-pinto lu-pinto marked this pull request as draft April 8, 2025 15:23
@lu-pinto lu-pinto force-pushed the flatten-Bytes-class-hierarchy branch from 1b4e159 to 8a24b0e Compare May 21, 2025 12:54
@lu-pinto
Copy link
Member Author

lu-pinto commented May 21, 2025

After this comment I will make this PR ready to be pulled in without stopping any development on Tuweni v1 as I'm leaving the current org.apache.tuweni namespace untouched.

I will squash all changes so far and will create an entire new package org.apache.tuweni.v2 which contains the new class hierarchy for Tuweni along with all of its dependents.

@lu-pinto lu-pinto force-pushed the flatten-Bytes-class-hierarchy branch from 8a24b0e to 1c641ff Compare May 22, 2025 12:49
@lu-pinto
Copy link
Member Author

recheck

@lu-pinto lu-pinto marked this pull request as ready for review May 22, 2025 13:25
@Consensys Consensys unlocked this conversation May 22, 2025
@lu-pinto lu-pinto force-pushed the flatten-Bytes-class-hierarchy branch 2 times, most recently from cc29c50 to dff599a Compare May 22, 2025 13:43
Copy link

@macfarla macfarla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to add a consensys copyright statement? Are both v1 and v2 tests running?

@github-actions
Copy link

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions
Copy link

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions github-actions bot added the Stale label Sep 19, 2025
@macfarla macfarla removed the Stale label Sep 25, 2025
@github-actions
Copy link

github-actions bot commented Oct 9, 2025

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions github-actions bot added the Stale label Oct 9, 2025
@github-actions
Copy link

Closed as inactive. Feel free to reopen if this PR is still being worked on.

@github-actions github-actions bot closed this Oct 23, 2025
@macfarla macfarla reopened this Oct 30, 2025
@macfarla macfarla removed the Stale label Oct 30, 2025
result[i] = this.ints[i] & other;
}
return new UInt256(result);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Bitwise Operation Errors in UInt Classes

The and, or, and xor methods in both UInt256 and UInt384 classes contain a byte indexing error when operating on Bytes or Bytes32 parameters. The byte offset calculation incorrectly uses the ints array index (i) instead of the bytes parameter index (j), leading to incorrect bitwise results and potential IndexOutOfBoundsException.

Additional Locations (4)

Fix in Cursor Fix in Web

fun create(keyPair: SECP256K1.KeyPair, now: Long): Packet {
val expiration = expirationFor(now)
val sigHash = createSignature(
PacketType.ENRRESPONSE,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Packet Signature Mismatch Causes Verification Failures

The ENRRequestPacket.create() method uses PacketType.ENRRESPONSE for the packet signature. This is inconsistent with the encode() method's use of PacketType.ENRREQUEST and will cause signature verification failures for ENRRequest packets.

Fix in Cursor Fix in Web

try {
SHA256Hash.Hash result = SHA256Hash.hash(shaInput);
try {
return SHA256Hash.hash(shaInput).bytes();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Double Hashing Causes Memory Leak

The sha2_256 methods (both byte[] and Bytes overloads) compute the hash twice when Sodium is available. The first hash object is stored and destroyed, but a new hash object is created and returned from a second computation, which is then leaked.

Additional Locations (1)

Fix in Cursor Fix in Web

@github-actions
Copy link

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions github-actions bot added the Stale label Nov 13, 2025
checkElementIndex(offset, bytes.length);
}
checkLength(bytes, offset);
return new ArrayWrappingBytes(bytes, offset, bytes.length);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Array Wrapper Overruns Bounds: Incorrect Length

The fromArray method creates an ArrayWrappingBytes with bytes.length as the length parameter, which attempts to wrap more bytes than available when offset > 0. This causes the wrapper to extend beyond the array bounds. The length should be SIZE (32 bytes) to correctly wrap exactly 32 bytes starting from the offset, matching the method's documented behavior and the validation performed by checkLength.

Fix in Cursor Fix in Web

@Override
public void appendTo(ByteBuffer byteBuffer) {
byteBuffer.put(this.byteBuffer);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Append Ignores Slice Boundaries

The appendTo method puts the entire byteBuffer into the target buffer, ignoring the offset and size() of this wrapper. When a ByteBufferWrappingBytes represents a slice (constructed with offset and length), this appends the wrong bytes. The method transfers from the buffer's current position/limit rather than the intended slice range defined by offset and size().

Fix in Cursor Fix in Web

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's not a bug

@lu-pinto lu-pinto force-pushed the flatten-Bytes-class-hierarchy branch from ad67e19 to a4def2a Compare November 13, 2025 14:31
@github-actions github-actions bot removed the Stale label Nov 14, 2025
private static final int SIZE = 32;

/** A {@code Bytes32} containing all zero bytes */
public static final Bytes ZERO = fromByte((byte) 0);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Type Mismatch: ZERO Constant Threatens Integrity

The ZERO constant is declared as type Bytes instead of Bytes32, causing a type inconsistency. The javadoc states it's a Bytes32 containing all zero bytes, but the actual type doesn't match. This breaks type safety and could cause issues when code expects a Bytes32 instance but receives a generic Bytes reference.

Fix in Cursor Fix in Web

public static final int SIZE = 48;

/** A {@code Bytes48} containing all zero bytes */
public static final Bytes ZERO = fromByte((byte) 0);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: ZERO Constant: Type Inconsistency Threatens Safety

The ZERO constant is declared as type Bytes instead of Bytes48, causing a type inconsistency. The javadoc states it's a Bytes48 containing all zero bytes, but the actual type doesn't match. This breaks type safety and could cause issues when code expects a Bytes48 instance but receives a generic Bytes reference.

Fix in Cursor Fix in Web

byte[] newBytesArray = new byte[otherSize];
System.arraycopy(bytesArray, 0, newBytesArray, otherSize - size, size);
bytesArray = newBytesArray;
size = otherSize;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Immutability Contract Violated: Stale Hashcodes

The and, or, and xor methods mutate the size field after object construction when resizing the internal array. Since size is inherited from the immutable parent Bytes class and used for hashcode caching, this mutation breaks the immutability contract and can cause cached hashcodes to become stale, leading to incorrect behavior in hash-based collections.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants