Ejemplo n.º 1
0
        /*
         * 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);
        }
Ejemplo n.º 2
0
        //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));
        }
Ejemplo n.º 3
0
        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
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 5
0
        /*
         * 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));
        }