dcha 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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