Merge branch 'android-test-poc9-rlpx' of opulence.git.beanstalkapp.com:/opulence/ethereumj into android-test-poc9-rlpx
This commit is contained in:
commit
7ffb5c16e5
|
@ -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>
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,4 +31,6 @@ public interface BlockStoreDatabase {
|
|||
public void save(TransactionReceiptVO transactionReceiptVO);
|
||||
|
||||
public TransactionReceipt getTransactionReceiptByHash(byte[] hash);
|
||||
|
||||
public boolean flush(List<Block> blocks);
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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) {}
|
||||
}
|
|
@ -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'
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ public class AccountState {
|
|||
}
|
||||
|
||||
public void setNonce(BigInteger nonce) {
|
||||
rlpEncoded = null;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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){
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 <thomas.pornin@cryptolog.com>
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
|
@ -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 <thomas.pornin@cryptolog.com>
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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 <thomas.pornin@cryptolog.com>
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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 <thomas.pornin@cryptolog.com>
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue