private static void CreateGlobalsTable(JET_DBID utxoDbId, Session jetSession)
        {
            JET_TABLEID globalsTableId;
            JET_COLUMNID chainTipColumnId;
            JET_COLUMNID unspentTxCountColumnId;
            JET_COLUMNID unspentOutputCountColumnId;
            JET_COLUMNID totalTxCountColumnId;
            JET_COLUMNID totalInputCountColumnId;
            JET_COLUMNID totalOutputCountColumnId;

            Api.JetCreateTable(jetSession, utxoDbId, "Globals", 0, 0, out globalsTableId);
            Api.JetAddColumn(jetSession, globalsTableId, "ChainTip", new JET_COLUMNDEF { coltyp = JET_coltyp.Binary }, null, 0, out chainTipColumnId);
            Api.JetAddColumn(jetSession, globalsTableId, "UnspentTxCount", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out unspentTxCountColumnId);
            Api.JetAddColumn(jetSession, globalsTableId, "UnspentOutputCount", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out unspentOutputCountColumnId);
            Api.JetAddColumn(jetSession, globalsTableId, "TotalTxCount", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out totalTxCountColumnId);
            Api.JetAddColumn(jetSession, globalsTableId, "TotalInputCount", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out totalInputCountColumnId);
            Api.JetAddColumn(jetSession, globalsTableId, "TotalOutputCount", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out totalOutputCountColumnId);

            // initialize global data
            using (var jetUpdate = jetSession.BeginUpdate(globalsTableId, JET_prep.Insert))
            {
                Api.SetColumn(jetSession, globalsTableId, unspentTxCountColumnId, 0);
                Api.SetColumn(jetSession, globalsTableId, unspentOutputCountColumnId, 0);
                Api.SetColumn(jetSession, globalsTableId, totalTxCountColumnId, 0);
                Api.SetColumn(jetSession, globalsTableId, totalInputCountColumnId, 0);
                Api.SetColumn(jetSession, globalsTableId, totalOutputCountColumnId, 0);

                jetUpdate.Save();
            }

            Api.JetCloseTable(jetSession, globalsTableId);
        }
        private static void CreateFlushTable(JET_DBID utxoDbId, Session jetSession)
        {
            JET_TABLEID flushTableId;
            JET_COLUMNID flushColumnId;

            var defaultValue = BitConverter.GetBytes(0);

            Api.JetCreateTable(jetSession, utxoDbId, "Flush", 0, 0, out flushTableId);
            Api.JetAddColumn(jetSession, flushTableId, "Flush", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnEscrowUpdate }, defaultValue, defaultValue.Length, out flushColumnId);

            // initialize global data
            using (var jetUpdate = jetSession.BeginUpdate(flushTableId, JET_prep.Insert))
            {
                Api.SetColumn(jetSession, flushTableId, flushColumnId, 0);

                jetUpdate.Save();
            }

            Api.JetCloseTable(jetSession, flushTableId);
        }
        private void CreateDatabase()
        {
            JET_DBID blockDbId;

            JET_TABLEID globalsTableId;
            JET_COLUMNID blockCountColumnId;
            JET_COLUMNID flushColumnId;

            JET_TABLEID blockIndexTableId;
            JET_COLUMNID blockIndexBlockHashColumnId;
            JET_COLUMNID blockIndexBlockIndexColumnId;

            JET_TABLEID blocksTableId;
            JET_COLUMNID blockIndexColumnId;
            JET_COLUMNID blockTxIndexColumnId;
            JET_COLUMNID blockDepthColumnId;
            JET_COLUMNID blockTxHashColumnId;
            JET_COLUMNID blockTxBytesColumnId;

            using (var jetSession = new Session(this.jetInstance))
            {
                var createGrbit = CreateDatabaseGrbit.None;
                if (EsentVersion.SupportsWindows7Features)
                    createGrbit |= Windows7Grbits.EnableCreateDbBackgroundMaintenance;

                Api.JetCreateDatabase(jetSession, jetDatabase, "", out blockDbId, createGrbit);

                var defaultValue = BitConverter.GetBytes(0);
                Api.JetCreateTable(jetSession, blockDbId, "Globals", 0, 0, out globalsTableId);
                Api.JetAddColumn(jetSession, globalsTableId, "BlockCount", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnEscrowUpdate }, defaultValue, defaultValue.Length, out blockCountColumnId);
                Api.JetAddColumn(jetSession, globalsTableId, "Flush", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnEscrowUpdate }, defaultValue, defaultValue.Length, out flushColumnId);

                // initialize global data
                using (var jetUpdate = jetSession.BeginUpdate(globalsTableId, JET_prep.Insert))
                {
                    Api.SetColumn(jetSession, globalsTableId, blockCountColumnId, 0);
                    Api.SetColumn(jetSession, globalsTableId, flushColumnId, 0);

                    jetUpdate.Save();
                }

                Api.JetCloseTable(jetSession, globalsTableId);

                Api.JetCreateTable(jetSession, blockDbId, "BlockIndex", 0, 0, out blockIndexTableId);
                Api.JetAddColumn(jetSession, blockIndexTableId, "BlockHash", new JET_COLUMNDEF { coltyp = JET_coltyp.Binary, cbMax = 32, grbit = ColumndefGrbit.ColumnNotNULL | ColumndefGrbit.ColumnFixed }, null, 0, out blockIndexBlockHashColumnId);
                Api.JetAddColumn(jetSession, blockIndexTableId, "BlockIndex", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL | ColumndefGrbit.ColumnFixed | ColumndefGrbit.ColumnAutoincrement }, null, 0, out blockIndexBlockIndexColumnId);

                Api.JetCreateIndex2(jetSession, blockIndexTableId,
                    new JET_INDEXCREATE[]
                    {
                        new JET_INDEXCREATE
                        {
                            cbKeyMost = 255,
                            grbit = CreateIndexGrbit.IndexUnique | CreateIndexGrbit.IndexDisallowNull,
                            szIndexName = "IX_BlockHash",
                            szKey = "+BlockHash\0\0",
                            cbKey = "+BlockHash\0\0".Length
                        }
                    }, 1);

                Api.JetCloseTable(jetSession, blockIndexTableId);

                Api.JetCreateTable(jetSession, blockDbId, "Blocks", 0, 0, out blocksTableId);
                Api.JetAddColumn(jetSession, blocksTableId, "BlockIndex", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out blockIndexColumnId);
                Api.JetAddColumn(jetSession, blocksTableId, "TxIndex", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out blockTxIndexColumnId);
                Api.JetAddColumn(jetSession, blocksTableId, "Depth", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out blockDepthColumnId);
                Api.JetAddColumn(jetSession, blocksTableId, "TxHash", new JET_COLUMNDEF { coltyp = JET_coltyp.Binary, cbMax = 32, grbit = ColumndefGrbit.ColumnNotNULL | ColumndefGrbit.ColumnFixed }, null, 0, out blockTxHashColumnId);
                Api.JetAddColumn(jetSession, blocksTableId, "TxBytes", new JET_COLUMNDEF { coltyp = JET_coltyp.LongBinary }, null, 0, out blockTxBytesColumnId);

                Api.JetCreateIndex2(jetSession, blocksTableId,
                    new JET_INDEXCREATE[]
                    {
                        new JET_INDEXCREATE
                        {
                            cbKeyMost = 255,
                            grbit = CreateIndexGrbit.IndexUnique | CreateIndexGrbit.IndexDisallowNull,
                            szIndexName = "IX_BlockIndexTxIndex",
                            szKey = "+BlockIndex\0TxIndex\0\0",
                            cbKey = "+BlockIndex\0TxIndex\0\0".Length
                        }
                    }, 1);

                Api.JetCloseTable(jetSession, blocksTableId);
            }
        }
        private void CreateDatabase()
        {
            JET_DBID blockDbId;
            JET_TABLEID globalsTableId;
            JET_COLUMNID flushColumnId;
            JET_TABLEID blockHeadersTableId;
            JET_COLUMNID blockHeaderHashColumnId;
            JET_COLUMNID blockHeaderPreviousHashColumnId;
            JET_COLUMNID blockHeaderHeightColumnId;
            JET_COLUMNID blockHeaderTotalWorkColumnId;
            JET_COLUMNID blockHeaderValidColumnId;
            JET_COLUMNID blockHeaderBytesColumnId;

            using (var jetSession = new Session(this.jetInstance))
            {
                var createGrbit = CreateDatabaseGrbit.None;
                if (EsentVersion.SupportsWindows7Features)
                    createGrbit |= Windows7Grbits.EnableCreateDbBackgroundMaintenance;

                Api.JetCreateDatabase(jetSession, jetDatabase, "", out blockDbId, createGrbit);

                var defaultValue = BitConverter.GetBytes(0);
                Api.JetCreateTable(jetSession, blockDbId, "Globals", 0, 0, out globalsTableId);
                Api.JetAddColumn(jetSession, globalsTableId, "Flush", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnEscrowUpdate }, defaultValue, defaultValue.Length, out flushColumnId);

                // initialize global data
                using (var jetUpdate = jetSession.BeginUpdate(globalsTableId, JET_prep.Insert))
                {
                    Api.SetColumn(jetSession, globalsTableId, flushColumnId, 0);

                    jetUpdate.Save();
                }

                Api.JetCloseTable(jetSession, globalsTableId);

                Api.JetCreateTable(jetSession, blockDbId, "BlockHeaders", 0, 0, out blockHeadersTableId);
                Api.JetAddColumn(jetSession, blockHeadersTableId, "BlockHash", new JET_COLUMNDEF { coltyp = JET_coltyp.Binary, cbMax = 32, grbit = ColumndefGrbit.ColumnNotNULL | ColumndefGrbit.ColumnFixed }, null, 0, out blockHeaderHashColumnId);
                Api.JetAddColumn(jetSession, blockHeadersTableId, "PreviousBlockHash", new JET_COLUMNDEF { coltyp = JET_coltyp.Binary, cbMax = 32, grbit = ColumndefGrbit.ColumnNotNULL | ColumndefGrbit.ColumnFixed }, null, 0, out blockHeaderPreviousHashColumnId);
                Api.JetAddColumn(jetSession, blockHeadersTableId, "Height", new JET_COLUMNDEF { coltyp = JET_coltyp.Long, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out blockHeaderHeightColumnId);
                Api.JetAddColumn(jetSession, blockHeadersTableId, "TotalWork", new JET_COLUMNDEF { coltyp = JET_coltyp.Binary, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out blockHeaderTotalWorkColumnId);
                Api.JetAddColumn(jetSession, blockHeadersTableId, "Valid", new JET_COLUMNDEF { coltyp = JET_coltyp.Bit, }, null, 0, out blockHeaderValidColumnId);
                Api.JetAddColumn(jetSession, blockHeadersTableId, "BlockHeaderBytes", new JET_COLUMNDEF { coltyp = JET_coltyp.Binary, grbit = ColumndefGrbit.ColumnNotNULL }, null, 0, out blockHeaderBytesColumnId);

                Api.JetCreateIndex2(jetSession, blockHeadersTableId,
                    new JET_INDEXCREATE[]
                    {
                        new JET_INDEXCREATE
                        {
                            cbKeyMost = 255,
                            grbit = CreateIndexGrbit.IndexUnique | CreateIndexGrbit.IndexDisallowNull,
                            szIndexName = "IX_BlockHash",
                            szKey = "+BlockHash\0\0",
                            cbKey = "+BlockHash\0\0".Length
                        }
                    }, 1);

                //Api.JetCreateIndex2(jetSession, blockHeadersTableId,
                //    new JET_INDEXCREATE[]
                //    {
                //        new JET_INDEXCREATE
                //        {
                //            cbKeyMost = 255,
                //            grbit = CreateIndexGrbit.IndexDisallowNull,
                //            szIndexName = "IX_PreviousBlockHash",
                //            szKey = "+PreviousBlockHash\0\0",
                //            cbKey = "+PreviousBlockHash\0\0".Length
                //        }
                //    }, 1);

                //Api.JetCreateIndex2(jetSession, blockHeadersTableId,
                //    new JET_INDEXCREATE[]
                //    {
                //        new JET_INDEXCREATE
                //        {
                //            cbKeyMost = 255,
                //            grbit = CreateIndexGrbit.IndexDisallowNull,
                //            szIndexName = "IX_Height",
                //            szKey = "+Height\0\0",
                //            cbKey = "+Height\0\0".Length
                //        }
                //    }, 1);

                Api.JetCreateIndex2(jetSession, blockHeadersTableId,
                    new JET_INDEXCREATE[]
                    {
                        new JET_INDEXCREATE
                        {
                            cbKeyMost = 255,
                            grbit = CreateIndexGrbit.IndexDisallowNull,
                            szIndexName = "IX_TotalWork",
                            szKey = "-TotalWork\0\0",
                            cbKey = "-TotalWork\0\0".Length
                        }
                    }, 1);

                Api.JetCloseTable(jetSession, blockHeadersTableId);
            }
        }