Example #1
0
        public void TestBlockchainKeyEquality()
        {
            var randomBlockchainKey = RandomData.RandomBlockchainKey();

            var sameBlockchainKey = new BlockchainKey
                                    (
                guid: randomBlockchainKey.Guid,
                rootBlockHash: randomBlockchainKey.RootBlockHash
                                    );

            var differentGuid = Guid.NewGuid();

            while (differentGuid == randomBlockchainKey.Guid)
            {
                differentGuid = Guid.NewGuid();
            }

            var differentBlockchainKeyGuid = new BlockchainKey
                                             (
                guid: differentGuid,
                rootBlockHash: randomBlockchainKey.RootBlockHash
                                             );

            var differentBlockchainKeyRootBlockHash = new BlockchainKey
                                                      (
                guid: randomBlockchainKey.Guid,
                rootBlockHash: ~randomBlockchainKey.RootBlockHash
                                                      );

            Assert.IsTrue(randomBlockchainKey.Equals(sameBlockchainKey));
            Assert.IsTrue(randomBlockchainKey == sameBlockchainKey);
            Assert.IsFalse(randomBlockchainKey != sameBlockchainKey);

            Assert.IsFalse(randomBlockchainKey.Equals(differentBlockchainKeyGuid));
            Assert.IsFalse(randomBlockchainKey == differentBlockchainKeyGuid);
            Assert.IsTrue(randomBlockchainKey != differentBlockchainKeyGuid);

            Assert.IsFalse(randomBlockchainKey.Equals(differentBlockchainKeyRootBlockHash));
            Assert.IsFalse(randomBlockchainKey == differentBlockchainKeyRootBlockHash);
            Assert.IsTrue(randomBlockchainKey != differentBlockchainKeyRootBlockHash);
        }
Example #2
0
        public void TestBlockchainKeyEquality()
        {
            var randomBlockchainKey = RandomData.RandomBlockchainKey();

            var sameBlockchainKey = new BlockchainKey
            (
                guid: randomBlockchainKey.Guid,
                rootBlockHash: randomBlockchainKey.RootBlockHash
            );

            var differentGuid = Guid.NewGuid();
            while (differentGuid == randomBlockchainKey.Guid)
                differentGuid = Guid.NewGuid();

            var differentBlockchainKeyGuid = new BlockchainKey
            (
                guid: differentGuid,
                rootBlockHash: randomBlockchainKey.RootBlockHash
            );

            var differentBlockchainKeyRootBlockHash = new BlockchainKey
            (
                guid: randomBlockchainKey.Guid,
                rootBlockHash: ~randomBlockchainKey.RootBlockHash
            );

            Assert.IsTrue(randomBlockchainKey.Equals(sameBlockchainKey));
            Assert.IsTrue(randomBlockchainKey == sameBlockchainKey);
            Assert.IsFalse(randomBlockchainKey != sameBlockchainKey);

            Assert.IsFalse(randomBlockchainKey.Equals(differentBlockchainKeyGuid));
            Assert.IsFalse(randomBlockchainKey == differentBlockchainKeyGuid);
            Assert.IsTrue(randomBlockchainKey != differentBlockchainKeyGuid);

            Assert.IsFalse(randomBlockchainKey.Equals(differentBlockchainKeyRootBlockHash));
            Assert.IsFalse(randomBlockchainKey == differentBlockchainKeyRootBlockHash);
            Assert.IsTrue(randomBlockchainKey != differentBlockchainKeyRootBlockHash);
        }
