예제 #1
0
            public TransactionBuildingContext CreateMemento()
            {
                var memento = new TransactionBuildingContext(Builder);

                memento.RestoreMemento(this);
                return(memento);
            }
예제 #2
0
        private IEnumerable <ICoin> BuildTransaction(
            TransactionBuildingContext ctx,
            BuilderGroup group,
            IEnumerable <Builder> builders,
            IEnumerable <ICoin> coins)
        {
            var originalCtx = ctx.CreateMemento();
            var target      = builders.Concat(ctx.AdditionalBuilders).Select(b => b(ctx)).Sum();

            if (ctx.CoverOnly != null)
            {
                target = ctx.CoverOnly + ctx.ChangeAmount;
            }
            var selection = CoinSelector.Select(coins, target);

            if (selection == null)
            {
                throw new NotEnoughFundsException("Not enough fund to cover the target");
            }
            var total  = selection.Select(s => s.Amount).Sum();
            var change = total - target;

            if (change < Money.Zero)
            {
                throw new NotEnoughFundsException("Not enough fund to cover the target");
            }
            if (change > ctx.Dust)
            {
                if (group.ChangeScript[(int)ctx.ChangeType] == null)
                {
                    throw new InvalidOperationException("A change address should be specified (" + ctx.ChangeType + ")");
                }

                ctx.RestoreMemento(originalCtx);
                ctx.ChangeAmount = change;
                try
                {
                    return(BuildTransaction(ctx, group, builders, coins));
                }
                finally
                {
                    ctx.ChangeAmount = Money.Zero;
                }
            }
            foreach (var coin in selection)
            {
                var input = ctx.Transaction.AddInput(new TxIn(coin.Outpoint));
                if (_LockTime != null && _LockTime.HasValue && !ctx.NonFinalSequenceSet)
                {
                    input.Sequence          = 0;
                    ctx.NonFinalSequenceSet = true;
                }
            }
            return(selection);
        }
예제 #3
0
		private IEnumerable<ICoin> BuildTransaction(
			TransactionBuildingContext ctx,
			BuilderGroup group,
			IEnumerable<Builder> builders,
			IEnumerable<ICoin> coins,
			IMoney zero)
		{
			var originalCtx = ctx.CreateMemento();
			var target = builders.Concat(ctx.AdditionalBuilders).Select(b => b(ctx)).Sum(zero);
			if(ctx.CoverOnly != null)
			{
				target = ctx.CoverOnly.Add(ctx.ChangeAmount);
			}

			var unconsumed = coins.Where(c => ctx.ConsumedCoins.All(cc => cc.Outpoint != c.Outpoint));
			var selection = CoinSelector.Select(unconsumed, target);
			if(selection == null)
				throw new NotEnoughFundsException("Not enough fund to cover the target",
					group.Name,
					target.Sub(unconsumed.Select(u => u.Amount).Sum(zero))
					);
			var total = selection.Select(s => s.Amount).Sum(zero);
			var change = total.Sub(target);
			if(change.CompareTo(zero) == -1)
				throw new NotEnoughFundsException("Not enough fund to cover the target",
					group.Name,
					change.Negate()
				);
			if(change.CompareTo(ctx.Dust) == 1)
			{
				var changeScript = group.ChangeScript[(int)ctx.ChangeType];
				if(changeScript == null)
					throw new InvalidOperationException("A change address should be specified (" + ctx.ChangeType + ")");
				if(!(ctx.Dust is Money) || change.CompareTo(GetDust(changeScript)) == 1)
				{
					ctx.RestoreMemento(originalCtx);
					ctx.ChangeAmount = change;
					try
					{
						return BuildTransaction(ctx, group, builders, coins, zero);
					}
					finally
					{
						ctx.ChangeAmount = zero;
					}
				}
			}
			foreach(var coin in selection)
			{
				ctx.ConsumedCoins.Add(coin);
				var input = ctx.Transaction.Inputs.FirstOrDefault(i => i.PrevOut == coin.Outpoint);
				if(input == null)
					input = ctx.Transaction.AddInput(new TxIn(coin.Outpoint));
				if(_LockTime != null && !ctx.NonFinalSequenceSet)
				{
					input.Sequence = 0;
					ctx.NonFinalSequenceSet = true;
				}
			}
			return selection;
		}
예제 #4
0
			public TransactionBuildingContext CreateMemento()
			{
				var memento = new TransactionBuildingContext(Builder);
				memento.RestoreMemento(this);
				return memento;
			}