ConnectInputs + stubs for GetCoinAge, GetMinFee and GetProofOfStakeReward.
[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 timestamp
570         /// </summary>
571         [Column("nTime")]
572         public uint nTime { get; set; }
573
574         /// <summary>
575         /// Transaction type flag
576         /// </summary>
577         [Column("TransactionFlags")]
578         public TxFlags TransactionFlags { get; set; }
579
580         /// <summary>
581         /// Transaction hash
582         /// </summary>
583         [Column("TransactionHash")]
584         public byte[] TransactionHash { get; set; }
585
586         /// <summary>
587         /// Transaction offset from the beginning of block header, encoded in VarInt format.
588         /// </summary>
589         [Column("TxOffset")]
590         public byte[] TxOffset { get; set; }
591
592         /// <summary>
593         /// Transaction size, encoded in VarInt format.
594         /// </summary>
595         [Column("TxSize")]
596         public byte[] TxSize { get; set; }
597         #endregion
598
599         /// <summary>
600         /// Read transaction from file.
601         /// </summary>
602         /// <param name="reader">Stream with read access.</param>
603         /// <param name="tx">CTransaction reference.</param>
604         /// <returns>Result</returns>
605         public bool ReadFromFile(ref Stream reader, long nBlockPos, out CTransaction tx)
606         {
607             var buffer = new byte[CTransaction.nMaxTxSize];
608
609             tx = null;
610
611             try
612             {
613                 reader.Seek(nBlockPos + nTxOffset, SeekOrigin.Begin); // Seek to transaction offset
614
615                 if (nTxSize != reader.Read(buffer, 0, nTxSize))
616                 {
617                     return false;
618                 }
619
620                 tx = new CTransaction(buffer);
621
622                 return true;
623             }
624             catch (IOException)
625             {
626                 // I/O error
627                 return false;
628             }
629             catch (TransactionConstructorException)
630             {
631                 // Constructor error
632                 return false;
633             }
634         }
635
636         /// <summary>
637         /// Transaction offset accessor
638         /// </summary>
639         [Ignore]
640         public long nTxOffset
641         {
642             get { return (long)VarInt.DecodeVarInt(TxOffset); }
643             private set { TxOffset = VarInt.EncodeVarInt(value); }
644         }
645
646         /// <summary>
647         /// Transaction size accessor
648         /// </summary>
649         [Ignore]
650         public int nTxSize
651         {
652             get { return (int)VarInt.DecodeVarInt(TxSize); }
653             private set { TxSize = VarInt.EncodeVarInt(value); }
654         }
655
656         [Ignore]
657         public bool IsCoinBase
658         {
659             get { return TransactionFlags == TxFlags.TX_COINBASE; }
660         }
661
662         [Ignore]
663         public bool IsCoinStake
664         {
665             get { return TransactionFlags == TxFlags.TX_COINSTAKE; }
666         }
667
668         public CMerkleNode(CTransaction tx)
669         {
670             nTime = tx.nTime;
671
672             nTxOffset = -1;
673             nParentBlockID = -1;
674
675             nTxSize = tx.Size;
676             TransactionHash = tx.Hash;
677
678             if (tx.IsCoinBase)
679             {
680                 TransactionFlags = TxFlags.TX_COINBASE;
681             }
682             else if (tx.IsCoinStake)
683             {
684                 TransactionFlags = TxFlags.TX_COINSTAKE;
685             }
686             else
687             {
688                 TransactionFlags = TxFlags.TX_USER;
689             }
690         }
691
692         public CMerkleNode(long nBlockId, long nOffset, CTransaction tx)
693         {
694             nTime = tx.nTime;
695
696             nParentBlockID = nBlockId;
697
698             nTxOffset = nOffset;
699             nTxSize = tx.Size;
700             TransactionHash = tx.Hash;
701
702             if (tx.IsCoinBase)
703             {
704                 TransactionFlags |= TxFlags.TX_COINBASE;
705             }
706             else if (tx.IsCoinStake)
707             {
708                 TransactionFlags |= TxFlags.TX_COINSTAKE;
709             }
710             else
711             {
712                 TransactionFlags |= TxFlags.TX_USER;
713             }
714         }
715
716     }
717
718     [Table("Outputs")]
719     public class TxOutItem
720     {
721         /// <summary>
722         /// Reference to transaction item.
723         /// </summary>
724         [ForeignKey(typeof(CMerkleNode), Name = "nMerkleNodeID")]
725         public long nMerkleNodeID { get; set; }
726
727         /// <summary>
728         /// Output flags
729         /// </summary>
730         public OutputFlags outputFlags { get; set; }
731
732         /// <summary>
733         /// Output number in VarInt format.
734         /// </summary>
735         public byte[] OutputNumber { get; set; }
736
737         /// <summary>
738         /// Output value in VarInt format.
739         /// </summary>
740         public byte[] OutputValue { get; set; }
741
742         /// <summary>
743         /// Second half of script which contains spending instructions.
744         /// </summary>
745         public byte[] scriptPubKey { get; set; }
746
747         /// <summary>
748         /// Getter for output number.
749         /// </summary>
750         [Ignore]
751         public uint nOut
752         {
753             get { return (uint)VarInt.DecodeVarInt(OutputNumber); }
754             set { OutputNumber = VarInt.EncodeVarInt(value); }
755         }
756
757         /// <summary>
758         /// Getter for output value.
759         /// </summary>
760         [Ignore]
761         public ulong nValue
762         {
763             get { return VarInt.DecodeVarInt(OutputValue); }
764             set { OutputValue = VarInt.EncodeVarInt(value); }
765         }
766
767         /// <summary>
768         /// Getter ans setter for IsSpent flag.
769         /// </summary>
770         [Ignore]
771         public bool IsSpent
772         {
773             get { return (outputFlags & OutputFlags.SPENT) != 0; }
774             set { outputFlags |= value ? OutputFlags.SPENT : OutputFlags.AVAILABLE; }
775         }
776     }
777
778
779     /// <summary>
780     /// TxOut + transaction hash
781     /// </summary>
782     public class InputsJoin : TxOutItem
783     {
784         public byte[] TransactionHash { get; set; }
785     }
786
787
788
789 }