Class: Ethereum::Trie
- Includes:
- Enumerable
- Defined in:
- lib/ethereum/trie.rb,
lib/ethereum/trie/nibble_key.rb
Overview
A implementation of Merkle Patricia Tree.
Direct Known Subclasses
Defined Under Namespace
Classes: InvalidNode, InvalidNodeType, NibbleKey
Constant Summary collapse
- NODE_TYPES =
%i(blank leaf extension branch).freeze
- NODE_KV_TYPE =
%i(leaf extension).freeze
- BRANCH_CARDINAL =
16- BRANCH_WIDTH =
BRANCH_CARDINAL + 1
- KV_WIDTH =
2- BLANK_NODE =
"".freeze
- BLANK_ROOT =
Utils.keccak256_rlp('').freeze
Instance Attribute Summary collapse
-
#db ⇒ Object
readonly
Returns the value of attribute db.
Instance Method Summary collapse
-
#[](key) ⇒ String
(also: #get)
Get value from trie.
-
#[]=(key, value) ⇒ Object
(also: #set)
Set value of key.
-
#clear ⇒ Object
clear all tree data.
-
#delete(key) ⇒ Object
Delete value at key.
- #each(&block) ⇒ Object
-
#find(node, nbk) ⇒ String
Get value inside a node.
- #has_key?(key) ⇒ Boolean (also: #include?)
-
#initialize(db, root_hash = BLANK_ROOT) ⇒ Trie
constructor
It presents a hash like interface.
-
#root_hash ⇒ Object
(also: #update_root_hash)
Empty or 32 bytes string.
- #root_hash_valid? ⇒ Boolean
- #set_root_hash(hash) ⇒ Object
-
#size ⇒ Object
Get count of all nodes of the trie.
-
#to_h ⇒ Object
Convert to hash.
Constructor Details
#initialize(db, root_hash = BLANK_ROOT) ⇒ Trie
It presents a hash like interface.
37 38 39 40 |
# File 'lib/ethereum/trie.rb', line 37 def initialize(db, root_hash=BLANK_ROOT) @db = db set_root_hash root_hash end |
Instance Attribute Details
#db ⇒ Object (readonly)
Returns the value of attribute db.
28 29 30 |
# File 'lib/ethereum/trie.rb', line 28 def db @db end |
Instance Method Details
#[](key) ⇒ String Also known as: get
Get value from trie.
85 86 87 |
# File 'lib/ethereum/trie.rb', line 85 def [](key) find @root_node, NibbleKey.from_string(key) end |
#[]=(key, value) ⇒ Object Also known as: set
Set value of key.
96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/ethereum/trie.rb', line 96 def []=(key, value) raise ArgumentError, "key must be string" unless key.instance_of?(String) raise ArgumentError, "value must be string" unless value.instance_of?(String) @root_node = update_and_delete_storage( @root_node, NibbleKey.from_string(key), value ) update_root_hash end |
#clear ⇒ Object
clear all tree data
158 159 160 161 162 |
# File 'lib/ethereum/trie.rb', line 158 def clear delete_child_storage(@root_node) delete_node_storage(@root_node) @root_node = BLANK_NODE end |
#delete(key) ⇒ Object
Delete value at key.
115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/ethereum/trie.rb', line 115 def delete(key) raise ArgumentError, "key must be string" unless key.instance_of?(String) raise ArgumentError, "max key size is 32" if key.size > 32 @root_node = delete_and_delete_storage( @root_node, NibbleKey.from_string(key) ) update_root_hash end |
#each(&block) ⇒ Object
139 140 141 |
# File 'lib/ethereum/trie.rb', line 139 def each(&block) to_h.each(&block) end |
#find(node, nbk) ⇒ String
Get value inside a node.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/ethereum/trie.rb', line 172 def find(node, nbk) node_type = get_node_type node case node_type when :blank BLANK_NODE when :branch return node.last if nbk.empty? sub_node = decode_to_node node[nbk[0]] find sub_node, nbk[1..-1] when :leaf node_key = NibbleKey.decode(node[0]).terminate(false) nbk == node_key ? node[1] : BLANK_NODE when :extension node_key = NibbleKey.decode(node[0]).terminate(false) if node_key.prefix?(nbk) sub_node = decode_to_node node[1] find sub_node, nbk[node_key.size..-1] else BLANK_NODE end else raise InvalidNodeType, "node type must be in #{NODE_TYPES}, given: #{node_type}" end end |
#has_key?(key) ⇒ Boolean Also known as: include?
143 144 145 |
# File 'lib/ethereum/trie.rb', line 143 def has_key?(key) self[key] != BLANK_NODE end |
#root_hash ⇒ Object Also known as: update_root_hash
Returns empty or 32 bytes string.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/ethereum/trie.rb', line 45 def root_hash # TODO: can I memoize computation below? return BLANK_ROOT if @root_node == BLANK_NODE raise InvalidNode, "invalid root node" unless @root_node.instance_of?(Array) val = FastRLP.encode @root_node key = Utils.keccak256 val @db.put key, val SPV.grabbing @root_node key end |
#root_hash_valid? ⇒ Boolean
72 73 74 75 76 |
# File 'lib/ethereum/trie.rb', line 72 def root_hash_valid? h = root_hash return true if h == BLANK_ROOT return @db.include?(h) end |
#set_root_hash(hash) ⇒ Object
61 62 63 64 65 66 67 68 69 70 |
# File 'lib/ethereum/trie.rb', line 61 def set_root_hash(hash) raise TypeError, "root hash must be String" unless hash.instance_of?(String) raise ArgumentError, "root hash must be 0 or 32 bytes long" unless [0,32].include?(hash.size) if hash == BLANK_ROOT @root_node = BLANK_NODE else @root_node = decode_to_node hash end end |
#size ⇒ Object
Get count of all nodes of the trie.
151 152 153 |
# File 'lib/ethereum/trie.rb', line 151 def size get_size @root_node end |
#to_h ⇒ Object
Convert to hash.
130 131 132 133 134 135 136 137 |
# File 'lib/ethereum/trie.rb', line 130 def to_h h = {} to_hash(@root_node).each do |k, v| key = k.terminate(false).to_string h[key] = v end h end |