/// <exception cref="ProtocolException"/> protected override void Parse() { _version = ReadUint32(); _prevBlockHash = ReadHash(); _merkleRoot = ReadHash(); _time = ReadUint32(); _difficultyTarget = ReadUint32(); _nonce = ReadUint32(); _hash = new Sha256Hash(Utils.ReverseBytes(Utils.DoubleDigest(Bytes, 0, Cursor))); if (Cursor == Bytes.Length) { // This message is just a header, it has no transactions. return; } var numTransactions = (int)ReadVarInt(); Transactions = new List <Transaction>(numTransactions); for (var i = 0; i < numTransactions; i++) { var tx = new Transaction(Params, Bytes, Cursor); Transactions.Add(tx); Cursor += tx.MessageSize; } }
/// <summary> /// Special case constructor, used for the genesis node, cloneAsHeader and unit tests. /// </summary> internal Block(NetworkParameters networkParams) : base(networkParams) { // Set up a few basic things. We are not complete after this though. _version = 1; _difficultyTarget = 0x1d07fff8; _time = (uint)UnixTime.ToUnixTime(DateTime.UtcNow); _prevBlockHash = Sha256Hash.ZeroHash; }
/// <summary> /// Adds a transaction to this block. /// </summary> internal void AddTransaction(Transaction t) { if (Transactions == null) { Transactions = new List <Transaction>(); } Transactions.Add(t); // Force a recalculation next time the values are needed. _merkleRoot = null; _hash = null; }
/// <exception cref="IOException"/> private void BlockChainDownload(Sha256Hash toHash) { // This may run in ANY thread. // The block chain download process is a bit complicated. Basically, we start with zero or more blocks in a // chain that we have from a previous session. We want to catch up to the head of the chain BUT we don't know // where that chain is up to or even if the top block we have is even still in the chain - we // might have got ourselves onto a fork that was later resolved by the network. // // To solve this, we send the peer a block locator which is just a list of block hashes. It contains the // blocks we know about, but not all of them, just enough of them so the peer can figure out if we did end up // on a fork and if so, what the earliest still valid block we know about is likely to be. // // Once it has decided which blocks we need, it will send us an inv with up to 500 block messages. We may // have some of them already if we already have a block chain and just need to catch up. Once we request the // last block, if there are still more to come it sends us an "inv" containing only the hash of the head // block. // // That causes us to download the head block but then we find (in processBlock) that we can't connect // it to the chain yet because we don't have the intermediate blocks. So we rerun this function building a // new block locator describing where we're up to. // // The getblocks with the new locator gets us another inv with another bunch of blocks. We download them once // again. This time when the peer sends us an inv with the head block, we already have it so we won't download // it again - but we recognize this case as special and call back into blockChainDownload to continue the // process. // // So this is a complicated process but it has the advantage that we can download a chain of enormous length // in a relatively stateless manner and with constant/bounded memory usage. Log.InfoFormat("blockChainDownload({0})", toHash); // TODO: Block locators should be abstracted out rather than special cased here. var blockLocator = new LinkedList <Sha256Hash>(); // We don't do the exponential thinning here, so if we get onto a fork of the chain we will end up // re-downloading the whole thing again. blockLocator.AddLast(_params.GenesisBlock.Hash); var topBlock = _blockChain.ChainHead.Header; if (!topBlock.Equals(_params.GenesisBlock)) { blockLocator.AddFirst(topBlock.Hash); } var message = new GetBlocksMessage(_params, blockLocator.ToList(), toHash); _conn.WriteMessage(message); }
/// <summary> /// Asks the connected peer for the block of the given hash, and returns a Future representing the answer. /// If you want the block right away and don't mind waiting for it, just call .get() on the result. Your thread /// will block until the peer answers. You can also use the Future object to wait with a timeout, or just check /// whether it's done later. /// </summary> /// <param name="blockHash">Hash of the block you were requesting.</param> /// <exception cref="IOException"/> public IAsyncResult BeginGetBlock(Sha256Hash blockHash, AsyncCallback callback, object state) { var getdata = new GetDataMessage(_params); var inventoryItem = new InventoryItem(InventoryItem.ItemType.Block, blockHash); getdata.AddItem(inventoryItem); var future = new GetDataFuture <Block>(inventoryItem, callback, state); // Add to the list of things we're waiting for. It's important this come before the network send to avoid // race conditions. lock (_pendingGetBlockFutures) { _pendingGetBlockFutures.Add(future); } _conn.WriteMessage(getdata); return(future); }
/// <exception cref="IOException"/> private void BlockChainDownload(Sha256Hash toHash) { // This may run in ANY thread. // The block chain download process is a bit complicated. Basically, we start with zero or more blocks in a // chain that we have from a previous session. We want to catch up to the head of the chain BUT we don't know // where that chain is up to or even if the top block we have is even still in the chain - we // might have got ourselves onto a fork that was later resolved by the network. // // To solve this, we send the peer a block locator which is just a list of block hashes. It contains the // blocks we know about, but not all of them, just enough of them so the peer can figure out if we did end up // on a fork and if so, what the earliest still valid block we know about is likely to be. // // Once it has decided which blocks we need, it will send us an inv with up to 500 block messages. We may // have some of them already if we already have a block chain and just need to catch up. Once we request the // last block, if there are still more to come it sends us an "inv" containing only the hash of the head // block. // // That causes us to download the head block but then we find (in processBlock) that we can't connect // it to the chain yet because we don't have the intermediate blocks. So we rerun this function building a // new block locator describing where we're up to. // // The getblocks with the new locator gets us another inv with another bunch of blocks. We download them once // again. This time when the peer sends us an inv with the head block, we already have it so we won't download // it again - but we recognize this case as special and call back into blockChainDownload to continue the // process. // // So this is a complicated process but it has the advantage that we can download a chain of enormous length // in a relatively stateless manner and with constant/bounded memory usage. Log.InfoFormat("blockChainDownload({0})", toHash); // TODO: Block locators should be abstracted out rather than special cased here. var blockLocator = new LinkedList<Sha256Hash>(); // We don't do the exponential thinning here, so if we get onto a fork of the chain we will end up // re-downloading the whole thing again. blockLocator.AddLast(_params.GenesisBlock.Hash); var topBlock = _blockChain.ChainHead.Header; if (!topBlock.Equals(_params.GenesisBlock)) blockLocator.AddFirst(topBlock.Hash); var message = new GetBlocksMessage(_params, blockLocator.ToList(), toHash); _conn.WriteMessage(message); }
/// <summary> /// Asks the connected peer for the block of the given hash, and returns a Future representing the answer. /// If you want the block right away and don't mind waiting for it, just call .get() on the result. Your thread /// will block until the peer answers. You can also use the Future object to wait with a timeout, or just check /// whether it's done later. /// </summary> /// <param name="blockHash">Hash of the block you were requesting.</param> /// <exception cref="IOException"/> public IAsyncResult BeginGetBlock(Sha256Hash blockHash, AsyncCallback callback, object state) { var getdata = new GetDataMessage(_params); var inventoryItem = new InventoryItem(InventoryItem.ItemType.Block, blockHash); getdata.AddItem(inventoryItem); var future = new GetDataFuture<Block>(inventoryItem, callback, state); // Add to the list of things we're waiting for. It's important this come before the network send to avoid // race conditions. lock (_pendingGetBlockFutures) { _pendingGetBlockFutures.Add(future); } _conn.WriteMessage(getdata); return future; }
public GetBlocksMessage(NetworkParameters networkParams, IList<Sha256Hash> locator, Sha256Hash stopHash) : base(networkParams) { _locator = locator; _stopHash = stopHash; }
/// <exception cref="ProtocolException"/> protected override void Parse() { _version = ReadUint32(); _prevBlockHash = ReadHash(); _merkleRoot = ReadHash(); _time = ReadUint32(); _difficultyTarget = ReadUint32(); _nonce = ReadUint32(); _hash = new Sha256Hash(Utils.ReverseBytes(Utils.DoubleDigest(Bytes, 0, Cursor))); if (Cursor == Bytes.Length) { // This message is just a header, it has no transactions. return; } var numTransactions = (int) ReadVarInt(); Transactions = new List<Transaction>(numTransactions); for (var i = 0; i < numTransactions; i++) { var tx = new Transaction(Params, Bytes, Cursor); Transactions.Add(tx); Cursor += tx.MessageSize; } }
/// <summary> /// Adds a transaction to this block. /// </summary> internal void AddTransaction(Transaction t) { if (Transactions == null) { Transactions = new List<Transaction>(); } Transactions.Add(t); // Force a recalculation next time the values are needed. _merkleRoot = null; _hash = null; }
/// <summary> /// Special case constructor, used for the genesis node, cloneAsHeader and unit tests. /// </summary> internal Block(NetworkParameters networkParams) : base(networkParams) { // Set up a few basic things. We are not complete after this though. _version = 1; _difficultyTarget = 0x1d07fff8; _time = (uint) UnixTime.ToUnixTime(DateTime.UtcNow); _prevBlockHash = Sha256Hash.ZeroHash; }
public GetBlocksMessage(NetworkParameters networkParams, IList <Sha256Hash> locator, Sha256Hash stopHash) : base(networkParams) { _locator = locator; _stopHash = stopHash; }