dcha 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,64 @@
1
+ module Dcha
2
+ module MPT
3
+ # :nodoc:
4
+ class Node < Array
5
+ autoload :Findable, 'dcha/mpt/node/findable'
6
+ autoload :Editable, 'dcha/mpt/node/editable'
7
+ autoload :Deletable, 'dcha/mpt/node/deletable'
8
+ autoload :ToHashable, 'dcha/mpt/node/to_hashable'
9
+
10
+ class << self
11
+ def decode(encoded)
12
+ return BLANK if encoded == BLANK.first
13
+ return encoded if encoded.is_a?(Node)
14
+ return new encoded if encoded.is_a?(Array)
15
+ new RLP.decode(Config.store[encoded])
16
+ end
17
+ end
18
+
19
+ BLANK = new(['']).freeze
20
+
21
+ BRANCH_CARDINAL = 16
22
+ BRANCH_WIDTH = BRANCH_CARDINAL + 1
23
+ KV_WIDTH = 2
24
+
25
+ include Node::Findable
26
+ include Node::Editable
27
+ include Node::Deletable
28
+ include Node::ToHashable
29
+
30
+ def type
31
+ return :blank if size == 1 && first.empty?
32
+
33
+ case size
34
+ when KV_WIDTH
35
+ NibbleKey.decode(first).terminate? ? :leaf : :extension
36
+ when BRANCH_WIDTH
37
+ :branch
38
+ end
39
+ end
40
+
41
+ def tree_size
42
+ case type
43
+ when :branch
44
+ children = take(BRANCH_CARDINAL).map(&:tree_size)
45
+ children.push(last != BLANK ? 0 : 1)
46
+ size.reduce(0, &:+)
47
+ when :extension then Node.decode(self[1]).tree_size
48
+ when :leaf then 1
49
+ when :blank then 0
50
+ end
51
+ end
52
+
53
+ def save(force = false)
54
+ value = RLP.encode self
55
+ return self if value.size < 32 && !force
56
+ key = Config.digest.hexdigest(value)
57
+
58
+ Config.store[key] = value
59
+
60
+ key
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,83 @@
1
+ module Dcha
2
+ module MPT
3
+ class Node < Array
4
+ # :nodoc:
5
+ module Deletable
6
+ def delete(key)
7
+ case type
8
+ when :blank then Node::BLANK
9
+ when :branch then delete_branch_node(key)
10
+ else
11
+ delete_kv_node(key)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def delete_branch_node(key)
18
+ if key.empty?
19
+ self[-1] = Node::BLANK
20
+ return normalize
21
+ end
22
+
23
+ new_sub_node = Node.decode(self[key[0]]).delete(key[1..-1])
24
+ encoded_new_sub_node = new_sub_node.save
25
+ return self if encoded_new_sub_node == self[key[0]]
26
+
27
+ self[key[0]] = encoded_new_sub_node
28
+ return normalize if encoded_new_sub_node == Node::BLANK
29
+
30
+ self
31
+ end
32
+
33
+ def delete_kv_node(key)
34
+ node_key = NibbleKey.decode(first).terminate(false)
35
+ return self unless node_key.prefix?(key)
36
+ return key == node_key ? Node::BLANK : self if type == :leaf
37
+
38
+ new_sub_node = Node.decode(self[1]).delete(key[node_key.size..-1])
39
+
40
+ replace_with_new_sub_node(node_key, new_sub_node)
41
+ end
42
+
43
+ def replace_with_new_sub_node(node_key, new_sub_node)
44
+ return self if new_sub_node.save == self[1]
45
+ return Node::BLANK if new_sub_node == Node::BLANK
46
+
47
+ case new_sub_node.type
48
+ when :branch
49
+ Node.new([node_key.encode, new_sub_node.save])
50
+ when :leaf, :extension
51
+ new_key = node_key + NibbleKey.decode(new_sub_node[0])
52
+ Node.new([new_key.encode, new_sub_node[1]])
53
+ end
54
+ end
55
+
56
+ def normalize
57
+ return self if non_blank_items.size > 1
58
+
59
+ non_blank_index = non_blank_items[0][1]
60
+ new_node = Node.new([NibbleKey.new([]).terminate(true).encode, last])
61
+ return new_node if non_blank_index == NibbleKey::TERMINATOR
62
+
63
+ replace_with_sub_node(non_blank_index)
64
+ end
65
+
66
+ def replace_with_sub_node(non_blank_index)
67
+ sub_node = Node.decode(self[non_blank_index])
68
+ case sub_node.type
69
+ when :branch
70
+ Node.new([NibbleKey.new([non_blank_index]).encode, sub_node.save])
71
+ when :leaf, :extension
72
+ new_key = NibbleKey.decode(sub_node[0]).unshift(non_blank_index)
73
+ Node.new(new_key.encode, sub_node[1])
74
+ end
75
+ end
76
+
77
+ def non_blank_items
78
+ each_with_index.reject { |(x, _)| x == Node::BLANK }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,135 @@
1
+ # rubocop:disable Metrics/LineLength
2
+ module Dcha
3
+ module MPT
4
+ class Node < Array
5
+ # :nodoc:
6
+ module Editable
7
+ def update(key, value)
8
+ case type
9
+ when :blank then
10
+ dup.clear.push key.terminate(true).encode, value
11
+ when :branch then update_branch(key, value)
12
+ when :leaf then update_leaf(key, value)
13
+ else update_extension(key, value)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def update_branch(key, value)
20
+ return dup.tap { |copy| copy[-1] = value } if key.empty?
21
+
22
+ new_node = Node.decode(self[key[0]])
23
+ .update(key[1..-1], value)
24
+ dup.tap do |copy|
25
+ copy[key[0]] = new_node
26
+ end
27
+ end
28
+
29
+ def update_leaf(key, value)
30
+ node_key, common_key, remain_key, remain_node_key = common_key_pairs(key)
31
+
32
+ no_remain_key = remain_key.empty? && remain_node_key.empty?
33
+ return dup.clear.push first, value if no_remain_key
34
+
35
+ new_node = if remain_node_key.empty?
36
+ convert_leaf_to_branch_node(remain_key, value)
37
+ else
38
+ expand_leaf_to_branch_node(remain_key, remain_node_key, value)
39
+ end
40
+
41
+ apply_node(common_key, node_key, new_node)
42
+ end
43
+
44
+ def apply_node(common_key, node_key, new_node)
45
+ if common_key.empty?
46
+ dup.clear.concat new_node
47
+ else
48
+ dup.clear.push node_key[0, common_key.size].encode,
49
+ Node.new(new_node).save
50
+ end
51
+ end
52
+
53
+ def convert_leaf_to_branch_node(key, value)
54
+ new_node = Node::BLANK * Node::BRANCH_WIDTH
55
+ new_node[-1] = self[1]
56
+
57
+ new_node[key[0]] = Node.new(
58
+ [
59
+ key[1..-1].terminate(true).encode,
60
+ value
61
+ ]
62
+ ).save
63
+ new_node
64
+ end
65
+
66
+ def expand_leaf_to_branch_node(key, node_key, value)
67
+ new_node = convert_leaf_to_branch_node(node_key, self[1])
68
+
69
+ if key.empty?
70
+ new_node[-1] = value
71
+ else
72
+ new_node[key[0]] = Node.new(
73
+ [key[1..-1].terminate(true).encode, value]
74
+ ).save
75
+ end
76
+
77
+ new_node
78
+ end
79
+
80
+ def update_extension(key, value)
81
+ node_key, common_key, remain_key, remain_node_key = common_key_pairs(key)
82
+
83
+ new_node = if remain_node_key.empty?
84
+ Node.decode(self[1]).update(remain_key, value)
85
+ else
86
+ expand_extension_to_branch_node(
87
+ remain_key, remain_node_key, value
88
+ )
89
+ end
90
+ apply_node(common_key, node_key, new_node)
91
+ end
92
+
93
+ def convert_extension_to_branch_node(key, value)
94
+ new_node = Node::BLANK * Node::BRANCH_WIDTH
95
+
96
+ if key.size == 1
97
+ new_node[key[0]] = value
98
+ return new_node
99
+ end
100
+
101
+ new_node[key[0]] = Node.new(
102
+ [key[1..-1].terminate(false).encode, value]
103
+ ).save
104
+
105
+ new_node
106
+ end
107
+
108
+ def expand_extension_to_branch_node(key, node_key, value)
109
+ new_node = convert_extension_to_branch_node(node_key, self[1])
110
+
111
+ if key.empty?
112
+ new_node[-1] = value
113
+ return new_node
114
+ end
115
+
116
+ new_node[key[0]] = Node.new(
117
+ [key[1..-1].terminate(true).encode, value]
118
+ ).save
119
+
120
+ new_node
121
+ end
122
+
123
+ def common_key_pairs(key)
124
+ node_key = NibbleKey.decode(first).terminate(false)
125
+
126
+ common = node_key.common_prefix(key)
127
+ remain = key[common.size..-1]
128
+ remain_node = node_key[common.size..-1]
129
+
130
+ [node_key, common, remain, remain_node]
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,37 @@
1
+ module Dcha
2
+ module MPT
3
+ class Node < Array
4
+ # :nodoc:
5
+ module Findable
6
+ def find(nbk)
7
+ case type
8
+ when :blank then Node::BLANK.first
9
+ when :branch then find_branch(nbk)
10
+ when :leaf then find_leaf(nbk)
11
+ when :extension then find_extension(nbk)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def find_branch(nbk)
18
+ return last if nbk.empty?
19
+ node = Node.decode(self[nbk[0]])
20
+ node.find(nbk[1..-1])
21
+ end
22
+
23
+ def find_leaf(nbk)
24
+ key = NibbleKey.decode(first).terminate(false)
25
+ nbk == key ? self[1] : Node::BLANK.first
26
+ end
27
+
28
+ def find_extension(nbk)
29
+ key = NibbleKey.decode(first).terminate(false)
30
+ return Node::BLANK.first unless key.prefix?(nbk)
31
+ node = Node.decode(self[1])
32
+ node.find nbk[key.size..-1]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+ module Dcha
2
+ module MPT
3
+ class Node < Array
4
+ # :nodoc:
5
+ module ToHashable
6
+ def to_h
7
+ case type
8
+ when :blank then {}
9
+ when :branch then branch_to_h
10
+ when :leaf, :extension
11
+ kv_to_h
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def branch_to_h
18
+ hash = {}
19
+ 16.times do |i|
20
+ sub_hash = Node.decode(self[i]).to_h
21
+ sub_hash.each { |k, v| hash[NibbleKey.new([i]) + k] = v }
22
+ end
23
+ hash[NibbleKey.terminator] = last if last
24
+ hash
25
+ end
26
+
27
+ def kv_to_h
28
+ nibbles = NibbleKey.decode(first).terminate(false)
29
+ sub_hash = if type == :extension
30
+ Node.decode(self[1]).to_h
31
+ else
32
+ { NibbleKey.terminator => self[1] }
33
+ end
34
+
35
+ {}.tap do |h|
36
+ sub_hash.each { |k, v| h[nibbles + k] = v }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,73 @@
1
+ module Dcha
2
+ module MPT
3
+ # :nodoc:
4
+ class Trie
5
+ include Enumerable
6
+
7
+ def initialize(hash = nil)
8
+ @root = if hash.nil?
9
+ Node::BLANK
10
+ else
11
+ Node.decode(hash)
12
+ end
13
+ end
14
+
15
+ def root_hash
16
+ return blank_root if @root == Node::BLANK
17
+ @root.save(true)
18
+ end
19
+ alias update_root_hash root_hash
20
+
21
+ def get(key)
22
+ @root.find NibbleKey.from_string(key)
23
+ end
24
+ alias [] get
25
+
26
+ def set(key, value)
27
+ @root = @root.update(
28
+ NibbleKey.from_string(key),
29
+ value
30
+ )
31
+
32
+ update_root_hash
33
+ end
34
+ alias []= set
35
+
36
+ def delete(key)
37
+ @root = @root.delete(NibbleKey.from_string(key))
38
+
39
+ update_root_hash
40
+ end
41
+
42
+ def to_h
43
+ Hash[
44
+ @root.to_h.map do |key, value|
45
+ [
46
+ key.terminate(false).to_s,
47
+ value
48
+ ]
49
+ end
50
+ ]
51
+ end
52
+
53
+ def each(&block)
54
+ to_h.each(&block)
55
+ end
56
+
57
+ def key?(key)
58
+ self[key] != Node::BLANK.first
59
+ end
60
+ alias include? key?
61
+
62
+ def size
63
+ @root.tree_size
64
+ end
65
+
66
+ private
67
+
68
+ def blank_root
69
+ @blank_root ||= Config.digest.hexdigest(RLP.encode('')).freeze
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,28 @@
1
+ module Dcha
2
+ # :nodoc:
3
+ class PacketManager < Hash
4
+ attr_reader :todo
5
+
6
+ def initialize
7
+ @todo = Queue.new
8
+ end
9
+
10
+ def <<(chunk)
11
+ self[chunk.tag] ||= []
12
+ self[chunk.tag] << chunk
13
+ self[chunk.tag].uniq!
14
+
15
+ check(chunk)
16
+ end
17
+
18
+ private
19
+
20
+ def check(chunk)
21
+ return unless self[chunk.tag].size == chunk.total
22
+ event = Oj.load(self[chunk.tag].sort.map(&:to_s).join)
23
+ @todo << event
24
+ # TODO: Release memory if buffer not completed
25
+ delete(chunk.tag)
26
+ end
27
+ end
28
+ end