Beispiel #1
0
        public static Script CreateOfferScript(OfferScriptPubKeyParameters parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }
            List <Op> ops = new List <Op>();

            ops.Add(OpcodeType.OP_DEPTH);
            ops.Add(Op.GetPushOp(parameters.Hashes.Length + 1));
            ops.Add(OpcodeType.OP_EQUAL);
            ops.Add(OpcodeType.OP_IF);
            foreach (var hash in parameters.Hashes)
            {
                ops.Add(OpcodeType.OP_RIPEMD160);
                ops.Add(Op.GetPushOp(hash.ToBytes()));
                ops.Add(OpcodeType.OP_EQUALVERIFY);
            }
            ops.Add(Op.GetPushOp(parameters.FulfillKey.ToBytes()));
            ops.Add(OpcodeType.OP_ELSE);
            ops.Add(Op.GetPushOp(parameters.Expiration));
            ops.Add(OpcodeType.OP_CHECKLOCKTIMEVERIFY);
            ops.Add(OpcodeType.OP_DROP);
            ops.Add(Op.GetPushOp(parameters.RedeemKey.ToBytes()));
            ops.Add(OpcodeType.OP_ENDIF);
            ops.Add(OpcodeType.OP_CHECKSIG);
            return(new Script(ops.ToArray()));
        }
Beispiel #2
0
        public TransactionSignature SignOffer(OfferInformation offerInformation)
        {
            if (offerInformation == null)
            {
                throw new ArgumentNullException(nameof(offerInformation));
            }
            AssertState(SolverClientStates.WaitingOffer);

            var offerScript = new OfferScriptPubKeyParameters
            {
                Hashes     = _PuzzleElements.OfType <RealPuzzle>().Select(p => p.Commitment.KeyHash).ToArray(),
                FulfillKey = offerInformation.FulfillKey,
                Expiration = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin).LockTime,
                RedeemKey  = InternalState.EscrowKey.PubKey
            }.ToScript();

            var escrowCoin = InternalState.EscrowedCoin;
            var txOut      = new TxOut(escrowCoin.Amount - offerInformation.Fee, offerScript.WitHash.ScriptPubKey.Hash);
            var offerCoin  = new Coin(escrowCoin.Outpoint, txOut).ToScriptCoin(offerScript);


            Transaction tx = new Transaction();

            tx.Inputs.Add(new TxIn(escrowCoin.Outpoint));
            tx.Outputs.Add(offerCoin.TxOut);

            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(escrowCoin);

            escrowCoin = escrowCoin.Clone();
            escrowCoin.OverrideScriptCode(escrow.GetInitiatorScriptCode());
            var signature = tx.Inputs.AsIndexedInputs().First().Sign(InternalState.EscrowKey, escrowCoin, SigHash.All);

            InternalState.OfferCoin = offerCoin;
            InternalState.Status    = SolverClientStates.WaitingPuzzleSolutions;
            return(signature);
        }
