public TransactionMsg deposit(dwacc value) { TransactionMsg ob = new TransactionMsg(); ob.Message = "Success"; return(ob); }
public TransactionMsg withdraw(dwacc value) { TransactionMsg ob = new TransactionMsg(); string data = JsonConvert.SerializeObject(value); StringContent content = new StringContent(data, Encoding.UTF8, "application/json"); HttpResponseMessage response = client.PostAsync(client.BaseAddress + "/Rules/evaluateMinBal/", content).Result; if (response.IsSuccessStatusCode) { string data1 = response.Content.ReadAsStringAsync().Result; ruleStatus s1 = JsonConvert.DeserializeObject <ruleStatus>(data1); if (s1.message == "Warning") { ob.Message = "Warning"; return(ob); } ob.Message = "No Warning"; return(ob); } return(null); }
public TransactionMsg transfer(transfers value) { dwacc ob4 = new dwacc { AccountId = value.source_accid, Balance = value.amount }; TransactionMsg ob = new TransactionMsg(); string data = JsonConvert.SerializeObject(ob4); StringContent content = new StringContent(data, Encoding.UTF8, "application/json"); HttpResponseMessage response = client.PostAsync(client.BaseAddress + "/Rules/evaluateMinBal/", content).Result; if (response.IsSuccessStatusCode) { string data1 = response.Content.ReadAsStringAsync().Result; ruleStatus s1 = JsonConvert.DeserializeObject <ruleStatus>(data1); if (s1.message == "Warning") { ob.Message = "Warning"; return(ob); } ob.Message = "No Warning"; return(ob); } return(null); }
private BlockMsg convertEntityToBlockMsg(Block entity) { var txDac = new TransactionDac(); var inputDac = new InputDac(); var outputDac = new OutputDac(); var blockMsg = new BlockMsg(); var headerMsg = new BlockHeaderMsg(); headerMsg.Version = entity.Version; headerMsg.Hash = entity.Hash; headerMsg.Height = entity.Height; headerMsg.PreviousBlockHash = entity.PreviousBlockHash; headerMsg.Bits = entity.Bits; headerMsg.Nonce = entity.Nonce; headerMsg.Timestamp = entity.Timestamp; var transactions = txDac.SelectByBlockHash(entity.Hash); headerMsg.TotalTransaction = transactions == null ? 0: transactions.Count; foreach (var tx in transactions) { var txMsg = new TransactionMsg(); txMsg.Version = tx.Version; txMsg.Hash = tx.Hash; txMsg.Timestamp = tx.Timestamp; txMsg.Locktime = tx.LockTime; var inputs = inputDac.SelectByTransactionHash(tx.Hash); var outputs = outputDac.SelectByTransactionHash(tx.Hash); foreach (var input in inputs) { txMsg.Inputs.Add(new InputMsg { OutputTransactionHash = input.OutputTransactionHash, OutputIndex = input.OutputIndex, Size = input.Size, UnlockScript = input.UnlockScript }); } foreach (var output in outputs) { txMsg.Outputs.Add(new OutputMsg { Index = output.Index, Amount = output.Amount, Size = output.Size, LockScript = output.LockScript }); } blockMsg.Transactions.Add(txMsg); } blockMsg.Header = headerMsg; return(blockMsg); }
public static bool Consume(string pFilePath) { try { if (isImportFile(pFilePath)) { new DialPlanImportExportTask().Run(pFilePath); } else { var _txMsg = TransactionMsg.Deserialize(pFilePath); if (_txMsg == null) { TimokLogger.Instance.LogRbr(LogSeverity.Critical, "R_Rbr.Consume", string.Format("TransactionMsg.Deserialize Error, File={0}", pFilePath)); return(false); } _txMsg.Execute(); } TimokLogger.Instance.LogRbr(LogSeverity.Status, "R_Rbr.Consume", string.Format("Finished, File={0}", pFilePath)); } catch (Exception _ex) { TimokLogger.Instance.LogRbr(LogSeverity.Critical, "R_Rbr.Consume", string.Format("File={0}, Exception:\r\n{1}", pFilePath, _ex)); return(false); } return(true); }
public void AddTxNoOutput(TransactionMsg transaction) { if (IsolateTxHashes.Contains(transaction.Hash)) { return; } Storage.Instance.PutData(IsolateTxsContainerName, transaction.Hash, transaction); var myAccounts = AccountDac.Default.GetAccountBook(); var outputs = transaction.GetUtxoSets(); var myOutputs = outputs.Where(x => myAccounts.Contains(x.Account)); var spents = transaction.Inputs.Select(x => $"{x.OutputTransactionHash}_{x.OutputIndex}").ToArray(); Monitor.Enter(isolateObj); IsolateTxHashes.Add(transaction.Hash); foreach (var myOutput in myOutputs) { var key = $"{myOutput.TransactionHash}_{myOutput.Index}"; MyIsolateUtxoSets.Add(key, myOutput); } IsolateSpentUtxos.AddRange(spents); Monitor.Exit(isolateObj); if (IsolateTxsExecThread == null || !IsolateTxsExecThread.IsAlive) { IsolateTxsExecThread = new Thread(new ParameterizedThreadStart(Start)); IsolateTxsExecThread.Start(); } }
public static Transaction ConvertToEntity(this TransactionMsg transactionMsg, TransExtensionParams transExtension, bool isCoinbase = false) { Transaction transaction = new Transaction(); transaction.BlockHash = transExtension.BlockHash; transaction.ExpiredTime = transactionMsg.ExpiredTime; transaction.Hash = transactionMsg.Hash; transaction.Inputs = transExtension.Inputs; transaction.IsDiscarded = false; transaction.LockTime = transactionMsg.Locktime; transaction.Outputs = transExtension.Outputs; transaction.Size = transactionMsg.Size; transaction.Timestamp = transactionMsg.Timestamp; transaction.TotalInput = transExtension.TotalInput; transaction.TotalOutput = transExtension.TotalOutput; transaction.Version = transactionMsg.Version; if (isCoinbase) { transaction.Fee = 0; } else { transaction.Fee = transExtension.TotalInput - transExtension.TotalOutput; } return(transaction); }
public static TransOM ConvertToOM(this TransactionMsg transaction) { TransOM result = new TransOM(); result.Hash = transaction.Hash; result.Size = transaction.Size; result.Timestamp = transaction.Timestamp; var firstUtxo = UtxoSetDac.Default.Get(transaction.Hash, 0); result.OutputAffirm = GlobalParameters.LocalHeight - firstUtxo.BlockHeight; result.OutputAmount = transaction.Outputs.Sum(x => x.Amount); result.InputList = new List <InputOM>(); if (transaction.InputCount == 1 && transaction.Inputs[0].OutputTransactionHash.Equals(DbDomains.EmptyHash)) { result.InputList.Add(new InputOM { AccountId = "Coinbase", Amount = 0, OutputTransactionHash = DbDomains.EmptyHash, UnlockScript = transaction.Inputs[0].UnlockScript }); } else { var spentHashIndexs = transaction.Inputs.Select(x => $"{x.OutputTransactionHash}_{x.OutputIndex}"); var utxos = UtxoSetDac.Default.Get(spentHashIndexs); transaction.Inputs.ForEach(x => { var utxo = utxos.FirstOrDefault(p => p.Index == x.OutputIndex && p.TransactionHash == x.OutputTransactionHash); if (utxo != null) { InputOM input = new InputOM(); input.AccountId = utxo.Account; input.Amount = utxo.Amount; input.OutputTransactionHash = utxo.TransactionHash; input.UnlockScript = utxo.LockScript; result.InputList.Add(input); } }); } result.OutputList = new List <OutputOM>(); var newUtxos = transaction.GetUtxoSets(); newUtxos.ForEach(x => { OutputOM output = new OutputOM(); output.Amount = x.Amount; output.LockScript = x.LockScript; output.ReceiverId = x.Account; output.Spent = UtxoSetDac.Default.Get(x.TransactionHash, x.Index).IsSpent; result.OutputList.Add(output); }); return(result); }
public IRpcMethodResult GetTxOut(string txid, int vount, bool unconfirmed = false) { try { GetTxOutOM result = null; var txComponent = new TransactionComponent(); var blockComponent = new BlockComponent(); string blockHash = null; TransactionMsg tx = txComponent.GetTransactionMsgFromDB(txid, out blockHash); if (tx == null && unconfirmed) { tx = txComponent.GetTransactionMsgFromPool(txid); } if (tx != null && tx.OutputCount > vount) { var output = tx.Outputs[vount]; long confirmations = 0; if (!string.IsNullOrWhiteSpace(blockHash)) { var block = blockComponent.GetBlockMsgByHash(blockHash); if (block != null) { var latestHeight = blockComponent.GetLatestHeight(); if (latestHeight > block.Header.Height) { confirmations = latestHeight - block.Header.Height; } } } result = new GetTxOutOM(); result.bestblock = blockHash; result.confirmations = confirmations; result.value = output.Amount; result.scriptPubKey = output.LockScript; result.version = tx.Version; result.coinbase = (tx.InputCount == 0 && tx.Inputs[0].OutputTransactionHash == Base16.Encode(HashHelper.EmptyHash())); } return(Ok(result)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
/// <summary> /// 估算交易费率 /// </summary> /// <returns></returns> public long EstimateSmartFee() { //对象初始化 var txDac = new TransactionDac(); var transactionMsgs = new List <TransactionMsg>(); var txPool = TransactionPool.Instance; long totalSize = 0; long totalFee = 0; //设置最大上限 long maxSize = BlockSetting.MAX_BLOCK_SIZE - (1 * 1024); //交易池中的项目按照费率从高到低排列 List <TransactionPoolItem> poolItemList = txPool.MainPool.OrderByDescending(t => t.FeeRate).ToList(); var index = 0; while (totalSize < maxSize && index < poolItemList.Count) { //获取totalFee和totalSize TransactionMsg tx = poolItemList[index].Transaction; //判断交易Hash是否在交易Msg中 if (tx != null && transactionMsgs.Where(t => t.Hash == tx.Hash).Count() == 0) { totalFee += Convert.ToInt64(poolItemList[index].FeeRate * tx.Serialize().LongLength / 1024.0); if (txDac.SelectByHash(tx.Hash) == null) { transactionMsgs.Add(tx); totalSize += tx.Size; } else { txPool.RemoveTransaction(tx.Hash); } } /* * else * { * break; * } */ index++; } //获取费率 if (poolItemList.Count == 0) { return(1024); } long feeRate = Convert.ToInt64(Math.Ceiling((totalFee / (totalSize / 1024.0)) / poolItemList.Count)); if (feeRate < 1024) { feeRate = 1024; } return(feeRate); }
public void AddNewTransaction(long feeRate, TransactionMsg transaction) { var item = new TransactionPoolItem(feeRate, transaction); if (TransactionPoolDac.Default.Insert(item)) { Storage.Instance.PutData(containerName, transaction.Hash, item); var payments = transaction.GetPayments(); PaymentDac.Default.InsertMem(payments); } }
public void AddToBlackFile(TransactionMsg txMsg) { if (txMsg == null) { return; } lock (lockTxFileObj) { Storage.Instance.PutData(containerName, txMsg.Hash, txMsg); } }
public void AddNewTransaction(long feeRate, TransactionMsg transaction) { if (this.MainPool.Where(item => item.Transaction.Hash == transaction.Hash).Count() == 0) { var item = new TransactionPoolItem(feeRate, transaction); item.Isolate = false; this.MainPool.Add(item); Storage.Instance.PutData(this.containerName, transaction.Hash, item); //Storage.Instance.Put(this.containerName, transaction.Hash, JsonConvert.SerializeObject(item, Formatting.Indented, new JsonSerializerSettings() { // ReferenceLoopHandling = ReferenceLoopHandling.Ignore //})); } }
public TransactionMsg CreateNewTransactionMsg(List <UtxoMsg> utxos, Dictionary <string, long> receiverIdAndValues) { var outputDac = new OutputDac(); var accountDac = new AccountDac(); var transaction = new TransactionMsg(); transaction.Timestamp = Time.EpochTime; transaction.Locktime = 0; foreach (var utxo in utxos) { var account = accountDac.SelectById(utxo.AccountId); if (account == null || account.WatchedOnly) { //TODO: throw exception; return(null); } var privateKey = account.PrivateKey; var inputMsg = new InputMsg(); inputMsg.OutputTransactionHash = utxo.TransactionHash; inputMsg.OutputIndex = utxo.OutputIndex; inputMsg.UnlockScript = Script.BuildUnlockScript(utxo.TransactionHash, utxo.OutputIndex, Base16.Decode(privateKey), Base16.Decode(account.PublicKey)); inputMsg.Size = inputMsg.UnlockScript.Length; transaction.Inputs.Add(inputMsg); outputDac.UpdateSpentStatus(utxo.TransactionHash, utxo.OutputIndex); } int index = 0; foreach (var key in receiverIdAndValues.Keys) { var value = receiverIdAndValues[key]; var outputMsg = new OutputMsg(); outputMsg.Index = index; outputMsg.Amount = value; outputMsg.LockScript = Script.BuildLockScipt(key); outputMsg.Size = outputMsg.LockScript.Length; transaction.Outputs.Add(outputMsg); index++; } transaction.Hash = transaction.GetHash(); return(transaction); }
public void CreateNewTransaction(TransactionMsg transaction, long feeRate) { var spents = transaction.Inputs.Select(x => $"{x.OutputTransactionHash}_{x.OutputIndex}"); var spentUtxos = UtxoSetDac.Default.Get(spents); if (spents.Count() == spentUtxos.Count() && !spentUtxos.Any(x => !x.IsConfirmed(GlobalParameters.LocalHeight))) { TransactionPool.Instance.AddNewTransaction(feeRate, transaction); } else { TransactionPool.Instance.AddTxNoOutput(transaction); } }
public TransactionMsg GetTransactionByHash(string transactionHash) { TransactionMsg msg = null; foreach (var root in this.RootList) { msg = this.getTransactionByHash(root, transactionHash); if (msg != null) { return(msg); } } return(null); }
public void AddTransactionToPool(TransactionMsg transaction) { var isBlacked = BlacklistTxs.Current.IsBlacked(transaction.Hash); if (isBlacked) { return; } if (TransactionPoolDac.Default.IsExist(transaction.Hash)) { return; } if (TransactionDac.Default.HasTransaction(transaction.Hash)) { return; } long feeRate = 0; long totalInput = 0; long totalOutput = 0; long fee = 0; try { var result = VerifyTransaction(transaction, out fee, out totalOutput, out totalInput); if (!result) { TransactionPool.Instance.AddTxNoOutput(transaction); return; } else { CreateNewTransaction(transaction, feeRate); } } catch (CommonException ex) { LogHelper.Error(transaction.Hash + ":" + ex.ToString()); //交易出错时,需要添加到黑名单所在的文件夹 BlacklistTxs.Current.Add(transaction.Hash); BlacklistTxs.Current.AddToBlackFile(transaction); throw ex; } }
public GetTxOutOM GetTxOut(string txid, int vount, bool unconfirmed = false) { GetTxOutOM result = null; TransactionMsg tx = null; tx = TransactionDac.Default.GetTransaction(txid); if (tx == null && unconfirmed) { tx = TransactionPoolDac.Default.Get(txid); } if (tx == null) { return(result); } if (!unconfirmed) { var utxo = UtxoSetDac.Default.Get(txid, vount); if (utxo == null) { return(result); } result = new GetTxOutOM(); result.bestblock = utxo.BlockHash; result.coinbase = utxo.IsCoinbase; result.confirmations = GlobalParameters.LocalHeight - utxo.BlockHeight; result.scriptPubKey = utxo.LockScript; result.value = utxo.Amount; } else { var output = tx.Outputs[vount]; result.bestblock = null; result.coinbase = false; result.confirmations = 0; result.scriptPubKey = output.LockScript; result.value = output.Amount; } result.version = Versions.EngineVersion; return(result); }
public static bool HasAddress(this TransactionMsg transaction, string account) { var newUtxos = transaction.GetUtxoSets(); if (newUtxos.Any(x => x.Account.Equals(account))) { return(true); } var spentHashIndexs = transaction.Inputs.Select(x => $"{x.OutputTransactionHash}_{x.OutputIndex}"); foreach (var input in transaction.Inputs) { var utxo = UtxoSetDac.Default.Get(input.OutputTransactionHash, input.OutputIndex); if (utxo != null && utxo.Account.Equals(account)) { return(true); } } return(false); }
public static Output ConvertToEntiry(this OutputMsg outputMsg, TransactionMsg transaction, BlockMsg blockMsg) { Output output = new Output(); output.Amount = outputMsg.Amount; output.BlockHash = blockMsg.Header.Hash; output.Index = outputMsg.Index; output.LockScript = outputMsg.LockScript; output.Size = outputMsg.Size; output.Index = transaction.Outputs.IndexOf(outputMsg); output.TransactionHash = transaction.Hash; output.Spent = false; output.IsDiscarded = false; var receiverId = AccountIdHelper.CreateAccountAddressByPublicKeyHash( Base16.Decode( Script.GetPublicKeyHashFromLockScript(outputMsg.LockScript) )); output.ReceiverId = receiverId; return(output); }
public TransactionMsg ConvertTxEntityToMsg(Transaction tx) { var inputDac = new InputDac(); var outputDac = new OutputDac(); var txMsg = new TransactionMsg(); txMsg.Version = tx.Version; txMsg.Hash = tx.Hash; txMsg.Timestamp = tx.Timestamp; txMsg.Locktime = tx.LockTime; var inputs = inputDac.SelectByTransactionHash(tx.Hash); var outputs = outputDac.SelectByTransactionHash(tx.Hash); foreach (var input in inputs) { txMsg.Inputs.Add(new InputMsg { OutputTransactionHash = input.OutputTransactionHash, OutputIndex = input.OutputIndex, Size = input.Size, UnlockScript = input.UnlockScript }); } foreach (var output in outputs) { txMsg.Outputs.Add(new OutputMsg { Index = output.Index, Amount = output.Amount, Size = output.Size, LockScript = output.LockScript }); } return(txMsg); }
public static List <UtxoSet> GetUtxoSets(this TransactionMsg transaction) { List <UtxoSet> sets = new List <UtxoSet>(); foreach (var output in transaction.Outputs) { sets.Add(new UtxoSet { BlockHeight = 0, IsCoinbase = false, IsSpent = false, Locktime = transaction.Locktime, TransactionHash = transaction.Hash, Index = output.Index, Amount = output.Amount, BlockHash = null, BlockTime = 0, TransactionTime = transaction.Timestamp, LockScript = output.LockScript, Account = GetAccountByLockScript == null ? null : GetAccountByLockScript(output.LockScript) }); } return(sets); }
public IRpcMethodResult EstimateTxFeeForSendToAddress(string toAddress, long amount, string comment, string commentTo, bool deductFeeFromAmount) { try { EstimateTxFeeOM result = new EstimateTxFeeOM(); var utxoComponent = new UtxoComponent(); var txComponent = new TransactionComponent(); var settingComponent = new SettingComponent(); var addressBookComponent = new AddressBookComponent(); var accountComponent = new AccountComponent(); if (!AccountIdHelper.AddressVerify(toAddress)) { throw new CommonException(ErrorCode.Service.Transaction.TO_ADDRESS_INVALID); } var setting = settingComponent.GetSetting(); var utxos = utxoComponent.GetAllConfirmedOutputs(); var tx = new TransactionMsg(); var totalSize = tx.Serialize().Length; var output = new OutputMsg(); output.Amount = amount; output.Index = 0; output.LockScript = Script.BuildLockScipt(toAddress); output.Size = output.LockScript.Length; tx.Outputs.Add(output); totalSize += output.Serialize().Length; var blockComponent = new BlockComponent(); var lastBlockHeight = blockComponent.GetLatestHeight(); var totalInput = 0L; var index = 0; double totalAmount = amount; double totalFee = setting.FeePerKB * ((double)totalSize / 1024.0); while (index < utxos.Count) { var account = accountComponent.GetAccountById(utxos[index].AccountId); if (account != null && !string.IsNullOrWhiteSpace(account.PrivateKey)) { var utxoTX = txComponent.GetTransactionMsgByHash(utxos[index].TransactionHash); Block utxoBlock = blockComponent.GetBlockEntiytByHash(utxos[index].BlockHash); if (utxoTX == null || utxoBlock == null) { index++; continue; } if (!utxoBlock.IsVerified) { index++; continue; } if (Time.EpochTime < utxoTX.Locktime) { index++; continue; } if (utxoTX.InputCount == 1 && utxoTX.Inputs[0].OutputTransactionHash == Base16.Encode(HashHelper.EmptyHash())) { var blockHeight = utxoBlock.Height; if (lastBlockHeight - blockHeight < 100L) { index++; continue; } } var input = new InputMsg(); input.OutputTransactionHash = utxos[index].TransactionHash; input.OutputIndex = utxos[index].OutputIndex; input.UnlockScript = Script.BuildUnlockScript(input.OutputTransactionHash, input.OutputIndex, Base16.Decode(decryptPrivateKey(account.PrivateKey)), Base16.Decode(account.PublicKey)); input.Size = input.UnlockScript.Length; tx.Inputs.Add(input); var size = input.Serialize().Length; totalSize += size; totalFee += setting.FeePerKB * ((double)size / 1024.0); totalInput += utxos[index].Amount; } else { index++; continue; } if (!deductFeeFromAmount) { totalAmount = amount + totalFee; } if (totalInput >= (long)Math.Ceiling(totalAmount)) { var size = output.Serialize().Length; if ((totalInput - (long)Math.Ceiling(totalAmount)) > (setting.FeePerKB * (double)size / 1024.0)) { totalSize += size; totalFee += setting.FeePerKB * ((double)size / 1024.0); } break; } index++; } if (totalInput < totalAmount) { throw new CommonException(ErrorCode.Service.Transaction.BALANCE_NOT_ENOUGH); } if (deductFeeFromAmount) { output.Amount -= (long)Math.Ceiling(totalFee); if (output.Amount <= 0) { throw new CommonException(ErrorCode.Service.Transaction.SEND_AMOUNT_LESS_THAN_FEE); } } result.totalFee = Convert.ToInt64(totalFee); result.totalSize = Convert.ToInt32(totalSize); return(Ok(result)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public IRpcMethodResult SendMany(string fromAccount, SendManyOutputIM[] receivers, string[] feeDeductAddresses) { try { string result = null; var utxoComponent = new UtxoComponent(); var txComponent = new TransactionComponent(); var settingComponent = new SettingComponent(); var addressBookComponent = new AddressBookComponent(); var accountComponent = new AccountComponent(); var transactionCommentComponent = new TransactionCommentComponent(); var blockComponent = new BlockComponent(); var lastBlockHeight = blockComponent.GetLatestHeight(); var setting = settingComponent.GetSetting(); var utxos = utxoComponent.GetAllConfirmedOutputs(); var tx = new TransactionMsg(); double totalOutput = 0; var totalSize = tx.Serialize().Length; if (receivers == null || receivers.Length == 0) { throw new CommonException(ErrorCode.Service.Transaction.TO_ADDRESS_INVALID); } foreach (var receiver in receivers) { if (!AccountIdHelper.AddressVerify(receiver.address)) { throw new CommonException(ErrorCode.Service.Transaction.TO_ADDRESS_INVALID); } var output = new OutputMsg(); output.Amount = receiver.amount; output.Index = tx.Outputs.Count; output.LockScript = Script.BuildLockScipt(receiver.address); output.Size = output.LockScript.Length; tx.Outputs.Add(output); totalSize += output.Serialize().Length; totalOutput += receiver.amount; } foreach (var address in feeDeductAddresses) { if (receivers.Where(r => r.address == address).Count() == 0) { throw new CommonException(ErrorCode.Service.Transaction.FEE_DEDUCT_ADDRESS_INVALID); } } var totalInput = 0L; var index = 0; double totalFee = setting.FeePerKB * ((double)totalSize / 1024.0); double totalAmount = totalOutput; while (index < utxos.Count) { var account = accountComponent.GetAccountById(utxos[index].AccountId); if (account != null && !string.IsNullOrWhiteSpace(account.PrivateKey)) { var utxoTX = txComponent.GetTransactionMsgByHash(utxos[index].TransactionHash); Block utxoBlock = blockComponent.GetBlockEntiytByHash(utxos[index].BlockHash); if (utxoTX == null || utxoBlock == null) { index++; continue; } if (!utxoBlock.IsVerified) { index++; continue; } if (Time.EpochTime < utxoTX.Locktime) { index++; continue; } if (utxoTX.InputCount == 1 && utxoTX.Inputs[0].OutputTransactionHash == Base16.Encode(HashHelper.EmptyHash())) { var blockHeight = utxoBlock.Height; if (lastBlockHeight - blockHeight < 100L) { index++; continue; } } var input = new InputMsg(); input.OutputTransactionHash = utxos[index].TransactionHash; input.OutputIndex = utxos[index].OutputIndex; input.UnlockScript = Script.BuildUnlockScript(input.OutputTransactionHash, input.OutputIndex, Base16.Decode(decryptPrivateKey(account.PrivateKey)), Base16.Decode(account.PublicKey)); input.Size = input.UnlockScript.Length; tx.Inputs.Add(input); var size = input.Serialize().Length; totalSize += size; totalFee += setting.FeePerKB * ((double)size / 1024.0); totalInput += utxos[index].Amount; } else { index++; continue; } if (feeDeductAddresses == null || feeDeductAddresses.Length == 0) { totalAmount = totalOutput + totalFee; } if (totalInput >= (long)Math.Ceiling(totalAmount)) { var size = tx.Outputs[0].Serialize().Length; if ((totalInput - (long)Math.Ceiling(totalAmount)) > (setting.FeePerKB * (double)size / 1024.0)) { totalSize += size; totalFee += setting.FeePerKB * ((double)size / 1024.0); if (feeDeductAddresses == null || feeDeductAddresses.Length == 0) { totalAmount = totalOutput + totalFee; } var newAccount = accountComponent.GenerateNewAccount(); if (setting.Encrypt) { if (!string.IsNullOrWhiteSpace(_cache.Get <string>("WalletPassphrase"))) { newAccount.PrivateKey = AES128.Encrypt(newAccount.PrivateKey, _cache.Get <string>("WalletPassphrase")); accountComponent.UpdatePrivateKeyAr(newAccount); } else { throw new CommonException(ErrorCode.Service.Wallet.WALLET_HAS_BEEN_LOCKED); } } var newOutput = new OutputMsg(); newOutput.Amount = totalInput - (long)Math.Ceiling(totalAmount); newOutput.Index = tx.Outputs.Count; newOutput.LockScript = Script.BuildLockScipt(newAccount.Id); newOutput.Size = newOutput.LockScript.Length; tx.Outputs.Add(newOutput); } break; } index++; } if (totalInput < totalAmount) { throw new CommonException(ErrorCode.Service.Transaction.BALANCE_NOT_ENOUGH); } if (feeDeductAddresses != null && feeDeductAddresses.Length > 0) { var averageFee = totalFee / feeDeductAddresses.Length; for (int i = 0; i < receivers.Length; i++) { if (feeDeductAddresses.Contains(receivers[i].address)) { tx.Outputs[i].Amount -= (long)Math.Ceiling(averageFee); if (tx.Outputs[i].Amount <= 0) { throw new CommonException(ErrorCode.Service.Transaction.SEND_AMOUNT_LESS_THAN_FEE); } } } } tx.Timestamp = Time.EpochTime; tx.Hash = tx.GetHash(); txComponent.AddTransactionToPool(tx); Startup.P2PBroadcastTransactionAction(tx.Hash); result = tx.Hash; for (int i = 0; i < receivers.Length; i++) { var receiver = receivers[i]; if (!string.IsNullOrWhiteSpace(receiver.tag)) { addressBookComponent.SetTag(receiver.address, receiver.tag); } if (!string.IsNullOrWhiteSpace(receiver.comment)) { transactionCommentComponent.Add(tx.Hash, i, receiver.comment); } } return(Ok(result)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public TransactionPoolItem(long feeRate, TransactionMsg transaction) { this.FeeRate = feeRate; this.Transaction = transaction; }
/// <summary> /// 创建新的区块 /// </summary> /// <param name="minerName"></param> /// <param name="generatorId"></param> /// <param name="accountId"></param> /// <returns></returns> public BlockMsg CreateNewBlock(string minerName, string generatorId, string remark = null, string accountId = null) { var accountDac = new AccountDac(); var blockDac = new BlockDac(); var outputDac = new OutputDac(); var txDac = new TransactionDac(); var txPool = TransactionPool.Instance; var transactionMsgs = new List <TransactionMsg>(); long lastBlockHeight = -1; string lastBlockHash = Base16.Encode(HashHelper.EmptyHash()); long lastBlockBits = -1; string lastBlockGenerator = null; //获取最后一个区块 var blockEntity = blockDac.SelectLast(); if (blockEntity != null) { lastBlockHeight = blockEntity.Height; lastBlockHash = blockEntity.Hash; lastBlockBits = blockEntity.Bits; lastBlockGenerator = blockEntity.GeneratorId; } long totalSize = 0; long maxSize = BlockSetting.MAX_BLOCK_SIZE - (1 * 1024); var poolItemList = txPool.MainPool.OrderByDescending(t => t.FeeRate).ToList(); var index = 0; while (totalSize < maxSize && index < poolItemList.Count) { var tx = poolItemList[index].Transaction; if (tx != null && transactionMsgs.Where(t => t.Hash == tx.Hash).Count() == 0) { if (txDac.SelectByHash(tx.Hash) == null) { transactionMsgs.Add(tx); totalSize += tx.Size; } else { txPool.RemoveTransaction(tx.Hash); } } else { break; } index++; } var minerAccount = accountDac.SelectDefaultAccount(); if (accountId != null) { var account = accountDac.SelectById(accountId); if (account != null && !string.IsNullOrWhiteSpace(account.PrivateKey)) { minerAccount = account; } } var minerAccountId = minerAccount.Id; BlockMsg newBlockMsg = new BlockMsg(); BlockHeaderMsg headerMsg = new BlockHeaderMsg(); headerMsg.Hash = Base16.Encode(HashHelper.EmptyHash()); headerMsg.GeneratorId = generatorId; newBlockMsg.Header = headerMsg; headerMsg.Height = lastBlockHeight + 1; headerMsg.PreviousBlockHash = lastBlockHash; if (headerMsg.Height == 0) { minerAccountId = BlockSetting.GenesisBlockReceiver; remark = BlockSetting.GenesisBlockRemark; } long totalAmount = 0; long totalFee = 0; foreach (var tx in transactionMsgs) { long totalInputsAmount = 0L; long totalOutputAmount = 0L; foreach (var input in tx.Inputs) { var utxo = outputDac.SelectByHashAndIndex(input.OutputTransactionHash, input.OutputIndex); if (utxo != null) { totalInputsAmount += utxo.Amount; } } foreach (var output in tx.Outputs) { totalOutputAmount += output.Amount; } totalAmount += totalOutputAmount; totalFee += (totalInputsAmount - totalOutputAmount); } //var work = new POW(headerMsg.Height); BlockMsg prevBlockMsg = null; BlockMsg prevStepBlockMsg = null; if (blockEntity != null) { prevBlockMsg = this.convertEntityToBlockMsg(blockEntity); } if (headerMsg.Height >= POC.DIFFIUCLTY_ADJUST_STEP) { prevStepBlockMsg = this.GetBlockMsgByHeight(headerMsg.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1); } var newBlockReward = POC.GetNewBlockReward(headerMsg.Height); headerMsg.Bits = POC.CalculateBaseTarget(headerMsg.Height, prevBlockMsg, prevStepBlockMsg); headerMsg.TotalTransaction = transactionMsgs.Count + 1; var coinbaseTxMsg = new TransactionMsg(); coinbaseTxMsg.Timestamp = Time.EpochTime; coinbaseTxMsg.Locktime = 0; var coinbaseInputMsg = new InputMsg(); coinbaseTxMsg.Inputs.Add(coinbaseInputMsg); coinbaseInputMsg.OutputIndex = 0; coinbaseInputMsg.OutputTransactionHash = Base16.Encode(HashHelper.EmptyHash()); coinbaseInputMsg.UnlockScript = Script.BuildMinerScript(minerName, remark); coinbaseInputMsg.Size = coinbaseInputMsg.UnlockScript.Length; var coinbaseOutputMsg = new OutputMsg(); coinbaseTxMsg.Outputs.Add(coinbaseOutputMsg); coinbaseOutputMsg.Amount = newBlockReward + totalFee; coinbaseOutputMsg.LockScript = Script.BuildLockScipt(minerAccountId); coinbaseOutputMsg.Size = coinbaseOutputMsg.LockScript.Length; coinbaseOutputMsg.Index = 0; coinbaseTxMsg.Hash = coinbaseTxMsg.GetHash(); newBlockMsg.Transactions.Insert(0, coinbaseTxMsg); foreach (var tx in transactionMsgs) { newBlockMsg.Transactions.Add(tx); } headerMsg.PayloadHash = newBlockMsg.GetPayloadHash(); var dsa = ECDsa.ImportPrivateKey(Base16.Decode(minerAccount.PrivateKey)); var signResult = dsa.SingnData(Base16.Decode(headerMsg.PayloadHash)); headerMsg.BlockSignature = Base16.Encode(signResult); headerMsg.BlockSigSize = headerMsg.BlockSignature.Length; headerMsg.TotalTransaction = newBlockMsg.Transactions.Count; return(newBlockMsg); }
public Transaction ConvertTxMsgToEntity(TransactionMsg txMsg) { var outputDac = new OutputDac(); var entity = new Transaction(); entity.Hash = txMsg.Hash; entity.BlockHash = null; entity.Version = txMsg.Version; entity.Timestamp = txMsg.Timestamp; entity.LockTime = txMsg.Locktime; entity.Inputs = new List <Input>(); entity.Outputs = new List <Output>(); long totalInput = 0L; long totalOutput = 0L; foreach (var inputMsg in txMsg.Inputs) { var input = new Input(); input.TransactionHash = txMsg.Hash; input.OutputTransactionHash = inputMsg.OutputTransactionHash; input.OutputIndex = inputMsg.OutputIndex; input.Size = inputMsg.Size; input.UnlockScript = inputMsg.UnlockScript; var output = outputDac.SelectByHashAndIndex(inputMsg.OutputTransactionHash, inputMsg.OutputIndex); if (output != null) { input.Amount = output.Amount; input.AccountId = output.ReceiverId; } entity.Inputs.Add(input); totalInput += input.Amount; } foreach (var outputMsg in txMsg.Outputs) { var output = new Output(); output.Index = outputMsg.Index; output.TransactionHash = entity.Hash; var address = AccountIdHelper.CreateAccountAddressByPublicKeyHash( Base16.Decode( Script.GetPublicKeyHashFromLockScript(outputMsg.LockScript) )); output.ReceiverId = address; output.Amount = outputMsg.Amount; output.Size = outputMsg.Size; output.LockScript = outputMsg.LockScript; entity.Outputs.Add(output); totalOutput += output.Amount; } entity.TotalInput = totalInput; entity.TotalOutput = totalOutput; entity.Fee = totalInput - totalOutput; entity.Size = txMsg.Size; if (txMsg.Inputs.Count == 1 && txMsg.Outputs.Count == 1 && txMsg.Inputs[0].OutputTransactionHash == Base16.Encode(HashHelper.EmptyHash())) { entity.Fee = 0; } return(entity); }
public static Transaction ConvertTxMsgToEntity(this TransactionMsg txMsg, bool isSelf = false) { var entity = new Transaction(); entity.Hash = txMsg.Hash; entity.BlockHash = null; entity.Version = txMsg.Version; entity.Timestamp = txMsg.Timestamp; entity.LockTime = txMsg.Locktime; entity.Inputs = new List <Input>(); entity.Outputs = new List <Output>(); long totalInput = 0L; long totalOutput = 0L; foreach (var inputMsg in txMsg.Inputs) { var input = new Input(); input.TransactionHash = txMsg.Hash; input.OutputTransactionHash = inputMsg.OutputTransactionHash; input.OutputIndex = inputMsg.OutputIndex; input.Size = inputMsg.Size; input.UnlockScript = inputMsg.UnlockScript; var utxo = UtxoSetDac.Default.Get(inputMsg.OutputTransactionHash, inputMsg.OutputIndex); if (utxo != null) { input.Amount = utxo.Amount; input.AccountId = utxo.Account; input.BlockHash = utxo.BlockHash; } else { input.Amount = 0; input.AccountId = ""; } entity.Inputs.Add(input); totalInput += input.Amount; } foreach (var outputMsg in txMsg.Outputs) { var output = new Output(); output.Index = outputMsg.Index; output.TransactionHash = entity.Hash; var address = AccountIdHelper.CreateAccountAddressByPublicKeyHash( Base16.Decode( Script.GetPublicKeyHashFromLockScript(outputMsg.LockScript) )); output.ReceiverId = address; output.Amount = outputMsg.Amount; output.Size = outputMsg.Size; output.LockScript = outputMsg.LockScript; entity.Outputs.Add(output); totalOutput += output.Amount; } entity.TotalInput = totalInput; entity.TotalOutput = totalOutput; entity.Fee = totalInput - totalOutput; entity.Size = txMsg.Size; var coinbaseHashIndex = $"{txMsg.Hash}_{0}"; var utxoset = UtxoSetDac.Default.Get(coinbaseHashIndex); entity.BlockHash = utxoset?.BlockHash; if (txMsg.Inputs.Count == 1 && txMsg.Outputs.Count == 1 && txMsg.Inputs[0].OutputTransactionHash == Base16.Encode(HashHelper.EmptyHash())) { entity.Fee = 0; } return(entity); }
public bool VerifyTransaction(TransactionMsg transaction, out long txFee, out long totalOutput, out long totalInput) { var blockComponent = new BlockComponent(); txFee = 0; //compatible with old node if (transaction.Locktime > 0 && transaction.ExpiredTime == transaction.Locktime) { transaction.ExpiredTime = 0; } //step 0 if (transaction.Hash != transaction.GetHash()) { LogHelper.Error("Tx Hash Error:" + transaction.Hash); LogHelper.Error("Timestamp:" + transaction.Timestamp); LogHelper.Error("Locktime:" + transaction.Locktime); LogHelper.Error("ExpiredTime:" + transaction.ExpiredTime); LogHelper.Error("InputCount:" + transaction.InputCount); LogHelper.Error("OutputCount:" + transaction.OutputCount); throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_HASH_ERROR); } //step 1 if (transaction.InputCount == 0 || transaction.OutputCount == 0) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.INPUT_AND_OUTPUT_CANNOT_BE_EMPTY); } //step 2 if (transaction.Hash == Base16.Encode(HashHelper.EmptyHash())) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.HASH_CANNOT_BE_EMPTY); } //step 3 if (transaction.Locktime < 0 || transaction.Locktime > (Time.EpochTime + BlockSetting.LOCK_TIME_MAX)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.LOCK_TIME_EXCEEDED_THE_LIMIT); } //step 4 if (transaction.Serialize().Length < BlockSetting.TRANSACTION_MIN_SIZE) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_SIZE_BELOW_THE_LIMIT); } //step 5 if (this.existsInDB(transaction.Hash)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_HAS_BEEN_EXISTED); } totalOutput = 0; totalInput = 0; foreach (var output in transaction.Outputs) { if (output.Amount <= 0 || output.Amount > BlockSetting.OUTPUT_AMOUNT_MAX) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_EXCEEDED_THE_LIMIT); } if (!Script.VerifyLockScriptFormat(output.LockScript)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.SCRIPT_FORMAT_ERROR); } totalOutput += output.Amount; } var count = transaction.Inputs.Distinct().Count(); if (count != transaction.Inputs.Count) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_DUPLICATED_IN_ONE_TRANSACTION); } foreach (var input in transaction.Inputs) { if (!Script.VerifyUnlockScriptFormat(input.UnlockScript)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.SCRIPT_FORMAT_ERROR); } var utxo = UtxoSetDac.Default.Get(input.OutputTransactionHash, input.OutputIndex); if (utxo != null) { if (!utxo.IsConfirmed(GlobalParameters.LocalHeight)) { if (utxo.IsCoinbase) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_NEED_100_CONFIRMS); } else { return(false); } } if (Time.EpochTime < utxo.Locktime) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_IS_LOCKED); } if (utxo.IsSpent()) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_HAS_BEEN_SPENT); } if (!Script.VerifyLockScriptByUnlockScript(input.OutputTransactionHash, input.OutputIndex, utxo.LockScript, input.UnlockScript)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_UNLOCK_FAIL); } totalInput += utxo.Amount; } else { //not found output, wait for other transactions or blocks; txFee = 0; return(false); } } if (totalOutput >= totalInput) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_LARGE_THAN_INPUT); } if ((totalInput - totalOutput) < BlockSetting.TRANSACTION_MIN_FEE) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_FEE_IS_TOO_FEW); } if (totalInput > BlockSetting.INPUT_AMOUNT_MAX) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.INPUT_EXCEEDED_THE_LIMIT); } if (totalOutput > BlockSetting.OUTPUT_AMOUNT_MAX) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_EXCEEDED_THE_LIMIT); } txFee = totalInput - totalOutput; return(true); }
public bool VerifyTransaction(TransactionMsg transaction, out long txFee, out long totalOutput, out long totalInput) { totalOutput = 0; totalInput = 0; txFee = 0; totalOutput = transaction.Outputs.Sum(x => x.Amount); foreach (var input in transaction.Inputs) { if (!Script.VerifyUnlockScriptFormat(input.UnlockScript)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.SCRIPT_FORMAT_ERROR); } var utxo = UtxoSetDac.Default.Get(input.OutputTransactionHash, input.OutputIndex); if (utxo != null) { if (!utxo.IsConfirmed(GlobalParameters.LocalHeight)) { if (utxo.IsCoinbase) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_NEED_100_CONFIRMS); } else { return(false); } } if (Time.EpochTime < utxo.Locktime) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_IS_LOCKED); } if (utxo.IsSpent()) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_HAS_BEEN_SPENT); } if (Time.EpochTime < utxo.DepositTime) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.DEPOSIT_TIME_NOT_EXPIRED); } if (!Script.VerifyLockScriptByUnlockScript(input.OutputTransactionHash, input.OutputIndex, utxo.LockScript, input.UnlockScript)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_UNLOCK_FAIL); } totalInput += utxo.Amount; } else { txFee = 0; return(false); } } if (totalOutput >= totalInput) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_LARGE_THAN_INPUT); } if ((totalInput - totalOutput) < BlockSetting.TRANSACTION_MIN_FEE) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_FEE_IS_TOO_FEW); } if (totalInput > BlockSetting.INPUT_AMOUNT_MAX) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.INPUT_EXCEEDED_THE_LIMIT); } if (totalOutput > BlockSetting.OUTPUT_AMOUNT_MAX) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_EXCEEDED_THE_LIMIT); } txFee = totalInput - totalOutput; return(true); }