Example #3
0
        public Data.Blockchain ReadBlockchain(BlockchainKey blockchainKey)
        {
            CheckDatabaseFolder();

            var blockListBuilder = ImmutableList.CreateBuilder <ChainedBlock>();
            var utxoBuilder      = ImmutableDictionary.CreateBuilder <UInt256, UnspentTx>();

            var connString = @"Server=localhost; Database=BitSharp_Blockchains; Trusted_Connection=true;";

            using (var conn = new SqlConnection(connString))
            {
                conn.Open();

                using (var cmd = conn.CreateCommand())
                {
                    cmd.CommandText = @"
                        SELECT BlockHash, PreviousBlockHash, Height, TotalWork
                        FROM ChainedBlocks
                        WHERE Guid = @guid AND RootBlockHash = @rootBlockHash
                        ORDER BY Height ASC";

                    cmd.Parameters.SetValue("@guid", SqlDbType.Binary, 16).Value          = blockchainKey.Guid.ToByteArray();
                    cmd.Parameters.SetValue("@rootBlockHash", SqlDbType.Binary, 32).Value = blockchainKey.RootBlockHash.ToDbByteArray();

                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var blockHash         = reader.GetUInt256(0);
                            var previousBlockHash = reader.GetUInt256(1);
                            var height            = reader.GetInt32(2);
                            var totalWork         = reader.GetBigInteger(3);

                            blockListBuilder.Add(new ChainedBlock(blockHash, previousBlockHash, height, totalWork));
                        }
                    }
                }

                using (var cmd = conn.CreateCommand())
                {
                    cmd.CommandText = @"
                        SELECT UtxoChunkBytes
                        FROM UtxoData
                        WHERE Guid = @guid AND RootBlockHash = @rootBlockHash";

                    cmd.Parameters.SetValue("@guid", SqlDbType.Binary, 16).Value          = blockchainKey.Guid.ToByteArray();
                    cmd.Parameters.SetValue("@rootBlockHash", SqlDbType.Binary, 32).Value = blockchainKey.RootBlockHash.ToDbByteArray();

                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var chunkBytes  = reader.GetBytes(0);
                            var chunkStream = new MemoryStream(chunkBytes);
                            using (var chunkReader = new BinaryReader(chunkStream))
                            {
                                var chunkLength = chunkReader.Read4Bytes().ToIntChecked();

                                var outputs = new TxOutputKey[chunkLength];

                                for (var i = 0; i < chunkLength; i++)
                                {
                                    var prevTxHash        = chunkReader.Read32Bytes();
                                    var prevTxOutputIndex = chunkReader.Read4Bytes();

                                    outputs[i] = new TxOutputKey(prevTxHash, prevTxOutputIndex);
                                }

                                //TODO utxoBuilder.UnionWith(outputs);
                            }
                        }
                    }
                }
            }

            return(new Data.Blockchain(blockListBuilder.ToImmutable(), blockListBuilder.Select(x => x.BlockHash).ToImmutableHashSet(), utxoBuilder.ToImmutable()));
        }
