BlockChain refactoring:

+ keep only index of block hash numbers in the cach
+ for the full block data, query DB
This commit is contained in:
romanman 2014-06-09 10:51:31 +01:00
parent b3bf0f024c
commit bb8291457a
9 changed files with 49 additions and 27 deletions

View File

@ -78,7 +78,7 @@ public class Block {
private void parseRLP() { private void parseRLP() {
RLPList params = (RLPList) RLP.decode2(rlpEncoded); RLPList params = RLP.decode2(rlpEncoded);
RLPList block = (RLPList) params.get(0); RLPList block = (RLPList) params.get(0);
// Parse Header // Parse Header

View File

@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*; import java.util.*;
import static org.ethereum.core.Denomination.*; import static org.ethereum.core.Denomination.*;
@ -21,7 +22,7 @@ import static org.ethereum.core.Denomination.*;
* Created on: 20/05/2014 10:44 * Created on: 20/05/2014 10:44
* *
*/ */
public class Blockchain extends ArrayList<Block> { public class Blockchain {
private static final long serialVersionUID = -143590724563460486L; private static final long serialVersionUID = -143590724563460486L;
@ -36,6 +37,10 @@ public class Blockchain extends ArrayList<Block> {
private long gasPrice = 1000; private long gasPrice = 1000;
private Block lastBlock; private Block lastBlock;
// keep the index of the chain for
// convenient usage, <block_number, block_hash>
private HashMap<Long, byte[]> index = new HashMap<Long, byte[]>();
// This map of transaction designed // This map of transaction designed
// to approve the tx by external trusted peer // to approve the tx by external trusted peer
private Map<String, WalletTransaction> walletTransactions = private Map<String, WalletTransaction> walletTransactions =
@ -50,7 +55,17 @@ public class Blockchain extends ArrayList<Block> {
public Block getLastBlock() { public Block getLastBlock() {
return lastBlock; return lastBlock;
} }
public int getSize(){
return index.size();
}
public Block getByNumber(int rowIndex){
byte[] parentHash = index.get((long)rowIndex);
if (parentHash == null) return null;
return new Block(db.get(parentHash));
}
public void addBlocks(List<Block> blocks) { public void addBlocks(List<Block> blocks) {
if (blocks.isEmpty()) if (blocks.isEmpty())
@ -60,15 +75,14 @@ public class Blockchain extends ArrayList<Block> {
// if it is the first block to add // if it is the first block to add
// check that the parent is the genesis // check that the parent is the genesis
if (this.isEmpty() if (index.isEmpty()
&& !Arrays.equals(StaticMessages.GENESIS_HASH, && !Arrays.equals(StaticMessages.GENESIS_HASH,
firstBlockToAdd.getParentHash())) { firstBlockToAdd.getParentHash())) {
return; return;
} }
// if there is some blocks already keep chain continuity // if there is some blocks already keep chain continuity
if (!this.isEmpty()) { if (!index.isEmpty()) {
Block lastBlock = this.get(this.size() - 1); String hashLast = Hex.toHexString(getLastBlock().getHash());
String hashLast = Hex.toHexString(lastBlock.getHash());
String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash()); String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash());
if (!hashLast.equals(blockParentHash)) return; if (!hashLast.equals(blockParentHash)) return;
} }
@ -87,7 +101,7 @@ public class Blockchain extends ArrayList<Block> {
removeWalletTransaction(tx); removeWalletTransaction(tx);
} }
} }
logger.info("*** Block chain size: [ {} ]", this.size()); logger.info("*** Block chain size: [ {} ]", index.size());
} }
private void addBlock(Block block) { private void addBlock(Block block) {
@ -97,9 +111,10 @@ public class Blockchain extends ArrayList<Block> {
// on this price will use default 10000000000000 // on this price will use default 10000000000000
// todo: refactor this longValue some constant defaults class 10000000000000L // todo: refactor this longValue some constant defaults class 10000000000000L
this.gasPrice = block.isGenesis() ? INITIAL_MIN_GAS_PRICE : block.getMinGasPrice(); this.gasPrice = block.isGenesis() ? INITIAL_MIN_GAS_PRICE : block.getMinGasPrice();
if(lastBlock == null || block.getNumber() > lastBlock.getNumber()) if(lastBlock == null || block.getNumber() > lastBlock.getNumber()){
this.lastBlock = block; this.lastBlock = block;
this.add(block); index.put(block.getNumber(), block.getParentHash());
}
} }
} }
@ -135,7 +150,7 @@ public class Blockchain extends ArrayList<Block> {
} }
public byte[] getLatestBlockHash(){ public byte[] getLatestBlockHash(){
if (this.isEmpty()) if (index.isEmpty())
return StaticMessages.GENESIS_HASH; return StaticMessages.GENESIS_HASH;
else else
return lastBlock.getHash(); return lastBlock.getHash();
@ -147,15 +162,15 @@ public class Blockchain extends ArrayList<Block> {
if (!iterator.hasNext()) { if (!iterator.hasNext()) {
logger.info("DB is empty - adding Genesis"); logger.info("DB is empty - adding Genesis");
Block genesis = Genesis.getInstance(); Block genesis = Genesis.getInstance();
this.addBlock(genesis); this.addBlock(genesis);
logger.debug("Block: " + genesis.getNumber() + " ---> " + genesis.toFlatString()); logger.debug("Block: " + genesis.getNumber() + " ---> " + genesis.toFlatString());
db.put(genesis.getParentHash(), genesis.getEncoded()); db.put(genesis.getParentHash(), genesis.getEncoded());
} else { } else {
logger.debug("Displaying blocks stored in DB sorted on blocknumber"); logger.debug("Displaying blocks stored in DB sorted on blocknumber");
byte[] parentHash = Genesis.PARENT_HASH; // get Genesis block by parentHash byte[] parentHash = Genesis.PARENT_HASH; // get Genesis block by parentHash
for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) { for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
this.addBlock(new Block(db.get(parentHash))); this.addBlock(new Block(db.get(parentHash)));
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Block: " + lastBlock.getNumber() + " ---> " + lastBlock.toFlatString()); logger.debug("Block: " + lastBlock.getNumber() + " ---> " + lastBlock.toFlatString());
parentHash = lastBlock.getHash(); parentHash = lastBlock.getHash();
} }

View File

@ -74,9 +74,9 @@ public class BlockChainTable extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (MainData.instance.getBlockchain().size() - 1 < lastFindIndex) return; if (MainData.instance.getBlockchain().getSize() - 1 < lastFindIndex) return;
Block block = MainData.instance.getBlockchain().get(lastFindIndex); Block block = MainData.instance.getBlockchain().getByNumber(lastFindIndex);
StringSelection stsel = new StringSelection(block.toString()); StringSelection stsel = new StringSelection(block.toString());
Clipboard system = Toolkit.getDefaultToolkit().getSystemClipboard(); Clipboard system = Toolkit.getDefaultToolkit().getSystemClipboard();
system.setContents(stsel,stsel); system.setContents(stsel,stsel);
@ -96,10 +96,10 @@ public class BlockChainTable extends JFrame {
return; return;
} }
for (int i = lastFindIndex + 1; i < MainData.instance.getBlockchain().size(); ++i) { for (int i = lastFindIndex + 1; i < MainData.instance.getBlockchain().getSize(); ++i) {
if (MainData.instance.getBlockchain().size() - 1 < i) return; if (MainData.instance.getBlockchain().getSize() - 1 < i) return;
Block block = MainData.instance.getBlockchain().get(i); Block block = MainData.instance.getBlockchain().getByNumber(i);
boolean found = block.toString().toLowerCase().contains(toFind.toLowerCase()); boolean found = block.toString().toLowerCase().contains(toFind.toLowerCase());
if (found) { if (found) {
// todo: now we find the first occur // todo: now we find the first occur

View File

@ -1,5 +1,6 @@
package org.ethereum.gui; package org.ethereum.gui;
import org.ethereum.core.Block;
import org.ethereum.manager.MainData; import org.ethereum.manager.MainData;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
@ -15,7 +16,7 @@ public class BlockTableModel extends AbstractTableModel {
public int getRowCount() { public int getRowCount() {
fireTableDataChanged(); fireTableDataChanged();
int rowCount = MainData.instance.getBlockchain().size(); int rowCount = MainData.instance.getBlockchain().getSize();
return rowCount; return rowCount;
} }
@ -30,6 +31,9 @@ public class BlockTableModel extends AbstractTableModel {
// byte[] hash = MainData.instance.getAllBlocks().get(rowIndex).getHash(); // byte[] hash = MainData.instance.getAllBlocks().get(rowIndex).getHash();
// return Hex.toHexString(hash); // return Hex.toHexString(hash);
return MainData.instance.getBlockchain().get(rowIndex).toString(); Block block = MainData.instance.getBlockchain().getByNumber(rowIndex);
if (block == null) return "";
return block.toString();
} }
} }

View File

@ -2,7 +2,6 @@ package org.ethereum.manager;
import org.ethereum.core.AccountState; import org.ethereum.core.AccountState;
import org.ethereum.core.Block; import org.ethereum.core.Block;
import org.ethereum.core.Blockchain;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.Database; import org.ethereum.db.Database;

View File

@ -359,6 +359,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
byte[] hash = MainData.instance.getBlockchain().getLatestBlockHash(); byte[] hash = MainData.instance.getBlockchain().getLatestBlockHash();
GetChainMessage chainMessage = new GetChainMessage((byte)100, hash); GetChainMessage chainMessage = new GetChainMessage((byte)100, hash);
chainMessage.toString();
ByteBuf buffer = ctx.alloc().buffer(chainMessage.getPayload().length + 8); ByteBuf buffer = ctx.alloc().buffer(chainMessage.getPayload().length + 8);
buffer.writeBytes(StaticMessages.MAGIC_PACKET); buffer.writeBytes(StaticMessages.MAGIC_PACKET);

View File

@ -34,6 +34,7 @@ public class GetChainMessage extends Message {
encodedElements[0] = new byte[]{0x14}; encodedElements[0] = new byte[]{0x14};
int i = 1; int i = 1;
for (byte[] hash : blockHashList){ for (byte[] hash : blockHashList){
this.blockHashList.add(hash);
byte[] element = RLP.encodeElement(hash); byte[] element = RLP.encodeElement(hash);
encodedElements[i] = element; encodedElements[i] = element;
++i; ++i;
@ -41,6 +42,8 @@ public class GetChainMessage extends Message {
encodedElements[i] = RLP.encodeByte(number); encodedElements[i] = RLP.encodeByte(number);
this.payload = RLP.encodeList(encodedElements); this.payload = RLP.encodeList(encodedElements);
this.parsed = true;
} }
@Override @Override

View File

@ -8,7 +8,7 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d{HH:mm:ss} [%c{1}] %m%n log4j.appender.stdout.layout.ConversionPattern= %d{HH:mm:ss} [%c{1}] %m%n
# filter noisy classes # filter noisy classes
log4j.logger.org.ethereum.net = FATAL log4j.logger.org.ethereum.net = INFO
log4j.logger.org.ethereum.net.peerdiscovery = WARN log4j.logger.org.ethereum.net.peerdiscovery = WARN
log4j.logger.java.nio = WARN log4j.logger.java.nio = WARN
log4j.logger.io.netty = FATAL log4j.logger.io.netty = FATAL

View File

@ -16,8 +16,8 @@ peer.discovery.port = 30303
# that is the peer through # that is the peer through
# we get the chain: [54.201.28.117] port: [30303] # we get the chain: [54.201.28.117] port: [30303]
# ZeroGox # ZeroGox
peer.active.ip = 54.204.10.41 #peer.active.ip = 54.204.10.41
peer.active.port = 30303 #peer.active.port = 30303
# Some dude in Canada # Some dude in Canada
#peer.active.ip = 131.104.247.135 #peer.active.ip = 131.104.247.135
@ -29,8 +29,8 @@ peer.active.port = 30303
# RomanJ general # RomanJ general
#peer.active.ip = 54.211.14.10 peer.active.ip = 54.211.14.10
#peer.active.port = 50505 peer.active.port = 50505
#peer.active.ip = 151.64.223.120 #peer.active.ip = 151.64.223.120
#peer.active.port = 30304 #peer.active.port = 30304