예제 #1
0
        public void CreateAddressTest()
        {
            //values came form brainwallet.org.  use that to confirm
            const String PRIVATE_KEY_AS_DEC2 = "56264673822963068407370790525340191907437491654303176136090258467429147271236";
            const String SOURCE_ADDRESS_2    = "1GKMJp7NGBv9a8eY8nuK31yXgoe6e8DDAz";
            const String PRIVATE_KEY_AS_HEX2 = "7c64ad461b06168990ea5902eb2e054b3a1324be28d7335f05ab7cebca7ce044";
            const String WIF_2 = "5Jm53JsNg72iix4PdChqyxvDuQXMfGuMsALY98VdeQWCsDikxYn";

            DC.Common.Models.Address source = new DC.Common.Models.Address(PRIVATE_KEY_AS_DEC2);

            Assert.IsTrue(source.BTCAddress == SOURCE_ADDRESS_2);
            Assert.IsTrue(source.PrivateKeyAsHex == PRIVATE_KEY_AS_HEX2);
            Assert.IsTrue(source.WifPrivateKey == WIF_2);
        }
예제 #2
0
        public Transaction(IList <DC.Common.Models.UnspentOutput> outputsToSpend, DC.Common.Models.Address sourceAddress, String destinationAddress, String destinationHash160, Decimal amount, Decimal fee = 0.0001M)
        {
            //Amount to send + miners fee
            Int64 sum = (outputsToSpend.Sum(o => o.Value));

            if (sum > 0)
            {
                _change = sum - Convert.ToInt64(amount * DC.Common.Math.SATOSHI) - Convert.ToInt64(fee * DC.Common.Math.SATOSHI);

                //CHANGE
                this.Change = DC.Common.Math.GetValueAsBytes(_change);
                this.Value  = DC.Common.Math.GetValueAsBytes(amount);

                _outputsToSpend = outputsToSpend;
            }
            else
            {
                throw new ArgumentNullException("No spendable outputs");
            }
        }
예제 #3
0
        public void TransactionConstructorTest()
        {
            IList <DC.Common.Models.UnspentOutput> outputsToSpend = new List <DC.Common.Models.UnspentOutput>();

            outputsToSpend.Add(new DC.Common.Models.UnspentOutput()
            {
                Value = 10000
            });
            outputsToSpend.Add(new DC.Common.Models.UnspentOutput()
            {
                Value = 20000
            });

            const String PRIVATE_KEY_AS_DEC2 = "56264673822963068407370790525340191907437491654303176136090258467429147271236";

            DC.Common.Models.Address    source = new DC.Common.Models.Address(PRIVATE_KEY_AS_DEC2);
            DC.Node.Helpers.Transaction t      = new DC.Node.Helpers.Transaction(outputsToSpend, source, "1DugongACGcyyvvgvcy8skYyezsx5jy3aV", "fakehash", 0.001M, 0.0001M);

            //CHANGE SHOULD BE 8000
            //Assert.AreEqual(t.Change, null);
            Assert.Inconclusive();
        }