Example #4
0
        public BlockchainKey WriteBlockchain(Data.Blockchain blockchain)
        {
            var guid          = Guid.NewGuid();
            var blockchainKey = new BlockchainKey(guid, blockchain.RootBlockHash);

            var connString = @"Server=localhost; Database=BitSharp_Blockchains; Trusted_Connection=true;";

            using (var conn = new SqlConnection(connString))
            {
                conn.Open();

                using (var trans = conn.BeginTransaction())
                {
                    // write out the metadata for the blockchain
                    using (var cmd = conn.CreateCommand())
                    {
                        cmd.Transaction = trans;

                        cmd.CommandText = @"
                            INSERT INTO BlockchainMetadata (Guid, RootBlockHash, TotalWork, IsComplete)
                            VALUES (@guid, @rootBlockHash, @totalWork, 0);";

                        cmd.Parameters.SetValue("@guid", SqlDbType.Binary, 16).Value          = blockchainKey.Guid.ToByteArray();
                        cmd.Parameters.SetValue("@rootBlockHash", SqlDbType.Binary, 32).Value = blockchainKey.RootBlockHash.ToDbByteArray();
                        cmd.Parameters.SetValue("@totalWork", SqlDbType.Binary, 64).Value     = blockchain.TotalWork.ToDbByteArray();

                        cmd.ExecuteNonQuery();
                    }

                    // write out the block metadata comprising the blockchain
                    using (var cmd = conn.CreateCommand())
                    {
                        cmd.Transaction = trans;

                        cmd.CommandText = @"
                            INSERT INTO ChainedBlocks (Guid, RootBlockHash, BlockHash, PreviousBlockHash, Height, TotalWork)
                            VALUES (@guid, @rootBlockHash, @blockHash, @previousBlockHash, @height, @totalWork)";

                        cmd.Parameters.SetValue("@guid", SqlDbType.Binary, 16).Value          = blockchainKey.Guid.ToByteArray();
                        cmd.Parameters.SetValue("@rootBlockHash", SqlDbType.Binary, 32).Value = blockchainKey.RootBlockHash.ToDbByteArray();
                        cmd.Parameters.Add(new SqlParameter {
                            ParameterName = "@blockHash", SqlDbType = SqlDbType.Binary, Size = 32
                        });
                        cmd.Parameters.Add(new SqlParameter {
                            ParameterName = "@previousBlockHash", SqlDbType = SqlDbType.Binary, Size = 32
                        });
                        cmd.Parameters.Add(new SqlParameter {
                            ParameterName = "@height", SqlDbType = SqlDbType.Int
                        });
                        cmd.Parameters.Add(new SqlParameter {
                            ParameterName = "@totalWork", SqlDbType = SqlDbType.Binary, Size = 64
                        });

                        foreach (var chainedBlock in blockchain.BlockList)
                        {
                            cmd.Parameters["@blockHash"].Value         = chainedBlock.BlockHash.ToDbByteArray();
                            cmd.Parameters["@previousBlockHash"].Value = chainedBlock.PreviousBlockHash.ToDbByteArray();
                            cmd.Parameters["@height"].Value            = chainedBlock.Height;
                            cmd.Parameters["@totalWork"].Value         = chainedBlock.TotalWork.ToDbByteArray();

                            cmd.ExecuteNonQuery();
                        }
                    }

                    // write out the utxo
                    using (var cmd = conn.CreateCommand())
                    {
                        cmd.Transaction = trans;

                        cmd.CommandText = @"
                            INSERT INTO UtxoData (Guid, RootBlockhash, UtxoChunkBytes)
                            VALUES (@guid, @rootBlockHash, @utxoChunkBytes)";

                        cmd.Parameters.SetValue("@guid", SqlDbType.Binary, 16).Value          = blockchainKey.Guid.ToByteArray();
                        cmd.Parameters.SetValue("@rootBlockHash", SqlDbType.Binary, 32).Value = blockchainKey.RootBlockHash.ToDbByteArray();
                        cmd.Parameters.Add(new SqlParameter {
                            ParameterName = "@utxoChunkBytes", SqlDbType = SqlDbType.VarBinary
                        });

                        var chunkSize     = 100000;
                        var currentOffset = 0;
                        var chunkBytes    = new byte[4 + (36 * chunkSize)];

                        using (var utxoEnumerator = blockchain.Utxo.GetEnumerator())
                        {
                            // chunk outer loop
                            while (currentOffset < blockchain.Utxo.Count)
                            {
                                var chunkLength = Math.Min(chunkSize, blockchain.Utxo.Count - currentOffset);

                                var chunkStream = new MemoryStream(chunkBytes);
                                using (var chunkWriter = new BinaryWriter(chunkStream))
                                {
                                    chunkWriter.Write4Bytes((UInt32)chunkLength);

                                    // chunk inner loop
                                    for (var i = 0; i < chunkLength; i++)
                                    {
                                        // get the next output from the utxo
                                        if (!utxoEnumerator.MoveNext())
                                        {
                                            throw new Exception();
                                        }

                                        var output = utxoEnumerator.Current;
                                        //TODO chunkWriter.Write32Bytes(output.TxHash);
                                        //TODO chunkWriter.Write4Bytes((UInt32)output.TxOutputIndex);
                                    }

                                    cmd.Parameters["@utxoChunkBytes"].Size  = chunkBytes.Length;
                                    cmd.Parameters["@utxoChunkBytes"].Value = chunkBytes;
                                }

                                // write the chunk
                                cmd.ExecuteNonQuery();

                                currentOffset += chunkLength;
                            }

                            // there should be no items left in utxo at this point
                            if (utxoEnumerator.MoveNext())
                            {
                                throw new Exception();
                            }
                        }
                    }

                    // mark write as complete
                    using (var cmd = conn.CreateCommand())
                    {
                        cmd.Transaction = trans;

                        cmd.CommandText = @"
                            UPDATE BlockchainMetadata SET IsComplete = 1
                            WHERE Guid = @guid AND RootBlockHash = @rootBlockHash;";

                        cmd.Parameters.SetValue("@guid", SqlDbType.Binary, 16).Value          = blockchainKey.Guid.ToByteArray();
                        cmd.Parameters.SetValue("@rootBlockHash", SqlDbType.Binary, 32).Value = blockchainKey.RootBlockHash.ToDbByteArray();

                        cmd.ExecuteNonQuery();
                    }


                    trans.Commit();
                }
            }

            return(blockchainKey);
        }
