@Override
  public DataWord get(DataWord key) {

    DataWord value = storage.get(key);
    if (value != null) value = value.clone();
    return value;
  }
  @Test
  public void testAddPerformance() {
    boolean enabled = false;

    if (enabled) {
      byte[] one =
          new byte[] {
            0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54, 0x41, 0x01, 0x31,
            0x54, 0x41, 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54, 0x41,
            0x01, 0x31, 0x54, 0x41
          }; // Random value

      int ITERATIONS = 10000000;

      long now1 = System.currentTimeMillis();
      for (int i = 0; i < ITERATIONS; i++) {
        DataWord x = new DataWord(one);
        x.add(x);
      }
      System.out.println("Add1: " + (System.currentTimeMillis() - now1) + "ms");

      long now2 = System.currentTimeMillis();
      for (int i = 0; i < ITERATIONS; i++) {
        DataWord x = new DataWord(one);
        x.add2(x);
      }
      System.out.println("Add2: " + (System.currentTimeMillis() - now2) + "ms");
    } else {
      System.out.println("ADD performance test is disabled.");
    }
  }
  @Test(expected = IndexOutOfBoundsException.class)
  public void testSignExtendException2() {

    byte k = 32;
    DataWord x = new DataWord();

    x.signExtend(k); // should throw an exception
  }
  @Test
  public void testSignExtend2() {
    DataWord x = new DataWord(Hex.decode("f2"));
    byte k = 1;
    String expected = "00000000000000000000000000000000000000000000000000000000000000f2";

    x.signExtend(k);
    System.out.println(x.toString());
    assertEquals(expected, x.toString());
  }
  @Test
  public void testSignExtend7() {

    byte k = 3;
    DataWord x = new DataWord(Hex.decode("ab82345678"));
    String expected = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff82345678";

    x.signExtend(k);
    System.out.println(x.toString());
    assertEquals(expected, x.toString());
  }
  @Override
  public byte[] getStorageHash() {

    SecureTrie storageTrie = new SecureTrie(null);

    for (DataWord key : storage.keySet()) {

      DataWord value = storage.get(key);

      storageTrie.update(key.getData(), RLP.encodeElement(value.getNoLeadZeroesData()));
    }

    return storageTrie.getRootHash();
  }
  @Test
  public void testMul() {
    byte[] one = new byte[32];
    one[31] = 0x1; // 0x0000000000000000000000000000000000000000000000000000000000000001

    byte[] two = new byte[32];
    two[11] = 0x1; // 0x0000000000000000000000010000000000000000000000000000000000000000

    DataWord x = new DataWord(one); // System.out.println(x.value());
    DataWord y = new DataWord(two); // System.out.println(y.value());
    x.mul(y);
    assertEquals(32, y.getData().length);
    assertEquals(
        "0000000000000000000000010000000000000000000000000000000000000000",
        Hex.toHexString(y.getData()));
  }
  @Test
  public void testAdd3() {
    byte[] three = new byte[32];
    for (int i = 0; i < three.length; i++) {
      three[i] = (byte) 0xff;
    }

    DataWord x = new DataWord(three);
    x.add(new DataWord(three));
    assertEquals(32, x.getData().length);
    System.out.println(Hex.toHexString(x.getData()));

    // FAIL
    //		DataWord y = new DataWord(three);
    //		y.add2(new DataWord(three));
    //		System.out.println(Hex.toHexString(y.getData()));
  }
  @Test
  public void testMod() {
    String expected = "000000000000000000000000000000000000000000000000000000000000001a";

    byte[] one = new byte[32];
    one[31] = 0x1e; // 0x000000000000000000000000000000000000000000000000000000000000001e

    byte[] two = new byte[32];
    for (int i = 0; i < two.length; i++) {
      two[i] = (byte) 0xff;
    }
    two[31] = 0x56; // 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff56

    DataWord x = new DataWord(one); // System.out.println(x.value());
    DataWord y = new DataWord(two); // System.out.println(y.value());
    y.mod(x);
    assertEquals(32, y.getData().length);
    assertEquals(expected, Hex.toHexString(y.getData()));
  }
  @Override
  public void put(DataWord key, DataWord value) {

    if (value.equals(DataWord.ZERO)) {
      storage.remove(key);
    } else {

      storage.put(key, value);
    }

    this.setDirty(true);
  }
  @Override
  public byte[] getEncoded() {

    byte[][] keys = new byte[storage.size()][];
    byte[][] values = new byte[storage.size()][];

    int i = 0;
    for (DataWord key : storage.keySet()) {

      DataWord value = storage.get(key);

      keys[i] = RLP.encodeElement(key.getData());
      values[i] = RLP.encodeElement(value.getNoLeadZeroesData());

      ++i;
    }

    byte[] rlpKeysList = RLP.encodeList(keys);
    byte[] rlpValuesList = RLP.encodeList(values);
    byte[] rlpCode = RLP.encodeElement(code);

    return RLP.encodeList(rlpKeysList, rlpValuesList, rlpCode);
  }
  @Test
  public void testAdd2() {
    byte[] two = new byte[32];
    two[31] = (byte) 0xff; // 0x000000000000000000000000000000000000000000000000000000000000ff

    DataWord x = new DataWord(two);
    x.add(new DataWord(two));
    System.out.println(Hex.toHexString(x.getData()));

    DataWord y = new DataWord(two);
    y.add2(new DataWord(two));
    System.out.println(Hex.toHexString(y.getData()));
  }
 @Override
 public byte[] getStorageSlot(byte[] slot) {
   DataWord ret =
       getBlockchain().getRepository().getContractDetails(contractAddr).get(new DataWord(slot));
   return ret.getData();
 }