Remove interfaces, split database objects into new file.
[NovacoinLibrary.git] / Novacoin / DatabaseObjects.cs
1 \feffusing SQLite.Net.Attributes;
2 using SQLiteNetExtensions.Attributes;
3 using System;
4 using System.IO;
5
6 namespace Novacoin
7 {
8     [Table("ChainState")]
9     public class ChainState
10     {
11         [PrimaryKey, AutoIncrement]
12         public long itemId { get; set; }
13
14         /// <summary>
15         /// Hash of top block in the best chain
16         /// </summary>
17         public byte[] HashBestChain { get; set; }
18
19         /// <summary>
20         /// Total trust score of best chain
21         /// </summary>
22         public byte[] BestChainTrust { get; set; }
23
24         public uint nBestHeight { get; set; }
25
26         [Ignore]
27         public uint256 nBestChainTrust
28         {
29             get { return BestChainTrust; }
30             set { BestChainTrust = value; }
31         }
32
33         [Ignore]
34         public uint256 nHashBestChain
35         {
36             get { return HashBestChain; }
37             set { HashBestChain = value; }
38         }
39     }
40
41     [Table("BlockStorage")]
42     public class CBlockStoreItem
43     {
44         #region IBlockStorageItem
45         /// <summary>
46         /// Item ID in the database
47         /// </summary>
48         [PrimaryKey, AutoIncrement]
49         public long ItemID { get; set; }
50
51         /// <summary>
52         /// PBKDF2+Salsa20 of block hash
53         /// </summary>
54         [Unique]
55         public byte[] Hash { get; set; }
56
57         /// <summary>
58         /// Version of block schema
59         /// </summary>
60         [Column("nVersion")]
61         public uint nVersion { get; set; }
62
63         /// <summary>
64         /// Previous block hash.
65         /// </summary>
66         [Column("prevHash")]
67         public byte[] prevHash { get; set; }
68
69         /// <summary>
70         /// Merkle root hash.
71         /// </summary>
72         [Column("merkleRoot")]
73         public byte[] merkleRoot { get; set; }
74
75         /// <summary>
76         /// Block timestamp.
77         /// </summary>
78         [Column("nTime")]
79         public uint nTime { get; set; }
80
81         /// <summary>
82         /// Compressed difficulty representation.
83         /// </summary>
84         [Column("nBits")]
85         public uint nBits { get; set; }
86
87         /// <summary>
88         /// Nonce counter.
89         /// </summary>
90         [Column("nNonce")]
91         public uint nNonce { get; set; }
92
93         /// <summary>
94         /// Next block hash.
95         /// </summary>
96         [Column("nextHash")]
97         public byte[] nextHash { get; set; }
98
99         /// <summary>
100         /// Block type flags
101         /// </summary>
102         [Column("BlockTypeFlag")]
103         public BlockType BlockTypeFlag { get; set; }
104
105         /// <summary>
106         /// Stake modifier
107         /// </summary>
108         [Column("nStakeModifier")]
109         public long nStakeModifier { get; set; }
110
111         /// <summary>
112         /// Proof-of-Stake hash
113         /// </summary>
114         [Column("hashProofOfStake")]
115         public byte[] hashProofOfStake { get; set; }
116
117         /// <summary>
118         /// Stake generation outpoint.
119         /// </summary>
120         [Column("prevoutStake")]
121         public byte[] prevoutStake { get; set; }
122
123         /// <summary>
124         /// Stake generation time.
125         /// </summary>
126         [Column("nStakeTime")]
127         public uint nStakeTime { get; set; }
128
129         /// <summary>
130         /// Block height, encoded in VarInt format
131         /// </summary>
132         [Column("nHeight")]
133         public uint nHeight { get; set; }
134
135         /// <summary>
136         /// Chain trust score, serialized and trimmed uint256 representation.
137         /// </summary>
138         [Column("ChainTrust")]
139         public byte[] ChainTrust { get; set; }
140
141         /// <summary>
142         /// Block position in file, encoded in VarInt format
143         /// </summary>
144         [Column("BlockPos")]
145         public byte[] BlockPos { get; set; }
146
147         /// <summary>
148         /// Block size in bytes, encoded in VarInt format
149         /// </summary>
150         [Column("BlockSize")]
151         public byte[] BlockSize { get; set; }
152         #endregion
153
154         /// <summary>
155         /// Accessor and mutator for BlockPos value.
156         /// </summary>
157         [Ignore]
158         public long nBlockPos
159         {
160             get { return (long)VarInt.DecodeVarInt(BlockPos); }
161             set { BlockPos = VarInt.EncodeVarInt(value); }
162         }
163
164         /// <summary>
165         /// Accessor and mutator for BlockSize value.
166         /// </summary>
167         [Ignore]
168         public int nBlockSize
169         {
170             get { return (int)VarInt.DecodeVarInt(BlockSize); }
171             set { BlockSize = VarInt.EncodeVarInt(value); }
172         }
173
174         /// <summary>
175         /// Fill database item with data from given block header.
176         /// </summary>
177         /// <param name="header">Block header</param>
178         /// <returns>Header hash</returns>
179         public uint256 FillHeader(CBlockHeader header)
180         {
181             uint256 _hash = header.Hash;
182
183             Hash = _hash;
184
185             nVersion = header.nVersion;
186             prevHash = header.prevHash;
187             merkleRoot = header.merkleRoot;
188             nTime = header.nTime;
189             nBits = header.nBits;
190             nNonce = header.nNonce;
191
192             return _hash;
193         }
194
195         /// <summary>
196         /// Reconstruct block header from item data.
197         /// </summary>
198         public CBlockHeader BlockHeader
199         {
200             get
201             {
202                 CBlockHeader header = new CBlockHeader();
203
204                 header.nVersion = nVersion;
205                 header.prevHash = prevHash;
206                 header.merkleRoot = merkleRoot;
207                 header.nTime = nTime;
208                 header.nBits = nBits;
209                 header.nNonce = nNonce;
210
211                 return header;
212             }
213         }
214
215         /// <summary>
216         /// Read block from file.
217         /// </summary>
218         /// <param name="reader">Stream with read access.</param>
219         /// <param name="reader">CBlock reference.</param>
220         /// <returns>Result</returns>
221         public bool ReadFromFile(ref Stream reader, out CBlock block)
222         {
223             var buffer = new byte[nBlockSize];
224             block = null;
225
226             try
227             {
228                 reader.Seek(nBlockPos, SeekOrigin.Begin);
229
230                 if (nBlockSize != reader.Read(buffer, 0, nBlockSize))
231                 {
232                     return false;
233                 }
234
235                 block = new CBlock(buffer);
236
237                 return true;
238             }
239             catch (IOException)
240             {
241                 // I/O error
242                 return false;
243             }
244             catch (BlockException)
245             {
246                 // Constructor exception
247                 return false;
248             }
249         }
250
251         /// <summary>
252         /// Writes given block to file and prepares cursor object for insertion into the database.
253         /// </summary>
254         /// <param name="writer">Stream with write access.</param>
255         /// <param name="block">CBlock reference.</param>
256         /// <returns>Result</returns>
257         public bool WriteToFile(ref Stream writer, ref CBlock block)
258         {
259             try
260             {
261                 byte[] blockBytes = block;
262
263                 var magicBytes = BitConverter.GetBytes(CBlockStore.nMagicNumber);
264                 var blkLenBytes = BitConverter.GetBytes(blockBytes.Length);
265
266                 // Seek to the end and then append magic bytes there.
267                 writer.Seek(0, SeekOrigin.End);
268                 writer.Write(magicBytes, 0, magicBytes.Length);
269                 writer.Write(blkLenBytes, 0, blkLenBytes.Length);
270
271                 // Save block size and current position in the block cursor fields.
272                 nBlockPos = writer.Position;
273                 nBlockSize = blockBytes.Length;
274
275                 // Write block and flush the stream.
276                 writer.Write(blockBytes, 0, blockBytes.Length);
277                 writer.Flush();
278
279                 return true;
280             }
281             catch (IOException)
282             {
283                 // I/O error
284                 return false;
285             }
286             catch (Exception)
287             {
288                 // Some serialization error
289                 return false;
290             }
291         }
292
293         /// <summary>
294         /// Previous block cursor
295         /// </summary>
296         [Ignore]
297         public CBlockStoreItem prev
298         {
299             get { return CBlockStore.Instance.GetMapCursor(prevHash); }
300         }
301
302         /// <summary>
303         /// Next block cursor
304         /// </summary>
305         [Ignore]
306         public CBlockStoreItem next
307         {
308             get
309             {
310                 if (nextHash == null)
311                 {
312                     return null;
313                 }
314
315                 return CBlockStore.Instance.GetMapCursor(nextHash);
316             }
317             set
318             {
319                 nextHash = value.Hash;
320
321                 CBlockStore.Instance.UpdateMapCursor(this);
322             }
323         }
324
325         [Ignore]
326         bool IsInMainChain
327         {
328             get { return (next != null); }
329         }
330
331         /// <summary>
332         /// STake modifier generation flag
333         /// </summary>
334         [Ignore]
335         public bool GeneratedStakeModifier
336         {
337             get { return (BlockTypeFlag & BlockType.BLOCK_STAKE_MODIFIER) != 0; }
338         }
339
340         /// <summary>
341         /// Stake entropy bit
342         /// </summary>
343         [Ignore]
344         public uint StakeEntropyBit
345         {
346             get { return ((uint)(BlockTypeFlag & BlockType.BLOCK_STAKE_ENTROPY) >> 1); }
347         }
348
349         /// <summary>
350         /// Sets stake modifier and flag.
351         /// </summary>
352         /// <param name="nModifier">New stake modifier.</param>
353         /// <param name="fGeneratedStakeModifier">Set generation flag?</param>
354         public void SetStakeModifier(long nModifier, bool fGeneratedStakeModifier)
355         {
356             nStakeModifier = nModifier;
357             if (fGeneratedStakeModifier)
358                 BlockTypeFlag |= BlockType.BLOCK_STAKE_MODIFIER;
359         }
360
361         /// <summary>
362         /// Set entropy bit.
363         /// </summary>
364         /// <param name="nEntropyBit">Entropy bit value (0 or 1).</param>
365         /// <returns>False if value is our of range.</returns>
366         public bool SetStakeEntropyBit(byte nEntropyBit)
367         {
368             if (nEntropyBit > 1)
369                 return false;
370             BlockTypeFlag |= (nEntropyBit != 0 ? BlockType.BLOCK_STAKE_ENTROPY : 0);
371             return true;
372         }
373
374         /// <summary>
375         /// Set proof-of-stake flag.
376         /// </summary>
377         public void SetProofOfStake()
378         {
379             BlockTypeFlag |= BlockType.BLOCK_PROOF_OF_STAKE;
380         }
381
382         /// <summary>
383         /// Block has no proof-of-stake flag.
384         /// </summary>
385         [Ignore]
386         public bool IsProofOfWork
387         {
388             get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) == 0; }
389         }
390
391         /// <summary>
392         /// Block has proof-of-stake flag set.
393         /// </summary>
394         [Ignore]
395         public bool IsProofOfStake
396         {
397             get { return (BlockTypeFlag & BlockType.BLOCK_PROOF_OF_STAKE) != 0; }
398         }
399
400         /// <summary>
401         /// Block trust score.
402         /// </summary>
403         [Ignore]
404         public uint256 nBlockTrust
405         {
406             get
407             {
408                 uint256 nTarget = 0;
409                 nTarget.Compact = nBits;
410
411                 /* Old protocol */
412                 if (nTime < NetInfo.nChainChecksSwitchTime)
413                 {
414                     return IsProofOfStake ? (new uint256(1) << 256) / (nTarget + 1) : 1;
415                 }
416
417                 /* New protocol */
418
419                 // Calculate work amount for block
420                 var nPoWTrust = NetInfo.nPoWBase / (nTarget + 1);
421
422                 // Set nPowTrust to 1 if we are checking PoS block or PoW difficulty is too low
423                 nPoWTrust = (IsProofOfStake || !nPoWTrust) ? 1 : nPoWTrust;
424
425                 // Return nPoWTrust for the first 12 blocks
426                 if (prev == null || prev.nHeight < 12)
427                     return nPoWTrust;
428
429                 CBlockStoreItem currentIndex = prev;
430
431                 if (IsProofOfStake)
432                 {
433                     var nNewTrust = (new uint256(1) << 256) / (nTarget + 1);
434
435                     // Return 1/3 of score if parent block is not the PoW block
436                     if (!prev.IsProofOfWork)
437                     {
438                         return nNewTrust / 3;
439                     }
440
441                     int nPoWCount = 0;
442
443                     // Check last 12 blocks type
444                     while (prev.nHeight - currentIndex.nHeight < 12)
445                     {
446                         if (currentIndex.IsProofOfWork)
447                         {
448                             nPoWCount++;
449                         }
450                         currentIndex = currentIndex.prev;
451                     }
452
453                     // Return 1/3 of score if less than 3 PoW blocks found
454                     if (nPoWCount < 3)
455                     {
456                         return nNewTrust / 3;
457                     }
458
459                     return nNewTrust;
460                 }
461                 else
462                 {
463                     var nLastBlockTrust = prev.nChainTrust - prev.prev.nChainTrust;
464
465                     // Return nPoWTrust + 2/3 of previous block score if two parent blocks are not PoS blocks
466                     if (!prev.IsProofOfStake || !prev.prev.IsProofOfStake)
467                     {
468                         return nPoWTrust + (2 * nLastBlockTrust / 3);
469                     }
470
471                     int nPoSCount = 0;
472
473                     // Check last 12 blocks type
474                     while (prev.nHeight - currentIndex.nHeight < 12)
475                     {
476                         if (currentIndex.IsProofOfStake)
477                         {
478                             nPoSCount++;
479                         }
480                         currentIndex = currentIndex.prev;
481                     }
482
483                     // Return nPoWTrust + 2/3 of previous block score if less than 7 PoS blocks found
484                     if (nPoSCount < 7)
485                     {
486                         return nPoWTrust + (2 * nLastBlockTrust / 3);
487                     }
488
489                     nTarget.Compact = prev.nBits;
490
491                     if (!nTarget)
492                     {
493                         return 0;
494                     }
495
496                     var nNewTrust = (new uint256(1) << 256) / (nTarget + 1);
497
498                     // Return nPoWTrust + full trust score for previous block nBits
499                     return nPoWTrust + nNewTrust;
500                 }
501             }
502         }
503
504         /// <summary>
505         /// Stake modifier checksum.
506         /// </summary>
507         public uint nStakeModifierChecksum;
508
509         /// <summary>
510         /// Chain trust score
511         /// </summary>
512         [Ignore]
513         public uint256 nChainTrust
514         {
515             get { return Interop.AppendWithZeros(ChainTrust); }
516             set { ChainTrust = Interop.TrimArray(value); }
517         }
518
519         public long nMint { get; internal set; }
520         public long nMoneySupply { get; internal set; }
521     }
522
523     /// <summary>
524     /// Block type.
525     /// </summary>
526     public enum BlockType
527     {
528         BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block
529         BLOCK_STAKE_ENTROPY = (1 << 1), // entropy bit for stake modifier
530         BLOCK_STAKE_MODIFIER = (1 << 2), // regenerated stake modifier
531     };
532
533     /// <summary>
534     /// Transaction type.
535     /// </summary>
536     public enum TxFlags : byte
537     {
538         TX_COINBASE,
539         TX_COINSTAKE,
540         TX_USER
541     }
542
543     /// <summary>
544     /// Output flags.
545     /// </summary>
546     public enum OutputFlags : byte
547     {
548         AVAILABLE, // Unspent output
549         SPENT      // Spent output
550     }
551
552     [Table("MerkleNodes")]
553     public class CMerkleNode
554     {
555         #region IMerkleNode
556         /// <summary>
557         /// Node identifier
558         /// </summary>
559         [PrimaryKey, AutoIncrement]
560         public long nMerkleNodeID { get; set; }
561
562         /// <summary>
563         /// Reference to parent block database item.
564         /// </summary>
565         [ForeignKey(typeof(CBlockStoreItem), Name = "ItemId")]
566         public long nParentBlockID { get; set; }
567
568         /// <summary>
569         /// Transaction type flag
570         /// </summary>
571         [Column("TransactionFlags")]
572         public TxFlags TransactionFlags { get; set; }
573
574         /// <summary>
575         /// Transaction hash
576         /// </summary>
577         [Column("TransactionHash")]
578         public byte[] TransactionHash { get; set; }
579
580         /// <summary>
581         /// Transaction offset from the beginning of block header, encoded in VarInt format.
582         /// </summary>
583         [Column("TxOffset")]
584         public byte[] TxOffset { get; set; }
585
586         /// <summary>
587         /// Transaction size, encoded in VarInt format.
588         /// </summary>
589         [Column("TxSize")]
590         public byte[] TxSize { get; set; }
591         #endregion
592
593         /// <summary>
594         /// Read transaction from file.
595         /// </summary>
596         /// <param name="reader">Stream with read access.</param>
597         /// <param name="tx">CTransaction reference.</param>
598         /// <returns>Result</returns>
599         public bool ReadFromFile(ref Stream reader, long nBlockPos, out CTransaction tx)
600         {
601             var buffer = new byte[CTransaction.nMaxTxSize];
602
603             tx = null;
604
605             try
606             {
607                 reader.Seek(nBlockPos + nTxOffset, SeekOrigin.Begin); // Seek to transaction offset
608
609                 if (nTxSize != reader.Read(buffer, 0, nTxSize))
610                 {
611                     return false;
612                 }
613
614                 tx = new CTransaction(buffer);
615
616                 return true;
617             }
618             catch (IOException)
619             {
620                 // I/O error
621                 return false;
622             }
623             catch (TransactionConstructorException)
624             {
625                 // Constructor error
626                 return false;
627             }
628         }
629
630         /// <summary>
631         /// Transaction offset accessor
632         /// </summary>
633         [Ignore]
634         public long nTxOffset
635         {
636             get { return (long)VarInt.DecodeVarInt(TxOffset); }
637             private set { TxOffset = VarInt.EncodeVarInt(value); }
638         }
639
640         /// <summary>
641         /// Transaction size accessor
642         /// </summary>
643         [Ignore]
644         public int nTxSize
645         {
646             get { return (int)VarInt.DecodeVarInt(TxSize); }
647             private set { TxSize = VarInt.EncodeVarInt(value); }
648         }
649
650         public CMerkleNode(CTransaction tx)
651         {
652             nTxOffset = -1;
653             nParentBlockID = -1;
654
655             nTxSize = tx.Size;
656             TransactionHash = tx.Hash;
657
658             if (tx.IsCoinBase)
659             {
660                 TransactionFlags |= TxFlags.TX_COINBASE;
661             }
662             else if (tx.IsCoinStake)
663             {
664                 TransactionFlags |= TxFlags.TX_COINSTAKE;
665             }
666             else
667             {
668                 TransactionFlags |= TxFlags.TX_USER;
669             }
670         }
671
672         public CMerkleNode(long nBlockId, long nOffset, CTransaction tx)
673         {
674             nParentBlockID = nBlockId;
675
676             nTxOffset = nOffset;
677             nTxSize = tx.Size;
678             TransactionHash = tx.Hash;
679
680             if (tx.IsCoinBase)
681             {
682                 TransactionFlags |= TxFlags.TX_COINBASE;
683             }
684             else if (tx.IsCoinStake)
685             {
686                 TransactionFlags |= TxFlags.TX_COINSTAKE;
687             }
688             else
689             {
690                 TransactionFlags |= TxFlags.TX_USER;
691             }
692         }
693
694     }
695
696     [Table("Outputs")]
697     public class TxOutItem
698     {
699         /// <summary>
700         /// Reference to transaction item.
701         /// </summary>
702         [ForeignKey(typeof(CMerkleNode), Name = "nMerkleNodeID")]
703         public long nMerkleNodeID { get; set; }
704
705         /// <summary>
706         /// Output flags
707         /// </summary>
708         public OutputFlags outputFlags { get; set; }
709
710         /// <summary>
711         /// Output number in VarInt format.
712         /// </summary>
713         public byte[] OutputNumber { get; set; }
714
715         /// <summary>
716         /// Output value in VarInt format.
717         /// </summary>
718         public byte[] OutputValue { get; set; }
719
720         /// <summary>
721         /// Second half of script which contains spending instructions.
722         /// </summary>
723         public byte[] scriptPubKey { get; set; }
724
725         /// <summary>
726         /// Getter for output number.
727         /// </summary>
728         [Ignore]
729         public uint nOut
730         {
731             get { return (uint)VarInt.DecodeVarInt(OutputNumber); }
732             set { OutputNumber = VarInt.EncodeVarInt(value); }
733         }
734
735         /// <summary>
736         /// Getter for output value.
737         /// </summary>
738         [Ignore]
739         public ulong nValue
740         {
741             get { return VarInt.DecodeVarInt(OutputValue); }
742             set { OutputValue = VarInt.EncodeVarInt(value); }
743         }
744
745         /// <summary>
746         /// Getter ans setter for IsSpent flag.
747         /// </summary>
748         [Ignore]
749         public bool IsSpent
750         {
751             get { return (outputFlags & OutputFlags.SPENT) != 0; }
752             set { outputFlags |= value ? OutputFlags.SPENT : OutputFlags.AVAILABLE; }
753         }
754     }
755
756
757     /// <summary>
758     /// TxOut + transaction hash
759     /// </summary>
760     public class InputsJoin : TxOutItem
761     {
762         public byte[] TransactionHash { get; set; }
763     }
764
765
766
767 }