Example #5
0
        public Data.Blockchain ReadBlockchain(BlockchainKey blockchainKey)
        {
            CheckDatabaseFolder();

            var blockListBuilder = ImmutableList.CreateBuilder <ChainedBlock>();
            var utxoBuilder      = ImmutableHashSet.CreateBuilder <TxOutputKey>();

            var dbPath     = GetDatabasePath(blockchainKey.Guid);
            var connString = @"ServerType=1; DataSource=localhost; Database={0}; Pooling=false; User=SYSDBA; Password=NA;".Format2(dbPath);

            using (var conn = new FbConnection(connString))
            {
                conn.Open();

                using (var cmd = conn.CreateCommand())
                {
                    cmd.CommandText = @"
                        SELECT BlockHash, PreviousBlockHash, Height, TotalWork
                        FROM ChainedBlocks
                        WHERE Guid = @guid AND RootBlockHash = @rootBlockHash
                        ORDER BY Height ASC";

                    cmd.Parameters.SetValue("@guid", FbDbType.Char, FbCharset.Octets, 16).Value          = blockchainKey.Guid.ToByteArray();
                    cmd.Parameters.SetValue("@rootBlockHash", FbDbType.Char, FbCharset.Octets, 32).Value = blockchainKey.RootBlockHash.ToDbByteArray();

                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var blockHash         = reader.GetUInt256(0);
                            var previousBlockHash = reader.GetUInt256(1);
                            var height            = reader.GetInt32(2);
                            var totalWork         = reader.GetBigInteger(3);

                            blockListBuilder.Add(new ChainedBlock(blockHash, previousBlockHash, height, totalWork));
                        }
                    }
                }

                using (var cmd = conn.CreateCommand())
                {
                    cmd.CommandText = @"
                        SELECT UtxoChunkBytes
                        FROM UtxoData
                        WHERE Guid = @guid AND RootBlockHash = @rootBlockHash";

                    cmd.Parameters.SetValue("@guid", FbDbType.Char, FbCharset.Octets, 16).Value          = blockchainKey.Guid.ToByteArray();
                    cmd.Parameters.SetValue("@rootBlockHash", FbDbType.Char, FbCharset.Octets, 32).Value = blockchainKey.RootBlockHash.ToDbByteArray();

                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var chunkBytes  = reader.GetBytes(0);
                            var chunkStream = new MemoryStream(chunkBytes);
                            using (var chunkReader = new BinaryReader(chunkStream))
                            {
                                var chunkLength = chunkReader.Read4Bytes().ToIntChecked();

                                var outputs = new TxOutputKey[chunkLength];

                                for (var i = 0; i < chunkLength; i++)
                                {
                                    var prevTxHash        = chunkReader.Read32Bytes();
                                    var prevTxOutputIndex = chunkReader.Read4Bytes();

                                    outputs[i] = new TxOutputKey(prevTxHash, prevTxOutputIndex);
                                }

                                utxoBuilder.UnionWith(outputs);
                            }
                        }
                    }
                }
            }

            return(new Data.Blockchain(blockListBuilder.ToImmutable(), blockListBuilder.Select(x => x.BlockHash).ToImmutableHashSet(), utxoBuilder.ToImmutable()));
        }
 public Blockchain ReadBlockchain(BlockchainKey chainedBlock)
 {
     throw new NotImplementedException();
 }