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 }