All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hedera.hapi.block.stream.output.codec.TransactionResultProtoCodec Maven / Gradle / Ivy

package com.hedera.hapi.block.stream.output.codec;

import com.hedera.pbj.runtime.*;
import com.hedera.pbj.runtime.io.*;
import com.hedera.pbj.runtime.io.buffer.*;
import com.hedera.pbj.runtime.io.stream.EOFException;
import java.io.IOException;
import java.nio.*;
import java.nio.charset.*;
import java.util.*;
import edu.umd.cs.findbugs.annotations.NonNull;

import com.hedera.hapi.block.stream.output.TransactionResult;

import com.hedera.hapi.block.stream.output.*;
import com.hedera.hapi.block.stream.output.schema.*;
import com.hedera.hapi.node.base.*;
import com.hedera.hapi.node.base.codec.*;
import java.util.*;

import static com.hedera.hapi.block.stream.output.schema.TransactionResultSchema.*;
import static com.hedera.pbj.runtime.ProtoWriterTools.*;
import static com.hedera.pbj.runtime.ProtoParserTools.*;
import static com.hedera.pbj.runtime.ProtoConstants.*;

/**
 * Protobuf Codec for TransactionResult model object. Generated based on protobuf schema.
 */
public final class TransactionResultProtoCodec implements Codec {
    

