44using System . Linq ;
55using System . Threading ;
66using System . Threading . Tasks ;
7+ using AElf . Cryptography ;
78using AElf . Kernel ;
89using AElf . Kernel . Blockchain . Application ;
910using AElf . Kernel . FeeCalculation . Extensions ;
@@ -36,6 +37,8 @@ public interface ITransactionAppService
3637
3738 Task < SendTransactionOutput > SendTransactionAsync ( SendTransactionInput input ) ;
3839
40+ Task < SendMultiTransactionOutput > SendMultiTransactionAsync ( SendMultiTransactionInput input ) ;
41+
3942 Task < string [ ] > SendTransactionsAsync ( SendTransactionsInput input ) ;
4043
4144 Task < CalculateTransactionFeeOutput > CalculateTransactionFeeAsync ( CalculateTransactionFeeInput input ) ;
@@ -49,19 +52,21 @@ public class TransactionAppService : AElfAppService, ITransactionAppService
4952 private readonly ITransactionResultStatusCacheProvider _transactionResultStatusCacheProvider ;
5053 private readonly IPlainTransactionExecutingService _plainTransactionExecutingService ;
5154 private readonly WebAppOptions _webAppOptions ;
52-
55+ private readonly MultiTransactionOptions _multiTransactionOptions ;
5356
5457 public TransactionAppService ( ITransactionReadOnlyExecutionService transactionReadOnlyExecutionService ,
5558 IBlockchainService blockchainService , IObjectMapper < ChainApplicationWebAppAElfModule > objectMapper ,
5659 ITransactionResultStatusCacheProvider transactionResultStatusCacheProvider ,
5760 IPlainTransactionExecutingService plainTransactionExecutingService ,
58- IOptionsMonitor < WebAppOptions > webAppOptions )
61+ IOptionsMonitor < WebAppOptions > webAppOptions ,
62+ IOptionsSnapshot < MultiTransactionOptions > multiTransactionSignerOptions )
5963 {
6064 _transactionReadOnlyExecutionService = transactionReadOnlyExecutionService ;
6165 _blockchainService = blockchainService ;
6266 _objectMapper = objectMapper ;
6367 _transactionResultStatusCacheProvider = transactionResultStatusCacheProvider ;
6468 _plainTransactionExecutingService = plainTransactionExecutingService ;
69+ _multiTransactionOptions = multiTransactionSignerOptions . Value ;
6570 _webAppOptions = webAppOptions . CurrentValue ;
6671
6772 LocalEventBus = NullLocalEventBus . Instance ;
@@ -238,6 +243,64 @@ public async Task<SendTransactionOutput> SendTransactionAsync(SendTransactionInp
238243 } ;
239244 }
240245
246+ public async Task < SendMultiTransactionOutput > SendMultiTransactionAsync ( SendMultiTransactionInput input )
247+ {
248+ var multiTxBytes = ByteArrayHelper . HexStringToByteArray ( input . RawTransactions ) ;
249+ var multiTransaction = MultiTransaction . Parser . ParseFrom ( multiTxBytes ) ;
250+ if ( multiTransaction . VerifyFields ( ) != MultiTransaction . ValidationStatus . Success )
251+ {
252+ throw new UserFriendlyException ( Error . Message [ Error . InvalidTransaction ] ,
253+ Error . InvalidTransaction . ToString ( ) ) ;
254+ }
255+
256+ CryptoHelper . RecoverPublicKey ( multiTransaction . Signature . ToByteArray ( ) , multiTransaction . GetHash ( ) . ToByteArray ( ) , out var pubkey ) ;
257+
258+ if ( ! await IsGatewayAddress ( Address . FromPublicKey ( pubkey ) ) )
259+ {
260+ throw new UserFriendlyException ( Error . Message [ Error . InvalidGatewaySignature ] ,
261+ Error . InvalidGatewaySignature . ToString ( ) ) ;
262+ }
263+
264+ var chain = await _blockchainService . GetChainAsync ( ) ;
265+ var txListOfCurrentChain = multiTransaction . Transactions
266+ . Where ( t => t . ChainId == chain . Id )
267+ . Select ( t => t . Transaction . ToByteArray ( ) . ToHex ( ) ) . ToArray ( ) ;
268+ var txIds = await PublishTransactionsAsync ( txListOfCurrentChain ) ;
269+
270+ return new SendMultiTransactionOutput
271+ {
272+ TransactionIds = txIds
273+ } ;
274+ }
275+
276+ private async Task < bool > IsGatewayAddress ( Address address )
277+ {
278+ if ( string . IsNullOrEmpty ( _multiTransactionOptions . GatewayAddress ) &&
279+ string . IsNullOrEmpty ( _multiTransactionOptions . GatewayContractAddress ) )
280+ {
281+ return true ;
282+ }
283+
284+ if ( ! string . IsNullOrEmpty ( _multiTransactionOptions . GatewayContractAddress ) )
285+ {
286+ var chain = await _blockchainService . GetChainAsync ( ) ;
287+ var isGatewayAddressBytes = await CallReadOnlyAsync ( new Transaction
288+ {
289+ From = address ,
290+ To = Address . FromBase58 ( _multiTransactionOptions . GatewayContractAddress ) ,
291+ MethodName = "IsGatewayAddress" ,
292+ Params = address . ToByteString ( ) ,
293+ RefBlockNumber = chain . BestChainHeight ,
294+ RefBlockPrefix = BlockHelper . GetRefBlockPrefix ( chain . BestChainHash )
295+ } ) ;
296+ var isGatewayAddress = new BoolValue ( ) ;
297+ isGatewayAddress . MergeFrom ( isGatewayAddressBytes ) ;
298+ return isGatewayAddress . Value ;
299+ }
300+
301+ return _multiTransactionOptions . GatewayAddress == address . ToBase58 ( ) ;
302+ }
303+
241304 /// <summary>
242305 /// Broadcast multiple transactions
243306 /// </summary>
0 commit comments