Added ethereum implementation without world manager.

This commit is contained in:
Adrian Tiberius 2015-07-09 21:48:42 +02:00
parent 5c9058d980
commit cec379db59
7 changed files with 426 additions and 31 deletions

View File

@ -0,0 +1,392 @@
package org.ethereum.android;
import org.ethereum.android.manager.BlockLoader;
import org.ethereum.core.Block;
import org.ethereum.core.Genesis;
import org.ethereum.core.Transaction;
import org.ethereum.core.TransactionReceipt;
import org.ethereum.core.Wallet;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.BlockStore;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.facade.Blockchain;
import org.ethereum.facade.Repository;
import org.ethereum.listener.CompositeEthereumListener;
import org.ethereum.listener.EthereumListener;
import org.ethereum.manager.AdminInfo;
import org.ethereum.net.client.PeerClient;
import org.ethereum.net.peerdiscovery.PeerDiscovery;
import org.ethereum.net.peerdiscovery.PeerInfo;
import org.ethereum.net.server.ChannelManager;
import org.ethereum.net.server.PeerServer;
import org.ethereum.net.submit.TransactionExecutor;
import org.ethereum.net.submit.TransactionTask;
import org.ethereum.util.ByteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.inject.Inject;
import javax.inject.Provider;
import static org.ethereum.config.SystemProperties.CONFIG;
public class Ethereum implements org.ethereum.facade.Ethereum {
private static final Logger logger = LoggerFactory.getLogger("facade");
BlockStore blockStore;
Blockchain blockchain;
Repository repository;
EthereumListener listener;
AdminInfo adminInfo;
ChannelManager channelManager;
PeerServer peerServer;
PeerDiscovery peerDiscovery;
BlockLoader blockLoader;
Provider<PeerClient> peerClientProvider;
Wallet wallet;
private PeerClient activePeer;
@Inject
public Ethereum(Blockchain blockchain, BlockStore blockStore, Repository repository, AdminInfo adminInfo,
ChannelManager channelManager, BlockLoader blockLoader,
Provider<PeerClient> peerClientProvider, EthereumListener listener,
PeerDiscovery peerDiscovery, Wallet wallet) {
System.out.println();
logger.info("EthereumImpl constructor");
this.blockchain = blockchain;
this.blockStore = blockStore;
this.repository = repository;
this.adminInfo = adminInfo;
this.channelManager = channelManager;
this.blockLoader = blockLoader;
this.peerClientProvider = peerClientProvider;
this.listener = listener;
this.peerDiscovery = peerDiscovery;
this.wallet = wallet;
}
@Override
public void init() {
init(null);
}
public void init(List<String> addresses) {
if (addresses != null) {
for (String address: addresses) {
wallet.importKey(address.getBytes());
}
}
// Load the blockchain
loadBlockchain();
// Start peer server
if (CONFIG.listenPort() > 0) {
Executors.newSingleThreadExecutor().submit(
new Runnable() {
public void run() {
// peerServer.start(CONFIG.listenPort());
}
}
);
}
}
public byte[] createRandomAccount() {
byte[] randomAddress = HashUtil.sha3(HashUtil.randomPeerId());
wallet.importKey(randomAddress);
return randomAddress;
}
public void loadBlockchain() {
if (!CONFIG.databaseReset())
blockStore.load();
Block bestBlock = blockStore.getBestBlock();
if (bestBlock == null) {
logger.info("DB is empty - adding Genesis");
Genesis genesis = (Genesis)Genesis.getInstance();
for (ByteArrayWrapper key : genesis.getPremine().keySet()) {
repository.createAccount(key.getData());
repository.addBalance(key.getData(), genesis.getPremine().get(key).getBalance());
}
blockStore.saveBlock(Genesis.getInstance(), new ArrayList<TransactionReceipt>());
blockchain.setBestBlock(Genesis.getInstance());
blockchain.setTotalDifficulty(Genesis.getInstance().getCumulativeDifficulty());
listener.onBlock(Genesis.getInstance(), new ArrayList<TransactionReceipt>() );
repository.dumpState(Genesis.getInstance(), 0, 0, null);
logger.info("Genesis block loaded");
} else {
blockchain.setBestBlock(bestBlock);
BigInteger totalDifficulty = blockStore.getTotalDifficulty();
blockchain.setTotalDifficulty(totalDifficulty);
logger.info("*** Loaded up to block [{}] totalDifficulty [{}] with stateRoot [{}]",
blockchain.getBestBlock().getNumber(),
blockchain.getTotalDifficulty().toString(),
Hex.toHexString(blockchain.getBestBlock().getStateRoot()));
}
if (CONFIG.rootHashStart() != null) {
// update world state by dummy hash
byte[] rootHash = Hex.decode(CONFIG.rootHashStart());
logger.info("Loading root hash from property file: [{}]", CONFIG.rootHashStart());
this.repository.syncToRoot(rootHash);
} else {
// Update world state to latest loaded block from db
this.repository.syncToRoot(blockchain.getBestBlock().getStateRoot());
}
/* todo: return it when there is no state conflicts on the chain
boolean dbValid = this.repository.getWorldState().validate() || bestBlock.isGenesis();
if (!dbValid){
logger.error("The DB is not valid for that blockchain");
System.exit(-1); // todo: reset the repository and blockchain
}
*/
}
/**
* Find a peer but not this one
*
* @param peer - peer to exclude
* @return online peer
*/
@Override
public PeerInfo findOnlinePeer(PeerInfo peer) {
Set<PeerInfo> excludePeers = new HashSet<>();
excludePeers.add(peer);
return findOnlinePeer(excludePeers);
}
@Override
public PeerInfo findOnlinePeer() {
Set<PeerInfo> excludePeers = new HashSet<>();
return findOnlinePeer(excludePeers);
}
@Override
public PeerInfo findOnlinePeer(Set<PeerInfo> excludePeers) {
logger.info("Looking for online peers...");
final EthereumListener listener = this.listener;
listener.trace("Looking for online peer");
startPeerDiscovery();
final Set<PeerInfo> peers = getPeers();
for (PeerInfo peer : peers) { // it blocks until a peer is available.
if (peer.isOnline() && !excludePeers.contains(peer)) {
logger.info("Found peer: {}", peer.toString());
listener.trace(String.format("Found online peer: [ %s ]", peer.toString()));
return peer;
}
}
return null;
}
@Override
public PeerInfo waitForOnlinePeer() {
PeerInfo peer = null;
while (peer == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
peer = this.findOnlinePeer();
}
return peer;
}
@Override
public Set<PeerInfo> getPeers() {
return peerDiscovery.getPeers();
}
@Override
public void startPeerDiscovery() {
if (!peerDiscovery.isStarted())
peerDiscovery.start();
}
@Override
public void stopPeerDiscovery() {
if (peerDiscovery.isStarted())
peerDiscovery.stop();
}
@Override
public void connect(InetAddress addr, int port, String remoteId) {
connect(addr.getHostName(), port, remoteId);
}
@Override
public void connect(String ip, int port, String remoteId) {
logger.info("Connecting to: {}:{}", ip, port);
if (activePeer == null)
activePeer = peerClientProvider.get();
activePeer.connect(ip, port, remoteId);
}
@Override
public Blockchain getBlockchain() {
return blockchain;
}
@Override
public void addListener(EthereumListener listener) {
((CompositeEthereumListener) this.listener).addListener(listener);
}
@Override
public boolean isBlockchainLoading() {
return blockchain.getQueue().size() > 2;
}
@Override
public void close() {
stopPeerDiscovery();
repository.close();
blockchain.close();
}
@Override
public PeerClient getDefaultPeer() {
if (activePeer == null) {
activePeer = peerClientProvider.get();
}
return activePeer;
}
@Override
public boolean isConnected() {
return activePeer != null;
}
@Override
public Transaction createTransaction(BigInteger nonce,
BigInteger gasPrice,
BigInteger gas,
byte[] receiveAddress,
BigInteger value, byte[] data) {
byte[] nonceBytes = ByteUtil.bigIntegerToBytes(nonce);
byte[] gasPriceBytes = ByteUtil.bigIntegerToBytes(gasPrice);
byte[] gasBytes = ByteUtil.bigIntegerToBytes(gas);
byte[] valueBytes = ByteUtil.bigIntegerToBytes(value);
return new Transaction(nonceBytes, gasPriceBytes, gasBytes,
receiveAddress, valueBytes, data);
}
@Override
public Future<Transaction> submitTransaction(Transaction transaction) {
TransactionTask transactionTask = new TransactionTask(transaction, channelManager);
return TransactionExecutor.instance.submitTransaction(transactionTask);
}
@Override
public Wallet getWallet() {
return wallet;
}
@Override
public Repository getRepository() {
return repository;
}
@Override
public AdminInfo getAdminInfo() {
return adminInfo;
}
@Override
public ChannelManager getChannelManager() {
return channelManager;
}
@Override
public Set<Transaction> getPendingTransactions() {
return blockchain.getPendingTransactions();
}
@Override
public BlockLoader getBlockLoader() {
return blockLoader;
}
@Override
public void exitOn(long number) {
blockchain.setExitOn(number);
}
}

