Reduced genesis block load time.

This commit is contained in:
Adrian Tiberius 2015-11-09 05:26:28 +02:00
parent 502ec0b9b1
commit cde1454b85
6 changed files with 164 additions and 9 deletions

View File

@ -231,13 +231,35 @@ public class EthereumRemoteService extends EthereumService {
if (ethereum != null) { if (ethereum != null) {
System.out.println("Loading genesis"); System.out.println("Loading genesis");
broadcastEvent(EventFlag.EVENT_TRACE, new TraceEventData("Loading genesis block. This may take a few minutes...")); broadcastEvent(EventFlag.EVENT_TRACE, new TraceEventData("Loading genesis block. This may take a few minutes..."));
/*
String genesisFile = CONFIG.genesisInfo(); String genesisFile = CONFIG.genesisInfo();
long startTime = System.nanoTime();
try { try {
InputStream is = getApplication().getAssets().open("genesis/" + genesisFile); InputStream genesis = getApplication().getAssets().open("genesis/" + genesisFile);
Genesis.androidGetInstance(is); Genesis.androidGetInstance(genesis);
genesis.close();
} catch (Exception e) { } catch (Exception e) {
System.out.println(e.getMessage()); System.out.println(e.getMessage());
} }
long endTime = System.nanoTime();
System.out.println((endTime - startTime)/1000000);
Genesis.reset();
*/
long startTime1 = System.nanoTime();
try {
InputStream genesis = getApplication().getAssets().open("genesis/genesis.bin");
InputStream premine = getApplication().getAssets().open("genesis/premine.bin");
InputStream roothash = getApplication().getAssets().open("genesis/roothash.bin");
Genesis.binaryGetInstance(genesis, premine, roothash);
genesis.close();
premine.close();
roothash.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
long endTime1 = System.nanoTime();
System.out.println((endTime1 - startTime1)/1000000);
System.out.println("Genesis loaded"); System.out.println("Genesis loaded");
if (privateKeys == null || privateKeys.size() == 0) { if (privateKeys == null || privateKeys.size() == 0) {
privateKeys = new ArrayList<>(); privateKeys = new ArrayList<>();

View File

@ -5,11 +5,12 @@ import org.ethereum.util.RLPList;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
import java.io.Serializable;
import java.math.BigInteger; import java.math.BigInteger;
import static org.ethereum.crypto.HashUtil.*; import static org.ethereum.crypto.HashUtil.*;
public class AccountState { public class AccountState implements Serializable {
private byte[] rlpEncoded; private byte[] rlpEncoded;

View File

@ -9,7 +9,13 @@ import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException; import org.json.simple.parser.ParseException;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -35,7 +41,7 @@ import static org.ethereum.util.ByteUtil.wrap;
* <p> * <p>
* See Yellow Paper: http://www.gavwood.com/Paper.pdf (Appendix I. Genesis Block) * See Yellow Paper: http://www.gavwood.com/Paper.pdf (Appendix I. Genesis Block)
*/ */
public class Genesis extends Block { public class Genesis extends Block implements Serializable {
private Map<ByteArrayWrapper, AccountState> premine = new HashMap<>(); private Map<ByteArrayWrapper, AccountState> premine = new HashMap<>();
@ -45,6 +51,10 @@ public class Genesis extends Block {
private static Block instance; private static Block instance;
public Genesis(byte[] rlpEncoded) {
super(rlpEncoded);
}
public Genesis(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] logsBloom, public Genesis(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] logsBloom,
byte[] difficulty, long number, long gasLimit, byte[] difficulty, long number, long gasLimit,
long gasUsed, long timestamp, long gasUsed, long timestamp,
@ -68,6 +78,17 @@ public class Genesis extends Block {
return instance; return instance;
} }
public static void reset() {
instance = null;
}
public static Block binaryGetInstance(InputStream genesis, InputStream premine, InputStream roothash) {
if (instance == null) {
instance = GenesisLoader.loadBinaryGenesis(genesis, premine, roothash);
}
return instance;
}
public Map<ByteArrayWrapper, AccountState> getPremine() { public Map<ByteArrayWrapper, AccountState> getPremine() {
return premine; return premine;
} }
@ -75,4 +96,17 @@ public class Genesis extends Block {
public void setPremine(Map<ByteArrayWrapper, AccountState> premine) { public void setPremine(Map<ByteArrayWrapper, AccountState> premine) {
this.premine = premine; this.premine = premine;
} }
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(obj);
return b.toByteArray();
}
public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream b = new ByteArrayInputStream(bytes);
ObjectInputStream o = new ObjectInputStream(b);
return o.readObject();
}
} }

View File

@ -4,15 +4,22 @@ import com.google.common.io.ByteStreams;
import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.JavaType;
import org.ethereum.core.AccountState; import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.core.Genesis; import org.ethereum.core.Genesis;
import org.ethereum.db.ByteArrayWrapper; import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.jsontestsuite.Utils; import org.ethereum.jsontestsuite.Utils;
import org.ethereum.trie.SecureTrie; import org.ethereum.trie.SecureTrie;
import org.ethereum.trie.Trie; import org.ethereum.trie.Trie;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
import org.ethereum.vm.program.Program;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -48,6 +55,97 @@ public class GenesisLoader {
byte[] rootHash = generateRootHash(premine); byte[] rootHash = generateRootHash(premine);
genesis.setStateRoot(rootHash); genesis.setStateRoot(rootHash);
return genesis;
} catch (Throwable e) {
System.err.print(e.getMessage());
System.err.println("Genesis block configuration is corrupted or not found ./resources/genesis/...");
System.exit(-1);
}
System.err.println("Genesis block configuration is corrupted or not found ./resources/genesis/...");
System.exit(-1);
return null;
}
public static void exportGenesis(Genesis genesis) {
try {
byte[] data = genesis.getEncoded();
FileOutputStream fos = new FileOutputStream("genesis.bin");
fos.write(data, 0, data.length);
fos.flush();
fos.close();
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(genesis.getPremine());
byte[] data1 = b.toByteArray();
FileOutputStream fos1 = new FileOutputStream("premine.bin");
fos1.write(data1, 0, data1.length);
fos1.flush();
fos1.close();
FileOutputStream fos2 = new FileOutputStream("roothash.bin");
fos2.write(genesis.getStateRoot(), 0, genesis.getStateRoot().length);
fos2.flush();
fos2.close();
} catch (Exception e) {
}
}
public static Genesis loadBinaryGenesis(InputStream genesisStream, InputStream premineStream, InputStream roothashStream) {
try {
byte[] data = ByteStreams.toByteArray(genesisStream);
Genesis genesis = new Genesis(data);
data = ByteStreams.toByteArray(premineStream);
Map<ByteArrayWrapper, AccountState> premine = (Map<ByteArrayWrapper, AccountState>)Genesis.deserialize(data);
genesis.setPremine(premine);
data = ByteStreams.toByteArray(roothashStream);
genesis.setStateRoot(data);
return genesis;
} catch (Throwable e) {
System.err.print(e.getMessage());
System.err.println("Genesis block configuration is corrupted or not found ./resources/genesis/...");
System.exit(-1);
}
System.err.println("Genesis block configuration is corrupted or not found ./resources/genesis/...");
System.exit(-1);
return null;
}
public static Genesis loadBinaryGenesis() {
try {
File inputFile = new File("genesis.bin");
byte[] data = new byte[(int)inputFile.length()];
FileInputStream fis = new FileInputStream(inputFile);
fis.read(data, 0, data.length);
fis.close();
Genesis genesis = new Genesis(data);
inputFile = new File("premine.bin");
data = new byte[(int)inputFile.length()];
fis = new FileInputStream(inputFile);
fis.read(data, 0, data.length);
fis.close();
Map<ByteArrayWrapper, AccountState> premine = (Map<ByteArrayWrapper, AccountState>)Genesis.deserialize(data);
genesis.setPremine(premine);
inputFile = new File("roothash.bin");
data = new byte[(int)inputFile.length()];
fis = new FileInputStream(inputFile);
fis.read(data, 0, data.length);
fis.close();
genesis.setStateRoot(data);
return genesis; return genesis;
} catch (Throwable e) { } catch (Throwable e) {

View File

@ -167,6 +167,7 @@ public class WorldManager {
Set<ByteArrayWrapper> keys = genesis.getPremine().keySet(); Set<ByteArrayWrapper> keys = genesis.getPremine().keySet();
int size = keys.size(); int size = keys.size();
int index = 0; int index = 0;
long startTime0 = System.nanoTime();
for (ByteArrayWrapper key : keys) { for (ByteArrayWrapper key : keys) {
index++; index++;
if (index % 500 == 0 || index == size) { if (index % 500 == 0 || index == size) {
@ -175,6 +176,8 @@ public class WorldManager {
repository.createAccount(key.getData()); repository.createAccount(key.getData());
repository.addBalance(key.getData(), genesis.getPremine().get(key).getBalance()); repository.addBalance(key.getData(), genesis.getPremine().get(key).getBalance());
} }
long endTime0 = System.nanoTime();
System.out.println("Import accounts time: " + ((endTime0 - startTime0) / 1000000));
blockStore.saveBlock(Genesis.getInstance(), Genesis.getInstance().getCumulativeDifficulty(), true); blockStore.saveBlock(Genesis.getInstance(), Genesis.getInstance().getCumulativeDifficulty(), true);
@ -183,7 +186,7 @@ public class WorldManager {
blockStore.flush(); blockStore.flush();
listener.onBlock(Genesis.getInstance(), new ArrayList<TransactionReceipt>()); listener.onBlock(Genesis.getInstance(), new ArrayList<TransactionReceipt>());
repository.dumpState(Genesis.getInstance(), 0, 0, null); repository.dumpState(Genesis.getInstance(), 0, 0, null);
repository.flush();
logger.info("Genesis block imported"); logger.info("Genesis block imported");
} else { } else {

View File

@ -55,8 +55,6 @@ public class Channel {
private final static Logger logger = LoggerFactory.getLogger("net"); private final static Logger logger = LoggerFactory.getLogger("net");
ChannelManager channelManager;
private MessageQueue msgQueue; private MessageQueue msgQueue;
private P2pHandler p2pHandler; private P2pHandler p2pHandler;
@ -81,10 +79,9 @@ public class Channel {
private boolean discoveryMode; private boolean discoveryMode;
@Inject @Inject
public Channel(ChannelManager channelManager, MessageQueue msgQueue, P2pHandler p2pHandler public Channel(MessageQueue msgQueue, P2pHandler p2pHandler
, ShhHandler shhHandler, BzzHandler bzzHandler, MessageCodec messageCodec , ShhHandler shhHandler, BzzHandler bzzHandler, MessageCodec messageCodec
, NodeManager nodeManager, EthHandlerFactory ethHandlerFactory) { , NodeManager nodeManager, EthHandlerFactory ethHandlerFactory) {
this.channelManager = channelManager;
this.msgQueue = msgQueue; this.msgQueue = msgQueue;
this.p2pHandler = p2pHandler; this.p2pHandler = p2pHandler;
this.shhHandler = shhHandler; this.shhHandler = shhHandler;