/*
* 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.core;
import org.ethereum.util.Functional;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPElement;
import org.ethereum.util.RLPList;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.commons.lang3.ArrayUtils.isEmpty;
import static org.ethereum.util.ByteUtil.toHexString;
public class BlockSummary {
private final Block block;
private final Map<byte[], BigInteger> rewards;
private final List<TransactionReceipt> receipts;
private final List<TransactionExecutionSummary> summaries;
private BigInteger totalDifficulty = BigInteger.ZERO;
public BlockSummary(byte[] rlp) {
RLPList summary = (RLPList) RLP.decode2(rlp).get(0);
this.block = new Block(summary.get(0).getRLPData());
this.rewards = decodeRewards((RLPList) summary.get(1));
this.summaries = decodeSummaries((RLPList) summary.get(2));
this.receipts = new ArrayList<>();
Map<String, TransactionReceipt> receiptByTxHash = decodeReceipts((RLPList) summary.get(3));
for (Transaction tx : this.block.getTransactionsList()) {
TransactionReceipt receipt = receiptByTxHash.get(toHexString(tx.getHash()));
receipt.setTransaction(tx);
this.receipts.add(receipt);
}
}
public BlockSummary(Block block, Map<byte[], BigInteger> rewards, List<TransactionReceipt> receipts, List<TransactionExecutionSummary> summaries) {
this.block = block;
this.rewards = rewards;
this.receipts = receipts;
this.summaries = summaries;
}
public Block getBlock() {
return block;
}
public List<TransactionReceipt> getReceipts() {
return receipts;
}
public List<TransactionExecutionSummary> getSummaries() {
return summaries;
}
/**
* All the mining rewards paid out for this block, including the main block rewards, uncle rewards, and transaction fees.
*/
public Map<byte[], BigInteger> getRewards() {
return rewards;
}
public void setTotalDifficulty(BigInteger totalDifficulty) {
this.totalDifficulty = totalDifficulty;
}
public BigInteger getTotalDifficulty() {
return totalDifficulty;
}
public byte[] getEncoded() {
return RLP.encodeList(
block.getEncoded(),
encodeRewards(rewards),
encodeSummaries(summaries),
encodeReceipts(receipts)
);
}
private static <T> byte[] encodeList(List<T> entries, Functional.Function<T, byte[]> encoder) {
byte[][] result = new byte[entries.size()][];
for (int i = 0; i < entries.size(); i++) {
result[i] = encoder.apply(entries.get(i));
}
return RLP.encodeList(result);
}
private static <T> List<T> decodeList(RLPList list, Functional.Function<byte[], T> decoder) {
List<T> result = new ArrayList<>();
for (RLPElement item : list) {
result.add(decoder.apply(item.getRLPData()));
}
return result;
}
private static <K, V> byte[] encodeMap(Map<K, V> map, Functional.Function<K, byte[]> keyEncoder, Functional.Function<V, byte[]> valueEncoder) {
byte[][] result = new byte[map.size()][];
int i = 0;
for (Map.Entry<K, V> entry : map.entrySet()) {
byte[] key = keyEncoder.apply(entry.getKey());
byte[] value = valueEncoder.apply(entry.getValue());
result[i++] = RLP.encodeList(key, value);
}
return RLP.encodeList(result);
}
private static <K, V> Map<K, V> decodeMap(RLPList list, Functional.Function<byte[], K> keyDecoder, Functional.Function<byte[], V> valueDecoder) {
Map<K, V> result = new HashMap<>();
for (RLPElement entry : list) {
K key = keyDecoder.apply(((RLPList) entry).get(0).getRLPData());
V value = valueDecoder.apply(((RLPList) entry).get(1).getRLPData());
result.put(key, value);
}
return result;
}
private static byte[] encodeSummaries(final List<TransactionExecutionSummary> summaries) {
return encodeList(summaries, new Functional.Function<TransactionExecutionSummary, byte[]>() {
@Override
public byte[] apply(TransactionExecutionSummary summary) {
return summary.getEncoded();
}
});
}
private static List<TransactionExecutionSummary> decodeSummaries(RLPList summaries) {
return decodeList(summaries, new Functional.Function<byte[], TransactionExecutionSummary>() {
@Override
public TransactionExecutionSummary apply(byte[] encoded) {
return new TransactionExecutionSummary(encoded);
}
});
}
private static byte[] encodeReceipts(List<TransactionReceipt> receipts) {
Map<String, TransactionReceipt> receiptByTxHash = new HashMap<>();
for (TransactionReceipt receipt : receipts) {
receiptByTxHash.put(toHexString(receipt.getTransaction().getHash()), receipt);
}
return encodeMap(receiptByTxHash, new Functional.Function<String, byte[]>() {
@Override
public byte[] apply(String txHash) {
return RLP.encodeString(txHash);
}
}, new Functional.Function<TransactionReceipt, byte[]>() {
@Override
public byte[] apply(TransactionReceipt receipt) {
return receipt.getEncoded();
}
});
}
private static Map<String, TransactionReceipt> decodeReceipts(RLPList receipts) {
return decodeMap(receipts, new Functional.Function<byte[], String>() {
@Override
public String apply(byte[] bytes) {
return new String(bytes);
}
}, new Functional.Function<byte[], TransactionReceipt>() {
@Override
public TransactionReceipt apply(byte[] encoded) {
return new TransactionReceipt(encoded);
}
});
}
private static byte[] encodeRewards(Map<byte[], BigInteger> rewards) {
return encodeMap(rewards, new Functional.Function<byte[], byte[]>() {
@Override
public byte[] apply(byte[] bytes) {
return RLP.encodeElement(bytes);
}
}, new Functional.Function<BigInteger, byte[]>() {
@Override
public byte[] apply(BigInteger reward) {
return RLP.encodeBigInteger(reward);
}
});
}
private static Map<byte[], BigInteger> decodeRewards(RLPList rewards) {
return decodeMap(rewards, new Functional.Function<byte[], byte[]>() {
@Override
public byte[] apply(byte[] bytes) {
return bytes;
}
}, new Functional.Function<byte[], BigInteger>() {
@Override
public BigInteger apply(byte[] bytes) {
return isEmpty(bytes) ? BigInteger.ZERO : new BigInteger(1, bytes);
}
});
}
}