示例#1
0
 public static Transaction SignPayment(Transaction payment, Key key, ScriptCoin fundingCoin)
 {
     return(new TransactionBuilder()
            .AddKeys(key)
            .AddCoins(fundingCoin)
            .SignTransaction(payment));
 }
 public override void ConfigureEscrowedCoin(ScriptCoin escrowedCoin, Key escrowKey)
 {
     AssertState(PromiseClientStates.WaitingEscrow);
     Logs.Tumbler.LogDebug($"PromiseClientSession.ConfigureEscrowedCoin() - escrowedCoin.Outpoint.Hash : {escrowedCoin.Outpoint.Hash}, escrowedCoin.Outpoint.N : {escrowedCoin.Outpoint.N}");
     base.ConfigureEscrowedCoin(escrowedCoin, escrowKey);
     InternalState.Status = PromiseClientStates.WaitingSignatureRequest;
 }
        public PromiseClientSession ReceiveTumblerEscrowedCoin(ScriptCoin escrowedCoin)
        {
            AssertState(TumblerClientSessionStates.WaitingTumblerEscrow);
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(escrowedCoin);

            if (escrow == null)
            {
                throw new PuzzleException("invalid-escrow");
            }
            if (!escrowedCoin.IsP2SH || escrowedCoin.RedeemType != RedeemType.WitnessV0)
            {
                throw new PuzzleException("invalid-escrow");
            }
            var expectedEscrow = GetTumblerEscrowParameters(escrow.Initiator);

            if (escrow != expectedEscrow)
            {
                throw new PuzzleException("invalid-escrow");
            }
            if (escrowedCoin.Amount != Parameters.Denomination)
            {
                throw new PuzzleException("invalid-amount");
            }


            InternalState.Status = TumblerClientSessionStates.PromisePhase;
            var session = new PromiseClientSession(Parameters.CreatePromiseParamaters());

            session.SetChannelId(InternalState.ChannelId);
            session.ConfigureEscrowedCoin(escrowedCoin, InternalState.TumblerEscrowKey);
            InternalState.TumblerEscrowKey = null;
            return(session);
        }
示例#4
0
        public async Task AcceptToMemoryPool_WithP2WSHValidTxns_IsSuccessfullAsync()
        {
            string dataDir = Path.Combine("TestData", nameof(MempoolValidatorTest), nameof(this.AcceptToMemoryPool_WithP2WSHValidTxns_IsSuccessfullAsync));

            Directory.CreateDirectory(dataDir);

            BitcoinSecret     miner   = new BitcoinSecret(new Key(), Network.PurpleRegTest);
            ITestChainContext context = await TestChainFactory.CreateAsync(Network.PurpleRegTest, miner.PubKey.ScriptPubKey.WitHash.ScriptPubKey, dataDir);

            IMempoolValidator validator = context.MempoolValidator;

            Assert.NotNull(validator);

            BitcoinSecret bob = new BitcoinSecret(new Key(), Network.PurpleRegTest);

            // Fund Bob
            // 50 Coins come from first tx on chain - send bob 42 and change back to miner
            ScriptCoin         witnessCoin = new ScriptCoin(context.SrcTxs[0].GetHash(), 0, context.SrcTxs[0].TotalOut, miner.PubKey.ScriptPubKey.WitHash.ScriptPubKey, miner.PubKey.ScriptPubKey);
            TransactionBuilder txBuilder   = new TransactionBuilder();
            Transaction        p2wshTx     = txBuilder
                                             .AddCoins(witnessCoin)
                                             .AddKeys(miner)
                                             .Send(bob, "42.00")
                                             .SendFees("0.001")
                                             .SetChange(miner)
                                             .BuildTransaction(true);

            Assert.True(txBuilder.Verify(p2wshTx)); //check fully signed
            MempoolValidationState state = new MempoolValidationState(false);

            Assert.True(await validator.AcceptToMemoryPool(state, p2wshTx), $"Transaction: {nameof(p2wshTx)} failed mempool validation.");

            Directory.Delete(dataDir, true);
        }
示例#5
0
        public virtual void ConfigureEscrowedCoin(uint160 channelId, ScriptCoin escrowedCoin, Key escrowKey,
                                                  Script redeemDestination)
        {
            if (escrowedCoin == null)
            {
                throw new ArgumentNullException(nameof(escrowedCoin));
            }
            if (escrowKey == null)
            {
                throw new ArgumentNullException(nameof(escrowKey));
            }
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(escrowedCoin);

            if (escrow == null ||
                escrow.Initiator != escrowKey.PubKey)
            {
                throw new PuzzleException("Invalid escrow");
            }
            InternalState.ChannelId         = channelId ?? throw new ArgumentNullException(nameof(channelId));
            InternalState.EscrowedCoin      = escrowedCoin;
            InternalState.EscrowKey         = escrowKey;
            InternalState.RedeemDestination =
                redeemDestination ?? throw new ArgumentNullException(nameof(redeemDestination));

            Logs.Tumbler.LogDebug(
                $"EscrowInitiator.ConfigureEscrowedCoin() - ChannelId : {InternalState.ChannelId}, EscrowedCoin.Outpoint.Hash : {InternalState.EscrowedCoin.Outpoint.Hash}, EscrowedCoin.Outpoint.N : {InternalState.EscrowedCoin.Outpoint.N}, RedeemDestination : {InternalState.RedeemDestination}");
        }
示例#6
0
        public Transaction CreatePayment(Money paid, ScriptCoin fundingCoin)
        {
            if (paid > GetFundAmount())
            {
                throw new MicroPaymentException("Payment reached the maximum");
            }
            var builder = new TransactionBuilder();

            if (fundingCoin.Redeem != Redeem || fundingCoin.Amount != Amount + Fees)
            {
                throw new MicroPaymentException("Invalid funding coin");
            }

            var fees    = Money.Min(paid, Fees);
            var toPayer = GetFundAmount() - paid;
            var toPayee = paid - fees;

            return(builder
                   .AddCoins(fundingCoin)
                   .Send(Payee.ScriptPubkey, toPayee)
                   .Send(Payer.ScriptPubkey, toPayer)
                   .SendFees(fees)
                   .Shuffle()
                   .BuildTransaction(false));
        }
