Coverage Summary for Class: MutableTrieImpl (co.rsk.db)
Class |
Method, %
|
Line, %
|
MutableTrieImpl |
60%
(9/15)
|
52.6%
(20/38)
|
MutableTrieImpl$StorageKeysIterator |
0%
(0/3)
|
0%
(0/19)
|
Total |
50%
(9/18)
|
35.1%
(20/57)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2019 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package co.rsk.db;
20
21 import co.rsk.core.RskAddress;
22 import co.rsk.core.types.ints.Uint24;
23 import co.rsk.crypto.Keccak256;
24 import co.rsk.trie.MutableTrie;
25 import co.rsk.trie.Trie;
26 import co.rsk.trie.TrieKeySlice;
27 import co.rsk.trie.TrieStore;
28 import org.ethereum.db.ByteArrayWrapper;
29 import org.ethereum.db.TrieKeyMapper;
30 import org.ethereum.vm.DataWord;
31
32 import java.util.*;
33
34 public class MutableTrieImpl implements MutableTrie {
35
36 private Trie trie;
37 private TrieKeyMapper trieKeyMapper = new TrieKeyMapper();
38 private TrieStore trieStore;
39
40 public MutableTrieImpl(TrieStore trieStore, Trie trie) {
41 this.trieStore = trieStore;
42 this.trie = trie;
43 }
44
45 @Override
46 public Trie getTrie() {
47 return trie;
48 }
49
50 @Override
51 public Keccak256 getHash() {
52 return trie.getHash();
53 }
54
55 @Override
56 public byte[] get(byte[] key) {
57 return trie.get(key);
58 }
59
60 @Override
61 public void put(byte[] key, byte[] value) {
62 trie = trie.put(key, value);
63 }
64
65 @Override
66 public void put(ByteArrayWrapper key, byte[] value) {
67 trie = trie.put(key, value);
68 }
69
70 @Override
71 public void put(String key, byte[] value) {
72 trie = trie.put(key, value);
73 }
74
75 @Override
76 public Uint24 getValueLength(byte[] key) {
77 Trie atrie = trie.find(key);
78 if (atrie == null) {
79 // TODO(mc) should be null?
80 return Uint24.ZERO;
81 }
82
83 return atrie.getValueLength();
84 }
85
86 @Override
87 public Optional<Keccak256> getValueHash(byte[] key) {
88 Trie atrie = trie.find(key);
89 if (atrie == null) {
90 return Optional.empty();
91 }
92 return Optional.of(atrie.getValueHash());
93 }
94
95 @Override
96 public Iterator<DataWord> getStorageKeys(RskAddress addr) {
97 byte[] accountStorageKey = trieKeyMapper.getAccountStoragePrefixKey(addr);
98 final int storageKeyOffset = (TrieKeyMapper.storagePrefix().length + TrieKeyMapper.SECURE_KEY_SIZE) * Byte.SIZE - 1;
99 Trie storageTrie = trie.find(accountStorageKey);
100
101 if (storageTrie != null) {
102 Iterator<Trie.IterationElement> storageIterator = storageTrie.getPreOrderIterator();
103 storageIterator.next(); // skip storage root
104 return new StorageKeysIterator(storageIterator, storageKeyOffset);
105 }
106 return Collections.emptyIterator();
107 }
108
109 @Override
110 public void deleteRecursive(byte[] key) {
111 trie = trie.deleteRecursive(key);
112 }
113
114 @Override
115 public void save() {
116 if (trieStore != null) {
117 trieStore.save(trie);
118 }
119 }
120
121 @Override
122 public void commit() {
123 // TODO(mc) is it OK to leave this empty? why?
124 }
125
126 @Override
127 public void rollback() {
128 // TODO(mc) is it OK to leave this empty? why?
129 }
130
131 @Override
132 public Set<ByteArrayWrapper> collectKeys(int size) {
133 return trie.collectKeys(size);
134 }
135
136 private static class StorageKeysIterator implements Iterator<DataWord> {
137 private final Iterator<Trie.IterationElement> storageIterator;
138 private final int storageKeyOffset;
139 private DataWord currentStorageKey;
140
141 StorageKeysIterator(Iterator<Trie.IterationElement> storageIterator, int storageKeyOffset) {
142 this.storageIterator = storageIterator;
143 this.storageKeyOffset = storageKeyOffset;
144 }
145
146 @Override
147 public boolean hasNext() {
148 if (currentStorageKey != null) {
149 return true;
150 }
151 while (storageIterator.hasNext()) {
152 Trie.IterationElement iterationElement = storageIterator.next();
153 if (iterationElement.getNode().getValue() != null) {
154 TrieKeySlice nodeKey = iterationElement.getNodeKey();
155 byte[] storageExpandedKeySuffix = nodeKey.slice(storageKeyOffset, nodeKey.length()).encode();
156 currentStorageKey = DataWord.valueOf(storageExpandedKeySuffix);
157 return true;
158 }
159 }
160 return false;
161 }
162
163 @Override
164 public DataWord next() {
165 if (currentStorageKey == null && !hasNext()) {
166 throw new NoSuchElementException();
167 }
168
169 DataWord next = currentStorageKey;
170 currentStorageKey = null;
171 return next;
172 }
173 }
174 }