57
57
import com .hedera .node .app .service .contract .impl .exec .scope .VerificationStrategies ;
58
58
import com .hedera .node .app .service .contract .impl .exec .systemcontracts .common .Call ;
59
59
import com .hedera .node .app .service .contract .impl .exec .systemcontracts .common .CallAddressChecks ;
60
+ import com .hedera .node .app .service .contract .impl .exec .systemcontracts .has .HasCallAttempt ;
61
+ import com .hedera .node .app .service .contract .impl .exec .systemcontracts .has .HasCallFactory ;
60
62
import com .hedera .node .app .service .contract .impl .exec .systemcontracts .hts .HtsCallAttempt ;
61
63
import com .hedera .node .app .service .contract .impl .exec .systemcontracts .hts .HtsCallFactory ;
62
64
import com .hedera .node .app .service .contract .impl .exec .systemcontracts .hts .SyntheticIds ;
86
88
import java .util .Map ;
87
89
import java .util .Optional ;
88
90
import java .util .function .Consumer ;
91
+ import org .apache .tuweni .units .bigints .UInt256 ;
89
92
import org .hyperledger .besu .datatypes .Wei ;
90
93
import org .hyperledger .besu .evm .frame .MessageFrame ;
91
94
import org .hyperledger .besu .evm .precompile .PrecompiledContract ;
95
+ import org .jetbrains .annotations .NotNull ;
92
96
import org .junit .jupiter .api .BeforeEach ;
93
97
import org .mockito .Mock ;
94
98
import org .mockito .Mockito ;
@@ -114,15 +118,24 @@ public abstract class AbstractContractXTest extends AbstractXTest {
114
118
@ Mock
115
119
private CallAddressChecks addressChecks ;
116
120
117
- private HtsCallFactory callAttemptFactory ;
121
+ private HtsCallFactory callHtsAttemptFactory ;
122
+
123
+ private HasCallFactory callHasAttemptFactory ;
118
124
119
125
protected ContractScaffoldingComponent component ;
120
126
127
+ public enum SystemContractCallType {
128
+ HTS_CALL ,
129
+ HAS_CALL
130
+ }
131
+
121
132
@ BeforeEach
122
133
void setUp () {
123
134
component = DaggerContractScaffoldingComponent .factory ().create (metrics , configuration (), storeMetricsService );
124
- callAttemptFactory = new HtsCallFactory (
135
+ callHtsAttemptFactory = new HtsCallFactory (
125
136
LIVE_SYNTHETIC_IDS , addressChecks , LIVE_VERIFICATION_STRATEGIES , component .callHtsTranslators ());
137
+ callHasAttemptFactory = new HasCallFactory (
138
+ LIVE_SYNTHETIC_IDS , addressChecks , LIVE_VERIFICATION_STRATEGIES , component .callHasTranslators ());
126
139
}
127
140
128
141
protected Configuration configuration () {
@@ -196,13 +209,18 @@ private void runHtsCallAndExpectOnSuccess(
196
209
@ NonNull final org .apache .tuweni .bytes .Bytes input ,
197
210
@ NonNull final Consumer <org .apache .tuweni .bytes .Bytes > outputAssertions ,
198
211
@ Nullable final String context ) {
199
- runHtsCallAndExpect (requiresDelegatePermission , sender , input , resultOnlyAssertion (result -> {
200
- assertEquals (
201
- MessageFrame .State .COMPLETED_SUCCESS ,
202
- result .getState (),
203
- Optional .ofNullable (context ).orElse ("An unspecified operation" ) + " should have succeeded" );
204
- outputAssertions .accept (result .getOutput ());
205
- }));
212
+ runCallAndExpect (
213
+ requiresDelegatePermission ,
214
+ SystemContractCallType .HTS_CALL ,
215
+ sender ,
216
+ input ,
217
+ resultOnlyAssertion (result -> {
218
+ assertEquals (
219
+ MessageFrame .State .COMPLETED_SUCCESS ,
220
+ result .getState (),
221
+ Optional .ofNullable (context ).orElse ("An unspecified operation" ) + " should have succeeded" );
222
+ outputAssertions .accept (result .getOutput ());
223
+ }));
206
224
}
207
225
208
226
protected void runHtsCallAndExpectRevert (
@@ -233,7 +251,7 @@ private void internalRunHtsCallAndExpectRevert(
233
251
@ NonNull final org .apache .tuweni .bytes .Bytes input ,
234
252
@ NonNull final ResponseCodeEnum status ,
235
253
@ Nullable final String context ) {
236
- runHtsCallAndExpect (false , sender , input , resultOnlyAssertion (result -> {
254
+ runCallAndExpect (false , SystemContractCallType . HTS_CALL , sender , input , resultOnlyAssertion (result -> {
237
255
assertEquals (
238
256
MessageFrame .State .REVERT ,
239
257
result .getState (),
@@ -248,8 +266,59 @@ private void internalRunHtsCallAndExpectRevert(
248
266
}));
249
267
}
250
268
251
- private void runHtsCallAndExpect (
269
+ protected void runHasCallAndExpectOnSuccess (
270
+ @ NonNull final org .hyperledger .besu .datatypes .Address sender ,
271
+ @ NonNull final org .apache .tuweni .bytes .Bytes input ,
272
+ @ NonNull final Consumer <org .apache .tuweni .bytes .Bytes > outputAssertions ,
273
+ @ Nullable final String context ) {
274
+ runCallAndExpect (false , SystemContractCallType .HAS_CALL , sender , input , resultOnlyAssertion (result -> {
275
+ assertEquals (
276
+ MessageFrame .State .COMPLETED_SUCCESS ,
277
+ result .getState (),
278
+ Optional .ofNullable (context ).orElse ("An unspecified operation" ) + " should have succeeded" );
279
+ outputAssertions .accept (result .getOutput ());
280
+ }));
281
+ }
282
+
283
+ protected void runHasCallAndExpectRevert (
284
+ @ NonNull final org .hyperledger .besu .datatypes .Address sender ,
285
+ @ NonNull final org .apache .tuweni .bytes .Bytes input ,
286
+ @ NonNull final ResponseCodeEnum status ,
287
+ @ NonNull final String context ,
288
+ final boolean useOrdinal ) {
289
+ internalRunHasCallAndExpectRevert (sender , input , status , context , useOrdinal );
290
+ }
291
+
292
+ private void internalRunHasCallAndExpectRevert (
293
+ @ NonNull final org .hyperledger .besu .datatypes .Address sender ,
294
+ @ NonNull final org .apache .tuweni .bytes .Bytes input ,
295
+ @ NonNull final ResponseCodeEnum status ,
296
+ @ Nullable final String context ,
297
+ final boolean useOrdinal ) {
298
+ runCallAndExpect (false , SystemContractCallType .HAS_CALL , sender , input , resultOnlyAssertion (result -> {
299
+ assertEquals (
300
+ MessageFrame .State .REVERT ,
301
+ result .getState (),
302
+ Optional .ofNullable (context ).orElse ("An unspecified operation" ) + " should have reverted" );
303
+ ResponseCodeEnum actualReason ;
304
+ if (useOrdinal ) {
305
+ actualReason = ResponseCodeEnum .fromProtobufOrdinal (
306
+ UInt256 .fromBytes (result .getOutput ()).intValue ());
307
+ } else {
308
+ actualReason = ResponseCodeEnum .fromString (
309
+ new String (result .getOutput ().toArrayUnsafe ()));
310
+ }
311
+ assertEquals (
312
+ status ,
313
+ actualReason ,
314
+ "'" + Optional .ofNullable (context ).orElse ("An unspecified operation" )
315
+ + "' should have reverted with " + status + " but instead reverted with " + actualReason );
316
+ }));
317
+ }
318
+
319
+ private void runCallAndExpect (
252
320
final boolean requiresDelegatePermission ,
321
+ @ NonNull final SystemContractCallType callType ,
253
322
@ NonNull final org .hyperledger .besu .datatypes .Address sender ,
254
323
@ NonNull final org .apache .tuweni .bytes .Bytes input ,
255
324
@ NonNull final Consumer <Call .PricedResult > resultAssertions ) {
@@ -288,15 +357,39 @@ private void runHtsCallAndExpect(
288
357
given (addressChecks .hasParentDelegateCall (frame )).willReturn (requiresDelegatePermission );
289
358
Mockito .lenient ().when (frame .getValue ()).thenReturn (Wei .MAX_WEI );
290
359
291
- final var attempt = callAttemptFactory .createCallAttemptFrom (input , DIRECT_OR_PROXY_REDIRECT , frame );
292
- final var call = attempt .asExecutableCall ();
360
+ Call .PricedResult pricedResult =
361
+ switch (callType ) {
362
+ case HTS_CALL -> {
363
+ yield getHtsPricedResult (input );
364
+ }
365
+ case HAS_CALL -> {
366
+ yield getHasPricedResult (input );
367
+ }
368
+ };
293
369
294
- final var pricedResult = requireNonNull (call ).execute (frame );
295
370
resultAssertions .accept (pricedResult );
296
371
// Note that committing a reverted calls should have no effect on state
297
372
((SavepointStackImpl ) context .savepointStack ()).commitFullStack ();
298
373
}
299
374
375
+ @ NotNull
376
+ private Call .PricedResult getHtsPricedResult (@ NonNull org .apache .tuweni .bytes .Bytes input ) {
377
+ final var attempt = callHtsAttemptFactory .createCallAttemptFrom (input , DIRECT_OR_PROXY_REDIRECT , frame );
378
+ final var call = attempt .asExecutableCall ();
379
+
380
+ final var pricedResult = requireNonNull (call ).execute (frame );
381
+ return pricedResult ;
382
+ }
383
+
384
+ @ NotNull
385
+ private Call .PricedResult getHasPricedResult (@ NonNull org .apache .tuweni .bytes .Bytes input ) {
386
+ final var attempt = callHasAttemptFactory .createCallAttemptFrom (input , DIRECT_OR_PROXY_REDIRECT , frame );
387
+ final var call = attempt .asExecutableCall ();
388
+
389
+ final var pricedResult = requireNonNull (call ).execute (frame );
390
+ return pricedResult ;
391
+ }
392
+
300
393
protected TransactionBody createCallTransactionBody (
301
394
final AccountID payer ,
302
395
final long value ,
@@ -379,6 +472,23 @@ public static org.apache.tuweni.bytes.Bytes bytesForRedirect(
379
472
org .apache .tuweni .bytes .Bytes .of (subSelector ));
380
473
}
381
474
475
+ //
476
+ // Encode given a ByteBuffer and accountId input bytes for a call to a given contract.
477
+ // Largely, this is used to encode the call to redirectToAccount() proxy contract for testing purposes.
478
+ // Copied here from TestHelpers as that class is not available in this package.
479
+ public static org .apache .tuweni .bytes .Bytes bytesForRedirectForAccount (
480
+ final ByteBuffer encodedErcCall , final AccountID accountID ) {
481
+ return bytesForRedirectForAccount (encodedErcCall .array (), asLongZeroAddress (accountID .accountNum ()));
482
+ }
483
+
484
+ public static org .apache .tuweni .bytes .Bytes bytesForRedirectForAccount (
485
+ final byte [] subSelector , final org .hyperledger .besu .datatypes .Address accountAddress ) {
486
+ return org .apache .tuweni .bytes .Bytes .concatenate (
487
+ org .apache .tuweni .bytes .Bytes .wrap (HasCallAttempt .REDIRECT_FOR_ACCOUNT .selector ()),
488
+ accountAddress ,
489
+ org .apache .tuweni .bytes .Bytes .of (subSelector ));
490
+ }
491
+
382
492
public static org .apache .tuweni .bytes .Bytes asBytesResult (final ByteBuffer encoded ) {
383
493
return org .apache .tuweni .bytes .Bytes .wrap (encoded .array ());
384
494
}
0 commit comments