示例#7
0
        public static void Execute()
        {
            // This P2SH scriptPubKey represents the hash of the
            // multi - sig script: redeemScript.Hash.ScriptPubKey
            Key bob     = new Key();
            Key alice   = new Key();
            Key satoshi = new Key();

            PubKey[] pubKeys       = new[] { bob.PubKey, alice.PubKey, satoshi.PubKey };
            Script   redeemScript  = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, pubKeys);
            Script   paymentScript = redeemScript.PaymentScript;

            Console.WriteLine("RedeemScript : " + redeemScript);
            Console.WriteLine("PaymentScript: " + paymentScript);
            Console.WriteLine("ScriptPubKey : " + redeemScript.Hash.ScriptPubKey);
            Console.WriteLine("WalletAddress: " + redeemScript.Hash.GetAddress(Network.Main));

            // Imagine that the multi-sig P2SH receives a coin in a transaction called received.
            Transaction received = new Transaction();

            // Pay to the script hash
            // Warning: The payment is sent to redeemScript.Hash and not to redeemScript!
            received.Outputs.Add(new TxOut(Money.Coins(1.0m), redeemScript.Hash));
            Console.WriteLine("receivedTxn: \n" + received);

            // any 2 of 3 owner that control the multi-sig address want to spend
            // instead of creating a Coin they will need to create a ScriptCoin
            // Give the redeemScript to the coin for Transaction construction and signing
            ScriptCoin coin = received.Outputs.AsCoins().First().ToScriptCoin(redeemScript);

            Console.WriteLine("ScriptCoin: " + coin);

            // The rest of the code concerning transaction generation and signing is exactly the same
            // as in the previous section about native multi sig
        }
        public virtual void ConfigureEscrowedCoin(ScriptCoin escrowedCoin, Key escrowKey, Script redeemDestination)
        {
            if (escrowedCoin == null)
            {
                throw new ArgumentNullException(nameof(escrowedCoin));
            }
            if (escrowKey == null)
            {
                throw new ArgumentNullException(nameof(escrowKey));
            }
            if (redeemDestination == null)
            {
                throw new ArgumentNullException(nameof(redeemDestination));
            }
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(escrowedCoin);

            if (escrow == null ||
                escrow.Initiator != escrowKey.PubKey)
            {
                throw new PuzzleException("Invalid escrow");
            }
            InternalState.EscrowedCoin      = escrowedCoin;
            InternalState.EscrowKey         = escrowKey;
            InternalState.RedeemDestination = redeemDestination;
        }
示例#9
0
        private void Code14()
        {
            Key bob     = new Key();
            Key alice   = new Key();
            Key satoshi = new Key();

            Script redeemScript =
                PayToMultiSigTemplate
                .Instance
                .GenerateScriptPubKey(2, new[] { bob.PubKey, alice.PubKey, satoshi.PubKey });

            Transaction received = new Transaction();

            //Pay to the script hash
            received.Outputs.Add(new TxOut(Money.Coins(1.0m), redeemScript.Hash));

            TransactionBuilder builder = new TransactionBuilder();

            //Give the redeemScript to the coin for Transaction construction
            //and signing
            ScriptCoin coin = new ScriptCoin(
                new OutPoint(received.GetHash(), 0),
                received.Outputs[0],
                redeemScript
                );
        }
        public PromiseClientSession ReceiveTumblerEscrowedCoin(ScriptCoin escrowedCoin)
        {
            AssertState(TumblerClientSessionStates.WaitingTumblerEscrow);
            var escrow         = EscrowScriptPubKeyParameters.GetFromCoin(escrowedCoin);
            var expectedEscrow = new EscrowScriptPubKeyParameters()
            {
                Initiator = escrow?.Initiator,
                Receiver  = InternalState.TumblerEscrowKey.PubKey,
                LockTime  = GetCycle().GetTumblerLockTime()
            };

            if (escrow == null || escrow != expectedEscrow)
            {
                throw new PuzzleException("invalid-escrow");
            }
            if (escrowedCoin.Amount != Parameters.Denomination)
            {
                throw new PuzzleException("invalid-amount");
            }


            InternalState.Status = TumblerClientSessionStates.PromisePhase;
            var session = new PromiseClientSession(Parameters.CreatePromiseParamaters());

            session.SetChannelId(InternalState.ChannelId);
            session.ConfigureEscrowedCoin(escrowedCoin, InternalState.TumblerEscrowKey);
            InternalState.TumblerEscrowKey = null;
            return(session);
        }
示例#11
0
        public byte[] GetSignatureHash(Script redeemScript, ITxOutput spentOutput)
        {
            var coin = ((BitcoinBasedTxOutput)spentOutput).Coin;

            var scriptCoint = new ScriptCoin(coin, redeemScript);

            return(Tx.GetSignatureHash(scriptCoint).ToBytes());
        }
示例#12
0
        public virtual void ConfigureEscrowedCoin(ScriptCoin escrowedCoin, Key escrowKey)
        {
            InternalState.EscrowKey    = escrowKey ?? throw new ArgumentNullException(nameof(escrowKey));
            InternalState.EscrowedCoin = escrowedCoin ?? throw new ArgumentNullException(nameof(escrowedCoin));

            Logs.Tumbler.LogDebug(
                $"EscrowReceiver.ConfigureEscrowedCoin() - EscrowedCoin.Outpoint.Hash : {InternalState.EscrowedCoin.Outpoint.Hash}, EscrowedCoin.Outpoint.N : {InternalState.EscrowedCoin.Outpoint.N}");
        }
 public override void ConfigureEscrowedCoin(uint160 channelId, ScriptCoin escrowedCoin, Key escrowKey,
                                            Script redeemDestination)
 {
     AssertState(SolverClientStates.WaitingEscrow);
     Logs.Tumbler.LogDebug($"SolverClientSession.ConfigureEscrowedCoin() - escrowedCoin.Outpoint.Hash : {escrowedCoin.Outpoint.Hash}, escrowedCoin.Outpoint.N : {escrowedCoin.Outpoint.N}");
     base.ConfigureEscrowedCoin(channelId, escrowedCoin, escrowKey, redeemDestination);
     InternalState.Status = SolverClientStates.WaitingPuzzle;
 }
