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 }