View File

@ -18,7 +18,6 @@ import org.ethereum.listener.CompositeEthereumListener;
import org.ethereum.listener.EthereumListener;
import org.ethereum.manager.AdminInfo;
import org.ethereum.android.manager.BlockLoader;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.MessageQueue;
import org.ethereum.net.client.PeerClient;
import org.ethereum.net.eth.EthHandler;
@ -60,16 +59,9 @@ public class EthereumModule {
@Provides
@Singleton
Ethereum provideEthereum(WorldManager worldManager, AdminInfo adminInfo, ChannelManager channelManager,
BlockLoader blockLoader, Provider<PeerClient> peerClientProvider, EthereumListener listener) {
return new EthereumImpl(worldManager, adminInfo, channelManager, blockLoader, peerClientProvider, listener);
}
@Provides
@Singleton
WorldManager provideWorldManager(Blockchain blockchain, Repository repository, Wallet wallet, PeerDiscovery peerDiscovery
,BlockStore blockStore, ChannelManager channelManager, AdminInfo adminInfo, EthereumListener listener) {
return new WorldManager(blockchain, repository, wallet, peerDiscovery, blockStore, channelManager, adminInfo, listener);
Ethereum provideEthereum(Blockchain blockchain, BlockStore blockStore, Repository repository, AdminInfo adminInfo, ChannelManager channelManager,
BlockLoader blockLoader, Provider<PeerClient> peerClientProvider, EthereumListener listener, PeerDiscovery peerDiscovery, Wallet wallet) {
return new org.ethereum.android.Ethereum(blockchain, blockStore, repository, adminInfo, channelManager, blockLoader, peerClientProvider, listener, peerDiscovery, wallet);
}
@Provides
@ -137,8 +129,8 @@ public class EthereumModule {
}
@Provides
ShhHandler provideShhHandler(WorldManager worldManager) {
return new ShhHandler(worldManager);
ShhHandler provideShhHandler(EthereumListener listener) {
return new ShhHandler(listener);
}
@Provides

View File

@ -18,12 +18,16 @@ import org.ethereum.android.service.events.VMTraceCreatedEventData;
import org.ethereum.config.SystemProperties;
import org.ethereum.core.Transaction;
import org.ethereum.core.TransactionReceipt;
import org.ethereum.facade.Ethereum;
import org.ethereum.crypto.HashUtil;
import org.ethereum.android.Ethereum;
import org.ethereum.net.p2p.HelloMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.ethereum.config.SystemProperties.CONFIG;
public class EthereumService extends Service {
static boolean isConnected = false;
@ -68,10 +72,20 @@ public class EthereumService extends Service {
System.out.println("Database folder: " + databaseFolder);
SystemProperties.CONFIG.setDataBaseDir(databaseFolder);
ethereum = DaggerEthereumComponent.builder()
ethereum = (Ethereum)DaggerEthereumComponent.builder()
.ethereumModule(new EthereumModule(this))
.build().ethereum();
ethereum.addListener(new EthereumListener());
// TODO: Add init and add/remove address service messages
List<String> addresses = new ArrayList<String>();
byte[] cowAddr = HashUtil.sha3("cow".getBytes());
addresses.add(new String(cowAddr));
String secret = CONFIG.coinbaseSecret();
byte[] cbAddr = HashUtil.sha3(secret.getBytes());
addresses.add(new String(cbAddr));
ethereum.init(addresses);
isInitialized = true;
} else {
System.out.println(" Already initialized");

View File

@ -124,8 +124,8 @@ public class EthereumModule {
}
@Provides
ShhHandler provideShhHandler(WorldManager worldManager) {
return new ShhHandler(worldManager);
ShhHandler provideShhHandler(EthereumListener listener) {
return new ShhHandler(listener);
}
@Provides

View File

@ -223,7 +223,7 @@ public class EthereumImpl implements Ethereum {
@Override
public Future<Transaction> submitTransaction(Transaction transaction) {
TransactionTask transactionTask = new TransactionTask(transaction, worldManager);
TransactionTask transactionTask = new TransactionTask(transaction, channelManager);
return TransactionExecutor.instance.submitTransaction(transactionTask);
}

View File

@ -2,7 +2,7 @@ package org.ethereum.net.shh;
import org.ethereum.crypto.ECKey;
import org.ethereum.facade.Blockchain;
import org.ethereum.manager.WorldManager;
import org.ethereum.listener.EthereumListener;
import org.ethereum.net.MessageQueue;
import io.netty.channel.ChannelHandlerContext;
@ -32,12 +32,11 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
private final static Logger logger = LoggerFactory.getLogger("net");
WorldManager worldManager;
EthereumListener listener;
@Inject
public ShhHandler(WorldManager worldManager) {
this.worldManager = worldManager;
public ShhHandler(EthereumListener listener) {
this.listener = listener;
}
public ShhHandler(MessageQueue msgQueue) {
@ -56,11 +55,11 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
if (ShhMessageCodes.inRange(msg.getCommand().asByte()))
logger.info("ShhHandler invoke: [{}]", msg.getCommand());
worldManager.getListener().trace(String.format("ShhHandler invoke: [%s]", msg.getCommand()));
listener.trace(String.format("ShhHandler invoke: [%s]", msg.getCommand()));
switch (msg.getCommand()) {
case STATUS:
worldManager.getListener().trace("[Recv: " + msg + "]");
listener.trace("[Recv: " + msg + "]");
break;
case MESSAGE:
whisper.processEnvelope((Envelope) msg);
@ -91,7 +90,7 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
public void activate() {
logger.info("SHH protocol activated");
worldManager.getListener().trace("SHH protocol activated");
listener.trace("SHH protocol activated");
whisper = new Whisper(msgQueue);
sendStatus();
this.active = true;

View File

@ -2,7 +2,6 @@ package org.ethereum.net.submit;
import org.ethereum.core.Transaction;
import org.ethereum.core.Wallet;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.server.ChannelManager;
import org.slf4j.Logger;
@ -21,11 +20,11 @@ public class TransactionTask implements Callable<Transaction> {
private static final Logger logger = LoggerFactory.getLogger("net");
private final Transaction tx;
private final WorldManager worldManager;
private final ChannelManager channelManager;
public TransactionTask(Transaction tx, WorldManager worldManager) {
public TransactionTask(Transaction tx, ChannelManager channelManager) {
this.tx = tx;
this.worldManager = worldManager;
this.channelManager = channelManager;
}
@Override
@ -33,7 +32,6 @@ public class TransactionTask implements Callable<Transaction> {
try {
logger.info("submit tx: {}", tx.toString());
ChannelManager channelManager = worldManager.getChannelManager();
channelManager.sendTransaction(tx);
return tx;