示例#14
0
 public async Task <Transaction> ReceiveAsync(ScriptCoin escrowedCoin, TransactionSignature clientSignature, Key escrowKey, FeeRate feeRate)
 {
     _ReceiveBatch.FeeRate = feeRate;
     return(await _ReceiveBatch.WaitTransactionAsync(new ClientEscapeData()
     {
         ClientSignature = clientSignature,
         EscrowedCoin = escrowedCoin,
         EscrowKey = escrowKey
     }).ConfigureAwait(false));
 }
示例#15
0
        private void Code16()
        {
            BitcoinAddress address      = new BitcoinPubKeyAddress("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB");
            var            birth        = Encoding.UTF8.GetBytes("18/07/1988");
            var            birthHash    = Hashes.Hash256(birth);
            Script         redeemScript = new Script(
                "OP_IF "
                + "OP_HASH256 " + Op.GetPushOp(birthHash.ToBytes()) + " OP_EQUAL " +
                "OP_ELSE "
                + address.ScriptPubKey + " " +
                "OP_ENDIF");

            var tx = new Transaction();

            tx.Outputs.Add(new TxOut(Money.Parse("0.0001"), redeemScript.Hash));
            ScriptCoin scriptCoin = tx.Outputs.AsCoins().First().ToScriptCoin(redeemScript);

            //Create spending transaction
            Transaction spending = new Transaction();

            spending.AddInput(new TxIn(new OutPoint(tx, 0)));

            ////Option 1 : Spender knows my birthdate
            ScriptEvaluationContext eval = new ScriptEvaluationContext();
            Op     pushBirthdate         = Op.GetPushOp(birth);
            Op     selectIf    = OpcodeType.OP_1; //go to if
            Op     redeemBytes = Op.GetPushOp(redeemScript.ToBytes());
            Script scriptSig   = new Script(pushBirthdate, selectIf, redeemBytes);

            spending.Inputs[0].ScriptSig = scriptSig;

            //Verify the script pass
            var result = eval.VerifyScript(scriptSig, tx.Outputs[0].ScriptPubKey, spending, 0, null);

            Console.WriteLine(result);
            ///////////

            ////Option 2 : Spender knows my private key
            eval = new ScriptEvaluationContext();
            BitcoinSecret secret     = new BitcoinSecret("...");
            var           sig        = spending.SignInput(secret.PrivateKey, scriptCoin);
            var           p2pkhProof = PayToPubkeyHashTemplate
                                       .Instance
                                       .GenerateScriptSig(sig, secret.PrivateKey.PubKey);

            selectIf  = OpcodeType.OP_0; //go to else
            scriptSig = p2pkhProof + selectIf + redeemBytes;
            spending.Inputs[0].ScriptSig = scriptSig;

            //Verify the script pass
            result = eval.VerifyScript(scriptSig, tx.Outputs[0].ScriptPubKey, spending, 0, null);
            Console.WriteLine(result);
            ///////////
        }