        /**
     * Parses a TransactionResult object from ProtoBuf bytes in a {@link ReadableSequentialData}. Throws if in strict mode ONLY.
     *
     * @param input The data input to parse data from, it is assumed to be in a state ready to read with position at start
     *              of data to read and limit set at the end of data to read. The data inputs limit will be changed by this
     *              method. If there are no bytes remaining in the data input,
     *              then the method also returns immediately.
     * @param strictMode when {@code true}, the parser errors out on unknown fields; otherwise they'll be simply skipped.
     * @param maxDepth a ParseException will be thrown if the depth of nested messages exceeds the maxDepth value.
     * @return Parsed TransactionResult model object or null if data input was null or empty
     * @throws ParseException If parsing fails
     */
    public @NonNull TransactionResult parse(
            @NonNull final ReadableSequentialData input,
            final boolean strictMode,
            final int maxDepth) throws ParseException {
        if (maxDepth < 0) {
            throw new ParseException("Reached maximum allowed depth of nested messages");
        }
        try {
            // -- TEMP STATE FIELDS --------------------------------------
                ResponseCodeEnum temp_status = ResponseCodeEnum.fromProtobufOrdinal(0);
        Timestamp temp_consensus_timestamp = null;
        Timestamp temp_parent_consensus_timestamp = null;
        ScheduleID temp_schedule_ref = null;
        long temp_transaction_fee_charged = 0;
        TransferList temp_transfer_list = null;
        List temp_token_transfer_lists = Collections.emptyList();
        List temp_automatic_token_associations = Collections.emptyList();
        List temp_paid_staking_rewards = Collections.emptyList();
        long temp_congestion_pricing_multiplier = 0;
    
                        // -- PARSE LOOP ---------------------------------------------
                // Continue to parse bytes out of the input stream until we get to the end.
                while (input.hasRemaining()) {
                    // Note: ReadableStreamingData.hasRemaining() won't flip to false
                    // until the end of stream is actually hit with a read operation.
                    // So we catch this exception here and **only** here, because an EOFException
                    // anywhere else suggests that we're processing malformed data and so
                    // we must re-throw the exception then.
                    final int tag;
                    try {
                        // Read the "tag" byte which gives us the field number for the next field to read
                        // and the wire type (way it is encoded on the wire).
                        tag = input.readVarInt(false);
                    } catch (EOFException e) {
                        // There's no more fields. Stop the parsing loop.
                        break;
                    }
        
                    // The field is the top 5 bits of the byte. Read this off
                    final int field = tag >>> TAG_FIELD_OFFSET;
        
                    // Ask the Schema to inform us what field this represents.
                    final var f = getField(field);
        
                    // Given the wire type and the field type, parse the field
                    switch (tag) {
                        case 8 /* type=0 [ENUM] field=1 [status] */ -> {
                            final var value = ResponseCodeEnum.fromProtobufOrdinal(readEnum(input));
                            temp_status = value;
                        }
                        case 18 /* type=2 [MESSAGE] field=2 [consensus_timestamp] */ -> {
                            final var messageLength = input.readVarInt(false);
                            final Timestamp value;
                            if (messageLength == 0) {
                            	value = Timestamp.DEFAULT;
                            } else {
                            	if (messageLength > 2097152) {
                            		throw new ParseException("consensus_timestamp size " + messageLength + " is greater than max " + 2097152);
                            	}
                            	final var limitBefore = input.limit();
                            	// Make sure that we have enough bytes in the message
                            	// to read the subObject.
                            	// If the buffer is truncated on the boundary of a subObject,
                            	// we will not throw.
                            	final var startPos = input.position();
                            	try {
                            		if ((startPos + messageLength) > limitBefore) {
                            			throw new BufferUnderflowException();
                            		}
                            		input.limit(startPos + messageLength);
                            		value = Timestamp.PROTOBUF.parse(input, strictMode, maxDepth - 1);
                            		// Make sure we read the full number of bytes. for the types
                            		if ((startPos + messageLength) != input.position()) {
                            			throw new BufferOverflowException();
                            		}
                            	} finally {
                            		input.limit(limitBefore);
                            	}
                            }
                            temp_consensus_timestamp = value;
                        }
                        case 26 /* type=2 [MESSAGE] field=3 [parent_consensus_timestamp] */ -> {
                            final var messageLength = input.readVarInt(false);
                            final Timestamp value;
                            if (messageLength == 0) {
                            	value = Timestamp.DEFAULT;
                            } else {
                            	if (messageLength > 2097152) {
                            		throw new ParseException("parent_consensus_timestamp size " + messageLength + " is greater than max " + 2097152);
                            	}
                            	final var limitBefore = input.limit();
                            	// Make sure that we have enough bytes in the message
                            	// to read the subObject.
                            	// If the buffer is truncated on the boundary of a subObject,
                            	// we will not throw.
                            	final var startPos = input.position();
                            	try {
                            		if ((startPos + messageLength) > limitBefore) {
                            			throw new BufferUnderflowException();
                            		}
                            		input.limit(startPos + messageLength);
                            		value = Timestamp.PROTOBUF.parse(input, strictMode, maxDepth - 1);
                            		// Make sure we read the full number of bytes. for the types
                            		if ((startPos + messageLength) != input.position()) {
                            			throw new BufferOverflowException();
                            		}
                            	} finally {
                            		input.limit(limitBefore);
                            	}
                            }
                            temp_parent_consensus_timestamp = value;
                        }
                        case 42 /* type=2 [MESSAGE] field=5 [schedule_ref] */ -> {
                            final var messageLength = input.readVarInt(false);
                            final ScheduleID value;
                            if (messageLength == 0) {
                            	value = ScheduleID.DEFAULT;
                            } else {
                            	if (messageLength > 2097152) {
                            		throw new ParseException("schedule_ref size " + messageLength + " is greater than max " + 2097152);
                            	}
                            	final var limitBefore = input.limit();
                            	// Make sure that we have enough bytes in the message
                            	// to read the subObject.
                            	// If the buffer is truncated on the boundary of a subObject,
                            	// we will not throw.
                            	final var startPos = input.position();
                            	try {
                            		if ((startPos + messageLength) > limitBefore) {
                            			throw new BufferUnderflowException();
                            		}
                            		input.limit(startPos + messageLength);
                            		value = ScheduleID.PROTOBUF.parse(input, strictMode, maxDepth - 1);
                            		// Make sure we read the full number of bytes. for the types
                            		if ((startPos + messageLength) != input.position()) {
                            			throw new BufferOverflowException();
                            		}
                            	} finally {
                            		input.limit(limitBefore);
                            	}
                            }
                            temp_schedule_ref = value;
                        }
                        case 48 /* type=0 [UINT64] field=6 [transaction_fee_charged] */ -> {
                            final var value = readUint64(input);
                            temp_transaction_fee_charged = value;
                        }
                        case 58 /* type=2 [MESSAGE] field=7 [transfer_list] */ -> {
                            final var messageLength = input.readVarInt(false);
                            final TransferList value;
                            if (messageLength == 0) {
                            	value = TransferList.DEFAULT;
                            } else {
                            	if (messageLength > 2097152) {
                            		throw new ParseException("transfer_list size " + messageLength + " is greater than max " + 2097152);
                            	}
                            	final var limitBefore = input.limit();
                            	// Make sure that we have enough bytes in the message
                            	// to read the subObject.
                            	// If the buffer is truncated on the boundary of a subObject,
                            	// we will not throw.
                            	final var startPos = input.position();
                            	try {
                            		if ((startPos + messageLength) > limitBefore) {
                            			throw new BufferUnderflowException();
                            		}
                            		input.limit(startPos + messageLength);
                            		value = TransferList.PROTOBUF.parse(input, strictMode, maxDepth - 1);
                            		// Make sure we read the full number of bytes. for the types
                            		if ((startPos + messageLength) != input.position()) {
                            			throw new BufferOverflowException();
                            		}
                            	} finally {
                            		input.limit(limitBefore);
                            	}
                            }
                            temp_transfer_list = value;
                        }
                        case 66 /* type=2 [MESSAGE] field=8 [token_transfer_lists] */ -> {
                            final var messageLength = input.readVarInt(false);
                            final TokenTransferList value;
                            if (messageLength == 0) {
                            	value = TokenTransferList.DEFAULT;
                            } else {
                            	if (messageLength > 2097152) {
                            		throw new ParseException("token_transfer_lists size " + messageLength + " is greater than max " + 2097152);
                            	}
                            	final var limitBefore = input.limit();
                            	// Make sure that we have enough bytes in the message
                            	// to read the subObject.
                            	// If the buffer is truncated on the boundary of a subObject,
                            	// we will not throw.
                            	final var startPos = input.position();
                            	try {
                            		if ((startPos + messageLength) > limitBefore) {
                            			throw new BufferUnderflowException();
                            		}
                            		input.limit(startPos + messageLength);
                            		value = TokenTransferList.PROTOBUF.parse(input, strictMode, maxDepth - 1);
                            		// Make sure we read the full number of bytes. for the types
                            		if ((startPos + messageLength) != input.position()) {
                            			throw new BufferOverflowException();
                            		}
                            	} finally {
                            		input.limit(limitBefore);
                            	}
                            }
                            if (temp_token_transfer_lists.size() >= 2097152) {
                        		throw new ParseException("token_transfer_lists size " + temp_token_transfer_lists.size() + " is greater than max " + 2097152);
                        	}
                        	temp_token_transfer_lists = addToList(temp_token_transfer_lists,value);
                        }
                        case 74 /* type=2 [MESSAGE] field=9 [automatic_token_associations] */ -> {
                            final var messageLength = input.readVarInt(false);
                            final TokenAssociation value;
                            if (messageLength == 0) {
                            	value = TokenAssociation.DEFAULT;
                            } else {
                            	if (messageLength > 2097152) {
                            		throw new ParseException("automatic_token_associations size " + messageLength + " is greater than max " + 2097152);
                            	}
                            	final var limitBefore = input.limit();
                            	// Make sure that we have enough bytes in the message
                            	// to read the subObject.
                            	// If the buffer is truncated on the boundary of a subObject,
                            	// we will not throw.
                            	final var startPos = input.position();
                            	try {
                            		if ((startPos + messageLength) > limitBefore) {
                            			throw new BufferUnderflowException();
                            		}
                            		input.limit(startPos + messageLength);
                            		value = TokenAssociation.PROTOBUF.parse(input, strictMode, maxDepth - 1);
                            		// Make sure we read the full number of bytes. for the types
                            		if ((startPos + messageLength) != input.position()) {
                            			throw new BufferOverflowException();
                            		}
                            	} finally {
                            		input.limit(limitBefore);
                            	}
                            }
                            if (temp_automatic_token_associations.size() >= 2097152) {
                        		throw new ParseException("automatic_token_associations size " + temp_automatic_token_associations.size() + " is greater than max " + 2097152);
                        	}
                        	temp_automatic_token_associations = addToList(temp_automatic_token_associations,value);
                        }
                        case 82 /* type=2 [MESSAGE] field=10 [paid_staking_rewards] */ -> {
                            final var messageLength = input.readVarInt(false);
                            final AccountAmount value;
                            if (messageLength == 0) {
                            	value = AccountAmount.DEFAULT;
                            } else {
                            	if (messageLength > 2097152) {
                            		throw new ParseException("paid_staking_rewards size " + messageLength + " is greater than max " + 2097152);
                            	}
                            	final var limitBefore = input.limit();
                            	// Make sure that we have enough bytes in the message
                            	// to read the subObject.
                            	// If the buffer is truncated on the boundary of a subObject,
                            	// we will not throw.
                            	final var startPos = input.position();
                            	try {
                            		if ((startPos + messageLength) > limitBefore) {
                            			throw new BufferUnderflowException();
                            		}
                            		input.limit(startPos + messageLength);
                            		value = AccountAmount.PROTOBUF.parse(input, strictMode, maxDepth - 1);
                            		// Make sure we read the full number of bytes. for the types
                            		if ((startPos + messageLength) != input.position()) {
                            			throw new BufferOverflowException();
                            		}
                            	} finally {
                            		input.limit(limitBefore);
                            	}
                            }
                            if (temp_paid_staking_rewards.size() >= 2097152) {
                        		throw new ParseException("paid_staking_rewards size " + temp_paid_staking_rewards.size() + " is greater than max " + 2097152);
                        	}
                        	temp_paid_staking_rewards = addToList(temp_paid_staking_rewards,value);
                        }
                        case 88 /* type=0 [UINT64] field=11 [congestion_pricing_multiplier] */ -> {
                            final var value = readUint64(input);
                            temp_congestion_pricing_multiplier = value;
                        }
        
                        default -> {
                            // The wire type is the bottom 3 bits of the byte. Read that off
                            final int wireType = tag & TAG_WIRE_TYPE_MASK;
                            // handle error cases here, so we do not do if statements in normal loop
                            // Validate the field number is valid (must be > 0)
                            if (field == 0) {
                                throw new IOException("Bad protobuf encoding. We read a field value of "
                                    + field);
                            }
                            // Validate the wire type is valid (must be >=0 && <= 5).
                            // Otherwise we cannot parse this.
                            // Note: it is always >= 0 at this point (see code above where it is defined).
                            if (wireType > 5) {
                                throw new IOException("Cannot understand wire_type of " + wireType);
                            }
                            // It may be that the parser subclass doesn't know about this field
                            if (f == null) {
                                if (strictMode) {
                                    // Since we are parsing is strict mode, this is an exceptional condition.
                                    throw new UnknownFieldException(field);
                                } else {
                                    // We just need to read off the bytes for this field to skip it
                                    // and move on to the next one.
                                    skipField(input, ProtoConstants.get(wireType), 2097152);
                                }
                            } else {
                                throw new IOException("Bad tag [" + tag + "], field [" + field
                                        + "] wireType [" + wireType + "]");
                            }
                        }
                    }
                }
    
            return new TransactionResult(temp_status, temp_consensus_timestamp, temp_parent_consensus_timestamp, temp_schedule_ref, temp_transaction_fee_charged, temp_transfer_list, temp_token_transfer_lists, temp_automatic_token_associations, temp_paid_staking_rewards, temp_congestion_pricing_multiplier);
        } catch (final Exception anyException) {
            if (anyException instanceof ParseException parseException) {
                throw parseException;
            }
            throw new ParseException(anyException);
        }
    }