예제 #4
0
        public byte[] CreateAndSignTransaction(DC.Common.Models.Address sourceAddress, String destinationAddress, String destinationHash160, Decimal amount, Decimal fee = 0.0001M)
        {
            if (!DC.Common.BitcoinHelper.IsValidAddress(destinationAddress))
            {
                throw new ArgumentException("Destination address is not valid");
            }

            List <Byte[]> signedOutPuts = new List <byte[]>(_outputsToSpend.Count);

            //Loop each output to sign
            for (Int32 i = 0; i < _outputsToSpend.Count; i++)
            {
                //1
                Byte[] version = this.Version;
                Debug.Assert(version[0] == 1);
                Debug.Assert(version.Length == 4);

                //2
                Byte[] tx_fields = version.Concat(this.NumTxIn);
                Debug.Assert(tx_fields.Length == 5);

                //Write out each input
                for (Int32 j = 0; j < _outputsToSpend.Count; j++)
                {
                    //THIS IS HASH OF THE TRANSACTION THAT CONTAINS THE UNSPENT OUTPUT
                    //NB, ALREADY REVERSED!

                    //3
                    Byte[] prevout_hash = DC.Common.StringHelper.HexStringToByte(_outputsToSpend[j].TxHash);
                    tx_fields = tx_fields.Concat(prevout_hash);

                    //4 (index 0)
                    //4 BYTE ARRAY, WITH PREVIOUS INDEX EG 01 00 00 00
                    Byte[] output_index = _outputsToSpend[j].OutputIndexAsBytes;
                    Debug.Assert(output_index.Length == 4);

                    tx_fields = tx_fields.Concat(output_index);

                    if (i == j)
                    {
                        //SWAP.  NB WE HAVE THE SCRYPT, JUST CONVERT TO BYTES
                        Byte[] previousOutputScript = _outputsToSpend[j].ScryptAsBytes;

                        Byte previousOutputScriptLength = Convert.ToByte(previousOutputScript.Length);
                        tx_fields = tx_fields.Concat(previousOutputScriptLength);
                        tx_fields = tx_fields.Concat(previousOutputScript);
                    }
                    else
                    {
                        Byte zeroScript = Convert.ToByte(0);
                        tx_fields = tx_fields.Concat(zeroScript);
                    }

                    //7
                    tx_fields = tx_fields.Concat(this.Sequence);
                }


                //8 number of outputs to send
                tx_fields = tx_fields.Concat(this.NumTxOut);

                //9 amount to send
                tx_fields = tx_fields.Concat(this.Value);

                //10
                //The script in the old transaction is called scriptPubKey
                //http://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx
                Byte[] outputScriptPubKey = DC.Common.Script.CreateScriptPubKey(destinationHash160);

                Byte outputScriptLen = Convert.ToByte(outputScriptPubKey.Length);
                tx_fields = tx_fields.Concat(outputScriptLen);
                tx_fields = tx_fields.Concat(outputScriptPubKey);

                if (_change > 0)
                {
                    //CHANGE amount
                    tx_fields = tx_fields.Concat(this.Change);

                    //http://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx
                    Byte[] changeScriptPubKey = DC.Common.Script.CreateScriptPubKey(sourceAddress.PublicKeyHash160); //SELF

                    Byte changeScriptLen = Convert.ToByte(changeScriptPubKey.Length);
                    tx_fields = tx_fields.Concat(changeScriptLen);
                    tx_fields = tx_fields.Concat(changeScriptPubKey);
                    //END CHANGE
                }

                //12
                tx_fields = tx_fields.Concat(this.LockTime);

                //13
                tx_fields = tx_fields.Concat(this.HashType);

                //DOUBLE HASH
                Byte[] hash_scriptless = Crypto.DoubleSHA256(tx_fields);

                //SIGN DATA
                Byte[] sig_data = Crypto.Sign(hash_scriptless, sourceAddress.d, DC.Common.Crypto.GetDomainParams());
                sig_data = sig_data.Concat(Convert.ToByte(1));

                //NOW WE HAVE TO APPEND
                //16.We construct the final scriptSig by concatenating:
                //<One-byte script OPCODE containing the length of the DER-encoded signature plus the one-byte hash code type>
                //|< The actual DER-encoded signature plus the one-byte hash code type>
                //|< One-byte script OPCODE containing the length of the public key>
                //|<The actual public key>

                //Byte[] final_signed = new Byte[1];
                //final_signed[0] = Convert.ToByte(sig_data.Length);
                //final_signed = final_signed.Concat(sig_data);

                //Byte[] pub_key2 = StringHelper.HexStringToByte(destinationHash160);
                //final_signed = final_signed.Concat(Convert.ToByte(pub_key2.Length));
                //final_signed = final_signed.Concat(pub_key2);
                //add to collection
                signedOutPuts.Add(sig_data);
            }

            //final_tx.write_int32(tx_fields['version'])
            //final_tx.write_compact_size(tx_fields['num_txin'])
            //final_tx.write(tx_fields['prevout_hash'])
            //final_tx.write_uint32(tx_fields['output_index'])
            Byte[] final_tx = this.Version;
            Debug.Assert(final_tx[0] == 1);
            Debug.Assert(final_tx.Length == 4);

            final_tx = final_tx.Concat(NumTxIn); //count
            Debug.Assert(final_tx.Length == 5);

            //Outputs to spend
            for (Int32 k = 0; k < _outputsToSpend.Count; k++)
            {
                //hash
                Byte[] previousTxHash = StringHelper.HexStringToByte(_outputsToSpend[k].TxHash);
                final_tx = final_tx.Concat(previousTxHash);

                //index
                Byte[] previousOutputIndex = _outputsToSpend[k].OutputIndexAsBytes;
                Debug.Assert(previousOutputIndex.Length == 4);
                final_tx = final_tx.Concat(previousOutputIndex);

                //add the signed data to the output.  nb,  this could be done in the other loop
                //new script legth
                //16.We construct the final scriptSig by concatenating:
                //<One-byte script OPCODE containing the length of the DER-encoded signature plus the one-byte hash code type>
                //|< The actual DER-encoded signature plus the one-byte hash code type>
                //|< One-byte script OPCODE containing the length of the public key>
                //|<The actual public key>
                Byte[] final_signed = new Byte[1];
                final_signed[0] = Convert.ToByte(signedOutPuts[k].Length);
                final_signed    = final_signed.Concat(signedOutPuts[k]);

                Byte[] pub_key = StringHelper.HexStringToByte(sourceAddress.PublicKeyAsHex);
                final_signed = final_signed.Concat(Convert.ToByte(pub_key.Length));
                final_signed = final_signed.Concat(pub_key);

                //add new signed tx
                final_tx = final_tx.Concat(Convert.ToByte(final_signed.Length));
                final_tx = final_tx.Concat(final_signed);
                final_tx = final_tx.Concat(this.Sequence);
            }

            //##and then we simply write the same data after the scriptSig that is in the signature-less transaction,
            //#  leaving out the four-byte hash code type (as this is encoded in the single byte following the signature data)

            //OUTPUTS
            final_tx = final_tx.Concat(this.NumTxOut);
            final_tx = final_tx.Concat(this.Value);

            Byte[] pub_key_script = DC.Common.Script.CreateScriptPubKey(destinationHash160);
            Byte[] scriptSigFinal = new Byte[1];
            scriptSigFinal[0] = Convert.ToByte(pub_key_script.Length); //Length pub key
            scriptSigFinal    = scriptSigFinal.Concat(pub_key_script); //pub key

            final_tx = final_tx.Concat(scriptSigFinal);

            if (_change > 0)
            {
                final_tx = final_tx.Concat(this.Change);
                Byte[] changeScriptPubKey = DC.Common.Script.CreateScriptPubKey(sourceAddress.PublicKeyHash160); //SELF
                final_tx = final_tx.Concat(Convert.ToByte(changeScriptPubKey.Length));
                final_tx = final_tx.Concat(changeScriptPubKey);
            }

            final_tx = final_tx.Concat(this.LockTime);

            return(final_tx);
        }