Coverage Summary for Class: TrieKeyMapper (org.ethereum.db)
Class |
Class, %
|
Method, %
|
Line, %
|
TrieKeyMapper |
100%
(1/1)
|
80%
(8/10)
|
78.3%
(18/23)
|
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 org.ethereum.db;
20
21 import co.rsk.core.RskAddress;
22 import co.rsk.remasc.RemascTransaction;
23 import org.ethereum.crypto.Keccak256Helper;
24 import org.ethereum.util.ByteUtil;
25 import org.ethereum.vm.DataWord;
26
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.Map;
30
31 /**
32 * Utility used for the Repository to translate {@link RskAddress} into keys of the trie.
33 *
34 * It uses internally a map cache of address->key (1:1, due to the immutability of the RskAddress object)
35 */
36 public class TrieKeyMapper {
37
38 public static final int SECURE_KEY_SIZE = 10;
39 public static final int REMASC_ACCOUNT_KEY_SIZE = SECURE_KEY_SIZE + RemascTransaction.REMASC_ADDRESS.getBytes().length;
40 public static final int ACCOUNT_KEY_SIZE = RskAddress.LENGTH_IN_BYTES;
41 public static final int SECURE_ACCOUNT_KEY_SIZE = SECURE_KEY_SIZE + ACCOUNT_KEY_SIZE;
42 private static final byte[] DOMAIN_PREFIX = new byte[] {0x00};
43 private static final byte[] STORAGE_PREFIX = new byte[] {0x00}; // This makes the MSB 0 be branching
44 private static final byte[] CODE_PREFIX = new byte[] {(byte) 0x80}; // This makes the MSB 1 be branching
45
46 private final Map<RskAddress, byte[]> accountKeys = new HashMap<>(); //map cache of address->key (1:1) ** RskAddress is immutable.
47
48 public synchronized byte[] getAccountKey(RskAddress addr) {
49 if (accountKeys.containsKey(addr)) {
50 byte[] key = accountKeys.get(addr);
51 return Arrays.copyOf(key, key.length);
52 }
53
54 byte[] key = mapRskAddressToKey(addr);
55
56 accountKeys.put(addr, key);
57
58 return Arrays.copyOf(key, key.length);
59 }
60
61 public byte[] getCodeKey(RskAddress addr) {
62 return ByteUtil.merge(getAccountKey(addr), CODE_PREFIX);
63 }
64
65 public byte[] getAccountStoragePrefixKey(RskAddress addr) {
66 return ByteUtil.merge(getAccountKey(addr), STORAGE_PREFIX);
67 }
68
69 public byte[] getAccountStorageKey(RskAddress addr, DataWord subkeyDW) {
70 // TODO(SDL) should we hash the full subkey or the stripped one?
71 byte[] subkey = subkeyDW.getData();
72 byte[] secureKeyPrefix = secureKeyPrefix(subkey);
73 byte[] storageKey = ByteUtil.merge(secureKeyPrefix, ByteUtil.stripLeadingZeroes(subkey));
74 return ByteUtil.merge(getAccountStoragePrefixKey(addr), storageKey);
75 }
76
77 public byte[] secureKeyPrefix(byte[] key) {
78 return Arrays.copyOfRange(Keccak256Helper.keccak256(key), 0, SECURE_KEY_SIZE);
79 }
80
81 public static byte[] domainPrefix() {
82 return Arrays.copyOf(DOMAIN_PREFIX, DOMAIN_PREFIX.length);
83 }
84
85 public static byte[] storagePrefix() {
86 return Arrays.copyOf(STORAGE_PREFIX, STORAGE_PREFIX.length);
87 }
88
89 protected byte[] mapRskAddressToKey(RskAddress addr) {
90 byte[] secureKey = secureKeyPrefix(addr.getBytes());
91 return ByteUtil.merge(DOMAIN_PREFIX, secureKey, addr.getBytes());
92 }
93
94 }