示例#16
0
        /// <summary>
        /// NEW!!  So far alright?
        /// </summary>
        public void SegwitTestNet()
        {
            //The faucet: https://testnet.manu.backend.hamburg/faucet
            //https://bitcoin.stackexchange.com/questions/59231/how-to-sign-a-segwit-transaction-via-nbitcoin
            var           net      = NBitcoin.Network.TestNet;
            BlockExplorer explorer = new BlockExplorer("https://testnet.blockexplorer.com/");
            HDWallet      wallet   = new HDWallet("seed12345678ryan12345678", net);
            uint          path     = 0;
            var           extkey   = wallet.GetPrivateKey(path);
            Key           k        = extkey.PrivateKey;

            //This gives you a Bech32 address (currently not really interoperable in wallets, so you need to convert it into P2SH)
            var address = k.PubKey.WitHash.GetAddress(net);

            var p2sh = address.GetScriptAddress();
            //p2sh is now an interoperable P2SH segwit address

            //SENT TO: 2NGSoYM3yLi9SXvZc5yYcSwHWyCWzgBrP9X
            //TXID 1397a4cc480879eae604ce871c47a4d690c6ea6a6dcfd7e38d95f31b81593556

            var response = explorer.GetUnspent(p2sh.ToString());
            List <ExplorerUnspent> unspent      = response.Convert <List <ExplorerUnspent> >();
            List <Transaction>     transactions = new List <Transaction>();

            foreach (var item in unspent)
            {
                string           txcontent  = "{\"txid\":\"6636b3fedb57be81232f92f80fa8d3df9a0f07305af2c7f705a7f353e516b1d7\",\"version\":1,\"locktime\":0,\"vin\":[{\"txid\":\"50b7d9a5fa1281e7020fa8a152835756e0d57d6b4d634b4251ab500e8630bc3e\",\"vout\":1,\"scriptSig\":{\"asm\":\"0014a16f4ba22e84c364ec4f8fe19d8a48762156b41e\",\"hex\":\"160014a16f4ba22e84c364ec4f8fe19d8a48762156b41e\"},\"sequence\":4294967295,\"n\":0,\"addr\":\"2N9viNVJ5MsAM8MXdUuATDwKeMjMLQkaXyR\",\"valueSat\":193987962850,\"value\":1939.8796285,\"doubleSpentTxID\":null}],\"vout\":[{\"value\":\"2.00000000\",\"n\":0,\"scriptPubKey\":{\"hex\":\"a9142f672b3ea4af55d9da43e507e3c060d2e34521ba87\",\"asm\":\"OP_HASH160 2f672b3ea4af55d9da43e507e3c060d2e34521ba OP_EQUAL\",\"addresses\":[\"2MwZsLbuB328gxHRfr1VDrfDrK6aWicQcAW\"],\"type\":\"scripthash\"},\"spentTxId\":null,\"spentIndex\":null,\"spentHeight\":null},{\"value\":\"1937.87862850\",\"n\":1,\"scriptPubKey\":{\"hex\":\"a914859695c2cb37ee30bf6a18943c8c27a3ac0e6faa87\",\"asm\":\"OP_HASH160 859695c2cb37ee30bf6a18943c8c27a3ac0e6faa OP_EQUAL\",\"addresses\":[\"2N5RaFdK3rgsNayXnkTQaSLKVBB3brW7G4m\"],\"type\":\"scripthash\"},\"spentTxId\":\"892e6facc4fc596852d41af367dd41f7a7ec1b11a319a202bc0d4c5b8f792f2f\",\"spentIndex\":0,\"spentHeight\":1255964}],\"blockhash\":\"000000000007dbc3ffd03559f2192b299bc0c20aa0aea8e1939f2731e01103e8\",\"blockheight\":1255946,\"confirmations\":123,\"time\":1514228293,\"blocktime\":1514228293,\"valueOut\":1939.8786285,\"size\":138,\"valueIn\":1939.8796285,\"fees\":0.001}";
                ExplorerResponse txResponse = explorer.GetTransaction(item.txid);
                RawFormat        format     = RawFormat.Satoshi;
                var tx = Transaction.Parse(txResponse.data, format, net);
                transactions.Add(tx);
            }
            //For spending, it works the same as a a normal P2SH
            //You need to get the ScriptCoin, the RedeemScript of you script coin should be k.PubKey.WitHash.ScriptPubKey.            var redeemScript = k.PubKey.WitHash.ScriptPubKey;
            var         redeemScript = k.PubKey.WitHash.ScriptPubKey;
            Transaction received     = transactions[0];
            ScriptCoin  coin         = received.Outputs.AsCoins().First().ToScriptCoin(redeemScript);
            //1397a4cc480879eae604ce871c47a4d690c6ea6a6dcfd7e38d95f31b81593556

            BitcoinAddress     destination = BitcoinAddress.Create("2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF"); //the faucet return address
            TransactionBuilder builder     = new TransactionBuilder();

            builder.AddCoins(coin);
            builder.AddKeys(k);
            builder.Send(destination, Money.Coins(1.99m));
            builder.SendFees(Money.Coins(0.001m));
            builder.SetChange(p2sh);
            var signedTx = builder.BuildTransaction(true);

            Console.WriteLine(signedTx.ToHex());
            string x = ";;";
            //Assert.True(builder.Verify(signedTx));
        }
示例#17
0
 public virtual void ConfigureEscrowedCoin(ScriptCoin escrowedCoin, Key escrowKey)
 {
     if (escrowedCoin == null)
     {
         throw new ArgumentNullException(nameof(escrowedCoin));
     }
     if (escrowKey == null)
     {
         throw new ArgumentNullException(nameof(escrowKey));
     }
     InternalState.EscrowKey    = escrowKey;
     InternalState.EscrowedCoin = escrowedCoin;
 }
示例#18
0
        static internal ICoin[] DummyFundsToCoins(IEnumerable <Transaction> txs, Script redeem, Key key)
        {
            var barecoins = txs.SelectMany(tx => tx.Outputs.AsCoins()).ToArray();
            var coins     = new ICoin[barecoins.Length];

            coins[0] = barecoins[0];
            coins[1] = barecoins[1];
            coins[2] = new ScriptCoin(barecoins[2], redeem);                          // p2sh
            coins[3] = new ScriptCoin(barecoins[3], redeem);                          // p2wsh
            coins[4] = new ScriptCoin(barecoins[4], key.PubKey.WitHash.ScriptPubKey); // p2sh-p2wpkh
            coins[5] = new ScriptCoin(barecoins[5], redeem);                          // p2sh-p2wsh
            return(coins);
        }
示例#19
0
        public async Task <Transaction> ReceiveAsync(ScriptCoin escrowedCoin, TransactionSignature clientSignature, Key escrowKey, FeeRate feeRate)
        {
            _ReceiveBatch.FeeRate = feeRate;
            var task = _ReceiveBatch.WaitTransactionAsync(new ClientEscapeData()
            {
                ClientSignature = clientSignature,
                EscrowedCoin    = escrowedCoin,
                EscrowKey       = escrowKey
            }).ConfigureAwait(false);

            Logs.Tumbler.LogDebug($"ClientEscape batch count {_ReceiveBatch.BatchCount}");
            return(await task);
        }
示例#20
0
 internal void AddRedeemInfo()
 {
     foreach (var match in MatchedRules)
     {
         var scriptRule = match.Rule as ScriptRule;
         if (scriptRule != null && scriptRule.RedeemScript != null)
         {
             CoinCollection collection = match.MatchType == MatchLocation.Input ? SpentCoins : ReceivedCoins;
             if (collection != null)
             {
                 var outpoint = new OutPoint(TransactionId, match.Index);
                 var coin     = collection[outpoint];
                 collection[outpoint] = new ScriptCoin(coin.Outpoint, coin.TxOut, scriptRule.RedeemScript);
             }
         }
     }
 }
