33using System . Linq ;
44using System . Threading ;
55using System . Threading . Tasks ;
6+ using AElf . CSharp . Core . Extension ;
7+ using AElf . Kernel . Blockchain . Application ;
68using AElf . Kernel . FeatureDisable . Core ;
79using AElf . Kernel . SmartContract . Domain ;
810using AElf . Kernel . SmartContract . Infrastructure ;
@@ -23,14 +25,17 @@ public class PlainTransactionExecutingService : IPlainTransactionExecutingServic
2325 private readonly ISmartContractExecutiveService _smartContractExecutiveService ;
2426 private readonly ITransactionContextFactory _transactionContextFactory ;
2527 private readonly IFeatureDisableService _featureDisableService ;
28+ private readonly IBlockchainService _blockchainService ;
2629
2730 public PlainTransactionExecutingService ( ISmartContractExecutiveService smartContractExecutiveService ,
2831 IEnumerable < IPostExecutionPlugin > postPlugins , IEnumerable < IPreExecutionPlugin > prePlugins ,
29- ITransactionContextFactory transactionContextFactory , IFeatureDisableService featureDisableService )
32+ ITransactionContextFactory transactionContextFactory , IFeatureDisableService featureDisableService ,
33+ IBlockchainService blockchainService )
3034 {
3135 _smartContractExecutiveService = smartContractExecutiveService ;
3236 _transactionContextFactory = transactionContextFactory ;
3337 _featureDisableService = featureDisableService ;
38+ _blockchainService = blockchainService ;
3439 _prePlugins = GetUniquePlugins ( prePlugins ) ;
3540 _postPlugins = GetUniquePlugins ( postPlugins ) ;
3641 Logger = NullLogger < PlainTransactionExecutingService > . Instance ;
@@ -61,6 +66,7 @@ public async Task<List<ExecutionReturnSet>> ExecuteAsync(TransactionExecutingDto
6166 var singleTxExecutingDto = new SingleTransactionExecutingDto
6267 {
6368 Depth = 0 ,
69+ InlineWithTransactionIdCounter = new InlineWithTransactionIdCounter ( ) ,
6470 ChainContext = groupChainContext ,
6571 Transaction = transaction ,
6672 CurrentBlockTime = transactionExecutingDto . BlockHeader . Time ,
@@ -71,7 +77,7 @@ public async Task<List<ExecutionReturnSet>> ExecuteAsync(TransactionExecutingDto
7177 var transactionExecutionTask = Task . Run ( ( ) => ExecuteOneAsync ( singleTxExecutingDto ,
7278 cancellationToken ) , cancellationToken ) ;
7379
74- trace = await transactionExecutionTask . WithCancellation ( cancellationToken ) ;
80+ trace = await transactionExecutionTask ;
7581 }
7682 catch ( OperationCanceledException )
7783 {
@@ -90,7 +96,7 @@ public async Task<List<ExecutionReturnSet>> ExecuteAsync(TransactionExecutingDto
9096 var result = GetTransactionResult ( trace , transactionExecutingDto . BlockHeader . Height ) ;
9197
9298 var returnSet = GetReturnSet ( trace , result ) ;
93- returnSets . Add ( returnSet ) ;
99+ returnSets . AddRange ( returnSet ) ;
94100 }
95101
96102 return returnSets ;
@@ -175,14 +181,22 @@ protected virtual async Task<TransactionTrace> ExecuteOneAsync(
175181
176182 #endregion
177183
184+ var methodName = txContext . Transaction . MethodName ;
185+ var originMethodName = MaybeRecoverInlineTransactionFunctionName ( methodName ) ;
186+ txContext . Transaction . MethodName = originMethodName ;
187+
178188 await executive . ApplyAsync ( txContext ) ;
179189
180190 if ( txContext . Trace . IsSuccessful ( ) )
191+ {
192+ // Maybe layered method name.
193+ txContext . Transaction . MethodName = methodName ;
181194 await ExecuteInlineTransactions ( singleTxExecutingDto . Depth , singleTxExecutingDto . CurrentBlockTime ,
182195 txContext , internalStateCache ,
183196 internalChainContext ,
184197 singleTxExecutingDto . OriginTransactionId ,
185198 cancellationToken ) ;
199+ }
186200
187201 #region PostTransaction
188202
@@ -221,11 +235,40 @@ private async Task ExecuteInlineTransactions(int depth, Timestamp currentBlockTi
221235 {
222236 var trace = txContext . Trace ;
223237 internalStateCache . Update ( txContext . Trace . GetStateSets ( ) ) ;
238+
239+ var methodNameCount = new Dictionary < string , int > ( ) ;
224240 foreach ( var inlineTx in txContext . Trace . InlineTransactions )
225241 {
242+ var needTxId = NeedTransactionId ( inlineTx . MethodName ) ;
243+ if ( needTxId )
244+ {
245+ txContext . InlineWithTransactionIdCounter . Increment ( ) ;
246+ if ( ! methodNameCount . TryAdd ( inlineTx . MethodName , 0 ) )
247+ {
248+ methodNameCount [ inlineTx . MethodName ] ++ ;
249+ inlineTx . MethodName =
250+ GenerateLayeredMethodNameForInlineTransaction (
251+ txContext . Transaction ,
252+ inlineTx . MethodName ,
253+ methodNameCount [ inlineTx . MethodName ]
254+ ) ;
255+ }
256+ else
257+ {
258+ inlineTx . MethodName = GenerateLayeredMethodNameForInlineTransaction (
259+ txContext . Transaction ,
260+ inlineTx . MethodName ,
261+ 0
262+ ) ;
263+ }
264+
265+ await _blockchainService . AddTransactionsAsync ( [ inlineTx ] ) ;
266+ }
267+
226268 var singleTxExecutingDto = new SingleTransactionExecutingDto
227269 {
228270 Depth = depth + 1 ,
271+ InlineWithTransactionIdCounter = txContext . InlineWithTransactionIdCounter ,
229272 ChainContext = internalChainContext ,
230273 Transaction = inlineTx ,
231274 CurrentBlockTime = currentBlockTime ,
@@ -246,6 +289,25 @@ private async Task ExecuteInlineTransactions(int depth, Timestamp currentBlockTi
246289 }
247290 }
248291
292+ private static string GenerateLayeredMethodNameForInlineTransaction ( Transaction parentTx , string inlineFunctionName ,
293+ int index )
294+ {
295+ var parentTxMethodName = parentTx . MethodName ;
296+ inlineFunctionName = inlineFunctionName . StartsWith ( '.' ) ? inlineFunctionName [ 1 ..] : inlineFunctionName ;
297+ return $ "{ parentTx . GetHash ( ) . ToHex ( ) } .{ parentTxMethodName } .{ inlineFunctionName } .{ index } ";
298+ }
299+
300+ private static string MaybeRecoverInlineTransactionFunctionName ( string methodName )
301+ {
302+ var parts = methodName . Split ( '.' ) ;
303+ return parts . Length > 1 ? parts [ ^ 2 ] : methodName ;
304+ }
305+
306+ private static bool NeedTransactionId ( string methodName )
307+ {
308+ return methodName . Contains ( '.' ) ;
309+ }
310+
249311 private async Task < bool > ExecutePluginOnPreTransactionStageAsync ( IExecutive executive ,
250312 ITransactionContext txContext ,
251313 Timestamp currentBlockTime ,
@@ -393,7 +455,7 @@ private TransactionResult GetTransactionResult(TransactionTrace trace, long bloc
393455 return txResult ;
394456 }
395457
396- private ExecutionReturnSet GetReturnSet ( TransactionTrace trace , TransactionResult result )
458+ private IEnumerable < ExecutionReturnSet > GetReturnSet ( TransactionTrace trace , TransactionResult result )
397459 {
398460 var returnSet = new ExecutionReturnSet
399461 {
@@ -402,12 +464,41 @@ private ExecutionReturnSet GetReturnSet(TransactionTrace trace, TransactionResul
402464 Bloom = result . Bloom ,
403465 TransactionResult = result
404466 } ;
467+ var returnSets = new List < ExecutionReturnSet > { returnSet } ;
405468
406469 if ( trace . IsSuccessful ( ) )
407470 {
408471 var transactionExecutingStateSets = trace . GetStateSets ( ) ;
409472 returnSet = GetReturnSet ( returnSet , transactionExecutingStateSets ) ;
410473 returnSet . ReturnValue = trace . ReturnValue ;
474+
475+ var inlineTxWithIdList = trace . GetAllInlineTransactions ( ) . Where ( tx => NeedTransactionId ( tx . MethodName ) ) ;
476+ foreach ( var inlineTx in inlineTxWithIdList )
477+ {
478+ var inlineTxId = inlineTx . GetHash ( ) ;
479+ var inlineReturnSet = new ExecutionReturnSet
480+ {
481+ TransactionId = inlineTxId ,
482+ Status = TransactionResultStatus . Mined ,
483+ TransactionResult = new TransactionResult
484+ {
485+ TransactionId = inlineTxId ,
486+ BlockNumber = result . BlockNumber ,
487+ Status = TransactionResultStatus . Mined
488+ }
489+ } ;
490+
491+ // No need to execute GetReturnSet method, because changes are already set to `returnSet`.
492+
493+ returnSets . Add ( inlineReturnSet ) ;
494+
495+ Logger . LogWarning ( $ "Inline tx id: { inlineTx . GetHash ( ) . ToHex ( ) } \n { inlineTx } ") ;
496+ var log = new InlineTransactionCreated ( )
497+ {
498+ Transaction = inlineTx
499+ } ;
500+ returnSet . TransactionResult . Logs . Add ( log . ToLogEvent ( inlineTx . To ) ) ;
501+ }
411502 }
412503 else
413504 {
@@ -426,7 +517,7 @@ private ExecutionReturnSet GetReturnSet(TransactionTrace trace, TransactionResul
426517 var reads = trace . GetFlattenedReads ( ) ;
427518 foreach ( var read in reads ) returnSet . StateAccesses [ read . Key ] = read . Value ;
428519
429- return returnSet ;
520+ return returnSets ;
430521 }
431522
432523 private ExecutionReturnSet GetReturnSet ( ExecutionReturnSet returnSet ,
@@ -476,6 +567,7 @@ protected ITransactionContext CreateTransactionContext(SingleTransactionExecutin
476567 singleTxExecutingDto . ChainContext , singleTxExecutingDto . OriginTransactionId , origin ,
477568 singleTxExecutingDto . Depth , singleTxExecutingDto . CurrentBlockTime ) ;
478569
570+ txContext . InlineWithTransactionIdCounter = singleTxExecutingDto . InlineWithTransactionIdCounter ;
479571 return txContext ;
480572 }
481573}
0 commit comments