Skip to content

Commit 7d9e0c7

Browse files
authored
feat(TCK): endpoint for ContractUpdate (#2477)
Signed-off-by: emiliyank <e.kadiyski@gmail.com>
1 parent aef471d commit 7d9e0c7

5 files changed

Lines changed: 226 additions & 5 deletions

File tree

sdk/src/main/java/com/hedera/hashgraph/sdk/ContractUpdateTransaction.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
import com.google.protobuf.Int32Value;
66
import com.google.protobuf.InvalidProtocolBufferException;
77
import com.google.protobuf.StringValue;
8-
import com.hedera.hashgraph.sdk.proto.ContractUpdateTransactionBody;
9-
import com.hedera.hashgraph.sdk.proto.SchedulableTransactionBody;
10-
import com.hedera.hashgraph.sdk.proto.SmartContractServiceGrpc;
11-
import com.hedera.hashgraph.sdk.proto.TransactionBody;
8+
import com.hedera.hashgraph.sdk.proto.*;
129
import com.hedera.hashgraph.sdk.proto.TransactionResponse;
1310
import io.grpc.MethodDescriptor;
1411
import java.time.Duration;
@@ -53,6 +50,8 @@ public final class ContractUpdateTransaction extends Transaction<ContractUpdateT
5350
@Nullable
5451
private Instant expirationTime = null;
5552

53+
private Duration expirationTimeDuration = null;
54+
5655
@Nullable
5756
private Key adminKey = null;
5857

@@ -154,6 +153,15 @@ public ContractUpdateTransaction setExpirationTime(Instant expirationTime) {
154153
Objects.requireNonNull(expirationTime);
155154
requireNotFrozen();
156155
this.expirationTime = expirationTime;
156+
this.expirationTimeDuration = null;
157+
return this;
158+
}
159+
160+
public ContractUpdateTransaction setExpirationTime(Duration expirationTime) {
161+
Objects.requireNonNull(expirationTime);
162+
requireNotFrozen();
163+
this.expirationTime = null;
164+
this.expirationTimeDuration = expirationTime;
157165
return this;
158166
}
159167

@@ -566,6 +574,9 @@ ContractUpdateTransactionBody.Builder build() {
566574
if (expirationTime != null) {
567575
builder.setExpirationTime(InstantConverter.toProtobuf(expirationTime));
568576
}
577+
if (expirationTimeDuration != null) {
578+
builder.setExpirationTime(InstantConverter.toProtobuf(expirationTimeDuration));
579+
}
569580
if (adminKey != null) {
570581
builder.setAdminKey(adminKey.toProtobufKey());
571582
}
@@ -593,7 +604,11 @@ ContractUpdateTransactionBody.Builder build() {
593604
}
594605

595606
if (autoRenewAccountId != null) {
596-
builder.setAutoRenewAccountId(autoRenewAccountId.toProtobuf());
607+
if (autoRenewAccountId.toString().equals("0.0.0")) {
608+
builder.setAutoRenewAccountId(AccountID.getDefaultInstance());
609+
} else {
610+
builder.setAutoRenewAccountId(autoRenewAccountId.toProtobuf());
611+
}
597612
}
598613

599614
return builder;

sdk/src/test/java/com/hedera/hashgraph/sdk/ContractUpdateTransactionTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package com.hedera.hashgraph.sdk;
33

44
import static org.assertj.core.api.Assertions.assertThat;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
56

67
import com.hedera.hashgraph.sdk.proto.ContractUpdateTransactionBody;
78
import com.hedera.hashgraph.sdk.proto.SchedulableTransactionBody;
@@ -96,6 +97,43 @@ void shouldBytes2() throws Exception {
9697
assertThat(tx2.toString()).isEqualTo(tx.toString());
9798
}
9899

100+
@Test
101+
void shouldSupportExpirationTimeDurationBytesRoundTrip() throws Exception {
102+
var tx = new ContractUpdateTransaction()
103+
.setNodeAccountIds(Arrays.asList(AccountId.fromString("0.0.5005"), AccountId.fromString("0.0.5006")))
104+
.setTransactionId(TransactionId.withValidStart(AccountId.fromString("0.0.5006"), validStart))
105+
.setContractId(ContractId.fromString("0.0.5007"))
106+
.setAdminKey(privateKey)
107+
.setMaxAutomaticTokenAssociations(101)
108+
.setAutoRenewPeriod(Duration.ofDays(1))
109+
.setContractMemo("with-duration")
110+
.setStakedAccountId(AccountId.fromString("0.0.3"))
111+
.setExpirationTime(Duration.ofSeconds(1234))
112+
.setProxyAccountId(new AccountId(0, 0, 4))
113+
.setMaxTransactionFee(Hbar.fromTinybars(100_000))
114+
.setAutoRenewAccountId(new AccountId(0, 0, 30));
115+
116+
// When expiration is set via Duration, Instant getter should be null
117+
assertThat(tx.getExpirationTime()).isNull();
118+
119+
var tx2 = (ContractUpdateTransaction) Transaction.fromBytes(tx.toBytes());
120+
assertThat(tx2.toString()).isEqualTo(tx.toString());
121+
assertThat(tx2.getExpirationTime()).isEqualTo(Instant.ofEpochSecond(1234));
122+
}
123+
124+
@Test
125+
void setExpirationTimeDurationOnFrozenTransactionShouldThrow() {
126+
var tx = spawnTestTransaction();
127+
assertThrows(IllegalStateException.class, () -> tx.setExpirationTime(Duration.ofSeconds(1)));
128+
}
129+
130+
@Test
131+
void getSetExpirationTimeInstant() {
132+
var instant = Instant.ofEpochSecond(1_234_567L);
133+
var tx = new ContractUpdateTransaction().setExpirationTime(instant);
134+
assertThat(tx.getExpirationTime()).isEqualTo(instant);
135+
}
136+
99137
@Test
100138
void fromScheduledTransaction() {
101139
var transactionBody = SchedulableTransactionBody.newBuilder()

sdk/src/testIntegration/java/com/hedera/hashgraph/sdk/test/integration/ContractUpdateIntegrationTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,60 @@ void cannotUpdateContractThatIsImmutable() throws Exception {
133133
.withMessageContaining(Status.MODIFYING_IMMUTABLE_CONTRACT.toString());
134134
}
135135
}
136+
137+
@Test
138+
@DisplayName("Setting autoRenewAccountId to 0.0.0 clears the field")
139+
void settingAutoRenewAccountIdToDefaultClearsField() throws Exception {
140+
try (var testEnv = new IntegrationTestEnv(1)) {
141+
142+
var response = new FileCreateTransaction()
143+
.setKeys(testEnv.operatorKey)
144+
.setContents(SMART_CONTRACT_BYTECODE)
145+
.execute(testEnv.client);
146+
147+
var fileId = Objects.requireNonNull(response.getReceipt(testEnv.client).fileId);
148+
149+
response = new ContractCreateTransaction()
150+
.setAdminKey(testEnv.operatorKey)
151+
.setGas(400000)
152+
.setConstructorParameters(new ContractFunctionParameters().addString("Hello from Hedera."))
153+
.setBytecodeFileId(fileId)
154+
.setContractMemo("[e2e::ContractCreateTransaction]")
155+
.execute(testEnv.client);
156+
157+
var contractId = Objects.requireNonNull(response.getReceipt(testEnv.client).contractId);
158+
159+
new ContractUpdateTransaction()
160+
.setContractId(contractId)
161+
.setAutoRenewAccountId(testEnv.operatorId)
162+
.execute(testEnv.client)
163+
.getReceipt(testEnv.client);
164+
165+
var infoWithAutoRenew =
166+
new ContractInfoQuery().setContractId(contractId).execute(testEnv.client);
167+
assertThat(Objects.requireNonNull(infoWithAutoRenew.autoRenewAccountId))
168+
.isEqualTo(testEnv.operatorId);
169+
170+
new ContractUpdateTransaction()
171+
.setContractId(contractId)
172+
.setAutoRenewAccountId(new com.hedera.hashgraph.sdk.AccountId(0, 0, 0))
173+
.execute(testEnv.client)
174+
.getReceipt(testEnv.client);
175+
176+
var infoCleared = new ContractInfoQuery().setContractId(contractId).execute(testEnv.client);
177+
assertThat(Objects.requireNonNull(infoCleared.autoRenewAccountId))
178+
.isEqualTo(new com.hedera.hashgraph.sdk.AccountId(0, 0, 0));
179+
180+
new ContractDeleteTransaction()
181+
.setTransferAccountId(testEnv.operatorId)
182+
.setContractId(contractId)
183+
.execute(testEnv.client)
184+
.getReceipt(testEnv.client);
185+
186+
new FileDeleteTransaction()
187+
.setFileId(fileId)
188+
.execute(testEnv.client)
189+
.getReceipt(testEnv.client);
190+
}
191+
}
136192
}

tck/src/main/java/com/hedera/hashgraph/tck/methods/sdk/ContractService.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.hedera.hashgraph.tck.methods.AbstractJSONRPC2Service;
1010
import com.hedera.hashgraph.tck.methods.sdk.param.contract.CreateContractParams;
1111
import com.hedera.hashgraph.tck.methods.sdk.param.contract.ExecuteContractParams;
12+
import com.hedera.hashgraph.tck.methods.sdk.param.contract.UpdateContractParams;
1213
import com.hedera.hashgraph.tck.methods.sdk.response.ContractResponse;
1314
import com.hedera.hashgraph.tck.util.KeyUtils;
1415
import java.time.Duration;
@@ -101,4 +102,54 @@ public ContractResponse executeContract(final ExecuteContractParams params) thro
101102

102103
return new ContractResponse("", receipt.status);
103104
}
105+
106+
@JSONRPC2Method("updateContract")
107+
public ContractResponse updateContract(final UpdateContractParams params) throws Exception {
108+
ContractUpdateTransaction transaction = new ContractUpdateTransaction().setGrpcDeadline(DEFAULT_GRPC_DEADLINE);
109+
110+
params.getContractId()
111+
.ifPresent(contractIdStr -> transaction.setContractId(ContractId.fromString(contractIdStr)));
112+
113+
params.getAdminKey().ifPresent(key -> {
114+
try {
115+
transaction.setAdminKey(KeyUtils.getKeyFromString(key));
116+
} catch (InvalidProtocolBufferException e) {
117+
throw new IllegalArgumentException(e);
118+
}
119+
});
120+
121+
params.getAutoRenewPeriod()
122+
.ifPresent(periodStr -> transaction.setAutoRenewPeriod(Duration.ofSeconds(Long.parseLong(periodStr))));
123+
124+
params.getAutoRenewAccountId()
125+
.ifPresent(accountIdStr -> transaction.setAutoRenewAccountId(AccountId.fromString(accountIdStr)));
126+
127+
params.getStakedAccountId()
128+
.ifPresent(accountIdStr -> transaction.setStakedAccountId(AccountId.fromString(accountIdStr)));
129+
130+
params.getStakedNodeId().ifPresent(nodeIdStr -> transaction.setStakedNodeId(Long.parseLong(nodeIdStr)));
131+
132+
params.getDeclineStakingReward().ifPresent(transaction::setDeclineStakingReward);
133+
134+
params.getMemo().ifPresent(transaction::setContractMemo);
135+
136+
params.getMaxAutomaticTokenAssociations()
137+
.ifPresent(maxAuto -> transaction.setMaxAutomaticTokenAssociations(maxAuto.intValue()));
138+
139+
params.getExpirationTime().ifPresent(expirationTimeStr -> {
140+
try {
141+
long expirationTimeSeconds = Long.parseLong(expirationTimeStr);
142+
transaction.setExpirationTime(Duration.ofSeconds(expirationTimeSeconds));
143+
} catch (NumberFormatException e) {
144+
throw new IllegalArgumentException("Invalid expiration time: " + expirationTimeStr, e);
145+
}
146+
});
147+
148+
params.getCommonTransactionParams()
149+
.ifPresent(common -> common.fillOutTransaction(transaction, sdkService.getClient()));
150+
151+
TransactionReceipt receipt = transaction.execute(sdkService.getClient()).getReceipt(sdkService.getClient());
152+
153+
return new ContractResponse(null, receipt.status);
154+
}
104155
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
package com.hedera.hashgraph.tck.methods.sdk.param.contract;
3+
4+
import com.hedera.hashgraph.tck.methods.JSONRPC2Param;
5+
import com.hedera.hashgraph.tck.methods.sdk.param.CommonTransactionParams;
6+
import com.hedera.hashgraph.tck.util.JSONRPCParamParser;
7+
import java.util.Map;
8+
import java.util.Optional;
9+
import lombok.AllArgsConstructor;
10+
import lombok.Getter;
11+
import lombok.NoArgsConstructor;
12+
13+
/**
14+
* UpdateContractParams for contract update method
15+
*/
16+
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
17+
@Getter
18+
@AllArgsConstructor
19+
@NoArgsConstructor
20+
public class UpdateContractParams extends JSONRPC2Param {
21+
private Optional<String> contractId;
22+
private Optional<String> adminKey;
23+
private Optional<String> autoRenewPeriod;
24+
private Optional<String> autoRenewAccountId;
25+
private Optional<String> stakedAccountId;
26+
private Optional<String> stakedNodeId;
27+
private Optional<Boolean> declineStakingReward;
28+
private Optional<String> memo;
29+
private Optional<Long> maxAutomaticTokenAssociations;
30+
private Optional<String> expirationTime;
31+
private Optional<CommonTransactionParams> commonTransactionParams;
32+
33+
@Override
34+
public UpdateContractParams parse(Map<String, Object> jrpcParams) throws Exception {
35+
var parsedContractId = Optional.ofNullable((String) jrpcParams.get("contractId"));
36+
var parsedAdminKey = Optional.ofNullable((String) jrpcParams.get("adminKey"));
37+
var parsedAutoRenewPeriod = Optional.ofNullable((String) jrpcParams.get("autoRenewPeriod"));
38+
var parsedAutoRenewAccountId = Optional.ofNullable((String) jrpcParams.get("autoRenewAccountId"));
39+
var parsedStakedAccountId = Optional.ofNullable((String) jrpcParams.get("stakedAccountId"));
40+
var parsedStakedNodeId = Optional.ofNullable((String) jrpcParams.get("stakedNodeId"));
41+
var parsedDeclineStakingReward = Optional.ofNullable((Boolean) jrpcParams.get("declineStakingReward"));
42+
var parsedMemo = Optional.ofNullable((String) jrpcParams.get("memo"));
43+
var parsedMaxAutomaticTokenAssociations =
44+
Optional.ofNullable((Long) jrpcParams.get("maxAutomaticTokenAssociations"));
45+
var parsedExpirationTime = Optional.ofNullable((String) jrpcParams.get("expirationTime"));
46+
var parsedCommonTransactionParams = JSONRPCParamParser.parseCommonTransactionParams(jrpcParams);
47+
48+
return new UpdateContractParams(
49+
parsedContractId,
50+
parsedAdminKey,
51+
parsedAutoRenewPeriod,
52+
parsedAutoRenewAccountId,
53+
parsedStakedAccountId,
54+
parsedStakedNodeId,
55+
parsedDeclineStakingReward,
56+
parsedMemo,
57+
parsedMaxAutomaticTokenAssociations,
58+
parsedExpirationTime,
59+
parsedCommonTransactionParams);
60+
}
61+
}

0 commit comments

Comments
 (0)