diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/datasource/LevelDbDataSource.java b/ethereumj-core-android/src/main/java/org/ethereum/android/datasource/LevelDbDataSource.java index 5e188cff..1c9215e4 100644 --- a/ethereumj-core-android/src/main/java/org/ethereum/android/datasource/LevelDbDataSource.java +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/datasource/LevelDbDataSource.java @@ -61,7 +61,7 @@ public class LevelDbDataSource implements KeyValueDataSource { options.logger(logger1); try { logger.debug("Opening database"); - File dbLocation = context.getDir(SystemProperties.CONFIG.databaseDir(), 0); + File dbLocation = new File(SystemProperties.CONFIG.databaseDir()); File fileLocation = new File(dbLocation, name); if (SystemProperties.CONFIG.databaseReset()) { diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/db/BlockStoreDatabase.java b/ethereumj-core-android/src/main/java/org/ethereum/android/db/BlockStoreDatabase.java index f9b3ed59..403b5bcd 100644 --- a/ethereumj-core-android/src/main/java/org/ethereum/android/db/BlockStoreDatabase.java +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/db/BlockStoreDatabase.java @@ -31,4 +31,6 @@ public interface BlockStoreDatabase { public void save(TransactionReceiptVO transactionReceiptVO); public TransactionReceipt getTransactionReceiptByHash(byte[] hash); + + public boolean flush(List blocks); } diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/db/BlockStoreImpl.java b/ethereumj-core-android/src/main/java/org/ethereum/android/db/BlockStoreImpl.java index d118ea97..8a0947ed 100644 --- a/ethereumj-core-android/src/main/java/org/ethereum/android/db/BlockStoreImpl.java +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/db/BlockStoreImpl.java @@ -28,7 +28,6 @@ public class BlockStoreImpl implements BlockStore { public Block getBlockByNumber(long blockNumber) { - List result = database.getByNumber(blockNumber); if (result.size() == 0) return null; BlockVO vo = (BlockVO) result.get(0); diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/db/InMemoryBlockStore.java b/ethereumj-core-android/src/main/java/org/ethereum/android/db/InMemoryBlockStore.java new file mode 100644 index 00000000..9a9248f7 --- /dev/null +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/db/InMemoryBlockStore.java @@ -0,0 +1,205 @@ +package org.ethereum.android.db; + + +import org.ethereum.core.Block; +import org.ethereum.core.TransactionReceipt; +import org.ethereum.db.BlockStore; +import org.ethereum.db.ByteArrayWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.math.BigInteger.ZERO; +import static org.ethereum.util.ByteUtil.wrap; + + +public class InMemoryBlockStore implements BlockStore { + + private static final Logger logger = LoggerFactory.getLogger("general"); + + Map hashIndex = new HashMap<>(); + Map numberIndex = new HashMap<>(); + List blocks = new ArrayList<>(); + + private BlockStoreDatabase database; + + BigInteger totalDifficulty = ZERO; + + public InMemoryBlockStore(BlockStoreDatabase database) { + + this.database = database; + } + + @Override + public byte[] getBlockHashByNumber(long blockNumber) { + + Block block = numberIndex.get(blockNumber); + + if (block == null) + return dbGetBlockHashByNumber(blockNumber); + else + return block.getHash(); + } + + @Override + public Block getBlockByNumber(long blockNumber) { + + Block block = numberIndex.get(blockNumber); + + if (block == null) + return dbGetBlockByNumber(blockNumber); + else + return block; + } + + @Override + public Block getBlockByHash(byte[] hash) { + + Block block = hashIndex.get(wrap(hash)); + + if (block == null) + return dbGetBlockByHash(hash); + else + return block; + } + + @Override + public List getListOfHashesStartFrom(byte[] hash, int qty) { + + Block startBlock = hashIndex.get(wrap(hash)); + + long endIndex = startBlock.getNumber() + qty; + endIndex = getBestBlock().getNumber() < endIndex ? getBestBlock().getNumber() : endIndex; + + List hashes = new ArrayList<>(); + + for (long i = startBlock.getNumber(); i <= endIndex; ++i){ + Block block = getBlockByNumber(i); + hashes.add(block.getHash() ); + } + + return hashes; + } + + @Override + public void deleteBlocksSince(long number) { + + // todo: delete blocks sinse + } + + @Override + public void saveBlock(Block block, List receipts) { + ByteArrayWrapper wHash = wrap(block.getHash()); + blocks.add(block); + hashIndex.put(wHash, block); + numberIndex.put(block.getNumber(), block); + totalDifficulty = totalDifficulty.add(block.getCumulativeDifficulty()); + } + + @Override + public BigInteger getTotalDifficultySince(long number) { + + // todo calculate from db + from cache + + throw new UnsupportedOperationException(); + } + + @Override + public BigInteger getTotalDifficulty() { + return totalDifficulty; + } + + @Override + public Block getBestBlock() { + if (blocks.size() == 0) return null; + return blocks.get(blocks.size() - 1); + } + + @Override + public List getAllBlocks() { + return blocks; + } + + @Override + public void reset() { + blocks.clear(); + hashIndex.clear(); + numberIndex.clear(); + } + + @Override + public TransactionReceipt getTransactionReceiptByHash(byte[] hash) { + return null; + } + + // FIXME: wrap from here in to db class + + public byte[] dbGetBlockHashByNumber(long blockNumber) { + + Block block = getBlockByNumber(blockNumber); + if (block != null) return block.getHash(); + return null; + } + + public Block dbGetBlockByNumber(long blockNumber) { + + List result = database.getByNumber(blockNumber); + if (result.size() == 0) return null; + BlockVO vo = (BlockVO) result.get(0); + + return new Block(vo.rlp); + } + + public Block dbGetBlockByHash(byte[] hash) { + + List result = database.getByHash(hash); + + if (result.size() == 0) return null; + BlockVO vo = (BlockVO) result.get(0); + + return new Block(vo.rlp); + } + + @Override + public void flush(){ + + long t_ = System.nanoTime(); + + database.flush(blocks); + Block block = getBestBlock(); + + blocks.clear(); + hashIndex.clear(); + numberIndex.clear(); + + saveBlock(block, null); + + long t__ = System.nanoTime(); + logger.info("Flush block store in: {} ms", ((float) (t__ - t_) / 1_000_000)); + + totalDifficulty = (BigInteger) database.getTotalDifficulty(); + } + + public void load(){ + + logger.info("loading db"); + + long t = System.nanoTime(); + + Block bestBlock = database.getBestBlock(); + if (bestBlock == null) return; + saveBlock(bestBlock, null); + + totalDifficulty = database.getTotalDifficulty(); + + long t_ = System.nanoTime(); + + logger.info("Loaded db in: {} ms", ((float)(t_ - t) / 1_000_000)); + } + +} \ No newline at end of file diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/db/OrmLiteBlockStoreDatabase.java b/ethereumj-core-android/src/main/java/org/ethereum/android/db/OrmLiteBlockStoreDatabase.java index 7c8ef683..782f6bac 100644 --- a/ethereumj-core-android/src/main/java/org/ethereum/android/db/OrmLiteBlockStoreDatabase.java +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/db/OrmLiteBlockStoreDatabase.java @@ -2,11 +2,13 @@ package org.ethereum.android.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; +import android.os.Environment; import android.util.Log; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.GenericRawResults; +import com.j256.ormlite.misc.TransactionManager; import com.j256.ormlite.stmt.DeleteBuilder; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; @@ -14,10 +16,12 @@ import com.j256.ormlite.table.TableUtils; import org.ethereum.core.Block; import org.ethereum.core.TransactionReceipt; +import java.io.File; import java.math.BigInteger; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implements BlockStoreDatabase { @@ -28,7 +32,8 @@ public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implement private Dao transactionDao = null; public OrmLiteBlockStoreDatabase(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); + super(context, Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + DATABASE_NAME, null, DATABASE_VERSION); } /** @@ -252,4 +257,27 @@ public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implement return new TransactionReceipt(vo.rlp); } + + public boolean flush(final List blocks) { + + try { + TransactionManager.callInTransaction(getBlockDao().getConnectionSource(), + new Callable() { + public Void call() throws Exception { + for (Block block : blocks) { + BlockVO blockVO = new BlockVO(block.getNumber(), block.getHash(), block.getEncoded(), block.getCumulativeDifficulty()); + save(blockVO); + } + // you could pass back an object here + return null; + } + }); + + + return true; + } catch(java.sql.SQLException e) { + Log.e(OrmLiteBlockStoreDatabase.class.getName(), "Error querying for hash", e); + return false; + } + } } diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/di/modules/EthereumModule.java b/ethereumj-core-android/src/main/java/org/ethereum/android/di/modules/EthereumModule.java index c5818731..8bc0db7b 100644 --- a/ethereumj-core-android/src/main/java/org/ethereum/android/di/modules/EthereumModule.java +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/di/modules/EthereumModule.java @@ -5,6 +5,7 @@ import android.content.Context; import com.j256.ormlite.android.apptools.OpenHelperManager; import org.ethereum.android.datasource.LevelDbDataSource; +import org.ethereum.android.db.InMemoryBlockStore; import org.ethereum.android.db.OrmLiteBlockStoreDatabase; import org.ethereum.android.db.BlockStoreImpl; import org.ethereum.config.SystemProperties; @@ -76,7 +77,7 @@ public class EthereumModule { @Singleton BlockStore provideBlockStore() { OrmLiteBlockStoreDatabase database = OpenHelperManager.getHelper(context, OrmLiteBlockStoreDatabase.class); - return new BlockStoreImpl(database); + return new InMemoryBlockStore(database); } @Provides diff --git a/ethereumj-core/src/main/resources/system.properties b/ethereumj-core/src/main/resources/system.properties index 36001248..70684ddd 100644 --- a/ethereumj-core/src/main/resources/system.properties +++ b/ethereumj-core/src/main/resources/system.properties @@ -90,7 +90,7 @@ samples.dir = samples database.reset = false # place to save physical storage files -database.dir = database +database.dir = /mnt/sdcard # this string is computed # to be eventually the address