From 55c7a9c088fffe734259afc6c27f97324310c4de Mon Sep 17 00:00:00 2001 From: romanman Date: Sun, 23 Nov 2014 21:14:00 +0100 Subject: [PATCH] Bloom filters, Logs, Transaction receipts. --- .../org/ethereum/core/BlockchainImpl.java | 40 ++++++-- .../main/java/org/ethereum/core/Bloom.java | 75 ++++++++++++++ .../org/ethereum/core/TransactionReceipt.java | 98 +++++++++++++++---- .../java/org/ethereum/db/RepositoryImpl.java | 5 + .../java/org/ethereum/db/RepositoryTrack.java | 6 ++ .../java/org/ethereum/facade/Repository.java | 3 + .../src/main/java/org/ethereum/util/RLP.java | 10 +- .../main/java/org/ethereum/vm/LogInfo.java | 30 +++++- .../java/test/ethereum/core/BloomTest.java | 47 +++++++++ .../java/test/ethereum/core/StateTest.java | 26 ----- .../test/ethereum/core/TransactionTest.java | 34 ++++++- .../test/java/test/ethereum/util/RLPTest.java | 1 + .../src/test/resources/log4j.properties | 2 +- 13 files changed, 316 insertions(+), 61 deletions(-) create mode 100644 ethereumj-core/src/main/java/org/ethereum/core/Bloom.java create mode 100644 ethereumj-core/src/test/java/test/ethereum/core/BloomTest.java diff --git a/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java b/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java index 77dfa005..295f7cb8 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java @@ -217,6 +217,8 @@ public class BlockchainImpl implements Blockchain { this.processBlock(block); track.commit(); + repository.flush(); // saving to the disc + // Remove all wallet transactions as they already approved by the net worldManager.getWallet().removeTransactions(block.getTransactionsList()); @@ -326,9 +328,21 @@ public class BlockchainImpl implements Blockchain { long totalGasUsed = 0; for (Transaction tx : block.getTransactionsList()) { stateLogger.debug("apply block: [{}] tx: [{}] ", block.getNumber(), i); - totalGasUsed += applyTransaction(block, tx); - if(block.getNumber() >= CONFIG.traceStartBlock()) - repository.dumpState(block, totalGasUsed, i++, tx.getHash()); + + TransactionReceipt receipt = applyTransaction(block, tx); + totalGasUsed += receipt.getCumulativeGasLong(); + receipt.setCumulativeGas(totalGasUsed); + + track.commit(); + receipt.setPostTxState(repository.getRoot()); + + if(block.getNumber() >= CONFIG.traceStartBlock()) + repository.dumpState(block, totalGasUsed, i++, tx.getHash()); + + // todo: (!!!). save the receipt + // todo: cache all the receipts and + // todo: save them to the disc together + // todo: with the block afterwards } this.addReward(block); @@ -398,10 +412,12 @@ public class BlockchainImpl implements Blockchain { * @param tx - the transaction to be applied * @return gasUsed - the total amount of gas used for this transaction. */ - public long applyTransaction(Block block, Transaction tx) { + public TransactionReceipt applyTransaction(Block block, Transaction tx) { logger.info("applyTransaction: [{}]", Hex.toHexString(tx.getHash())); + TransactionReceipt receipt = new TransactionReceipt(); + byte[] coinbase = block.getCoinbase(); // VALIDATE THE SENDER @@ -416,7 +432,9 @@ public class BlockchainImpl implements Blockchain { if (stateLogger.isWarnEnabled()) stateLogger.warn("Invalid nonce account.nonce={} tx.nonce={}", nonce, txNonce); - return 0; + + receipt.setCumulativeGas(0); + return receipt; } // UPDATE THE NONCE @@ -474,7 +492,9 @@ public class BlockchainImpl implements Blockchain { if (track.getBalance(senderAddress).compareTo(gasDebit) == -1) { logger.debug("No gas to start the execution: sender={}", Hex.toHexString(senderAddress)); - return 0; + + receipt.setCumulativeGas(0); + return receipt; } track.addBalance(senderAddress, gasDebit.negate()); @@ -529,7 +549,9 @@ public class BlockchainImpl implements Blockchain { } catch (RuntimeException e) { trackTx.rollback(); - return new BigInteger(1, tx.getGasLimit()).longValue(); + + receipt.setCumulativeGas(tx.getGasLimit()); + return receipt; } trackTx.commit(); } else { @@ -543,7 +565,9 @@ public class BlockchainImpl implements Blockchain { track.addBalance(coinbase, refund.negate()); } } - return gasUsed; + + receipt.setCumulativeGas(gasUsed); + return receipt; } /** diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Bloom.java b/ethereumj-core/src/main/java/org/ethereum/core/Bloom.java new file mode 100644 index 00000000..ab91eb49 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/core/Bloom.java @@ -0,0 +1,75 @@ +package org.ethereum.core; + +import org.spongycastle.util.encoders.Hex; + +/** + * www.etherj.com + * + * @author: Roman Mandeleil + * Created on: 20/11/2014 11:10 + * + * http://www.herongyang.com/Java/Bit-String-Set-Bit-to-Byte-Array.html + */ + +public class Bloom { + + byte[] data = new byte[512]; + + + public Bloom(byte[] data){ + } + + public static Bloom create(byte[] toBloom){ + + int mov1 = (toBloom[0] & 1) * 256 + (toBloom[1] & 255); + int mov2 = (toBloom[2] & 1) * 256 + (toBloom[3] & 255); + int mov3 = (toBloom[4] & 1) * 256 + (toBloom[5] & 255); + + byte[] data = new byte[512]; + Bloom bloom = new Bloom(data); + + bloom.setBit(mov1, 1); + bloom.setBit(mov2, 1); + bloom.setBit(mov3, 1); + + return bloom; + } + + public void or(Bloom bloom){ + + for (int i = 0; i < data.length; ++i){ + data[i] |= bloom.data[i]; + } + } + + public void setBit(int pos, int val) { + + if (data.length - 1 < pos ) + throw new Error("outside bloom limit, pos: " + pos); + + int posByte = (pos - 1) / 8; + int posBit = (pos - 1) % 8; + byte oldByte = data[posByte]; + oldByte = (byte) (((0xFF7F >> (( posBit + 1)) & oldByte) & 0x00FF)); + byte newByte = (byte) ((val << ( 8 - ( posBit + 1))) | oldByte); + data[posByte] = newByte; + } + + public int getBit(int pos) { + + if (data.length - 1 < pos ) + throw new Error("outside bloom limit, pos: " + pos); + + int posByte = pos / 8; + int posBit = pos % 8; + byte valByte = data[posByte]; + int valInt = valByte >> (8 - (posBit + 1)) & 0x0001; + return valInt; + } + + + @Override + public String toString() { + return Hex.toHexString(data); + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/core/TransactionReceipt.java b/ethereumj-core/src/main/java/org/ethereum/core/TransactionReceipt.java index 4880312e..3bb005d3 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/TransactionReceipt.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/TransactionReceipt.java @@ -1,60 +1,118 @@ package org.ethereum.core; import org.ethereum.util.RLP; +import org.ethereum.vm.LogInfo; +import org.spongycastle.util.BigIntegers; import org.spongycastle.util.encoders.Hex; +import java.math.BigInteger; +import java.util.Iterator; +import java.util.List; + /** * The transaction receipt is a tuple of three items * comprising the transaction, together with the post-transaction state, * and the cumulative gas used in the block containing the transaction receipt * as of immediately after the transaction has happened, * - * ** not todo: the transaction receipt was removed from the game but don't remove it - * as it will be used in the very near future. * */ public class TransactionReceipt { - private Transaction transaction; private byte[] postTxState; private byte[] cumulativeGas; + private Bloom bloomFilter; + private List logInfoList; /* Tx Receipt in encoded form */ private byte[] rlpEncoded; - public TransactionReceipt(Transaction transaction, byte[] postTxState, byte[] cumulativeGas) { - this.transaction = transaction; - this.postTxState = postTxState; - this.cumulativeGas = cumulativeGas; - } - - public Transaction getTransaction() { - return transaction; - } - - public byte[] getPostTxState() { - return postTxState; + public TransactionReceipt() { } + public TransactionReceipt(byte[] postTxState, byte[] cumulativeGas, + Bloom bloomFilter, List logInfoList) { + this.postTxState = postTxState; + this.cumulativeGas = cumulativeGas; + this.bloomFilter = bloomFilter; + this.logInfoList = logInfoList; + } + + public byte[] getPostTxState() { + return postTxState; + } + + public byte[] getCumulativeGas() { + return cumulativeGas; + } + + public long getCumulativeGasLong() { + return new BigInteger(1, cumulativeGas).longValue(); + } + + + public Bloom getBloomFilter() { + return bloomFilter; + } + + public List getLogInfoList() { + return logInfoList; + } + + + /* [postTxState, cumulativeGas, bloomFilter, logInfoList] */ public byte[] getEncoded() { if(rlpEncoded != null) return rlpEncoded; - byte[] transactionEl = transaction.getEncoded(); - byte[] postTxStateEl = RLP.encodeElement(this.postTxState); - byte[] cumulativeGasEl = RLP.encodeElement(this.cumulativeGas); + byte[] postTxStateRLP = RLP.encodeElement(this.postTxState); + byte[] cumulativeGasRLP = RLP.encodeElement(this.cumulativeGas); + byte[] bloomRLP = RLP.encodeElement(this.bloomFilter.data); - rlpEncoded = RLP.encodeList(transactionEl, postTxStateEl, cumulativeGasEl); + byte[][] logInfoListE = new byte[logInfoList.size()][]; + + int i = 0; + for (LogInfo logInfo : logInfoList){ + logInfoListE[i] = logInfo.getEncoded(); + ++i; + } + byte[] logInfoListRLP = RLP.encodeList(logInfoListE); + + rlpEncoded = RLP.encodeList(postTxStateRLP, cumulativeGasRLP, bloomRLP, logInfoListRLP); return rlpEncoded; } + public void setPostTxState(byte[] postTxState) { + this.postTxState = postTxState; + } + + public void setCumulativeGas(long cumulativeGas) { + this.cumulativeGas = BigIntegers.asUnsignedByteArray( BigInteger.valueOf( cumulativeGas ) ); + } + + public void setCumulativeGas(byte[] cumulativeGas) { + this.cumulativeGas = cumulativeGas; + } + + public void setBloomFilter(Bloom bloomFilter) { + this.bloomFilter = bloomFilter; + } + + public void setLogInfoList(List logInfoList) { + this.logInfoList = logInfoList; + } + @Override public String toString() { + + // todo: fix that + return "TransactionReceipt[" + - "\n " + transaction + "\n , postTxState=" + Hex.toHexString(postTxState) + "\n , cumulativeGas=" + Hex.toHexString(cumulativeGas) + + "\n , bloom=" + bloomFilter.toString() + + "\n , logs=" + logInfoList + ']'; } diff --git a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java index 68103f3b..8876bfa6 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java @@ -126,9 +126,14 @@ public class RepositoryImpl implements Repository { accountState.setDeleted(false); accountState.setDirty(false); } + } + + @Override + public void flush(){ worldState.sync(); } + @Override public void rollback() { throw new UnsupportedOperationException(); diff --git a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryTrack.java b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryTrack.java index 333a5d1b..5480c35b 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryTrack.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryTrack.java @@ -178,6 +178,12 @@ public class RepositoryTrack implements Repository { } + @Override + public void flush(){ + throw new UnsupportedOperationException(); + } + + @Override public void commit() { logger.debug("commit changes"); diff --git a/ethereumj-core/src/main/java/org/ethereum/facade/Repository.java b/ethereumj-core/src/main/java/org/ethereum/facade/Repository.java index 30aa5e64..2a43a471 100644 --- a/ethereumj-core/src/main/java/org/ethereum/facade/Repository.java +++ b/ethereumj-core/src/main/java/org/ethereum/facade/Repository.java @@ -146,6 +146,9 @@ public interface Repository { */ public Repository startTracking(); + public void flush(); + + /** * Store all the temporary changes made * to the repository in the actual database diff --git a/ethereumj-core/src/main/java/org/ethereum/util/RLP.java b/ethereumj-core/src/main/java/org/ethereum/util/RLP.java index 6f1bf244..01c42f58 100644 --- a/ethereumj-core/src/main/java/org/ethereum/util/RLP.java +++ b/ethereumj-core/src/main/java/org/ethereum/util/RLP.java @@ -16,6 +16,7 @@ import java.util.List; import org.ethereum.util.RLP; import org.ethereum.util.RLPItem; import org.ethereum.util.RLPList; +import org.spongycastle.util.encoders.Hex; /** * Recursive Length Prefix (RLP) encoding. @@ -865,9 +866,14 @@ public class RLP { public static byte[] encodeList(byte[]... elements) { + if (elements == null){ + return new byte[] {(byte)OFFSET_SHORT_LIST }; + } + int totalLength = 0; - for (int i = 0; i < elements.length; ++i) { - totalLength += elements[i].length; + for (int i = 0; + elements != null && i < elements.length; ++i) { + totalLength += elements[i].length; } byte[] data; diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/LogInfo.java b/ethereumj-core/src/main/java/org/ethereum/vm/LogInfo.java index b3eded70..fb94f2a5 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/LogInfo.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/LogInfo.java @@ -1,7 +1,10 @@ package org.ethereum.vm; +import org.ethereum.core.BlockHeader; +import org.ethereum.util.RLP; import org.spongycastle.util.encoders.Hex; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -15,12 +18,15 @@ import java.util.List; public class LogInfo { byte[] address; - List topics; + List topics = new ArrayList<>(); byte[] data; + /* Log info in encoded form */ + private byte[] rlpEncoded; + public LogInfo(byte[] address, List topics, byte[] data) { this.address = address; - this.topics = topics; + this.topics = (topics == null) ? new ArrayList() : topics; this.data = data; } @@ -36,6 +42,26 @@ public class LogInfo { return data; } + /* [address, [topic, topic ...] data] */ + public byte[] getEncoded() { + + + byte[] addressEncoded = RLP.encodeElement(this.address); + + byte[][] topicsEncoded = null; + if (topics != null){ + topicsEncoded = new byte[topics.size()][]; + int i = 0; + for( byte[] topic : topics ){ + topicsEncoded[i] = topic; + ++i; + } + } + + byte[] dataEncoded = RLP.encodeElement(data); + return RLP.encodeList(addressEncoded, RLP.encodeList(topicsEncoded), dataEncoded); + } + @Override public String toString() { diff --git a/ethereumj-core/src/test/java/test/ethereum/core/BloomTest.java b/ethereumj-core/src/test/java/test/ethereum/core/BloomTest.java new file mode 100644 index 00000000..139bf85c --- /dev/null +++ b/ethereumj-core/src/test/java/test/ethereum/core/BloomTest.java @@ -0,0 +1,47 @@ +package test.ethereum.core; + +import org.ethereum.core.Bloom; +import org.ethereum.crypto.SHA3Helper; +import org.junit.Test; +import org.spongycastle.util.encoders.Hex; + +/** + * www.etherj.com + * + * @author: Roman Mandeleil + * Created on: 20/11/2014 11:29 + */ + +public class BloomTest { + + + @Test + public void test1(){ + + byte[] key = SHA3Helper.sha3(Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826")); + + Bloom bloom = Bloom.create(key); + System.out.println(bloom); + + } + + @Test + public void test2(){ + + byte[] key = Hex.decode("0954D2BEF0CA79C1A988AE5FF3072C2AEA90F3967A9596065123F2A15AA37EF3"); + + Bloom bloom = Bloom.create(key); + System.out.println(bloom); + } + + @Test + public void test3(){ + + byte[] key = SHA3Helper.sha3(Hex.decode("22341AE42D6DD7384BC8584E50419EA3AC75B83F ")); + + Bloom bloom = Bloom.create(key); + System.out.println(bloom); + } + + +} diff --git a/ethereumj-core/src/test/java/test/ethereum/core/StateTest.java b/ethereumj-core/src/test/java/test/ethereum/core/StateTest.java index 122b7605..a4321900 100644 --- a/ethereumj-core/src/test/java/test/ethereum/core/StateTest.java +++ b/ethereumj-core/src/test/java/test/ethereum/core/StateTest.java @@ -34,32 +34,6 @@ public class StateTest { assertEquals(GENESIS_STATE_ROOT, Hex.toHexString(trie.getRootHash())); } - @Test // right way to calc tx trie hash - public void testCalculatePostTxState() { - - /* txTrieHash */ - String expected = "a77691cf47bec9021d3f027fc8ef2d51b758b600a79967154354b8e37108896f"; - Transaction tx = new Transaction( - new byte[]{}, - Hex.decode("09184E72A000"), - Hex.decode("03E8"), - Hex.decode("0000000000000000000000000000000000000000"), - Hex.decode("03e8"), - Hex.decode("60016000546006601160003960066000f261778e600054") - ); - byte[] cowPrivKey = Hex.decode("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4"); - tx.sign(cowPrivKey); - - byte[] postTxState = Hex.decode("7fa5bd00f6e03b5a5718560f1e25179b227167585a3c3da06a48f554365fb527"); - byte[] cumGas = Hex.decode("0272"); - - TransactionReceipt tr = new TransactionReceipt(tx, postTxState, cumGas); - - Trie trie = new TrieImpl(new MockDB()); - trie.update(RLP.encodeInt(0), tr.getEncoded()); - String txTrieRoot = Hex.toHexString(trie.getRootHash()); - assertEquals(expected, txTrieRoot); - } @Test // calc state after applying first tx on genesis public void test2() { diff --git a/ethereumj-core/src/test/java/test/ethereum/core/TransactionTest.java b/ethereumj-core/src/test/java/test/ethereum/core/TransactionTest.java index ba4cecc1..e398c87b 100644 --- a/ethereumj-core/src/test/java/test/ethereum/core/TransactionTest.java +++ b/ethereumj-core/src/test/java/test/ethereum/core/TransactionTest.java @@ -8,7 +8,12 @@ import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.util.ArrayList; +import java.util.List; +import org.ethereum.core.Bloom; +import org.ethereum.core.TransactionReceipt; +import org.ethereum.vm.LogInfo; import test.ethereum.TestContext; import org.ethereum.core.Transaction; import org.ethereum.crypto.ECKey; @@ -89,7 +94,7 @@ public class TransactionTest { System.out.println("Signature public key\t: " + Hex.toHexString(key.getPubKey())); System.out.println("Sender is\t\t: " + Hex.toHexString(key.getAddress())); - Assert.assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", Hex.toHexString(key.getAddress())); System.out.println(tx.toString()); @@ -130,7 +135,7 @@ public class TransactionTest { System.out.println("Signature public key\t: " + Hex.toHexString(key.getPubKey())); System.out.println("Sender is\t\t: " + Hex.toHexString(key.getAddress())); - Assert.assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", Hex.toHexString(key.getAddress())); } @@ -277,4 +282,29 @@ public class TransactionTest { System.out.println( Hex.toHexString(tx2.getSender())); } + + + @Test + public void encodeReceiptTest(){ + + String data = "f90244a0f5ff3fbd159773816a7c707a9b8cb6bb778b934a8f6466c7830ed970498f4b688301e848b902000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dbda94cd2a3d9f938e13cd947ec05abc7fe734df8dd826c083a1a1a1"; + + byte[] stateRoot = Hex.decode("f5ff3fbd159773816a7c707a9b8cb6bb778b934a8f6466c7830ed970498f4b68"); + byte[] gasUsed = Hex.decode("01E848"); + Bloom bloom = new Bloom(Hex.decode("0000000000000000800000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")); + + LogInfo logInfo1 = new LogInfo( + Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), + null, + Hex.decode("a1a1a1") + ); + + List logs = new ArrayList<>(); + logs.add(logInfo1); + + TransactionReceipt receipt = new TransactionReceipt(stateRoot, gasUsed, bloom, logs); + + assertEquals(data, + Hex.toHexString(receipt.getEncoded())); + } } diff --git a/ethereumj-core/src/test/java/test/ethereum/util/RLPTest.java b/ethereumj-core/src/test/java/test/ethereum/util/RLPTest.java index e35de54f..18e368d4 100644 --- a/ethereumj-core/src/test/java/test/ethereum/util/RLPTest.java +++ b/ethereumj-core/src/test/java/test/ethereum/util/RLPTest.java @@ -799,4 +799,5 @@ public class RLPTest { System.out.println(Hex.toHexString(encodedData)); } + } \ No newline at end of file diff --git a/ethereumj-core/src/test/resources/log4j.properties b/ethereumj-core/src/test/resources/log4j.properties index 5855c171..580af930 100644 --- a/ethereumj-core/src/test/resources/log4j.properties +++ b/ethereumj-core/src/test/resources/log4j.properties @@ -19,7 +19,7 @@ log4j.logger.peermonitor = ERROR log4j.logger.java.nio = ERROR log4j.logger.io.netty = ERROR log4j.logger.wire = ERROR -log4j.logger.VM = TRACE +log4j.logger.VM = ERROR log4j.logger.main = ERROR log4j.logger.trie = ERROR log4j.logger.state = INFO