public bool AcceptBlock(ref CBlock block) { uint256 nHash = block.header.Hash; if (blockMap.ContainsKey(nHash)) { // Already have this block. return false; } CBlockStoreItem prevBlockCursor; if (!blockMap.TryGetValue(block.header.prevHash, out prevBlockCursor)) { // Unable to get the cursor. return false; } var prevBlockHeader = prevBlockCursor.BlockHeader; uint nHeight = prevBlockCursor.nHeight + 1; // Check timestamp against prev if (NetInfo.FutureDrift(block.header.nTime) < prevBlockHeader.nTime) { // block's timestamp is too early return false; } // Check that all transactions are finalized foreach (var tx in block.vtx) { if (!tx.IsFinal(nHeight, block.header.nTime)) { return false; } } // Check that the block chain matches the known block chain up to a checkpoint if (!HashCheckpoints.Verify(nHeight, nHash)) { return false; // rejected by checkpoint lock-in } // 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 newCursor = new CBlockStoreItem() { nHeight = nHeight, }; newCursor.FillHeader(block.header); if (!AddItemToIndex(ref newCursor, ref block)) { dbConn.Rollback(); return false; } return true; }
/// <summary> /// Init the block storage manager. /// </summary> /// <param name="IndexDB">Path to index database</param> /// <param name="BlockFile">Path to block file</param> public CBlockStore(string IndexDB = "blockstore.dat", string BlockFile = "blk0001.dat") { strDbFile = IndexDB; strBlockFile = BlockFile; bool firstInit = !File.Exists(strDbFile); dbPlatform = new SQLitePlatformGeneric(); dbConn = new SQLiteConnection(dbPlatform, strDbFile); fStreamReadWrite = File.Open(strBlockFile, FileMode.OpenOrCreate, FileAccess.ReadWrite); Instance = this; if (firstInit) { lock (LockObj) { // Create tables dbConn.CreateTable<CBlockStoreItem>(CreateFlags.AutoIncPK); dbConn.CreateTable<CMerkleNode>(CreateFlags.AutoIncPK); dbConn.CreateTable<TxOutItem>(CreateFlags.ImplicitPK); dbConn.CreateTable<ChainState>(CreateFlags.AutoIncPK); ChainParams = new ChainState() { nBestChainTrust = 0, nBestHeight = 0, nHashBestChain = 0 }; dbConn.Insert(ChainParams); var genesisBlock = new CBlock( Interop.HexToArray( "01000000" + // nVersion=1 "0000000000000000000000000000000000000000000000000000000000000000" + // prevhash is zero "7b0502ad2f9f675528183f83d6385794fbcaa914e6d385c6cb1d866a3b3bb34c" + // merkle root "398e1151" + // nTime=1360105017 "ffff0f1e" + // nBits=0x1e0fffff "d3091800" + // nNonce=1575379 "01" + // nTxCount=1 "01000000" + // nVersion=1 "398e1151" + // nTime=1360105017 "01" + // nInputs=1 "0000000000000000000000000000000000000000000000000000000000000000" + // input txid is zero "ffffffff" + // n=uint.maxValue "4d" + // scriptSigLen=77 "04ffff001d020f274468747470733a2f2f626974636f696e74616c6b2e6f72672f696e6465782e7068703f746f7069633d3133343137392e6d736731353032313936236d736731353032313936" + // scriptSig "ffffffff" + // nSequence=uint.maxValue "01" + // nOutputs=1 "0000000000000000" + // nValue=0 "00" + // scriptPubkeyLen=0 "00000000" + // nLockTime=0 "00" // sigLen=0 )); // Write block to file. var rootCursor = new CBlockStoreItem() { nHeight = 0 }; rootCursor.FillHeader(genesisBlock.header); if (!AddItemToIndex(ref rootCursor, ref genesisBlock)) { throw new Exception("Unable to write genesis block"); } } } else { var blockTreeItems = dbConn.Query<CBlockStoreItem>("select * from [BlockStorage] order by [ItemId] asc"); // Init list of block items foreach (var item in blockTreeItems) { item.nStakeModifierChecksum = StakeModifier.GetModifierChecksum(item); blockMap.TryAdd(item.Hash, item); if (item.IsProofOfStake) { // build mapStakeSeen mapStakeSeen.TryAdd(item.prevoutStake, item.nStakeTime); } } // Load data about the top node. ChainParams = dbConn.Table<ChainState>().First(); genesisBlockCursor = dbConn.Query<CBlockStoreItem>("select * from [BlockStorage] where [Hash] = ?", (byte[])NetInfo.nHashGenesisBlock).First(); bestBlockCursor = dbConn.Query<CBlockStoreItem>("select * from [BlockStorage] where [Hash] = ?", ChainParams.HashBestChain).First(); } }