using System; using System.Text; using System.Collections.Generic; namespace Novacoin { /// /// Represents the block. Block consists of header, transaction array and header signature. /// public class CBlock { /// /// Block header. /// public CBlockHeader header; /// /// Transactions array. /// public CTransaction[] vtx; /// /// Block header signature. /// public byte[] signature = new byte[0]; public CBlock(CBlock b) { header = new CBlockHeader(b.header); for (int i = 0; i < b.vtx.Length; i++) { vtx[i] = new CTransaction(b.vtx[i]); } b.signature.CopyTo(signature, 0); } /// /// Parse byte sequence and initialize new block instance /// /// public CBlock (IList blockBytes) { ByteQueue wBytes = new ByteQueue(blockBytes); // Fill the block header fields header = new CBlockHeader(wBytes.Get(80)); // Parse transactions list vtx = CTransaction.ReadTransactionsList(ref wBytes); // Read block signature signature = wBytes.Get((int)wBytes.GetVarInt()); } public CBlock() { // Initialize empty array of transactions. Please note that such // configuration is not valid real block since it has to provide // at least one transaction. vtx = new CTransaction[0]; } /// /// Is this a Proof-of-Stake block? /// public bool IsProofOfStake { get { return (vtx.Length > 1 && vtx[1].IsCoinStake); } } /// /// Was this signed correctly? /// public bool SignatureOK { get { if (IsProofOfStake) { if (signature.Length == 0) { return false; // No signature } txnouttype whichType; IList> solutions; if (!ScriptCode.Solver(vtx[1].vout[1].scriptPubKey, out whichType, out solutions)) { return false; // No solutions found } if (whichType == txnouttype.TX_PUBKEY) { CPubKey pubkey; try { pubkey = new CPubKey(solutions[0]); } catch (Exception) { return false; // Error while loading public key } return pubkey.VerifySignature(header.Hash, signature); } } else { // Proof-of-Work blocks have no signature return true; } return false; } } /// /// Get current instance as sequence of bytes /// /// Byte sequence public IList Bytes { get { List r = new List(); r.AddRange(header.Bytes); r.AddRange(VarInt.EncodeVarInt(vtx.LongLength)); // transactions count foreach (CTransaction tx in vtx) { r.AddRange(tx.Bytes); } r.AddRange(VarInt.EncodeVarInt(signature.LongLength)); r.AddRange(signature); return r; } } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.AppendFormat("CBlock(\n header={0},\n", header.ToString()); foreach(CTransaction tx in vtx) { sb.AppendFormat("{0}", tx.ToString()); } if (IsProofOfStake) { sb.AppendFormat(", signature={0}, signatureOK={1}\n", Interop.ToHex(signature), SignatureOK); } sb.Append(")"); // TODO return sb.ToString(); } } }