com.swirlds.common.merkle.synchronization.task.Lesson Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swirlds-common Show documentation
Show all versions of swirlds-common Show documentation
Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.
/*
* Copyright (C) 2021-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.swirlds.common.merkle.synchronization.task;
import static com.swirlds.common.merkle.synchronization.task.LessonType.CUSTOM_VIEW_ROOT;
import static com.swirlds.common.merkle.synchronization.task.LessonType.INTERNAL_NODE_DATA;
import static com.swirlds.common.merkle.synchronization.task.LessonType.LEAF_NODE_DATA;
import static com.swirlds.common.merkle.synchronization.task.LessonType.NODE_IS_UP_TO_DATE;
import com.swirlds.common.Releasable;
import com.swirlds.common.crypto.Hash;
import com.swirlds.common.io.SelfSerializable;
import com.swirlds.common.io.streams.SerializableDataInputStream;
import com.swirlds.common.io.streams.SerializableDataOutputStream;
import com.swirlds.common.merkle.synchronization.views.LearnerTreeView;
import java.io.IOException;
import java.util.List;
/**
* Used during the synchronization protocol to send data needed to reconstruct a single node.
*/
public class Lesson implements Releasable, SelfSerializable {
private static final long CLASS_ID = 0x98bc0d340d9bca1dL;
private static class ClassVersion {
public static final int ORIGINAL = 1;
}
private byte lessonType;
private SelfSerializable subLesson;
private LearnerTreeView learnerView;
/**
* Zero-arg constructor for constructable registry.
*/
public Lesson() {}
/**
* This constructor is used by the teacher to create new lessons.
*
* @param lessonType
* the type of the lesson
* @param subLesson
* the payload of the lesson
*/
public Lesson(final byte lessonType, final SelfSerializable subLesson) {
this.lessonType = lessonType;
this.subLesson = subLesson;
}
/**
* This constructor is used by the learner when deserializing lessons.
*
* @param learnerTreeView
* the learner's view
*/
public Lesson(final LearnerTreeView learnerTreeView) {
this.learnerView = learnerTreeView;
}
/**
* {@inheritDoc}
*/
@Override
public void serialize(final SerializableDataOutputStream out) throws IOException {
out.writeByte(lessonType);
if (lessonType != NODE_IS_UP_TO_DATE) {
subLesson.serialize(out);
}
}
/**
* {@inheritDoc}
*/
@Override
public void deserialize(final SerializableDataInputStream in, final int version) throws IOException {
lessonType = in.readByte();
switch (lessonType) {
case NODE_IS_UP_TO_DATE:
return;
case LEAF_NODE_DATA:
subLesson = new LeafDataLesson<>(learnerView);
break;
case INTERNAL_NODE_DATA:
subLesson = new InternalDataLesson<>(learnerView);
break;
case CUSTOM_VIEW_ROOT:
subLesson = new CustomViewRootLesson();
break;
default:
throw new IllegalStateException("unsupported lesson type " + lessonType);
}
subLesson.deserialize(in, subLesson.getVersion());
}
/**
* Returns true if the learner already has the required data.
*/
public boolean isCurrentNodeUpToDate() {
return lessonType == NODE_IS_UP_TO_DATE;
}
/**
* Check if this lesson is about a leaf node.
* @return true if the lesson is about a leaf node
*/
public boolean isLeafLesson() {
return lessonType == LEAF_NODE_DATA;
}
/**
* Check if this lesson is about an internal node or a leaf node.
* Unset if {@link #isCurrentNodeUpToDate()} returns true.
*
* @return if the node in the lesson is an internal node.
*/
public boolean isInternalLesson() {
return lessonType == INTERNAL_NODE_DATA;
}
/**
* Check if there are any queries attached to this lesson.
*/
public boolean hasQueries() {
return lessonType == INTERNAL_NODE_DATA;
}
/**
* Get the queries contained within this lesson (i.e. the hashes of the children of an internal node). Will be unset
* and throw an exception if {@link #hasQueries()} returns false.
*
* @return a list of child hashes
*/
@SuppressWarnings("unchecked")
public List getQueries() {
return ((InternalDataLesson) subLesson).getQueries();
}
/**
* Get the leaf node. Will be unset and throw an exception if {@link #isCurrentNodeUpToDate()} is true or
* if {@link #isCustomViewRoot()} is true.
*
* @return the leaf node, or null if unset
*/
@SuppressWarnings("unchecked")
public T getNode() {
if (lessonType == LEAF_NODE_DATA) {
return ((LeafDataLesson) subLesson).getLeaf();
}
return ((InternalDataLesson) subLesson).getInternal();
}
/**
* Check if this is the initial lesson for a custom root.
*
* @return true if this is the initial lesson for the custom root
*/
public boolean isCustomViewRoot() {
return lessonType == CUSTOM_VIEW_ROOT;
}
/**
* If {@link #isCustomViewRoot()} returns true, this method returns the class ID for the
* root of the subtree with the custom view.
*
* @return the class ID of the root of the subtree
*/
public long getCustomViewClassId() {
return ((CustomViewRootLesson) subLesson).getRootClassId();
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public boolean release() {
if (lessonType == LEAF_NODE_DATA && learnerView != null) {
final T node = ((LeafDataLesson) subLesson).getLeaf();
if (node != null) {
learnerView.releaseNode(node);
}
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public long getClassId() {
return CLASS_ID;
}
/**
* {@inheritDoc}
*/
@Override
public int getVersion() {
return ClassVersion.ORIGINAL;
}
}