Merge branch 'android-test-poc9-rlpx' of opulence.git.beanstalkapp.com:/opulence/ethereumj into android-test-poc9-rlpx

This commit is contained in:
Jarrad Hope 2015-06-23 08:53:20 +02:00
commit 7ffb5c16e5
178 changed files with 8703 additions and 755 deletions

View File

@ -2,7 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.ethereum.android_app" >
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="org.ethereum.android_app.EthereumApplication"
android:allowBackup="true"
@ -20,5 +19,7 @@
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest>

View File

@ -31,6 +31,7 @@ public class ConsoleFragment extends Fragment {
public void setEthereumManager(EthereumManager ethereumManager) {
this.ethereumManager = ethereumManager;
/*
ethereumManager.addListener(new EthereumListenerAdapter() {
@Override
@ -38,12 +39,18 @@ public class ConsoleFragment extends Fragment {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
console.append(output);
//console.append(output);
}
});
}
});
*/
}
public void updateDuration(long duration) {
console.append(String.valueOf(duration/1000) + "seconds");
}
}

View File

@ -2,6 +2,7 @@ package org.ethereum.android_app;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Environment;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
@ -12,6 +13,9 @@ import android.view.MenuItem;
import android.os.Build;
import org.ethereum.android.EthereumManager;
import org.ethereum.config.SystemProperties;
import java.io.File;
public class MainActivity extends ActionBarActivity {
@ -35,7 +39,15 @@ public class MainActivity extends ActionBarActivity {
toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
ethereumManager = new EthereumManager(this);
String databaseFolder = null;
File extStore = Environment.getExternalStorageDirectory();
if (extStore.exists()) {
databaseFolder = extStore.getAbsolutePath();
} else {
databaseFolder = getApplicationInfo().dataDir;
}
ethereumManager = new EthereumManager(this, databaseFolder);
adapter = new TabsPagerAdapter(getSupportFragmentManager(), ethereumManager);
viewPager = (ViewPager) findViewById(R.id.pager);
@ -100,7 +112,9 @@ public class MainActivity extends ActionBarActivity {
Log.v(TAG, "111");
Log.v(TAG, "222");
ethereumManager.connect();
long duration = ethereumManager.connect(SystemProperties.CONFIG.databaseDir() + File.separator + "poc-9-492k.dmp");
//ConsoleFragment consoleeFrag = (ConsoleFragment)getSupportFragmentManager().findFragmentById(R.id.console);
//consoleeFrag.updateDuration(duration);
Log.v(TAG, "333");
while(true) {

View File

@ -33,6 +33,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
tasks.withType(JavaCompile){
@ -40,11 +43,14 @@ tasks.withType(JavaCompile){
}
dependencies {
apt 'com.google.dagger:dagger-compiler:2.0'
apt "com.google.dagger:dagger-compiler:2.0"
compile fileTree(dir: 'libs', include: ['*.jar'])
compile (project(':ethereumj-core')) {
exclude group: "commons-codec", module: "commons-codec"
exclude group: "commons-logging", module: "commons-logging"
exclude group: "org.apache.commons", module: "commons-pool2"
exclude group: "org.slf4j", module: "slf4j-log4j12"
exclude group: "log4j", module: "apache-log4j-extras"
exclude group: "org.hibernate", module: "hibernate-core"
exclude group: "org.hibernate", module: "hibernate-entitymanager"
exclude group: "redis.clients", module: "jedis"
@ -55,8 +61,10 @@ dependencies {
compile "com.j256.ormlite:ormlite-android:4.48"
compile "org.glassfish:javax.annotation:10.0-b28"
compile "org.iq80.leveldb:leveldb:0.7"
compile 'org.slf4j:slf4j-android:1.7.12'
compile 'javax.persistence:persistence-api:1.0.2'
compile "com.github.tony19:logback-android-core:1.1.1-3"
compile "com.github.tony19:logback-android-classic:1.1.1-3"
compile "org.slf4j:slf4j-api:1.7.12"
compile "javax.persistence:persistence-api:1.0.2"
compile group: 'com.thetransactioncompany', name: 'jsonrpc2-server', version: '1.11'
compile group: "com.thetransactioncompany", name: "jsonrpc2-server", version: "1.11"
}

View File

@ -0,0 +1,142 @@
<configuration>
<property name="LOG_DIR" value="/data/data/org.ethereum.android_app/files" />
<!-- Create a logcat appender -->
<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>%msg</pattern>
</encoder>
</appender>
<!-- Create a file appender for TRACE-level messages
<appender name="TraceLog" class="ch.qos.logback.core.FileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>TRACE</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_DIR}/trace.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
Create a file appender for DEBUG-level messages
<appender name="DebugLog" class="ch.qos.logback.core.FileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_DIR}/debug.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
-->
<logger name="core" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="net" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="db" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="peerdiscovery" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="io.netty" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="wire" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="wallet" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="dump" level="OFF">
<appender-ref ref="logcat" />
</logger>
<logger name="trie" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="block" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="blockqueue" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="general" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="peermonitor" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="VM" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="main" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="state" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="repository" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="blockchain" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="txs" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="gas" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="execute" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="hsqldb.db" level="ERROR">
<appender-ref ref="logcat" />
</logger>
<logger name="test" level="INFO">
<appender-ref ref="logcat" />
</logger>
<root level="INFO">
<appender-ref ref="logcat" />
</root>
</configuration>

View File

@ -9,6 +9,7 @@ import org.ethereum.android.di.components.DaggerEthereumComponent;
import org.ethereum.config.SystemProperties;
import org.ethereum.facade.Ethereum;
import org.ethereum.listener.EthereumListenerAdapter;
import org.ethereum.android.manager.BlockLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ethereum.android.jsonrpc.JsonRpcServer;
@ -22,9 +23,16 @@ public class EthereumManager {
private JsonRpcServer jsonRpcServer;
public EthereumManager(Context context) {
public EthereumManager(Context context, String databaseFolder) {
System.setProperty("sun.arch.data.model", "32");
System.setProperty("leveldb.mmap", "false");
if (databaseFolder != null) {
System.out.println("Database folder: " + databaseFolder);
SystemProperties.CONFIG.setDataBaseDir(databaseFolder);
}
ethereum = DaggerEthereumComponent.builder()
.ethereumModule(new EthereumModule(context))
.build().ethereum();
@ -36,12 +44,18 @@ public class EthereumManager {
}
public void connect() {
public long connect(String dumpFile) {
ethereum.connect(SystemProperties.CONFIG.activePeerIP(),
SystemProperties.CONFIG.activePeerPort(),
SystemProperties.CONFIG.activePeerNodeid());
//ethereum.getBlockchain();
long duration = 0;
if (dumpFile == null) {
ethereum.connect(SystemProperties.CONFIG.activePeerIP(),
SystemProperties.CONFIG.activePeerPort(),
SystemProperties.CONFIG.activePeerNodeid());
} else {
BlockLoader blockLoader = (BlockLoader)ethereum.getBlockLoader();
blockLoader.loadBlocks(dumpFile);
}
return duration;
}
public void startPeerDiscovery() {
@ -59,7 +73,13 @@ public class EthereumManager {
jsonRpcServer.start();
}
public void onDestroy() {
public void onDestroy() {
close();
}
public void close() {
ethereum.close();
OpenHelperManager.releaseHelper();
}

View File

@ -3,6 +3,8 @@ package org.ethereum.android.datasource;
import org.ethereum.config.SystemProperties;
import org.ethereum.datasource.KeyValueDataSource;
import org.fusesource.leveldbjni.JniDBFactory;
import org.fusesource.leveldbjni.internal.JniDB;
import org.iq80.leveldb.CompressionType;
import org.iq80.leveldb.DB;
import org.iq80.leveldb.DBIterator;
@ -53,23 +55,37 @@ public class LevelDbDataSource implements KeyValueDataSource {
Options options = new Options();
options.createIfMissing(true);
options.compressionType(CompressionType.NONE);
org.iq80.leveldb.Logger logger1 = new org.iq80.leveldb.Logger() {
public void log(String message) {
logger.debug(message);
}
};
options.logger(logger1);
options.blockSize(10 * 1024);
options.writeBufferSize(10 * 1024);
options.cacheSize(0);
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()) {
destroyDB(fileLocation);
}
logger.debug("Initializing new or existing database: '{}'", fileLocation.getAbsolutePath());
db = Iq80DBFactory.factory.open(fileLocation, options);
logger.debug("Initializing new or existing database: '{}'", name);
try {
db = JniDBFactory.factory.open(fileLocation, options);
} catch (Throwable e) {
System.out.println("No native version of LevelDB found");
}
String cpu = System.getProperty("sun.arch.data.model");
String os = System.getProperty("os.name");
if (db instanceof JniDB)
System.out.println("Native version of LevelDB loaded for: " + os + "." + cpu + "bit");
else{
System.out.println("Pure Java version of LevelDB loaded");
db = Iq80DBFactory.factory.open(fileLocation, options);
}
} catch (IOException ioe) {
logger.error(ioe.getMessage(), ioe);
@ -143,4 +159,4 @@ public class LevelDbDataSource implements KeyValueDataSource {
logger.error("Failed to find the db file on the close: {} ", name);
}
}
}
}

View File

@ -31,4 +31,6 @@ public interface BlockStoreDatabase {
public void save(TransactionReceiptVO transactionReceiptVO);
public TransactionReceipt getTransactionReceiptByHash(byte[] hash);
public boolean flush(List<Block> blocks);
}

View File

@ -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);
@ -110,4 +109,14 @@ public class BlockStoreImpl implements BlockStore {
return database.getTransactionReceiptByHash(hash);
}
@Override
public void load() {
}
@Override
public void flush() {
}
}

View File

@ -9,7 +9,7 @@ import java.math.BigInteger;
@DatabaseTable(tableName = "block")
public class BlockVO {
@DatabaseField(index = true, dataType = DataType.BYTE_ARRAY)
@DatabaseField(index = true, persisterClass = HashPersister.class)
byte[] hash;
@DatabaseField(index = true, dataType = DataType.LONG_OBJ)

View File

@ -0,0 +1,65 @@
package org.ethereum.android.db;
import android.text.TextUtils;
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.field.SqlType;
import com.j256.ormlite.field.types.StringType;
import android.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HashPersister extends StringType
{
private static final String delimiter = ",";
private static final HashPersister singleTon = new HashPersister();
private static final Logger logger = LoggerFactory.getLogger("persister");
private HashPersister()
{
super(SqlType.STRING, new Class<?>[]{ String[].class });
}
public static HashPersister getSingleton()
{
return singleTon;
}
@Override
public Object javaToSqlArg(FieldType fieldType, Object javaObject)
{
byte[] array = (byte[]) javaObject;
if (array == null)
{
return null;
}
else
{
String string = new String(Base64.encode(array, Base64.DEFAULT));
//String string = new String(array);
//logger.info("sqlArgToJava: " + string);
return string;
}
}
@Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos)
{
String string = (String)sqlArg;
//logger.info("sqlArgToJava: " + string);
if ( string == null )
{
return null;
}
else
{
return Base64.decode(string, Base64.DEFAULT);
//return string.getBytes();
}
}
}

View File

@ -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<ByteArrayWrapper, Block> hashIndex = new HashMap<>();
Map<Long, Block> numberIndex = new HashMap<>();
List<Block> 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<byte[]> getListOfHashesStartFrom(byte[] hash, int qty) {
Block startBlock = hashIndex.get(wrap(hash));
long endIndex = startBlock.getNumber() + qty;
endIndex = getBestBlock().getNumber() < endIndex ? getBestBlock().getNumber() : endIndex;
List<byte[]> 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<TransactionReceipt> 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<Block> 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));
}
}

View File

@ -2,22 +2,27 @@ 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;
import org.ethereum.config.SystemProperties;
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 +33,8 @@ public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implement
private Dao<TransactionReceiptVO, Integer> transactionDao = null;
public OrmLiteBlockStoreDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
super(context, SystemProperties.CONFIG.databaseDir()
+ File.separator + DATABASE_NAME, null, DATABASE_VERSION);
}
/**
@ -191,7 +197,7 @@ public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implement
try {
GenericRawResults<String[]> rawResults = getBlockDao().queryRaw("select max(number) from block");
List<String[]> results = rawResults.getResults();
if (results.size() > 0 && results.get(0).length > 0) {
if (results.get(0)[0] != null) {
bestNumber = Long.valueOf(results.get(0)[0]);
}
} catch(java.sql.SQLException e) {
@ -252,4 +258,30 @@ public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implement
return new TransactionReceipt(vo.rlp);
}
public boolean flush(final List<Block> blocks) {
reset();
try {
TransactionManager.callInTransaction(getBlockDao().getConnectionSource(),
new Callable<Void>() {
public Void call() throws Exception {
int lastIndex = blocks.size() - 1;
for (int i = 0; i < 1000; ++i){
Block block = blocks.get(lastIndex - i);
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;
}
}
}

View File

@ -16,7 +16,7 @@ import javax.persistence.Table;
@DatabaseTable(tableName = "transaction_receipt")
public class TransactionReceiptVO {
@DatabaseField(index = true, dataType = DataType.BYTE_ARRAY)
@DatabaseField(index = true, persisterClass = HashPersister.class)
byte[] hash;
@DatabaseField(dataType = DataType.BYTE_ARRAY)

View File

@ -5,8 +5,8 @@ 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;
import org.ethereum.core.BlockchainImpl;
import org.ethereum.core.Wallet;
@ -19,7 +19,7 @@ import org.ethereum.facade.Repository;
import org.ethereum.listener.CompositeEthereumListener;
import org.ethereum.listener.EthereumListener;
import org.ethereum.manager.AdminInfo;
import org.ethereum.manager.BlockLoader;
import org.ethereum.android.manager.BlockLoader;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.MessageQueue;
import org.ethereum.net.client.PeerClient;
@ -76,7 +76,7 @@ public class EthereumModule {
@Singleton
BlockStore provideBlockStore() {
OrmLiteBlockStoreDatabase database = OpenHelperManager.getHelper(context, OrmLiteBlockStoreDatabase.class);
return new BlockStoreImpl(database);
return new InMemoryBlockStore(database);
}
@Provides

View File

@ -28,6 +28,7 @@ import io.netty.util.CharsetUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.channel.ChannelFuture;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.facade.Ethereum;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
@ -48,11 +49,75 @@ public final class JsonRpcServer {
this.ethereum = ethereum;
this.dispatcher = new Dispatcher();
this.dispatcher.register(new web3_clientVersion(this.ethereum));
this.dispatcher.register(new web3_sha3(this.ethereum));
this.dispatcher.register(new net_version(this.ethereum));
this.dispatcher.register(new net_listening(this.ethereum));
this.dispatcher.register(new net_peerCount(this.ethereum));
this.dispatcher.register(new eth_protocolVersion(this.ethereum));
this.dispatcher.register(new eth_coinbase(this.ethereum));
this.dispatcher.register(new eth_mining(this.ethereum));
this.dispatcher.register(new eth_hashrate(this.ethereum));
this.dispatcher.register(new eth_gasPrice(this.ethereum));
this.dispatcher.register(new eth_accounts(this.ethereum));
this.dispatcher.register(new eth_blockNumber(this.ethereum));
this.dispatcher.register(new eth_getBalance(this.ethereum));
this.dispatcher.register(new eth_getStorageAt(this.ethereum));
this.dispatcher.register(new eth_getTransactionCount(this.ethereum));
this.dispatcher.register(new eth_getBlockTransactionCountByHash(this.ethereum));
this.dispatcher.register(new eth_getBlockTransactionCountByNumber(this.ethereum));
this.dispatcher.register(new eth_getUncleCountByBlockHash(this.ethereum));
this.dispatcher.register(new eth_getUncleCountByBlockNumber(this.ethereum));
this.dispatcher.register(new eth_getCode(this.ethereum));
this.dispatcher.register(new eth_sign(this.ethereum));
this.dispatcher.register(new eth_sendTransaction(this.ethereum));
this.dispatcher.register(new eth_call(this.ethereum));
this.dispatcher.register(new eth_estimateGas(this.ethereum));
this.dispatcher.register(new eth_getBlockByHash(this.ethereum));
this.dispatcher.register(new eth_getBlockByNumber(this.ethereum));
this.dispatcher.register(new eth_getTransactionByHash(this.ethereum));
this.dispatcher.register(new eth_getTransactionByBlockHashAndIndex(this.ethereum));
this.dispatcher.register(new eth_getTransactionByBlockNumberAndIndex(this.ethereum));
this.dispatcher.register(new eth_getUncleByBlockHashAndIndex(this.ethereum));
this.dispatcher.register(new eth_getUncleByBlockNumberAndIndex(this.ethereum));
this.dispatcher.register(new eth_getCompilers(this.ethereum));
this.dispatcher.register(new eth_compileSolidity(this.ethereum));
this.dispatcher.register(new eth_compileLLL(this.ethereum));
this.dispatcher.register(new eth_compileSerpent(this.ethereum));
this.dispatcher.register(new eth_newFilter(this.ethereum));
this.dispatcher.register(new eth_newBlockFilter(this.ethereum));
this.dispatcher.register(new eth_newPendingTransactionFilter(this.ethereum));
this.dispatcher.register(new eth_uninstallFilter(this.ethereum));
this.dispatcher.register(new eth_getFilterChanges(this.ethereum));
this.dispatcher.register(new eth_getFilterLogs(this.ethereum));
this.dispatcher.register(new eth_getLogs(this.ethereum));
this.dispatcher.register(new eth_getWork(this.ethereum));
this.dispatcher.register(new eth_submitWork(this.ethereum));
this.dispatcher.register(new db_putString(this.ethereum));
this.dispatcher.register(new db_getString(this.ethereum));
this.dispatcher.register(new db_putHex(this.ethereum));
this.dispatcher.register(new db_getHex(this.ethereum));
this.dispatcher.register(new shh_version(this.ethereum));
this.dispatcher.register(new shh_post(this.ethereum));
this.dispatcher.register(new shh_newIdentity(this.ethereum));
this.dispatcher.register(new shh_hasIdentity(this.ethereum));
this.dispatcher.register(new shh_newGroup(this.ethereum));
this.dispatcher.register(new shh_addToGroup(this.ethereum));
this.dispatcher.register(new shh_newFilter(this.ethereum));
this.dispatcher.register(new shh_uninstallFilter(this.ethereum));
this.dispatcher.register(new shh_getFilterChanges(this.ethereum));
this.dispatcher.register(new shh_getMessages(this.ethereum));
FilterManager.getInstance();
org.ethereum.android.jsonrpc.whisper.FilterManager.getInstance();
}
public void start() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {

View File

@ -0,0 +1,257 @@
package org.ethereum.android.jsonrpc;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServer;
import org.ethereum.core.Account;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.core.BlockHeader;
import org.ethereum.core.Transaction;
import org.ethereum.crypto.HashUtil;
import org.ethereum.facade.Ethereum;
import org.ethereum.util.RLP;
import org.ethereum.vm.DataWord;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import static org.ethereum.core.Denomination.SZABO;
public abstract class JsonRpcServerMethod implements RequestHandler {
private String name = "";
protected Ethereum ethereum;
public JsonRpcServerMethod(Ethereum ethereum) {
this.ethereum = ethereum;
name = this.getClass().getSimpleName();
}
public String[] handledRequests() {
return new String[]{name};
}
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals(name)) {
return worker(req, ctx);
} else {
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
protected abstract JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx);
protected long getBlockNumber(String height) {
long blockNumber = 0;
switch (height) {
case "earliest":
blockNumber = 0;
break;
case "latest":
blockNumber = -1;
break;
case "pending":
blockNumber = -2;
break;
default:
blockNumber = jsToLong(height);
}
if (blockNumber >= 0)
blockNumber = -1;
return blockNumber;
}
protected byte[] jsToAddress(String data) {
return Hex.decode(data.substring(2));
}
protected int jsToInt(String data) {
return Integer.parseInt(data.substring(2), 16);
}
protected long jsToLong(String data) {
return Long.parseLong(data.substring(2), 16);
}
protected BigInteger jsToBigInteger(String data) {
return new BigInteger(data.substring(2), 16);
}
protected Transaction jsToTransaction(JSONObject obj) throws Exception {
if ((!obj.containsKey("to") || ((String)obj.get("to")).equals("")) && (!obj.containsKey("data") || ((String)obj.get("data")).equals(""))) {
throw new Exception("");
}
byte[] from = ((Account) ethereum.getWallet().getAccountCollection().toArray()[1]).getEcKey().getAddress();
if (obj.containsKey("from") && !((String)obj.get("from")).equals("")) {
from = jsToAddress((String) obj.get("from"));
}
Account acc = null;
for (Account ac : ethereum.getWallet().getAccountCollection()) {
if (Arrays.equals(ac.getAddress(), from)) {
acc = ac;
break;
}
}
if (acc == null) {
throw new Exception("");
}
byte[] senderPrivKey = acc.getEcKey().getPrivKeyBytes();
// default - from ethereumj-studio
byte[] to = null;
if (obj.containsKey("to") && !((String)obj.get("to")).equals("")) {
to = jsToAddress((String) obj.get("to"));
}
// default - from ethereumj-studio
BigInteger gasPrice = SZABO.value().multiply(BigInteger.TEN);
if (obj.containsKey("gasPrice") && !((String)obj.get("gasPrice")).equals("")) {
gasPrice = jsToBigInteger((String) obj.get("gasPrice"));
}
// default - from cpp-ethereum
BigInteger gas = acc.getBalance().divide(gasPrice);
BigInteger gasBBRemaining = new BigInteger(Long.toString((ethereum.getBlockchain().getBestBlock().getGasLimit() - ethereum.getBlockchain().getBestBlock().getGasUsed()) / 5));
if (gasBBRemaining.compareTo(gas) < 0)
gas = gasBBRemaining;
if (obj.containsKey("gas") && !((String)obj.get("gas")).equals("")) {
gas = jsToBigInteger((String) obj.get("gas"));
}
// default - from ethereumj-studio
BigInteger value = new BigInteger("1000");
if (obj.containsKey("value") && !((String)obj.get("value")).equals("")) {
value = jsToBigInteger((String) obj.get("value"));
}
// default - from ethereumj-studio
BigInteger nonce = ethereum.getRepository().getNonce(acc.getAddress());
if (obj.containsKey("nonce") && !((String)obj.get("nonce")).equals("")) {
nonce = jsToBigInteger((String) obj.get("nonce"));
}
// default - from ethereumj-studio
byte[] data = new byte[]{};
if (obj.containsKey("data") && !((String)obj.get("data")).equals("")) {
data = jsToAddress((String) obj.get("data"));
}
Transaction tx = ethereum.createTransaction(nonce, gasPrice, gas, to, value, data);
tx.sign(senderPrivKey);
return tx;
}
protected JSONObject blockToJS (Block block, Boolean detailed) {
JSONObject res = new JSONObject();
if (block == null)
return null;
res.put("number", "0x" + Long.toHexString(block.getNumber()));
res.put("hash", "0x" + Hex.toHexString(block.getHash()));
res.put("parentHash", "0x" + Hex.toHexString(block.getParentHash()));
res.put("nonce", "0x" + Hex.toHexString(block.getNonce()));
res.put("sha3Uncles", "0x" + Hex.toHexString(block.getUnclesHash()));
res.put("logsBloom", "0x" + Hex.toHexString(block.getLogBloom()));
res.put("transactionsRoot", "0x" + Hex.toHexString(block.getHeader().getTxTrieRoot()));
res.put("stateRoot", "0x" + Hex.toHexString(block.getStateRoot()));
res.put("miner", "0x" + Hex.toHexString(block.getCoinbase()));
res.put("difficulty", "0x" + block.getDifficultyBI().toString(16));
res.put("totalDifficulty", "0x" + block.getCumulativeDifficulty().toString(16));
res.put("extraData", "0x" + Hex.toHexString(block.getExtraData()));
// No way to get size of block in bytes, so I try calculate it using formula from getEncoded
byte[] header = block.getHeader().getEncoded();
byte[] transactions = RLP.encodeList();
byte[][] unclesEncoded = new byte[block.getUncleList().size()][];
int i = 0;
for (BlockHeader uncle : block.getUncleList()) {
unclesEncoded[i] = uncle.getEncoded();
++i;
}
byte[] uncles = RLP.encodeList(unclesEncoded);
byte[] rlpEncoded = RLP.encodeList(header, transactions, uncles);
res.put("size", "0x" + Integer.toHexString(rlpEncoded.length));
res.put("gasLimit", "0x" + Long.toHexString(block.getGasLimit()));
res.put("gasUsed", "0x" + Long.toHexString(block.getGasUsed()));
res.put("timestamp", "0x" + Long.toHexString(block.getTimestamp()));
JSONArray transactionsJA = new JSONArray();
i = 0;
for (Transaction transaction : block.getTransactionsList()) {
if (detailed) {
JSONObject tx = transactionToJS(transaction);
tx.put("transactionIndex", "0x" + Integer.toHexString(i));
tx.put("blockHash", "0x" + Hex.toHexString(block.getHash()));
tx.put("blockNumber", "0x" + Long.toHexString(block.getNumber()));
transactionsJA.add(tx);
} else {
transactionsJA.add("0x" + Hex.toHexString(transaction.getHash()));
}
++i;
}
res.put("transactions", transactionsJA);
//TODO: ask if I correctly get uncle's hash (takes form -core right now)
JSONArray unclesJA = new JSONArray();
for (BlockHeader uncle : block.getUncleList()) {
unclesJA.add("0x" + Hex.toHexString(HashUtil.sha3(uncle.getEncoded())));
}
res.put("uncles", unclesJA);
return res;
}
protected JSONObject transactionToJS (Transaction transaction) {
JSONObject res = new JSONObject();
res.put("hash", "0x" + Hex.toHexString(transaction.getHash()));
res.put("nonce", "0x" + Hex.toHexString(transaction.getNonce()));
res.put("from", "0x" + Hex.toHexString(transaction.getSender()));
res.put("to", "0x" + Hex.toHexString(transaction.getReceiveAddress()));
res.put("value", "0x" + Hex.toHexString(transaction.getValue()));
res.put("gasPrice", "0x" + Hex.toHexString(transaction.getGasPrice()));
res.put("gas", "0x" + Hex.toHexString(transaction.getGasLimit()));
res.put("input", "0x" + Hex.toHexString(transaction.getData()));
/*
No way to get this data from inside of transaction.
TODO: Ask roman to include it into transaction class.
res.put("transactionIndex", "0x" + "");
res.put("blockHash", "0x" + "");
res.put("blockNumber", "0x" + "");
*/
return res;
}
}

View File

@ -0,0 +1,30 @@
package org.ethereum.android.jsonrpc.filter;
import net.minidev.json.JSONArray;
import org.ethereum.facade.Ethereum;
public abstract class FilterBase {
protected int id;
protected long lastRequest = System.currentTimeMillis();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public long getLastRequestTime() {
return lastRequest;
}
protected void updateLastRequest() {
lastRequest = System.currentTimeMillis();
}
public abstract void processEvent(Object data);
public abstract JSONArray toJS();
public abstract JSONArray toJS(Ethereum ethereum);
}

View File

@ -0,0 +1,38 @@
package org.ethereum.android.jsonrpc.filter;
import net.minidev.json.JSONArray;
import org.ethereum.core.Block;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.util.ArrayList;
public class FilterBlock extends FilterBase {
private ArrayList<String> blocks = new ArrayList<String>();
public void processEvent(Object data) {
if (data instanceof Block) {
synchronized (blocks) {
blocks.add("0x" + Hex.toHexString(((Block) data).getHash()));
}
}
}
public JSONArray toJS() {
updateLastRequest();
JSONArray res = new JSONArray();
synchronized (blocks) {
for(String item : blocks) {
res.add(item);
}
blocks.clear();
}
return res;
}
public JSONArray toJS(Ethereum ethereum) {
return null;
}
}

View File

@ -0,0 +1,199 @@
package org.ethereum.android.jsonrpc.filter;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import org.ethereum.core.Block;
import org.ethereum.core.Transaction;
import org.ethereum.core.TransactionReceipt;
import org.ethereum.facade.Ethereum;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.LogInfo;
import org.spongycastle.util.encoders.Hex;
import java.util.ArrayList;
import java.util.Arrays;
/*
Right now LogInfo not contains information about Transaction and Transaction not have information about block.
TODO: talk to Roman about create links between LogInfo and Transaction and between Transaction and Block.
*/
public class FilterLog extends FilterBase {
private ArrayList<LogInfo> logs = new ArrayList<LogInfo>();
long blockFrom;
long blockTo;
ArrayList<byte[]> addresses = new ArrayList<>();
ArrayList<byte[]> topics = new ArrayList<>();
public FilterLog (Ethereum ethereum, JSONObject data) {
blockFrom = ethereum.getBlockchain().getBestBlock().getNumber();
if (data.containsKey("fromBlock") && !((String)data.get("fromBlock")).equals("")) {
String fromS = (String)data.get("fromBlock");
if (fromS.equals("latest")) {
} else if (fromS.equals("pending") || fromS.equals("earliest")) {
blockFrom = -1;
} else {
blockFrom = Long.parseLong(fromS.substring(2), 16);
}
}
blockTo = ethereum.getBlockchain().getBestBlock().getNumber();
if (data.containsKey("toBlock") && !((String)data.get("toBlock")).equals("")) {
String fromS = (String)data.get("toBlock");
if (fromS.equals("latest")) {
} else if (fromS.equals("pending") || fromS.equals("earliest")) {
blockTo = -1;
} else {
blockTo = Long.parseLong(fromS.substring(2), 16);
}
}
if (data.containsKey("address")) {
if (data.get("address") instanceof String) {
addresses.add(Hex.decode(((String) data.get("address")).substring(2)));
} else if (data.get("address") instanceof JSONArray){
for (Object item : (JSONArray)data.get("address")) {
if (item instanceof String) {
addresses.add(Hex.decode(((String) item).substring(2)));
}
}
}
}
if (data.containsKey("topics")) {
if (data.get("topics") instanceof String) {
topics.add(Hex.decode(((String) data.get("topics")).substring(2)));
} else if (data.get("topics") instanceof JSONArray){
for (Object item : (JSONArray)data.get("topics")) {
if (item instanceof String) {
topics.add(Hex.decode(((String) item).substring(2)));
}
}
}
}
}
/*
TODO: Right now Bloom from -core can be used only to check total mach of 2 same class objects. Will be nice to have possibility to check contains.
*/
public void processEvent(Object data) {
if (data instanceof LogInfo) {
synchronized (logs) {
LogInfo li = (LogInfo)data;
//TODO: check if li inside blockFrom - blockTo
if (checkLogInfo(li))
logs.add(li);
}
}
}
public JSONArray toJS() {
updateLastRequest();
JSONArray res = new JSONArray();
synchronized (logs) {
for(LogInfo item : logs) {
res.add(logInfoToJS(item));
}
logs.clear();
}
return res;
}
public JSONArray toJS(Ethereum ethereum) {
JSONArray res = new JSONArray();
// Process mined blocks
if (blockFrom >= 0) {
long i = blockFrom;
while (true) {
Block block = ethereum.getBlockchain().getBlockByNumber(i);
if (block == null)
break;
for (Transaction tx : block.getTransactionsList()) {
TransactionReceipt txr = ethereum.getBlockchain().getTransactionReceiptByHash(tx.getHash());
if (txr != null) {
for (LogInfo li : txr.getLogInfoList()) {
if (checkLogInfo(li))
res.add(logInfoToJS(li));
}
}
}
i++;
}
}
/*
Process pending transactions. But not sure if BlockChain can return TransactionReceipt for pending transaction.
*/
if (blockFrom < 0 || blockTo < 0) {
for (Transaction tx : ethereum.getPendingTransactions()) {
TransactionReceipt txr = ethereum.getBlockchain().getTransactionReceiptByHash(tx.getHash());
if (txr != null) {
for (LogInfo li : txr.getLogInfoList()) {
if (checkLogInfo(li))
res.add(logInfoToJS(li));
}
}
}
}
return res;
}
private boolean checkLogInfo(LogInfo li) {
boolean found = false;
for (byte[] address : addresses) {
if (Arrays.equals(address, li.getAddress())) {
found = true;
break;
}
}
if (!found)
return false;
found = false;
for (byte[] topic : topics) {
for (DataWord litopic : li.getTopics()) {
if (Arrays.equals(topic, litopic.getData())) {
found = true;
break;
}
}
if (found)
break;
}
if (!found)
return false;
return true;
}
private JSONObject logInfoToJS(LogInfo li) {
JSONObject res = new JSONObject();
/*
TODO: check here if log's transaction / block mined or pending.
*/
res.put("type", "pending");
res.put("logIndex", null);
res.put("transactionIndex", null);
res.put("transactionHash", null);
res.put("blockHash", null);
res.put("blockNumber", null);
res.put("address", Hex.toHexString(li.getAddress()));
res.put("data", Hex.toHexString(li.getData()));
JSONArray topics = new JSONArray();
for (DataWord topic : li.getTopics()) {
topics.add(Hex.toHexString(topic.getData()));
}
res.put("topics", topics);
return res;
}
}

View File

@ -0,0 +1,98 @@
package org.ethereum.android.jsonrpc.filter;
import net.minidev.json.JSONArray;
import org.ethereum.facade.Ethereum;
import java.util.Hashtable;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
/*
This class must receive notification from -core about new log, Block, Transaction. Right now I not see the way todo that.
TODO: ask advice from Roman about how to send notification to this class.
*/
public class FilterManager {
protected static FilterManager instance = null;
public static FilterManager getInstance() {
if (instance == null)
instance = new FilterManager();
return instance;
}
private Timer timer = null;
private long filterAutoUninstall = TimeUnit.MINUTES.toMillis(5);
protected Hashtable<Integer, FilterBase> filters;
protected int last_id = 0;
private FilterManager() {
filters = new Hashtable<Integer, FilterBase>();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
long now = System.currentTimeMillis();
synchronized (filters) {
for (Map.Entry<Integer, FilterBase> item : filters.entrySet()) {
if (now - item.getValue().getLastRequestTime() >= filterAutoUninstall) {
filters.remove(item.getKey());
}
}
}
}
}, TimeUnit.MINUTES.toMillis(1));
}
public void processEvent(Object data) {
synchronized (filters) {
for (Map.Entry<Integer, FilterBase> item : filters.entrySet()) {
item.getValue().processEvent(data);
}
}
}
public int addFilter(FilterBase filter) {
filter.setId(++last_id);
filters.put(filter.getId(), filter);
return filter.getId();
}
public FilterBase getFilter(int id) {
if (filters.containsKey(id)) {
return filters.get(id);
}
return null;
}
public boolean uninstallFilter(int id) {
synchronized (filters) {
if (!filters.containsKey(id))
return false;
filters.remove(id);
}
return true;
}
public JSONArray toJS(int id) {
synchronized (filters) {
if (!filters.containsKey(id))
return null;
return filters.get(id).toJS();
}
}
public JSONArray toJS(int id, Ethereum ethereum) {
synchronized (filters) {
if (!filters.containsKey(id))
return null;
return filters.get(id).toJS(ethereum);
}
}
}