示例#21
0
        public uint256 CreateRealHash(Transaction tx, ScriptCoin _Escrow, Money feeVariation)
        {
            /*
             * Not sure if this is best way to do this, but had to add this for step 7
             * when verifying valid Hashes, the server will have to make real hashes, but
             * it doesn't have access to RealHash class. So I created this function that
             * takes care of that
             */
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(_Escrow);
            var coin   = _Escrow.Clone();

            coin.OverrideScriptCode(escrow.GetInitiatorScriptCode());
            var Transaction = tx.Clone();

            Transaction.Outputs[0].Value -= feeVariation;
            return(Transaction.GetSignatureHash(coin, SigHash.All));
        }
示例#22
0
 public void ReadWrite(BitcoinStream stream)
 {
     if (stream.Serializing)
     {
         stream.ReadWrite(ScriptCoin.Redeem);
         stream.ReadWrite(ScriptCoin.Outpoint);
         stream.ReadWrite(ScriptCoin.TxOut);
     }
     else
     {
         Script   redeem   = null;
         OutPoint outpoint = null;
         TxOut    txout    = null;
         stream.ReadWrite(ref redeem);
         stream.ReadWrite(ref outpoint);
         stream.ReadWrite(ref txout);
         ScriptCoin = new ScriptCoin(outpoint, txout, redeem);
     }
 }
示例#23
0
		public Transaction CreatePayment(Money paid, ScriptCoin fundingCoin)
		{
			if(paid > GetFundAmount())
				throw new MicroPaymentException("Payment reached the maximum");
			var builder = new TransactionBuilder();
			if(fundingCoin.Redeem != Redeem || fundingCoin.Amount != Amount + Fees)
				throw new MicroPaymentException("Invalid funding coin");

			var fees = Money.Min(paid, Fees);
			var toPayer = GetFundAmount() - paid;
			var toPayee = paid - fees;
			return builder
				.AddCoins(fundingCoin)
				.Send(Payee.ScriptPubkey, toPayee)
				.Send(Payer.ScriptPubkey, toPayer)
				.SendFees(fees)
				.Shuffle()
				.BuildTransaction(false);
		}
示例#24
0
        private List <ScriptCoin> GetRewardCoins(Transaction coinStake)
        {
            var coins = new List <ScriptCoin>();

            // Identify any outputs paying the reward script a nonzero amount.
            TxOut[] rewardOutputs = coinStake.Outputs.Where(o => o.ScriptPubKey == StraxCoinstakeRule.CirrusRewardScript && o.Value != 0).ToArray();

            // This shouldn't be the case but check anyway.
            if (rewardOutputs.Length != 0)
            {
                foreach (TxOut txOutput in rewardOutputs)
                {
                    // The reward script is P2SH, so we need to inform the builder of the corresponding redeem script to enable it to be spent.
                    var coin = ScriptCoin.Create(this.network, coinStake, txOutput, StraxCoinstakeRule.CirrusRewardScriptRedeem);
                    coins.Add(coin);
                }
            }

            return(coins);
        }
        public async void AcceptToMemoryPool_WithSegWitValidTxns_IsSuccessfull()
        {
            string dataDir = Path.Combine("TestData", nameof(MempoolValidatorTest), nameof(this.AcceptToMemoryPool_WithSegWitValidTxns_IsSuccessfull));

            Directory.CreateDirectory(dataDir);

            BitcoinSecret     miner     = new BitcoinSecret(new Key(), Network.RegTest);
            ITestChainContext context   = TestChainFactory.Create(Network.RegTest, miner.PubKey.ScriptPubKey.WitHash.ScriptPubKey.Hash.ScriptPubKey, dataDir);
            IMempoolValidator validator = context.MempoolValidator;

            Assert.NotNull(validator);

            BitcoinSecret bob = new BitcoinSecret(new Key(), Network.RegTest);

            // Fund Bob
            // 50 Coins come from first tx on chain - send bob 42 and change back to miner
            ScriptCoin         witnessCoin    = new ScriptCoin(context.SrcTxs[0].GetHash(), 0, context.SrcTxs[0].TotalOut, miner.PubKey.ScriptPubKey.WitHash.ScriptPubKey.Hash.ScriptPubKey, miner.PubKey.ScriptPubKey);
            TransactionBuilder txBuilder      = new TransactionBuilder();
            Transaction        p2shOverp2wpkh = txBuilder
                                                .AddCoins(witnessCoin)
                                                .AddKeys(miner)
                                                .Send(bob, "42.00")
                                                .SendFees("0.001")
                                                .SetChange(miner)
                                                .BuildTransaction(true);

            Assert.True(txBuilder.Verify(p2shOverp2wpkh)); //check fully signed

            // remove witness data from tx
            Transaction noWitTx = p2shOverp2wpkh.WithOptions(TransactionOptions.None);

            Assert.Equal(p2shOverp2wpkh.GetHash(), noWitTx.GetHash());
            Assert.True(noWitTx.GetSerializedSize() < p2shOverp2wpkh.GetSerializedSize());

            Assert.True(txBuilder.Verify(p2shOverp2wpkh)); //check fully signed
            MempoolValidationState state = new MempoolValidationState(false);

            Assert.True(await validator.AcceptToMemoryPool(state, p2shOverp2wpkh), $"Transaction: {nameof(p2shOverp2wpkh)} failed mempool validation.");

            Directory.Delete(dataDir, true);
        }
示例#26
0
        public PromiseClientSession ReceiveTumblerEscrowedCoin(ScriptCoin escrowedCoin)
        {
            AssertState(TumblerClientSessionStates.WaitingTumblerEscrow);
            var escrow = EscrowScriptBuilder.ExtractEscrowScriptPubKeyParameters(escrowedCoin.Redeem);

            if (escrow == null || !escrow.EscrowKeys.Contains(InternalState.TumblerEscrowKey.PubKey))
            {
                throw new PuzzleException("invalid-escrow");
            }
            if (escrowedCoin.Amount != Parameters.Denomination)
            {
                throw new PuzzleException("invalid-amount");
            }


            InternalState.Status = TumblerClientSessionStates.PromisePhase;
            var session = new PromiseClientSession(Parameters.CreatePromiseParamaters());

            session.ConfigureEscrowedCoin(escrowedCoin, InternalState.TumblerEscrowKey);
            InternalState.TumblerEscrowKey = null;
            return(session);
        }