Beispiel #3
0
        public OfferInformation CheckBlindedFactors(BlindFactor[] blindFactors, FeeRate feeRate)
        {
            if (blindFactors == null)
            {
                throw new ArgumentNullException(nameof(blindFactors));
            }
            if (blindFactors.Length != Parameters.RealPuzzleCount)
            {
                throw new ArgumentException("Expecting " + Parameters.RealPuzzleCount + " blind factors");
            }
            AssertState(SolverServerStates.WaitingBlindFactor);
            Puzzle unblindedPuzzle = null;
            int    y = 0;

            for (int i = 0; i < Parameters.RealPuzzleCount; i++)
            {
                var solvedPuzzle = InternalState.SolvedPuzzles[i];
                var unblinded    = new Puzzle(Parameters.ServerKey, solvedPuzzle.Puzzle).Unblind(blindFactors[i]);
                if (unblindedPuzzle == null)
                {
                    unblindedPuzzle = unblinded;
                }
                else if (unblinded != unblindedPuzzle)
                {
                    throw new PuzzleException("Invalid blind factor");
                }
                y++;
            }

            InternalState.FulfillKey = new Key();

            Transaction dummy = new Transaction();

            dummy.AddInput(new TxIn(InternalState.EscrowedCoin.Outpoint));
            dummy.Inputs[0].ScriptSig = new Script(
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(InternalState.EscrowedCoin.Redeem.ToBytes())
                );
            dummy.Inputs[0].Witnessify();
            dummy.AddOutput(new TxOut(InternalState.EscrowedCoin.Amount, new Key().ScriptPubKey.Hash));

            var offerTransactionFee = feeRate.GetFee(dummy.GetVirtualSize());


            var escrow            = InternalState.EscrowedCoin;
            var escrowInformation = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin);
            var redeem            = new OfferScriptPubKeyParameters
            {
                Hashes     = InternalState.SolvedPuzzles.Select(p => p.SolutionKey.GetHash()).ToArray(),
                FulfillKey = InternalState.FulfillKey.PubKey,
                Expiration = escrowInformation.LockTime,
                RedeemKey  = escrowInformation.Initiator
            }.ToScript();
            var txOut = new TxOut(escrow.Amount - offerTransactionFee, redeem.WitHash.ScriptPubKey.Hash);

            InternalState.OfferCoin = new Coin(escrow.Outpoint, txOut).ToScriptCoin(redeem);
            InternalState.Status    = SolverServerStates.WaitingFulfillment;
            return(new OfferInformation
            {
                FulfillKey = InternalState.FulfillKey.PubKey,
                Fee = offerTransactionFee
            });
        }
Beispiel #4
0
 public static OfferScriptPubKeyParameters ExtractOfferScriptParameters(Script scriptPubKey)
 {
     if (scriptPubKey == null)
     {
         throw new ArgumentNullException(nameof(scriptPubKey));
     }
     try
     {
         var result = new OfferScriptPubKeyParameters();
         var ops    = scriptPubKey.ToOps().ToArray();
         int i      = 0;
         if (ops[i++].Code != OpcodeType.OP_DEPTH)
         {
             return(null);
         }
         var pushCount = ops[i++].GetInt();
         if (pushCount == null || pushCount > 500)
         {
             return(null);
         }
         result.Hashes = new uint160[pushCount.Value - 1];
         CheckMinimal(ops[i - 1], pushCount.Value);
         if (ops[i++].Code != OpcodeType.OP_EQUAL)
         {
             return(null);
         }
         if (ops[i++].Code != OpcodeType.OP_IF)
         {
             return(null);
         }
         for (int y = 0; y < result.Hashes.Length; y++)
         {
             if (ops[i++].Code != OpcodeType.OP_RIPEMD160)
             {
                 return(null);
             }
             result.Hashes[y] = new uint160(ops[i++].PushData);
             if (ops[i++].Code != OpcodeType.OP_EQUALVERIFY)
             {
                 return(null);
             }
         }
         result.FulfillKey = new PubKey(ops[i++].PushData);
         if (ops[i++].Code != OpcodeType.OP_ELSE)
         {
             return(null);
         }
         result.Expiration = new LockTime(checked ((uint)ops[i++].GetLong()));
         CheckMinimal(ops[i - 1], (uint)result.Expiration);
         if (ops[i++].Code != OpcodeType.OP_CHECKLOCKTIMEVERIFY)
         {
             return(null);
         }
         if (ops[i++].Code != OpcodeType.OP_DROP)
         {
             return(null);
         }
         result.RedeemKey = new PubKey(ops[i++].PushData);
         if (ops[i++].Code != OpcodeType.OP_ENDIF)
         {
             return(null);
         }
         if (ops[i++].Code != OpcodeType.OP_CHECKSIG)
         {
             return(null);
         }
         if (i != ops.Length)
         {
             return(null);
         }
         return(result);
     }
     catch { return(null); }
 }