Beispiel #1
0
        /// <summary>
        /// Given a trie node type, and a pair of nibbles, packs them into a prefix/shared-nibbles pair (extension) or prefix/key-remainder pair (leaf) respectively.
        /// </summary>
        /// <param name="type">The trie node type to pack into the first item of our node.</param>
        /// <param name="nibbles">The nibble array to pack into the first item of our node.</param>
        /// <returns>Returns a packed byte array which represents the new data for the first item of our node.</returns>
        private byte[] PackPrefixedNode(TrieNodeType type, byte[] nibbles)
        {
            // Determine the base prefix for the data (we set our first bit (odd/even) next).
            TrieNodePrefix prefix = TrieNodePrefix.ExtensionNodeEven;

            if (type == TrieNodeType.Leaf)
            {
                prefix = TrieNodePrefix.LeafNodeEven;
            }

            // We set the first bit based off of if it's even or odd length.
            bool oddLength = (nibbles.Length % 2) != 0;

            if (oddLength)
            {
                prefix = (TrieNodePrefix)((int)prefix | 1);
            }

            // If it's odd, just adding our prefix will make it byte-aligned. Otherwise we add a zero after the prefix.
            if (oddLength)
            {
                nibbles = new byte[] { (byte)prefix }.Concat(nibbles);
            }
            else
            {
                nibbles = new byte[] { (byte)prefix, 0 }.Concat(nibbles);
            }

            return(NibbleArrayToByteArray(nibbles));
        }
Beispiel #2
0
        /// <summary>
        /// Given a packed byte array which represents data for the first item of a leaf or extension node, unpacks the data accordingly.
        /// </summary>
        /// <param name="data">The packed data for the node's first item.</param>
        /// <returns>Returns the unpacked data from the provided leaf or extension node's first item. This includes the type of node it is, and the nibble set that constitutes the shared nibbles (extension) or key remainder (leaf).</returns>
        private (TrieNodeType type, byte[] nibbles) UnpackPrefixedNode(byte[] data)
        {
            // Obtain our list of nibbles.
            byte[] nibbles = ByteArrayToNibbleArray(data);

            // Check our prefix and handle our data accordingly.
            TrieNodePrefix prefix = (TrieNodePrefix)nibbles[0];

            if (prefix == TrieNodePrefix.ExtensionNodeEven)
            {
                return(TrieNodeType.Extension, nibbles.Slice(2));
            }
            else if (prefix == TrieNodePrefix.ExtensionNodeOdd)
            {
                return(TrieNodeType.Extension, nibbles.Slice(1));
            }
            else if (prefix == TrieNodePrefix.LeafNodeEven)
            {
                return(TrieNodeType.Leaf, nibbles.Slice(2));
            }
            else if (prefix == TrieNodePrefix.LeafNodeOdd)
            {
                return(TrieNodeType.Leaf, nibbles.Slice(1));
            }

            // Throw our error otherwise.
            throw new ArgumentException("Attempted to unpack invalid trie node type!");
        }
Beispiel #3
0
        // Node types/prefixes/unpacking
        /// <summary>
        /// Given a direct trie node, obtains the type of node.
        /// </summary>
        /// <param name="node">The node to obtain the type of.</param>
        /// <returns>Returns the type of node for the provided node.</returns>
        private TrieNodeType GetNodeType(RLPList node)
        {
            // If this node is null or has no items, we say it's a blank type.
            if (node == null || node.Items.Count == 0)
            {
                return(TrieNodeType.Blank);
            }

            // If it has two items then it is either a leaf or an extension node. We can determine this based off of the use of a terminator.
            if (node.Items.Count == 2)
            {
                // Check our first nibble to obtain prefix, then return our type accordingly. This is faster than unpacking the whole nibble set.
                TrieNodePrefix prefix = (TrieNodePrefix)GetNibble(node.Items[0], 0);
                if (prefix == TrieNodePrefix.ExtensionNodeEven || prefix == TrieNodePrefix.ExtensionNodeOdd)
                {
                    return(TrieNodeType.Extension);
                }
                else
                {
                    return(TrieNodeType.Leaf);
                }
            }

            // Otherwise if it has 17 items, it's a branch node.
            else if (node.Items.Count == 17)
            {
                return(TrieNodeType.Branch);
            }

            // Otherwise this node is not formatted properly.
            throw new ArgumentException("Failed to interpret node type from node prefix in trie.");
        }