/// <summary> /// get history from withdrawn or deposit table /// </summary> /// <typeparam name="TBlockchainTransaction"></typeparam> /// <param name="repoQuery">withdrawn or deposit</param> /// <param name="offset"></param> /// <param name="limit"></param> /// <param name="orderBy"></param> /// <returns></returns> public virtual List <BlockchainTransaction> GetHistory <TBlockchainTransaction>( IRepositoryBlockchainTransaction <TBlockchainTransaction> repoQuery, int offset = -1, int limit = -1, string[] orderBy = null) { try { Console.WriteLine("FIND HISTORY FROM ABS"); return(repoQuery.FindTransactionHistory(offset, limit, orderBy)); } catch (Exception e) { Console.WriteLine(e.Message); throw e; } }
/// <summary> /// get history from both withdrawn and deposit table /// </summary> /// <param name="tableInternalWithdrawName"></param> /// <param name="offset"></param> /// <param name="limit"></param> /// <param name="orderBy"></param> /// <param name="numberData"></param> /// <param name="currency"></param> /// <param name="withdrawRepository"></param> /// <param name="search"></param> /// <param name="userID"></param> /// <param name="depositRepository"></param> /// <returns></returns> public virtual List <BlockchainTransaction> GetAllHistory <T1, T2>(out int numberData, string userID, string currency, IRepositoryBlockchainTransaction <T1> withdrawRepository, IRepositoryBlockchainTransaction <T2> depositRepository, string tableInternalWithdrawName, int offset = -1, int limit = -1, string[] orderBy = null, string search = null, long day = -1) { try { Console.WriteLine("FIND HISTORY FROM ABS"); return(withdrawRepository.FindTransactionHistoryAll(out numberData, userID, currency, withdrawRepository.GetTableName(), depositRepository.GetTableName(), tableInternalWithdrawName, offset, limit, orderBy, search, day)); } catch (Exception e) { Console.WriteLine(e.Message); throw e; } }
public virtual async Task <ReturnObject> ScanBlockAsync <TWithDraw, TDeposit, TBlockResponse, TTransaction>( string networkName, IRepositoryBlockchainTransaction <TWithDraw> withdrawRepoQuery, IRepositoryBlockchainTransaction <TDeposit> depositRepoQuery, EthereumRpc rpcClass) where TWithDraw : BlockchainTransaction where TDeposit : BlockchainTransaction where TBlockResponse : EthereumBlockResponse where TTransaction : EthereumTransactionResponse { try { int lastBlock = -1; int blockNumber = -1; //Get lastBlock from last time int.TryParse( CacheHelper.GetCacheString(String.Format(RedisCacheKey.KEY_SCANBLOCK_LASTSCANBLOCK, networkName)), out lastBlock); if (lastBlock < 0) { lastBlock = 0; } //get blockNumber: var result = rpcClass.GetBlockNumber(); if (result.Status == Status.STATUS_ERROR) { throw new Exception("Cant GetBlockNumber"); } if (!int.TryParse(result.Data, out blockNumber)) { throw new Exception("Cant parse block number"); } //Get list of new block that have transactions if (lastBlock >= blockNumber) { lastBlock = blockNumber; } //lastBlock = 4519651; //blockNumber = 4519660; Console.WriteLine("SCAN FROM " + lastBlock + "___" + blockNumber); List <TBlockResponse> blocks = new List <TBlockResponse>(); for (int i = lastBlock; i <= blockNumber - 1; i++) { if (i < 0) { continue; } result = rpcClass.GetBlockByNumber(i); if (result.Status == Status.STATUS_ERROR) { return(result); } if (result.Data == null) { continue; } TBlockResponse block = JsonHelper.DeserializeObject <TBlockResponse>(result.Data); if (block.TransactionsResponse.Length > 0) { //if (block.T.Equals(AppSettingHelper.GetSmartContractAddress())) //{ // Console.WriteLine(JsonHelper.SerializeObject(block)); //} //else //{ //} blocks.Add(block); //foreach (var trans in block.TransactionsResponse) //{ // if (trans.To != null) // if (AppSettingHelper.GetSmartContractAddress().ToLower().Equals(trans.To.ToLower())) // { // var paras = rpcClass.DecodeInput(trans.Input); // foreach (var para in paras) // { // Console.WriteLine(para.Parameter.Name + "_" + para.Result.ToString()); // } // // Console.WriteLine(JsonHelper.SerializeObject(trans)); // } //} Console.WriteLine("Add block " + i); } } Console.WriteLine("Total block has transaction: " + blocks.Count); CacheHelper.SetCacheString(String.Format(RedisCacheKey.KEY_SCANBLOCK_LASTSCANBLOCK, networkName), blockNumber.ToString()); if (blocks.Count <= 0) { throw new Exception("no blocks have transaction"); } //Get done,List<> blocks now contains all block that have transaction //check Transaction and update: //Search transactions which need to scan: //var withdrawPendingTransactions = withdrawRepoQuery.FindTransactionsNotCompleteOnNet(); ////Scan all block and check Withdraw transaction: //Console.WriteLine("Scan withdrawPendingTransactions"); //if (withdrawPendingTransactions.Count > 0) //{ // foreach (TBlockResponse block in blocks) // { // if (withdrawPendingTransactions.Count <= 0) // { // //SCAN DONE: // break; // } // for (int i = withdrawPendingTransactions.Count - 1; i >= 0; i--) // { // BlockchainTransaction currentPending = withdrawPendingTransactions[i]; // EthereumTransactionResponse trans = // block.TransactionsResponse.SingleOrDefault(x => x.Hash.Equals(currentPending.Hash)); // int _blockNumber = -1; // int fee = 0; // if (trans != null) // { // trans.BlockNumber.HexToInt(out _blockNumber); // if (trans.Fee != null) // trans.Fee.HexToInt(out fee); // Console.WriteLine("HELLO " + currentPending.Hash); // currentPending.BlockNumber = _blockNumber; // currentPending.Fee = fee; // currentPending.UpdatedAt = (int)CommonHelper.GetUnixTimestamp(); // // _currentPending.Status = Status.StatusCompleted; // // _currentPending.InProcess = 0; // Console.WriteLine("CaLL UPDATE"); // withdrawRepoQuery.Update((TWithDraw)currentPending); // withdrawPendingTransactions.RemoveAt(i); // } // } // } //} Console.WriteLine("Scan withdrawPendingTransactions Done"); using (var dbConnection = SmartContractRepositoryFactory.GetDbConnection()) { var userRepository = SmartContractRepositoryFactory.GetUserRepository(dbConnection); //check wallet balance and update foreach (TBlockResponse block in blocks) { foreach (EthereumTransactionResponse trans in block.TransactionsResponse) { var checkHash = rpcClass.CheckTransactionReceipt(trans.Hash); if (checkHash.Status == Status.STATUS_ERROR) { continue; } if (trans.To != null) { if (AppSettingHelper.GetSmartContractAddress().ToLower().Equals(trans.To.ToLower())) { var paras = rpcClass.DecodeInput(trans.Input); string _fromAddress = ""; string _toAddress = ""; string _value = ""; foreach (var para in paras) { //Console.WriteLine(para.Parameter.Name + "_" + para.Result.ToString()); switch (para.Parameter.Name) { case "_from": _fromAddress = para.Result.ToString(); break; case "_to": _toAddress = para.Result.ToString(); break; case "_value": _value = para.Result.ToString(); break; default: break; } } var user = userRepository.FindByAddress(_toAddress); // var user = userRepository.FindByAddress("123"); // var _sendWallet = wallet.FindWalletByAddressAndNetworkName(toAddress, networkName); if (user == null) //if(false) { //logger.Info(to + " is not exist in Wallet!!!"); continue; } else { //Console.WriteLine("value" + _trans.value); // if (trans.Value.HexToBigInteger(out var transactionValue)) { // var userID = ""; // if (_sendWallet != null) //wallet.UpdateBalanceDeposit(toAddress, EthereumRpc.WeiToEther(transactionValue), // networkName); var _deposite = new EthereumTransaction.EthereumDepositTransaction(); _deposite.Id = CommonHelper.GenerateUuid(); _deposite.FromAddress = _fromAddress; _deposite.ToAddress = _toAddress; _deposite.UserId = user.mem_id; _deposite.Hash = trans.Hash; BigInteger amount = 0; if (BigInteger.TryParse(_value, out amount)) { _deposite.Amount = EthereumRpc.WeiToEther(amount); userRepository.AddBalance(_deposite.UserId, _deposite.Amount); } int bNum = 0; if (trans.BlockNumber.HexToInt(out bNum)) { _deposite.BlockNumber = bNum; } _deposite.Status = Status.STATUS_COMPLETED; _deposite.CreatedAt = (int)CommonHelper.GetUnixTimestamp(); _deposite.UpdatedAt = (int)CommonHelper.GetUnixTimestamp(); depositRepoQuery.Insert(_deposite as TDeposit); } } // Console.WriteLine(JsonHelper.SerializeObject(trans)); } } } } } return(new ReturnObject { Status = Status.STATUS_COMPLETED, Message = "Scan done" }); } catch (Exception e) { return(new ReturnObject { Status = Status.STATUS_ERROR, Message = e.Message }); } }
/// <summary> /// Send Transaction with optimistic lock /// Send with multiple thread /// </summary> /// <param name="repoQuery"></param> /// <param name="rpcClass"></param> /// <param name="privateKey"></param> /// <typeparam name="TBlockchainTransaction"></typeparam> /// <returns></returns> public virtual async Task <ReturnObject> SendTransactionAsync <TBlockchainTransaction>( IRepositoryBlockchainTransaction <TBlockchainTransaction> repoQuery, IBlockchainRpc rpcClass, string privateKey = "") where TBlockchainTransaction : BlockchainTransaction { /* * 1. Query Transaction Withdraw pending * 2. Update Processing = 1, version = version + 1 * 3. Commit Transaction * 4. Call RPC send transaction * 5. Update Transaction Status */ // find transaction pending // var pendingTransaction = repoQuery.FindTransactionPending(); var pendingTransaction = repoQuery.FindRowPending(); if (pendingTransaction?.Id == null) { //if (!CacheHelper.HaveKey("cache")) //{ // long numberOfTicks = (DateTime.Now.Ticks - startTime); // TimeSpan ts = TimeSpan.FromTicks(numberOfTicks); // double minutesFromTs = ts.TotalMinutes; // CacheHelper.SetCacheString("cache", minutesFromTs.ToString()); //} //Console.WriteLine("END TIME " + CacheHelper.GetCacheString("cache")); return(new ReturnObject { Status = Status.STATUS_SUCCESS, Message = "Not found Transaction" }); } if (DbConnection.State != ConnectionState.Open) { //Console.WriteLine(DbConnection.State); DbConnection.Open(); } //begin first transaction var transactionScope = DbConnection.BeginTransaction(); try { //lock transaction for process var resultLock = await repoQuery.LockForProcess(pendingTransaction); if (resultLock.Status == Status.STATUS_ERROR) { transactionScope.Rollback(); return(new ReturnObject { Status = Status.STATUS_SUCCESS, Message = "Cannot Lock For Process" }); } //commit transaction transactionScope.Commit(); } catch (Exception e) { transactionScope.Rollback(); return(new ReturnObject { Status = Status.STATUS_ERROR, Message = e.ToString() }); } //Update Version to Model pendingTransaction.Version += 1; //start send and update var transactionDbSend = DbConnection.BeginTransaction(); try { //Call RPC Transaction //TODO EDIT RPC Class var sendTransaction = await rpcClass.SendTransactionAsync(pendingTransaction); pendingTransaction.Status = sendTransaction.Status; pendingTransaction.IsProcessing = 0; // pendingTransaction.UpdatedAt = (int) CommonHelper.GetUnixTimestamp(); // set in SafeUpdate pendingTransaction.Hash = sendTransaction.Data; //create database email when send success if (sendTransaction.Status == Status.STATUS_COMPLETED) { var email = GetEmailByTransaction(pendingTransaction); if (email != null) { // await CreateDataEmail("Notify send " + pendingTransaction.NetworkName(), // email, pendingTransaction.Amount, // Constants.TEMPLATE_EMAIL_SENT, pendingTransaction.NetworkName(),Constants.TYPE_SEND); await SendMailBusiness.SendMailBusiness.CreateDataEmail("Notify send " + pendingTransaction.NetworkName(), email, pendingTransaction.Amount, pendingTransaction.Id, EmailTemplate.Sent, pendingTransaction.NetworkName(), VakapayRepositoryFactory, false); } } var result = await repoQuery.SafeUpdate(pendingTransaction); if (result.Status == Status.STATUS_ERROR) { transactionDbSend.Rollback(); return(new ReturnObject { Status = Status.STATUS_ERROR, Message = "Cannot Save Transaction Status" }); } transactionDbSend.Commit(); return(new ReturnObject { Status = sendTransaction.Status, Message = sendTransaction.Message, Data = sendTransaction.Data }); } catch (Exception e) { //release lock transactionDbSend.Rollback(); var resultRelease = repoQuery.ReleaseLock(pendingTransaction); Console.WriteLine(JsonHelper.SerializeObject(resultRelease)); throw e; } }
public virtual async Task <ReturnObject> ScanBlockAsync <TWithDraw, TDeposit, TBlockResponse, TTransaction>( string networkName, IWalletBusiness wallet, IRepositoryBlockchainTransaction <TWithDraw> withdrawRepoQuery, IRepositoryBlockchainTransaction <TDeposit> depositRepoQuery, IBlockchainRpc rpcClass) where TWithDraw : BlockchainTransaction where TDeposit : BlockchainTransaction where TBlockResponse : EthereumBlockResponse where TTransaction : EthereumTransactionResponse { try { int lastBlock = -1; int blockNumber = -1; //Get lastBlock from last time int.TryParse( CacheHelper.GetCacheString(String.Format(RedisCacheKey.KEY_SCANBLOCK_LASTSCANBLOCK, networkName)), out lastBlock); if (lastBlock < 0) { lastBlock = 0; } //get blockNumber: var _result = rpcClass.GetBlockNumber(); if (_result.Status == Status.STATUS_ERROR) { throw new Exception("Cant GetBlockNumber"); } if (!int.TryParse(_result.Data.ToString(), out blockNumber)) { throw new Exception("Cant parse block number"); } //Get list of new block that have transactions if (lastBlock >= blockNumber) { lastBlock = blockNumber; } Console.WriteLine("SCAN FROM " + lastBlock + "___" + blockNumber); List <TBlockResponse> blocks = new List <TBlockResponse>(); for (int i = lastBlock; i <= blockNumber; i++) { if (i < 0) { continue; } _result = rpcClass.GetBlockByNumber(i); if (_result.Status == Status.STATUS_ERROR) { return(_result); } if (_result.Data == null) { continue; } TBlockResponse _block = JsonHelper.DeserializeObject <TBlockResponse>(_result.Data.ToString()); if (_block.TransactionsResponse.Length > 0) { blocks.Add(_block); } } CacheHelper.SetCacheString(String.Format(RedisCacheKey.KEY_SCANBLOCK_LASTSCANBLOCK, networkName), blockNumber.ToString()); if (blocks.Count <= 0) { throw new Exception("no blocks have transaction"); } //Get done,List<> blocks now contains all block that have transaction //check Transaction and update: //Search transactions which need to scan: var withdrawPendingTransactions = withdrawRepoQuery.FindTransactionsNotCompleteOnNet(); //Scan all block and check Withdraw transaction: Console.WriteLine("Scan withdrawPendingTransactions"); if (withdrawPendingTransactions.Count > 0) { foreach (TBlockResponse _block in blocks) { if (withdrawPendingTransactions.Count <= 0) { //SCAN DONE: break; } for (int i = withdrawPendingTransactions.Count - 1; i >= 0; i--) { BlockchainTransaction _currentPending = withdrawPendingTransactions[i]; EthereumTransactionResponse _trans = _block.TransactionsResponse.SingleOrDefault(x => x.Hash.Equals(_currentPending.Hash)); int _blockNumber = -1; int _fee = 0; if (_trans != null) { _trans.BlockNumber.HexToInt(out _blockNumber); if (_trans.Fee != null) { _trans.Fee.HexToInt(out _fee); } Console.WriteLine("HELLO " + _currentPending.Hash); _currentPending.BlockNumber = _blockNumber; _currentPending.Fee = _fee; _currentPending.UpdatedAt = (int)CommonHelper.GetUnixTimestamp(); // _currentPending.Status = Status.StatusCompleted; // _currentPending.InProcess = 0; Console.WriteLine("CaLL UPDATE"); portfolioHistoryBusiness.InsertWithPrice(_currentPending.UserId); withdrawRepoQuery.Update((TWithDraw)_currentPending); withdrawPendingTransactions.RemoveAt(i); } } } } Console.WriteLine("Scan withdrawPendingTransactions Done"); //check wallet balance and update foreach (TBlockResponse _block in blocks) { foreach (EthereumTransactionResponse _trans in _block.TransactionsResponse) { string _toAddress = _trans.To; string _fromAddress = _trans.From; if (!wallet.CheckExistedAddress(_toAddress, networkName)) { //logger.Info(to + " is not exist in Wallet!!!"); continue; } else { //Console.WriteLine("value" + _trans.value); int _transaValue = 0; if (_trans.Value.HexToInt(out _transaValue)) { var userID = ""; // portfolioHistoryBusiness.InsertWithPrice(_trans.i); wallet.UpdateBalanceDeposit(_toAddress, (Decimal)_transaValue, networkName); } } } } return(new ReturnObject { Status = Status.STATUS_COMPLETED, Message = "Scan done" }); } catch (Exception e) { return(new ReturnObject { Status = Status.STATUS_ERROR, Message = e.Message }); } }
/// <summary> /// Send Transaction with optimistic lock /// Send with multiple thread /// </summary> /// <param name="repoQuery"></param> /// <param name="rpcClass"></param> /// <param name="privateKey"></param> /// <typeparam name="TBlockchainTransaction"></typeparam> /// <returns></returns> public virtual async Task <ReturnObject> SendTransactionAsync <TBlockchainTransaction>( IRepositoryBlockchainTransaction <TBlockchainTransaction> repoQuery, IBlockchainRpc rpcClass, string privateKey = "") where TBlockchainTransaction : BlockchainTransaction { /* * 1. Query Transaction Withdraw pending * 2. Update Processing = 1, version = version + 1 * 3. Commit Transaction * 4. Call RPC send transaction * 5. Update Transaction Status */ var pendingTransaction = repoQuery.FindRowPending(); if (pendingTransaction?.Id == null) { //Console.WriteLine("END TIME " + CacheHelper.GetCacheString("cache")); return(new ReturnObject { Status = Status.STATUS_SUCCESS, Message = "Not found Transaction" }); } if (DbConnection.State != ConnectionState.Open) { //Console.WriteLine(DbConnection.State); DbConnection.Open(); } //begin first transaction var transactionScope = DbConnection.BeginTransaction(); try { //lock transaction for process var resultLock = await repoQuery.LockForProcess(pendingTransaction); if (resultLock.Status == Status.STATUS_ERROR) { transactionScope.Rollback(); return(new ReturnObject { Status = Status.STATUS_SUCCESS, Message = "Cannot Lock For Process" }); } //commit transaction transactionScope.Commit(); } catch (Exception e) { transactionScope.Rollback(); return(new ReturnObject { Status = Status.STATUS_ERROR, Message = e.ToString() }); } //Update Version to Model pendingTransaction.Version += 1; //start send and update var transactionDbSend = DbConnection.BeginTransaction(); try { //Call RPC Transaction //TODO EDIT RPC Class var sendTransaction = await rpcClass.SendTransactionAsync1(pendingTransaction); pendingTransaction.Status = sendTransaction.Status; pendingTransaction.IsProcessing = 0; pendingTransaction.Hash = sendTransaction.Data; //create database email when send success if (sendTransaction.Status == Status.STATUS_COMPLETED) { // var email = GetEmailByTransaction(pendingTransaction); // if (email != null) // { // // await SendMailBusiness.SendMailBusiness.CreateDataEmail( // "Notify send " + pendingTransaction.NetworkName(), // email, pendingTransaction.Amount, pendingTransaction.Id, // EmailTemplate.Sent, pendingTransaction.NetworkName(), SmartContractRepositoryFactory, // false); // } } var result = await repoQuery.SafeUpdate(pendingTransaction); if (result.Status == Status.STATUS_ERROR) { transactionDbSend.Rollback(); return(new ReturnObject { Status = Status.STATUS_ERROR, Message = "Cannot Save Transaction Status" }); } transactionDbSend.Commit(); return(new ReturnObject { Status = sendTransaction.Status, Message = sendTransaction.Message, Data = sendTransaction.Data }); } catch (Exception e) { //release lock Console.WriteLine(e.Message); transactionDbSend.Rollback(); var resultRelease = repoQuery.ReleaseLock(pendingTransaction); Console.WriteLine(JsonHelper.SerializeObject(resultRelease)); throw e; } }