コード例 #1
0
        protected override void Parse()
        {
            var numHeaders = base.ReadVarInt();
            if (numHeaders > MaxHeaders)
            {
                throw new ProtocolException("Too many headers: got " + numHeaders + " which is larger than " + MaxHeaders);
            }

            BlockHeaders = new List<Block>();

            for (var i = 0UL; i < numHeaders; ++i)
            {
                // Read 80 bytes of the header and one more byte for the transaction list, which is always a 00 because the
                // transaction list is empty.
                var blockHeaderBytes = base.ReadBytes(81);
                if (blockHeaderBytes[80] != 0)
                {
                    throw new ProtocolException("Block header does not end with a null byte");
                }
                var newBlockHeader = new Block(this.NetworkParameters, blockHeaderBytes);
                BlockHeaders.Add(newBlockHeader);
            }
            if (!Log.IsDebugEnabled) return;
            foreach (var blockHeader in BlockHeaders)
            {
                Log.Debug(blockHeader);
            }
        }
コード例 #2
0
        public override void OnBlocksDownloaded(Peer peer, Block block, int blocksLeft)
        {
            if (blocksLeft == 0)
            {
                DoneDownload();
                _done.Release();
            }

            if (blocksLeft < 0 || _originalBlocksLeft <= 0)
                return;

            var pct = 100.0 - (100.0 * (blocksLeft / (double)_originalBlocksLeft));
            if ((int)pct != _lastPercent)
            {
                Progress(pct, UnixTime.FromUnixTime(block.TimeSeconds * 1000));
                _lastPercent = (int)pct;
            }
        }
コード例 #3
0
ファイル: BlockTest.cs プロジェクト: perljedi/BitcoinSharp
 public void TestBadTransactions()
 {
     var block = new Block(_params, _blockBytes);
     // Re-arrange so the coinbase transaction is not first.
     var tx1 = block.Transactions[0];
     var tx2 = block.Transactions[1];
     block.Transactions[0] = tx2;
     block.Transactions[1] = tx1;
     try
     {
         block.Verify();
         Assert.Fail();
     }
     catch (VerificationException)
     {
         // We should get here.
     }
 }
コード例 #4
0
ファイル: BlockTest.cs プロジェクト: perljedi/BitcoinSharp
        public void TestJavaSerialiazation()
        {
            var block = new Block(_params, _blockBytes);
            var tx = block.Transactions[1];

            // Serialize using Java.
            byte[] javaBits;
            using (var bos = new MemoryStream())
            {
                var oos = new BinaryFormatter();
                oos.Serialize(bos, tx);
                javaBits = bos.ToArray();
            }
            // Deserialize again.
            Transaction tx2;
            using (var bos = new MemoryStream(javaBits))
            {
                var ois = new BinaryFormatter();
                tx2 = (Transaction) ois.Deserialize(bos);
            }

            // Note that this will actually check the transactions are equal by doing BitCoin serialization and checking
            // the byte streams are the same! A true "deep equals" is not implemented for Transaction. The primary purpose
            // of this test is to ensure no errors occur during the Java serialization/deserialization process.
            Assert.AreEqual(tx, tx2);
        }
