/* * private void Fill() * { * IEnumerable<Transaction> memoryPoolTransactions = Blockchain.Singleton.MemPool.GetSortedVerifiedTransactions(); * foreach (IPolicyPlugin plugin in Plugin.Policies) * memoryPoolTransactions = plugin.FilterForBlock(memoryPoolTransactions); * List<Transaction> transactions = memoryPoolTransactions.ToList(); * Fixed8 amountNetFee = Block.CalculateNetFee(transactions); * TransactionOutput[] outputs = amountNetFee == Fixed8.Zero ? new TransactionOutput[0] : new[] { new TransactionOutput * { * AssetId = Blockchain.UtilityToken.Hash, * Value = amountNetFee, * ScriptHash = wallet.GetChangeAddress() * } }; * while (true) * { * ulong nonce = GetNonce(); * MinerTransaction tx = new MinerTransaction * { * Nonce = (uint)(nonce % (uint.MaxValue + 1ul)), * Attributes = new TransactionAttribute[0], * Inputs = new CoinReference[0], * Outputs = outputs, * Witnesses = new Witness[0] * }; * if (!Snapshot.ContainsTransaction(tx.Hash)) * { * Nonce = nonce; * transactions.Insert(0, tx); * break; * } * } * TransactionHashes = transactions.Select(p => p.Hash).ToArray(); * Transactions = transactions.ToDictionary(p => p.Hash); * NextConsensus = Blockchain.GetConsensusAddress(Snapshot.GetValidators(transactions).ToArray()); * Timestamp = Math.Max(TimeProvider.Current.UtcNow.ToTimestamp(), this.PrevHeader().Timestamp + 1); * } */ public void Fill() { IEnumerable <Transaction> mem_pool = Blockchain.Singleton.MemPool.GetSortedVerifiedTransactions(); foreach (IPolicyPlugin plugin in Plugin.Policies) { mem_pool = plugin.FilterForBlock(mem_pool); } List <Transaction> transactions = mem_pool.ToList(); Fixed8 amount_netfee = Block.CalculateNetFee(transactions); //By BHP Fixed8 amount_txfee = BhpTxFee.CalcuTxFee(transactions); while (true) { ulong nonce = GetNonce(); //By BHP MinerTransaction tx = new MiningTransaction().MakeMinerTransaction(wallet, BlockIndex, nonce, amount_txfee, amount_netfee); if (!Snapshot.ContainsTransaction(tx.Hash)) { Nonce = nonce; transactions.Insert(0, tx); break; } } TransactionHashes = transactions.Select(p => p.Hash).ToArray(); Transactions = transactions.ToDictionary(p => p.Hash); NextConsensus = Blockchain.GetConsensusAddress(Snapshot.GetValidators(transactions).ToArray()); Timestamp = Math.Max(TimeProvider.Current.UtcNow.ToTimestamp(), this.PrevHeader().Timestamp + 1); }
//private string RequestRpc(string method, string kvs) //{ // string jsonRes = ""; // using (HttpClient client = new HttpClient()) // { // string uri = $"{ExtensionSettings.Default.DataRPCServer.Host}/{method}?{kvs}"; // client.BaseAddress = new Uri(uri); // client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // var response = client.GetAsync(uri).Result; // Task<Stream> task = response.Content.ReadAsStreamAsync(); // Stream backStream = task.Result; // StreamReader reader = new StreamReader(backStream); // jsonRes = reader.ReadToEnd(); // reader.Close(); // backStream.Close(); // } // return jsonRes; //} private Transaction MakeToColdTransaction(Coin[] coins, UInt160 outAddress, UInt256 assetId, UInt160 fee_address = null) { int MaxInputCount = 50; Transaction tx = new ContractTransaction(); tx.Attributes = new TransactionAttribute[0]; tx.Witnesses = new Witness[0]; List <CoinReference> inputs = new List <CoinReference>(); List <TransactionOutput> outputs = new List <TransactionOutput>(); Fixed8 sum = Fixed8.Zero; if (coins.Length < 50) { MaxInputCount = coins.Length; } for (int j = 0; j < MaxInputCount; j++) { sum += coins[j].Output.Value; inputs.Add(new CoinReference { PrevHash = coins[j].Reference.PrevHash, PrevIndex = coins[j].Reference.PrevIndex }); } tx.Inputs = inputs.ToArray(); outputs.Add(new TransactionOutput { AssetId = assetId, ScriptHash = outAddress, Value = sum }); if (tx.SystemFee > Fixed8.Zero) { outputs.Add(new TransactionOutput { AssetId = Blockchain.UtilityToken.Hash, Value = tx.SystemFee }); } tx.Outputs = outputs.ToArray(); Fixed8 transfee = BhpTxFee.EstimateTxFee(tx, assetId); if (tx.Outputs[0].Value <= transfee) { return(null); } tx.Outputs[0].Value -= transfee; return(TransactionContract.EstimateFee(wallet, tx, null, fee_address)); }
public T MakeTransaction <T>(Wallet wallet, T tx, UInt160 from = null, UInt160 fee_address = null, UInt160 change_address = null, Fixed8 fee = default(Fixed8), Fixed8 transaction_fee = default(Fixed8)) where T : Transaction { if (tx.Outputs == null) { tx.Outputs = new TransactionOutput[0]; } if (tx.Attributes == null) { tx.Attributes = new TransactionAttribute[0]; } fee += tx.SystemFee; var pay_total = (typeof(T) == typeof(IssueTransaction) ? new TransactionOutput[0] : tx.Outputs).GroupBy(p => p.AssetId, (k, g) => new { AssetId = k, Value = g.Sum(p => p.Value) }).ToDictionary(p => p.AssetId); if (fee > Fixed8.Zero) { if (pay_total.ContainsKey(Blockchain.UtilityToken.Hash)) { pay_total[Blockchain.UtilityToken.Hash] = new { AssetId = Blockchain.UtilityToken.Hash, Value = pay_total[Blockchain.UtilityToken.Hash].Value + fee }; } else { pay_total.Add(Blockchain.UtilityToken.Hash, new { AssetId = Blockchain.UtilityToken.Hash, Value = fee }); } } /* * var pay_coins = pay_total.Select(p => new * { * AssetId = p.Key, * Unspents = from == null ? wallet.FindUnspentCoins(p.Key, p.Value.Value) : wallet.FindUnspentCoins(p.Key, p.Value.Value, from) * }).ToDictionary(p => p.AssetId); */ //By BHP //When transferring money, finding UTXO requires additional transaction fees bool hasBhpFeeAddress = false; if (pay_total.Any(p => p.Key.Equals(Blockchain.GoverningToken.Hash) && fee_address != null)) { hasBhpFeeAddress = true; } var pay_coins = pay_total.Select(p => new { AssetId = p.Key, Unspents = from == null ? wallet.FindUnspentCoins(p.Key, p.Value.Value + BhpTxFee.EstimateTxFee(tx, p.Key, hasBhpFeeAddress)) : wallet.FindUnspentCoins(p.Key, p.Value.Value + BhpTxFee.EstimateTxFee(tx, p.Key, hasBhpFeeAddress), from) }).ToDictionary(p => p.AssetId); if (pay_coins.Any(p => p.Value.Unspents == null)) { return(null); } var input_sum = pay_coins.Values.ToDictionary(p => p.AssetId, p => new { p.AssetId, Value = p.Unspents.Sum(q => q.Output.Value) }); if (change_address == null) { change_address = wallet.GetChangeAddress(); } List <TransactionOutput> outputs_new = new List <TransactionOutput>(tx.Outputs); List <int> changeNum = new List <int>(); //添加找零地址 By BHP foreach (UInt256 asset_id in input_sum.Keys) { Fixed8 txFee = BhpTxFee.EstimateTxFee(tx, asset_id, hasBhpFeeAddress); if (input_sum[asset_id].Value > (pay_total[asset_id].Value + txFee)) { outputs_new.Add(new TransactionOutput { AssetId = asset_id, Value = input_sum[asset_id].Value - pay_total[asset_id].Value - txFee, ScriptHash = change_address }); changeNum.Add(outputs_new.Count - 1); } } //By BHP for (int i = 0; i < tx.Attributes.Length; i++) { if (tx.Attributes[i].Usage == TransactionAttributeUsage.SmartContractScript) { using (ScriptBuilder sb = new ScriptBuilder()) { sb.EmitPush(changeNum.Count); if (changeNum.Count > 0) { for (int j = changeNum.Count - 1; j >= 0; j--) { sb.EmitPush(changeNum[j]); } } sb.EmitPush(tx.Attributes[i].Data); tx.Attributes[i].Data = sb.ToArray(); } } } tx.Inputs = pay_coins.Values.SelectMany(p => p.Unspents).Select(p => p.Reference).ToArray(); tx.Outputs = outputs_new.ToArray(); return(EstimateFee(wallet, tx, from, fee_address, hasBhpFeeAddress));//BHP }
/// <summary> /// caluate tx fee (token and share) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="wallet"></param> /// <param name="tx"></param> /// <param name="from"></param> /// <param name="fee_address"></param> /// <returns></returns> public static T EstimateFee <T>(Wallet wallet, T tx, UInt160 from, UInt160 fee_address, bool hasBhpFeeAddress = false) where T : Transaction { Fixed8 bhp_fee, coin_value; Coin[] feeCoins; if (hasBhpFeeAddress) { bhp_fee = BhpTxFee.EstimateTxFee(tx); feeCoins = wallet.FindUnspentCoins(Blockchain.GoverningToken.Hash, bhp_fee, fee_address); if (feeCoins == null) { return(null); } tx.Inputs = tx.Inputs.Concat(feeCoins.Select(p => { return(p.Reference); })).ToArray(); coin_value = feeCoins.Sum(p => p.Output.Value); if (coin_value > bhp_fee) { tx.Outputs = tx.Outputs.Concat(new[] { new TransactionOutput() { AssetId = Blockchain.GoverningToken.Hash, ScriptHash = fee_address, Value = coin_value - bhp_fee } }).ToArray(); } return(tx); } if (!ExtensionSettings.Default.WalletConfig.IsBhpFee) { return(tx); } if (!tx.Outputs.Any(p => p.AssetId == Blockchain.GoverningToken.Hash)) //without bhp { if (tx.Outputs.Any(p => p.AssetId != Blockchain.GoverningToken.Hash && p.AssetId != Blockchain.UtilityToken.Hash)) //except bhp and gas { bhp_fee = BhpTxFee.EstimateTxFee(tx); if (fee_address == null && from != null) { fee_address = from; } feeCoins = fee_address == null?wallet.FindUnspentCoins(Blockchain.GoverningToken.Hash, bhp_fee) : wallet.FindUnspentCoins(Blockchain.GoverningToken.Hash, bhp_fee, fee_address); if (feeCoins == null) { return(null); } tx.Inputs = tx.Inputs.Concat(feeCoins.Select(p => { return(p.Reference); })).ToArray(); coin_value = feeCoins.Sum(p => p.Output.Value); if (coin_value > bhp_fee) { tx.Outputs = tx.Outputs.Concat(new[] { new TransactionOutput() { AssetId = Blockchain.GoverningToken.Hash, ScriptHash = fee_address == null ? wallet.GetChangeAddress() : fee_address, Value = coin_value - bhp_fee } }).ToArray(); } } } return(tx); }
/* * public virtual bool Verify(Snapshot snapshot, IEnumerable<Transaction> mempool) * { * if (Size > MaxTransactionSize) return false; * for (int i = 1; i < Inputs.Length; i++) * for (int j = 0; j < i; j++) * if (Inputs[i].PrevHash == Inputs[j].PrevHash && Inputs[i].PrevIndex == Inputs[j].PrevIndex) * return false; * if (mempool.Where(p => p != this).SelectMany(p => p.Inputs).Intersect(Inputs).Count() > 0) * return false; * if (snapshot.IsDoubleSpend(this)) * return false; * foreach (var group in Outputs.GroupBy(p => p.AssetId)) * { * AssetState asset = snapshot.Assets.TryGet(group.Key); * if (asset == null) return false; * if (asset.Expiration <= snapshot.Height + 1 && asset.AssetType != AssetType.GoverningToken && asset.AssetType != AssetType.UtilityToken) * return false; * foreach (TransactionOutput output in group) * if (output.Value.GetData() % (long)Math.Pow(10, 8 - asset.Precision) != 0) * return false; * } * TransactionResult[] results = GetTransactionResults()?.ToArray(); * if (results == null) return false; * TransactionResult[] results_destroy = results.Where(p => p.Amount > Fixed8.Zero).ToArray(); * if (results_destroy.Length > 1) return false; * if (results_destroy.Length == 1 && results_destroy[0].AssetId != Blockchain.UtilityToken.Hash) * return false; * if (SystemFee > Fixed8.Zero && (results_destroy.Length == 0 || results_destroy[0].Amount < SystemFee)) * return false; * TransactionResult[] results_issue = results.Where(p => p.Amount < Fixed8.Zero).ToArray(); * switch (Type) * { * case TransactionType.MinerTransaction: * case TransactionType.ClaimTransaction: * if (results_issue.Any(p => p.AssetId != Blockchain.UtilityToken.Hash)) * return false; * break; * case TransactionType.IssueTransaction: * if (results_issue.Any(p => p.AssetId == Blockchain.UtilityToken.Hash)) * return false; * break; * default: * if (results_issue.Length > 0) * return false; * break; * } * if (Attributes.Count(p => p.Usage == TransactionAttributeUsage.ECDH02 || p.Usage == TransactionAttributeUsage.ECDH03) > 1) * return false; * if (!VerifyReceivingScripts()) return false; * return this.VerifyWitnesses(snapshot); * } */ public virtual bool Verify(Snapshot snapshot, IEnumerable <Transaction> mempool) { if (Size > MaxTransactionSize) { return(false); } for (int i = 1; i < Inputs.Length; i++) { for (int j = 0; j < i; j++) { if (Inputs[i].PrevHash == Inputs[j].PrevHash && Inputs[i].PrevIndex == Inputs[j].PrevIndex) { return(false); } } } if (mempool.Where(p => p != this).SelectMany(p => p.Inputs).Intersect(Inputs).Count() > 0) { return(false); } if (snapshot.IsDoubleSpend(this)) { return(false); } foreach (var group in Outputs.GroupBy(p => p.AssetId)) { AssetState asset = snapshot.Assets.TryGet(group.Key); if (asset == null) { return(false); } if (asset.Expiration <= snapshot.Height + 1 && asset.AssetType != AssetType.GoverningToken && asset.AssetType != AssetType.UtilityToken) { return(false); } foreach (TransactionOutput output in group) { if (output.Value.GetData() % (long)Math.Pow(10, 8 - asset.Precision) != 0) { return(false); } } } TransactionResult[] results = GetTransactionResults()?.ToArray(); if (results == null) { return(false); } TransactionResult[] results_destroy = results.Where(p => p.Amount > Fixed8.Zero).ToArray(); //By BHP if (BhpTxFee.Verify(this, results_destroy, SystemFee) == false) { return(false); } TransactionResult[] results_issue = results.Where(p => p.Amount < Fixed8.Zero).ToArray(); switch (Type) { //By BHP case TransactionType.MinerTransaction: if (VerifyMiningTransaction.Verify(Outputs, Attributes) == false) { return(false); } break; case TransactionType.ClaimTransaction: if (results_issue.Any(p => p.AssetId != Blockchain.UtilityToken.Hash)) { return(false); } break; case TransactionType.IssueTransaction: if (results_issue.Any(p => p.AssetId == Blockchain.UtilityToken.Hash)) { return(false); } break; default: if (results_issue.Length > 0) { return(false); } break; } if (Attributes.Count(p => p.Usage == TransactionAttributeUsage.ECDH02 || p.Usage == TransactionAttributeUsage.ECDH03) > 1) { return(false); } if (!VerifyReceivingScripts()) { return(false); } //By BHP if (VerifyTransactionContract.Verify(snapshot, this) == false) { return(false); } return(this.VerifyWitnesses(snapshot)); }