示例#27
0
        public virtual void ConfigureEscrowedCoin(ScriptCoin escrowedCoin, Key escrowKey, Key redeemKey)
        {
            if (escrowedCoin == null)
            {
                throw new ArgumentNullException(nameof(escrowedCoin));
            }
            if (escrowKey == null)
            {
                throw new ArgumentNullException(nameof(escrowKey));
            }
            if (redeemKey == null)
            {
                throw new ArgumentNullException(nameof(redeemKey));
            }
            var escrow = EscrowScriptBuilder.ExtractEscrowScriptPubKeyParameters(escrowedCoin.Redeem);

            if (escrow == null || !escrow.EscrowKeys.Any(e => e == escrowKey.PubKey))
            {
                throw new PuzzleException("Invalid escrow");
            }
            InternalState.EscrowedCoin = escrowedCoin;
            InternalState.EscrowKey    = escrowKey;
            InternalState.RedeemKey    = redeemKey;
        }
示例#28
0
 public override void ConfigureEscrowedCoin(ScriptCoin escrowedCoin, Key escrowKey, Key redeemKey)
 {
     AssertState(SolverClientStates.WaitingEscrow);
     base.ConfigureEscrowedCoin(escrowedCoin, escrowKey, redeemKey);
     InternalState.Status = SolverClientStates.WaitingPuzzle;
 }
示例#29
0
 private uint GetCorrelation(ScriptCoin escrowCoin)
 {
     return(new uint160(escrowCoin.Redeem.Hash.ToString()).GetLow32());
 }
示例#30
0
 public static EscrowScriptPubKeyParameters GetFromCoin(ScriptCoin coin)
 {
     return(GetFromScript(coin.Redeem));
 }
示例#31
0
		public static Transaction SignPayment(Transaction payment, Key key, ScriptCoin fundingCoin)
		{
			return new TransactionBuilder()
			   .AddKeys(key)
			   .AddCoins(fundingCoin)
			   .SignTransaction(payment);
		}
示例#32
0
		public void Assert(Transaction payment, bool isRefund, Money paid, ScriptCoin fundCoin = null)
		{
			if(payment.Inputs.Count != 1)
				throw new MicroPaymentException("The payment should have one input");

			var actualFees = GetFundAmount() - payment.TotalOut;
			var expectedFees = Money.Min(paid, Fees);
			if(actualFees < Money.Zero || !actualFees.Almost(expectedFees,0.1m))
				throw new MicroPaymentException("Unexpected fees in the payment");

			if(!GetPaid(payment).Almost(paid))
				throw new MicroPaymentException("Unexpected amount in the payment");

			if(paid > GetFundAmount())
				throw new MicroPaymentException("Payment reached the maximum");

			if(fundCoin != null)
			{
				if(payment.Inputs[0].PrevOut != fundCoin.Outpoint)
					throw new MicroPaymentException("The input reference is incorrect");
				if(fundCoin.Amount != Fees + Amount)
					throw new MicroPaymentException("The fund coin is incorrect");
			}
			if(isRefund)
			{
				if(payment.Outputs.Count != 1)
					throw new MicroPaymentException("The refund should have one output");

				if(payment.Outputs[0].Value != Amount)
					throw new MicroPaymentException("Unexpected amount in the output of the refund transaction");

				if(payment.Outputs[0].ScriptPubKey != Payer.ScriptPubkey)
					throw new MicroPaymentException("The refund address in the refund transaction is not equal to the expected one");

				if(payment.LockTime != Expiration)
					throw new MicroPaymentException("The refund transaction has invalid locktime");
			}
			else
			{
				if(payment.LockTime != default(LockTime))
					throw new MicroPaymentException("The payment transaction has invalid locktime");
				if(payment.Outputs.Count != 1 && payment.Outputs.Count != 2)
					throw new MicroPaymentException("The payment should have one or two outputs");
			}
		}