View File

@ -0,0 +1,38 @@
package org.ethereum.android.jsonrpc.filter;
import net.minidev.json.JSONArray;
import org.ethereum.core.Transaction;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.util.ArrayList;
public class FilterTransaction extends FilterBase {
private ArrayList<String> transactions = new ArrayList<String>();
public void processEvent(Object data) {
if (data instanceof Transaction) {
synchronized (transactions) {
transactions.add("0x" + Hex.toHexString(((Transaction) data).getHash()));
}
}
}
public JSONArray toJS() {
updateLastRequest();
JSONArray res = new JSONArray();
synchronized (transactions) {
for(String item : transactions) {
res.add(item);
}
transactions.clear();
}
return res;
}
public JSONArray toJS(Ethereum ethereum) {
return null;
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
Deprecated
*/
public class db_getHex extends JsonRpcServerMethod {
public db_getHex (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
Deprecated
*/
public class db_getString extends JsonRpcServerMethod {
public db_getString (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
Deprecated
*/
public class db_putHex extends JsonRpcServerMethod {
public db_putHex (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
Deprecated
*/
public class db_putString extends JsonRpcServerMethod {
public db_putString (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}

View File

@ -0,0 +1,29 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.ethereum.core.*;
import org.spongycastle.util.encoders.Hex;
import java.util.ArrayList;
import java.util.Collection;
public class eth_accounts extends JsonRpcServerMethod {
public eth_accounts (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
Collection<Account> accounts = ethereum.getWallet().getAccountCollection();
ArrayList<String> tmp = new ArrayList<String>();
for (Account ac : accounts) {
tmp.add("0x" + Hex.toHexString(ac.getEcKey().getAddress()));
}
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,25 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
No matter how long I wait on synchronization - all time got best block number = 0
TODO: check this after Adrian finish db implementation.
*/
public class eth_blockNumber extends JsonRpcServerMethod {
public eth_blockNumber (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
String tmp = "0x" + Long.toHexString(ethereum.getBlockchain().getBestBlock().getNumber());
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,61 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.Transaction;
import org.ethereum.facade.Ethereum;
import org.ethereum.vm.Program;
import org.ethereum.vm.VM;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
/*
It's magic here, not sure if -core have this possibility at all. I found this in test and studio. But not sure that getHReturn it's what specification mean.
TODO: get advice from Roman
*/
public class eth_call extends JsonRpcServerMethod {
public eth_call (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
JSONObject obj = (JSONObject)params.get(0);
Transaction tx;
try {
tx = jsToTransaction(obj);
} catch (Exception e) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
}
String height = (String)params.get(1);
long blockNumber = getBlockNumber(height);
byte[] root = ethereum.getBlockchain().getBestBlock().getStateRoot();
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(ethereum.getBlockchain().getBlockByNumber(blockNumber).getStateRoot());
}
VM vm = new VM();
Program program = new Program(tx.getData(), null);
vm.play(program);
byte[] result = program.getResult().getHReturn();
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(root);
}
String tmp = "0x" + Hex.toHexString(result);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -2,28 +2,30 @@ package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.ethereum.core.*;
import org.spongycastle.util.encoders.Hex;
public class eth_coinbase implements RequestHandler {
/*
Present big issue - current ethereumj-core not have coinbase "functionality".
On each app start - it create 2 addresses: "cow", coinbase.secret ("monkey") --- WorldManager.java -> init
Also because not present mining functionality - no wat to identify what address will be coinbase (mining success payment place to)
TODO: change this after fix in ethereumj-core
*/
private String name = "";
private Ethereum ethereum;
public class eth_coinbase extends JsonRpcServerMethod {
public eth_coinbase(Ethereum ethereum) {
this.ethereum = ethereum;
name = this.getClass().getSimpleName();
public eth_coinbase (Ethereum ethereum) {
super(ethereum);
}
public String[] handledRequests() {
return new String[]{name};
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
Wallet w = ethereum.getWallet();
String tmp = "0x" + Hex.toHexString(((Account) w.getAccountCollection().toArray()[1]).getEcKey().getAddress());
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals(name)) {
//TODO: place business logic here
return null;
} else {
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
}

View File

@ -0,0 +1,33 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
/*
TODO: -core not have lll compiler
*/
public class eth_compileLLL extends JsonRpcServerMethod {
public eth_compileLLL (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
String code = (String)params.get(0);
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
}

View File

@ -0,0 +1,55 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.facade.Ethereum;
import org.ethereum.serpent.SerpentCompiler;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
Example taken from -studio. Not sure if we must call encodeMachineCodeForVMRun in end
TODO: get advice from Roman about encodeMachineCodeForVMRun
*/
public class eth_compileSerpent extends JsonRpcServerMethod {
public eth_compileSerpent (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
String code = (String)params.get(0);
String asmResult = "";
byte[] machineCode = null;
try {
Pattern pattern = Pattern.compile("(.*?)init:(.*?)code:(.*?)", Pattern.DOTALL);
Matcher matcher = pattern.matcher(code);
if (matcher.find()) {
asmResult = SerpentCompiler.compileFullNotion(code);
machineCode = SerpentCompiler.compileFullNotionAssemblyToMachine(asmResult);
} else {
asmResult = SerpentCompiler.compile(code);
machineCode = SerpentCompiler.compileAssemblyToMachine(asmResult);
// machineCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null);
}
} catch (Throwable th) {
return new JSONRPC2Response(JSONRPC2Error.INTERNAL_ERROR, req.getID());
}
return new JSONRPC2Response("0x" + Hex.toHexString(machineCode), req.getID());
}
}
}

View File

@ -0,0 +1,33 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
/*
TODO: -core not have solidity compiler
*/
public class eth_compileSolidity extends JsonRpcServerMethod {
public eth_compileSolidity (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
String code = (String)params.get(0);
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
}

View File

@ -0,0 +1,61 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.Transaction;
import org.ethereum.facade.Ethereum;
import org.ethereum.vm.Program;
import org.ethereum.vm.VM;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
/*
It's magic here, not sure if -core have this possibility at all. I found this in test and studio. But not sure that getHReturn it's what specification mean.
TODO: get advice from Roman
*/
public class eth_estimateGas extends JsonRpcServerMethod {
public eth_estimateGas (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
JSONObject obj = (JSONObject)params.get(0);
Transaction tx;
try {
tx = jsToTransaction(obj);
} catch (Exception e) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
}
String height = (String)params.get(1);
long blockNumber = getBlockNumber(height);
byte[] root = ethereum.getBlockchain().getBestBlock().getStateRoot();
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(ethereum.getBlockchain().getBlockByNumber(blockNumber).getStateRoot());
}
VM vm = new VM();
Program program = new Program(tx.getData(), null);
vm.play(program);
long result = program.getResult().getGasUsed();
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(root);
}
String tmp = "0x" + Long.toHexString(result);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,22 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import static org.ethereum.core.Denomination.SZABO;
public class eth_gasPrice extends JsonRpcServerMethod {
public eth_gasPrice (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
String tmp = "0x" + Long.toHexString(10 * SZABO.longValue());
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,55 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
/*
TODO: ask roman advice for this method.
*/
public class eth_getBalance extends JsonRpcServerMethod {
public eth_getBalance (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String) params.get(0));
String height = (String)params.get(1);
long blockNumber = getBlockNumber(height);
byte[] root = ethereum.getBlockchain().getBestBlock().getStateRoot();
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(ethereum.getBlockchain().getBlockByNumber(blockNumber).getStateRoot());
}
BigInteger balance = ethereum.getRepository().getBalance(address);
if (blockNumber == -2) {
BigInteger tmpB = ethereum.getWallet().getBalance(address);
balance = tmpB != BigInteger.ZERO ? tmpB : balance;
}
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(root);
}
String tmp = "0x" + balance.toString(16);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,39 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
/*
By specification this method can receive hash of pending block but from -core it's not possible.
TODO: get advice from Roman about pending block
*/
public class eth_getBlockByHash extends JsonRpcServerMethod {
public eth_getBlockByHash (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String) params.get(0));
Boolean detailed = (Boolean)params.get(1);
Block block = ethereum.getBlockchain().getBlockByHash(address);
JSONRPC2Response res = new JSONRPC2Response(blockToJS(block, detailed), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,47 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
/*
By specification this method can receive number of pending block but from -core it's not possible.
TODO: get advice from Roman about pending block
*/
public class eth_getBlockByNumber extends JsonRpcServerMethod {
public eth_getBlockByNumber (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
String height = (String)params.get(0);
long blockNumber = getBlockNumber(height);
Boolean detailed = (Boolean)params.get(1);
if (blockNumber == -1) {
blockNumber = ethereum.getBlockchain().getBestBlock().getNumber();
}
// TODO: here we must load pending block but -core not "group" it.
if (blockNumber == -2) {
}
Block block = ethereum.getBlockchain().getBlockByNumber(blockNumber);
JSONRPC2Response res = new JSONRPC2Response(blockToJS(block, detailed), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,29 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
public class eth_getBlockTransactionCountByHash extends JsonRpcServerMethod {
public eth_getBlockTransactionCountByHash (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] hash = jsToAddress((String)params.get(0));
String tmp = "0x" + Integer.toHexString(ethereum.getBlockchain().getBlockByHash(hash).getTransactionsList().size());
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,40 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import java.util.List;
public class eth_getBlockTransactionCountByNumber extends JsonRpcServerMethod {
public eth_getBlockTransactionCountByNumber (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
String height = (String)params.get(0);
long blockNumber = getBlockNumber(height);
if (blockNumber == -1)
blockNumber = ethereum.getBlockchain().getBestBlock().getNumber();
int count = 0;
if (blockNumber == -2) {
count = ethereum.getBlockchain().getPendingTransactions().size();
} else {
count = ethereum.getBlockchain().getBlockByNumber(blockNumber).getTransactionsList().size();
}
String tmp = "0x" + Integer.toHexString(count);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,48 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
/*
Not sure if pending can have code. Also code by itself related to repository not very clear for me.
TODO: ask Roman advice for this method.
*/
public class eth_getCode extends JsonRpcServerMethod {
public eth_getCode (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String)params.get(0));
String height = (String)params.get(1);
long blockNumber = getBlockNumber(height);
byte[] root = ethereum.getBlockchain().getBestBlock().getStateRoot();
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(ethereum.getBlockchain().getBlockByNumber(blockNumber).getStateRoot());
}
String tmp = "0x" + Hex.toHexString(ethereum.getRepository().getCode(address));
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(root);
}
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,27 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import java.util.ArrayList;
/*
As I see right now -core have only serpent compiler
*/
public class eth_getCompilers extends JsonRpcServerMethod {
public eth_getCompilers (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
ArrayList<String> tmp = new ArrayList<String>();
tmp.add("serpent");
//TODO: add lll and solidity when they will be implemented in -core
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,31 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.filter.FilterBase;
import org.ethereum.android.jsonrpc.filter.FilterLog;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
public class eth_getFilterChanges extends JsonRpcServerMethod {
public eth_getFilterChanges (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
int id = jsToInt((String) params.get(0));
JSONRPC2Response res = new JSONRPC2Response(FilterManager.getInstance().toJS(id), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,31 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.filter.FilterBase;
import org.ethereum.android.jsonrpc.filter.FilterLog;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
public class eth_getFilterLogs extends JsonRpcServerMethod {
public eth_getFilterLogs (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
int id = jsToInt((String) params.get(0));
JSONRPC2Response res = new JSONRPC2Response(FilterManager.getInstance().toJS(id, ethereum), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,30 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.filter.FilterLog;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
public class eth_getLogs extends JsonRpcServerMethod {
public eth_getLogs (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
JSONObject obj = (JSONObject)params.get(0);
JSONRPC2Response res = new JSONRPC2Response((new FilterLog(ethereum, obj)).toJS(ethereum), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,49 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServer;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.ethereum.vm.DataWord;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
/*
As I see getStorageValue not check Pending Transactions.
TODO: ask roman advice for this method.
*/
public class eth_getStorageAt extends JsonRpcServerMethod {
public eth_getStorageAt(Ethereum ethereum) { super(ethereum); }
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 3) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String)params.get(0));
long key = jsToLong((String) params.get(1));
String height = (String)params.get(2);
long blockNumber = getBlockNumber(height);
byte[] root = ethereum.getBlockchain().getBestBlock().getStateRoot();
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(ethereum.getBlockchain().getBlockByNumber(blockNumber).getStateRoot());
}
String tmp = "0x" + Hex.toHexString(ethereum.getRepository().getStorageValue(address, new DataWord(key)).getData());
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(root);
}
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,49 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
public class eth_getTransactionByBlockHashAndIndex extends JsonRpcServerMethod {
public eth_getTransactionByBlockHashAndIndex (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String) params.get(0));
int index = jsToInt((String) params.get(1));
Block block = ethereum.getBlockchain().getBlockByHash(address);
if (block == null)
return new JSONRPC2Response(null, req.getID());
if (block.getTransactionsList().size() <= index)
return new JSONRPC2Response(null, req.getID());
JSONObject tx = transactionToJS(block.getTransactionsList().get(index));
tx.put("transactionIndex", "0x" + Integer.toHexString(index));
tx.put("blockHash", "0x" + Hex.toHexString(block.getHash()));
tx.put("blockNumber", "0x" + Long.toHexString(block.getNumber()));
JSONRPC2Response res = new JSONRPC2Response(tx, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,57 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.List;
public class eth_getTransactionByBlockNumberAndIndex extends JsonRpcServerMethod {
public eth_getTransactionByBlockNumberAndIndex (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
String height = (String)params.get(0);
long blockNumber = getBlockNumber(height);
int index = jsToInt((String) params.get(1));
if (blockNumber == -1) {
blockNumber = ethereum.getBlockchain().getBestBlock().getNumber();
}
// TODO: here we must load pending block but -core not "group" it.
if (blockNumber == -2) {
}
Block block = ethereum.getBlockchain().getBlockByNumber(blockNumber);
if (block == null)
return new JSONRPC2Response(null, req.getID());
if (block.getTransactionsList().size() <= index)
return new JSONRPC2Response(null, req.getID());
JSONObject tx = transactionToJS(block.getTransactionsList().get(index));
tx.put("transactionIndex", "0x" + Integer.toHexString(index));
tx.put("blockHash", "0x" + Hex.toHexString(block.getHash()));
tx.put("blockNumber", "0x" + Long.toHexString(block.getNumber()));
JSONRPC2Response res = new JSONRPC2Response(tx, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,37 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.TransactionReceipt;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
TODO: get advice from Roman about get block from transaction.
*/
public class eth_getTransactionByHash extends JsonRpcServerMethod {
public eth_getTransactionByHash (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String) params.get(0));
TransactionReceipt transaction = ethereum.getBlockchain().getTransactionReceiptByHash(address);
if (transaction == null)
return new JSONRPC2Response(null, req.getID());
JSONRPC2Response res = new JSONRPC2Response(transactionToJS(transaction.getTransaction()), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,66 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServer;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.AccountState;
import org.ethereum.core.Transaction;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
/*
Can't find correct way to get contracts' state for specified block number. Right now method return correct value only for "latest" parameter
TODO: ask roman advice for this method.
*/
public class eth_getTransactionCount extends JsonRpcServerMethod {
public eth_getTransactionCount(Ethereum ethereum) { super(ethereum); }
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String) params.get(0));
String height = (String)params.get(1);
long blockNumber = getBlockNumber(height);
byte[] root = ethereum.getBlockchain().getBestBlock().getStateRoot();
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(ethereum.getBlockchain().getBlockByNumber(blockNumber).getStateRoot());
}
BigInteger nonce = BigInteger.ZERO;
AccountState accountState = ethereum.getRepository().getAccountState(address);
if (accountState != null)
nonce = accountState.getNonce();
if (blockNumber == -1) {
synchronized (ethereum.getBlockchain().getPendingTransactions()) {
for (Transaction tx : ethereum.getBlockchain().getPendingTransactions()) {
if (Arrays.equals(address, tx.getSender())) {
nonce.add(BigInteger.ONE);
}
}
}
}
if (blockNumber >= 0) {
ethereum.getRepository().syncToRoot(root);
}
String tmp = "0x" + nonce.toString(16);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,41 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.Block;
import org.ethereum.crypto.HashUtil;
import org.ethereum.facade.Ethereum;
import java.util.List;
public class eth_getUncleByBlockHashAndIndex extends JsonRpcServerMethod {
public eth_getUncleByBlockHashAndIndex (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String) params.get(0));
int index = jsToInt((String) params.get(1));
Block block = ethereum.getBlockchain().getBlockByHash(address);
if (block == null)
return new JSONRPC2Response(null, req.getID());
if (block.getUncleList().size() <= index)
return new JSONRPC2Response(null, req.getID());
Block uncle = ethereum.getBlockchain().getBlockByHash(HashUtil.sha3(block.getUncleList().get(index).getEncoded()));
JSONRPC2Response res = new JSONRPC2Response(blockToJS(uncle, false), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,49 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.Block;
import org.ethereum.crypto.HashUtil;
import org.ethereum.facade.Ethereum;
import java.util.List;
public class eth_getUncleByBlockNumberAndIndex extends JsonRpcServerMethod {
public eth_getUncleByBlockNumberAndIndex (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
String height = (String)params.get(0);
long blockNumber = getBlockNumber(height);
int index = jsToInt((String) params.get(1));
if (blockNumber == -1) {
blockNumber = ethereum.getBlockchain().getBestBlock().getNumber();
}
// TODO: here we must load pending block but -core not "group" it.
if (blockNumber == -2) {
}
Block block = ethereum.getBlockchain().getBlockByNumber(blockNumber);
if (block == null)
return new JSONRPC2Response(null, req.getID());
if (block.getUncleList().size() <= index)
return new JSONRPC2Response(null, req.getID());
Block uncle = ethereum.getBlockchain().getBlockByHash(HashUtil.sha3(block.getUncleList().get(index).getEncoded()));
JSONRPC2Response res = new JSONRPC2Response(blockToJS(uncle, false), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,29 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
public class eth_getUncleCountByBlockHash extends JsonRpcServerMethod {
public eth_getUncleCountByBlockHash (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] hash = jsToAddress((String)params.get(0));
String tmp = "0x" + Integer.toHexString(ethereum.getBlockchain().getBlockByHash(hash).getUncleList().size());
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,44 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
Not sure if pending transactions can have uncle.
TODO: ask Roman about this
*/
public class eth_getUncleCountByBlockNumber extends JsonRpcServerMethod {
public eth_getUncleCountByBlockNumber (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
String height = (String)params.get(0);
long blockNumber = getBlockNumber(height);
if (blockNumber == -1)
blockNumber = ethereum.getBlockchain().getBestBlock().getNumber();
int count = 0;
if (blockNumber == -2) {
count = 0;
} else {
count = ethereum.getBlockchain().getBlockByNumber(blockNumber).getUncleList().size();
}
String tmp = "0x" + Integer.toHexString(count);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
TODO: right now -core not auto start mining so no way to get information about state
*/
public class eth_getWork extends JsonRpcServerMethod {
public eth_getWork (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}

View File

@ -0,0 +1,24 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
TODO: right now -core not have "finished" mining architecture so not have hashrate
*/
public class eth_hashrate extends JsonRpcServerMethod {
public eth_hashrate (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
String tmp = "0x" + Integer.toHexString(0);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,24 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
TODO: right now -core not auto start mining and also not have marker to identify if it's happening
*/
public class eth_mining extends JsonRpcServerMethod {
public eth_mining (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
Boolean tmp = false;
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,24 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.filter.FilterBlock;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.facade.Ethereum;
public class eth_newBlockFilter extends JsonRpcServerMethod {
public eth_newBlockFilter (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
int id = FilterManager.getInstance().addFilter(new FilterBlock());
String tmp = "0x" + Integer.toHexString(id);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,32 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.filter.FilterLog;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
public class eth_newFilter extends JsonRpcServerMethod {
public eth_newFilter (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
JSONObject obj = (JSONObject)params.get(0);
int id = FilterManager.getInstance().addFilter(new FilterLog(ethereum, obj));
String tmp = "0x" + Integer.toHexString(id);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,25 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.filter.FilterBlock;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.android.jsonrpc.filter.FilterTransaction;
import org.ethereum.facade.Ethereum;
public class eth_newPendingTransactionFilter extends JsonRpcServerMethod {
public eth_newPendingTransactionFilter (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
int id = FilterManager.getInstance().addFilter(new FilterTransaction());
String tmp = "0x" + Integer.toHexString(id);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,22 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.ethereum.net.eth.EthHandler;
public class eth_protocolVersion extends JsonRpcServerMethod {
public eth_protocolVersion (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
String tmp = Byte.toString(EthHandler.VERSION);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,54 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.Account;
import org.ethereum.core.Transaction;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.ethereum.core.Denomination.SZABO;
import static org.ethereum.config.SystemProperties.CONFIG;
/*
Not sure if we must call submitTransaction from here but logically to do it. Also not clear how created transaction added to pending and to "from" account pending (in test - it didn't)
TODO: get advice from Roman. By spec if created transaction (empty data param) - result must be 20 bytes hash, but I got 32 bytes for both contract and transaction create.
*/
public class eth_sendTransaction extends JsonRpcServerMethod {
public eth_sendTransaction (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
JSONObject obj = (JSONObject)params.get(0);
Transaction tx;
try {
tx = jsToTransaction(obj);
} catch (Exception e) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
}
try {
ethereum.submitTransaction(tx).get(CONFIG.transactionApproveTimeout(), TimeUnit.SECONDS);
} catch (Exception e) {
return new JSONRPC2Response(JSONRPC2Error.INTERNAL_ERROR, req.getID());
}
String tmp = "0x" + Hex.toHexString(tx.getHash());
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,53 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.core.Account;
import org.ethereum.crypto.ECKey;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.util.Arrays;
import java.util.List;
import static org.ethereum.util.ByteUtil.bigIntegerToBytes;
public class eth_sign extends JsonRpcServerMethod {
public eth_sign (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 2) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] address = jsToAddress((String) params.get(0));
byte[] data = jsToAddress((String) params.get(1));
String out = null;
for (Account ac : ethereum.getWallet().getAccountCollection()) {
if (Arrays.equals(ac.getAddress(), address)) {
ECKey.ECDSASignature sig = ac.getEcKey().doSign(data);
byte[] sigData = new byte[65];
sigData[0] = sig.v;
System.arraycopy(bigIntegerToBytes(sig.r, 32), 0, sigData, 1, 32);
System.arraycopy(bigIntegerToBytes(sig.s, 32), 0, sigData, 33, 32);
out = Hex.toHexString(sigData);
break;
}
}
if (out == null) {
return new JSONRPC2Response(JSONRPC2Error.INTERNAL_ERROR, req.getID());
}
String tmp = "0x" + out;
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,35 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
TODO: right now -core not auto start mining so no way to get information about state
*/
public class eth_submitWork extends JsonRpcServerMethod {
public eth_submitWork (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 3) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] nonce = jsToAddress((String) params.get(0));
byte[] powHash = jsToAddress((String) params.get(1));
byte[] mixDigest = jsToAddress((String) params.get(2));
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,31 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.filter.FilterBase;
import org.ethereum.android.jsonrpc.filter.FilterLog;
import org.ethereum.android.jsonrpc.filter.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
public class eth_uninstallFilter extends JsonRpcServerMethod {
public eth_uninstallFilter (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
int id = jsToInt((String) params.get(0));
JSONRPC2Response res = new JSONRPC2Response(FilterManager.getInstance().uninstallFilter(id), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,24 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
TODO: right now -core not mark fact of start listening, it do it automatically and only send Listening trace "string" message.
*/
public class net_listening extends JsonRpcServerMethod {
public net_listening (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
Boolean tmp = true;
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,31 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.ethereum.net.peerdiscovery.PeerInfo;
import java.util.Set;
public class net_peerCount extends JsonRpcServerMethod {
public net_peerCount (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
int pc = 0;
final Set<PeerInfo> peers = ethereum.getPeers();
synchronized (peers) {
for (PeerInfo peer : peers) {
if (peer.isOnline())
pc++;
}
}
String tmp = "0x" + Integer.toHexString(pc);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
TODO: request go version how this must be identified. Cpp version just return "".
*/
public class net_version extends JsonRpcServerMethod {
public net_version (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
String tmp = "";
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,32 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
TODO: not present clear specification for this method, also cpp and go version not provide it.
*/
public class shh_addToGroup extends JsonRpcServerMethod {
public shh_addToGroup(Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] identity = jsToAddress((String)params.get(0));
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,32 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.whisper.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
TODO: done it when shh will be ready in -core
*/
public class shh_getFilterChanges extends JsonRpcServerMethod {
public shh_getFilterChanges(Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
int id = jsToInt((String)params.get(0));
JSONRPC2Response res = new JSONRPC2Response(FilterManager.getInstance().toJS(id), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,32 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.whisper.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
TODO: done it when shh will be ready in -core
*/
public class shh_getMessages extends JsonRpcServerMethod {
public shh_getMessages(Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
int id = jsToInt((String)params.get(0));
JSONRPC2Response res = new JSONRPC2Response(FilterManager.getInstance().toJSAll(id), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,32 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
TODO: done it when shh will be ready in -core
*/
public class shh_hasIdentity extends JsonRpcServerMethod {
public shh_hasIdentity(Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] identity = jsToAddress((String)params.get(0));
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,38 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.whisper.Filter;
import org.ethereum.android.jsonrpc.whisper.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
TODO: done it when shh will be ready in -core
*/
public class shh_newFilter extends JsonRpcServerMethod {
public shh_newFilter(Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
JSONObject obj = (JSONObject)params.get(0);
int id = FilterManager.getInstance().addFilter(new Filter(obj));
String tmp = "0x" + Integer.toHexString(id);
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
TODO: not present clear specification for this method, also cpp and go version not provide it.
*/
public class shh_newGroup extends JsonRpcServerMethod {
public shh_newGroup(Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
/*
TODO: done it when shh will be ready in -core
*/
public class shh_newIdentity extends JsonRpcServerMethod {
public shh_newIdentity(Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}

View File

@ -0,0 +1,60 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.util.ArrayList;
import java.util.List;
/*
TODO: done it when shh will be ready in -core
*/
public class shh_post extends JsonRpcServerMethod {
public shh_post (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
JSONObject obj = (JSONObject)params.get(0);
byte[] from = null;
if (obj.containsKey("from"))
from = jsToAddress((String)obj.get("from"));
byte[] to = null;
if (obj.containsKey("to"))
to = jsToAddress((String)obj.get("to"));
ArrayList<byte[]> topics = new ArrayList<>();
for (Object item : (JSONArray)obj.get("topics")) {
if (item instanceof String) {
topics.add(jsToAddress((String)item));
}
}
byte[] payload = jsToAddress((String)obj.get("payload"));
int priority = jsToInt((String) obj.get("priority"));
int ttl = jsToInt((String)obj.get("ttl"));
//TODO:
JSONRPC2Response res = new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,32 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.android.jsonrpc.whisper.FilterManager;
import org.ethereum.facade.Ethereum;
import java.util.List;
/*
TODO: done it when shh will be ready in -core
*/
public class shh_uninstallFilter extends JsonRpcServerMethod {
public shh_uninstallFilter(Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
int id = jsToInt((String)params.get(0));
JSONRPC2Response res = new JSONRPC2Response(FilterManager.getInstance().uninstallFilter(id), req.getID());
return res;
}
}
}

View File

@ -0,0 +1,22 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.facade.Ethereum;
import org.ethereum.net.shh.ShhHandler;
public class shh_version extends JsonRpcServerMethod {
public shh_version (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
String tmp = "" + ShhHandler.VERSION;
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.config.SystemProperties;
import org.ethereum.facade.Ethereum;
import org.ethereum.util.Utils;
public class web3_clientVersion extends JsonRpcServerMethod {
public web3_clientVersion (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
String tmp = "ethereumj/v" + SystemProperties.CONFIG.projectVersion() + "/android/java" + Utils.JAVA_VERSION;
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}

View File

@ -0,0 +1,32 @@
package org.ethereum.android.jsonrpc.method;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.*;
import org.ethereum.android.jsonrpc.JsonRpcServerMethod;
import org.ethereum.crypto.SHA3Helper;
import org.ethereum.facade.Ethereum;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
public class web3_sha3 extends JsonRpcServerMethod {
public web3_sha3 (Ethereum ethereum) {
super(ethereum);
}
protected JSONRPC2Response worker(JSONRPC2Request req, MessageContext ctx) {
List<Object> params = req.getPositionalParams();
if (params.size() != 1) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
} else {
byte[] data = jsToAddress((String)params.get(0));
String tmp = "0x" + Hex.toHexString(SHA3Helper.sha3(data));
JSONRPC2Response res = new JSONRPC2Response(tmp, req.getID());
return res;
}
}
}

View File

@ -0,0 +1,86 @@
package org.ethereum.android.jsonrpc.whisper;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import org.ethereum.facade.Ethereum;
import org.ethereum.net.shh.ShhMessage;
import org.spongycastle.util.encoders.Hex;
import java.util.ArrayList;
/*
TODO: replace ShhMessage with real class when Roman finish Shh.
*/
public class Filter {
protected int id;
protected ArrayList<ShhMessage> messages;
byte[] to = null;
boolean isWildcard = false;
ArrayList<ArrayList<byte[]>> or;
ArrayList<byte[]> and;
int sendID = 0;
public Filter (JSONObject data) {
messages = new ArrayList<ShhMessage>();
if (data.containsKey("to")) {
to = Hex.decode(((String)data.get("to")).substring(2));
}
JSONArray topics = (JSONArray)data.get("topics");
for (Object item : topics) {
if (item == null) {
isWildcard = true;
}
else if (item instanceof JSONArray) {
ArrayList<byte[]> tmp = new ArrayList<byte[]>();
for (Object ori : (JSONArray)item) {
if (ori instanceof String) {
tmp.add(Hex.decode(((String)ori).substring(2)));
}
}
or.add(tmp);
} else if (item instanceof String) {
and.add(Hex.decode(((String)item).substring(2)));
}
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void processEvent(Object data) {
//TODO: parse incomming data when we will know what comes.
}
public JSONArray toJS() {
JSONArray res = new JSONArray();
synchronized (messages) {
for (int i = sendID; i < messages.size(); i++) {
res.add(toJS(messages.get(i)));
}
sendID = messages.size();
}
return res;
}
public JSONArray toJSAll() {
JSONArray res = new JSONArray();
synchronized (messages) {
for (int i = 0; i < messages.size(); i++) {
res.add(toJS(messages.get(i)));
}
sendID = messages.size();
}
return res;
}
private JSONObject toJS (ShhMessage data) {
JSONObject res = new JSONObject();
return res;
}
}

View File

@ -0,0 +1,80 @@
package org.ethereum.android.jsonrpc.whisper;
import net.minidev.json.JSONArray;
import org.ethereum.facade.Ethereum;
import java.util.Hashtable;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
/*
This class must receive notification from -core about new whisper message. Right now I not see the way todo that.
TODO: ask advice from Roman about how to send notification to this class.
*/
public class FilterManager {
protected static FilterManager instance = null;
public static FilterManager getInstance() {
if (instance == null)
instance = new FilterManager();
return instance;
}
protected Hashtable<Integer, Filter> filters;
protected int last_id = 0;
private FilterManager() {
filters = new Hashtable<Integer, Filter>();
}
public void processEvent(Object data) {
synchronized (filters) {
for (Map.Entry<Integer, Filter> item : filters.entrySet()) {
item.getValue().processEvent(data);
}
}
}
public int addFilter(Filter filter) {
filter.setId(++last_id);
filters.put(filter.getId(), filter);
return filter.getId();
}
public Filter getFilter(int id) {
if (filters.containsKey(id)) {
return filters.get(id);
}
return null;
}
public boolean uninstallFilter(int id) {
synchronized (filters) {
if (!filters.containsKey(id))
return false;
filters.remove(id);
}
return true;
}
public JSONArray toJS(int id) {
synchronized (filters) {
if (!filters.containsKey(id))
return null;
return filters.get(id).toJS();
}
}
public JSONArray toJSAll(int id) {
synchronized (filters) {
if (!filters.containsKey(id))
return null;
return filters.get(id).toJSAll();
}
}
}

View File

@ -0,0 +1,84 @@
package org.ethereum.android.manager;
import org.ethereum.core.Block;
import org.ethereum.core.ImportResult;
import org.ethereum.facade.Blockchain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import java.io.FileInputStream;
import java.io.IOException;
import org.ethereum.android.util.Scanner;
import javax.inject.Inject;
import javax.inject.Singleton;
import static org.ethereum.config.SystemProperties.CONFIG;
@Singleton
public class BlockLoader extends org.ethereum.manager.BlockLoader {
private static final Logger logger = LoggerFactory.getLogger("BlockLoader");
Scanner scanner = null;
@Inject
public BlockLoader(Blockchain blockchain) {
super(blockchain);
}
public void loadBlocks(String dumpFile){
try {
long startTime = System.currentTimeMillis();
FileInputStream inputStream = null;
inputStream = new FileInputStream(dumpFile);
scanner = new Scanner(inputStream);
System.out.println("Loading blocks: " + dumpFile);
while (scanner.hasNext()) {
byte[] blockRLPBytes = Hex.decode(scanner.nextLine());
Block block = new Block(blockRLPBytes);
long t1 = System.nanoTime();
if (block.getNumber() > blockchain.getBestBlock().getNumber()){
blockchain.tryToConnect(block);
long t1_ = System.nanoTime();
float elapsed = ((float)(t1_ - t1) / 1_000_000);
if (block.getNumber() % 1000 == 0 || elapsed > 10_000) {
String result = String.format("Imported block #%d took: [%02.2f msec]",
block.getNumber(), elapsed);
System.out.println(result);
}
} else {
if (block.getNumber() % 10000 == 0)
System.out.println("Skipping block #" + block.getNumber());
}
block = null;
blockRLPBytes = null;
}
long duration = System.currentTimeMillis() - startTime;
System.out.println("Finished loading blocks in " + (duration / 1000) + " seconds (" + (duration / 60000) + " minutes)");
//return duration;
} catch (IOException e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
} catch (Exception e) {
logger.error(e.getMessage(), e);
System.out.println(e.getMessage());
}
//return 0;
}
}

View File

@ -0,0 +1,92 @@
package org.ethereum.android.util;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
class Locale {
final static int US=0;
}
public class Scanner {
private BufferedInputStream in;
int c;
int offset;
boolean atBeginningOfLine;
public Scanner(InputStream stream) {
in = new BufferedInputStream(stream);
try {
atBeginningOfLine = true;
c = (char)in.read();
} catch (IOException e) {
c = -1;
}
}
public boolean hasNext() {
if (!atBeginningOfLine)
throw new Error("hasNext only works "+
"after a call to nextLine");
return c != -1;
}
public String next() {
StringBuffer sb = new StringBuffer();
atBeginningOfLine = false;
try {
while (c <= ' ') {
c = in.read();
}
while (c > ' ') {
sb.append((char)c);
c = in.read();
}
} catch (IOException e) {
c = -1;
return "";
}
return sb.toString();
}
public String nextLine() {
StringBuffer sb = new StringBuffer();
atBeginningOfLine = true;
try {
while (c != '\n') {
sb.append((char)c);
c = in.read();
}
c = in.read();
} catch (IOException e) {
c = -1;
return "";
}
return sb.toString();
}
public int nextInt() {
String s = next();
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return 0; //throw new Error("Malformed number " + s);
}
}
public double nextDouble() {
return new Double(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public void useLocale(int l) {}
}

View File

@ -9,13 +9,11 @@ buildscript {
dependencies {
classpath 'me.champeau.gradle:antlr4-gradle-plugin:0.1'
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:3.0.1'
//classpath "gradle.plugin.com.ewerk.gradle.plugins:dagger-plugin:1.0.0"
}
}
plugins {
id 'java'
// id "com.ewerk.gradle.plugins.dagger" version "1.0.0"
id 'application'
id 'jacoco'
id 'com.github.johnrengelman.shadow' version '1.2.1'
@ -32,7 +30,7 @@ repositories {
sourceCompatibility = 1.7
mainClassName = 'org.ethereum.Start'
applicationDefaultJvmArgs = ["-server", "-Xms2g"]
applicationDefaultJvmArgs = ["-server", "-Xss32m"]
ext.generatedSrcDir = file('src/gen/java')
@ -115,7 +113,7 @@ configurations {
}
ext {
slf4jVersion = '1.7.7'
slf4jVersion = '1.7.12'
leveldbVersion = '0.7'
scastleVersion = '1.51.0.0'
log4jVersion = '1.2.17'
@ -129,43 +127,41 @@ dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile('io.netty:netty-all:4.0.28.Final') {
exclude group: 'commons-logging', module: 'commons-logging'
}
compile "com.madgag.spongycastle:core:${scastleVersion}"
// for SHA3 and SECP256K1
compile "com.madgag.spongycastle:prov:${scastleVersion}"
// for SHA3 and SECP256K1
compile('io.netty:netty-all:4.0.28.Final')
compile "com.madgag.spongycastle:core:${scastleVersion}" // for SHA3 and SECP256K1
compile "com.madgag.spongycastle:prov:${scastleVersion}" // for SHA3 and SECP256K1
compile "org.iq80.leveldb:leveldb:${leveldbVersion}"
compile('com.cedarsoftware:java-util:1.8.0') {
exclude group: 'commons-logging', module: 'commons-logging'
} // for deep equals
compile "org.fusesource.leveldbjni:leveldbjni:1.8"
compile 'org.antlr:antlr4-runtime:4.5' // for serpent compilation
compile 'com.yuvalshavit:antlr-denter:1.1'
compile "org.slf4j:slf4j-log4j12:${slf4jVersion}"
compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.13'
compile 'com.google.code.findbugs:jsr305:3.0.0'
compile 'com.fasterxml.jackson.core:jackson-databind:2.2.0'
compile 'org.apache.commons:commons-collections4:4.0'
compile 'commons-io:commons-io:2.4'
compile "com.cedarsoftware:java-util:1.8.0" // for deep equals
compile "org.antlr:antlr4-runtime:4.5" // for serpent compilation
compile "com.yuvalshavit:antlr-denter:1.1"
compile "org.javassist:javassist:3.15.0-GA"
compile "org.slf4j:slf4j-api:${slf4jVersion}"
compile "log4j:log4j:${log4jVersion}"
compile "org.codehaus.jackson:jackson-mapper-asl:1.9.13"
compile "com.google.code.findbugs:jsr305:3.0.0"
compile "com.fasterxml.jackson.core:jackson-databind:2.5.1"
compile "org.apache.commons:commons-collections4:4.0"
compile "commons-codec:commons-codec:1.10"
compile 'org.hsqldb:hsqldb:1.8.0.10' // best performance - do not upgrade!
compile "org.hibernate:hibernate-core:${hibernateVersion}"
compile "org.hibernate:hibernate-entitymanager:${hibernateVersion}"
compile "commons-dbcp:commons-dbcp:1.4"
compile "redis.clients:jedis:2.6.0"
compile('com.googlecode.json-simple:json-simple:1.1.1') {
compile "com.h2database:h2:1.4.187"
compile "org.slf4j:slf4j-log4j12:${slf4jVersion}"
compile "log4j:apache-log4j-extras:${log4jVersion}"
compile("com.googlecode.json-simple:json-simple:1.1.1") {
exclude group: 'junit', module: 'junit'
exclude group: 'xml-apis', module: 'xml-apis'
}
compile 'commons-io:commons-io:2.4'
testCompile "junit:junit:${junitVersion}"
testCompile 'com.google.dagger:dagger:2.1-SNAPSHOT'
testCompile 'com.google.dagger:dagger-compiler:2.0'
}

View File

@ -71,6 +71,7 @@ public class AccountState {
}
public void setNonce(BigInteger nonce) {
rlpEncoded = null;
this.nonce = nonce;
}

View File

@ -56,7 +56,6 @@ public class Block {
public Block(byte[] rawData) {
logger.debug("new from [" + Hex.toHexString(rawData) + "]");
this.rlpEncoded = rawData;
this.parsed = false;
}
public Block(BlockHeader header, List<Transaction> transactionsList, List<BlockHeader> uncleList) {
@ -360,7 +359,7 @@ public class Block {
parseTxs(txTransactions);
String calculatedRoot = Hex.toHexString(txsState.getRootHash());
if (!calculatedRoot.equals(Hex.toHexString(expectedRoot)))
logger.error("Added tx receipts don't match the given txsStateRoot");
logger.error("Transactions trie root validation failed for block #{}", this.header.getNumber());
}
/**

View File

@ -1,6 +1,7 @@
package org.ethereum.core;
import org.ethereum.config.Constants;
import org.ethereum.config.SystemProperties;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.BlockStore;
import org.ethereum.facade.Blockchain;
@ -24,8 +25,8 @@ import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import javax.inject.Inject;
@ -34,9 +35,7 @@ import javax.inject.Singleton;
import static org.ethereum.config.Constants.*;
import static org.ethereum.config.SystemProperties.CONFIG;
import static org.ethereum.core.Denomination.SZABO;
import static org.ethereum.core.ImportResult.EXIST;
import static org.ethereum.core.ImportResult.NO_PARENT;
import static org.ethereum.core.ImportResult.SUCCESS;
import static org.ethereum.core.ImportResult.*;
/**
* The Ethereum blockchain is in many ways similar to the Bitcoin blockchain,
@ -110,6 +109,7 @@ public class BlockchainImpl implements Blockchain {
public BlockchainImpl() {
}
//todo: autowire over constructor
@Inject
public BlockchainImpl(BlockStore blockStore, Repository repository,
@ -172,14 +172,13 @@ public class BlockchainImpl implements Blockchain {
public ImportResult tryToConnect(Block block) {
recordBlock(block);
if (logger.isInfoEnabled())
logger.info("Try connect block hash: {}, number: {}",
Hex.toHexString(block.getHash()).substring(0, 6),
block.getNumber());
if (blockStore.getBlockByHash(block.getHash()) != null) {
if (blockStore.getBestBlock().getNumber() >= block.getNumber() &&
blockStore.getBlockByHash(block.getHash()) != null) {
if (logger.isDebugEnabled())
logger.debug("Block already exist hash: {}, number: {}",
@ -194,6 +193,7 @@ public class BlockchainImpl implements Blockchain {
// to connect to the main chain
if (bestBlock.isParentOf(block)) {
add(block);
recordBlock(block);
return SUCCESS;
} else {
if (1 == 1) // FIXME: WORKARROUND
@ -292,11 +292,15 @@ public class BlockchainImpl implements Blockchain {
//System.out.println(" Receipts listroot is: " + receiptListHash + " logbloomlisthash is " + logBloomListHash);
track.commit();
repository.flush(); // saving to the disc
storeBlock(block, receipts);
if (adminInfo.isConsensus() &&
block.getNumber() % 5_000 == 0) {
repository.flush();
blockStore.flush();
}
// Remove all wallet transactions as they already approved by the net
wallet.removeTransactions(block.getTransactionsList());
@ -304,13 +308,12 @@ public class BlockchainImpl implements Blockchain {
clearPendingTransactions(block.getTransactionsList());
listener.trace(String.format("Block chain size: [ %d ]", this.getSize()));
listener.onBlock(block);
listener.onBlockReciepts(receipts);
listener.onBlock(block, receipts);
if (blockQueue != null &&
blockQueue.size() == 0 &&
!syncDoneCalled &&
channelManager.isAllSync()) {
blockQueue.size() == 0 &&
!syncDoneCalled &&
channelManager.isAllSync()) {
logger.info("Sync done");
syncDoneCalled = true;
@ -489,7 +492,7 @@ public class BlockchainImpl implements Blockchain {
programInvokeFactory, block, listener, totalGasUsed);
executor.init();
executor.execute2();
executor.execute();
executor.go();
executor.finalization();
@ -567,18 +570,20 @@ public class BlockchainImpl implements Blockchain {
/* Debug check to see if the state is still as expected */
String blockStateRootHash = Hex.toHexString(block.getStateRoot());
String worldStateRootHash = Hex.toHexString(repository.getRoot());
if (!blockStateRootHash.equals(worldStateRootHash)) {
stateLogger.error("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
adminInfo.lostConsensus();
if(!SystemProperties.CONFIG.blockChainOnly())
if (!blockStateRootHash.equals(worldStateRootHash)) {
System.out.println("CONFLICT: BLOCK #" + block.getNumber() );
System.exit(1);
// in case of rollback hard move the root
// Block parentBlock = blockStore.getBlockByHash(block.getParentHash());
// repository.syncToRoot(parentBlock.getStateRoot());
// todo: after the rollback happens other block should be requested
}
stateLogger.error("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
adminInfo.lostConsensus();
System.out.println("CONFLICT: BLOCK #" + block.getNumber() );
// System.exit(1);
// in case of rollback hard move the root
// Block parentBlock = blockStore.getBlockByHash(block.getParentHash());
// repository.syncToRoot(parentBlock.getStateRoot());
// todo: after the rollback happens other block should be requested
}
blockStore.saveBlock(block, receipts);
setBestBlock(block);
@ -652,11 +657,10 @@ public class BlockchainImpl implements Blockchain {
if (!CONFIG.recordBlocks()) return;
if (block.getNumber() == 1) {
//FileSystemUtils.deleteRecursively(new File(CONFIG.dumpDir()));
try {
FileUtils.forceDelete(new File(CONFIG.dumpDir()));
FileUtils.forceDelete(new File(CONFIG.dumpDir()));
} catch (IOException e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
}
}

View File

@ -47,6 +47,7 @@ public class TransactionExecutor {
private VM vm;
private Program program;
PrecompiledContracts.PrecompiledContract precompiledContract;
long m_endGas = 0;
long basicTxCost = 0;
@ -138,7 +139,7 @@ public class TransactionExecutor {
readyToExecute = true;
}
public void execute2() {
public void execute() {
if (!readyToExecute) return;
@ -148,6 +149,7 @@ public class TransactionExecutor {
BigInteger txGasCost = toBI(tx.getGasPrice()).multiply(toBI(txGasLimit));
track.addBalance(tx.getSender(), txGasCost.negate());
if (logger.isInfoEnabled())
logger.info("Paying: txGasCost: [{}], gasPrice: [{}], gasLimit: [{}]", txGasCost, toBI(tx.getGasPrice()), txGasLimit);
@ -162,17 +164,43 @@ public class TransactionExecutor {
if (!readyToExecute) return;
byte[] targetAddress = tx.getReceiveAddress();
byte[] code = track.getCode(targetAddress);
if (code.length > 0) {
ProgramInvoke programInvoke =
programInvokeFactory.createProgramInvoke(tx, currentBlock, cacheTrack, blockStore);
this.vm = new VM();
this.program = new Program(code, programInvoke);
precompiledContract =
PrecompiledContracts.getContractForAddress(new DataWord(targetAddress));
if (precompiledContract != null) {
long requiredGas = precompiledContract.getGasForData(tx.getData());
long txGasLimit = toBI(tx.getGasLimit()).longValue();
if (requiredGas > txGasLimit) {
// no refund
// no endowment
return;
} else {
m_endGas = txGasLimit - requiredGas - basicTxCost;
// BigInteger refundCost = toBI(m_endGas * toBI( tx.getGasPrice() ).longValue() );
// track.addBalance(tx.getSender(), refundCost);
// FIXME: save return for vm trace
byte[] out = precompiledContract.execute(tx.getData());
}
} else {
m_endGas = toBI(tx.getGasLimit()).longValue() - basicTxCost;
byte[] code = track.getCode(targetAddress);
if (code.length > 0) {
ProgramInvoke programInvoke =
programInvokeFactory.createProgramInvoke(tx, currentBlock, cacheTrack, blockStore);
this.vm = new VM();
this.program = new Program(code, programInvoke);
} else {
m_endGas = toBI(tx.getGasLimit()).longValue() - basicTxCost;
}
}
BigInteger endowment = toBI(tx.getValue());
@ -224,6 +252,8 @@ public class TransactionExecutor {
m_endGas -= returnDataGasValue.longValue();
initCode = result.getHReturn();
cacheTrack.saveCode(tx.getContractAddress(), initCode);
} else {
result.setHReturn(initCode);
}
}
@ -257,7 +287,7 @@ public class TransactionExecutor {
public void finalization() {
if (!readyToExecute) return;
if (!readyToExecute ) return;
cacheTrack.commit();
@ -294,9 +324,8 @@ public class TransactionExecutor {
track.delete(address.getLast20Bytes());
}
// Keep execution logs todo: that yet
//*cpp* if (m_ext)
// m_logs = m_ext->sub.logs;
if (result != null)
logs = result.getLogInfoList();
if (result.getLogInfoList() != null){

View File

@ -1,5 +1,6 @@
package org.ethereum.crypto;
import org.ethereum.crypto.cryptohash.Keccak256;
import org.ethereum.util.RLP;
import org.ethereum.util.Utils;
import org.spongycastle.crypto.Digest;
@ -35,7 +36,9 @@ public class HashUtil {
}
public static byte[] sha3(byte[] input) {
return SHA3Helper.sha3(input);
Keccak256 digest = new Keccak256();
digest.update(input);
return digest.digest();
}
public static byte[] sha3(byte[] input, int start, int length) {

View File

@ -0,0 +1,165 @@
// $Id: Digest.java 232 2010-06-17 14:19:24Z tp $
package org.ethereum.crypto.cryptohash;
/**
* <p>This interface documents the API for a hash function. This
* interface somewhat mimics the standard {@code
* java.security.MessageDigest} class. We do not extend that class in
* order to provide compatibility with reduced Java implementations such
* as J2ME. Implementing a {@code java.security.Provider} compatible
* with Sun's JCA ought to be easy.</p>
*
* <p>A {@code Digest} object maintains a running state for a hash
* function computation. Data is inserted with {@code update()} calls;
* the result is obtained from a {@code digest()} method (where some
* final data can be inserted as well). When a digest output has been
* produced, the objet is automatically resetted, and can be used
* immediately for another digest operation. The state of a computation
* can be cloned with the {@link #copy} method; this can be used to get
* a partial hash result without interrupting the complete
* computation.</p>
*
* <p>{@code Digest} objects are stateful and hence not thread-safe;
* however, distinct {@code Digest} objects can be accessed concurrently
* without any problem.</p>
*
* <pre>
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* ===========================(LICENSE END)=============================
* </pre>
*
* @version $Revision: 232 $
* @author Thomas Pornin &lt;thomas.pornin@cryptolog.com&gt;
*/
public interface Digest {
/**
* Insert one more input data byte.
*
* @param in the input byte
*/
public void update(byte in);
/**
* Insert some more bytes.
*
* @param inbuf the data bytes
*/
public void update(byte[] inbuf);
/**
* Insert some more bytes.
*
* @param inbuf the data buffer
* @param off the data offset in {@code inbuf}
* @param len the data length (in bytes)
*/
public void update(byte[] inbuf, int off, int len);
/**
* Finalize the current hash computation and return the hash value
* in a newly-allocated array. The object is resetted.
*
* @return the hash output
*/
public byte[] digest();
/**
* Input some bytes, then finalize the current hash computation
* and return the hash value in a newly-allocated array. The object
* is resetted.
*
* @param inbuf the input data
* @return the hash output
*/
public byte[] digest(byte[] inbuf);
/**
* Finalize the current hash computation and store the hash value
* in the provided output buffer. The {@code len} parameter
* contains the maximum number of bytes that should be written;
* no more bytes than the natural hash function output length will
* be produced. If {@code len} is smaller than the natural
* hash output length, the hash output is truncated to its first
* {@code len} bytes. The object is resetted.
*
* @param outbuf the output buffer
* @param off the output offset within {@code outbuf}
* @param len the requested hash output length (in bytes)
* @return the number of bytes actually written in {@code outbuf}
*/
public int digest(byte[] outbuf, int off, int len);
/**
* Get the natural hash function output length (in bytes).
*
* @return the digest output length (in bytes)
*/
public int getDigestLength();
/**
* Reset the object: this makes it suitable for a new hash
* computation. The current computation, if any, is discarded.
*/
public void reset();
/**
* Clone the current state. The returned object evolves independantly
* of this object.
*
* @return the clone
*/
public Digest copy();
/**
* <p>Return the "block length" for the hash function. This
* value is naturally defined for iterated hash functions
* (Merkle-Damgard). It is used in HMAC (that's what the
* <a href="http://tools.ietf.org/html/rfc2104">HMAC specification</a>
* names the "{@code B}" parameter).</p>
*
* <p>If the function is "block-less" then this function may
* return {@code -n} where {@code n} is an integer such that the
* block length for HMAC ("{@code B}") will be inferred from the
* key length, by selecting the smallest multiple of {@code n}
* which is no smaller than the key length. For instance, for
* the Fugue-xxx hash functions, this function returns -4: the
* virtual block length B is the HMAC key length, rounded up to
* the next multiple of 4.</p>
*
* @return the internal block length (in bytes), or {@code -n}
*/
public int getBlockLength();
/**
* <p>Get the display name for this function (e.g. {@code "SHA-1"}
* for SHA-1).</p>
*
* @see Object
*/
public String toString();
}

View File

@ -0,0 +1,266 @@
// $Id: DigestEngine.java 229 2010-06-16 20:22:27Z tp $
package org.ethereum.crypto.cryptohash;
/**
* <p>This class is a template which can be used to implement hash
* functions. It takes care of some of the API, and also provides an
* internal data buffer whose length is equal to the hash function
* internal block length.</p>
*
* <p>Classes which use this template MUST provide a working {@link
* #getBlockLength} method even before initialization (alternatively,
* they may define a custom {@link #getInternalBlockLength} which does
* not call {@link #getBlockLength}. The {@link #getDigestLength} should
* also be operational from the beginning, but it is acceptable that it
* returns 0 while the {@link #doInit} method has not been called
* yet.</p>
*
* <pre>
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* ===========================(LICENSE END)=============================
* </pre>
*
* @version $Revision: 229 $
* @author Thomas Pornin &lt;thomas.pornin@cryptolog.com&gt;
*/
public abstract class DigestEngine implements Digest {
/**
* Reset the hash algorithm state.
*/
protected abstract void engineReset();
/**
* Process one block of data.
*
* @param data the data block
*/
protected abstract void processBlock(byte[] data);
/**
* Perform the final padding and store the result in the
* provided buffer. This method shall call {@link #flush}
* and then {@link #update} with the appropriate padding
* data in order to get the full input data.
*
* @param buf the output buffer
* @param off the output offset
*/
protected abstract void doPadding(byte[] buf, int off);
/**
* This function is called at object creation time; the
* implementation should use it to perform initialization tasks.
* After this method is called, the implementation should be ready
* to process data or meaningfully honour calls such as
* {@link #getDigestLength}
*/
protected abstract void doInit();
private int digestLen, blockLen, inputLen;
private byte[] inputBuf, outputBuf;
private long blockCount;
/**
* Instantiate the engine.
*/
public DigestEngine()
{
doInit();
digestLen = getDigestLength();
blockLen = getInternalBlockLength();
inputBuf = new byte[blockLen];
outputBuf = new byte[digestLen];
inputLen = 0;
blockCount = 0;
}
private void adjustDigestLen()
{
if (digestLen == 0) {
digestLen = getDigestLength();
outputBuf = new byte[digestLen];
}
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public byte[] digest()
{
adjustDigestLen();
byte[] result = new byte[digestLen];
digest(result, 0, digestLen);
return result;
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public byte[] digest(byte[] input)
{
update(input, 0, input.length);
return digest();
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public int digest(byte[] buf, int offset, int len)
{
adjustDigestLen();
if (len >= digestLen) {
doPadding(buf, offset);
reset();
return digestLen;
} else {
doPadding(outputBuf, 0);
System.arraycopy(outputBuf, 0, buf, offset, len);
reset();
return len;
}
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public void reset()
{
engineReset();
inputLen = 0;
blockCount = 0;
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public void update(byte input)
{
inputBuf[inputLen ++] = (byte)input;
if (inputLen == blockLen) {
processBlock(inputBuf);
blockCount ++;
inputLen = 0;
}
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public void update(byte[] input)
{
update(input, 0, input.length);
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public void update(byte[] input, int offset, int len)
{
while (len > 0) {
int copyLen = blockLen - inputLen;
if (copyLen > len)
copyLen = len;
System.arraycopy(input, offset, inputBuf, inputLen,
copyLen);
offset += copyLen;
inputLen += copyLen;
len -= copyLen;
if (inputLen == blockLen) {
processBlock(inputBuf);
blockCount ++;
inputLen = 0;
}
}
}
/**
* Get the internal block length. This is the length (in
* bytes) of the array which will be passed as parameter to
* {@link #processBlock}. The default implementation of this
* method calls {@link #getBlockLength} and returns the same
* value. Overriding this method is useful when the advertised
* block length (which is used, for instance, by HMAC) is
* suboptimal with regards to internal buffering needs.
*
* @return the internal block length (in bytes)
*/
protected int getInternalBlockLength()
{
return getBlockLength();
}
/**
* Flush internal buffers, so that less than a block of data
* may at most be upheld.
*
* @return the number of bytes still unprocessed after the flush
*/
protected final int flush()
{
return inputLen;
}
/**
* Get a reference to an internal buffer with the same size
* than a block. The contents of that buffer are defined only
* immediately after a call to {@link #flush()}: if
* {@link #flush()} return the value {@code n}, then the
* first {@code n} bytes of the array returned by this method
* are the {@code n} bytes of input data which are still
* unprocessed. The values of the remaining bytes are
* undefined and may be altered at will.
*
* @return a block-sized internal buffer
*/
protected final byte[] getBlockBuffer()
{
return inputBuf;
}
/**
* Get the "block count": this is the number of times the
* {@link #processBlock} method has been invoked for the
* current hash operation. That counter is incremented
* <em>after</em> the call to {@link #processBlock}.
*
* @return the block count
*/
protected long getBlockCount()
{
return blockCount;
}
/**
* This function copies the internal buffering state to some
* other instance of a class extending {@code DigestEngine}.
* It returns a reference to the copy. This method is intended
* to be called by the implementation of the {@link #copy}
* method.
*
* @param dest the copy
* @return the value {@code dest}
*/
protected Digest copyState(DigestEngine dest)
{
dest.inputLen = inputLen;
dest.blockCount = blockCount;
System.arraycopy(inputBuf, 0, dest.inputBuf, 0,
inputBuf.length);
adjustDigestLen();
dest.adjustDigestLen();
System.arraycopy(outputBuf, 0, dest.outputBuf, 0,
outputBuf.length);
return dest;
}
}

View File

@ -0,0 +1,60 @@
// $Id: Keccak256.java 189 2010-05-14 21:21:46Z tp $
package org.ethereum.crypto.cryptohash;
/**
* <p>This class implements the Keccak-256 digest algorithm under the
* {@link org.ethereum.crypto.cryptohash.Digest} API.</p>
*
* <pre>
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* ===========================(LICENSE END)=============================
* </pre>
*
* @version $Revision: 189 $
* @author Thomas Pornin &lt;thomas.pornin@cryptolog.com&gt;
*/
public class Keccak256 extends KeccakCore {
/**
* Create the engine.
*/
public Keccak256()
{
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public Digest copy()
{
return copyState(new Keccak256());
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public int getDigestLength()
{
return 32;
}
}

View File

@ -0,0 +1,585 @@
// $Id: KeccakCore.java 258 2011-07-15 22:16:50Z tp $
package org.ethereum.crypto.cryptohash;
/**
* This class implements the core operations for the Keccak digest
* algorithm.
*
* <pre>
* ==========================(LICENSE BEGIN)============================
*
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* ===========================(LICENSE END)=============================
* </pre>
*
* @version $Revision: 258 $
* @author Thomas Pornin &lt;thomas.pornin@cryptolog.com&gt;
*/
abstract class KeccakCore extends DigestEngine {
KeccakCore()
{
}
private long[] A;
private byte[] tmpOut;
private static final long[] RC = {
0x0000000000000001L, 0x0000000000008082L,
0x800000000000808AL, 0x8000000080008000L,
0x000000000000808BL, 0x0000000080000001L,
0x8000000080008081L, 0x8000000000008009L,
0x000000000000008AL, 0x0000000000000088L,
0x0000000080008009L, 0x000000008000000AL,
0x000000008000808BL, 0x800000000000008BL,
0x8000000000008089L, 0x8000000000008003L,
0x8000000000008002L, 0x8000000000000080L,
0x000000000000800AL, 0x800000008000000AL,
0x8000000080008081L, 0x8000000000008080L,
0x0000000080000001L, 0x8000000080008008L
};
/**
* Encode the 64-bit word {@code val} into the array
* {@code buf} at offset {@code off}, in little-endian
* convention (least significant byte first).
*
* @param val the value to encode
* @param buf the destination buffer
* @param off the destination offset
*/
private static final void encodeLELong(long val, byte[] buf, int off)
{
buf[off + 0] = (byte)val;
buf[off + 1] = (byte)(val >>> 8);
buf[off + 2] = (byte)(val >>> 16);
buf[off + 3] = (byte)(val >>> 24);
buf[off + 4] = (byte)(val >>> 32);
buf[off + 5] = (byte)(val >>> 40);
buf[off + 6] = (byte)(val >>> 48);
buf[off + 7] = (byte)(val >>> 56);
}
/**
* Decode a 64-bit little-endian word from the array {@code buf}
* at offset {@code off}.
*
* @param buf the source buffer
* @param off the source offset
* @return the decoded value
*/
private static final long decodeLELong(byte[] buf, int off)
{
return (buf[off + 0] & 0xFFL)
| ((buf[off + 1] & 0xFFL) << 8)
| ((buf[off + 2] & 0xFFL) << 16)
| ((buf[off + 3] & 0xFFL) << 24)
| ((buf[off + 4] & 0xFFL) << 32)
| ((buf[off + 5] & 0xFFL) << 40)
| ((buf[off + 6] & 0xFFL) << 48)
| ((buf[off + 7] & 0xFFL) << 56);
}
/** @see org.ethereum.crypto.cryptohash.DigestEngine */
protected void engineReset()
{
doReset();
}
/** @see org.ethereum.crypto.cryptohash.DigestEngine */
protected void processBlock(byte[] data)
{
/* Input block */
for (int i = 0; i < data.length; i += 8)
A[i >>> 3] ^= decodeLELong(data, i);
long t0, t1, t2, t3, t4;
long tt0, tt1, tt2, tt3, tt4;
long t, kt;
long c0, c1, c2, c3, c4, bnn;
/*
* Unrolling four rounds kills performance big time
* on Intel x86 Core2, in both 32-bit and 64-bit modes
* (less than 1 MB/s instead of 55 MB/s on x86-64).
* Unrolling two rounds appears to be fine.
*/
for (int j = 0; j < 24; j += 2) {
tt0 = A[ 1] ^ A[ 6];
tt1 = A[11] ^ A[16];
tt0 ^= A[21] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[ 4] ^ A[ 9];
tt3 = A[14] ^ A[19];
tt0 ^= A[24];
tt2 ^= tt3;
t0 = tt0 ^ tt2;
tt0 = A[ 2] ^ A[ 7];
tt1 = A[12] ^ A[17];
tt0 ^= A[22] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[ 0] ^ A[ 5];
tt3 = A[10] ^ A[15];
tt0 ^= A[20];
tt2 ^= tt3;
t1 = tt0 ^ tt2;
tt0 = A[ 3] ^ A[ 8];
tt1 = A[13] ^ A[18];
tt0 ^= A[23] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[ 1] ^ A[ 6];
tt3 = A[11] ^ A[16];
tt0 ^= A[21];
tt2 ^= tt3;
t2 = tt0 ^ tt2;
tt0 = A[ 4] ^ A[ 9];
tt1 = A[14] ^ A[19];
tt0 ^= A[24] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[ 2] ^ A[ 7];
tt3 = A[12] ^ A[17];
tt0 ^= A[22];
tt2 ^= tt3;
t3 = tt0 ^ tt2;
tt0 = A[ 0] ^ A[ 5];
tt1 = A[10] ^ A[15];
tt0 ^= A[20] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[ 3] ^ A[ 8];
tt3 = A[13] ^ A[18];
tt0 ^= A[23];
tt2 ^= tt3;
t4 = tt0 ^ tt2;
A[ 0] = A[ 0] ^ t0;
A[ 5] = A[ 5] ^ t0;
A[10] = A[10] ^ t0;
A[15] = A[15] ^ t0;
A[20] = A[20] ^ t0;
A[ 1] = A[ 1] ^ t1;
A[ 6] = A[ 6] ^ t1;
A[11] = A[11] ^ t1;
A[16] = A[16] ^ t1;
A[21] = A[21] ^ t1;
A[ 2] = A[ 2] ^ t2;
A[ 7] = A[ 7] ^ t2;
A[12] = A[12] ^ t2;
A[17] = A[17] ^ t2;
A[22] = A[22] ^ t2;
A[ 3] = A[ 3] ^ t3;
A[ 8] = A[ 8] ^ t3;
A[13] = A[13] ^ t3;
A[18] = A[18] ^ t3;
A[23] = A[23] ^ t3;
A[ 4] = A[ 4] ^ t4;
A[ 9] = A[ 9] ^ t4;
A[14] = A[14] ^ t4;
A[19] = A[19] ^ t4;
A[24] = A[24] ^ t4;
A[ 5] = (A[ 5] << 36) | (A[ 5] >>> (64 - 36));
A[10] = (A[10] << 3) | (A[10] >>> (64 - 3));
A[15] = (A[15] << 41) | (A[15] >>> (64 - 41));
A[20] = (A[20] << 18) | (A[20] >>> (64 - 18));
A[ 1] = (A[ 1] << 1) | (A[ 1] >>> (64 - 1));
A[ 6] = (A[ 6] << 44) | (A[ 6] >>> (64 - 44));
A[11] = (A[11] << 10) | (A[11] >>> (64 - 10));
A[16] = (A[16] << 45) | (A[16] >>> (64 - 45));
A[21] = (A[21] << 2) | (A[21] >>> (64 - 2));
A[ 2] = (A[ 2] << 62) | (A[ 2] >>> (64 - 62));
A[ 7] = (A[ 7] << 6) | (A[ 7] >>> (64 - 6));
A[12] = (A[12] << 43) | (A[12] >>> (64 - 43));
A[17] = (A[17] << 15) | (A[17] >>> (64 - 15));
A[22] = (A[22] << 61) | (A[22] >>> (64 - 61));
A[ 3] = (A[ 3] << 28) | (A[ 3] >>> (64 - 28));
A[ 8] = (A[ 8] << 55) | (A[ 8] >>> (64 - 55));
A[13] = (A[13] << 25) | (A[13] >>> (64 - 25));
A[18] = (A[18] << 21) | (A[18] >>> (64 - 21));
A[23] = (A[23] << 56) | (A[23] >>> (64 - 56));
A[ 4] = (A[ 4] << 27) | (A[ 4] >>> (64 - 27));
A[ 9] = (A[ 9] << 20) | (A[ 9] >>> (64 - 20));
A[14] = (A[14] << 39) | (A[14] >>> (64 - 39));
A[19] = (A[19] << 8) | (A[19] >>> (64 - 8));
A[24] = (A[24] << 14) | (A[24] >>> (64 - 14));
bnn = ~A[12];
kt = A[ 6] | A[12];
c0 = A[ 0] ^ kt;
kt = bnn | A[18];
c1 = A[ 6] ^ kt;
kt = A[18] & A[24];
c2 = A[12] ^ kt;
kt = A[24] | A[ 0];
c3 = A[18] ^ kt;
kt = A[ 0] & A[ 6];
c4 = A[24] ^ kt;
A[ 0] = c0;
A[ 6] = c1;
A[12] = c2;
A[18] = c3;
A[24] = c4;
bnn = ~A[22];
kt = A[ 9] | A[10];
c0 = A[ 3] ^ kt;
kt = A[10] & A[16];
c1 = A[ 9] ^ kt;
kt = A[16] | bnn;
c2 = A[10] ^ kt;
kt = A[22] | A[ 3];
c3 = A[16] ^ kt;
kt = A[ 3] & A[ 9];
c4 = A[22] ^ kt;
A[ 3] = c0;
A[ 9] = c1;
A[10] = c2;
A[16] = c3;
A[22] = c4;
bnn = ~A[19];
kt = A[ 7] | A[13];
c0 = A[ 1] ^ kt;
kt = A[13] & A[19];
c1 = A[ 7] ^ kt;
kt = bnn & A[20];
c2 = A[13] ^ kt;
kt = A[20] | A[ 1];
c3 = bnn ^ kt;
kt = A[ 1] & A[ 7];
c4 = A[20] ^ kt;
A[ 1] = c0;
A[ 7] = c1;
A[13] = c2;
A[19] = c3;
A[20] = c4;
bnn = ~A[17];
kt = A[ 5] & A[11];
c0 = A[ 4] ^ kt;
kt = A[11] | A[17];
c1 = A[ 5] ^ kt;
kt = bnn | A[23];
c2 = A[11] ^ kt;
kt = A[23] & A[ 4];
c3 = bnn ^ kt;
kt = A[ 4] | A[ 5];
c4 = A[23] ^ kt;
A[ 4] = c0;
A[ 5] = c1;
A[11] = c2;
A[17] = c3;
A[23] = c4;
bnn = ~A[ 8];
kt = bnn & A[14];
c0 = A[ 2] ^ kt;
kt = A[14] | A[15];
c1 = bnn ^ kt;
kt = A[15] & A[21];
c2 = A[14] ^ kt;
kt = A[21] | A[ 2];
c3 = A[15] ^ kt;
kt = A[ 2] & A[ 8];
c4 = A[21] ^ kt;
A[ 2] = c0;
A[ 8] = c1;
A[14] = c2;
A[15] = c3;
A[21] = c4;
A[ 0] = A[ 0] ^ RC[j + 0];
tt0 = A[ 6] ^ A[ 9];
tt1 = A[ 7] ^ A[ 5];
tt0 ^= A[ 8] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[24] ^ A[22];
tt3 = A[20] ^ A[23];
tt0 ^= A[21];
tt2 ^= tt3;
t0 = tt0 ^ tt2;
tt0 = A[12] ^ A[10];
tt1 = A[13] ^ A[11];
tt0 ^= A[14] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[ 0] ^ A[ 3];
tt3 = A[ 1] ^ A[ 4];
tt0 ^= A[ 2];
tt2 ^= tt3;
t1 = tt0 ^ tt2;
tt0 = A[18] ^ A[16];
tt1 = A[19] ^ A[17];
tt0 ^= A[15] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[ 6] ^ A[ 9];
tt3 = A[ 7] ^ A[ 5];
tt0 ^= A[ 8];
tt2 ^= tt3;
t2 = tt0 ^ tt2;
tt0 = A[24] ^ A[22];
tt1 = A[20] ^ A[23];
tt0 ^= A[21] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[12] ^ A[10];
tt3 = A[13] ^ A[11];
tt0 ^= A[14];
tt2 ^= tt3;
t3 = tt0 ^ tt2;
tt0 = A[ 0] ^ A[ 3];
tt1 = A[ 1] ^ A[ 4];
tt0 ^= A[ 2] ^ tt1;
tt0 = (tt0 << 1) | (tt0 >>> 63);
tt2 = A[18] ^ A[16];
tt3 = A[19] ^ A[17];
tt0 ^= A[15];
tt2 ^= tt3;
t4 = tt0 ^ tt2;
A[ 0] = A[ 0] ^ t0;
A[ 3] = A[ 3] ^ t0;
A[ 1] = A[ 1] ^ t0;
A[ 4] = A[ 4] ^ t0;
A[ 2] = A[ 2] ^ t0;
A[ 6] = A[ 6] ^ t1;
A[ 9] = A[ 9] ^ t1;
A[ 7] = A[ 7] ^ t1;
A[ 5] = A[ 5] ^ t1;
A[ 8] = A[ 8] ^ t1;
A[12] = A[12] ^ t2;
A[10] = A[10] ^ t2;
A[13] = A[13] ^ t2;
A[11] = A[11] ^ t2;
A[14] = A[14] ^ t2;
A[18] = A[18] ^ t3;
A[16] = A[16] ^ t3;
A[19] = A[19] ^ t3;
A[17] = A[17] ^ t3;
A[15] = A[15] ^ t3;
A[24] = A[24] ^ t4;
A[22] = A[22] ^ t4;
A[20] = A[20] ^ t4;
A[23] = A[23] ^ t4;
A[21] = A[21] ^ t4;
A[ 3] = (A[ 3] << 36) | (A[ 3] >>> (64 - 36));
A[ 1] = (A[ 1] << 3) | (A[ 1] >>> (64 - 3));
A[ 4] = (A[ 4] << 41) | (A[ 4] >>> (64 - 41));
A[ 2] = (A[ 2] << 18) | (A[ 2] >>> (64 - 18));
A[ 6] = (A[ 6] << 1) | (A[ 6] >>> (64 - 1));
A[ 9] = (A[ 9] << 44) | (A[ 9] >>> (64 - 44));
A[ 7] = (A[ 7] << 10) | (A[ 7] >>> (64 - 10));
A[ 5] = (A[ 5] << 45) | (A[ 5] >>> (64 - 45));
A[ 8] = (A[ 8] << 2) | (A[ 8] >>> (64 - 2));
A[12] = (A[12] << 62) | (A[12] >>> (64 - 62));
A[10] = (A[10] << 6) | (A[10] >>> (64 - 6));
A[13] = (A[13] << 43) | (A[13] >>> (64 - 43));
A[11] = (A[11] << 15) | (A[11] >>> (64 - 15));
A[14] = (A[14] << 61) | (A[14] >>> (64 - 61));
A[18] = (A[18] << 28) | (A[18] >>> (64 - 28));
A[16] = (A[16] << 55) | (A[16] >>> (64 - 55));
A[19] = (A[19] << 25) | (A[19] >>> (64 - 25));
A[17] = (A[17] << 21) | (A[17] >>> (64 - 21));
A[15] = (A[15] << 56) | (A[15] >>> (64 - 56));
A[24] = (A[24] << 27) | (A[24] >>> (64 - 27));
A[22] = (A[22] << 20) | (A[22] >>> (64 - 20));
A[20] = (A[20] << 39) | (A[20] >>> (64 - 39));
A[23] = (A[23] << 8) | (A[23] >>> (64 - 8));
A[21] = (A[21] << 14) | (A[21] >>> (64 - 14));
bnn = ~A[13];
kt = A[ 9] | A[13];
c0 = A[ 0] ^ kt;
kt = bnn | A[17];
c1 = A[ 9] ^ kt;
kt = A[17] & A[21];
c2 = A[13] ^ kt;
kt = A[21] | A[ 0];
c3 = A[17] ^ kt;
kt = A[ 0] & A[ 9];
c4 = A[21] ^ kt;
A[ 0] = c0;
A[ 9] = c1;
A[13] = c2;
A[17] = c3;
A[21] = c4;
bnn = ~A[14];
kt = A[22] | A[ 1];
c0 = A[18] ^ kt;
kt = A[ 1] & A[ 5];
c1 = A[22] ^ kt;
kt = A[ 5] | bnn;
c2 = A[ 1] ^ kt;
kt = A[14] | A[18];
c3 = A[ 5] ^ kt;
kt = A[18] & A[22];
c4 = A[14] ^ kt;
A[18] = c0;
A[22] = c1;
A[ 1] = c2;
A[ 5] = c3;
A[14] = c4;
bnn = ~A[23];
kt = A[10] | A[19];
c0 = A[ 6] ^ kt;
kt = A[19] & A[23];
c1 = A[10] ^ kt;
kt = bnn & A[ 2];
c2 = A[19] ^ kt;
kt = A[ 2] | A[ 6];
c3 = bnn ^ kt;
kt = A[ 6] & A[10];
c4 = A[ 2] ^ kt;
A[ 6] = c0;
A[10] = c1;
A[19] = c2;
A[23] = c3;
A[ 2] = c4;
bnn = ~A[11];
kt = A[ 3] & A[ 7];
c0 = A[24] ^ kt;
kt = A[ 7] | A[11];
c1 = A[ 3] ^ kt;
kt = bnn | A[15];
c2 = A[ 7] ^ kt;
kt = A[15] & A[24];
c3 = bnn ^ kt;
kt = A[24] | A[ 3];
c4 = A[15] ^ kt;
A[24] = c0;
A[ 3] = c1;
A[ 7] = c2;
A[11] = c3;
A[15] = c4;
bnn = ~A[16];
kt = bnn & A[20];
c0 = A[12] ^ kt;
kt = A[20] | A[ 4];
c1 = bnn ^ kt;
kt = A[ 4] & A[ 8];
c2 = A[20] ^ kt;
kt = A[ 8] | A[12];
c3 = A[ 4] ^ kt;
kt = A[12] & A[16];
c4 = A[ 8] ^ kt;
A[12] = c0;
A[16] = c1;
A[20] = c2;
A[ 4] = c3;
A[ 8] = c4;
A[ 0] = A[ 0] ^ RC[j + 1];
t = A[ 5];
A[ 5] = A[18];
A[18] = A[11];
A[11] = A[10];
A[10] = A[ 6];
A[ 6] = A[22];
A[22] = A[20];
A[20] = A[12];
A[12] = A[19];
A[19] = A[15];
A[15] = A[24];
A[24] = A[ 8];
A[ 8] = t;
t = A[ 1];
A[ 1] = A[ 9];
A[ 9] = A[14];
A[14] = A[ 2];
A[ 2] = A[13];
A[13] = A[23];
A[23] = A[ 4];
A[ 4] = A[21];
A[21] = A[16];
A[16] = A[ 3];
A[ 3] = A[17];
A[17] = A[ 7];
A[ 7] = t;
}
}
/** @see org.ethereum.crypto.cryptohash.DigestEngine */
protected void doPadding(byte[] out, int off)
{
int ptr = flush();
byte[] buf = getBlockBuffer();
if ((ptr + 1) == buf.length) {
buf[ptr] = (byte)0x81;
} else {
buf[ptr] = (byte)0x01;
for (int i = ptr + 1; i < (buf.length - 1); i ++)
buf[i] = 0;
buf[buf.length - 1] = (byte)0x80;
}
processBlock(buf);
A[ 1] = ~A[ 1];
A[ 2] = ~A[ 2];
A[ 8] = ~A[ 8];
A[12] = ~A[12];
A[17] = ~A[17];
A[20] = ~A[20];
int dlen = getDigestLength();
for (int i = 0; i < dlen; i += 8)
encodeLELong(A[i >>> 3], tmpOut, i);
System.arraycopy(tmpOut, 0, out, off, dlen);
}
/** @see org.ethereum.crypto.cryptohash.DigestEngine */
protected void doInit()
{
A = new long[25];
tmpOut = new byte[(getDigestLength() + 7) & ~7];
doReset();
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public int getBlockLength()
{
return 200 - 2 * getDigestLength();
}
private final void doReset()
{
for (int i = 0; i < 25; i ++)
A[i] = 0;
A[ 1] = 0xFFFFFFFFFFFFFFFFL;
A[ 2] = 0xFFFFFFFFFFFFFFFFL;
A[ 8] = 0xFFFFFFFFFFFFFFFFL;
A[12] = 0xFFFFFFFFFFFFFFFFL;
A[17] = 0xFFFFFFFFFFFFFFFFL;
A[20] = 0xFFFFFFFFFFFFFFFFL;
}
/** @see org.ethereum.crypto.cryptohash.DigestEngine */
protected Digest copyState(KeccakCore dst)
{
System.arraycopy(A, 0, dst.A, 0, 25);
return super.copyState(dst);
}
/** @see org.ethereum.crypto.cryptohash.Digest */
public String toString()
{
return "Keccak-" + (getDigestLength() << 3);
}
}

View File

@ -2,12 +2,15 @@ package org.ethereum.datasource;
import org.ethereum.config.SystemProperties;
import org.fusesource.leveldbjni.JniDBFactory;
import org.fusesource.leveldbjni.internal.JniDB;
import org.iq80.leveldb.CompressionType;
import org.iq80.leveldb.DB;
import org.iq80.leveldb.DBIterator;
import org.iq80.leveldb.Options;
import org.iq80.leveldb.WriteBatch;
import org.iq80.leveldb.impl.Iq80DBFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -46,6 +49,10 @@ public class LevelDbDataSource implements KeyValueDataSource {
Options options = new Options();
options.createIfMissing(true);
options.compressionType(CompressionType.NONE);
options.blockSize(10 * 1024);
options.writeBufferSize(10 * 1024);
options.cacheSize(0);
try {
logger.debug("Opening database");
File dbLocation = new File(System.getProperty("user.dir") + "/" +
@ -57,7 +64,23 @@ public class LevelDbDataSource implements KeyValueDataSource {
}
logger.debug("Initializing new or existing database: '{}'", name);
db = factory.open(fileLocation, options);
try {
db = JniDBFactory.factory.open(fileLocation, options);
} catch (Throwable e) {
System.out.println("No native version of LevelDB found");
}
String cpu = System.getProperty("sun.arch.data.model");
String os = System.getProperty("os.name");
if (db instanceof JniDB)
System.out.println("Native version of LevelDB loaded for: " + os + "." + cpu + "bit");
else{
System.out.println("Pure Java version of LevelDB loaded");
db = Iq80DBFactory.factory.open(fileLocation, options);
}
} catch (IOException ioe) {
logger.error(ioe.getMessage(), ioe);

View File

@ -3,6 +3,7 @@ package org.ethereum.db;
import org.ethereum.core.Block;
import org.ethereum.core.TransactionReceipt;
import org.hibernate.SessionFactory;
import java.math.BigInteger;
@ -39,4 +40,10 @@ public interface BlockStore {
void reset();
TransactionReceipt getTransactionReceiptByHash(byte[] hash);
}
public void flush();
public void load();
//public void setSessionFactory(SessionFactory sessionFactory);
}

View File

@ -3,6 +3,7 @@ package org.ethereum.db;
import org.ethereum.core.Block;
import org.ethereum.core.TransactionReceipt;
import org.ethereum.crypto.HashUtil;
import org.hibernate.SessionFactory;
import java.math.BigInteger;
@ -75,4 +76,17 @@ public class BlockStoreDummy implements BlockStore {
public TransactionReceipt getTransactionReceiptByHash(byte[] hash) {
return null;
}
@Override
public void flush() {
}
@Override
public void load() {
}
//@Override
public void setSessionFactory(SessionFactory sessionFactory) {
}
}

View File

@ -3,11 +3,9 @@ package org.ethereum.db;
import org.ethereum.core.Block;
import org.ethereum.core.TransactionReceipt;
import org.ethereum.util.ByteUtil;
import org.hibernate.SessionFactory;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
@ -173,4 +171,19 @@ public class BlockStoreImpl implements BlockStore {
return new TransactionReceipt(vo.rlp);
}
}
@Override
public void flush() {
}
@Override
public void load() {
}
/*
@Override
public void setSessionFactory(SessionFactory sessionFactory) {
}
*/
}

View File

@ -2,10 +2,7 @@ package org.ethereum.db;
import java.math.BigInteger;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.*;
/**
* @author Roman Mandeleil
@ -21,6 +18,7 @@ public class BlockVO {
Long number;
@Lob
@Column(length=102400)
byte[] rlp;
BigInteger cumulativeDifficulty;

View File

@ -1,12 +1,16 @@
package org.ethereum.db;
import org.ethereum.trie.SecureTrie;
import org.ethereum.trie.Trie;
import org.ethereum.util.*;
import org.ethereum.vm.DataWord;
import org.spongycastle.util.encoders.Hex;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
/**
* @author Roman Mandeleil
@ -16,33 +20,23 @@ public class ContractDetailsCacheImpl implements ContractDetails {
private Map<DataWord, DataWord> storage = new HashMap<>();
ContractDetails origContract = new ContractDetailsImpl();
private byte[] code = ByteUtil.EMPTY_BYTE_ARRAY;
private byte[] code = EMPTY_BYTE_ARRAY;
private boolean dirty = false;
private boolean deleted = false;
public ContractDetailsCacheImpl() {
}
public ContractDetailsCacheImpl(byte[] rlpCode) {
decode(rlpCode);
}
public ContractDetailsCacheImpl(Map<DataWord, DataWord> storage, byte[] code) {
public ContractDetailsCacheImpl(ContractDetails origContract) {
this.origContract = origContract;
this.code = origContract != null ? origContract.getCode() : EMPTY_BYTE_ARRAY;
}
@Override
public void put(DataWord key, DataWord value) {
if (value.equals(DataWord.ZERO)) {
storage.remove(key);
} else {
storage.put(key, value);
}
storage.put(key, value);
this.setDirty(true);
}
@ -50,8 +44,17 @@ public class ContractDetailsCacheImpl implements ContractDetails {
public DataWord get(DataWord key) {
DataWord value = storage.get(key);
if (value != null) value = value.clone();
return value;
if (value != null)
value = value.clone();
else{
if (origContract == null) return null;
value = origContract.get(key);
}
if (value == null || value.isZero())
return null;
else
return value;
}
@Override
@ -99,7 +102,7 @@ public class ContractDetailsCacheImpl implements ContractDetails {
storage.put(new DataWord(key.getRLPData()), new DataWord(value.getRLPData()));
}
this.code = (code.getRLPData() == null) ? ByteUtil.EMPTY_BYTE_ARRAY : code.getRLPData();
this.code = (code.getRLPData() == null) ? EMPTY_BYTE_ARRAY : code.getRLPData();
}
@Override
@ -158,9 +161,10 @@ public class ContractDetailsCacheImpl implements ContractDetails {
for (int i = 0; i < storageKeys.size(); ++i){
DataWord key = storageKeys.get(i);
DataWord value = storageKeys.get(i);
DataWord value = storageValues.get(i);
storage.put(key, value);
if (value.isZero())
storage.put(key, null);
}
}
@ -174,7 +178,7 @@ public class ContractDetailsCacheImpl implements ContractDetails {
@Override
public ContractDetails clone() {
ContractDetailsCacheImpl contractDetails = new ContractDetailsCacheImpl();
ContractDetailsCacheImpl contractDetails = new ContractDetailsCacheImpl(origContract);
Object storageClone = ((HashMap<DataWord, DataWord>)storage).clone();
@ -192,5 +196,16 @@ public class ContractDetailsCacheImpl implements ContractDetails {
return ret;
}
public void commit(){
if (origContract == null) return;
for (DataWord key : storage.keySet()) {
origContract.put(key, storage.get(key));
}
origContract.setCode(code);
}
}

Some files were not shown because too many files have changed in this diff Show More