        /**
     * Write out a TransactionResult model to output stream in protobuf format.
     *
     * @param data The input model data to write
     * @param out The output stream to write to
     * @throws IOException If there is a problem writing
     */
    public void write(@NonNull TransactionResult data, @NonNull final WritableSequentialData out) throws IOException {
            // [1] - status
        writeEnum(out, STATUS, data.status());
        // [2] - consensus_timestamp
        writeMessage(out, CONSENSUS_TIMESTAMP, data.consensusTimestamp(), com.hedera.hapi.node.base.Timestamp.PROTOBUF::write, com.hedera.hapi.node.base.Timestamp.PROTOBUF::measureRecord);
        // [3] - parent_consensus_timestamp
        writeMessage(out, PARENT_CONSENSUS_TIMESTAMP, data.parentConsensusTimestamp(), com.hedera.hapi.node.base.Timestamp.PROTOBUF::write, com.hedera.hapi.node.base.Timestamp.PROTOBUF::measureRecord);
        // [5] - schedule_ref
        writeMessage(out, SCHEDULE_REF, data.scheduleRef(), com.hedera.hapi.node.base.ScheduleID.PROTOBUF::write, com.hedera.hapi.node.base.ScheduleID.PROTOBUF::measureRecord);
        // [6] - transaction_fee_charged
        writeLong(out, TRANSACTION_FEE_CHARGED, data.transactionFeeCharged(), true);
        // [7] - transfer_list
        writeMessage(out, TRANSFER_LIST, data.transferList(), com.hedera.hapi.node.base.TransferList.PROTOBUF::write, com.hedera.hapi.node.base.TransferList.PROTOBUF::measureRecord);
        // [8] - token_transfer_lists
        writeMessageList(out, TOKEN_TRANSFER_LISTS, data.tokenTransferLists(), com.hedera.hapi.node.base.TokenTransferList.PROTOBUF::write, com.hedera.hapi.node.base.TokenTransferList.PROTOBUF::measureRecord);
        // [9] - automatic_token_associations
        writeMessageList(out, AUTOMATIC_TOKEN_ASSOCIATIONS, data.automaticTokenAssociations(), com.hedera.hapi.node.base.TokenAssociation.PROTOBUF::write, com.hedera.hapi.node.base.TokenAssociation.PROTOBUF::measureRecord);
        // [10] - paid_staking_rewards
        writeMessageList(out, PAID_STAKING_REWARDS, data.paidStakingRewards(), com.hedera.hapi.node.base.AccountAmount.PROTOBUF::write, com.hedera.hapi.node.base.AccountAmount.PROTOBUF::measureRecord);
        // [11] - congestion_pricing_multiplier
        writeLong(out, CONGESTION_PRICING_MULTIPLIER, data.congestionPricingMultiplier(), true);
    
    }