示例#33
0
        static void Main()
        {
            //===========================================================================================
            //Chapter8. Using the TransactionBuilder

            //You have seen how the TransactionBuilder works when you have signed your first P2SH and multi-sig transaction.
            //We will see how you can harness its full power, for signing more complicated transactions.
            //With the TransactionBuilder you can:
            //1.Spend any
            //P2PK, P2PKH,
            //multi-sig,
            //P2WPK, P2WSH.
            //2.Spend any P2SH on the previous redeem script.
            //3.Spend Stealth Coin(DarkWallet).
            //4.Issue and transfer Colored Coins(open asset, following chapter).
            //5.Combine partially signed transactions.
            //6.Estimate the final size of an unsigned transaction and its fees.
            //7.Verify if a transaction is fully signed.

            //The goal of the TransactionBuilder is to take Coins and Keys as input, and return back a signed or partially signed transaction.
            //Picture depiction:
            //Coins -> Signed transaction(or it could be a signed transactions) <-Keys.


            //The TransactionBuilder will figure out what Coin to use and what to sign by itself.
            //Examine TransactionBuilder class containing lots of properties and methods.


            //The usage of the builder is done in four steps:
            //1.You gather the Coins that spent,
            //2.You gather the Keys that you own,
            //3.You enumerate how much Money you want to send to where scriptPubKey indicates,
            //4.You build and sign the transaction,
            //5.Optional: you give the transaction to somebody else, then he will sign or continue to build it.


            //Now let’s gather some Coins.
            //For that, let us create a fake transaction with some funds on it.
            //Let’s say that the transaction has a P2PKH, P2PK, and multi-sig coin of Bob and Alice.
            RandomUtils.Random = new UnsecureRandom();


            //Private key generator.
            Key           privateKeyGenerator = new Key();
            BitcoinSecret bitcoinSecretFromPrivateKeyGenerator = privateKeyGenerator.GetBitcoinSecret(Network.Main);
            Key           privateKeyFromBitcoinSecret          = bitcoinSecretFromPrivateKeyGenerator.PrivateKey;

            Console.WriteLine($"privateKeyFromBitcoinSecret.ToString(Network.Main): {privateKeyFromBitcoinSecret.ToString(Network.Main)}");
            //L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo is for Alice
            //KxMrK5EJeUZ1z3Jyo2zPkurRVtYFefab4WQitV5CyjKApHsWfWg9 is for Bob
            //KyStsAHgSehHvewS5YfGwhQGfEWYd8qY2XZg6q2M6TqaM8Q8rayg is for Satoshi
            //L2f9Ntm8UUeTLZFv25oZ8WoRW8kAofUjdUdtCq9axCp1hZrsLZja is for Nico

            BitcoinSecret bitcoinSecretForAlice   = new BitcoinSecret("L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo", Network.Main);
            BitcoinSecret bitcoinSecretForBob     = new BitcoinSecret("KxMrK5EJeUZ1z3Jyo2zPkurRVtYFefab4WQitV5CyjKApHsWfWg9", Network.Main);
            BitcoinSecret bitcoinSecretForSatoshi = new BitcoinSecret("KyStsAHgSehHvewS5YfGwhQGfEWYd8qY2XZg6q2M6TqaM8Q8rayg", Network.Main);
            BitcoinSecret bitcoinSecretForScanKey = new BitcoinSecret("L2f9Ntm8UUeTLZFv25oZ8WoRW8kAofUjdUdtCq9axCp1hZrsLZja", Network.Main);


            Key bobPrivateKey        = bitcoinSecretForAlice.PrivateKey;
            Key alicePrivateKey      = bitcoinSecretForBob.PrivateKey;
            Key satoshiPrivateKey    = bitcoinSecretForSatoshi.PrivateKey;
            Key privateKeyForScanKey = bitcoinSecretForScanKey.PrivateKey;



            Script scriptPubKeyOfBobAlice =
                PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, bobPrivateKey.PubKey, alicePrivateKey.PubKey);

            //This transaction will send money to Bob and Alice.
            //The thing you should notice is that this transaction is added by various types of scriptPubKey, such as P2PK(bobPrivateKey.PubKey), P2PKH(alicePrivateKey.PubKey.Hash), and multi-sig ScriptPubKey(scriptPubKeyOfBobAlice).
            var txGettingCoinForBobAlice = new Transaction();

            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), bobPrivateKey.PubKey));        // P2PK
            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), alicePrivateKey.PubKey.Hash)); // P2PKH
            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), scriptPubKeyOfBobAlice));

            //Now let’s say they want to use the coins of this transaction to pay Satoshi.

            //First they have to get their coins.
            Coin[] coins = txGettingCoinForBobAlice.Outputs.AsCoins().ToArray();

            Coin bobCoin      = coins[0];
            Coin aliceCoin    = coins[1];
            Coin bobAliceCoin = coins[2];

            //Now let’s say Bob wants to send 0.2 BTC, Alice 0.3 BTC, and they agree to use bobAlice to send 0.5 BTC.
            //Build the transaction by using the features of the TransactionBuilder class.
            var         builderForSendingCoinToSatoshi = new TransactionBuilder();
            Transaction txForSpendingCoinToSatoshi     = builderForSendingCoinToSatoshi
                                                         .AddCoins(bobCoin)
                                                         //PriveteKey of Bob to be used for signing.
                                                         .AddKeys(bobPrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.2m))
                                                         .SetChange(bobPrivateKey)
                                                         .Then()
                                                         .AddCoins(aliceCoin)
                                                         .AddKeys(alicePrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.3m))
                                                         .SetChange(alicePrivateKey)
                                                         .Then()
                                                         .AddCoins(bobAliceCoin)
                                                         .AddKeys(bobPrivateKey, alicePrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.5m))
                                                         .SetChange(scriptPubKeyOfBobAlice)
                                                         .SendFees(Money.Coins(0.0001m))
                                                         .BuildTransaction(sign: true);

            Console.WriteLine(txForSpendingCoinToSatoshi);

            //Then you can verify it is fully signed and ready to send to the network.
            //Verify you did not screw up.
            Console.WriteLine(builderForSendingCoinToSatoshi.Verify(txForSpendingCoinToSatoshi)); // True



            //============================================================================================
            //Do with a ScriptCoin.

            //The nice thing about this model is that it works the same way for P2SH, P2WSH, P2SH(P2WSH), and P2SH(P2PKH) except you need to create ScriptCoin.

            //Illustration:
            //Coin-> ScriptCoin <-RedeemScript.

            var txGettingScriptCoinForBobAlice = new Transaction();

            txGettingScriptCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1.0m), scriptPubKeyOfBobAlice.Hash));

            coins = txGettingScriptCoinForBobAlice.Outputs.AsCoins().ToArray();
            ScriptCoin bobAliceScriptCoin = coins[0].ToScriptCoin(scriptPubKeyOfBobAlice);

            //Then the signature:
            var builderForSendingScriptCoinToSatoshi = new TransactionBuilder();
            var txForSendingScriptCoinToSatoshi      = builderForSendingScriptCoinToSatoshi
                                                       .AddCoins(bobAliceScriptCoin)
                                                       .AddKeys(bobPrivateKey, alicePrivateKey)
                                                       .Send(satoshiPrivateKey, Money.Coins(0.9m))
                                                       .SetChange(scriptPubKeyOfBobAlice.Hash)
                                                       .SendFees(Money.Coins(0.0001m))
                                                       .BuildTransaction(true);

            Console.WriteLine(builderForSendingScriptCoinToSatoshi.Verify(txForSendingScriptCoinToSatoshi));
            //Output:
            //True


            //============================================================================================
            //Do with a StealthCoin.

            //For Stealth Coin, this is basically the same thing except that, if you remember our introduction on Dark Wallet, you need a ScanKey to see the StealthCoin.

            //Illustration:
            //ScanKey + Transaction + StealthAddress => StealthCoin.

            //Let’s create darkAliceBob stealth address as in previous chapter:


            BitcoinStealthAddress bitcoinStealthAddressForBobAlice =
                new BitcoinStealthAddress
                (
                    scanKey: privateKeyForScanKey.PubKey,
                    pubKeys: new[] { alicePrivateKey.PubKey, bobPrivateKey.PubKey },
                    signatureCount: 2,
                    bitfield: null,
                    network: Network.Main
                );


            //Let’s say someone sent the coin to this transaction via the darkAliceBob which is a BitcoinStealthAddress:
            var txGettingCoinForBobAliceToBitcoinStealthAddress = new Transaction();

            bitcoinStealthAddressForBobAlice
            .SendTo(txGettingCoinForBobAliceToBitcoinStealthAddress, Money.Coins(1.0m));

            //The scanner will detect the StealthCoin:
            //Get the stealth coin with the scanKey.
            StealthCoin stealthCoin
                = StealthCoin.Find(txGettingCoinForBobAliceToBitcoinStealthAddress, bitcoinStealthAddressForBobAlice, privateKeyForScanKey);

            //And forward it to Bob and Alice, who will sign:
            //Let Bob and Alice sign and spend the coin.
            TransactionBuilder builderForBobAliceToBitcoinStealthAddress = new TransactionBuilder();

            txGettingCoinForBobAliceToBitcoinStealthAddress = builderForBobAliceToBitcoinStealthAddress
                                                              .AddCoins(stealthCoin)
                                                              .AddKeys(bobPrivateKey, alicePrivateKey, privateKeyForScanKey)
                                                              .Send(satoshiPrivateKey, Money.Coins(0.9m))
                                                              .SetChange(scriptPubKeyOfBobAlice.Hash)
                                                              .SendFees(Money.Coins(0.0001m))
                                                              .BuildTransaction(true);
            Console.WriteLine(builderForBobAliceToBitcoinStealthAddress.Verify(txGettingCoinForBobAliceToBitcoinStealthAddress));
            //Output:
            //True

            //Note: You need the scanKey for spending a StealthCoin
        }
