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();
}
}
}