/* * Copyright (c) [2016] [ <ether.camp> ] * This file is part of the ethereumJ library. * * The ethereumJ library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The ethereumJ library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>. */ package org.ethereum.jsontestsuite.suite; import org.ethereum.util.ByteUtil; import org.ethereum.vm.DataWord; import org.json.simple.JSONObject; import org.spongycastle.util.encoders.Hex; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * @author Roman Mandeleil * @since 28.06.2014 */ public class AccountState { byte[] address; byte[] balance; byte[] code; byte[] nonce; Map<DataWord, DataWord> storage = new HashMap<>(); public AccountState(byte[] address, JSONObject accountState) { this.address = address; String balance = accountState.get("balance").toString(); String code = (String) accountState.get("code"); String nonce = accountState.get("nonce").toString(); JSONObject store = (JSONObject) accountState.get("storage"); this.balance = TestCase.toBigInt(balance).toByteArray(); if (code != null && code.length() > 2) this.code = Hex.decode(code.substring(2)); else this.code = ByteUtil.EMPTY_BYTE_ARRAY; this.nonce = TestCase.toBigInt(nonce).toByteArray(); int size = store.keySet().size(); Object[] keys = store.keySet().toArray(); for (int i = 0; i < size; ++i) { String keyS = keys[i].toString(); String valS = store.get(keys[i]).toString(); byte[] key = Utils.parseData(keyS); byte[] value = Utils.parseData(valS); storage.put(new DataWord(key), new DataWord(value)); } } public byte[] getAddress() { return address; } public byte[] getBalance() { return balance; } public BigInteger getBigIntegerBalance() { return new BigInteger(balance); } public byte[] getCode() { return code; } public byte[] getNonce() { return nonce; } public long getNonceLong() { return new BigInteger(nonce).longValue(); } public Map<DataWord, DataWord> getStorage() { return storage; } public List<String> compareToReal(org.ethereum.core.AccountState state, ContractDetailsImpl details) { List<String> results = new ArrayList<>(); BigInteger expectedBalance = new BigInteger(1, this.getBalance()); if (!state.getBalance().equals(expectedBalance)) { String formattedString = String.format("Account: %s: has unexpected balance, expected balance: %s found balance: %s", Hex.toHexString(this.address), expectedBalance.toString(), state.getBalance().toString()); results.add(formattedString); } BigInteger expectedNonce = new BigInteger(1, this.getNonce()); if (!state.getNonce().equals(expectedNonce)) { state.getNonce(); this.getNonce(); String formattedString = String.format("Account: %s: has unexpected nonce, expected nonce: %s found nonce: %s", Hex.toHexString(this.address), expectedNonce.toString(), state.getNonce().toString()); results.add(formattedString); } if (!Arrays.equals(details.getCode(), this.getCode())) { String formattedString = String.format("Account: %s: has unexpected nonce, expected nonce: %s found nonce: %s", Hex.toHexString(this.address), Hex.toHexString(this.getCode()), Hex.toHexString(details.getCode())); results.add(formattedString); } // compare storage Set<DataWord> keys = details.getStorage().keySet(); Set<DataWord> expectedKeys = this.getStorage().keySet(); Set<DataWord> checked = new HashSet<>(); for (DataWord key : keys) { DataWord value = details.getStorage().get(key); DataWord expectedValue = this.getStorage().get(key); if (expectedValue == null) { String formattedString = String.format("Account: %s: has unexpected storage data: %s = %s", Hex.toHexString(this.address), key.toString(), value.toString()); results.add(formattedString); continue; } if (!expectedValue.equals(value)) { String formattedString = String.format("Account: %s: has unexpected value, for key: %s , expectedValue: %s real value: %s", Hex.toHexString(this.address), key.toString(), expectedValue.toString(), value.toString()); results.add(formattedString); continue; } checked.add(key); } for (DataWord key : expectedKeys) { if (!checked.contains(key)) { String formattedString = String.format("Account: %s: doesn't exist expected storage key: %s", Hex.toHexString(this.address), key.toString()); results.add(formattedString); } } return results; } @Override public String toString() { return "AccountState{" + "address=" + Hex.toHexString(address) + ", balance=" + Hex.toHexString(balance) + ", code=" + Hex.toHexString(code) + ", nonce=" + Hex.toHexString(nonce) + ", storage=" + storage + '}'; } }