Use byte[] instead of IEnumerable<byte> if possible
[NovacoinLibrary.git] / Novacoin / CBlock.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 block. Block consists of header, transaction array and header signature.
27         /// </summary>
28         public class CBlock
29         {
30                 /// <summary>
31                 /// Block header.
32                 /// </summary>
33                 public CBlockHeader header;
34
35                 /// <summary>
36                 /// Transactions array.
37                 /// </summary>
38                 public CTransaction[] vtx;
39
40         /// <summary>
41         /// Block header signature.
42         /// </summary>
43         public byte[] signature = new byte[0];
44
45         public CBlock(CBlock b)
46         {
47             header = new CBlockHeader(b.header);
48
49             for (int i = 0; i < b.vtx.Length; i++)
50             {
51                 vtx[i] = new CTransaction(b.vtx[i]);
52             }
53
54             b.signature.CopyTo(signature, 0);
55         }
56
57         /// <summary>
58         /// Parse byte sequence and initialize new block instance
59         /// </summary>
60         /// <param name="blockBytes"></param>
61                 public CBlock (IList<byte> blockBytes)
62                 {
63             ByteQueue wBytes = new ByteQueue(blockBytes);
64
65             // Fill the block header fields
66             header = new CBlockHeader(wBytes.Get(80));
67
68             // Parse transactions list
69             vtx = CTransaction.ReadTransactionsList(ref wBytes);
70
71             // Read block signature
72             signature = wBytes.Get((int)wBytes.GetVarInt());
73                 }
74
75         public CBlock()
76         {
77             // Initialize empty array of transactions. Please note that such 
78             // configuration is not valid real block since it has to provide 
79             // at least one transaction.
80             vtx = new CTransaction[0];
81         }
82
83         /// <summary>
84         /// Is this a Proof-of-Stake block?
85         /// </summary>
86         public bool IsProofOfStake
87         {
88             get
89             {
90                 return (vtx.Length > 1 && vtx[1].IsCoinStake);
91             }
92         }
93
94         /// <summary>
95         /// Was this signed correctly?
96         /// </summary>
97         public bool SignatureOK
98         {
99             get
100             {
101                 if (IsProofOfStake)
102                 {
103                     if (signature.Length == 0)
104                     {
105                         return false; // No signature
106                     }
107
108                     txnouttype whichType;
109                     IList<byte[]> solutions;
110
111                     if (!ScriptCode.Solver(vtx[1].vout[1].scriptPubKey, out whichType, out solutions))
112                     {
113                         return false; // No solutions found
114                     }
115
116                     if (whichType == txnouttype.TX_PUBKEY)
117                     {
118                         CPubKey pubkey;
119
120                         try
121                         {
122                             pubkey = new CPubKey(solutions[0]);
123                         }
124                         catch (Exception)
125                         {
126                             return false; // Error while loading public key
127                         }
128
129                         return pubkey.VerifySignature(header.Hash, signature);
130                     }
131                 }
132                 else
133                 {
134                     // Proof-of-Work blocks have no signature
135
136                     return true;
137                 }
138
139                 return false;
140             }
141         }
142
143         /// <summary>
144         /// Get current instance as sequence of bytes
145         /// </summary>
146         /// <returns>Byte sequence</returns>
147         public IList<byte> Bytes 
148         {
149             get
150             {
151                 var r = new List<byte>();
152
153                 r.AddRange(header.Bytes);
154                 r.AddRange(VarInt.EncodeVarInt(vtx.LongLength)); // transactions count
155
156                 foreach (var tx in vtx)
157                 {
158                     r.AddRange(tx.Bytes);
159                 }
160
161                 r.AddRange(VarInt.EncodeVarInt(signature.LongLength));
162                 r.AddRange(signature);
163
164                 return r;
165             }
166         }
167
168         public override string ToString()
169         {
170             var sb = new StringBuilder();
171
172             sb.AppendFormat("CBlock(\n header={0},\n", header.ToString());
173
174             foreach(var tx in vtx)
175             {
176                 sb.AppendFormat("{0}", tx.ToString());
177             }
178
179             if (IsProofOfStake)
180             {
181                 sb.AppendFormat(", signature={0}, signatureOK={1}\n", Interop.ToHex(signature), SignatureOK);
182             }
183
184             sb.Append(")");
185             
186             return sb.ToString();
187         }
188         }
189 }
190