Ejemplo n.º 1
0
        /// <summary>
        /// Create the signing bag with matching scripts and private keys
        /// Then sign the inputs.
        /// </summary>
        public Transaction Sign(CoinParameters parameters, SignRawTransaction rawTransactions)
        {
            var transaction = this.Serializer.FromHex(rawTransactions.RawTransactionHex);
            var bag         = new TransactionSigner.SignerBag {
                Items = new List <TransactionSigner.RedeemScript>()
            };
            var keys = rawTransactions.PrivateKeys.Select(s => new BitcoinPrivateKey(parameters, s)).ToList();

            // create a linked object between the pub key hash and its outpoint
            var inputs = rawTransactions.Inputs
                         .Select(input => new { Input = input, PubKeyHash = new Script.Script(CryptoUtil.ConvertHex(input.ScriptPubKey)).TryGetPubKeyHash() })
                         .Where(p => p.PubKeyHash.IsNotNull()).ToList();

            // compare private keys with redeem script pub key hash and add to the bag
            foreach (var key in keys)
            {
                // there should be at least one redeem script per private key
                var inserts = inputs.Where(f => f.PubKeyHash.SequenceEqual(key.Hash160)).ToList();
                Thrower.If(inserts.None()).Throw <TransactionException>("Private key had no matching redeem script '{0}'".StringFormat(key.PublicKey.ToAddress(parameters).ToString()));
                inserts.ForEach(insert => bag.Add(insert.Input.TransactionId, insert.Input.Output, insert.Input.ScriptPubKey, key));
            }

            this.Signer.SignInputs(transaction, bag);

            return(transaction);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// The create a pay to pub key hash transaction.
        /// </summary>
        public virtual Transaction CreatePubKeyHashTransaction(CoinParameters parameters, CreateRawTransaction rawTransaction)
        {
            var transaction = new Transaction
            {
                Version   = parameters.TransactionVersion,
                Locktime  = 0,
                Timestamp = (int)DateTime.UtcNow.UnixTimeStampFromDateTime()
            };

            // create the inputs
            transaction.Inputs = rawTransaction.Inputs
                                 .Select(input => new TransactionInput
            {
                Outpoint = new TransactionOutPoint
                {
                    Hash  = input.TransactionId,
                    Index = input.Output
                },
                ScriptBytes = Enumerable.Empty <byte>().ToArray(),

                Sequence = 0xffffffff     // uint.MaxValue
            }).ToList();

            // create the output
            transaction.Outputs = rawTransaction.Outputs
                                  .Select((output, index) => new TransactionOutput
            {
                Index       = index,
                Value       = this.Serializer.ValueToNum(output.Value),
                ScriptBytes = ScriptBuilder.CreateOutputScript(Address.Create(parameters, output.Key)).GetProgram()
            }).ToList();

            return(transaction);
        }
Ejemplo n.º 3
0
        public void Given_a_signed_transaction_with_multipul_inputs_When_serialized_to_hex_Then_is_valid()
        {
            var param = new CoinParameters {
                CoinTag = "BTC", PublicKeyAddressVersion = 0, PrivateKeyVersion = 128
            };
            var builder = TransactionBuilder.Create(param);

            var key1 = new BitcoinPrivateKey(param, "KxSFAwxgg1kh2CKqmVGDJfQBKypAabiJ7UgDbJcvnRQ3ccbCm8oz");
            var key2 = new BitcoinPrivateKey(param, "KwgcwLEWhzpcWvZtEJuYiPk4BJHNtGhp1tdqL2wKt1xe4Kv8kVd5");

            var create = builder.CreateTransaction()
                         .AddInput("2a99b070f457c8f2f6cb0f818b951c2038759af7abd98e57aecaf73989cd3474", 1)
                         .AddInput("2a99b070f457c8f2f6cb0f818b951c2038759af7abd98e57aecaf73989cd3474", 0)
                         .AddOutput("19vrUuKgwKvAhiXfwVBaeHDQo7wMJg4VjD", 0.00020000M)
                         .AddOutput("1227pgTWYNsPNVN647NzsceFeXeLt18fTT", 0.00005000M);
            var trx      = builder.CreatePubKeyHashTransaction(param, create);
            var unsigned = builder.Serializer.ToHex(trx);

            var sign = builder.CreateSignature(unsigned)
                       .AddKey(key1.ToWifKey(param))
                       .AddKey(key2.ToWifKey(param))
                       .AddInput("2a99b070f457c8f2f6cb0f818b951c2038759af7abd98e57aecaf73989cd3474", 0,
                                 "76a914a92c9ee052cdcb7ac955b179d5d5553aa1aed28f88ac")
                       .AddInput("2a99b070f457c8f2f6cb0f818b951c2038759af7abd98e57aecaf73989cd3474", 1,
                                 "76a914c789d0b3ec2bee3b2e057e2b759d1bd249095cd888ac");

            trx = builder.Sign(param, sign);
            var signed = builder.Serializer.ToHex(trx);

            Assert.AreEqual("01000000027434cd8939f7caae578ed9abf79a7538201c958b810fcbf6f2c857f470b0992a010000006b483045022100b8642683528bce3b71911e970b045c05309035e410c7d7b3ff4def78958fe8670220148eb4bf6b07aa32b74c1041dc1c98b6646d68c3f4001b7e7683abd705ec4c3101210396c9b0b5664c28c4667e9931a9665a7d99222794b3a1d514e3dd198c2cc688e0ffffffff7434cd8939f7caae578ed9abf79a7538201c958b810fcbf6f2c857f470b0992a000000006b48304502210083099361f7feca8003687bb1a5454447846adec11b23e9760cc0c96273fcd39202207894c09e8744b266dfac87dcf0e6aedb848caf4aa451b285a14dc6fc041b6a1a012102b5d6110585425f5af0eaf84262e3962477d7974f97ed5ead5bd25a1eb415c40dffffffff02204e0000000000001976a91461f05b61eb47be1d96e417272d3d3d3c346e2e9188ac88130000000000001976a9140b2e3c8cfae581f5fa526070a705e617d3c61be488ac00000000", signed);
        }
Ejemplo n.º 4
0
        public void Given_a_signed_transaction_When_serialized_to_hex_Then_is_valid()
        {
            var param = new CoinParameters {
                CoinTag = "BTC", PublicKeyAddressVersion = 0, PrivateKeyVersion = 128
            };
            var builder = TransactionBuilder.Create(param);

            var prv         = "KxSFAwxgg1kh2CKqmVGDJfQBKypAabiJ7UgDbJcvnRQ3ccbCm8oz";
            var key         = new BitcoinPrivateKey(param, prv);
            var destination = Address.Create(param, "19vrUuKgwKvAhiXfwVBaeHDQo7wMJg4VjD");
            var change      = Address.Create(param, "1KC4ZkESbdjYVfdYWuAkmSscQfD1VEWb32");

            var create = new CreateRawTransaction()
                         .AddInput("9e779dbc84fe9c4082bc6fff332ddee81a6f56908720f25cb83ea9441cfa801b", 0)
                         .AddOutput(destination.ToString(), 0.00010000M)
                         .AddOutput(change.ToString(), 0.00030000M);
            var trx      = builder.CreatePubKeyHashTransaction(param, create);
            var unsigned = builder.Serializer.ToHex(trx);

            var sign = new SignRawTransaction(unsigned)
                       .AddKey(key.ToWifKey(param))
                       .AddInput("9e779dbc84fe9c4082bc6fff332ddee81a6f56908720f25cb83ea9441cfa801b",
                                 0,
                                 "76a914c789d0b3ec2bee3b2e057e2b759d1bd249095cd888ac");

            trx = builder.Sign(param, sign);
            var signed = builder.Serializer.ToHex(trx);

            Assert.AreEqual("01000000011b80fa1c44a93eb85cf2208790566f1ae8de2d33ff6fbc82409cfe84bc9d779e000000006b483045022100911e4ffada078f43c792b797b0d864a519cb088083b89003810aaf28325a6ecd02207f2e9790511710ae93309f4b3b30c0379b8917b6a0fb1cdcc9c711fc6f1831ef01210396c9b0b5664c28c4667e9931a9665a7d99222794b3a1d514e3dd198c2cc688e0ffffffff0210270000000000001976a91461f05b61eb47be1d96e417272d3d3d3c346e2e9188ac30750000000000001976a914c789d0b3ec2bee3b2e057e2b759d1bd249095cd888ac00000000", signed);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BitcoinPrivateKey"/> class.
        /// Parses the given private key as created by the BitCoin C++ RPC.
        /// </summary>
        /// <param name="coinParameters">
        /// The expected header parameters of the key. If you don't care, provide null.
        /// </param>
        /// <param name="encoded">
        /// The base58 encoded string.
        /// </param>
        public BitcoinPrivateKey(CoinParameters coinParameters, string encoded)
        {
            var decoded = Base58Encoding.DecodeWithCheckSum(encoded);
            var version = decoded.First();

            Thrower.Condition <ArgumentException>(coinParameters.PrivateKeyVersion != version, string.Format("Mismatched version number, trying to cross networks? expected={0} found={1}", coinParameters.PrivateKeyVersion, version));

            var bytes = decoded.Skip(1).ToArray();

            this.Compressed = false;

            if (bytes.Length == 33)
            {
                // private key associated with a compressed public key
                Thrower.Condition <ArgumentException>(bytes.Last() != CompressedBytes.First(), string.Format("Invalid private key"));

                bytes           = bytes.Take(32).ToArray();
                this.Compressed = true;
            }

            // 256 bit keys
            Thrower.Condition <ArgumentException>(bytes.Length != Length, string.Format("Keys are 256 bits, so you must provide {0} bytes, got {1}", Length, bytes.Length));

            this.Bytes = bytes;
        }
Ejemplo n.º 6
0
 public CoinService(bool useTestNet, string daemonUrl, string rpcUsername, string rpcPassword, string walletPassword, short rpcRequestTimeoutInSeconds)
 {
     _rpcConnector = new RpcConnector(this);
     Parameters    = new CoinParameters(this, daemonUrl, rpcUsername, rpcPassword, walletPassword, rpcRequestTimeoutInSeconds);
     Parameters.DaemonUrlTestnet = daemonUrl;
     Parameters.UseTestnet       = useTestNet;
 }
Ejemplo n.º 7
0
 /// <summary>
 /// Create a bitcoin address from a public key RIPEMD160 hash and specify if it is a Script or a Pub key
 /// </summary>
 public static Address Create(CoinParameters coinParameters, byte[] hash160, bool isScript)
 {
     return(new Address
     {
         Hash160 = hash160,
         CoinParameters = coinParameters,
         AddressVersion = isScript ?
                          coinParameters.ScriptAddressVersion :
                          coinParameters.PublicKeyAddressVersion
     });
 }
Ejemplo n.º 8
0
        public void Given_an_rpc_transaction_with_big_inputs_When_deserialized_to_hex_Then_is_successfully_compared()
        {
            // A json transaction as it's returned by the rpc method
            var param = new CoinParameters {
                CoinTag = "BTC", PublicKeyAddressVersion = 0, PrivateKeyVersion = 128
            };
            var builder        = TransactionBuilder.Create(param);
            var BigTransaction = File.OpenText(@"..\..\Resources\BigTransaction.json").ReadToEnd();
            var trx            = JsonSerializer.DeSerialize <DecodedRawTransaction>(BigTransaction);
            var rawTransaction = builder.Serializer.ToHex(builder.Parse(trx));

            Assert.AreEqual(trx.Hex, rawTransaction);
        }
Ejemplo n.º 9
0
        public void Given_an_rpc_coinbase_transaction_When_deserialized_from_hex_Then_is_successfully_compared()
        {
            // A json transaction as it's returned by the rpc method
            var param = new CoinParameters {
                CoinTag = "BTC", PublicKeyAddressVersion = 0, PrivateKeyVersion = 128
            };
            var builder = TransactionBuilder.Create(param);
            var jsonCoinbaseTransaction = File.OpenText(@"..\..\Resources\CoinbaseTransaction.json").ReadToEnd();
            var trx = JsonSerializer.DeSerialize <DecodedRawTransaction>(jsonCoinbaseTransaction);

            var decoded = builder.Serializer.FromHex(trx.Hex);

            CompareTransactions(decoded, builder.Parse(trx));
        }
Ejemplo n.º 10
0
        public void Given_an_unsigned_transaction_When_serialized_to_hex_Then_is_valid()
        {
            var param = new CoinParameters {
                CoinTag = "BTC", PublicKeyAddressVersion = 0, PrivateKeyVersion = 128
            };
            var builder = TransactionBuilder.Create(param);

            var create = new CreateRawTransaction()
                         .AddInput("9e779dbc84fe9c4082bc6fff332ddee81a6f56908720f25cb83ea9441cfa801b", 0)
                         .AddOutput("19vrUuKgwKvAhiXfwVBaeHDQo7wMJg4VjD", 0.00010000M)
                         .AddOutput("1KC4ZkESbdjYVfdYWuAkmSscQfD1VEWb32", 0.00030000M);
            var trx      = builder.CreatePubKeyHashTransaction(param, create);
            var unsigned = builder.Serializer.ToHex(trx);

            Assert.AreEqual("01000000011b80fa1c44a93eb85cf2208790566f1ae8de2d33ff6fbc82409cfe84bc9d779e0000000000ffffffff0210270000000000001976a91461f05b61eb47be1d96e417272d3d3d3c346e2e9188ac30750000000000001976a914c789d0b3ec2bee3b2e057e2b759d1bd249095cd888ac00000000", unsigned);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Create a bitcoin address from an imported string.
        /// </summary>
        public static Address Create(CoinParameters coinParameters, string address)
        {
            var decoded = Base58Encoding.DecodeWithCheckSum(address);
            var version = decoded.First();
            var hash    = decoded.Skip(1).ToArray();

            Thrower.If(hash.Length != Length).Throw <AddressException>("Invalid length? expected={0} found={1}", Length, hash.Length);
            Thrower.If(
                version != coinParameters.PublicKeyAddressVersion &&
                version != coinParameters.ScriptAddressVersion)
            .Throw <AddressException>("Mismatched version number, trying to cross networks? expected={0},{1} found={2}", coinParameters.PublicKeyAddressVersion, coinParameters.ScriptAddressVersion, version);

            return(new Address {
                Hash160 = hash, CoinParameters = coinParameters, AddressVersion = version
            });
        }
Ejemplo n.º 12
0
        public void Given_an_unsigned_transaction_with_multipul_inputs_When_serialized_to_hex_Then_is_valid()
        {
            var param = new CoinParameters {
                CoinTag = "BTC", PublicKeyAddressVersion = 0, PrivateKeyVersion = 128
            };
            var builder = TransactionBuilder.Create(param);

            var create = new CreateRawTransaction()
                         .AddInput("2a99b070f457c8f2f6cb0f818b951c2038759af7abd98e57aecaf73989cd3474", 1)
                         .AddInput("2a99b070f457c8f2f6cb0f818b951c2038759af7abd98e57aecaf73989cd3474", 0)
                         .AddOutput("19vrUuKgwKvAhiXfwVBaeHDQo7wMJg4VjD", 0.00020000M)
                         .AddOutput("1227pgTWYNsPNVN647NzsceFeXeLt18fTT", 0.00005000M);
            var trx      = builder.CreatePubKeyHashTransaction(param, create);
            var unsigned = builder.Serializer.ToHex(trx);

            Assert.AreEqual("01000000027434cd8939f7caae578ed9abf79a7538201c958b810fcbf6f2c857f470b0992a0100000000ffffffff7434cd8939f7caae578ed9abf79a7538201c958b810fcbf6f2c857f470b0992a0000000000ffffffff02204e0000000000001976a91461f05b61eb47be1d96e417272d3d3d3c346e2e9188ac88130000000000001976a9140b2e3c8cfae581f5fa526070a705e617d3c61be488ac00000000", unsigned);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Import the private key to a wallet import format.
        /// </summary>
        /// <param name="coinParameters">
        /// The coin network to import to.
        /// </param>
        public string ToWifKey(CoinParameters coinParameters)
        {
            Guard.Require(coinParameters.PrivateKeyVersion < 256 && coinParameters.PrivateKeyVersion >= 0, "PrivateKeyVersion");
            Guard.Require(this.HasPrivateKey, "HasPrivateKey");

            var key = this.Bytes;
            var version = new[] { (byte)coinParameters.PrivateKeyVersion }.ToArray();

            key = version.Concat(key).ToArray();

            if (this.PrivateKey.Key.Compressed)
            {
                // compressed public keys so we append the zero to the private key
                key = key.Concat(CompressedBytes).ToArray();
            }

            return(Base58Encoding.EncodeWithCheckSum(key));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// </summary>
        /// <param name="test">
        /// </param>
        private static void RunTest(TestVector test)
        {
            var constHash = "Bitcoin seed".Select(Convert.ToByte).ToArray();

            var headers = new CoinParameters {
                PublicKeyAddressVersion = 0, PrivateKeyVersion = 128
            };

            var seed   = CryptoUtil.ConvertHex(test.strHexMaster);
            var key    = ExtendedKey.Create(constHash, seed);
            var pubkey = key.GetPublicKey();

            foreach (var derive in test.vDerive)
            {
                var skey    = key.Serialize();
                var spubkey = pubkey.Serialize();

                Guard.Require(skey == derive.prv);
                Guard.Require(spubkey == derive.pub);

                var pkey    = ExtendedKey.Parse(derive.prv);
                var ppubkey = ExtendedKey.Parse(derive.pub);

                var wif1 = pkey.GetKey(1).PrivateKey.ToWifKey(headers);
                var wif2 = key.GetKey(1).PrivateKey.ToWifKey(headers);
                Guard.Require(wif1 == wif2);

                var addr1 = ppubkey.GetKey(1).PublicKey.ToAddress(headers);
                var addr2 = pubkey.GetKey(1).ToAddress(headers);
                Guard.Require(addr1.ToString() == addr2.ToString());

                key = key.GetChild(derive.nChild);
                if ((derive.nChild & 0x80000000) == 0)
                {
                    var pubkeyn = pubkey.GetChild(derive.nChild);
                    pubkey = key.GetPublicKey();
                    Guard.Require(pubkey.Master.ToAddress(headers).ToString() == pubkeyn.Master.ToAddress(headers).ToString());
                }
                else
                {
                    pubkey = key.GetPublicKey();
                }
            }
        }
Ejemplo n.º 15
0
 public Address GetToAddress(CoinParameters param, bool forcePayToPubKey)
 {
     if (this.IsSentToAddress())
     {
         return(Address.Create(param, this.GetPubKeyHash()));
     }
     else if (this.IsPayToScriptHash())
     {
         return(Address.Create(param, this.GetPubKeyHash()));
     }
     else if (forcePayToPubKey && this.IsSentToRawPubKey())
     {
         return(new BitcoinPublicKey(this.GetPubKey()).ToAddress(param));
     }
     else
     {
         throw new ScriptException("Cannot cast this script to a pay-to-address type");
     }
 }
Ejemplo n.º 16
0
        /// <summary>
        /// This method does some final operation on the context
        /// </summary>
        /// <param name="coinParameters">The coinParameters.</param>
        /// <param name="previousRawTransactions">The transaction to modify.</param>
        private static void GridcoinHack(CoinParameters coinParameters, List <DecodedRawTransaction> previousRawTransactions)
        {
            if (coinParameters.CoinTag == "GRC")
            {
                //// for some reason the GRC client will not return the HEX of an output
                //// pars the raw transaction and populate the HEX from there
                //// this will be fixed in the next release of the Gridcoin client
                //// see git issue and pull request https://github.com/gridcoin/Gridcoin-Research/issues/86#issuecomment-218024574

                previousRawTransactions.ForEach(trx =>
                {
                    var cloned = TransactionBuilder.Create(coinParameters).Serializer.FromHex(trx.Hex);

                    trx.VOut.ForEach(output =>
                    {
                        output.ScriptPubKey.Hex = CryptoUtil.ToHex(cloned.Outputs.ElementAt(output.N).ScriptBytes);
                    });
                });
            }
        }
Ejemplo n.º 17
0
        public override Transaction CreatePubKeyHashTransaction(CoinParameters parameters, CreateRawTransaction rawTransaction)
        {
            var transaction = base.CreatePubKeyHashTransaction(parameters, rawTransaction);

            var changePointer = transaction.Inputs.SingleOrDefault(p => p.Outpoint.Index == -1);

            if (changePointer == null)
            {
                return(transaction);
            }

            var rawChangeOutput         = rawTransaction.Outputs.Single(p => p.Key == changePointer.Outpoint.Hash);
            var changeOutputScriptBytes = ScriptBuilder
                                          .CreateOutputScript(Address.Create(parameters, rawChangeOutput.Key)).GetProgram();

            changePointer.Outpoint.Index =
                transaction.Outputs.Single(p => p.ScriptBytes == changeOutputScriptBytes).Index;
            changePointer.Outpoint.Hash = "0";

            return(transaction);
        }
Ejemplo n.º 18
0
        public void Given_an_unsigned_timestamped_transaction_with_multipul_inputs_When_serialized_to_hex_Then_is_valid()
        {
            var param = new CoinParameters {
                CoinTag = "PPC", PublicKeyAddressVersion = 55, PrivateKeyVersion = 183
            };
            var builder = TransactionBuilder.Create(param);

            var create = new CreateRawTransaction()
                         .AddInput("c41e47d99557b2c25e72ee3c6bacf9796b09791cda5ea654225621701a2bc87d", 1)
                         .AddInput("32b137d72a26681fa4ac1de3cab1cdcf05e0fd592b0a1cd81a3bd35000dfddf4", 1)
                         .AddInput("69a3b97a4207eb7da766b9a29862acae00d3f3e00965d3b31f879abae1a58a50", 0)
                         .AddOutput("PXCfHLaR2RCMnHsYCAtSoyjwBkhaniC9Ty", 1.10000000M)
                         .AddOutput("PXDHGy2j11atyPoqyNZfccwS46gv6K4BkL", 20.82399100M)
                         .AddOutput("PEBAEAM6R7SZkhQmvHa7eBfCNfTCE5CGYT", 1.40000000M)
                         .AddOutput("PFj9YzkCRiihArX46KM9kZappnWa5svFhe", 2.53000000M);
            var trx = builder.CreatePubKeyHashTransaction(param, create);

            trx.Timestamp = 1461838729; // specific to this transaction
            var unsigned = builder.Serializer.ToHex(trx);

            Assert.AreEqual("0100000089e32157037dc82b1a7021562254a65eda1c79096b79f9ac6b3cee725ec2b25795d9471ec40100000000fffffffff4dddf0050d33b1ad81c0a2b59fde005cfcdb1cae31daca41f68262ad737b1320100000000ffffffff508aa5e1ba9a871fb3d36509e0f3d300aeac6298a2b966a77deb07427ab9a3690000000000ffffffff04e0c81000000000001976a914f808ce1d1a2c111581237f65931e8ae56d6cbfd088acb7bf3d01000000001976a914f826d9dfd3b0dfdacf09ea6cc7d48c9569ace1b288acc05c1500000000001976a9143d45ff4529a9326804aa1fe2800e55418c00604c88acd09a2600000000001976a9144e4adeb9f14731d0370b10cff700e12c36571b7e88ac00000000", unsigned);
        }
Ejemplo n.º 19
0
        public void Given_a_signed_timestamped_transaction_with_multipul_inputs_When_serialized_to_hex_Then_is_valid()
        {
            var param = new CoinParameters {
                CoinTag = "PPC", PublicKeyAddressVersion = 55, PrivateKeyVersion = 183
            };
            var builder = TransactionBuilder.Create(param);

            var key1 = new BitcoinPrivateKey(param, "79rzXNEtHfWJQxPUHJpMLnuuLKD9NnJAFeYVYtus2JjyXcKkCQ1");
            var key2 = new BitcoinPrivateKey(param, "7Ab1bFhaW5oC1LN7AgaHKr9ZZGumLSxThq8qMP3iP1oJYwAW2Kq");

            var create = new CreateRawTransaction()
                         .AddInput("c41e47d99557b2c25e72ee3c6bacf9796b09791cda5ea654225621701a2bc87d", 1)
                         .AddInput("32b137d72a26681fa4ac1de3cab1cdcf05e0fd592b0a1cd81a3bd35000dfddf4", 1)
                         .AddInput("69a3b97a4207eb7da766b9a29862acae00d3f3e00965d3b31f879abae1a58a50", 0)
                         .AddOutput("PXCfHLaR2RCMnHsYCAtSoyjwBkhaniC9Ty", 1.10000000M)
                         .AddOutput("PXDHGy2j11atyPoqyNZfccwS46gv6K4BkL", 20.82399100M)
                         .AddOutput("PEBAEAM6R7SZkhQmvHa7eBfCNfTCE5CGYT", 1.40000000M)
                         .AddOutput("PFj9YzkCRiihArX46KM9kZappnWa5svFhe", 2.53000000M);
            var trx = builder.CreatePubKeyHashTransaction(param, create);

            trx.Timestamp = 1461838729; // specific to this transaction
            var unsigned = builder.Serializer.ToHex(trx);

            var sign = builder.CreateSignature(unsigned)
                       .AddKey(key1.ToWifKey(param))
                       .AddKey(key2.ToWifKey(param))
                       .AddInput("c41e47d99557b2c25e72ee3c6bacf9796b09791cda5ea654225621701a2bc87d", 1,
                                 "76a914f826d9dfd3b0dfdacf09ea6cc7d48c9569ace1b288ac")
                       .AddInput("32b137d72a26681fa4ac1de3cab1cdcf05e0fd592b0a1cd81a3bd35000dfddf4", 1,
                                 "76a9144e4adeb9f14731d0370b10cff700e12c36571b7e88ac")
                       .AddInput("69a3b97a4207eb7da766b9a29862acae00d3f3e00965d3b31f879abae1a58a50", 0,
                                 "76a9144e4adeb9f14731d0370b10cff700e12c36571b7e88ac");

            trx = builder.Sign(param, sign);
            var signed = builder.Serializer.ToHex(trx);

            Assert.AreEqual("0100000089e32157037dc82b1a7021562254a65eda1c79096b79f9ac6b3cee725ec2b25795d9471ec4010000008a47304402200cf6263646697a3e90114ead2d461c56a26cb22c3758c1aa3bdd4d1e2d8461ba022048d1c17cc00ab21177a14bcac61fcc990969e1b855c1cdc9ede503af56d924410141042cfdbfaee53942b2c8d9c67631e099e604e6e4e01594394942f33fa237eca310ac0aa79189d96c79e9e764826243614ebdfd400680421dff54314d9eabb87daafffffffff4dddf0050d33b1ad81c0a2b59fde005cfcdb1cae31daca41f68262ad737b132010000008b483045022100c867962f5c584897e5231e45d06065e4bc9dbf26ea4bcbc6de3ceebe87791ade02205c8b016d84a38a25275d89da8f6435016313e1d108f15638609e791570fbd8a10141040c65817203cc55de4c2ab32413497fd9e917a5c1d4711e7772a7277f491d3dc50879852e697a2551547c5d8e28a0a97280e8e63d4590a9c722ce2a84c6d71f3affffffff508aa5e1ba9a871fb3d36509e0f3d300aeac6298a2b966a77deb07427ab9a369000000008b4830450221008d55d7eb528622f4d803c0756f11e49fd6b3206789d6603e9f3221a3473cda18022002663afafc52cc4c3a5bc9c16401d13a853f2e0b4b258c923ec3c18e85aeab100141040c65817203cc55de4c2ab32413497fd9e917a5c1d4711e7772a7277f491d3dc50879852e697a2551547c5d8e28a0a97280e8e63d4590a9c722ce2a84c6d71f3affffffff04e0c81000000000001976a914f808ce1d1a2c111581237f65931e8ae56d6cbfd088acb7bf3d01000000001976a914f826d9dfd3b0dfdacf09ea6cc7d48c9569ace1b288acc05c1500000000001976a9143d45ff4529a9326804aa1fe2800e55418c00604c88acd09a2600000000001976a9144e4adeb9f14731d0370b10cff700e12c36571b7e88ac00000000", signed);
        }
Ejemplo n.º 20
0
 public CoinService()
 {
     _rpcConnector = new RpcConnector(this);
     Parameters    = new CoinParameters(this, null, null, null, null, 0);
 }
Ejemplo n.º 21
0
 /// <summary>
 /// Initializes a new instance of the <see cref="TransactionSigner"/> class.
 /// </summary>
 public TransactionSigner(CoinParameters coinParameters, TransactionSerializer serializer)
 {
     this.CoinParameters = coinParameters;
     this.Serializer     = serializer;
 }
Ejemplo n.º 22
0
        /// <summary>
        /// Create a transaction builder for a given coin.
        /// Some other Blockchain coins have different serializes of network parameters,
        /// this is calculated when creating the builder.
        /// </summary>
        public static TransactionBuilder Create(CoinParameters param)
        {
            AddressUtil.PopulateCoinParameters(param);

            // todo: move factory selector in a configuration file
            var lst = new List <string>
            {
                "BTC", "TRC", "GRC", "DOGE", "DASH", "RDD", "XPM", "LTC", "NMC",
                "QRK", "PPC", "MTR", "GB", "SHM", "CRX", "UBIQ", "ARG", "ZYD", "DLC",
                "STRAT", "SH"
            };

            if (lst.Contains(param.CoinTag))
            {
                var ser = new TransactionSerializer(param);
                // coin scale can be found in util.h (static const int64_t COIN = 100000000)
                param.CoinScale          = 100000000;
                param.TransactionVersion = 1;

                if (param.CoinTag == "QRK")
                {
                    param.CoinScale = 100000;
                }

                if (param.CoinTag == "PPC")
                {
                    param.CoinScale = 1000000;
                    ser             = new TransactionSerializerTimeStamped(param);
                }

                if (param.CoinTag == "GRC")
                {
                    ser = new TransactionSerializerGridcoin(param);
                }

                if (param.CoinTag == "RDD")
                {
                    param.TransactionVersion = 2;
                    ser = new TransactionSerializerReddcoin(param);
                }

                if (param.CoinTag == "MTR")
                {
                    ser = new TransactionSerializerTimeStamped(param);
                }

                if (param.CoinTag == "GB")
                {
                    ser = new TransactionSerializerTimeStamped(param);
                }

                if (param.CoinTag == "SHM")
                {
                    ser = new TransactionSerializerTimeStamped(param);
                }

                if (param.CoinTag == "CRX")
                {
                    ser = new TransactionSerializerTimeStamped(param);
                }

                if (param.CoinTag == "UBIQ")
                {
                    ser = new TransactionSerializerTimeStamped(param);
                }

                if (param.CoinTag == "STRAT")
                {
                    ser = new TransactionSerializerTimeStamped(param);
                }

                if (param.CoinTag == "DST")
                {
                    ser = new TransactionSerializerTimeStamped(param);
                    return(new DeStreamTransactionBuilder(param, ser, new TransactionSigner(param, ser)));
                }

                var builder = new TransactionBuilder(param, ser, new TransactionSigner(param, ser));

                return(builder);
            }

            return(new TransactionBuilderClient());
        }
Ejemplo n.º 23
0
 protected TransactionBuilder(CoinParameters param, TransactionSerializer serializer, TransactionSigner signer)
 {
     this.CoinParameters = param;
     this.Serializer     = serializer;
     this.Signer         = signer;
 }
Ejemplo n.º 24
0
 public DeStreamTransactionBuilder(CoinParameters param, TransactionSerializer serializer, TransactionSigner signer) : base(param, serializer, signer)
 {
 }
Ejemplo n.º 25
0
 public CoinService(string daemonUrl, string rpcUsername, string rpcPassword, string walletPassword)
 {
     _rpcConnector = new RpcConnector(this);
     Parameters = new CoinParameters(this, daemonUrl, rpcUsername, rpcPassword, walletPassword, 0);
 }
Ejemplo n.º 26
0
 //  this provides support for cases where *.config files are not an option
 public CoinService(String daemonUrl, String rpcUsername, String rpcPassword, String walletPassword, Int16 rpcRequestTimeoutInSeconds)
 {
     _rpcConnector = new RpcConnector(this);
     Parameters    = new CoinParameters(this, daemonUrl, rpcUsername, rpcPassword, walletPassword, rpcRequestTimeoutInSeconds);
 }
Ejemplo n.º 27
0
 /// <summary>
 /// The create.
 /// </summary>
 /// <param name="headers">
 /// The headers.
 /// </param>
 /// <returns>
 /// The <see cref="ReceiveInfo"/>.
 /// </returns>
 public BitcoinPrivateKey GetKey(CoinParameters headers)
 {
     return(new BitcoinPrivateKey(headers, this.PrivateKey));
 }
Ejemplo n.º 28
0
        /// <summary>
        ///  Create a transaction.
        /// This allows to create a transaction using the private keys,
        /// This means we don't need to open the wallet to send the transaction and all the handling of open wallet synchronization is not required.
        /// </summary>
        public static async Task <TransactionContext> CreateAsync(CoinParameters param, IBitcoinClient client, IEnumerable <TransactionInfo> items)
        {
            if (string.Equals(param.CoinTag, "DST"))
            {
                return(await CreateDeStreamAsync(param, client, items));
            }

            var context = new TransactionContext
            {
                CoinParameters          = param,
                PreviousRawTransactions = new List <DecodedRawTransaction>(),
                CreateRawTransaction    = new CreateRawTransaction(),
                SendItems = new List <TransactionInfo>()
            };

            foreach (var item in items)
            {
                context.SendItems.Add(item);

                // check if receiving address is already in the transaction, this is allowed but not supported by the client.
                if (item.SpendToAddresses.Select(s => s.PublicKey)
                    .Intersect(item.SpendFromAddresses.Select(s => s.PublicKey)).Any())
                {
                    item.Fail(false, FailedReason.CannotSendToSelfUnlessChange);
                    continue;
                }

                if (item.SpendFromAddresses.SelectMany(s => s.Transactions).None())
                {
                    item.Fail(false, FailedReason.NoTransactionsFound);
                    continue;
                }

                // check if a transaction is already in use
                if (context.CreateRawTransaction.Inputs.
                    Any(source => item.SpendFromAddresses.SelectMany(s => s.Transactions)
                        .Any(target => source.TransactionId == target.Hash && source.Output == target.Index)))
                {
                    item.Fail(true, FailedReason.TransactionInputAlreadyInUse);
                    continue;
                }

                // check if receiving address is already in the transaction, this is allowed but not supported by the client.
                if (context.CreateRawTransaction.Outputs
                    .Any(source => item.SpendToAddresses.Any(target => source.Key == target.PublicKey)))
                {
                    item.Fail(true, FailedReason.ReceiveAddressAlreadyInOutput);
                    continue;
                }

                if (item.RequestedFee <= 0)
                {
                    item.Fail(false, FailedReason.FeeCannotBeZero);
                    continue;
                }

                ////try
                ////{
                ////    var rawTrxListAsync = item.SpendFromAddresses
                ////        .SelectMany(s => s.Transactions)
                ////        .DistinctBy(t => t.Hash)
                ////        .Where(a => context.PreviousRawTransactions.None(b => b.TxId == a.Hash))
                ////        .Select(async trx => await client.GetRawTransactionAsync(trx.Hash, 1));

                ////    var previousRawTransactions = (await Task.WhenAll(rawTrxListAsync)).ToList();
                ////    context.PreviousRawTransactions.AddRange(previousRawTransactions);

                ////    // the Gridcoin hack
                ////    GridcoinHack(context.CoinParameters, previousRawTransactions);
                ////}
                ////catch (Exception)
                ////{
                ////    item.Fail(false, FailedReason.FailedReadingTransactionsFromClient);
                ////    continue;
                ////}

                // validate all the transaction outpoints have the ScriptPubKey Hex
                ////item.SpendFromAddresses.ForEach(spend =>
                ////    spend.Transactions.ForEach(strx =>
                ////    {
                ////        var output = context.PreviousRawTransactions
                ////            .Where(t => t.TxId == strx.Hash)
                ////            .SelectMany(s => s.VOut)
                ////            .SingleOrDefault(v => v.N == strx.Index);

                ////        if (output.IsNotNull() && output.Value == strx.Value)
                ////        {
                ////            if (output.ScriptPubKey.IsNotNull())
                ////            {
                ////                if (output.ScriptPubKey.Addresses.Any(addr => addr == spend.PublicKey))
                ////                {
                ////                    strx.ScriptPubKeyHex = output.ScriptPubKey.Hex;
                ////                }
                ////            }
                ////        }
                ////    }));

                if (item.SpendFromAddresses.SelectMany(s => s.Transactions).Any(t => t.ScriptPubKeyHex.IsNullOrEmpty()))
                {
                    item.Fail(false, FailedReason.ScriptPubKeyHexNotFound);
                    continue;
                }

                //// get the outputs associated with the sender address
                var spendToEnumerated   = item.SpendToAddresses.ToList();
                var spendFromEnumerated = item.SpendFromAddresses.SelectMany(s => s.Transactions).ToList();
                ////var outputs = previousRawTransactions
                ////    .ToDictionary(rawtrx => rawtrx.TxId, rawtrx => rawtrx.VOut
                ////        .Where(vout => vout.ScriptPubKey.Addresses
                ////            .Any(add => item.SpendFromAddresses.Any(a => a.PublicKey == add))));

                //// calculate the sum of inputs and outputs.
                var inputSum  = spendFromEnumerated.Select(t => t.Value).Sum();
                var outputSum = spendToEnumerated.Select(spt => spt.Amount).Sum();

                var change = inputSum - outputSum;

                if (change < 0)
                {
                    item.Fail(false, FailedReason.InvalidSum);
                    continue;
                }

                if (item.SpendToAddresses.Any(s => s.TakeFee))
                {
                    //// take the fee from a receiver address.
                    var receiver = item.SpendToAddresses.First(s => s.TakeFee);

                    if (receiver.Amount < item.RequestedFee)
                    {
                        item.Fail(false, FailedReason.InsufficientFeeOnReceiver);
                        continue;
                    }

                    receiver.Amount -= item.RequestedFee;
                }
                else
                {
                    //// take the fee from the sender
                    if (change < item.RequestedFee)
                    {
                        item.Fail(false, FailedReason.InsufficientFeeOnSender);
                        continue;
                    }

                    change -= item.RequestedFee;
                }

                if (change > 0)
                {
                    if (item.ChangeAddress.IsNullOrEmpty())
                    {
                        item.Fail(false, FailedReason.NoChangeAddressFound);
                        continue;
                    }
                }

                // try to calculate the fee if trx is too big the default fee may not be enough
                // http://bitcoin.stackexchange.com/questions/7537/calculator-for-estimated-tx-fees
                // https://en.bitcoin.it/wiki/Transaction_fees
                // http://bitcoin.stackexchange.com/questions/3400/what-is-the-exact-formula-for-calculating-transaction-fees
                // http://bitcoin.stackexchange.com/questions/1195/how-to-calculate-transaction-size-before-sending
                // formula fee = [Normal fee * (500 KB) / (500KB - Block size)] - [Normal fee / (1 - Block size / 500KB)]
                // trx size = [in*148 + out*34 + 10 plus or minus 'in']

                //// TODO: move this code to a facotry to allow calculation of fee per coin
                //// coins have different block sizes sand this needs to be acocunted for as well

                var ins      = spendFromEnumerated.Count();
                var outs     = spendToEnumerated.Count();
                var sizeByte = Convert.ToDecimal((ins * 148) + (outs * 34) + 10 + (ins / 2));

                // we'll calculate roughly the coin fee times size of transaction
                const decimal AvgSizeBytes = 1000;
                if (sizeByte >= AvgSizeBytes)
                {
                    var feeRatio    = sizeByte / AvgSizeBytes;
                    var expectedFee = feeRatio * item.CoinFee;

                    if (expectedFee > item.RequestedFee)
                    {
                        item.Fail(false, FailedReason.InsufficientFeeForTransactionSize);
                        continue;
                    }
                }

                spendFromEnumerated.ForEach(vout => context.CreateRawTransaction.AddInput(vout.Hash, (int)vout.Index));
                spendToEnumerated.ForEach(spt => context.CreateRawTransaction.AddOutput(spt.PublicKey, spt.Amount));

                if (change > 0)
                {
                    context.CreateRawTransaction.AddOutput(item.ChangeAddress, change);
                }
            }

            if (context.SendItems.All(w => w.Failed))
            {
                return(context);
            }

            //// create the builder and build the transaction (either a client using the coins client or locally if supported).
            await TransactionBuilder.Create(param).Build(client, context);

            // seems we are done here
            return(context);
        }
Ejemplo n.º 29
0
        private static async Task <TransactionContext> CreateDeStreamAsync(CoinParameters param, IBitcoinClient client,
                                                                           IEnumerable <TransactionInfo> items)
        {
            const decimal feeRate = (decimal)0.0077;

            var context = new TransactionContext
            {
                CoinParameters          = param,
                PreviousRawTransactions = new List <DecodedRawTransaction>(),
                CreateRawTransaction    = new CreateRawTransaction(),
                SendItems = new List <TransactionInfo>()
            };

            foreach (var item in items)
            {
                context.SendItems.Add(item);

                // check if receiving address is already in the transaction, this is allowed but not supported by the client.
                if (item.SpendToAddresses.Select(s => s.PublicKey)
                    .Intersect(item.SpendFromAddresses.Select(s => s.PublicKey)).Any())
                {
                    item.Fail(false, FailedReason.CannotSendToSelfUnlessChange);
                    continue;
                }

                if (item.SpendFromAddresses.SelectMany(s => s.Transactions).None())
                {
                    item.Fail(false, FailedReason.NoTransactionsFound);
                    continue;
                }

                // check if a transaction is already in use
                if (context.CreateRawTransaction.Inputs.Any(source => item.SpendFromAddresses
                                                            .SelectMany(s => s.Transactions)
                                                            .Any(target => source.TransactionId == target.Hash && source.Output == target.Index)))
                {
                    item.Fail(true, FailedReason.TransactionInputAlreadyInUse);
                    continue;
                }

                // check if receiving address is already in the transaction, this is allowed but not supported by the client.
                if (context.CreateRawTransaction.Outputs
                    .Any(source => item.SpendToAddresses.Any(target => source.Key == target.PublicKey)))
                {
                    item.Fail(true, FailedReason.ReceiveAddressAlreadyInOutput);
                    continue;
                }

                if (item.SpendFromAddresses.SelectMany(s => s.Transactions).Any(t => t.ScriptPubKeyHex.IsNullOrEmpty()))
                {
                    item.Fail(false, FailedReason.ScriptPubKeyHexNotFound);
                    continue;
                }

                //// get the outputs associated with the sender address
                var spendToEnumerated   = item.SpendToAddresses.ToList();
                var spendFromEnumerated = item.SpendFromAddresses.SelectMany(s => s.Transactions).ToList();

                //// calculate the sum of inputs and outputs.
                var inputSum  = spendFromEnumerated.Select(t => t.Value).Sum();
                var outputSum = spendToEnumerated.Select(spt => spt.Amount).Sum();

                var change = inputSum - outputSum;

                if (change < 0)
                {
                    item.Fail(false, FailedReason.InvalidSum);
                    continue;
                }

                if (item.SpendToAddresses.Any(s => s.TakeFee))
                {
                    item.SpendToAddresses.First(s => s.TakeFee).Amount /= decimal.One + feeRate;
                }
                else
                {
                    change -= outputSum * feeRate;
                }

                if (change > 0)
                {
                    if (item.ChangeAddress.IsNullOrEmpty())
                    {
                        item.Fail(false, FailedReason.NoChangeAddressFound);
                        continue;
                    }
                }

                spendFromEnumerated.ForEach(vout => context.CreateRawTransaction.AddInput(vout.Hash, (int)vout.Index));
                spendToEnumerated.ForEach(spt => context.CreateRawTransaction.AddOutput(spt.PublicKey, spt.Amount));

                if (change > 0)
                {
                    context.CreateRawTransaction.AddOutput(item.ChangeAddress, change);
                    context.CreateRawTransaction.AddInput(item.ChangeAddress, -1);
                }
            }

            if (context.SendItems.All(w => w.Failed))
            {
                return(context);
            }

            //// create the builder and build the transaction (either a client using the coins client or locally if supported).
            await TransactionBuilder.Create(param).Build(client, context);

            // seems we are done here
            return(context);
        }
Ejemplo n.º 30
0
 public CoinService()
 {
     _rpcConnector = new RpcConnector(this);
     Parameters = new CoinParameters(this);
 }
Ejemplo n.º 31
0
 public CoinService(string daemonUrl, string rpcUsername, string rpcPassword, string walletPassword)
 {
     Parameters    = new CoinParameters(this, daemonUrl, rpcUsername, rpcPassword, walletPassword, 0);
     _rpcConnector = new RpcConnector(this);
 }
Ejemplo n.º 32
0
 //  this provides support for cases where *.config files are not an option
 public CoinService(string daemonUrl, string rpcUsername, string rpcPassword, string walletPassword, short rpcRequestTimeoutInSeconds)
 {
     Parameters    = new CoinParameters(this, daemonUrl, rpcUsername, rpcPassword, walletPassword, rpcRequestTimeoutInSeconds);
     _rpcConnector = new RpcConnector(this);
 }
Ejemplo n.º 33
0
 //  this provides support for cases where *.config files are not an option
 public CoinService(string daemonUrl, string rpcUsername, string rpcPassword, string walletPassword, short rpcRequestTimeoutInSeconds)
 {
     _rpcConnector = new RpcConnector(this);
     Parameters = new CoinParameters(this, daemonUrl, rpcUsername, rpcPassword, walletPassword, rpcRequestTimeoutInSeconds);
 }