コード例 #5
0
 private static Block CreateGenesis(NetworkParameters networkParameters)
 {
     var genesisBlock = new Block(networkParameters);
     var transaction = new Transaction(networkParameters);
     // A script containing the difficulty bits and the following message:
     //   "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
     var bytes = Hex.Decode("04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73");
     transaction.AddInput(new TransactionInput(networkParameters, transaction, bytes));
     using (var scriptPubKeyBytes = new MemoryStream())
     {
         Script.WriteBytes(scriptPubKeyBytes,Hex.Decode("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
         scriptPubKeyBytes.Write(Script.OpCheckSig);
         transaction.AddOutput(new TransactionOutput(networkParameters, transaction, scriptPubKeyBytes.ToArray()));
     }
     genesisBlock.AddTransaction(transaction);
     return genesisBlock;
 }
コード例 #6
0
 public HeadersMessage(NetworkParameters @params, Block headers)
     : base(@params)
 {
     BlockHeaders = new List<Block>() { headers };
 }
コード例 #7
0
 private static Block GetBlock1()
 {
     var b1 = new Block(_testNet);
     b1.MerkleRoot = new Sha256Hash(Hex.Decode("0e8e58ecdacaa7b3c6304a35ae4ffff964816d2b80b62b58558866ce4e648c10"));
     b1.Nonce = 236038445;
     b1.TimeSeconds = 1296734340;
     b1.PreviousBlockHash = new Sha256Hash(Hex.Decode("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"));
     Assert.AreEqual("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604", b1.HashAsString);
     b1.VerifyHeader();
     return b1;
 }
コード例 #8
0
ファイル: BlockTest.cs プロジェクト: perljedi/BitcoinSharp
 public void TestHeaderParse()
 {
     var block = new Block(_params, _blockBytes);
     var header = block.CloneAsHeader();
     var reparsed = new Block(_params, header.BitcoinSerialize());
     Assert.AreEqual(reparsed, header);
 }
コード例 #9
0
ファイル: BlockTest.cs プロジェクト: perljedi/BitcoinSharp
 public void TestBitCoinSerialization()
 {
     // We have to be able to re-serialize everything exactly as we found it for hashing to work. This test also
     // proves that transaction serialization works, along with all its sub-objects like scripts and in/outpoints.
     //
     // NB: This tests the BITCOIN proprietary serialization protocol. A different test checks Java serialization
     // of transactions.
     var block = new Block(_params, _blockBytes);
     Assert.IsTrue(_blockBytes.SequenceEqual(block.BitcoinSerialize()));
 }
コード例 #10
0
ファイル: StoredBlock.cs プロジェクト: perljedi/BitcoinSharp
 /// <summary>
 /// Creates a new StoredBlock, calculating the additional fields by adding to the values in this block.
 /// </summary>
 /// <exception cref="VerificationException"/>
 public StoredBlock Build(Block block)
 {
     // Stored blocks track total work done in this chain, because the canonical chain is the one that represents
     // the largest amount of work done not the tallest.
     var chainWork = _chainWork.Add(block.GetWork());
     var height = _height + 1;
     return new StoredBlock(block.CloneAsHeader(), chainWork, height);
 }
コード例 #11
0
ファイル: StoredBlock.cs プロジェクト: perljedi/BitcoinSharp
 public StoredBlock(Block blockHeader, BigInteger chainWork, uint height)
 {
     _blockHeader = blockHeader;
     _chainWork = chainWork;
     _height = height;
 }
コード例 #12
0
ファイル: BlockChain.cs プロジェクト: perljedi/BitcoinSharp
        /// <summary>
        ///     For the transactions in the given block, update the txToWalletMap such that each wallet maps to a list of
        ///     transactions for which it is relevant.
        /// </summary>
        /// <exception cref="VerificationException" />
        private void ScanTransactions(Block block, IDictionary<IDefaultWallet, List<Transaction>> walletToTransactionMap)
        {
            foreach (var transaction in block.Transactions)
            {
                try
                {
                    foreach (var wallet in _wallets)
                    {
                        var shouldReceive =
                            transaction.TransactionOutputs.Where(output => !output.ScriptPublicKey.IsSentToIp)
                                .Any(output => output.IsMine(wallet));

                        // Coinbase transactions don't have anything useful in their inputs (as they create coins out of thin air).
                        if (!shouldReceive && !transaction.IsCoinBase)
                        {
                            foreach (var transactionInput in transaction.TransactionInputs)
                            {
                                var publicKey = transactionInput.ScriptSig.PublicKey;
                                // This is not thread safe as a key could be removed between the call to isPubKeyMine and receive.
                                if (wallet.IsPublicKeyMine(publicKey))
                                {
                                    shouldReceive = true;
                                }
                            }
                        }

                        if (!shouldReceive) continue;
                        List<Transaction> transactions;
                        if (!walletToTransactionMap.TryGetValue(wallet, out transactions))
                        {
                            transactions = new List<Transaction>();
                            walletToTransactionMap[wallet] = transactions;
                        }
                        transactions.Add(transaction);
                    }
                }
                catch (ScriptException e)
                {
                    // We don't want scripts we don't understand to break the block chain so just note that this tx was
                    // not scanned here and continue.
                    Log.Warn("Failed to parse a script: " + e);
                }
            }
        }
コード例 #13
0
ファイル: BlockChain.cs プロジェクト: perljedi/BitcoinSharp
        /// <exception cref="BitcoinSharp.Blockchain.Store.BlockStoreException" />
        /// <exception cref="VerificationException" />
        /// <exception cref="ScriptException" />
        private bool Add(Block block, bool tryConnecting)
        {
            lock (this)
            {
                if (Environment.TickCount - _statsLastTime > 1000)
                {
                    // More than a second passed since last stats logging.
                    Log.InfoFormat("{0} blocks per second", _statsBlocksAdded);
                    _statsLastTime = Environment.TickCount;
                    _statsBlocksAdded = 0;
                }
                // We check only the chain head for double adds here to avoid potentially expensive block chain misses.
                if (block.Equals(_chainHead.BlockHeader))
                {
                    // Duplicate add of the block at the top of the chain, can be a natural artifact of the download process.
                    return true;
                }

                // Does this block contain any transactions we might care about? Check this up front before verifying the
                // blocks validity so we can skip the merkle root verification if the contents aren't interesting. This saves
                // a lot of time for big blocks.
                var contentsImportant = false;
                var walletToTransactionMap = new Dictionary<IDefaultWallet, List<Transaction>>();
                if (block.Transactions != null)
                {
                    ScanTransactions(block, walletToTransactionMap);
                    contentsImportant = walletToTransactionMap.Count > 0;
                }

                // Prove the block is internally valid: hash is lower than target, etc. This only checks the block contents
                // if there is a tx sending or receiving coins using an address in one of our wallets. And those transactions
                // are only lightly verified: presence in a valid connecting block is taken as proof of validity. See the
                // article here for more details: http://code.google.com/p/bitcoinj/wiki/SecurityModel
                try
                {
                    block.VerifyHeader();
                    if (contentsImportant)
                        block.VerifyTransactions();
                }
                catch (VerificationException e)
                {
                    Log.Error("Failed to verify block:", e);
                    Log.Error(block.HashAsString);
                    throw;
                }

                // Try linking it to a place in the currently known blocks.
                var previousStoredBlock = _blockStore.Get(block.PreviousBlockHash);

                if (previousStoredBlock == null)
                {
                    // We can't find the previous block. Probably we are still in the process of downloading the chain and a
                    // block was solved whilst we were doing it. We put it to one side and try to connect it later when we
                    // have more blocks.
                    Log.WarnFormat("Block does not connect: {0}", block.HashAsString);
                    _unconnectedBlocks.Add(block);
                    return false;
                }
                // It connects to somewhere on the chain. Not necessarily the top of the best known chain.
                //
                // Create a new StoredBlock from this block. It will throw away the transaction data so when block goes
                // out of scope we will reclaim the used memory.
                var newStoredBlock = previousStoredBlock.Build(block);
                CheckDifficultyTransitions(previousStoredBlock, newStoredBlock);
                _blockStore.Put(newStoredBlock);
                ConnectBlock(newStoredBlock, previousStoredBlock, walletToTransactionMap);

                if (tryConnecting)
                    TryConnectingUnconnected();

                _statsBlocksAdded++;
                return true;
            }
        }
コード例 #14
0
ファイル: BlockChain.cs プロジェクト: perljedi/BitcoinSharp
 /// <summary>
 ///     Processes a received block and tries to add it to the chain. If there's something wrong with the block an
 ///     exception is thrown. If the block is OK but cannot be connected to the chain at this time, returns false.
 ///     If the block can be connected to the chain, returns true.
 /// </summary>
 /// <exception cref="VerificationException" />
 /// <exception cref="ScriptException" />
 public bool Add(Block block)
 {
     lock (this)
     {
         return Add(block, true);
     }
 }
コード例 #15
0
ファイル: BlockTest.cs プロジェクト: perljedi/BitcoinSharp
 public void TestProofOfWork()
 {
     // This params accepts any difficulty target.
     var @params = NetworkParameters.UnitTests();
     var block = new Block(@params, _blockBytes);
     block.Nonce = 12346;
     try
     {
         block.Verify();
         Assert.Fail();
     }
     catch (VerificationException)
     {
         // Expected.
     }
     // Blocks contain their own difficulty target. The BlockChain verification mechanism is what stops real blocks
     // from containing artificially weak difficulties.
     block.TargetDifficulty = Block.EasiestDifficultyTarget;
     // Now it should pass.
     block.Verify();
     // Break the nonce again at the lower difficulty level so we can try solving for it.
     block.Nonce = 1;
     try
     {
         block.Verify();
         Assert.Fail();
     }
     catch (VerificationException)
     {
         // Expected to fail as the nonce is no longer correct.
     }
     // Should find an acceptable nonce.
     block.Solve();
     block.Verify();
     Assert.AreEqual(block.Nonce, 2U);
 }
コード例 #16
0
 public virtual void OnBlocksDownloaded(Peer peer, Block block, int blocksLeft)
 {
 }
コード例 #17
0
 /// <exception cref="System.IO.IOException"/>
 /// <exception cref="BlockStoreException"/>
 private void Load(FileInfo file)
 {
     _log.InfoFormat("Reading block store from {0}", file);
     using (var input = file.OpenRead())
     {
         // Read a version byte.
         var version = input.Read();
         if (version == -1)
         {
             // No such file or the file was empty.
             throw new FileNotFoundException(file.Name + " does not exist or is empty");
         }
         if (version != 1)
         {
             throw new BlockStoreException("Bad version number: " + version);
         }
         // Chain head pointer is the first thing in the file.
         var chainHeadHash = new byte[32];
         if (StreamExtensions.Read(input, chainHeadHash) < chainHeadHash.Length)
             throw new BlockStoreException("Truncated block store: cannot read chain head hash");
         _chainHead = new Sha256Hash(chainHeadHash);
         _log.InfoFormat("Read chain head from disk: {0}", _chainHead);
         var now = Environment.TickCount;
         // Rest of file is raw block headers.
         var headerBytes = new byte[Block.HeaderSize];
         try
         {
             while (true)
             {
                 // Read a block from disk.
                 if (StreamExtensions.Read(input, headerBytes) < 80)
                 {
                     // End of file.
                     break;
                 }
                 // Parse it.
                 var b = new Block(_params, headerBytes);
                 // Look up the previous block it connects to.
                 var prev = Get(b.PreviousBlockHash);
                 StoredBlock s;
                 if (prev == null)
                 {
                     // First block in the stored chain has to be treated specially.
                     if (b.Equals(_params.GenesisBlock))
                     {
                         s = new StoredBlock(_params.GenesisBlock.CloneAsHeader(), _params.GenesisBlock.GetWork(), 0);
                     }
                     else
                     {
                         throw new BlockStoreException("Could not connect " + b.Hash + " to " + b.PreviousBlockHash);
                     }
                 }
                 else
                 {
                     // Don't try to verify the genesis block to avoid upsetting the unit tests.
                     b.VerifyHeader();
                     // Calculate its height and total chain work.
                     s = prev.Build(b);
                 }
                 // Save in memory.
                 _blockMap[b.Hash] = s;
             }
         }
         catch (ProtocolException e)
         {
             // Corrupted file.
             throw new BlockStoreException(e);
         }
         catch (VerificationException e)
         {
             // Should not be able to happen unless the file contains bad blocks.
             throw new BlockStoreException(e);
         }
         var elapsed = Environment.TickCount - now;
         _log.InfoFormat("Block chain read complete in {0}ms", elapsed);
     }
 }
コード例 #18
0
ファイル: BlockTest.cs プロジェクト: perljedi/BitcoinSharp
 public void TestBlockVerification()
 {
     var block = new Block(_params, _blockBytes);
     block.Verify();
     Assert.AreEqual("00000000a6e5eb79dcec11897af55e90cd571a4335383a3ccfbc12ec81085935", block.HashAsString);
 }
コード例 #19
0
ファイル: Block.cs プロジェクト: perljedi/BitcoinSharp
 /// <summary>
 ///     Returns a copy of the block, but without any transactions.
 /// </summary>
 public Block CloneAsHeader()
 {
     var block = new Block(NetworkParameters)
     {
         _nonce = _nonce,
         _previousBlockHash = _previousBlockHash.Duplicate(),
         _merkleRoot = MerkleRoot.Duplicate(),
         _version = _version,
         _time = _time,
         _targetDifficulty = _targetDifficulty,
         Transactions = null,
         _hash = Hash.Duplicate()
     };
     return block;
 }
コード例 #20
0
        public void TestBadDifficulty()
        {
            Assert.IsTrue(_testNetChain.Add(GetBlock1()));
            var b2 = GetBlock2();
            Assert.IsTrue(_testNetChain.Add(b2));
            var params2 = NetworkParameters.TestNet();
            var bad = new Block(params2);
            // Merkle root can be anything here, doesn't matter.
            bad.MerkleRoot = new Sha256Hash(Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
            // Nonce was just some number that made the hash < difficulty limit set below, it can be anything.
            bad.Nonce = 140548933;
            bad.TimeSeconds = 1279242649;
            bad.PreviousBlockHash = b2.Hash;
            // We're going to make this block so easy 50% of solutions will pass, and check it gets rejected for having a
            // bad difficulty target. Unfortunately the encoding mechanism means we cannot make one that accepts all
            // solutions.
            bad.TargetDifficulty = Block.EasiestDifficultyTarget;
            try
            {
                _testNetChain.Add(bad);
                // The difficulty target above should be rejected on the grounds of being easier than the networks
                // allowable difficulty.
                Assert.Fail();
            }
            catch (VerificationException e)
            {
                Assert.IsTrue(e.Message.IndexOf("Target difficulty is bad") >= 0, e.Message);
            }

            // Accept any level of difficulty now.
            params2.ProofOfWorkLimit = new BigInteger("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
            try
            {
                _testNetChain.Add(bad);
                // We should not get here as the difficulty target should not be changing at this point.
                Assert.Fail();
            }
            catch (VerificationException e)
            {
                Assert.IsTrue(e.Message.IndexOf("Unexpected change in difficulty") >= 0, e.Message);
            }

            // TODO: Test difficulty change is not out of range when a transition period becomes valid.
        }
コード例 #21
0
ファイル: Block.cs プロジェクト: perljedi/BitcoinSharp
        /// <summary>
        ///     Returns a solved block that builds on top of this one. This exists for unit tests.
        /// </summary>
        internal Block CreateNextBlock(Address toAddress, uint time)
        {
            var block = new Block(NetworkParameters) {TargetDifficulty = _targetDifficulty};
            block.AddCoinbaseTransaction(EmptyBytes);

            // Add a transaction paying 50 coins to the "to" address.
            var transaction = new Transaction(NetworkParameters);
            transaction.AddOutput(new TransactionOutput(NetworkParameters, transaction, Utils.ToNanoCoins(50, 0),
                toAddress));
            // The input does not really need to be a valid signature, as long as it has the right general form.
            var input = new TransactionInput(NetworkParameters, transaction,
                Script.CreateInputScript(EmptyBytes, EmptyBytes));
            // Importantly the outpoint hash cannot be zero as that's how we detect a coinbase transaction in isolation
            // but it must be unique to avoid 'different' transactions looking the same.
            var counter = new byte[32];
            counter[0] = (byte) _transactionCounter++;
            input.Outpoint.Hash = new Sha256Hash(counter);
            transaction.AddInput(input);
            block.AddTransaction(transaction);

            block.PreviousBlockHash = Hash;
            block.TimeSeconds = time;
            block.Solve();
            block.VerifyHeader();
            return block;
        }
コード例 #22
0
 // Some blocks from the test net.
 private static Block GetBlock2()
 {
     var b2 = new Block(_testNet);
     b2.MerkleRoot = new Sha256Hash(Hex.Decode("addc858a17e21e68350f968ccd384d6439b64aafa6c193c8b9dd66320470838b"));
     b2.Nonce = 2642058077;
     b2.TimeSeconds = 1296734343;
     b2.PreviousBlockHash = new Sha256Hash(Hex.Decode("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604"));
     Assert.AreEqual("000000037b21cac5d30fc6fda2581cf7b2612908aed2abbcc429c45b0557a15f", b2.HashAsString);
     b2.VerifyHeader();
     return b2;
 }
コード例 #23
0
ファイル: TestUtils.cs プロジェクト: perljedi/BitcoinSharp
 /// <exception cref="BitcoinSharp.Blockchain.Store.BlockStoreException"/>
 public static Block MakeSolvedTestBlock(NetworkParameters @params, Block prev)
 {
     var b = prev.CreateNextBlock(new EcKey().ToAddress(@params));
     b.Solve();
     return b;
 }