private ConcurrentDictionary<COutPoint, uint> mapStakeSeen = new ConcurrentDictionary<COutPoint, uint>();
- private ConcurrentDictionary<COutPoint, uint> mapStakeSeenOrphan = new ConcurrentDictionary<COutPoint, uint>();
+ private ConcurrentDictionary<Tuple<COutPoint, uint>, uint256> mapStakeSeenOrphan = new ConcurrentDictionary<Tuple<COutPoint, uint>, uint256>();
/// <summary>
bool fScriptChecks = cursor.nHeight >= Checkpoints.TotalBlocksEstimate;
var scriptFlags = scriptflag.SCRIPT_VERIFY_NOCACHE | scriptflag.SCRIPT_VERIFY_P2SH;
- ulong nFees = 0;
- ulong nValueIn = 0;
- ulong nValueOut = 0;
+ long nFees = 0;
+ long nValueIn = 0;
+ long nValueOut = 0;
uint nSigOps = 0;
var queuedMerkleNodes = new Dictionary<uint256, CMerkleNode>();
return false; // too many sigops
}
- ulong nTxValueIn = tx.GetValueIn(ref inputs);
- ulong nTxValueOut = tx.nValueOut;
+ long nTxValueIn = tx.GetValueIn(ref inputs);
+ long nTxValueOut = tx.nValueOut;
nValueIn += nTxValueIn;
nValueOut += nTxValueOut;
if (!block.IsProofOfStake)
{
- ulong nBlockReward = CBlock.GetProofOfWorkReward(cursor.nBits, nFees);
+ long nBlockReward = CBlock.GetProofOfWorkReward(cursor.nBits, nFees);
// Check coinbase reward
if (block.vtx[0].nValueOut > nBlockReward)
}
}
- cursor.nMint = (long)(nValueOut - nValueIn + nFees);
- cursor.nMoneySupply = (cursor.prev != null ? cursor.prev.nMoneySupply : 0) + (long)nValueOut - (long)nValueIn;
+ cursor.nMint = nValueOut - nValueIn + nFees;
+ cursor.nMoneySupply = (cursor.prev != null ? cursor.prev.nMoneySupply : 0) + nValueOut - nValueIn;
if (!UpdateDBCursor(ref cursor))
{
if (!tx.IsCoinBase)
{
- ulong nValueIn = 0;
- ulong nFees = 0;
+ long nValueIn = 0;
+ long nFees = 0;
for (uint i = 0; i < tx.vin.Length; i++)
{
var prevout = tx.vin[i].prevout;
if (tx.IsCoinStake)
{
// ppcoin: coin stake tx earns reward instead of paying fee
- ulong nCoinAge;
+ long nCoinAge;
if (!tx.GetCoinAge(ref inputs, out nCoinAge))
{
return false; // unable to get coin age for coinstake
}
- ulong nReward = tx.nValueOut - nValueIn;
+ long nReward = tx.nValueOut - nValueIn;
- ulong nCalculatedReward = CBlock.GetProofOfStakeReward(nCoinAge, cursorBlock.nBits, tx.nTime) - tx.GetMinFee(1, false, CTransaction.MinFeeMode.GMF_BLOCK) + CTransaction.nCent;
+ long nCalculatedReward = CBlock.GetProofOfStakeReward(nCoinAge, cursorBlock.nBits, tx.nTime) - tx.GetMinFee(1, false, CTransaction.MinFeeMode.GMF_BLOCK) + CTransaction.nCent;
if (nReward > nCalculatedReward)
{
}
// Tally transaction fees
- ulong nTxFee = nValueIn - tx.nValueOut;
+ long nTxFee = nValueIn - tx.nValueOut;
if (nTxFee < 0)
{
return false; // nTxFee < 0
}
}
+ // Check that the block chain matches the known block chain up to a checkpoint
+ if (!Checkpoints.Verify(nHeight, nHash))
+ {
+ return false; // rejected by checkpoint lock-in
+ }
+
// TODO: Enforce rule that the coinbase starts with serialized block height
// Write block to file.
if (block.IsProofOfStake)
{
- if (!block.SignatureOK)
- {
- // Proof-of-Stake signature validation failure.
- return false;
- }
-
// TODO: proof-of-stake validation
uint256 hashProofOfStake = 0, targetProofOfStake = 0;
{
if (block.IsProofOfStake)
{
- // TODO: limit duplicity on stake
+ var proof = block.ProofOfStake;
+
+ // Limited duplicity on stake: prevents block flood attack
+ // Duplicate stake allowed only when there is orphan child block
+ if (mapStakeSeenOrphan.ContainsKey(proof) && !orphanMapByPrev.ContainsKey(blockHash))
+ {
+ return false; // duplicate proof-of-stake
+ }
+ else
+ {
+ mapStakeSeenOrphan.TryAdd(proof, blockHash);
+ }
}
- var block2 = new CBlock(block);
- orphanMap.TryAdd(blockHash, block2);
- orphanMapByPrev.TryAdd(blockHash, block2);
+ orphanMap.TryAdd(blockHash, block);
+ orphanMapByPrev.TryAdd(blockHash, block);
return true;
}
return false;
}
- // Recursively process any orphan blocks that depended on this one
- var orphansQueue = new List<uint256>();
- orphansQueue.Add(blockHash);
-
- for (int i = 0; i < orphansQueue.Count; i++)
+ if (orphanMapByPrev.Count > 0)
{
- var hashPrev = orphansQueue[i];
+ // Recursively process any orphan blocks that depended on this one
+
+ var orphansQueue = new List<uint256>();
+ orphansQueue.Add(blockHash);
- foreach (var pair in orphanMap)
+ for (int i = 0; i < orphansQueue.Count; i++)
{
- var orphanBlock = pair.Value;
+ var hashPrev = orphansQueue[i];
- if (orphanBlock.header.prevHash == blockHash)
+ foreach (var pair in orphanMapByPrev)
{
- if (AcceptBlock(ref orphanBlock))
+ var orphanBlock = pair.Value;
+
+ if (orphanBlock.header.prevHash == blockHash)
{
- orphansQueue.Add(pair.Key);
- }
+ if (AcceptBlock(ref orphanBlock))
+ {
+ orphansQueue.Add(pair.Key);
+ }
+
+ CBlock dummy1;
+ orphanMap.TryRemove(pair.Key, out dummy1);
- CBlock dummy1;
- orphanMap.TryRemove(pair.Key, out dummy1);
+ uint256 dummyHash;
+ mapStakeSeenOrphan.TryRemove(orphanBlock.ProofOfStake, out dummyHash);
+ }
}
- }
- CBlock dummy2;
- orphanMap.TryRemove(hashPrev, out dummy2);
+ CBlock dummy2;
+ orphanMapByPrev.TryRemove(hashPrev, out dummy2);
+ }
}
return true;