Пример #1
0
        /// <summary>
        /// Uses the checksum in the last 4 bytes of the decoded data to verify the rest are correct. The checksum is removed from the returned data.
        /// </summary>
        /// <exception cref="AddressFormatException">If the input is not base 58 or the checksum does not validate.</exception>
        public byte[] DecodeChecked(string input)
        {
            var tmp = Decode(input);

            if (tmp.Length < 4)
            {
                throw new AddressFormatException("Input too short");
            }

            var checksum = new byte[4];

            Array.Copy(tmp, tmp.Length - 4, checksum, 0, 4);

            var bytes = new byte[tmp.Length - 4];

            Array.Copy(tmp, 0, bytes, 0, tmp.Length - 4);

            tmp = DoubleDigestSha256Helper.DoubleDigest(bytes);
            var hash = new byte[4];

            Array.Copy(tmp, 0, hash, 0, 4);
            if (!hash.SequenceEqual(checksum))
            {
                throw new AddressFormatException("Checksum does not validate");
            }
            return(bytes);
        }
Пример #2
0
        /////throws ClassNotFoundException, IOException
        //private void readObject(ObjectInputStream ois)
        //{
        //	ois.defaultReadObject();
        //	// This code is not actually necessary, as transient fields are initialized to the default value which is in
        //	// this case null. However it clears out a FindBugs warning and makes it explicit what we're doing.
        //	hash = null;
        //}

        private void parseHeader()
        {
            if (headerParsed)
            {
                return;
            }

            Cursor            = Offset;
            Version           = ReadUint32();
            PreviousBlockHash = ReadHash();
            MerkleRoot        = ReadHash();
            TimeSeconds       = ReadUint32();
            difficultyTarget  = ReadUint32();
            nonce             = ReadUint32();

            hash = new Sha256Hash(DoubleDigestSha256Helper.DoubleDigest(Bytes, Offset, Cursor).ReverseBytes());

            headerParsed     = true;
            headerBytesValid = ParseRetain;
        }
Пример #3
0
        private List <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 concenation 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 even the last tx is repeated to make it so (see
            // tx3 above). A tree with 5 transactions would look like this:
            //
            //         root
            //        /     \
            //       1        5
            //     /   \     / \
            //    2     3    4  4
            //  / \   / \   / \
            // t1 t2 t3 t4 t5 t5

            EnsureParsedTransactions();
            List <byte[]> tree = new List <byte[]>();

            // Start by adding all the hashes of the transactions as leaves of the tree.
            foreach (Transaction transaction in Transactions)
            {
                tree.Add(transaction.Hash.Bytes);
            }

            int 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 (int levelSize = Transactions.Count; levelSize > 1; levelSize = (levelSize + 1) / 2)
            {
                // For each pair of nodes on that level:
                for (int 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.
                    int    right      = Math.Min(left + 1, levelSize - 1);
                    byte[] leftBytes  = tree[levelOffset + left].ReverseBytes();
                    byte[] rightBytes = tree[levelOffset + right].ReverseBytes();
                    tree.Add(DoubleDigestSha256Helper.DoubleDigestTwoBuffers(leftBytes, 0, 32, rightBytes, 0, 32).ReverseBytes());
                }

                // Move to the next level.
                levelOffset += levelSize;
            }
            return(tree);
        }