6
6
7
7
use drupol \phpmerkle \Hasher \DoubleSha256 ;
8
8
use drupol \phpmerkle \Hasher \HasherInterface ;
9
+ use drupol \phptree \Modifier \FulfillCapacity ;
10
+ use drupol \phptree \Modifier \RemoveNullNode ;
9
11
10
12
/**
11
13
* Class MerkleNode.
12
14
*/
13
- class MerkleNode extends ValueNode
15
+ class MerkleNode extends ValueNode implements MerkleNodeInterface
14
16
{
15
17
/**
16
18
* @var \drupol\phpmerkle\Hasher\HasherInterface
17
19
*/
18
20
private $ hasher ;
19
21
22
+ /**
23
+ * @var \drupol\phptree\Modifier\ModifierInterface[]
24
+ */
25
+ private $ modifiers ;
26
+
20
27
/**
21
28
* MerkleNode constructor.
22
29
*
@@ -32,6 +39,10 @@ public function __construct(
32
39
parent ::__construct ($ value , $ capacity , null , null );
33
40
34
41
$ this ->hasher = $ hasher ?? new DoubleSha256 ();
42
+ $ this ->modifiers = [
43
+ new RemoveNullNode (),
44
+ new FulfillCapacity (),
45
+ ];
35
46
}
36
47
37
48
/**
@@ -43,60 +54,40 @@ public function getValue()
43
54
return parent ::getValue ();
44
55
}
45
56
46
- return $ this ->clone ()-> hash ();
57
+ return $ this ->hash ();
47
58
}
48
59
49
60
/**
50
61
* {@inheritdoc}
51
62
*/
52
- private function doHash (): string
63
+ public function normalize (): MerkleNodeInterface
53
64
{
54
- // If node is a leaf, then compute its hash from its value.
55
- if (true === $ this ->isLeaf ()) {
56
- $ value = $ this ->getValue ();
57
-
58
- if (null === $ value ) {
59
- return '' ;
60
- }
65
+ $ tree = $ this ->clone ();
61
66
62
- return $ this ->hasher ->hash ($ value );
67
+ foreach ($ this ->modifiers as $ modifier ) {
68
+ $ tree = $ modifier ->modify ($ tree );
63
69
}
64
70
65
- // Remove all nodes with null value.
66
- if (null !== $ parent = $ this ->getParent ()) {
67
- /** @var \drupol\phptree\Node\MerkleNode $node */
68
- foreach ($ parent ->all () as $ node ) {
69
- if (false === $ node ->isLeaf ()) {
70
- continue ;
71
- }
72
-
73
- if (null !== $ node ->getValue ()) {
74
- continue ;
75
- }
76
-
77
- $ node ->getParent ()->remove ($ node );
71
+ /** @var \drupol\phptree\Node\MerkleNodeInterface $tree */
72
+ return $ tree ;
73
+ }
78
74
79
- return $ this ->hash ();
80
- }
75
+ /**
76
+ * {@inheritdoc}
77
+ */
78
+ private function doHash (MerkleNodeInterface $ node ): string
79
+ {
80
+ // If node is a leaf, then compute its hash from its value.
81
+ if (true === $ node ->isLeaf ()) {
82
+ return $ this ->hasher ->hash ($ node ->getValue ());
81
83
}
82
84
83
- // If node with children is not fulfilled, make sure it is complete.
84
- if ($ this ->degree () !== $ this ->capacity ()) {
85
- $ children = iterator_to_array ($ this ->children ());
86
-
87
- if ([] !== $ children ) {
88
- $ this ->add (current ($ children )->clone ());
89
- }
85
+ $ hash = '' ;
86
+ /** @var \drupol\phptree\Node\MerkleNodeInterface $child */
87
+ foreach ($ node ->children () as $ child ) {
88
+ $ hash .= $ this ->doHash ($ child );
90
89
}
91
90
92
- $ hash = array_reduce (
93
- iterator_to_array ($ this ->children ()),
94
- static function ($ carry , MerkleNode $ node ): string {
95
- return $ carry . $ node ->doHash ();
96
- },
97
- ''
98
- );
99
-
100
91
return $ this ->hasher ->hash ($ hash );
101
92
}
102
93
@@ -105,6 +96,6 @@ static function ($carry, MerkleNode $node): string {
105
96
*/
106
97
private function hash (): string
107
98
{
108
- return $ this ->hasher ->unpack ($ this ->doHash ());
99
+ return $ this ->hasher ->unpack ($ this ->doHash ($ this -> normalize () ));
109
100
}
110
101
}
0 commit comments