This Research and Development technical paper is created to help alleviate some bottlenecks within and during the light client server build for Teku.
Problems & Solutions ordered top-down from recent-to-oldest
Function return Array.from(pubkeys).map((pk) => PublicKey.fromBytes(pk.valueOf() as Uint8Array));
in Typescript for DeserializePubKeys
function needs to be converted into Java.
- Refactor function
- Function
@Override
public Foo getFoo() {
return new Fizz();
}
@Override
public Foo getAnotherFoo() {
return new Buzz();
}
might give a clue as to the solution.
- Importing
Array
fromjava.lang.reflect
partially solved issue. - Refactoring return method
Array.from
intoArray.get
orArray.set
partially solved issue.
pubkeys
function withinArray.set(pubkeys)
method insufficient. Error: 'set(java.lang.Object, int, java.lang.Object)' in 'java.lang.reflect.Array' cannot be applied to '(tech.pegasys.teku.lightclient.client.LightClientUpdate)'. Possibly change pubkeys function?
- Changed
SszPublicKey
intoPublicKey
, insufficient.
PublicKey
function needs to be converted into an object.Rectangle rectOne = new Rectangle(originOne, 100, 200);
function Object might have clue.
PublicKey pubkeys = new PublicKey(Object null, int 100)
function insufficient.return Array.get()
withoutpublickeys
insufficient, might have to reangle direction of refactoring.
Array.prototype.map()
seems like the only best resolution.
return Array.prototype.map();
insufficient
Object[] mapped = in.stream().map(e -> doMap(e)).toArray();
might provide clue.
Object[] mapped = Arrays.stream(pubkeys)
partially solved issue,pubkeys
still returning error.Object[] mapped = Arrays.stream(new PublicKey[]{pubkeys})
solved 'pubkeys' issue.
- In TypeScript,
var MakePoint = () => 1;
is the same asvar MakePoint = function () { return 1; };
, converting it into Java will mean creating a simple function.
- Function
function(pk){PublicKey.fromBytes(pk.valueOf() as Uint8Array)};
insufficient. - Removing
{}
Brackets insufficient.
TBD (To Be Determined)
Function altair.LightClientUpdate["nextSyncCommittee"]["pubkeys"]
in Typescript needs to be converted into Java.
- Refactor function
- Creating
pubkeys.LightClientUpdate pubkeys;
insufficient.
- This function example might work:
B b;
b = new B();
b.doSomething();
- Implemented:
private LightClientUpdate pubkeys;
pubkeys = new void LightClientUpdate();
not sufficient.
- Possibly
return Array.from(pubkeys).map((pk) => PublicKey.fromBytes(pk.valueOf() as Uint8Array));
function in Typescript could be clue to overall solution...
- Changed
public interface DeserializePubkeys extends PublicKey
function intopublic class DeserializePubkeys
, insufficient. - Implemented
private LightClientUpdate["syncCommittee"] pubkeys;
, insufficient. - Implemented
LightClientUpdate pubkeys = example();
, worked...
LightClientUpdate pubkeys = example();
function from above test case solved compiling error, expanding on this new discovery.
- Function:
LightClientUpdate pubkeys = new LightClientUpdate() {
public Bytes48 toBytesCompressed() {
return null;
}
public void forceValidation() throws IllegalArgumentException {
}
public boolean isInGroup() {
return false;
}
public boolean isValid() {
return false;
}
public int hashCode() {
return 0;
}
public boolean equals(Object obj) {
return false;
}
};
Resolved pubkeys
issue. "SyncCommittee" might not be needed.
LightClientUpdate pubkeys = new LightClientUpdate() {
public Bytes48 toBytesCompressed() {
return null;
}
public void forceValidation() throws IllegalArgumentException {
}
public boolean isInGroup() {
return false;
}
public boolean isValid() {
return false;
}
public int hashCode() {
return 0;
}
public boolean equals(Object obj) {
return false;
}
};
"SyncCommittee" might not be needed.
Java having issues returning classes within functions.
- Create separate classes and return them solely?
- Implementing a similar function:
public Engine getEngine() {return new Engine();}
might work.
- Implementing
return new BeaconBlockHeader();
works. - Implementing
return new NodeSlot();
insufficient. - Implementing getters and setters:
NodeSlot block;
NodeSlot getBlock() { return block;}
void setBlock() {this.block = block;}
insufficient.
Created ToBlockHeader
class.
Issue importing .block
from general altair
class from Teku client using these Typescript functions as reference:
slot: block.slot,
proposerIndex: block.proposerIndex,
parentRoot: block.parentRoot,
stateRoot: block.stateRoot,
bodyRoot: ssz.altair.BeaconBlockBody.hashTreeRoot(block.body),
- Find alternate class within client.
- No
BeaconBlock
sole class within Teku client. altair.LightClientUpdate
andaltair.BeaconBlock
have similar instances and a possible solution can be derived from LightClientStore class.
imported NodeSlot
and other corresponding classes to resolve issue.
participantPubkeys.push(pubkeys.get(i));
function within public T[] getParticipantPubkeys()
insufficient.
- Refactor function/s.
- Method cannot be pushed via
T
variable. - The old "GenericArray" problem via Java could be a major diagnosis of this issue...
Created Stack<T> participantPubkeys = new Stack<T>();
.
bits.length
function within for (int i = 0; i < bits.length; i++)
function within public T[] getParticipantPubkeys()
insufficient.
- Refactor function/s.
- Vector Instantiating in Java quite possible for solution.
- Created
Vector<boolean> bits = new Vector<boolean>();
, insufficient.
- Creating a
Vector
within aVector
might work via Stack overflow question.
- Created
Vector<Vector<Boolean>> bits = new Vector<Vector<Boolean>>();
, insufficient. - Added an integer
(100)
toVector
instantiation, insufficient. - Created
List<Integer> bits = new ArrayList<Integer>();
, insufficient.
- Created
int[] bits = new int[100];
which obiously works, only issue is that dependent on the Lodestar Light Client Utils class as reference, theBitVector
is directly correlated toVector<Boolean>
which doesn't translate into an integer array in Java...
Function to convert Vector into Array in Java implemented:
Vector<Boolean> vector = new Vector<Boolean>();
Object[] bits = vector.toArray();
T[]
constant within public T[] getParticipantPubkeys<T> () {}
function insufficient.
- Refactor function/s.
- Typescript Documentation in order to convert constant successfully into Java.
- Typescript Generics.
- Added class to
T[]
function, insufficient. - Refactored
T[]
intoArray<T>
, insufficient.
T[]
constant most likely Generic Array, thus cannot be implemented as Generic Array due to Java constraints.
List<T> pubkeys = new ArrayList<T>();
function creation a possibility.
- Refunction function into
public T[] getParticipantPubkeys()
.
Function: public T[] getParticipantPubkeys()
resolved issue.
rootArray.length
within if (rootArray.length != expectedLength)
from List<Bytes32> rootArray = new ArrayList<Bytes32>();
insufficient.
- Refactor function/s.
- Refactored
public void assertZeroHashes(Bytes32 rootArray, int expectedLength) {
byte[] rootsArray = rootArray.toArray();
Refactored
public void assertZeroHashes(Bytes32 rootArray, int expectedLength) {
byte[] rootsArray = rootArray.toArray();
Function:
public boolean isZeroHash() {
for (int i = 0; i < root.length; i++) {
if (root[i] !== 0) {
return false;
}
}
return true;
}
Refusing to recognize !==
as proper expression for private Bytes32[] root;
.
- Refactor function/s.
- Refactoring
private Bytes32[] root;
intoprivate Bytes32 root[32];
not sufficient. - Refactoring
private Bytes32[] root;
intoprivate Bytes32 root;
not sufficient. - Refactoring
int i = 0; i < root.length; i++
intobyte i = 0; i < root.length; i++
not sufficient.
Researching Primitive Data Types for Java.
- Most developers expect to see an
int
value within Byte functions for 32-bit or 64-bit registers so changingint
intobytes
or any other primitive type will most likely not be sufficient.
- Refactoring
root
intoint[] root = new int[20];
is insufficient as a test case. - Refactoring
root[i] != 0
while keepingroot
intoint[] root = new int[20];
solves!==
operand issue.
!==
operand not sufficient for Java functions, yet!=
cannot be applied toBytes32
.- Interesting...
org.apache.tuweni.bytes.Bytes32
interface has a standard integer of 32.
- Added getters and setters to root function, thus refactors for loop into
for (int i = 0; i < getRoot().length; i++) { if (getRoot(i) != 0) { return false;}
, insufficient.
- Function within
Bytes32
class:
static Bytes32 random(Random generator) {
byte[] array = new byte[32];
generator.nextBytes(array);
return wrap(array);
}
could possibly provide solution, more research to be done.
root.toArray(array);
function created within
static Utilities (Bytes32 root) {
byte[] array = new byte[32];
root.toArray(array);
return array;
}
quite possible to be refactored into isZeroHash()
function.
- Created
byte[] root = new byte[32];
, then refactoredroot[i] != 0
function within if function. Problem likely solved.
Created byte[] root = new byte[32];
, then refactored root[i] != 0
function within if function within 'isZeroHash()` function. Final function:
byte[] root = new byte[32];
public boolean isZeroHash() {
for (int i = 0; i < root.length; i++) {
if (root[i] != 0) {
return false;
}
}
return true;
}
Entire function might need to be refactored (after entire light-client test against Gradle, but for now, it works).
IntelliJ refusing to reveal compilation errors.
- Re-install IntelliJ
Re-Installed, problem not solved
- Redirect Environmental Variables
The default is set to $USER_HOME/.gradle
. It can be overridden in one of the following ways:
You can set the GRADLE_USER_HOME
environment variable (for example, %APPDATA%\.gradle
). For more information, refer to Gradle documentation. The variable's value is picked up automatically. The new path is reflected in the field.
You might need to restart your IDE in order for this change to take effect.
You can specify the location manually: type the location in the path or click the Browse button and in the dialog that opens, select the needed directory.
Manually entered values take precedence over the environment variables.
If the Gradle location is set in Use Gradle from with the Specified location option and its path is defined in the environment variable GRADLE_HOME
or PATH
, IntelliJ IDEA deduces this location and suggests its path as the default value.
Tried implementing /.gradle
, did not work, moving onto other possible solutions
- "Use Gradle from [Specified Location], automatically directs to undesired file, currently trying to implement new re-direction"
.gradle
files report compilation errors, .java
files do not.
Uninstall/delete all Java development kits and reinstall via IntelliJ.
First two Hypotheses were incorrect. The solution was to create an entirely new project using IntelliJ as IntelliJ doesn't coherently absorb projects built by other tools (i.e Eclipse, SpringBoot, etc).
ArrayIntCache<Boolean> bits
function needs to be an array, but is not being accepted as an array.
Full function:
public int sumBits(ArrayIntCache<Boolean> bits) {
int sum = 0;
for (boolean bit: bits) {
if (bit) {
sum++;
}
}
return sum;
}
You can view the source code here:
- Refactor function into array
Recorded in Solution
- Find "ArrayLike" function/class within Teku repo and apply. Reference (in Typescript):
export interface ArrayLike<T> {
[n: number]: T;
readonly length: number;
[Symbol.iterator](): Iterator<T>;
}
Serched:
- Folder: ssz/generator/main
-
- Package: tech.pegasys.teku.ssz
-
-
- Class: ContainersGenerator
-
-
- Package: tech.pegasys.teku.ssz.containers
-
-
- Class: ContainerSchemaTemplate
-
-
-
- Class: ContainerTemplate
-
- Folder: ssz/generator/test
-
- Package: tech.pegasys.teku.ssz.containers
-
-
- Class: GeneratedClassesNotModified
-
- Folder: ssz/main
-
- Package: tech.pegasys.teku.ssz
-
-
- Class: InvalidValueSchemaException
-
-
-
- Class: Merkleizable
-
-
-
- Class: SimpleOffsetSerializable
-
-
-
- Class: SszCollection
-
-
-
- Class: SszComposite
-
-
-
- Class: SszContainer
-
-
-
- Class: SszData <- possibility Tested
-
-
-
- Class: SszList <- possibility Tested
-
-
-
- Class: SszMutableCollection
-
-
-
- Class: SszMutableComposite
-
-
-
- Class: SszMutableContainer
-
-
-
- Class: SszMutableData
-
-
-
- Class: SszMutableList
-
-
-
- Class: SszMutableRefComposite
-
-
-
- Class: SszMutableRefContainer
-
-
-
- Class: SszMutableRefList
-
-
-
- Class: SszMutableRefVector
-
-
-
- Class: szMutableVector
-
-
-
- Class: SszPrimitive
-
-
-
- Class: SszUnion
-
-
-
- Class: SszVector
-
-
- Package: tech.pegasys.teku.ssz.cache
-
-
- Class: ArrayIntCache <- possibility Tested
-
-
-
- Class: Cache <- possibility Tested
-
-
-
- Class: IntCache <- possibility Tested
-
-
-
- Class: NoopIntCache <- possibility Tested
-
-
-
- Class: SoftRefIntCache <- possibility Tested
-
-
- Package: tech.pegasys.teku.ssz.collections
-
-
- Class: SszBitlist
-
-
-
- Class: SszBitvector
-
-
-
- Class: SszByteList <- possibility Tested
-
-
-
- Class: SszBytes32Vector
-
-
-
- Class: SszByteVector
-
-
-
- Class: SszMutableBytes32Vector
-
-
-
- Class: SszMutablePrimitiveCollection
-
-
-
- Class: SszMutablePrimitiveList
-
-
-
- Class: SszMutablePrimitiveVector
-
-
-
- Class: SszUInt64List
-
-
- Package: tech.pegasys.teku.ssz.collections.impl
-
-
- Class: AbstractSszMutablePrimitiveCollection <- possibility Tested
-
-
-
- Class: BitlistImpl
-
-
-
- Class: BitvectorImpl
-
-
-
- Class: SszBitlistImpl <- very strong possibility Tested
-
-
-
- Class: SszBitvectorImpl <- very strong possibility Tested
-
-
-
- Class: SszBytes32VectorImpl <- strong possibility Tested
-
-
-
- Class: SszByteVectorImpl <- strong possibility Tested
-
-
-
- Class: SszMutableBytes32VectorImpl <- strong possibility Tested
-
-
-
- Class: SszMutablePrimitiveListImpl <- possibility Tested
-
-
-
- Class: SszMutablePrimitiveVectorImpl <- possibility Tested
-
-
-
- Class: SszMutableUInt64ListImpl
-
-
-
- Class: SszPrimitiveListImpl
-
-
-
- Class: SszPrimitiveVectorImpl
-
-
-
- Class: SszUInt64ListImpl
-
-
- Package: tech.pegasys.teku.ssz.containers
-
-
- Class: Containers <-all most likely do not need to be checked
-
-
- Package: tech.pegasys.teku.ssz.impl
-
-
- Class: AbstractSszCollection
-
-
-
- Class: AbstractSszComposite
-
-
-
- Class: AbstractSszImmutableContainer
-
-
-
- Class: AbstractSszMutableCollection
-
-
-
- Class: AbstractSszMutableComposite
-
-
-
- Class: AbstractSszPrimitive <- possibility Tested
-
-
-
- Class: SszContainerImpl
-
-
-
- Class: SszListImpl
-
-
-
- Class: SszMutableContainerImpl
-
-
-
- Class: SszMutableListImpl
-
-
-
- Class: SszMutableVectorImpl
-
-
-
- Class: SszUnionImpl
-
-
-
- Class: SszUtils
-
-
-
- Class: SszVectorImpl
-
-
- Package: tech.pegasys.teku.ssz.primitive
-
-
- Class: SszBit
-
-
-
- Class: SszByte
-
-
-
- Class: SszBytes32
-
-
-
- Class: SszBytes4
-
-
-
- Class: SszNone
-
-
-
- Class: SszUInt256
-
-
-
- Class: SszUInt64
-
-
- Package: tech.pegasys.teku.ssz.schema
-
-
- Class: SszCollectionSchema
-
-
-
- Class: SszCompositeSchema
-
-
-
- Class: SszContainerSchema
-
-
-
- Class: SszListSchema
-
-
-
- Class: SszPrimitiveSchema
-
-
-
- Class: SszPrimitiveSchemas
-
-
-
- Class: SszSchema <- possibility Tested
-
-
-
- Class: SszSchemaHints
-
-
-
- Class: SszType
-
-
-
- Class: SszUnionSchema <- possibility Tested
-
-
-
- Class: SszVectorSchema
-
-
- Package: tech.pegasys.teku.ssz.schema.collections
-
-
- Class: SszBitlistSchema <- possibility Tested
-
-
-
- Class: SszBitvectorSchema <- possibility Tested
-
-
-
- Class: SszByteListSchema
-
-
-
- Class: SszBytes32VectorSchema
-
-
-
- Class: SszByteVectorSchema
-
-
-
- Class: SszPrimitiveCollectionSchema
-
-
-
- Class: SszPrimitiveListSchema
-
-
-
- Class: SszPrimitiveVectorSchema
-
-
-
- Class: SszUInt64ListSchema
-
-
- Package: tech.pegasys.teku.ssz.schema.collections.impl
-
-
- Class: SchemaUtils
-
-
-
- Class: SszBitlistSchemaImpl
-
-
-
- Class: SszBitvectorSchemaImpl
-
-
-
- Class: SszByteListSchemaImpl
-
-
-
- Class: SszBytes32VectorSchemaImpl
-
-
-
- Class: SszByteVectorSchemaImpl
-
-
-
- Class: SszPrimitiveListSchemaImpl
-
-
-
- Class: SszPrimitiveVectorSchemaImpl
-
-
-
- Class: SszUInt64ListSchemaImpl
-
-
- Package: tech.pegasys.teku.ssz.schema.impl
-
-
- Class: AbstractSszCollectionSchema
-
-
-
- Class: AbstractSszContainerSchema
-
-
-
- Class: AbstractSszListSchema
-
-
-
- Class: AbstractSszPrimitiveSchema
-
-
-
- Class: AbstractSszVectorSchema
-
-
-
- Class: LoadingUtil
-
-
-
- Class: SszListSchemaImpl
-
-
-
- Class: SszUnionSchemaImpl
-
-
-
- Class: StoringUtil
-
-
- Package: tech.pegasys.teku.ssz.sos
-
-
- Class: SimpleSszReader
-
-
-
- Class: SszByteArrayWriter
-
-
-
- Class: SszDeserializeException
-
-
-
- Class: SszField
-
-
-
- Class: SszLengthBounds
-
-
-
- Class: SszReader
-
-
-
- Class: SszWriter
-
-
- Package: tech.pegasys.teku.ssz.tree
-
-
- Class: BranchNode
-
-
-
- Class: GIndexUtil
-
-
-
- Class: LazyBranchNode
-
-
-
- Class: LeafDataNode
-
-
-
- Class: LeafNode
-
-
-
- Class: SimpleBranchNode
-
-
-
- Class: SimpleLeafNode
-
-
-
- Class: SszNodeTemplate
-
-
-
- Class: SszSuperNode
-
-
-
- Class: TillIndexVisitor
-
-
-
- Class: TreeNode
-
-
-
- Class: TreeNodeSource
-
-
-
- Class: TreeNodeStore
-
-
-
- Class: TreeUpdates
-
-
-
- Class: TreeUtil
-
-
-
- Class: TreeVisitor
-
-
- Package: tech.pegasys.teku.ssz.type
-
-
- Class: Bytes20
-
-
-
- Class: Bytes4
-
-
-
- Class: Bytes8 Searched, Tested, Not Applicable
-
- Folder: data/beaconrestapi/main
-
- Package: tech.pegasys.teku.beaconrestapi
-
-
- Class: ListQueryParameterUtils
-
- Folder: networking/net/main
-
- Package: tech.pegasys.teku.networking.nat
-
-
- Class: TekuRegistryListener
-
- Folder: networking/p2p/rpc
-
- Package: tech.pegasys.teku.networking.p2p.rpc
-
-
- Class: RpcMethod
-
-
-
- Class: RpcRequestHandler <- extremely strong possibility
-
-
-
- Class: RpcRequestHandler
-
-
-
- Class: RpcStreamController
-
-
-
- Class: StreamClosedException
-
-
-
- Class: StreamTimeoutException
-
The first hypothesis was the correct trajectory. Discovered a "Generic Array" needed to be created as a Class or Interface within the Light-Client folder/package.
Code (to be refactored if necessary):
public class ArrayLike<T>
{
private final Object[] arr;
public final int number;
// constructor
public ArrayLike(int number)
{
// Creates a new object array of the specified length
arr = new Object[number];
this.number = number;
}
// Method to get object present at index `i` in the array
T get(int i) {
@SuppressWarnings("unchecked")
final T e = (T)arr[i];
return e;
}
// Method to set a value `e` at index `i` in the array
void set(int i, T e) {
arr[i] = e;
}
}
But, Java does not support Generic Arrays so this code was implemented in response:
List<Boolean> bits = new ArrayList<Boolean>();