        /**
     * Reads from this data input the length of the data within the input. The implementation may
     * read all the data, or just some special serialized data, as needed to find out the length of
     * the data.
     *
     * @param input The input to use
     * @return The length of the data item in the input
     * @throws ParseException If parsing fails
     */
    public int measure(@NonNull final ReadableSequentialData input) throws ParseException {
        final var start = input.position();
        parse(input);
        final var end = input.position();
        return (int)(end - start);
    }

        /**
     * Compute number of bytes that would be written when calling {@code write()} method.
     *
     * @param data The input model data to measure write bytes for
     * @return The length in bytes that would be written
     */
    public int measureRecord(TransactionResult data) {
        int size = 0;
            // [1] - status
        size += sizeOfEnum(STATUS, data.status());
        // [2] - consensus_timestamp
        size += sizeOfMessage(CONSENSUS_TIMESTAMP, data.consensusTimestamp(), com.hedera.hapi.node.base.Timestamp.PROTOBUF::measureRecord);
        // [3] - parent_consensus_timestamp
        size += sizeOfMessage(PARENT_CONSENSUS_TIMESTAMP, data.parentConsensusTimestamp(), com.hedera.hapi.node.base.Timestamp.PROTOBUF::measureRecord);
        // [5] - schedule_ref
        size += sizeOfMessage(SCHEDULE_REF, data.scheduleRef(), com.hedera.hapi.node.base.ScheduleID.PROTOBUF::measureRecord);
        // [6] - transaction_fee_charged
        size += sizeOfLong(TRANSACTION_FEE_CHARGED, data.transactionFeeCharged(), true);
        // [7] - transfer_list
        size += sizeOfMessage(TRANSFER_LIST, data.transferList(), com.hedera.hapi.node.base.TransferList.PROTOBUF::measureRecord);
        // [8] - token_transfer_lists
        size += sizeOfMessageList(TOKEN_TRANSFER_LISTS, data.tokenTransferLists(), com.hedera.hapi.node.base.TokenTransferList.PROTOBUF::measureRecord);
        // [9] - automatic_token_associations
        size += sizeOfMessageList(AUTOMATIC_TOKEN_ASSOCIATIONS, data.automaticTokenAssociations(), com.hedera.hapi.node.base.TokenAssociation.PROTOBUF::measureRecord);
        // [10] - paid_staking_rewards
        size += sizeOfMessageList(PAID_STAKING_REWARDS, data.paidStakingRewards(), com.hedera.hapi.node.base.AccountAmount.PROTOBUF::measureRecord);
        // [11] - congestion_pricing_multiplier
        size += sizeOfLong(CONGESTION_PRICING_MULTIPLIER, data.congestionPricingMultiplier(), true);
    
        return size;
    }

        /**
     * Compares the given item with the bytes in the input, and returns false if it determines that
     * the bytes in the input could not be equal to the given item. Sometimes we need to compare an
     * item in memory with serialized bytes and don't want to incur the cost of deserializing the
     * entire object, when we could have determined the bytes do not represent the same object very
     * cheaply and quickly.
     *
     * @param item The item to compare. Cannot be null.
     * @param input The input with the bytes to compare
     * @return true if the bytes represent the item, false otherwise.
     * @throws ParseException If parsing fails
     */
    public boolean fastEquals(@NonNull TransactionResult item, @NonNull final ReadableSequentialData input) throws ParseException {
        return item.equals(parse(input));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy