Add license header.
[NovacoinLibrary.git] / Novacoin / CTransaction.cs
1 \feff/**
2  *  Novacoin classes library
3  *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
4
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 using System;
20 using System.Text;
21 using System.Collections.Generic;
22
23 namespace Novacoin
24 {
25     /// <summary>
26     /// Represents the transaction. Any transaction must provide one input and one output at least.
27     /// </summary>
28     public class CTransaction
29     {
30         /// <summary>
31         /// Version of transaction schema.
32         /// </summary>
33         public uint nVersion = 1;
34
35         /// <summary>
36         /// Transaction timestamp.
37         /// </summary>
38         public uint nTime = 0;
39
40         /// <summary>
41         /// Array of transaction inputs
42         /// </summary>
43         public CTxIn[] vin;
44
45         /// <summary>
46         /// Array of transaction outputs
47         /// </summary>
48         public CTxOut[] vout;
49
50         /// <summary>
51         /// Block height or timestamp when transaction is final
52         /// </summary>
53         public uint nLockTime = 0;
54
55         /// <summary>
56         /// Initialize an empty instance
57         /// </summary>
58         public CTransaction()
59         {
60             // Initialize empty input and output arrays. Please note that such 
61             // configuration is not valid for real transaction, you have to supply 
62             // at least one input and one output.
63             vin = new CTxIn[0];
64             vout = new CTxOut[0];
65         }
66
67         /// <summary>
68         /// Initialize new instance as a copy of another transaction
69         /// </summary>
70         /// <param name="tx">Transaction to copy from</param>
71         public CTransaction(CTransaction tx)
72         {
73             nVersion = tx.nVersion;
74             nTime = tx.nTime;
75
76             vin = new CTxIn[tx.vin.Length];
77
78             for (int i = 0; i < vin.Length; i++)
79             {
80                 vin[i] = new CTxIn(tx.vin[i]);
81             }
82
83             vout = new CTxOut[tx.vout.Length];
84
85             for (int i = 0; i < vout.Length; i++)
86             {
87                 vout[i] = new CTxOut(tx.vout[i]);
88             }
89
90             nLockTime = tx.nLockTime;
91         }
92
93
94         /// <summary>
95         /// Parse byte sequence and initialize new instance of CTransaction
96         /// </summary>
97         /// <param name="txBytes">Byte sequence</param>
98                 public CTransaction(IList<byte> txBytes)
99         {
100             ByteQueue wBytes = new ByteQueue(txBytes);
101
102             nVersion = BitConverter.ToUInt32(wBytes.Get(4), 0);
103             nTime = BitConverter.ToUInt32(wBytes.Get(4), 0);
104
105             int nInputs = (int)(int)wBytes.GetVarInt();
106             vin = new CTxIn[nInputs];
107
108             for (int nCurrentInput = 0; nCurrentInput < nInputs; nCurrentInput++)
109             {
110                 // Fill inputs array
111                 vin[nCurrentInput] = new CTxIn();
112                 
113                 vin[nCurrentInput].prevout = new COutPoint(wBytes.Get(36));
114
115                 int nScriptSigLen = (int)wBytes.GetVarInt();
116                 vin[nCurrentInput].scriptSig = new CScript(wBytes.Get(nScriptSigLen));
117
118                 vin[nCurrentInput].nSequence = BitConverter.ToUInt32(wBytes.Get(4), 0);
119             }
120
121             int nOutputs = (int)wBytes.GetVarInt();
122             vout = new CTxOut[nOutputs];
123
124             for (int nCurrentOutput = 0; nCurrentOutput < nOutputs; nCurrentOutput++)
125             {
126                 // Fill outputs array
127                 vout[nCurrentOutput] = new CTxOut();
128                 vout[nCurrentOutput].nValue = BitConverter.ToInt64(wBytes.Get(8), 0);
129
130                 int nScriptPKLen = (int)wBytes.GetVarInt();
131                 vout[nCurrentOutput].scriptPubKey = new CScript(wBytes.Get(nScriptPKLen));
132             }
133
134             nLockTime = BitConverter.ToUInt32(wBytes.Get(4), 0);
135         }
136
137         /// <summary>
138         /// Read transactions array which is encoded in the block body.
139         /// </summary>
140         /// <param name="wTxBytes">Bytes sequence</param>
141         /// <returns>Transactions array</returns>
142         public static CTransaction[] ReadTransactionsList(ref ByteQueue wTxBytes)
143         {
144             CTransaction[] tx;
145
146             // Read amount of transactions
147             int nTransactions = (int)wTxBytes.GetVarInt();
148             tx = new CTransaction[nTransactions];
149
150             for (int nTx = 0; nTx < nTransactions; nTx++)
151             {
152                 // Fill the transactions array
153                 tx[nTx] = new CTransaction();
154
155                 tx[nTx].nVersion = BitConverter.ToUInt32(wTxBytes.Get(4), 0);
156                 tx[nTx].nTime = BitConverter.ToUInt32(wTxBytes.Get(4), 0);
157
158                 // Inputs array
159                 tx[nTx].vin = CTxIn.ReadTxInList(ref wTxBytes);
160
161                 // outputs array
162                 tx[nTx].vout = CTxOut.ReadTxOutList(ref wTxBytes);
163
164                 tx[nTx].nLockTime = BitConverter.ToUInt32(wTxBytes.Get(4), 0);
165             }
166
167             return tx;
168         }
169
170         public bool IsCoinBase
171         {
172             get { return (vin.Length == 1 && vin[0].prevout.IsNull && vout.Length >= 1); }
173         }
174
175         public bool IsCoinStake
176         {
177             get
178             {
179                 return (vin.Length > 0 && (!vin[0].prevout.IsNull) && vout.Length >= 2 && vout[0].IsEmpty);
180             }
181         }
182
183         /// <summary>
184         /// Transaction hash
185         /// </summary>
186         public Hash256 Hash
187         {
188             get { return Hash256.Compute256(Bytes); }
189         }
190
191         /// <summary>
192         /// A sequence of bytes, which corresponds to the current state of CTransaction.
193         /// </summary>
194         public IList<byte> Bytes
195         {
196             get
197             {
198                 List<byte> resultBytes = new List<byte>();
199
200                 // Typical transaction example:
201                 //
202                 // 01000000 -- version
203                 // 78b4c953 -- timestamp
204                 // 06       -- amount of txins
205                 // 340d96b77ec4ee9d42b31cadc2fab911e48d48c36274d516f226d5e85bbc512c -- txin hash
206                 // 01000000 -- txin outnumber
207                 // 6b       -- txin scriptSig length
208                 // 483045022100c8df1fc17b6ea1355a39b92146ec67b3b53565e636e028010d3a8a87f6f805f202203888b9b74df03c3960773f2a81b2dfd1efb08bb036a8f3600bd24d5ed694cd5a0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4c -- txin scriptSig
209                 // ffffffff -- txin nSequence
210                 // 364c640420de8fa77313475970bf09ce4d0b1f8eabb8f1d6ea49d90c85b202ee -- txin hash
211                 // 01000000 -- txin outnumber
212                 // 6b       -- txin scriptSig length
213                 // 483045022100b651bf3a6835d714d2c990c742136d769258d0170c9aac24803b986050a8655b0220623651077ff14b0a9d61e30e30f2c15352f70491096f0ec655ae1c79a44e53aa0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4c -- txin scriptSig
214                 // ffffffff -- txin nSequence
215                 // 7adbd5f2e521f567bfea2cb63e65d55e66c83563fe253464b75184a5e462043d -- txin hash
216                 // 00000000 -- txin outnumber
217                 // 6a       -- txin scriptSig length
218                 // 4730440220183609f2b995993acc9df241aff722d48b9a731b0cd376212934565723ed81f00220737e7ce75ef39bdc061d0dcdba3ee24e43b899696a7c96803cee0a79e1f78ecb0121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4c -- txin scriptSig
219                 // ffffffff -- txin nSequence
220                 // 999eb03e00a41c2f9fde8865a554ceebbc48d30f4c8ba22dd88da8c9b46fa920 -- txin hash
221                 // 03000000 -- txin outnumber
222                 // 6b       -- txin scriptSig length
223                 // 483045022100ec1ab104ef086ba79b0f2611ebf1bfdd22a7a1020f6630fa1c6707546626e0db022056093d4048a999392185ccc735ef736a5497bd68f60b42e6c0c93ba770b54d010121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4c -- txin scriptSig
224                 // ffffffff -- txin nSequence
225                 // c0543b86be257ddd85b014a76718a70fab9eaa3c477460e4ca187094d86f369c -- txin hash
226                 // 05000000 -- txin outnumber
227                 // 69       -- txin scriptSig length
228                 // 463043021f24275c72f952043174daf01d7f713f878625f0522124a3cab48a0a2e12604202201b47742e6697b0ebdd1e4ba49c74baf142a0228ad0e0ee847488994c9dce78470121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4c -- txin scriptSig
229                 // ffffffff -- txin nSequence
230                 // e1793d4519147782293dd1db6d90e461265d91db2cc6889c37209394d42ad10d -- txin hash
231                 // 05000000 -- txin outnumber
232                 // 6a       -- txin scriptSig length
233                 // 473044022018a0c3d73b2765d75380614ab36ee8e3c937080894a19166128b1e3357b208fb0220233c9609985f535547381431526867ad0255ec4969afe5c360544992ed6b3ed60121030dd13e6d3c63fa10cc0b6bf968fbbfcb9a988b333813b1f22d04fa60e344bc4c -- txin scriptSig
234                 // ffffffff -- txin nSequence
235                 // 02 -- amount of txouts
236                 // e542000000000000 -- txout value
237                 // 19 -- scriptPubKey length
238                 // 76a91457d84c814b14bd86bf32f106b733baa693db7dc788ac -- scriptPubKey
239                 // 409c000000000000 -- txout value
240                 // 19 -- scriptPubKey length
241                 // 76a91408c8768d5d6bf7c1d9609da4e766c3f1752247b188ac -- scriptPubKey
242                 // 00000000 -- lock time
243
244                 resultBytes.AddRange(BitConverter.GetBytes(nVersion));
245                 resultBytes.AddRange(BitConverter.GetBytes(nTime));
246                 resultBytes.AddRange(VarInt.EncodeVarInt(vin.LongLength));
247
248                 foreach (CTxIn input in vin)
249                 {
250                     resultBytes.AddRange(input.Bytes);
251                 }
252
253                 resultBytes.AddRange(VarInt.EncodeVarInt(vout.LongLength));
254
255                 foreach (CTxOut output in vout)
256                 {
257                     resultBytes.AddRange(output.Bytes);
258                 }
259
260                 resultBytes.AddRange(BitConverter.GetBytes(nLockTime));
261
262                 return resultBytes;
263             }
264         }
265
266         public override string ToString()
267         {
268             StringBuilder sb = new StringBuilder();
269
270             sb.AppendFormat("CTransaction(\n nVersion={0},\n nTime={1},\n", nVersion, nTime);
271
272             foreach (CTxIn txin in vin)
273             {
274                 sb.AppendFormat(" {0},\n", txin.ToString());
275             }
276
277             foreach (CTxOut txout in vout)
278             {
279                 sb.AppendFormat(" {0},\n", txout.ToString());
280             }
281
282             sb.AppendFormat("\nnLockTime={0}\n)", nLockTime);
283
284             return sb.ToString();
285         }
286         }
287 }