private IList <byte[]> BuildMerkleTree() { // The Merkle root is based on a tree of hashes calculated from the transactions: // // root // /\ // / \ // A B // / \ / \ // t1 t2 t3 t4 // // The tree is represented as a list: t1,t2,t3,t4,A,B,root where each entry is a hash. // // The hashing algorithm is double SHA-256. The leaves are a hash of the serialized contents of the // transaction. The interior nodes are hashes of the concentration of the two child hashes. // // This structure allows the creation of proof that a transaction was included into a block without having to // provide the full block contents. Instead, you can provide only a Merkle branch. For example to prove tx2 was // in a block you can just provide tx2, the hash(tx1) and B. Now the other party has everything they need to // derive the root, which can be checked against the block header. These proofs aren't used right now but // will be helpful later when we want to download partial block contents. // // Note that if the number of transactions is not a power of two the last tx is repeated to make it so (see // tx3 above). A tree with 5 transactions would look like this: // // root // / \ // / \ // 1 6 // / \ / \ // 2 3 4 5 // / \ / \ / \ / \ // t1 t2 t3 t4 t5 t5 t5 t5 var tree = new List <byte[]>(); // Start by adding all the hashes of the transactions as leaves of the tree. foreach (var t in Transactions) { tree.Add(t.Hash.Hash); } var levelOffset = 0; // Offset in the list where the currently processed level starts. // Step through each level, stopping when we reach the root (levelSize == 1). for (var levelSize = Transactions.Count; levelSize > 1; levelSize = (levelSize + 1) / 2) { // For each pair of nodes on that level: for (var left = 0; left < levelSize; left += 2) { // The right hand node can be the same as the left hand, in the case where we don't have enough // transactions to be a power of two. var right = Math.Min(left + 1, levelSize - 1); var leftBytes = Utils.ReverseBytes(tree[levelOffset + left]); var rightBytes = Utils.ReverseBytes(tree[levelOffset + right]); tree.Add(Utils.ReverseBytes(Utils.DoubleDigestTwoBuffers(leftBytes, 0, 32, rightBytes, 0, 32))); } // Move to the next level. levelOffset += levelSize; } return(tree); }
/// <exception cref="BitCoinSharp.ProtocolException" /> protected override void Parse() { _version = ReadUint32(); // First come the inputs. var numInputs = ReadVarInt(); _inputs = new List <TransactionInput>((int)numInputs); for (var i = 0UL; i < numInputs; i++) { var input = new TransactionInput(Params, this, Bytes, Cursor); _inputs.Add(input); Cursor += input.MessageSize; } // Now the outputs var numOutputs = ReadVarInt(); _outputs = new List <TransactionOutput>((int)numOutputs); for (var i = 0UL; i < numOutputs; i++) { var output = new TransactionOutput(Params, this, Bytes, Cursor); _outputs.Add(output); Cursor += output.MessageSize; } _lockTime = ReadUint32(); // Store a hash, it may come in useful later (want to avoid re-serialization costs). _hash = new Sha256Hash(Utils.ReverseBytes(Utils.DoubleDigest(Bytes, Offset, Cursor - Offset))); }
/// <exception cref="BitCoinSharp.ProtocolException" /> protected override void Parse() { _version = ReadUint32(); _prevBlockHash = ReadHash(); _merkleRoot = ReadHash(); _time = ReadUint32(); _difficultyTarget = ReadUint32(); _nonce = ReadUint32(); _hash = 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> /// Calculates the block hash by serializing the block and hashing the resulting bytes. /// </summary> private byte[] CalculateHash() { using (var bos = new MemoryStream()) { WriteHeader(bos); return(Utils.ReverseBytes(Utils.DoubleDigest(bos.ToArray()))); } }
/// <exception cref="System.IO.IOException" /> private void WriteHeader(Stream stream) { Utils.Uint32ToByteStreamLe(_version, stream); stream.Write(Utils.ReverseBytes(_prevBlockHash)); stream.Write(Utils.ReverseBytes(MerkleRoot)); Utils.Uint32ToByteStreamLe(_time, stream); Utils.Uint32ToByteStreamLe(_difficultyTarget, stream); Utils.Uint32ToByteStreamLe(_nonce, stream); }
/// <exception cref="IOException"/> public override void BitcoinSerializeToStream(Stream stream) { stream.Write(new VarInt((ulong)_items.Count).Encode()); foreach (var i in _items) { // Write out the type code. Utils.Uint32ToByteStreamLe((uint)i.Type, stream); // And now the hash. stream.Write(Utils.ReverseBytes(i.Hash.Bytes)); } }
internal Sha256Hash ReadHash() { var hash = new byte[32]; Array.Copy(Bytes, Cursor, hash, 0, 32); // We have to flip it around, as it's been read off the wire in little endian. // Not the most efficient way to do this but the clearest. hash = Utils.ReverseBytes(hash); Cursor += 32; return(new Sha256Hash(hash)); }
public override byte[] BitcoinSerialize() { using (var buf = new MemoryStream()) { // Version, for some reason. Utils.Uint32ToByteStreamLe(NetworkParameters.ProtocolVersion, buf); // Then a vector of block hashes. This is actually a "block locator", a set of block // identifiers that spans the entire chain with exponentially increasing gaps between // them, until we end up at the genesis block. See CBlockLocator::Set() buf.Write(new VarInt((ulong) _locator.Count).Encode()); foreach (var hash in _locator) { // Have to reverse as wire format is little endian. buf.Write(Utils.ReverseBytes(hash.Bytes)); } // Next, a block ID to stop at. buf.Write(_stopHash.Bytes); return buf.ToArray(); } }
/// <exception cref="IOException"/> public override void BitcoinSerializeToStream(Stream stream) { stream.Write(Utils.ReverseBytes(Hash.Bytes)); Utils.Uint32ToByteStreamLe((uint)Index, stream); }
/// <exception cref="System.IO.IOException" /> public override void BitcoinSerializeToStream(Stream stream) { Debug.Assert(Hash.Length == 32); stream.Write(Utils.ReverseBytes(Hash)); Utils.Uint32ToByteStreamLe((uint)Index, stream); }