Пример #1
0
        public ScriptCoinModel OpenChannel(
            [ModelBinder(BinderType = typeof(TumblerParametersModelBinder))]
            ClassicTumblerParameters tumblerId,
            [FromBody] OpenChannelRequest request)
        {
            if (tumblerId == null)
            {
                throw new ArgumentNullException("tumblerId");
            }
            var height = Services.BlockExplorerService.GetCurrentHeight();
            var cycle  = GetCycle(request.CycleStart);

            if (!cycle.IsInPhase(CyclePhase.TumblerChannelEstablishment, height))
            {
                throw new ActionResultException(BadRequest("invalid-phase"));
            }
            var fee = Services.FeeService.GetFeeRate();

            try
            {
                if (!Parameters.VoucherKey.Verify(request.Signature, NBitcoin.Utils.ToBytes((uint)request.CycleStart, true), request.Nonce))
                {
                    throw new ActionResultException(BadRequest("incorrect-voucher"));
                }
                if (!Repository.MarkUsedNonce(request.CycleStart, request.Nonce))
                {
                    throw new ActionResultException(BadRequest("nonce-already-used"));
                }

                var escrowKey = new Key();

                var escrow = new EscrowScriptPubKeyParameters();
                escrow.LockTime  = cycle.GetTumblerLockTime();
                escrow.Receiver  = request.EscrowKey;
                escrow.Initiator = escrowKey.PubKey;

                Logs.Tumbler.LogInformation($"Cycle {cycle.Start} Asked to open channel");
                var txOut              = new TxOut(Parameters.Denomination, escrow.ToScript().Hash);
                var tx                 = Services.WalletService.FundTransaction(txOut, fee);
                var correlation        = escrow.GetCorrelation();
                var escrowTumblerLabel = $"Cycle {cycle.Start} Tumbler Escrow";
                Services.BlockExplorerService.Track(txOut.ScriptPubKey);

                Tracker.AddressCreated(cycle.Start, TransactionType.TumblerEscrow, txOut.ScriptPubKey, correlation);
                Tracker.TransactionCreated(cycle.Start, TransactionType.TumblerEscrow, tx.GetHash(), correlation);
                Logs.Tumbler.LogInformation($"Cycle {cycle.Start} Channel created " + tx.GetHash());

                var coin = tx.Outputs.AsCoins().First(o => o.ScriptPubKey == txOut.ScriptPubKey && o.TxOut.Value == txOut.Value);

                var session = new PromiseServerSession(Parameters.CreatePromiseParamaters());
                var redeem  = Services.WalletService.GenerateAddress();
                session.ConfigureEscrowedCoin(coin.ToScriptCoin(escrow.ToScript()), escrowKey, redeem.ScriptPubKey);
                Repository.Save(cycle.Start, session);

                Services.BroadcastService.Broadcast(tx);

                var redeemTx = session.CreateRedeemTransaction(fee);
                Tracker.AddressCreated(cycle.Start, TransactionType.TumblerRedeem, redeem.ScriptPubKey, correlation);
                Services.TrustedBroadcastService.Broadcast(cycle.Start, TransactionType.TumblerRedeem, correlation, redeemTx);
                return(new ScriptCoinModel(session.EscrowedCoin));
            }
            catch (PuzzleException)
            {
                throw new ActionResultException(BadRequest("incorrect-voucher"));
            }
            catch (NotEnoughFundsException ex)
            {
                Logs.Tumbler.LogInformation(ex.Message);
                throw new ActionResultException(BadRequest("tumbler-insufficient-funds"));
            }
        }