示例#1
0
        public TrustedBroadcastRequest FulfillOffer(
            TransactionSignature clientSignature,
            Script cashout,
            FeeRate feeRate)
        {
            if (clientSignature == null)
            {
                throw new ArgumentNullException(nameof(clientSignature));
            }
            if (feeRate == null)
            {
                throw new ArgumentNullException(nameof(feeRate));
            }
            AssertState(SolverServerStates.WaitingFulfillment);
            Script offerScript = GetOfferScript();

            var offer = GetUnsignedOfferTransaction();

            PubKey clientKey = AssertValidSignature(clientSignature, offer);

            TransactionBuilder builder = new TransactionBuilder();

            builder.StandardTransactionPolicy.CheckFee = false;
            builder.Extensions.Add(new EscrowBuilderExtension());
            builder.AddCoins(InternalState.EscrowedCoin);
            builder.AddKeys(InternalState.EscrowKey);
            builder.AddKnownSignature(clientKey, clientSignature);
            builder.SignTransactionInPlace(offer);
            if (!builder.Verify(offer))
            {
                throw new PuzzleException("invalid-tumbler-signature");
            }
            var offerCoin = offer.Outputs.AsCoins().First().ToScriptCoin(offerScript);

            var         solutions = InternalState.SolvedPuzzles.Select(s => s.SolutionKey).ToArray();
            Transaction fulfill   = new Transaction();

            fulfill.Inputs.Add(new TxIn(offerCoin.Outpoint));
            fulfill.Outputs.Add(new TxOut(offerCoin.Amount, cashout));

            var fulfillScript = SolverScriptBuilder.CreateFulfillScript(NBitcoin.BuilderExtensions.BuilderExtension.DummySignature, solutions);

            fulfill.Inputs[0].ScriptSig = fulfillScript + Op.GetPushOp(offerCoin.Redeem.ToBytes());

            fulfill.Outputs[0].Value -= feeRate.GetFee(fulfill.GetVirtualSize());

            var signature = fulfill.Inputs.AsIndexedInputs().First().Sign(InternalState.FulfillKey, offerCoin, SigHash.All);

            fulfillScript = SolverScriptBuilder.CreateFulfillScript(signature, solutions);
            fulfill.Inputs[0].ScriptSig = fulfillScript + Op.GetPushOp(offerCoin.Redeem.ToBytes());

            InternalState.OfferClientSignature = clientSignature;
            InternalState.Status = SolverServerStates.WaitingEscape;
            return(new TrustedBroadcastRequest
            {
                Key = InternalState.FulfillKey,
                PreviousScriptPubKey = offerCoin.ScriptPubKey,
                Transaction = fulfill
            });
        }
示例#2
0
        public TrustedBroadcastRequest FulfillOffer(
            TransactionSignature clientSignature,
            Script cashout,
            FeeRate feeRate)
        {
            if (clientSignature == null)
            {
                throw new ArgumentNullException(nameof(clientSignature));
            }
            if (feeRate == null)
            {
                throw new ArgumentNullException(nameof(feeRate));
            }
            AssertState(SolverServerStates.WaitingFulfillment);

            var    offer     = GetUnsignedOfferTransaction();
            PubKey clientKey = AssertValidSignature(clientSignature, offer);

            offer.Inputs[0].ScriptSig = new Script(
                Op.GetPushOp(clientSignature.ToBytes()),
                Op.GetPushOp(CreateOfferSignature().ToBytes()),
                Op.GetPushOp(InternalState.EscrowedCoin.Redeem.ToBytes())
                );
            offer.Inputs[0].Witnessify();

            if (!offer.Inputs.AsIndexedInputs().First().VerifyScript(_Network, InternalState.EscrowedCoin))
            {
                throw new PuzzleException("invalid-tumbler-signature");
            }


            var         solutions = InternalState.SolvedPuzzles.Select(s => s.SolutionKey).ToArray();
            Transaction fulfill   = new Transaction();

            fulfill.Inputs.Add(new TxIn());
            fulfill.Outputs.Add(new TxOut(InternalState.OfferCoin.Amount, cashout));

            var fulfillScript = SolverScriptBuilder.CreateFulfillScript(null, solutions);

            fulfill.Inputs[0].ScriptSig = fulfillScript + Op.GetPushOp(InternalState.OfferCoin.Redeem.ToBytes());
            fulfill.Inputs[0].Witnessify();
            var virtualSize = fulfill.HasWitness ? fulfill.GetVirtualSize(_Network.Consensus.Options.WitnessScaleFactor) : fulfill.GetSerializedSize();

            fulfill.Outputs[0].Value -= feeRate.GetFee(virtualSize);

            InternalState.OfferClientSignature = clientSignature;
            InternalState.Status = SolverServerStates.WaitingEscape;
            return(new TrustedBroadcastRequest
            {
                Key = InternalState.FulfillKey,
                PreviousScriptPubKey = InternalState.OfferCoin.ScriptPubKey,
                Transaction = fulfill
            });
        }