forked from peercoin/peercoin
-
Notifications
You must be signed in to change notification settings - Fork 13
/
main.h
2228 lines (1846 loc) · 63.9 KB
/
main.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2013 The PPCoin developers
// Copyright (c) 2013-2014 The Slimcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_MAIN_H
#define BITCOIN_MAIN_H
#include "bignum.h"
#include "net.h"
#include "script.h"
#include <math.h> /* pow */
#ifdef WIN32
#include <io.h> /* for _commit */
#endif
#include <list>
//the size of the block to hash, from the nVersion to the nNonce
#define HASH_PBLOCK_SIZE(pblock) UEND(pblock->nNonce) - UBEGIN(pblock->nVersion)
#define HASH_BLOCK_SIZE(block) UEND(block.nNonce) - UBEGIN(block.nVersion)
class CWallet;
class CBlock;
class CBlockIndex;
class CKeyItem;
class CReserveKey;
class COutPoint;
class CWalletTx;
class CTransaction;
class CTxOut;
class CAddress;
class CInv;
class CRequestTracker;
class CNode;
static const unsigned int MAX_BLOCK_SIZE = 1000000;
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
static const int64 MIN_TX_FEE = CENT;
static const int64 MIN_RELAY_TX_FEE = CENT;
static const int64 MAX_MONEY = 250000000 * COIN;
static const int64 MAX_MINT_PROOF_OF_WORK = 50 * COIN;
static const int64 MAX_MINT_PROOF_OF_BURN = 250 * COIN;
static const int64 MIN_TXOUT_AMOUNT = MIN_TX_FEE;
// Default for -maxorphanblocks, maximum number of orphan blocks kept in memory
static const unsigned int DEFAULT_MAX_ORPHAN_BLOCKS = 750;
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
static const int COINBASE_MATURITY_SLM = 500;
// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
static const int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
static const int STAKE_TARGET_SPACING = 90; // 90 second block spacing
static const int POB_TARGET_SPACING = 3; // 3 PoW block spacing target between each PoB block
static const int STAKE_MIN_AGE = 60 * 60 * 24 * 7; // minimum age for coin age
static const int STAKE_MAX_AGE = 60 * 60 * 24 * 90; // stake age of full weight
#ifdef USE_UPNP
static const int fHaveUPnP = true;
#else
static const int fHaveUPnP = false;
#endif
static const uint256 hashGenesisBlockOfficial("0x00000766be5a4bb74c040b85a98d2ba2b433c5f4c673912b3331ea6f18d61bea");
static const uint256 hashGenesisBlockTestNet("0x00000d7e8a80fec4057cb6d560822705596040bf41f0ebb2465dcdf46e4c517e");
static const int64 nMaxClockDrift = 2 * 60 * 60; // two hours
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern std::map<uint256, CBlockIndex*> mapBlockIndex;
extern std::set<std::pair<COutPoint, unsigned int> > setStakeSeen;
extern std::set<std::pair<uint256, uint256> > setBurnSeen;
extern uint256 hashGenesisBlock;
extern unsigned int nStakeMinAge;
extern int nCoinbaseMaturity;
extern CBlockIndex* pindexGenesisBlock;
extern int nBestHeight;
extern CBigNum bnBestChainTrust;
extern CBigNum bnBestInvalidTrust;
extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated;
extern uint64 nLastBlockTx;
extern uint64 nLastBlockSize;
extern int64 nLastCoinStakeSearchInterval;
extern const std::string strMessageMagic;
extern double dHashesPerSec;
extern int64 nHPSTimerStart;
extern int64 nTimeBestReceived;
extern CCriticalSection cs_setpwalletRegistered;
extern std::set<CWallet*> setpwalletRegistered;
extern std::map<uint256, CBlock*> mapOrphanBlocks;
// Settings
extern int64 nTransactionFee;
//////////////////////////////////////////////////////////////////////////////
/* Proof Of Burn */
//////////////////////////////////////////////////////////////////////////////
//Burn addresses
const CBitcoinAddress burnOfficialAddress("SfSLMCoinMainNetworkBurnAddr1DeTK5");
const CBitcoinAddress burnTestnetAddress("mmSLiMCoinTestnetBurnAddress1XU5fu");
#define BURN_CONSTANT .01 * CENT
//The hash of a burnt tx doubles smoothly over the course of 350000.0 blocks,
// do not change this without changing BURN_DECAY_RATE (keep floating point)
#define BURN_HASH_DOUBLE 350000.0
//The growth rate of the hash (2 ** (1 / BURN_HASH_DOUBLE)) rounded up,
// do not change this without changing BURN_HASH_DOUBLE
#define BURN_DECAY_RATE 1.00000198
//a burn tx requires atleast x >= 6 confirmations between it and the best block, BURN_MIN_CONFIMS must be > 0
#define BURN_MIN_CONFIRMS 6
#define BURN_HARDER_TARGET 0.5 //make the burn target 0.5 times the intermediate calculated target
//keeps things safe
#if BURN_MIN_CONFIRMS < 1
#error BURN_MIN_CONFIRMS must be greater than or equal to 1
#endif
////////////////////////////////
//PATCHES
////////////////////////////////
//Rounds down the burn hash for all hashes after (or equalling) timestamp 1402314985, not really needed though
// has became a legacy thing due to the burn_hash_intermediate
extern const u32int BURN_ROUND_DOWN;
//at blocks with timestamps greater or equaling 1403247483, when checking burn hash equality in
// CBlock::CheckProofOfBurn, uses the intermediate hash
inline bool use_burn_hash_intermediate(u32int nTime)
{
const u32int BURN_INTERMEDIATE_TIME = 1403247483; //Fri, 20 Jun 2014 06:58:03 GMT
return nTime >= BURN_INTERMEDIATE_TIME ? true : false;
}
//Adjusts the trust values for PoW and PoB blocks
extern const uint64 CHAINCHECKS_SWITCH_TIME;
//Adjusts PoB and PoS targets
extern const uint64 POB_POS_TARGET_SWITCH_TIME;
////////////////////////////////
//PATCHES
////////////////////////////////
void SlimCoinAfterBurner(CWallet *pwallet);
bool HashBurnData(uint256 burnBlockHash, uint256 hashPrevBlock, uint256 burnTxHash,
s32int burnBlkHeight, int64 burnValue, uint256 &smallestHashRet, bool fRetIntermediate);
bool GetBurnHash(uint256 hashPrevBlock, s32int burnBlkHeight, s32int burnCTx,
s32int burnCTxOut, uint256 &smallestHashRet, bool fRetIntermediate);
bool GetAllTxClassesByIndex(s32int blkHeight, s32int txDepth, s32int txOutDepth,
CBlock &blockRet, CTransaction &txRet, CTxOut &txOutRet);
//Scans all of the hashes of this transaction and returns the smallest one
bool ScanBurnHashes(const CWalletTx &burnWTx, uint256 &smallestHashRet);
//Applies ScanBurnHashes to all of the burnt hashes stored in the setBurnHashes
void HashAllBurntTx(uint256 &smallestHashRet, CWalletTx &smallestWTxRet);
inline double calculate_burn_multiplier(int64 burnValue, s32int nPoWBlocksBetween)
{
return (BURN_CONSTANT / burnValue) * pow(2, (nPoWBlocksBetween - BURN_MIN_CONFIRMS) / BURN_HASH_DOUBLE);
}
//Given a number of burnt coins and their depth in the chain, returns the number of effectivly burnt coins
inline int64 BurnCalcEffectiveCoins(int64 nCoins, s32int depthInChain)
{
return nCoins / pow(BURN_DECAY_RATE, depthInChain);
}
inline void GetBurnAddress(CBitcoinAddress &addressRet)
{
addressRet = fTestNet ? burnTestnetAddress : burnOfficialAddress;
return;
}
//the burn address, when created, the constuctor automatically assigns its value
class CBurnAddress : public CBitcoinAddress
{
public:
CBurnAddress()
{
GetBurnAddress(*this);
}
};
//if any == true, then compare address with both testnet and realnet burn addresses
// else compare only with the address that corresponds to which network the client is connected to
inline bool IsBurnAddress(const CBitcoinAddress &address, bool any=false)
{
if(any)
return address == burnTestnetAddress || address == burnOfficialAddress;
else{
CBurnAddress burnAddress;
return address == burnAddress;
}
}
//makes a uint256 number into its compact form and returns it as a uint256 again
inline const uint256 becomeCompact(const uint256 &num)
{
//+ 1 at the end so that hashes that are originally above target, when
// made compact, will still not make the limit,
//ex: hash 0x000000221312312 -> 0x00000022131000...01 //still does not make the target
// target 0x000000221310000...000
return CBigNum().SetCompact(CBigNum(num).GetCompact()).getuint256() + 1;
}
//////////////////////////////////////////////////////////////////////////////
/* Proof Of Burn */
//////////////////////////////////////////////////////////////////////////////
class CReserveKey;
class CTxDB;
class CTxIndex;
void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn);
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock=NULL, bool fUpdate=false, bool fConnect=true);
bool ProcessBlock(CNode* pfrom, CBlock* pblock);
bool CheckDiskSpace(uint64 nAdditionalBytes=0);
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
FILE* AppendBlockFile(unsigned int& nFileRet);
bool LoadBlockIndex(bool fAllowNew=true);
void PrintBlockTree();
bool ProcessMessages(CNode* pfrom);
bool SendMessages(CNode* pto, bool fSendTrickle);
void GenerateSlimcoins(bool fGenerate, CWallet* pwallet);
CBlock* CreateNewBlock(CReserveKey& reservekey, CWallet* pwallet, bool fProofOfStake=false, const CWalletTx *burnWalletTx=NULL);
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
bool CheckProofOfWork(uint256 hash, u32int nBits);
bool CheckProofOfBurnHash(uint256 hash, u32int nBurnBits);
int64 GetProofOfWorkReward(u32int nBits, bool fProofOfBurn=false);
int64 GetProofOfStakeReward(int64 nCoinAge, u32int nTime);
unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
int GetNumBlocksOfPeers();
bool IsInitialBlockDownload();
std::string GetWarnings(std::string strFor);
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock);
uint256 WantedByOrphan(const CBlock* pblockOrphan);
const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
void SlimCoinMiner(CWallet *pwallet, bool fProofOfStake);
CBlockIndex *pindexByHeight(s32int nHeight);
//Returns the number of proof of work blocks between (not including) the
// blocks with heights startHeight and endHeight
s32int nPoWBlocksBetween(s32int startHeight, s32int endHeight);
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
/** Position on disk for a particular transaction. */
class CDiskTxPos
{
public:
unsigned int nFile;
unsigned int nBlockPos;
unsigned int nTxPos;
CDiskTxPos()
{
SetNull();
}
CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn)
{
nFile = nFileIn;
nBlockPos = nBlockPosIn;
nTxPos = nTxPosIn;
}
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; }
bool IsNull() const { return (nFile == -1); }
friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b)
{
return (a.nFile == b.nFile &&
a.nBlockPos == b.nBlockPos &&
a.nTxPos == b.nTxPos);
}
friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b)
{
return !(a == b);
}
std::string ToString() const
{
if (IsNull())
return "null";
else
return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);
}
void print() const
{
printf("%s", ToString().c_str());
}
};
/** An inpoint - a combination of a transaction and an index n into its vin */
class CInPoint
{
public:
CTransaction* ptx;
unsigned int n;
CInPoint() { SetNull(); }
CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
void SetNull() { ptx = NULL; n = -1; }
bool IsNull() const { return (ptx == NULL && n == -1); }
};
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class COutPoint
{
public:
uint256 hash;
unsigned int n;
COutPoint() { SetNull(); }
COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
void SetNull() { hash = 0; n = -1; }
bool IsNull() const { return (hash == 0 && n == -1); }
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
{
return (a.hash == b.hash && a.n == b.n);
}
friend bool operator!=(const COutPoint& a, const COutPoint& b)
{
return !(a == b);
}
std::string ToString() const
{
return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n);
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
/** An input of a transaction. It contains the location of the previous
* transaction's output that it claims and a signature that matches the
* output's public key.
*/
class CTxIn
{
public:
COutPoint prevout;
CScript scriptSig;
unsigned int nSequence;
CTxIn()
{
nSequence = std::numeric_limits<unsigned int>::max();
}
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
{
prevout = prevoutIn;
scriptSig = scriptSigIn;
nSequence = nSequenceIn;
}
CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
{
prevout = COutPoint(hashPrevTx, nOut);
scriptSig = scriptSigIn;
nSequence = nSequenceIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(prevout);
READWRITE(scriptSig);
READWRITE(nSequence);
)
bool IsFinal() const
{
return (nSequence == std::numeric_limits<unsigned int>::max());
}
friend bool operator==(const CTxIn& a, const CTxIn& b)
{
return (a.prevout == b.prevout &&
a.scriptSig == b.scriptSig &&
a.nSequence == b.nSequence);
}
friend bool operator!=(const CTxIn& a, const CTxIn& b)
{
return !(a == b);
}
std::string ToStringShort() const
{
return strprintf(" %s %d", prevout.hash.ToString().c_str(), prevout.n);
}
std::string ToString() const
{
std::string str;
str += "CTxIn(";
str += prevout.ToString();
if (prevout.IsNull())
str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
else
str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
if (nSequence != std::numeric_limits<unsigned int>::max())
str += strprintf(", nSequence=%u", nSequence);
str += ")";
return str;
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
/** An output of a transaction. It contains the public key that the next input
* must be able to sign with to claim it.
*/
class CTxOut
{
public:
int64 nValue;
CScript scriptPubKey;
CTxOut()
{
SetNull();
}
CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
{
nValue = nValueIn;
scriptPubKey = scriptPubKeyIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(nValue);
READWRITE(scriptPubKey);
)
void SetNull()
{
nValue = -1;
scriptPubKey.clear();
}
bool IsNull() const
{
return (nValue == -1);
}
void SetEmpty()
{
nValue = 0;
scriptPubKey.clear();
}
bool IsEmpty() const
{
return (nValue == 0 && scriptPubKey.empty());
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
friend bool operator==(const CTxOut& a, const CTxOut& b)
{
return (a.nValue == b.nValue &&
a.scriptPubKey == b.scriptPubKey);
}
friend bool operator!=(const CTxOut& a, const CTxOut& b)
{
return !(a == b);
}
std::string ToStringShort() const
{
return strprintf(" out %s %s", FormatMoney(nValue).c_str(), scriptPubKey.ToString(true).c_str());
}
std::string ToString() const
{
if (IsEmpty()) return "CTxOut(empty)";
if (scriptPubKey.size() < 6)
return "CTxOut(error)";
return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().c_str());
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
enum GetMinFee_mode
{
GMF_BLOCK,
GMF_RELAY,
GMF_SEND,
};
typedef std::map<uint256, std::pair<CTxIndex, CTransaction> > MapPrevTx;
/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
*/
class CTransaction
{
public:
int nVersion;
unsigned int nTime;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
unsigned int nLockTime;
// Denial-of-service detection:
mutable int nDoS;
bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
CTransaction()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(nTime);
READWRITE(vin);
READWRITE(vout);
READWRITE(nLockTime);
)
void SetNull()
{
nVersion = 1;
nTime = GetAdjustedTime();
vin.clear();
vout.clear();
nLockTime = 0;
nDoS = 0; // Denial-of-service prevention
}
bool IsNull() const
{
return (vin.empty() && vout.empty());
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
{
// Time based nLockTime implemented in 0.1.6
if (nLockTime == 0)
return true;
if (nBlockHeight == 0)
nBlockHeight = nBestHeight;
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
return true;
BOOST_FOREACH(const CTxIn& txin, vin)
if (!txin.IsFinal())
return false;
return true;
}
bool IsNewerThan(const CTransaction& old) const
{
if (vin.size() != old.vin.size())
return false;
for (unsigned int i = 0; i < vin.size(); i++)
if (vin[i].prevout != old.vin[i].prevout)
return false;
bool fNewer = false;
unsigned int nLowest = std::numeric_limits<unsigned int>::max();
for (unsigned int i = 0; i < vin.size(); i++)
{
if (vin[i].nSequence != old.vin[i].nSequence)
{
if (vin[i].nSequence <= nLowest)
{
fNewer = false;
nLowest = vin[i].nSequence;
}
if (old.vin[i].nSequence < nLowest)
{
fNewer = true;
nLowest = old.vin[i].nSequence;
}
}
}
return fNewer;
}
bool IsCoinBase() const
{
return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1);
}
bool IsCoinStake() const
{
// ppcoin: the coin stake transaction is marked with the first output empty
return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());
}
/** Check for standard transaction types
@return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
bool IsStandard() const;
/** Check for standard transaction types
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return True if all inputs (scriptSigs) use only standard transaction forms
@see CTransaction::FetchInputs
*/
bool AreInputsStandard(const MapPrevTx& mapInputs) const;
/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
@return number of sigops this transaction's outputs will produce when spent
@see CTransaction::FetchInputs
*/
unsigned int GetLegacySigOpCount() const;
/** Count ECDSA signature operations in pay-to-script-hash inputs.
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return maximum number of sigops required to validate this transaction's inputs
@see CTransaction::FetchInputs
*/
unsigned int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const;
/** Amount of bitcoins spent by this transaction.
@return sum of all outputs (note: does not include fees)
*/
int64 GetValueOut() const
{
int64 nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout)
{
nValueOut += txout.nValue;
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
}
return nValueOut;
}
//Returns the pubKet of the first txIn of this tx
bool GetSendersPubKey(CScript &scriptPubKeyRet, bool fOurPubKey=false) const;
//return the index of a burn transaction in vout, -1 if not found
s32int GetBurnOutTxIndex() const
{
//find the burnt transaction
CBurnAddress burnAddress;
u32int i;
for(i = 0; i < vout.size(); i++)
{
CBitcoinAddress address;
if(!ExtractAddress(vout[i].scriptPubKey, address))
continue;
if(address == burnAddress)
break;
}
//if i hit the end for the for loop, it means it found nothing so return -1
return i == vout.size() ? -1 : i;
}
bool IsBurnTx() const
{
return GetBurnOutTxIndex() == -1 ? false : true;
}
//if (return value).IsNull() == true, then some error occured
CTxOut GetBurnOutTx() const
{
s32int burnTxOutIndex = GetBurnOutTxIndex();
if(burnTxOutIndex == -1)
return CTxOut(); //error
return vout[burnTxOutIndex];
}
//return the number of effective burnt coins of a burnTx
int64 EffectiveBurntCoinsLeft(s32int BurnBlkHeight, s32int LastBlkHeight = -1) const
{
if (LastBlkHeight < 0)
LastBlkHeight = nBestHeight;
const CTxOut burnOutTx = GetBurnOutTx();
//This is not a burnTx if burnOutTx is null
if (burnOutTx.IsNull())
return 0;
const s32int between = nPoWBlocksBetween(BurnBlkHeight, LastBlkHeight);
//This burn Tx is still immature
if (between < BURN_MIN_CONFIRMS)
return 0;
return BurnCalcEffectiveCoins(burnOutTx.nValue, between);
}
/** Amount of bitcoins coming in to this transaction
Note that lightweight clients may not know anything besides the hash of previous transactions,
so may not be able to calculate this.
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return Sum of value of all inputs (scriptSigs)
@see CTransaction::FetchInputs
*/
int64 GetValueIn(const MapPrevTx& mapInputs) const;
static bool AllowFree(double dPriority)
{
// Large (in bytes) low-priority (new, small-coin) transactions
// need a fee.
return dPriority > COIN * 960 / 250; //960 blocks per day
}
int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, enum GetMinFee_mode mode=GMF_BLOCK) const
{
// Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
unsigned int nNewBlockSize = nBlockSize + nBytes;
int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
if (fAllowFree)
{
if (nBlockSize == 1)
{
// Transactions under 10K are free
// (about 4500bc if made of 50bc inputs)
if (nBytes < 10000)
nMinFee = 0;
}
else
{
// Free transaction area
if (nNewBlockSize < 27000)
nMinFee = 0;
}
}
// To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01
if (nMinFee < nBaseFee)
{
BOOST_FOREACH(const CTxOut& txout, vout)
if (txout.nValue < CENT)
nMinFee = nBaseFee;
}
// Raise the price as the block approaches full
if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2)
{
if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN)
return MAX_MONEY;
nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize);
}
if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
return nMinFee;
}
bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)
{
CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION);
if (!filein)
return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");
// Read transaction
if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
return error("CTransaction::ReadFromDisk() : fseek failed");
try {
filein >> *this;
}
catch (std::exception &e) {
return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
}
// Return file pointer
if (pfileRet)
{
if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
return error("CTransaction::ReadFromDisk() : second fseek failed");
*pfileRet = filein.release();
}
return true;
}
friend bool operator==(const CTransaction& a, const CTransaction& b)
{
return (a.nVersion == b.nVersion &&
a.nTime == b.nTime &&
a.vin == b.vin &&
a.vout == b.vout &&
a.nLockTime == b.nLockTime);
}
friend bool operator!=(const CTransaction& a, const CTransaction& b)
{
return !(a == b);
}
std::string ToStringShort() const
{
std::string str;
str += strprintf("%s %s", GetHash().ToString().c_str(), IsCoinBase()? "base" : (IsCoinStake()? "stake" : "user"));
return str;
}
std::string ToString() const
{
std::string str;
str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
GetHash().ToString().substr(0,10).c_str(),
nTime,
nVersion,
vin.size(),
vout.size(),
nLockTime);
for (unsigned int i = 0; i < vin.size(); i++)
str += " " + vin[i].ToString() + "\n";
for (unsigned int i = 0; i < vout.size(); i++)
str += " " + vout[i].ToString() + "\n";
return str;
}
void print() const
{
printf("%s", ToString().c_str());
}
bool ReadFromDisk(CTxDB& txdb, const uint256& hash, CTxIndex& txindexRet);
bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet);
bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
bool ReadFromDisk(COutPoint prevout);
bool DisconnectInputs(CTxDB& txdb);
/** Fetch from memory and/or disk. inputsRet keys are transaction hashes.
@param[in] txdb Transaction database
@param[in] mapTestPool List of pending changes to the transaction index database
@param[in] fBlock True if being called to add a new best-block to the chain
@param[in] fMiner True if being called by CreateNewBlock
@param[out] inputsRet Pointers to this transaction's inputs
@param[out] fInvalid returns true if transaction is invalid
@return Returns true if all inputs are in txdb or mapTestPool
*/
bool FetchInputs(CTxDB& txdb, const std::map<uint256, CTxIndex>& mapTestPool,
bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid);
/** Sanity check previous transactions, then, if all checks succeed,
mark them as spent by this transaction.
@param[in] inputs Previous transactions (from FetchInputs)
@param[out] mapTestPool Keeps track of inputs that need to be updated on disk
@param[in] posThisTx Position of this transaction on disk
@param[in] pindexBlock
@param[in] fBlock true if called from ConnectBlock
@param[in] fMiner true if called from CreateNewBlock
@param[in] fStrictPayToScriptHash true if fully validating p2sh transactions
@return Returns true if all checks succeed
*/
bool ConnectInputs(CTxDB& txdb, MapPrevTx inputs,
std::map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash=true);
bool ClientConnectInputs();
bool CheckTransaction() const;
bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const; // ppcoin: get transaction coin age
protected:
const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const;
};
/** A transaction with a merkle branch linking it to the block chain. */
class CMerkleTx : public CTransaction
{
public:
uint256 hashBlock;
std::vector<uint256> vMerkleBranch;
int nIndex;
// memory only
mutable bool fMerkleVerified;
CMerkleTx()
{
Init();
}
CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
{
Init();
}
void Init()
{
hashBlock = 0;
nIndex = -1;
fMerkleVerified = false;
}
IMPLEMENT_SERIALIZE
(
nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
nVersion = this->nVersion;
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
)
int SetMerkleBranch(const CBlock* pblock=NULL);
int GetDepthInMainChain(CBlockIndex* &pindexRet) const;
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }