));
// Write block to file.
- var itemTemplate = new CBlockStoreItem()
+ var rootCursor = new CBlockStoreItem()
{
nHeight = 0
};
- itemTemplate.FillHeader(genesisBlock.header);
+ rootCursor.FillHeader(genesisBlock.header);
- if (!AddItemToIndex(ref itemTemplate, ref genesisBlock))
+ if (!AddItemToIndex(ref rootCursor, ref genesisBlock))
{
throw new Exception("Unable to write genesis block");
}
return true;
}
- private bool AddItemToIndex(ref CBlockStoreItem itemTemplate, ref CBlock block)
+ private bool AddItemToIndex(ref CBlockStoreItem newCursor, ref CBlock block)
{
- uint256 blockHash = itemTemplate.Hash;
+ uint256 blockHash = newCursor.Hash;
if (blockMap.ContainsKey(blockHash))
{
dbConn.BeginTransaction();
// Compute chain trust score
- itemTemplate.nChainTrust = (itemTemplate.prev != null ? itemTemplate.prev.nChainTrust : 0) + itemTemplate.nBlockTrust;
+ newCursor.nChainTrust = (newCursor.prev != null ? newCursor.prev.nChainTrust : 0) + newCursor.nBlockTrust;
- if (!itemTemplate.SetStakeEntropyBit(Entropy.GetStakeEntropyBit(itemTemplate.nHeight, blockHash)))
+ if (!newCursor.SetStakeEntropyBit(Entropy.GetStakeEntropyBit(newCursor.nHeight, blockHash)))
{
return false; // SetStakeEntropyBit() failed
}
// compute stake modifier
long nStakeModifier = 0;
bool fGeneratedStakeModifier = false;
- if (!StakeModifier.ComputeNextStakeModifier(itemTemplate, ref nStakeModifier, ref fGeneratedStakeModifier))
+ if (!StakeModifier.ComputeNextStakeModifier(ref newCursor, ref nStakeModifier, ref fGeneratedStakeModifier))
{
return false; // ComputeNextStakeModifier() failed
}
- itemTemplate.SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
- itemTemplate.nStakeModifierChecksum = StakeModifier.GetModifierChecksum(itemTemplate);
+ newCursor.SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
+ newCursor.nStakeModifierChecksum = StakeModifier.GetModifierChecksum(newCursor);
- if (!ModifierCheckpoints.Verify(itemTemplate.nHeight, itemTemplate.nStakeModifierChecksum))
+ if (!ModifierCheckpoints.Verify(newCursor.nHeight, newCursor.nStakeModifierChecksum))
{
return false; // Stake modifier checkpoints mismatch
}
// Add to index
if (block.IsProofOfStake)
{
- itemTemplate.SetProofOfStake();
+ newCursor.SetProofOfStake();
- itemTemplate.prevoutStake = block.vtx[1].vin[0].prevout;
- itemTemplate.nStakeTime = block.vtx[1].nTime;
+ newCursor.prevoutStake = block.vtx[1].vin[0].prevout;
+ newCursor.nStakeTime = block.vtx[1].nTime;
// Save proof-of-stake hash value
uint256 hashProofOfStake;
{
return false; // hashProofOfStake not found
}
- itemTemplate.hashProofOfStake = hashProofOfStake;
+ newCursor.hashProofOfStake = hashProofOfStake;
}
- if (!itemTemplate.WriteToFile(ref fStreamReadWrite, ref block))
+ if (!newCursor.WriteToFile(ref fStreamReadWrite, ref block))
{
return false;
}
- if (dbConn.Insert(itemTemplate) == 0)
+ if (dbConn.Insert(newCursor) == 0)
{
return false; // Insert failed
}
// Get last RowID.
- itemTemplate.ItemID = dbPlatform.SQLiteApi.LastInsertRowid(dbConn.Handle);
+ newCursor.ItemID = dbPlatform.SQLiteApi.LastInsertRowid(dbConn.Handle);
- if (!blockMap.TryAdd(blockHash, itemTemplate))
+ if (!blockMap.TryAdd(blockHash, newCursor))
{
return false; // blockMap add failed
}
- if (itemTemplate.nChainTrust > ChainParams.nBestChainTrust)
+ if (newCursor.nChainTrust > ChainParams.nBestChainTrust)
{
// New best chain
- if (!SetBestChain(ref itemTemplate))
+ if (!SetBestChain(ref newCursor))
{
return false; // SetBestChain failed.
}
if (tx.IsCoinStake)
{
- // Coin stake tx earns reward instead of paying fee
- long nCoinAge;
- if (!tx.GetCoinAge(ref inputs, out nCoinAge))
+ if (HashCheckpoints.LastCheckpointTime < tx.nTime)
{
- return false; // unable to get coin age for coinstake
- }
-
- long nReward = tx.nValueOut - nValueIn;
+ // Coin stake tx earns reward instead of paying fee
+ long nCoinAge;
+ if (!tx.GetCoinAge(ref inputs, out nCoinAge))
+ {
+ return false; // unable to get coin age for coinstake
+ }
- long nCalculatedReward = CBlock.GetProofOfStakeReward(nCoinAge, cursorBlock.nBits, tx.nTime) - tx.GetMinFee(1, false, CTransaction.MinFeeMode.GMF_BLOCK) + CTransaction.nCent;
+ long nReward = tx.nValueOut - nValueIn;
+ long nCalculatedReward = CBlock.GetProofOfStakeReward(nCoinAge, cursorBlock.nBits, tx.nTime) - tx.GetMinFee(1, false, CTransaction.MinFeeMode.GMF_BLOCK) + CTransaction.nCent;
- if (nReward > nCalculatedReward)
- {
- return false; // coinstake pays too much
+ if (nReward > nCalculatedReward)
+ {
+ return false; // coinstake pays too much
+ }
}
}
else
var prevBlockHeader = prevBlockCursor.BlockHeader;
- // TODO: proof-of-work/proof-of-stake verification
uint nHeight = prevBlockCursor.nHeight + 1;
// Check timestamp against prev
return false; // rejected by checkpoint lock-in
}
- // TODO: Enforce rule that the coinbase starts with serialized block height
+ // Enforce rule that the coinbase starts with serialized block height
+ var expect = new CScript();
+ expect.AddNumber((int)nHeight);
+
+ byte[] expectBytes = expect;
+ byte[] scriptSig = block.vtx[0].vin[0].scriptSig;
+
+ if (!expectBytes.SequenceEqual(scriptSig.Take(expectBytes.Length)))
+ {
+ return false; // coinbase doesn't start with serialized height.
+ }
// Write block to file.
- var itemTemplate = new CBlockStoreItem()
+ var newCursor = new CBlockStoreItem()
{
nHeight = nHeight,
};
- itemTemplate.FillHeader(block.header);
+ newCursor.FillHeader(block.header);
- if (!AddItemToIndex(ref itemTemplate, ref block))
+ if (!AddItemToIndex(ref newCursor, ref block))
{
dbConn.Rollback();
if (block.IsProofOfStake)
{
- // TODO: proof-of-stake validation
-
uint256 hashProofOfStake = 0, targetProofOfStake = 0;
if (!StakeModifier.CheckProofOfStake(block.vtx[1], block.header.nBits, out hashProofOfStake, out targetProofOfStake))
{