From 19fd347b1e4b0683f34110a77addf4ec697bc3fe Mon Sep 17 00:00:00 2001 From: jasperpotts Date: Thu, 8 Sep 2022 10:50:25 -0700 Subject: [PATCH] Tweaks for final edge cases. Added Conversion in model record constructors from OpenOf to OneOF.UNSET. Added work around for more cyclic dependency with Keys. Fixed field sorting in writers. --- .../hashgraph/protoparser/ModelGenerator.java | 35 +- .../hashgraph/protoparser/OneOfField.java | 2 +- .../hashgraph/protoparser/TestGenerator.java | 3 +- gradle.properties | 2 +- modules/hedera-proto-api/build.gradle.kts | 3 + .../hedera/hashgraph/hapi/EdgeCaseTests.java | 384 +++++++++++++++--- 6 files changed, 365 insertions(+), 64 deletions(-) diff --git a/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/ModelGenerator.java b/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/ModelGenerator.java index 2cd9d80..71579c0 100644 --- a/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/ModelGenerator.java +++ b/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/ModelGenerator.java @@ -173,10 +173,7 @@ private static void generateRecordFile(Protobuf3Parser.MessageDefContext msgDef, """.formatted(javaRecordName, fields.stream() .filter(f -> f instanceof OneOfField || f.optional()) - .map(f -> FIELD_INDENT+""" - if (%s == null) { - throw new NullPointerException("Parameter '%s' must be supplied and can not be null"); - }""".formatted(f.nameCamelFirstLower(),f.nameCamelFirstLower()).replaceAll("\n","\n"+FIELD_INDENT)) + .map(ModelGenerator::generateCostructorCode) .collect(Collectors.joining("\n")) ).replaceAll("\n","\n"+FIELD_INDENT); } @@ -207,4 +204,32 @@ private static void generateRecordFile(Protobuf3Parser.MessageDefContext msgDef, } } -} + private static String generateCostructorCode(final Field f) { + StringBuilder sb = new StringBuilder(FIELD_INDENT+""" + if (%s == null) { + throw new NullPointerException("Parameter '%s' must be supplied and can not be null"); + }""".formatted(f.nameCamelFirstLower(),f.nameCamelFirstLower())); + if (f instanceof OneOfField) { + final OneOfField oof = (OneOfField)f; + for (Field subField: oof.fields()) { + if(subField.optional()) { + sb.append(""" + + // handle special case where protobuf does not have destination between a OneOf with optional + // value of empty vs a unset OneOf. + if(%s.kind() == %sOneOfType.%s && ((Optional)%s.value()).isEmpty()) { + %s = new OneOf<>(%sOneOfType.UNSET, null); + }""".formatted( + f.nameCamelFirstLower(), + f.nameCamelFirstUpper(), + camelToUpperSnake(subField.name()), + f.nameCamelFirstLower(), + f.nameCamelFirstLower(), + f.nameCamelFirstUpper() + )); + } + } + } + return sb.toString().replaceAll("\n","\n"+FIELD_INDENT); + } +} \ No newline at end of file diff --git a/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/OneOfField.java b/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/OneOfField.java index 27887fb..c2fb157 100644 --- a/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/OneOfField.java +++ b/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/OneOfField.java @@ -55,7 +55,7 @@ public FieldType type() { */ @Override public int fieldNumber() { - return -1; + return fields.get(0).fieldNumber(); } /** diff --git a/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/TestGenerator.java b/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/TestGenerator.java index 35fd92a..0274f50 100644 --- a/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/TestGenerator.java +++ b/buildSrc/src/main/java/com/hedera/hashgraph/protoparser/TestGenerator.java @@ -248,7 +248,8 @@ private static String generateTestData(String modelClassName, Field field, boole if(subField instanceof SingleField) { final String enumValueName = camelToUpperSnake(subField.name()); // special cases to break cyclic dependencies - if (!("THRESHOLD_KEY".equals(enumValueName) || "KEY_LIST".equals(enumValueName))) { + if (!("THRESHOLD_KEY".equals(enumValueName) || "KEY_LIST".equals(enumValueName) + || "THRESHOLD_SIGNATURE".equals(enumValueName)|| "SIGNATURE_LIST".equals(enumValueName))) { final String listStr; if (subField.optional()) { Field.FieldType convertedSubFieldType = getOptionalConvertedFieldType(subField); diff --git a/gradle.properties b/gradle.properties index a43544e..d619de2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ version = 0.28.1-SNAPSHOT # Need increased heap for running Gradle itself, or SonarQube will run the JVM out of metaspace -org.gradle.jvmargs = -Xmx2048m +org.gradle.jvmargs = -Xmx8192M # Default JMH benchmark includes regex includesRegex=.* diff --git a/modules/hedera-proto-api/build.gradle.kts b/modules/hedera-proto-api/build.gradle.kts index e2aca85..0dff7ee 100644 --- a/modules/hedera-proto-api/build.gradle.kts +++ b/modules/hedera-proto-api/build.gradle.kts @@ -9,6 +9,9 @@ dependencies { testImplementation("com.hedera.hashgraph:hedera-protobuf-java-api:0.29.1") } +tasks.withType().configureEach { + maxParallelForks = 4 +} // ===== PROTOBUF GENERATION =========================================================================================== diff --git a/modules/hedera-proto-api/src/test/java/com/hedera/hashgraph/hapi/EdgeCaseTests.java b/modules/hedera-proto-api/src/test/java/com/hedera/hashgraph/hapi/EdgeCaseTests.java index 0e23a6c..8590769 100644 --- a/modules/hedera-proto-api/src/test/java/com/hedera/hashgraph/hapi/EdgeCaseTests.java +++ b/modules/hedera-proto-api/src/test/java/com/hedera/hashgraph/hapi/EdgeCaseTests.java @@ -1,21 +1,19 @@ package com.hedera.hashgraph.hapi; -import com.google.protobuf.ByteString; -import com.google.protobuf.StringValue; -import com.google.protobuf.UInt32Value; +import com.google.protobuf.*; +import com.hedera.hashgraph.hapi.model.base.Timestamp; import com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody.MemoFieldOneOfType; import com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody.StakedIdOneOfType; import com.hedera.hashgraph.hapi.parser.TokenTransferListProtoParser; import com.hedera.hashgraph.hapi.parser.contract.ContractLoginfoProtoParser; import com.hedera.hashgraph.hapi.parser.contract.ContractUpdateTransactionBodyProtoParser; +import com.hedera.hashgraph.hapi.parser.token.CryptoUpdateTransactionBodyProtoParser; import com.hedera.hashgraph.hapi.writer.TokenTransferListWriter; import com.hedera.hashgraph.hapi.writer.contract.ContractLoginfoWriter; import com.hedera.hashgraph.hapi.writer.contract.ContractUpdateTransactionBodyWriter; +import com.hedera.hashgraph.hapi.writer.token.CryptoUpdateTransactionBodyWriter; import com.hedera.hashgraph.protoparse.MalformedProtobufException; -import com.hederahashgraph.api.proto.java.ContractLoginfo; -import com.hederahashgraph.api.proto.java.ContractUpdateTransactionBody; -import com.hederahashgraph.api.proto.java.TokenID; -import com.hederahashgraph.api.proto.java.TokenTransferList; +import com.hederahashgraph.api.proto.java.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -203,6 +201,323 @@ public void testOneOfsWithDefaultValues() throws MalformedProtobufException, IOE assertEquals(modelWithMemoWrapper, readWithMemoWrapper); } + /** + * Make sure we can write and parse protobufs with oneOfs that contain the unset optional value types. + */ + @Test + public void testOneOfsWithUnsetOptional() throws MalformedProtobufException, IOException { + final ContractUpdateTransactionBody protoEmpty = ContractUpdateTransactionBody.newBuilder() + .build(); + final byte[] protoEmptyBytes = protoEmpty.toByteArray(); + System.out.println(" protoEmpty.hasMemoWrapper() = " + protoEmpty.hasMemoWrapper()); + printProtoBuf("protoEmptyBytes",protoEmptyBytes); + final ContractUpdateTransactionBody protoWithMemoWrapperEmptyStr = ContractUpdateTransactionBody.newBuilder() + .setMemoWrapper(StringValue.getDefaultInstance()) + .build(); + System.out.println(" protoWithMemoWrapperEmptyStr.hasMemoWrapper() = " + protoWithMemoWrapperEmptyStr.hasMemoWrapper()); + final byte[] protoWithMemoWrapperEmptyStrBytes = protoWithMemoWrapperEmptyStr.toByteArray(); + printProtoBuf("protoWithMemoWrapperEmptyStrBytes",protoWithMemoWrapperEmptyStrBytes); + final ContractUpdateTransactionBody protoWithMemoWrapper = ContractUpdateTransactionBody.newBuilder() + .clearMemoWrapper() + .build(); + System.out.println(" protoWithMemoWrapper.hasMemoWrapper() = " + protoWithMemoWrapper.hasMemoWrapper()); + final byte[] protoWithMemoWrapperBytes = protoWithMemoWrapper.toByteArray(); + printProtoBuf("protoWithMemoWrapperBytes",protoWithMemoWrapperBytes); + + final com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody modelEmpty = + new com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody( + null, + null, + null, + null, + null, + null, + new OneOf<>(MemoFieldOneOfType.UNSET,null), + Optional.empty(), + null, + new OneOf<>(StakedIdOneOfType.UNSET, null), + Optional.empty() + ); + final ByteArrayOutputStream bout3 = new ByteArrayOutputStream(); + ContractUpdateTransactionBodyWriter.write(modelEmpty,bout3); + final byte[] modelEmptyBytes = bout3.toByteArray(); + printProtoBuf("modelEmptyBytes",modelEmptyBytes); + + final com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody modelWithMemoWrapper = + new com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody( + null, + null, + null, + null, + null, + null, + new OneOf<>(MemoFieldOneOfType.MEMO_WRAPPER,Optional.empty()), + Optional.empty(), + null, + new OneOf<>(StakedIdOneOfType.UNSET, null), + Optional.empty() + ); + final ByteArrayOutputStream bout5 = new ByteArrayOutputStream(); + ContractUpdateTransactionBodyWriter.write(modelWithMemoWrapper,bout5); + final byte[] modelWithMemoWrapperBytes = bout5.toByteArray(); + printProtoBuf("modelWithMemoWrapperBytes",modelWithMemoWrapperBytes); + + assertArrayEquals(protoEmptyBytes, modelEmptyBytes); + assertArrayEquals(protoWithMemoWrapperBytes, modelWithMemoWrapperBytes); + + final var readEmpty = new ContractUpdateTransactionBodyProtoParser().parse(modelEmptyBytes); + final var readWithMemoWrapper = new ContractUpdateTransactionBodyProtoParser().parse(modelWithMemoWrapperBytes); + assertEquals(modelEmpty, readEmpty); + assertEquals(modelWithMemoWrapper, readWithMemoWrapper); + } + + /** + * Fix embedded messages + */ + @Test + public void testEmbeddedMessageSize() throws MalformedProtobufException, IOException { + /** + * contractID= + * ContractID[shardNum=21, realmNum=21, contract=OneOf[kind=CONTRACT_NUM, value=0]], + * expirationTime=Timestamp[seconds=21, nanos=21], + * adminKey=Key[key=OneOf[kind=CONTRACT_ID, value=ContractID[shardNum=0, realmNum=0, contract=OneOf[kind=CONTRACT_NUM, value=-21]]]], + * proxyAccountID=AccountID[shardNum=21, realmNum=21, account=OneOf[kind=ACCOUNT_NUM, value=0]], + * autoRenewPeriod=Duration[seconds=21], + * fileID=FileID[shardNum=21, realmNum=21, fileNum=21], + * memoField=OneOf[kind=MEMO_WRAPPER, value=Optional[]], + * maxAutomaticTokenAssociations=Optional[0], + * autoRenewAccountId=AccountID[shardNum=21, realmNum=21, account=OneOf[kind=ACCOUNT_NUM, value=0]], + * stakedId=OneOf[kind=STAKED_ACCOUNT_ID, value=AccountID[shardNum=0, realmNum=0, account=OneOf[kind=ACCOUNT_NUM, value=-21]]], + * declineReward=Optional[false]] + */ + final ContractUpdateTransactionBody proto = ContractUpdateTransactionBody.newBuilder() + .setContractID(ContractID.newBuilder().setShardNum(21).setRealmNum(21).setContractNum(0).build()) + .setExpirationTime(com.hederahashgraph.api.proto.java.Timestamp.newBuilder().setSeconds(21).setNanos(21).build()) + .setAdminKey(Key.newBuilder().setContractID(ContractID.newBuilder().setShardNum(0).setRealmNum(0).setContractNum(-21).build()).build()) + .setMemoWrapper(StringValue.newBuilder().build()) + .setDeclineReward(BoolValue.newBuilder().setValue(false).build()) + .build(); + final byte[] protoBytes = proto.toByteArray(); + printProtoBuf("protoBytes",protoBytes); + + final com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody model = + new com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody( + new com.hedera.hashgraph.hapi.model.ContractID( + 21,21, + new OneOf<>(com.hedera.hashgraph.hapi.model.ContractID.ContractOneOfType.CONTRACT_NUM, 0L)), + new Timestamp(21,21), + new com.hedera.hashgraph.hapi.model.Key(new OneOf<>(com.hedera.hashgraph.hapi.model.Key.KeyOneOfType.CONTRACT_ID, + new com.hedera.hashgraph.hapi.model.ContractID( + 0,0, + new OneOf<>(com.hedera.hashgraph.hapi.model.ContractID.ContractOneOfType.CONTRACT_NUM, -21L)))), + null, + null, + null, + new OneOf<>(MemoFieldOneOfType.MEMO_WRAPPER,Optional.of("")), + Optional.empty(), + null, + new OneOf<>(StakedIdOneOfType.UNSET, null), + Optional.of(false) + ); + final ByteArrayOutputStream bout3 = new ByteArrayOutputStream(); + ContractUpdateTransactionBodyWriter.write(model,bout3); + final byte[] modelBytes = bout3.toByteArray(); + printProtoBuf("modelBytes",modelBytes); + + + assertArrayEquals(protoBytes, protoBytes); + + final var readModelBytes = new ContractUpdateTransactionBodyProtoParser().parse(protoBytes); + assertEquals(model, readModelBytes); + } + @Test + public void testOptionalZero() throws MalformedProtobufException, IOException { + final ContractUpdateTransactionBody proto = ContractUpdateTransactionBody.newBuilder() + .setMaxAutomaticTokenAssociations(Int32Value.of(0)) + .build(); + final byte[] protoBytes = proto.toByteArray(); + printProtoBuf("protoBytes",protoBytes); + + final com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody model = + new com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody( + null, + null, + null, + null, + null, + null, + new OneOf<>(MemoFieldOneOfType.UNSET,null), + Optional.of(0), + null, + new OneOf<>(StakedIdOneOfType.UNSET, null), + Optional.empty() + ); + final ByteArrayOutputStream bout3 = new ByteArrayOutputStream(); + ContractUpdateTransactionBodyWriter.write(model,bout3); + final byte[] modelBytes = bout3.toByteArray(); + printProtoBuf("modelBytes",modelBytes); + + + assertArrayEquals(protoBytes, protoBytes); + + final var readModelBytes = new ContractUpdateTransactionBodyProtoParser().parse(protoBytes); + assertEquals(model, readModelBytes); + } + @Test + public void testExtraBytesLeftAtEnd() throws MalformedProtobufException, IOException { + final ContractUpdateTransactionBody proto = ContractUpdateTransactionBody.newBuilder() + .setMaxAutomaticTokenAssociations(Int32Value.of(0)) + .setAutoRenewAccountId(AccountID.newBuilder().setShardNum(21).setRealmNum(21).setAccountNum(0).build()) + .build(); + final byte[] protoBytes = proto.toByteArray(); + printProtoBuf("protoBytes",protoBytes); + + final com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody model = + new com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody( + null, + null, + null, + null, + null, + null, + new OneOf<>(MemoFieldOneOfType.UNSET,null), + Optional.of(0), + new com.hedera.hashgraph.hapi.model.AccountID(21,21,new OneOf<>(com.hedera.hashgraph.hapi.model.AccountID.AccountOneOfType.ACCOUNT_NUM, 0L)), + new OneOf<>(StakedIdOneOfType.UNSET, null), + Optional.empty() + ); + final ByteArrayOutputStream bout3 = new ByteArrayOutputStream(); + ContractUpdateTransactionBodyWriter.write(model,bout3); + final byte[] modelBytes = bout3.toByteArray(); + printProtoBuf("modelBytes",modelBytes); + + + assertArrayEquals(protoBytes, protoBytes); + + final var readModelBytes = new ContractUpdateTransactionBodyProtoParser().parse(protoBytes); + assertEquals(model, readModelBytes); + } + + /** + * Fix embedded messages + */ + @Test + public void testEmbeddedMessageSize2() throws MalformedProtobufException, IOException { + final ContractUpdateTransactionBody proto = ContractUpdateTransactionBody.newBuilder() + .setContractID(ContractID.newBuilder().setShardNum(7).setRealmNum(8).setContractNum(9).build()) + .build(); + final byte[] protoBytes = proto.toByteArray(); + printProtoBuf("protoBytes",protoBytes); + + final com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody model = + new com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody( + new com.hedera.hashgraph.hapi.model.ContractID( + 7,8, + new OneOf<>(com.hedera.hashgraph.hapi.model.ContractID.ContractOneOfType.CONTRACT_NUM, 9L)), + null, + null, + null, + null, + null, + new OneOf<>(MemoFieldOneOfType.UNSET,null), + Optional.empty(), + null, + new OneOf<>(StakedIdOneOfType.UNSET, null), + Optional.empty() + ); + final ByteArrayOutputStream bout3 = new ByteArrayOutputStream(); + ContractUpdateTransactionBodyWriter.write(model,bout3); + final byte[] modelBytes = bout3.toByteArray(); + printProtoBuf("modelBytes",modelBytes); + + assertArrayEquals(protoBytes, modelBytes); + + final var readModelBytes = new ContractUpdateTransactionBodyProtoParser().parse(protoBytes); + assertEquals(model, readModelBytes); + } + + /** + * Test missing byte case with below data + * + * ContractUpdateTransactionBody[ + * memoField=OneOf[kind=MEMO_WRAPPER, value=Optional[]], + * maxAutomaticTokenAssociations=Optional[0], + */ + @Test + public void testMissingBytes() throws MalformedProtobufException, IOException { + final ContractUpdateTransactionBody proto = ContractUpdateTransactionBody.newBuilder() + .setMemoWrapper(StringValue.of("")) + .setMaxAutomaticTokenAssociations(Int32Value.of(0)) + .build(); + final byte[] protoBytes = proto.toByteArray(); + printProtoBuf("protoBytes",protoBytes); + + final com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody model = + new com.hedera.hashgraph.hapi.model.contract.ContractUpdateTransactionBody( + null, + null, + null, + null, + null, + null, + new OneOf<>(MemoFieldOneOfType.MEMO_WRAPPER,Optional.of("")), + Optional.of(0), + null, + new OneOf<>(StakedIdOneOfType.UNSET, null), + Optional.empty() + ); + System.out.println("model = " + model); + final ByteArrayOutputStream bout3 = new ByteArrayOutputStream(); + ContractUpdateTransactionBodyWriter.write(model,bout3); + final byte[] modelBytes = bout3.toByteArray(); + printProtoBuf("modelBytes",modelBytes); + + assertArrayEquals(protoBytes, modelBytes); + + final var readModelBytes = new ContractUpdateTransactionBodyProtoParser().parse(protoBytes); + assertEquals(model, readModelBytes); + } + + /** + * Fix one of with boolean false + */ + @Test + public void testOneOfBooleanFalse() throws MalformedProtobufException, IOException { + final CryptoUpdateTransactionBody proto = CryptoUpdateTransactionBody.newBuilder() + .setReceiverSigRequired(false) + .build(); + final byte[] protoBytes = proto.toByteArray(); + printProtoBuf("protoBytes",protoBytes); + + final com.hedera.hashgraph.hapi.model.token.CryptoUpdateTransactionBody model = + new com.hedera.hashgraph.hapi.model.token.CryptoUpdateTransactionBody( + null, + null, + null, + 0, + new OneOf<>(com.hedera.hashgraph.hapi.model.token.CryptoUpdateTransactionBody.SendRecordThresholdFieldOneOfType.UNSET, null), + new OneOf<>(com.hedera.hashgraph.hapi.model.token.CryptoUpdateTransactionBody.ReceiveRecordThresholdFieldOneOfType.UNSET, null), + null, + null, + new OneOf<>(com.hedera.hashgraph.hapi.model.token.CryptoUpdateTransactionBody.ReceiverSigRequiredFieldOneOfType.RECEIVER_SIG_REQUIRED, false), + Optional.empty(), + Optional.empty(), + new OneOf<>(com.hedera.hashgraph.hapi.model.token.CryptoUpdateTransactionBody.StakedIdOneOfType.UNSET, null), + Optional.empty() + ); + System.out.println("model = " + model); + System.out.println("model.receiverSigRequiredField().value() = " + model.receiverSigRequiredField().value()); + final ByteArrayOutputStream bout3 = new ByteArrayOutputStream(); + CryptoUpdateTransactionBodyWriter.write(model,bout3); + final byte[] modelBytes = bout3.toByteArray(); + printProtoBuf("modelBytes",modelBytes); + + assertArrayEquals(protoBytes, modelBytes); + + final var readModelBytes = new CryptoUpdateTransactionBodyProtoParser().parse(protoBytes); + assertEquals(model, readModelBytes); + } + public static final Stream createUints() { return Stream.of( null, @@ -240,56 +555,13 @@ public static final void printProtoBuf(String name, byte[] bytes) { */ static final int TAG_WRITE_TYPE_MASK = 0b0000_0111; } + /* -ContractUpdateTransactionBody[ - contractID=ContractID[ - shardNum=0, realmNum=0, contract=OneOf[ - kind=CONTRACT_NUM, value=-21]], expirationTime=Timestamp[ - seconds=0, nanos=0], adminKey=Key[ - key=OneOf[ - kind=CONTRACT_ID, - value=ContractID[ - shardNum=-21, - realmNum=-21, - contract=OneOf[ - kind=CONTRACT_NUM, - value=-42 - ] - ] - ] - ], - proxyAccountID=AccountID[ - shardNum=0, - realmNum=0, - account=OneOf[ - kind=ACCOUNT_NUM, - value=-21] - ], - autoRenewPeriod=Duration[seconds=0], - fileID=FileID[shardNum=0, realmNum=0, fileNum=0], - memoField=OneOf[kind=MEMO_WRAPPER, value=Optional.empty], - maxAutomaticTokenAssociations=Optional[-21], - autoRenewAccountId=AccountID[ - shardNum=0, - realmNum=0, - account=OneOf[ - kind=ACCOUNT_NUM, value=-21] - ], - stakedId=OneOf[ - kind=STAKED_ACCOUNT_ID, - value=AccountID[ - shardNum=-21, - realmNum=-21, - account=OneOf[ - kind=ACCOUNT_NUM, value=-42 - ] - ] - ], - declineReward=Optional[ - false - ] - ] -ContractUpdateTransactionBody[contractID=ContractID[shardNum=0, realmNum=0, contract=OneOf[kind=CONTRACT_NUM, value=-21]], expirationTime=Timestamp[seconds=0, nanos=0], adminKey=Key[key=OneOf[kind=CONTRACT_ID, value=ContractID[shardNum=-21, realmNum=-21, contract=OneOf[kind=CONTRACT_NUM, value=-42]]]], proxyAccountID=AccountID[shardNum=0, realmNum=0, account=OneOf[kind=ACCOUNT_NUM, value=-21]], autoRenewPeriod=Duration[seconds=0], fileID=FileID[shardNum=0, realmNum=0, fileNum=0], memoField=OneOf[kind=UNSET, value=null], maxAutomaticTokenAssociations=Optional[-21], autoRenewAccountId=AccountID[shardNum=0, realmNum=0, account=OneOf[kind=ACCOUNT_NUM, value=-21]], stakedId=OneOf[kind=STAKED_ACCOUNT_ID, value=AccountID[shardNum=-21, realmNum=-21, account=OneOf[kind=ACCOUNT_NUM, value=-42]]], declineReward=Optional[false]] + + protoBytes 10, 6, 8, 21, 16, 21, 24, 0, 18, 4, 8, 21, 16, 21, 26, 13, 10, 11, 24, -21, -1, -1, -1, -1, -1, -1, -1, -1, 1, 82, 0, 122, 0, + [field|type][ 1| 2],[ 0| 6],[ 1| 0],[ 2| 5],[ 2| 0],[ 2| 5],[ 3| 0],[ 0| 0],[ 2| 2],[ 0| 4],[ 1| 0],[ 2| 5],[ 2| 0],[ 2| 5],[ 3| 2],[ 1| 5],[ 1| 2],[ 1| 3],[ 3| 0],[ -3| 3],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ 0| 1],[ 10| 2],[ 0| 0],[ 15| 2],[ 0| 0], + modelBytes 10, 6, 24, 0, 8, 21, 16, 21, 18, 4, 8, 21, 16, 21, 26, 13, 10, 11, 24, -21, -1, -1, -1, -1, -1, -1, -1, -1, 1, 82, 0, 122, 0, + [field|type][ 1| 2],[ 0| 6],[ 3| 0],[ 0| 0],[ 1| 0],[ 2| 5],[ 2| 0],[ 2| 5],[ 2| 2],[ 0| 4],[ 1| 0],[ 2| 5],[ 2| 0],[ 2| 5],[ 3| 2],[ 1| 5],[ 1| 2],[ 1| 3],[ 3| 0],[ -3| 3],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ -1| 7],[ 0| 1],[ 10| 2],[ 0| 0],[ 15| 2],[ 0| 0], */ \ No newline at end of file