示例#34
0
		public void CanBuildWitTransaction()
		{
			Key alice = new Key();
			Key bob = new Key();
			Transaction previousTx = null;
			Coin previousCoin = null;
			WitScriptCoin witnessCoin = null;
			TransactionBuilder builder = null;
			Transaction signedTx = null;
			ScriptCoin scriptCoin = null;

			//P2WPKH
			previousTx = new Transaction();
			previousTx.Outputs.Add(new TxOut(Money.Coins(1.0m), alice.PubKey.WitHash));
			previousCoin = previousTx.Outputs.AsCoins().First();

			builder = new TransactionBuilder();
			builder.AddKeys(alice);
			builder.AddCoins(previousCoin);
			builder.Send(bob, Money.Coins(0.4m));
			builder.SendFees(Money.Satoshis(30000));
			builder.SetChange(alice);
			signedTx = builder.BuildTransaction(true);
			Assert.True(builder.Verify(signedTx));

			//P2WSH
			previousTx = new Transaction();
			previousTx.Outputs.Add(new TxOut(Money.Coins(1.0m), alice.PubKey.ScriptPubKey.WitHash));
			previousCoin = previousTx.Outputs.AsCoins().First();

			witnessCoin = new WitScriptCoin(previousCoin, alice.PubKey.ScriptPubKey);
			builder = new TransactionBuilder();
			builder.AddKeys(alice);
			builder.AddCoins(witnessCoin);
			builder.Send(bob, Money.Coins(0.4m));
			builder.SendFees(Money.Satoshis(30000));
			builder.SetChange(alice);
			signedTx = builder.BuildTransaction(true);
			Assert.True(builder.Verify(signedTx));


			//P2SH(P2WPKH)
			previousTx = new Transaction();
			previousTx.Outputs.Add(new TxOut(Money.Coins(1.0m), alice.PubKey.WitHash.ScriptPubKey.Hash));
			previousCoin = previousTx.Outputs.AsCoins().First();

			scriptCoin = new ScriptCoin(previousCoin, alice.PubKey.WitHash.ScriptPubKey);
			builder = new TransactionBuilder();
			builder.AddKeys(alice);
			builder.AddCoins(scriptCoin);
			builder.Send(bob, Money.Coins(0.4m));
			builder.SendFees(Money.Satoshis(30000));
			builder.SetChange(alice);
			signedTx = builder.BuildTransaction(true);
			Assert.True(builder.Verify(signedTx));

			//P2SH(P2WSH)
			previousTx = new Transaction();
			previousTx.Outputs.Add(new TxOut(Money.Coins(1.0m), alice.PubKey.ScriptPubKey.WitHash.ScriptPubKey.Hash));
			previousCoin = previousTx.Outputs.AsCoins().First();

			witnessCoin = new WitScriptCoin(previousCoin, alice.PubKey.ScriptPubKey);
			builder = new TransactionBuilder();
			builder.AddKeys(alice);
			builder.AddCoins(witnessCoin);
			builder.Send(bob, Money.Coins(0.4m));
			builder.SendFees(Money.Satoshis(30000));
			builder.SetChange(alice);
			signedTx = builder.BuildTransaction(true);
			Assert.True(builder.Verify(signedTx));

			//Can remove witness data from tx
			var signedTx2 = signedTx.WithOptions(TransactionOptions.None);
			Assert.Equal(signedTx.GetHash(), signedTx2.GetHash());
			Assert.True(signedTx2.GetSerializedSize() < signedTx.GetSerializedSize());
		}