mirror of
https://github.com/status-im/ethereumj-personal.git
synced 2025-02-22 08:28:08 +00:00
Merged latest develop changes.
Some interop fixes.
This commit is contained in:
parent
a8dbead829
commit
c6288e295d
@ -8,6 +8,7 @@ import org.ethereum.android.service.EthereumConnector;
|
|||||||
public class EthereumApplication extends MultiDexApplication {
|
public class EthereumApplication extends MultiDexApplication {
|
||||||
|
|
||||||
public EthereumConnector ethereum = null;
|
public EthereumConnector ethereum = null;
|
||||||
|
public String log="";
|
||||||
|
|
||||||
@Override public void onCreate() {
|
@Override public void onCreate() {
|
||||||
|
|
||||||
|
@ -154,8 +154,13 @@ public class RemoteMainActivity extends ActionBarActivity implements ActivityInt
|
|||||||
|
|
||||||
Date date = new Date(timestamp);
|
Date date = new Date(timestamp);
|
||||||
|
|
||||||
|
EthereumApplication app = (EthereumApplication)getApplication();
|
||||||
|
app.log += formatter.format(date) + " -> " + message + "\n\n";
|
||||||
|
if (app.log.length() > 10000) {
|
||||||
|
app.log = app.log.substring(5000);
|
||||||
|
}
|
||||||
for(FragmentInterface fragment: fragments) {
|
for(FragmentInterface fragment: fragments) {
|
||||||
fragment.onMessage(formatter.format(date) + " -> " + message + "\n");
|
fragment.onMessage(app.log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,8 @@ dependencies {
|
|||||||
exclude group: "org.hibernate", module: "hibernate-entitymanager"
|
exclude group: "org.hibernate", module: "hibernate-entitymanager"
|
||||||
exclude group: "redis.clients", module: "jedis"
|
exclude group: "redis.clients", module: "jedis"
|
||||||
exclude group: "org.antlr", module: "antlr4-runtime"
|
exclude group: "org.antlr", module: "antlr4-runtime"
|
||||||
|
exclude group: "org.fusesource.leveldbjni", module: "leveldbjni"
|
||||||
|
exclude group: "org.fusesource.leveldbjni", module: "leveldbjni-all"
|
||||||
}
|
}
|
||||||
|
|
||||||
//compile "com.google.dagger:dagger:2.1-SNAPSHOT"
|
//compile "com.google.dagger:dagger:2.1-SNAPSHOT"
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="db" level="ERROR">
|
<logger name="db" level="DEBUG">
|
||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
@ -87,7 +87,7 @@
|
|||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="general" level="ERROR">
|
<logger name="general" level="DEBUG">
|
||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
@ -99,19 +99,19 @@
|
|||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="main" level="ERROR">
|
<logger name="main" level="DEBUG">
|
||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="state" level="ERROR">
|
<logger name="state" level="DEBUG">
|
||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="repository" level="ERROR">
|
<logger name="repository" level="DEBUG">
|
||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="blockchain" level="ERROR">
|
<logger name="blockchain" level="DEBUG">
|
||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
@ -127,7 +127,7 @@
|
|||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="hsqldb.db" level="ERROR">
|
<logger name="hsqldb.db" level="DEBUG">
|
||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
@ -135,7 +135,7 @@
|
|||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<root level="INFO">
|
<root level="DEBUG">
|
||||||
<appender-ref ref="logcat" />
|
<appender-ref ref="logcat" />
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
|
@ -19,7 +19,9 @@ import java.util.HashSet;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
import static org.fusesource.leveldbjni.JniDBFactory.factory;
|
||||||
|
|
||||||
|
//import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Roman Mandeleil
|
* @author Roman Mandeleil
|
||||||
@ -55,6 +57,7 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
|||||||
logger.debug("Opening database");
|
logger.debug("Opening database");
|
||||||
File dbLocation = new File(SystemProperties.CONFIG.databaseDir());
|
File dbLocation = new File(SystemProperties.CONFIG.databaseDir());
|
||||||
File fileLocation = new File(dbLocation, name);
|
File fileLocation = new File(dbLocation, name);
|
||||||
|
if (!dbLocation.exists()) dbLocation.mkdirs();
|
||||||
|
|
||||||
if (SystemProperties.CONFIG.databaseReset()) {
|
if (SystemProperties.CONFIG.databaseReset()) {
|
||||||
destroyDB(fileLocation);
|
destroyDB(fileLocation);
|
||||||
|
@ -137,8 +137,8 @@ public class EthereumModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
ShhHandler provideShhHandler(EthereumListener listener) {
|
ShhHandler provideShhHandler(WorldManager worldManager) {
|
||||||
return new ShhHandler(listener);
|
return new ShhHandler(worldManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -5,7 +5,7 @@ import com.thetransactioncompany.jsonrpc2.server.*;
|
|||||||
import org.ethereum.android.jsonrpc.full.JsonRpcServerMethod;
|
import org.ethereum.android.jsonrpc.full.JsonRpcServerMethod;
|
||||||
import org.ethereum.core.AccountState;
|
import org.ethereum.core.AccountState;
|
||||||
import org.ethereum.facade.Ethereum;
|
import org.ethereum.facade.Ethereum;
|
||||||
import org.ethereum.serpent.SerpentCompiler;
|
//import org.ethereum.serpent.SerpentCompiler;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -35,12 +35,12 @@ public class eth_compileSerpent extends JsonRpcServerMethod {
|
|||||||
Pattern pattern = Pattern.compile("(.*?)init:(.*?)code:(.*?)", Pattern.DOTALL);
|
Pattern pattern = Pattern.compile("(.*?)init:(.*?)code:(.*?)", Pattern.DOTALL);
|
||||||
Matcher matcher = pattern.matcher(code);
|
Matcher matcher = pattern.matcher(code);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
asmResult = SerpentCompiler.compileFullNotion(code);
|
//asmResult = SerpentCompiler.compileFullNotion(code);
|
||||||
machineCode = SerpentCompiler.compileFullNotionAssemblyToMachine(asmResult);
|
//machineCode = SerpentCompiler.compileFullNotionAssemblyToMachine(asmResult);
|
||||||
} else {
|
} else {
|
||||||
asmResult = SerpentCompiler.compile(code);
|
//asmResult = SerpentCompiler.compile(code);
|
||||||
machineCode = SerpentCompiler.compileAssemblyToMachine(asmResult);
|
//machineCode = SerpentCompiler.compileAssemblyToMachine(asmResult);
|
||||||
machineCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null);
|
//machineCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null);
|
||||||
}
|
}
|
||||||
} catch (Throwable th) {
|
} catch (Throwable th) {
|
||||||
return new JSONRPC2Response(JSONRPC2Error.INTERNAL_ERROR, req.getID());
|
return new JSONRPC2Response(JSONRPC2Error.INTERNAL_ERROR, req.getID());
|
||||||
|
@ -444,7 +444,7 @@ public class EthereumRemoteService extends EthereumService {
|
|||||||
String identifier = ((Bundle)message.obj).getString("identifier");
|
String identifier = ((Bundle)message.obj).getString("identifier");
|
||||||
clientListeners.put(identifier, message.replyTo);
|
clientListeners.put(identifier, message.replyTo);
|
||||||
Bundle data = message.getData();
|
Bundle data = message.getData();
|
||||||
data.setClassLoader(EnumSet.class.getClassLoader());
|
data.setClassLoader(EventFlag.class.getClassLoader());
|
||||||
EnumSet<EventFlag> flags = (EnumSet<EventFlag>)data.getSerializable("flags");
|
EnumSet<EventFlag> flags = (EnumSet<EventFlag>)data.getSerializable("flags");
|
||||||
EnumSet<EventFlag> list = (flags == null || flags.contains(EventFlag.EVENT_ALL)) ? EnumSet.allOf(EventFlag.class) : flags;
|
EnumSet<EventFlag> list = (flags == null || flags.contains(EventFlag.EVENT_ALL)) ? EnumSet.allOf(EventFlag.class) : flags;
|
||||||
for (EventFlag flag: list) {
|
for (EventFlag flag: list) {
|
||||||
|
@ -54,7 +54,13 @@ public class PendingTransactionsEventData extends EventData {
|
|||||||
private PendingTransactionsEventData(Parcel in) {
|
private PendingTransactionsEventData(Parcel in) {
|
||||||
|
|
||||||
super(in);
|
super(in);
|
||||||
transactions = new HashSet<Transaction>(Arrays.asList((Transaction[])in.readParcelableArray(org.ethereum.android.interop.Transaction.class.getClassLoader())));
|
Parcelable[] transactions = in.readParcelableArray(org.ethereum.android.interop.Transaction.class.getClassLoader());
|
||||||
|
Transaction[] txs = new Transaction[transactions.length];
|
||||||
|
int index = 0;
|
||||||
|
for (Parcelable transaction: transactions) {
|
||||||
|
txs[index] = (Transaction)transaction;
|
||||||
|
}
|
||||||
|
this.transactions = new HashSet<Transaction>(Arrays.asList(txs));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ plugins {
|
|||||||
id 'application'
|
id 'application'
|
||||||
id 'jacoco'
|
id 'jacoco'
|
||||||
id 'com.github.johnrengelman.shadow' version '1.2.1'
|
id 'com.github.johnrengelman.shadow' version '1.2.1'
|
||||||
id 'me.champeau.gradle.antlr4' version '0.1'
|
|
||||||
id 'com.github.kt3k.coveralls' version '2.0.1x'
|
id 'com.github.kt3k.coveralls' version '2.0.1x'
|
||||||
id 'com.jfrog.bintray' version '1.0'
|
id 'com.jfrog.bintray' version '1.0'
|
||||||
}
|
}
|
||||||
@ -30,7 +29,7 @@ repositories {
|
|||||||
sourceCompatibility = 1.7
|
sourceCompatibility = 1.7
|
||||||
|
|
||||||
mainClassName = 'org.ethereum.Start'
|
mainClassName = 'org.ethereum.Start'
|
||||||
applicationDefaultJvmArgs = ["-server", "-Xss32m"]
|
applicationDefaultJvmArgs = ["-server", "-Xss32m", "-Xms3500m"]
|
||||||
|
|
||||||
ext.generatedSrcDir = file('src/gen/java')
|
ext.generatedSrcDir = file('src/gen/java')
|
||||||
|
|
||||||
@ -45,24 +44,7 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
antlr4 {
|
|
||||||
extraArgs = ['-package', 'org.ethereum.serpent']
|
|
||||||
output = file("${generatedSrcDir}/org/ethereum/serpent")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isJavaProject(project)) {
|
|
||||||
compileJava.dependsOn antlr4
|
|
||||||
} else if (isAndroidProject(project)) {
|
|
||||||
preBuild.dependsOn antlr4
|
|
||||||
} else {
|
|
||||||
throw new GradleException('unknown plugin type')
|
|
||||||
}
|
|
||||||
public static boolean isJavaProject(Project project) {
|
|
||||||
project.plugins.findPlugin('java')
|
|
||||||
}
|
|
||||||
public static boolean isAndroidProject(Project project) {
|
|
||||||
project.plugins.findPlugin('com.android.application') || project.plugins.findPlugin('com.android.library')
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile){
|
tasks.withType(JavaCompile){
|
||||||
options.warnings = false
|
options.warnings = false
|
||||||
@ -108,10 +90,6 @@ test {
|
|||||||
systemProperty "file.encoding", "UTF-8"
|
systemProperty "file.encoding", "UTF-8"
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
|
||||||
compile.extendsFrom antlr4
|
|
||||||
}
|
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
slf4jVersion = '1.7.12'
|
slf4jVersion = '1.7.12'
|
||||||
leveldbVersion = '0.7'
|
leveldbVersion = '0.7'
|
||||||
@ -133,9 +111,10 @@ dependencies {
|
|||||||
|
|
||||||
compile "org.iq80.leveldb:leveldb:${leveldbVersion}"
|
compile "org.iq80.leveldb:leveldb:${leveldbVersion}"
|
||||||
|
|
||||||
|
compile "org.fusesource.leveldbjni:leveldbjni:1.8"
|
||||||
|
compile "org.fusesource.leveldbjni:leveldbjni-all:1.8"
|
||||||
|
|
||||||
compile "com.cedarsoftware:java-util:1.8.0" // for deep equals
|
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.javassist:javassist:3.15.0-GA"
|
||||||
compile "org.slf4j:slf4j-api:${slf4jVersion}"
|
compile "org.slf4j:slf4j-api:${slf4jVersion}"
|
||||||
compile "log4j:log4j:${log4jVersion}"
|
compile "log4j:log4j:${log4jVersion}"
|
||||||
@ -149,7 +128,9 @@ dependencies {
|
|||||||
compile "commons-dbcp:commons-dbcp:1.4"
|
compile "commons-dbcp:commons-dbcp:1.4"
|
||||||
compile "redis.clients:jedis:2.6.0"
|
compile "redis.clients:jedis:2.6.0"
|
||||||
compile "com.h2database:h2:1.4.187"
|
compile "com.h2database:h2:1.4.187"
|
||||||
compile "org.mapdb:mapdb:1.0.7"
|
|
||||||
|
// compile "org.mapdb:mapdb:1.0.7"
|
||||||
|
compile "org.mapdb:mapdb:2.0-alpha3"
|
||||||
|
|
||||||
compile "org.slf4j:slf4j-log4j12:${slf4jVersion}"
|
compile "org.slf4j:slf4j-log4j12:${slf4jVersion}"
|
||||||
compile "log4j:apache-log4j-extras:${log4jVersion}"
|
compile "log4j:apache-log4j-extras:${log4jVersion}"
|
||||||
|
3
ethereumj-core/src/gen/java/.gitignore
vendored
3
ethereumj-core/src/gen/java/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
!README.md
|
|
@ -1,5 +0,0 @@
|
|||||||
This is the output directory for transient sources generated from grammars in
|
|
||||||
the `src/main/antlr4` directory using the `gradle antlr4` task. Sources are
|
|
||||||
output here instead of the typical `build/generated-src` output directory in
|
|
||||||
order to avoid confusing IntelliJ IDEA. See the antlr plugin configuration in
|
|
||||||
`build.gradle` for details.
|
|
@ -1,241 +0,0 @@
|
|||||||
// @author Roman Mandeleil
|
|
||||||
// @since 22.03.2014
|
|
||||||
|
|
||||||
grammar Serpent;
|
|
||||||
|
|
||||||
tokens {
|
|
||||||
INDENT, DEDENT }
|
|
||||||
@lexer::header {
|
|
||||||
import com.yuvalshavit.antlr4.DenterHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@lexer::members {
|
|
||||||
private final DenterHelper denter = new DenterHelper(NL, SerpentParser.INDENT, SerpentParser.DEDENT) {
|
|
||||||
@Override
|
|
||||||
public Token pullToken() {
|
|
||||||
return SerpentLexer.super.nextToken(); // must be to super.nextToken, or we'll recurse forever!
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Token nextToken() {
|
|
||||||
return denter.nextToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
parse: block EOF
|
|
||||||
;
|
|
||||||
|
|
||||||
parse_init_code_block : 'init' ':' INDENT block DEDENT 'code' ':' INDENT block DEDENT;
|
|
||||||
|
|
||||||
block: ( asm | array_assign | assign | contract_storage_assign | special_func | if_elif_else_stmt |
|
|
||||||
while_stmt | ret_func_1 | ret_func_2 | suicide_func | stop_func | single_send_func | msg_func |
|
|
||||||
single_create_func)* ;
|
|
||||||
|
|
||||||
|
|
||||||
asm: '[asm' asm_symbol 'asm]' NL;
|
|
||||||
asm_symbol: (ASM_SYMBOLS | INT | HEX_NUMBER)* ;
|
|
||||||
|
|
||||||
if_elif_else_stmt: 'if' condition ':' INDENT block DEDENT
|
|
||||||
('elif' condition ':' INDENT block DEDENT)*
|
|
||||||
('else:' INDENT block DEDENT)?
|
|
||||||
;
|
|
||||||
|
|
||||||
while_stmt: 'while' condition ':' INDENT block DEDENT;
|
|
||||||
|
|
||||||
|
|
||||||
/* special functions */
|
|
||||||
|
|
||||||
special_func :
|
|
||||||
msg_datasize |
|
|
||||||
msg_sender |
|
|
||||||
msg_value |
|
|
||||||
tx_gasprice |
|
|
||||||
tx_origin |
|
|
||||||
tx_gas |
|
|
||||||
contract_balance |
|
|
||||||
contract_address |
|
|
||||||
block_prevhash |
|
|
||||||
block_coinbase |
|
|
||||||
block_timestamp |
|
|
||||||
block_number |
|
|
||||||
block_difficulty |
|
|
||||||
block_gaslimit
|
|
||||||
;
|
|
||||||
|
|
||||||
msg_datasize
|
|
||||||
: 'msg.datasize' ;
|
|
||||||
|
|
||||||
msg_sender
|
|
||||||
: 'msg.sender' ;
|
|
||||||
|
|
||||||
msg_value
|
|
||||||
: 'msg.value' ;
|
|
||||||
|
|
||||||
tx_gasprice
|
|
||||||
: 'tx.gasprice' ;
|
|
||||||
|
|
||||||
tx_origin
|
|
||||||
: 'tx.origin' ;
|
|
||||||
|
|
||||||
tx_gas
|
|
||||||
: 'tx.gas' ;
|
|
||||||
|
|
||||||
contract_balance
|
|
||||||
: 'contract.balance' ;
|
|
||||||
|
|
||||||
contract_address
|
|
||||||
: 'contract.address' ;
|
|
||||||
|
|
||||||
block_prevhash
|
|
||||||
: 'block.prevhash' ;
|
|
||||||
|
|
||||||
block_coinbase
|
|
||||||
: 'block.coinbase' ;
|
|
||||||
|
|
||||||
block_timestamp
|
|
||||||
: 'block.timestamp' ;
|
|
||||||
|
|
||||||
block_number
|
|
||||||
: 'block.number' ;
|
|
||||||
|
|
||||||
block_difficulty
|
|
||||||
: 'block.difficulty' ;
|
|
||||||
|
|
||||||
block_gaslimit
|
|
||||||
: 'block.gaslimit' ;
|
|
||||||
|
|
||||||
msg_func: 'msg' '(' int_val ',' int_val ',' int_val ',' arr_def ',' int_val ',' int_val')' ;
|
|
||||||
|
|
||||||
send_func: 'send' '(' int_val ',' int_val ',' int_val ')';
|
|
||||||
single_send_func: send_func NL;
|
|
||||||
|
|
||||||
create_func: 'create' '(' int_val ',' int_val ',' int_val ')';
|
|
||||||
single_create_func: create_func NL;
|
|
||||||
|
|
||||||
msg_data: 'msg.data' '[' expression ']' ;
|
|
||||||
|
|
||||||
array_assign: VAR '[' int_val ']' EQ_OP expression NL;
|
|
||||||
array_retreive: VAR '[' int_val ']';
|
|
||||||
|
|
||||||
assign: VAR EQ_OP (expression | arr_def | msg_func) NL;
|
|
||||||
arr_def : '[' (int_val ','?)* ']';
|
|
||||||
|
|
||||||
|
|
||||||
contract_storage_assign: 'contract.storage' '[' expression ']' EQ_OP expression NL;
|
|
||||||
contract_storage_load: 'contract.storage' '[' expression ']';
|
|
||||||
|
|
||||||
|
|
||||||
mul_expr
|
|
||||||
: int_val
|
|
||||||
| mul_expr OP_MUL int_val
|
|
||||||
;
|
|
||||||
|
|
||||||
add_expr
|
|
||||||
: mul_expr
|
|
||||||
| add_expr OP_ADD mul_expr
|
|
||||||
;
|
|
||||||
|
|
||||||
rel_exp
|
|
||||||
: add_expr
|
|
||||||
| rel_exp OP_REL add_expr
|
|
||||||
;
|
|
||||||
|
|
||||||
eq_exp
|
|
||||||
: rel_exp
|
|
||||||
| eq_exp OP_EQ rel_exp
|
|
||||||
;
|
|
||||||
|
|
||||||
and_exp
|
|
||||||
: eq_exp
|
|
||||||
| and_exp OP_AND eq_exp
|
|
||||||
;
|
|
||||||
|
|
||||||
ex_or_exp
|
|
||||||
: and_exp
|
|
||||||
| ex_or_exp OP_EX_OR and_exp
|
|
||||||
;
|
|
||||||
|
|
||||||
in_or_exp
|
|
||||||
: ex_or_exp
|
|
||||||
| in_or_exp OP_IN_OR ex_or_exp
|
|
||||||
;
|
|
||||||
|
|
||||||
log_and_exp
|
|
||||||
: in_or_exp
|
|
||||||
| log_and_exp OP_LOG_AND in_or_exp
|
|
||||||
;
|
|
||||||
|
|
||||||
log_or_exp
|
|
||||||
: log_and_exp
|
|
||||||
| log_or_exp OP_LOG_OR log_and_exp
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
expression : log_or_exp ;
|
|
||||||
|
|
||||||
condition: expression ;
|
|
||||||
|
|
||||||
|
|
||||||
int_val : INT |
|
|
||||||
hex_num |
|
|
||||||
get_var |
|
|
||||||
special_func |
|
|
||||||
'(' expression ')' |
|
|
||||||
OP_NOT '(' expression ')' |
|
|
||||||
msg_data |
|
|
||||||
send_func |
|
|
||||||
contract_storage_load |
|
|
||||||
array_retreive
|
|
||||||
;
|
|
||||||
|
|
||||||
hex_num
|
|
||||||
: HEX_NUMBER
|
|
||||||
;
|
|
||||||
|
|
||||||
ret_func_1: 'return' '(' expression ')' NL;
|
|
||||||
ret_func_2: 'return' '(' expression ',' expression ')' NL;
|
|
||||||
suicide_func: 'suicide' '(' expression ')' NL;
|
|
||||||
stop_func: 'stop' NL;
|
|
||||||
|
|
||||||
get_var: VAR;
|
|
||||||
|
|
||||||
INT: [0-9]+;
|
|
||||||
|
|
||||||
|
|
||||||
ASM_SYMBOLS: 'STOP' | 'ADD' | 'MUL' | 'SUB' | 'DIV' | 'SDIV' | 'MOD' |'SMOD' | 'EXP' | 'NEG' | 'LT' | 'GT' | 'SLT' | 'SGT'| 'EQ' | 'NOT' | 'AND' | 'OR' | 'XOR' | 'BYTE' | 'SHA3' | 'ADDRESS' | 'BALANCE' | 'ORIGIN' | 'CALLER' | 'CALLVALUE' | 'CALLDATALOAD' | 'CALLDATASIZE' | 'CALLDATACOPY' | 'CODESIZE' | 'CODECOPY' | 'GASPRICE' | 'PREVHASH' | 'COINBASE' | 'TIMESTAMP' | 'NUMBER' | 'DIFFICULTY' | 'GASLIMIT' | 'POP' | 'DUP' | 'SWAP' | 'MLOAD' | 'MSTORE' | 'MSTORE8' | 'SLOAD' | 'SSTORE' | 'JUMP' | 'JUMPI' | 'PC' | 'MSIZE' | 'GAS' | 'PUSH1' | 'PUSH2' | 'PUSH3' | 'PUSH4' | 'PUSH5' | 'PUSH6' | 'PUSH7' | 'PUSH8' | 'PUSH9' | 'PUSH10' | 'PUSH11' | 'PUSH12' | 'PUSH13' | 'PUSH14' | 'PUSH15' | 'PUSH16' | 'PUSH17' | 'PUSH18' | 'PUSH19' | 'PUSH20' | 'PUSH21' | 'PUSH22' | 'PUSH23' | 'PUSH24' | 'PUSH25' | 'PUSH26' | 'PUSH27' | 'PUSH28' | 'PUSH29' | 'PUSH30' | 'PUSH31' | 'PUSH32' | 'CREATE' | 'CALL' | 'RETURN' | 'SUICIDE';
|
|
||||||
|
|
||||||
|
|
||||||
/* 'xor', 'and', 'or', 'not' operands should be defined
|
|
||||||
first among lexer rules because it
|
|
||||||
can be mismatched as a var lexa */
|
|
||||||
OP_EX_OR: 'xor';
|
|
||||||
OP_LOG_AND: '&&' | 'and';
|
|
||||||
OP_LOG_OR: '||' | 'or';
|
|
||||||
OP_NOT: '!' | 'not';
|
|
||||||
|
|
||||||
|
|
||||||
EQ_OP: '=' ;
|
|
||||||
|
|
||||||
NL: ('\r'? '\n' ' '*); // note the ' '*;
|
|
||||||
WS: [ \t]+ -> skip;
|
|
||||||
LINE_COMMENT: '//' ~[\r\n]* -> skip;
|
|
||||||
|
|
||||||
VAR: [a-zA-Z][a-zA-Z0-9]* ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
OP_ADD : '+' | '-';
|
|
||||||
OP_MUL : '*' | '/' | '^' | '%' | '#/' | '#%' ;
|
|
||||||
|
|
||||||
OP_REL : '<' | '>' | '<=' | '>=';
|
|
||||||
OP_EQ : '==' | '!=';
|
|
||||||
OP_AND: '&';
|
|
||||||
OP_IN_OR: '|';
|
|
||||||
|
|
||||||
|
|
||||||
HEX_DIGIT : [0-9a-fA-F];
|
|
||||||
HEX_NUMBER : ('0x' | '0X' )HEX_DIGIT+;
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
|||||||
OP_IN_OR=53
|
|
||||||
T__29=7
|
|
||||||
EQ_OP=43
|
|
||||||
T__28=8
|
|
||||||
T__27=9
|
|
||||||
OP_AND=52
|
|
||||||
T__26=10
|
|
||||||
T__25=11
|
|
||||||
T__24=12
|
|
||||||
T__23=13
|
|
||||||
T__22=14
|
|
||||||
T__21=15
|
|
||||||
T__20=16
|
|
||||||
OP_MUL=49
|
|
||||||
DEDENT=57
|
|
||||||
T__9=27
|
|
||||||
T__8=28
|
|
||||||
T__7=29
|
|
||||||
INDENT=56
|
|
||||||
T__6=30
|
|
||||||
T__5=31
|
|
||||||
T__4=32
|
|
||||||
T__19=17
|
|
||||||
OP_EQ=51
|
|
||||||
T__16=20
|
|
||||||
T__15=21
|
|
||||||
T__18=18
|
|
||||||
T__17=19
|
|
||||||
T__12=24
|
|
||||||
T__11=25
|
|
||||||
T__14=22
|
|
||||||
T__13=23
|
|
||||||
T__10=26
|
|
||||||
OP_EX_OR=39
|
|
||||||
OP_NOT=42
|
|
||||||
VAR=47
|
|
||||||
NL=44
|
|
||||||
LINE_COMMENT=46
|
|
||||||
OP_LOG_OR=41
|
|
||||||
OP_ADD=48
|
|
||||||
HEX_DIGIT=54
|
|
||||||
INT=37
|
|
||||||
T__30=6
|
|
||||||
T__31=5
|
|
||||||
T__32=4
|
|
||||||
T__33=3
|
|
||||||
WS=45
|
|
||||||
T__34=2
|
|
||||||
T__35=1
|
|
||||||
T__1=35
|
|
||||||
T__0=36
|
|
||||||
T__3=33
|
|
||||||
T__2=34
|
|
||||||
ASM_SYMBOLS=38
|
|
||||||
HEX_NUMBER=55
|
|
||||||
OP_REL=50
|
|
||||||
OP_LOG_AND=40
|
|
||||||
'|'=53
|
|
||||||
'code'=36
|
|
||||||
'block.number'=35
|
|
||||||
'block.gaslimit'=34
|
|
||||||
'asm]'=33
|
|
||||||
'contract.balance'=32
|
|
||||||
'msg.sender'=31
|
|
||||||
'='=43
|
|
||||||
'return'=30
|
|
||||||
'elif'=29
|
|
||||||
'create'=28
|
|
||||||
'msg.data'=27
|
|
||||||
'tx.origin'=26
|
|
||||||
'else:'=25
|
|
||||||
'tx.gasprice'=24
|
|
||||||
')'=23
|
|
||||||
'xor'=39
|
|
||||||
'msg.datasize'=22
|
|
||||||
'block.difficulty'=21
|
|
||||||
'suicide'=20
|
|
||||||
'block.prevhash'=18
|
|
||||||
'contract.storage'=19
|
|
||||||
'init'=17
|
|
||||||
'msg.value'=16
|
|
||||||
'[asm'=15
|
|
||||||
'contract.address'=14
|
|
||||||
'block.timestamp'=13
|
|
||||||
'send'=12
|
|
||||||
'if'=11
|
|
||||||
'('=10
|
|
||||||
':'=9
|
|
||||||
'['=8
|
|
||||||
'while'=7
|
|
||||||
'tx.gas'=6
|
|
||||||
'msg'=5
|
|
||||||
','=4
|
|
||||||
'block.coinbase'=3
|
|
||||||
'&'=52
|
|
||||||
'stop'=2
|
|
||||||
']'=1
|
|
@ -1,95 +0,0 @@
|
|||||||
OP_IN_OR=53
|
|
||||||
T__29=7
|
|
||||||
EQ_OP=43
|
|
||||||
T__28=8
|
|
||||||
T__27=9
|
|
||||||
OP_AND=52
|
|
||||||
T__26=10
|
|
||||||
T__25=11
|
|
||||||
T__24=12
|
|
||||||
T__23=13
|
|
||||||
T__22=14
|
|
||||||
T__21=15
|
|
||||||
T__20=16
|
|
||||||
OP_MUL=49
|
|
||||||
T__9=27
|
|
||||||
T__8=28
|
|
||||||
T__7=29
|
|
||||||
T__6=30
|
|
||||||
T__5=31
|
|
||||||
T__4=32
|
|
||||||
T__19=17
|
|
||||||
OP_EQ=51
|
|
||||||
T__16=20
|
|
||||||
T__15=21
|
|
||||||
T__18=18
|
|
||||||
T__17=19
|
|
||||||
T__12=24
|
|
||||||
T__11=25
|
|
||||||
T__14=22
|
|
||||||
T__13=23
|
|
||||||
T__10=26
|
|
||||||
OP_EX_OR=39
|
|
||||||
OP_NOT=42
|
|
||||||
VAR=47
|
|
||||||
NL=44
|
|
||||||
LINE_COMMENT=46
|
|
||||||
OP_LOG_OR=41
|
|
||||||
OP_ADD=48
|
|
||||||
HEX_DIGIT=54
|
|
||||||
INT=37
|
|
||||||
T__30=6
|
|
||||||
T__31=5
|
|
||||||
T__32=4
|
|
||||||
T__33=3
|
|
||||||
WS=45
|
|
||||||
T__34=2
|
|
||||||
T__35=1
|
|
||||||
T__1=35
|
|
||||||
T__0=36
|
|
||||||
T__3=33
|
|
||||||
T__2=34
|
|
||||||
ASM_SYMBOLS=38
|
|
||||||
HEX_NUMBER=55
|
|
||||||
OP_REL=50
|
|
||||||
OP_LOG_AND=40
|
|
||||||
'|'=53
|
|
||||||
'code'=36
|
|
||||||
'block.number'=35
|
|
||||||
'block.gaslimit'=34
|
|
||||||
'asm]'=33
|
|
||||||
'contract.balance'=32
|
|
||||||
'msg.sender'=31
|
|
||||||
'='=43
|
|
||||||
'return'=30
|
|
||||||
'elif'=29
|
|
||||||
'create'=28
|
|
||||||
'msg.data'=27
|
|
||||||
'tx.origin'=26
|
|
||||||
'else:'=25
|
|
||||||
'tx.gasprice'=24
|
|
||||||
')'=23
|
|
||||||
'xor'=39
|
|
||||||
'msg.datasize'=22
|
|
||||||
'block.difficulty'=21
|
|
||||||
'suicide'=20
|
|
||||||
'block.prevhash'=18
|
|
||||||
'contract.storage'=19
|
|
||||||
'init'=17
|
|
||||||
'msg.value'=16
|
|
||||||
'[asm'=15
|
|
||||||
'contract.address'=14
|
|
||||||
'block.timestamp'=13
|
|
||||||
'send'=12
|
|
||||||
'if'=11
|
|
||||||
'('=10
|
|
||||||
':'=9
|
|
||||||
'['=8
|
|
||||||
'while'=7
|
|
||||||
'tx.gas'=6
|
|
||||||
'msg'=5
|
|
||||||
','=4
|
|
||||||
'block.coinbase'=3
|
|
||||||
'&'=52
|
|
||||||
'stop'=2
|
|
||||||
']'=1
|
|
@ -297,6 +297,7 @@ public class BlockchainImpl implements Blockchain {
|
|||||||
if (needFlush(block)) {
|
if (needFlush(block)) {
|
||||||
repository.flush();
|
repository.flush();
|
||||||
blockStore.flush();
|
blockStore.flush();
|
||||||
|
System.gc();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all wallet transactions as they already approved by the net
|
// Remove all wallet transactions as they already approved by the net
|
||||||
|
@ -257,8 +257,12 @@ public class TransactionExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.getException() != null)
|
if (result.getException() != null){
|
||||||
|
result.getDeleteAccounts().clear();
|
||||||
|
result.getLogInfoList().clear();
|
||||||
|
result.futureRefundGas(0);
|
||||||
throw result.getException();
|
throw result.getException();
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|
||||||
|
@ -1,24 +1,19 @@
|
|||||||
package org.ethereum.datasource;
|
package org.ethereum.datasource;
|
||||||
|
|
||||||
import org.ethereum.config.SystemProperties;
|
import org.ethereum.config.SystemProperties;
|
||||||
|
import org.iq80.leveldb.*;
|
||||||
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.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
import static org.fusesource.leveldbjni.JniDBFactory.factory;
|
||||||
|
|
||||||
|
//import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Roman Mandeleil
|
* @author Roman Mandeleil
|
||||||
@ -55,6 +50,7 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
|||||||
File dbLocation = new File(System.getProperty("user.dir") + "/" +
|
File dbLocation = new File(System.getProperty("user.dir") + "/" +
|
||||||
SystemProperties.CONFIG.databaseDir() + "/");
|
SystemProperties.CONFIG.databaseDir() + "/");
|
||||||
File fileLocation = new File(dbLocation, name);
|
File fileLocation = new File(dbLocation, name);
|
||||||
|
if (!dbLocation.exists()) dbLocation.mkdirs();
|
||||||
|
|
||||||
if (SystemProperties.CONFIG.databaseReset()) {
|
if (SystemProperties.CONFIG.databaseReset()) {
|
||||||
destroyDB(fileLocation);
|
destroyDB(fileLocation);
|
||||||
@ -104,27 +100,34 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<byte[]> keys() {
|
public Set<byte[]> keys() {
|
||||||
|
try {
|
||||||
DBIterator dbIterator = db.iterator();
|
try (DBIterator dbIterator = db.iterator()) {
|
||||||
Set<byte[]> keys = new HashSet<>();
|
Set<byte[]> keys = new HashSet<>();
|
||||||
while (dbIterator.hasNext()) {
|
while (dbIterator.hasNext()) {
|
||||||
|
keys.add(dbIterator.next().getKey());
|
||||||
Map.Entry<byte[], byte[]> entry = dbIterator.next();
|
|
||||||
keys.add(entry.getKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBatch(Map<byte[], byte[]> rows) {
|
public void updateBatch(Map<byte[], byte[]> rows) {
|
||||||
|
try {
|
||||||
WriteBatch batch = db.createWriteBatch();
|
try (WriteBatch batch = db.createWriteBatch()) {
|
||||||
|
for (Map.Entry<byte[], byte[]> row : rows.entrySet()) {
|
||||||
for (Map.Entry<byte[], byte[]> row : rows.entrySet())
|
|
||||||
batch.put(row.getKey(), row.getValue());
|
batch.put(row.getKey(), row.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
db.write(batch);
|
db.write(batch);
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
@ -2,25 +2,22 @@ package org.ethereum.datasource.mapdb;
|
|||||||
|
|
||||||
import org.ethereum.config.SystemProperties;
|
import org.ethereum.config.SystemProperties;
|
||||||
import org.ethereum.datasource.KeyValueDataSource;
|
import org.ethereum.datasource.KeyValueDataSource;
|
||||||
import org.ethereum.db.ByteArrayWrapper;
|
|
||||||
import org.mapdb.DB;
|
import org.mapdb.DB;
|
||||||
import org.mapdb.DBMaker;
|
import org.mapdb.DBMaker;
|
||||||
import org.mapdb.HTreeMap;
|
import org.mapdb.Serializer;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static java.lang.System.getProperty;
|
import static java.lang.System.getProperty;
|
||||||
import static org.ethereum.util.ByteUtil.wrap;
|
|
||||||
|
|
||||||
public class MapDBDataSource implements KeyValueDataSource {
|
public class MapDBDataSource implements KeyValueDataSource {
|
||||||
|
|
||||||
private static final int BATCH_SIZE = 1024 * 1000 * 10;
|
private static final int BATCH_SIZE = 1024 * 1000 * 10;
|
||||||
|
|
||||||
private DB db;
|
private DB db;
|
||||||
private HTreeMap<ByteArrayWrapper, byte[]> map;
|
private Map<byte[], byte[]> map;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -30,16 +27,16 @@ public class MapDBDataSource implements KeyValueDataSource {
|
|||||||
dbLocation.mkdirs();
|
dbLocation.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
db = DBMaker.newFileDB(new File(dbLocation, name))
|
|
||||||
.asyncWriteEnable()
|
db = DBMaker.fileDB(new File(dbLocation, name))
|
||||||
.mmapFileEnableIfSupported()
|
.transactionDisable()
|
||||||
// .compressionEnable()
|
|
||||||
.cacheDisable()
|
|
||||||
// .asyncWriteFlushDelay(1000)
|
|
||||||
.closeOnJvmShutdown()
|
.closeOnJvmShutdown()
|
||||||
.make();
|
.make();
|
||||||
|
|
||||||
this.map = db.createHashMap(name).makeOrGet();
|
this.map = db.hashMapCreate(name)
|
||||||
|
.keySerializer(Serializer.BYTE_ARRAY)
|
||||||
|
.valueSerializer(Serializer.BYTE_ARRAY)
|
||||||
|
.makeOrGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -49,13 +46,13 @@ public class MapDBDataSource implements KeyValueDataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] get(byte[] key) {
|
public byte[] get(byte[] key) {
|
||||||
return map.get(wrap(key));
|
return map.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] put(byte[] key, byte[] value) {
|
public byte[] put(byte[] key, byte[] value) {
|
||||||
try {
|
try {
|
||||||
return map.put(wrap(key), value);
|
return map.put(key, value);
|
||||||
} finally {
|
} finally {
|
||||||
db.commit();
|
db.commit();
|
||||||
}
|
}
|
||||||
@ -72,11 +69,7 @@ public class MapDBDataSource implements KeyValueDataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<byte[]> keys() {
|
public Set<byte[]> keys() {
|
||||||
HashSet<byte[]> result = new HashSet<>();
|
return map.keySet();
|
||||||
for (ByteArrayWrapper key : map.keySet()) {
|
|
||||||
result.add(key.getData());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,7 +80,7 @@ public class MapDBDataSource implements KeyValueDataSource {
|
|||||||
byte[] value = rows.get(key);
|
byte[] value = rows.get(key);
|
||||||
savedSize += value.length;
|
savedSize += value.length;
|
||||||
|
|
||||||
map.put(wrap(key), value);
|
map.put(key, value);
|
||||||
if (savedSize > BATCH_SIZE) {
|
if (savedSize > BATCH_SIZE) {
|
||||||
db.commit();
|
db.commit();
|
||||||
savedSize = 0;
|
savedSize = 0;
|
||||||
|
@ -28,6 +28,8 @@ public interface Database {
|
|||||||
*/
|
*/
|
||||||
public void delete(byte[] key);
|
public void delete(byte[] key);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the database connection
|
* Close the database connection
|
||||||
*/
|
*/
|
||||||
|
@ -64,6 +64,11 @@ public class DatabaseImpl implements Database {
|
|||||||
return this.keyValueDataSource;
|
return this.keyValueDataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(){
|
||||||
|
keyValueDataSource.init();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -11,7 +13,6 @@ import java.util.Set;
|
|||||||
|
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
import static org.ethereum.util.ByteUtil.wrap;
|
import static org.ethereum.util.ByteUtil.wrap;
|
||||||
import static org.spongycastle.util.encoders.Hex.decode;
|
|
||||||
|
|
||||||
public class DetailsDataStore {
|
public class DetailsDataStore {
|
||||||
|
|
||||||
@ -64,15 +65,10 @@ public class DetailsDataStore {
|
|||||||
public void flush() {
|
public void flush() {
|
||||||
long keys = cache.size();
|
long keys = cache.size();
|
||||||
|
|
||||||
ByteArrayWrapper largeDetailsKey = wrap(decode("b61662398570293e4f0d25525e2b3002b7fe0836"));
|
|
||||||
ContractDetails largeDetails = cache.get(largeDetailsKey);
|
|
||||||
|
|
||||||
long start = System.nanoTime();
|
long start = System.nanoTime();
|
||||||
long totalSize = flushInternal();
|
long totalSize = flushInternal();
|
||||||
long finish = System.nanoTime();
|
long finish = System.nanoTime();
|
||||||
|
|
||||||
if (largeDetails != null) cache.put(largeDetailsKey, largeDetails);
|
|
||||||
|
|
||||||
float flushSize = (float) totalSize / 1_048_576;
|
float flushSize = (float) totalSize / 1_048_576;
|
||||||
float flushTime = (float) (finish - start) / 1_000_000;
|
float flushTime = (float) (finish - start) / 1_000_000;
|
||||||
gLogger.info(format("Flush details in: %02.2f ms, %d keys, %02.2fMB", flushTime, keys, flushSize));
|
gLogger.info(format("Flush details in: %02.2f ms, %d keys, %02.2fMB", flushTime, keys, flushSize));
|
||||||
@ -110,4 +106,14 @@ public class DetailsDataStore {
|
|||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void temporarySave(String addr, byte[] data){
|
||||||
|
try {
|
||||||
|
FileOutputStream fos = new FileOutputStream(addr);
|
||||||
|
fos.write(data);
|
||||||
|
fos.close();
|
||||||
|
System.out.println("drafted: " + addr);
|
||||||
|
} catch (IOException e) {e.printStackTrace();}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,4 +79,9 @@ public class TrackDatabase implements Database {
|
|||||||
public void close() {
|
public void close() {
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,8 +124,8 @@ public class EthereumModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
ShhHandler provideShhHandler(EthereumListener listener) {
|
ShhHandler provideShhHandler(WorldManager worldManager) {
|
||||||
return new ShhHandler(listener);
|
return new ShhHandler(worldManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -62,12 +62,13 @@ public class BlockLoader {
|
|||||||
if (block.getNumber() % 10000 == 0)
|
if (block.getNumber() % 10000 == 0)
|
||||||
System.out.println("Skipping block #" + block.getNumber());
|
System.out.println("Skipping block #" + block.getNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.println(" * Done * ");
|
||||||
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -148,8 +148,6 @@ public class EthHandler extends SimpleChannelInboundHandler<EthMessage> {
|
|||||||
case NEW_BLOCK:
|
case NEW_BLOCK:
|
||||||
msgQueue.receivedMessage(msg);
|
msgQueue.receivedMessage(msg);
|
||||||
processNewBlock((NewBlockMessage) msg);
|
processNewBlock((NewBlockMessage) msg);
|
||||||
case PACKET_COUNT:
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -74,12 +74,8 @@ public enum EthMessageCodes {
|
|||||||
* in the list (following the message ID) is a block in the format described
|
* in the list (following the message ID) is a block in the format described
|
||||||
* in the main Ethereum specification.
|
* in the main Ethereum specification.
|
||||||
*/
|
*/
|
||||||
NEW_BLOCK(0x07),
|
NEW_BLOCK(0x07);
|
||||||
|
|
||||||
/**
|
|
||||||
* [+0x08
|
|
||||||
*/
|
|
||||||
PACKET_COUNT(0X08);
|
|
||||||
|
|
||||||
static byte OFFSET = 0;
|
static byte OFFSET = 0;
|
||||||
private int cmd;
|
private int cmd;
|
||||||
@ -101,7 +97,7 @@ public enum EthMessageCodes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean inRange(byte code) {
|
public static boolean inRange(byte code) {
|
||||||
return code >= STATUS.asByte() && code <= PACKET_COUNT.asByte();
|
return code >= STATUS.asByte() && code <= NEW_BLOCK.asByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setOffset(byte offset) {
|
public static void setOffset(byte offset) {
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
package org.ethereum.net.eth;
|
|
||||||
|
|
||||||
import org.ethereum.net.p2p.PongMessage;
|
|
||||||
import org.ethereum.util.RLP;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper around an Ethereum Ping message on the network
|
|
||||||
*/
|
|
||||||
public class PacketCountMessage extends EthMessage {
|
|
||||||
|
|
||||||
public PacketCountMessage() {
|
|
||||||
encode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PacketCountMessage(byte[] payload) {
|
|
||||||
this.encoded = payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public byte[] getEncoded() {
|
|
||||||
return this.encoded;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void encode() {
|
|
||||||
this.encoded = RLP.encodeList(new byte[]{EthMessageCodes.STATUS.asByte()});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<PongMessage> getAnswerMessage() {
|
|
||||||
return PongMessage.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EthMessageCodes getCommand() {
|
|
||||||
return EthMessageCodes.PACKET_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "[" + getCommand().name() + "]";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +1,12 @@
|
|||||||
package org.ethereum.net.message;
|
package org.ethereum.net.message;
|
||||||
|
|
||||||
import org.ethereum.net.eth.BlockHashesMessage;
|
import org.ethereum.net.eth.*;
|
||||||
import org.ethereum.net.eth.BlocksMessage;
|
|
||||||
import org.ethereum.net.eth.EthMessageCodes;
|
|
||||||
import org.ethereum.net.eth.GetBlockHashesMessage;
|
|
||||||
import org.ethereum.net.eth.GetBlocksMessage;
|
|
||||||
import org.ethereum.net.eth.NewBlockMessage;
|
|
||||||
import org.ethereum.net.eth.PacketCountMessage;
|
|
||||||
import org.ethereum.net.eth.StatusMessage;
|
|
||||||
import org.ethereum.net.eth.TransactionsMessage;
|
|
||||||
import org.ethereum.net.p2p.DisconnectMessage;
|
import org.ethereum.net.p2p.DisconnectMessage;
|
||||||
import org.ethereum.net.p2p.HelloMessage;
|
import org.ethereum.net.p2p.HelloMessage;
|
||||||
import org.ethereum.net.p2p.P2pMessageCodes;
|
import org.ethereum.net.p2p.P2pMessageCodes;
|
||||||
import org.ethereum.net.p2p.PeersMessage;
|
import org.ethereum.net.p2p.PeersMessage;
|
||||||
|
import org.ethereum.net.shh.Envelope;
|
||||||
import org.ethereum.net.shh.ShhMessageCodes;
|
import org.ethereum.net.shh.ShhMessageCodes;
|
||||||
import org.ethereum.util.RLP;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory to create protocol message objects based on the RLP encoded data
|
* Factory to create protocol message objects based on the RLP encoded data
|
||||||
@ -62,8 +54,6 @@ public class MessageFactory {
|
|||||||
return new BlocksMessage(encoded);
|
return new BlocksMessage(encoded);
|
||||||
case NEW_BLOCK:
|
case NEW_BLOCK:
|
||||||
return new NewBlockMessage(encoded);
|
return new NewBlockMessage(encoded);
|
||||||
case PACKET_COUNT:
|
|
||||||
return new PacketCountMessage(encoded);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,9 +62,9 @@ public class MessageFactory {
|
|||||||
ShhMessageCodes receivedCommand = ShhMessageCodes.fromByte(code);
|
ShhMessageCodes receivedCommand = ShhMessageCodes.fromByte(code);
|
||||||
switch (receivedCommand) {
|
switch (receivedCommand) {
|
||||||
case STATUS:
|
case STATUS:
|
||||||
break;
|
return new org.ethereum.net.shh.StatusMessage(encoded);
|
||||||
case MESSAGE:
|
case MESSAGE:
|
||||||
break;
|
return new Envelope(encoded);
|
||||||
case ADD_FILTER:
|
case ADD_FILTER:
|
||||||
break;
|
break;
|
||||||
case REMOVE_FILTER:
|
case REMOVE_FILTER:
|
||||||
|
@ -211,9 +211,9 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
|||||||
capability.getVersion() == ShhHandler.VERSION) {
|
capability.getVersion() == ShhHandler.VERSION) {
|
||||||
|
|
||||||
// Activate ShhHandler for this peer
|
// Activate ShhHandler for this peer
|
||||||
// ShhHandler shhHandler =
|
ShhHandler shhHandler = channel.getShhHandler();
|
||||||
// (ShhHandler) ctx.pipeline().get(Capability.SHH);
|
ctx.pipeline().addLast(Capability.SHH, shhHandler);
|
||||||
// shhHandler.activate();
|
shhHandler.activate();
|
||||||
}
|
}
|
||||||
capInCommon.add(capability);
|
capInCommon.add(capability);
|
||||||
}
|
}
|
||||||
@ -256,17 +256,17 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
|||||||
public void adaptMessageIds(List<Capability> capabilities) {
|
public void adaptMessageIds(List<Capability> capabilities) {
|
||||||
|
|
||||||
Collections.sort(capabilities);
|
Collections.sort(capabilities);
|
||||||
byte offset = (byte) (P2pMessageCodes.USER.asByte() + 1);
|
int offset = P2pMessageCodes.USER.asByte() + 1;
|
||||||
|
|
||||||
for (Capability capability : capabilities) {
|
for (Capability capability : capabilities) {
|
||||||
|
|
||||||
if (capability.getName().equals(Capability.ETH)) {
|
if (capability.getName().equals(Capability.ETH)) {
|
||||||
EthMessageCodes.setOffset(offset);
|
EthMessageCodes.setOffset((byte)offset);
|
||||||
offset += EthMessageCodes.values().length;
|
offset += EthMessageCodes.values().length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (capability.getName().equals(Capability.SHH)) {
|
if (capability.getName().equals(Capability.SHH)) {
|
||||||
ShhMessageCodes.setOffset(offset);
|
ShhMessageCodes.setOffset((byte)offset);
|
||||||
offset += ShhMessageCodes.values().length;
|
offset += ShhMessageCodes.values().length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,12 @@ import io.netty.buffer.Unpooled;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import io.netty.channel.socket.DatagramPacket;
|
import io.netty.channel.socket.DatagramPacket;
|
||||||
import org.antlr.v4.runtime.misc.Triple;
|
|
||||||
import org.ethereum.crypto.ECKey;
|
import org.ethereum.crypto.ECKey;
|
||||||
import org.ethereum.net.rlpx.*;
|
import org.ethereum.net.rlpx.*;
|
||||||
import org.ethereum.net.rlpx.discover.table.KademliaOptions;
|
import org.ethereum.net.rlpx.discover.table.KademliaOptions;
|
||||||
import org.ethereum.net.rlpx.discover.table.NodeTable;
|
import org.ethereum.net.rlpx.discover.table.NodeTable;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -7,22 +7,18 @@ import org.ethereum.util.RLPElement;
|
|||||||
import org.ethereum.util.RLPList;
|
import org.ethereum.util.RLPList;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.util.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import static org.ethereum.net.shh.ShhMessageCodes.MESSAGE;
|
import static org.ethereum.net.shh.ShhMessageCodes.MESSAGE;
|
||||||
import static org.ethereum.crypto.HashUtil.sha3;
|
import static org.ethereum.crypto.HashUtil.sha3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by kest on 6/12/15.
|
* @author by Konstantin Shabalin
|
||||||
*/
|
*/
|
||||||
public class Envelope extends ShhMessage {
|
public class Envelope extends ShhMessage {
|
||||||
|
|
||||||
private long expire;
|
private int expire;
|
||||||
private long ttl;
|
private int ttl;
|
||||||
|
|
||||||
private Topic[] topics;
|
private Topic[] topics;
|
||||||
private byte[] data;
|
private byte[] data;
|
||||||
@ -33,8 +29,8 @@ public class Envelope extends ShhMessage {
|
|||||||
super(encoded);
|
super(encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Envelope(long ttl, Topic[] topics, Message msg) {
|
public Envelope(int ttl, Topic[] topics, Message msg) {
|
||||||
this.expire = System.currentTimeMillis() + ttl;
|
this.expire = (int)(System.currentTimeMillis()/1000 + ttl);
|
||||||
this.ttl = ttl;
|
this.ttl = ttl;
|
||||||
this.topics = topics;
|
this.topics = topics;
|
||||||
this.data = msg.getBytes();
|
this.data = msg.getBytes();
|
||||||
@ -45,12 +41,14 @@ public class Envelope extends ShhMessage {
|
|||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
byte[] data = this.data;
|
|
||||||
|
|
||||||
long sent = this.expire - this.ttl;
|
byte[] data = this.data;
|
||||||
|
int sent = this.expire - this.ttl;
|
||||||
|
int flags = data[0] < 0 ? (data[0] & 0xFF) : data[0];
|
||||||
|
|
||||||
Message m = new Message(data[0], sent, this.ttl, hash());
|
Message m = new Message(data[0], sent, this.ttl, hash());
|
||||||
|
|
||||||
if ((m.getFlags() & Message.SIGNATURE_FLAG) == Message.SIGNATURE_FLAG) {
|
if ((flags & Message.SIGNATURE_FLAG) == Message.SIGNATURE_FLAG) {
|
||||||
if (data.length < Message.SIGNATURE_LENGTH) {
|
if (data.length < Message.SIGNATURE_LENGTH) {
|
||||||
throw new Error("Unable to open the envelope. First bit set but len(data) < len(signature)");
|
throw new Error("Unable to open the envelope. First bit set but len(data) < len(signature)");
|
||||||
}
|
}
|
||||||
@ -70,17 +68,21 @@ public class Envelope extends ShhMessage {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
m.decrypt(privKey);
|
if (!m.decrypt(privKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parse() {
|
private void parse() {
|
||||||
if (encoded == null) encode();
|
if (encoded == null) encode();
|
||||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
if (isEmpty()) return;
|
||||||
|
|
||||||
this.expire = ByteUtil.byteArrayToLong(paramsList.get(0).getRLPData());
|
RLPList paramsList = (RLPList)((RLPList) RLP.decode2(encoded).get(0)).get(0);
|
||||||
this.ttl = ByteUtil.byteArrayToLong(paramsList.get(1).getRLPData());
|
|
||||||
|
this.expire = ByteUtil.byteArrayToInt(paramsList.get(0).getRLPData());
|
||||||
|
this.ttl = ByteUtil.byteArrayToInt(paramsList.get(1).getRLPData());
|
||||||
|
|
||||||
List<Topic> topics = new ArrayList<>();
|
List<Topic> topics = new ArrayList<>();
|
||||||
RLPList topicsList = (RLPList) RLP.decode2(paramsList.get(2).getRLPData()).get(0);
|
RLPList topicsList = (RLPList) RLP.decode2(paramsList.get(2).getRLPData()).get(0);
|
||||||
@ -98,7 +100,7 @@ public class Envelope extends ShhMessage {
|
|||||||
|
|
||||||
private void encode() {
|
private void encode() {
|
||||||
byte[] expire = RLP.encode(this.expire);
|
byte[] expire = RLP.encode(this.expire);
|
||||||
byte[] ttl = RLP.encode(this.expire);
|
byte[] ttl = RLP.encode(this.ttl);
|
||||||
|
|
||||||
List<byte[]> topics = new Vector<>();
|
List<byte[]> topics = new Vector<>();
|
||||||
for (Topic t : this.topics) {
|
for (Topic t : this.topics) {
|
||||||
@ -110,39 +112,49 @@ public class Envelope extends ShhMessage {
|
|||||||
byte[] data = RLP.encodeElement(this.data);
|
byte[] data = RLP.encodeElement(this.data);
|
||||||
byte[] nonce = RLP.encodeInt(this.nonce);
|
byte[] nonce = RLP.encodeInt(this.nonce);
|
||||||
|
|
||||||
this.encoded = RLP.encodeList(expire, ttl, encodedTopics, data, nonce);
|
this.encoded = RLP.encodeList(RLP.encodeList(expire, ttl, encodedTopics, data, nonce));
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] encodeWithoutNonce() {
|
|
||||||
byte[] expire = RLP.encode(this.expire);
|
|
||||||
byte[] ttl = RLP.encode(this.expire);
|
|
||||||
|
|
||||||
List<byte[]> topics = new Vector<>();
|
|
||||||
for (Topic t : this.topics) {
|
|
||||||
topics.add(RLP.encodeElement(t.getBytes()));
|
|
||||||
}
|
|
||||||
byte[][] topicsArray = topics.toArray(new byte[topics.size()][]);
|
|
||||||
byte[] encodedTopics = RLP.encodeList(topicsArray);
|
|
||||||
|
|
||||||
byte[] data = RLP.encodeElement(this.data);
|
|
||||||
|
|
||||||
return RLP.encodeList(expire, ttl, encodedTopics, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: complete the nonce implementation
|
|
||||||
public void seal(long pow) {
|
public void seal(long pow) {
|
||||||
byte[] d = new byte[64];
|
byte[] d = new byte[64];
|
||||||
Arrays.fill(d, (byte) 0);
|
encode();
|
||||||
byte[] rlp = encodeWithoutNonce();
|
byte[] rlp = this.encoded;
|
||||||
|
int l = rlp.length < 32 ? rlp.length : 32;
|
||||||
|
System.arraycopy(rlp, 0, d, 0, l);
|
||||||
|
|
||||||
long then = System.currentTimeMillis() + pow;
|
long then = System.currentTimeMillis() + pow;
|
||||||
this.nonce = 0;
|
|
||||||
for (int bestBit = 0; System.currentTimeMillis() < then; ) {
|
|
||||||
for (int i = 0; i < 1024; ++i, ++bestBit) {
|
|
||||||
|
|
||||||
|
for (int bestBit = 0; System.currentTimeMillis() < then;) {
|
||||||
|
for (int i = 0, nonce = 0; i < 1024; ++i, ++nonce) {
|
||||||
|
byte[] nonceBytes = intToByteArray(nonce);
|
||||||
|
System.arraycopy(nonceBytes, 0, d, 60, nonceBytes.length);
|
||||||
|
int fbs = getFirstBitSet(sha3(d));
|
||||||
|
if (fbs > bestBit) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
bestBit = fbs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.encoded = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getFirstBitSet(byte[] bytes) {
|
||||||
|
BitSet b = BitSet.valueOf(bytes);
|
||||||
|
for (int i = 0; i < b.length(); i++) {
|
||||||
|
if (b.get(i)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] intToByteArray(int value) {
|
||||||
|
return new byte[] {
|
||||||
|
(byte)(value >>> 24),
|
||||||
|
(byte)(value >>> 16),
|
||||||
|
(byte)(value >>> 8),
|
||||||
|
(byte)value};
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] hash() {
|
private byte[] hash() {
|
||||||
if (encoded == null) encode();
|
if (encoded == null) encode();
|
||||||
@ -177,6 +189,22 @@ public class Envelope extends ShhMessage {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
if (encoded == null) encode();
|
||||||
|
return encoded.length < 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String topicsToString() {
|
||||||
|
StringBuilder topics = new StringBuilder();
|
||||||
|
topics.append("[");
|
||||||
|
for (Topic t : this.topics) {
|
||||||
|
topics.append(Hex.toHexString(t.getBytes()));
|
||||||
|
topics.append(", ");
|
||||||
|
}
|
||||||
|
topics.append("]");
|
||||||
|
return topics.toString();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShhMessageCodes getCommand() {
|
public ShhMessageCodes getCommand() {
|
||||||
return MESSAGE;
|
return MESSAGE;
|
||||||
@ -195,6 +223,17 @@ public class Envelope extends ShhMessage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.toString();
|
if (!parsed) parse();
|
||||||
|
if (isEmpty()) {
|
||||||
|
return "[" + this.getCommand().name() + " empty envelope]";
|
||||||
|
} else {
|
||||||
|
return "[" + this.getCommand().name() +
|
||||||
|
" expire=" + this.expire +
|
||||||
|
" ttl=" + this.ttl +
|
||||||
|
" topics=" + topicsToString() +
|
||||||
|
" data=" + Hex.toHexString(this.data) +
|
||||||
|
" nonce=" + Hex.toHexString(new byte[]{(byte) this.nonce}) +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package org.ethereum.net.shh;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Filter {
|
||||||
|
private byte[] to;
|
||||||
|
private byte[] from;
|
||||||
|
private TopicMatcher filterTopics;
|
||||||
|
|
||||||
|
public Filter(byte[] to, byte[] from, TopicMatcher filterTopics) {
|
||||||
|
this.to = to;
|
||||||
|
this.from = from;
|
||||||
|
this.filterTopics = filterTopics;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Filter(Message m, Topic[] topics) {
|
||||||
|
this.to = m.getTo();
|
||||||
|
this.from = m.getPubKey();
|
||||||
|
this.filterTopics = new TopicMatcher(topics);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTo(byte[] to) {
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrom(byte[] from) {
|
||||||
|
this.from = from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopicMatcher getFilterTopics() {
|
||||||
|
return filterTopics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilterTopics(TopicMatcher filterTopics) {
|
||||||
|
this.filterTopics = filterTopics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Topic> getTopics() {
|
||||||
|
return filterTopics.getTopics();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean match(Filter f) {
|
||||||
|
|
||||||
|
if (this.to != null) {
|
||||||
|
if (!Arrays.equals(this.to, f.getTo())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.from != null) {
|
||||||
|
if (!Arrays.equals(this.from, f.getFrom())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.filterTopics != null) {
|
||||||
|
Topic[] topics = new Topic[f.getTopics().size()];
|
||||||
|
f.getTopics().toArray(topics);
|
||||||
|
return this.filterTopics.matches(topics);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trigger() {
|
||||||
|
System.out.print("Trigger is called.");
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,9 @@ import org.ethereum.crypto.ECKey;
|
|||||||
import org.spongycastle.util.BigIntegers;
|
import org.spongycastle.util.BigIntegers;
|
||||||
|
|
||||||
import org.spongycastle.math.ec.ECPoint;
|
import org.spongycastle.math.ec.ECPoint;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
@ -14,20 +16,23 @@ import static org.ethereum.net.shh.ShhMessageCodes.MESSAGE;
|
|||||||
import static org.ethereum.util.ByteUtil.merge;
|
import static org.ethereum.util.ByteUtil.merge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by kest on 6/12/15.
|
* @author by Konstantin Shabalin
|
||||||
*/
|
*/
|
||||||
public class Message extends ShhMessage {
|
public class Message extends ShhMessage {
|
||||||
|
|
||||||
private byte flags;
|
private byte flags;
|
||||||
private byte[] signature;
|
private byte[] signature;
|
||||||
private byte[] payload;
|
private byte[] payload;
|
||||||
|
private byte[] to;
|
||||||
|
|
||||||
private long sent;
|
private int sent;
|
||||||
private long ttl;
|
private int ttl;
|
||||||
|
|
||||||
private byte[] envelopeHash;
|
private byte[] envelopeHash;
|
||||||
|
|
||||||
public static final byte SIGNATURE_FLAG = 127;
|
private boolean decrypted;
|
||||||
|
|
||||||
|
public static final int SIGNATURE_FLAG = 128;
|
||||||
public static final int SIGNATURE_LENGTH = 65;
|
public static final int SIGNATURE_LENGTH = 65;
|
||||||
|
|
||||||
// public Message(byte[] encoded) {
|
// public Message(byte[] encoded) {
|
||||||
@ -39,21 +44,24 @@ public class Message extends ShhMessage {
|
|||||||
Random r = new Random();
|
Random r = new Random();
|
||||||
byte[] randByte = new byte[1];
|
byte[] randByte = new byte[1];
|
||||||
r.nextBytes(randByte);
|
r.nextBytes(randByte);
|
||||||
flags = randByte[0];
|
int flags = r.nextInt(256);
|
||||||
if (flags < 0) {
|
// if (flags < 0) {
|
||||||
flags = (byte)(flags & 0xF);
|
// flags = (byte)(flags & 0xF);
|
||||||
}
|
// }
|
||||||
flags &= ~SIGNATURE_FLAG;
|
flags &= ~SIGNATURE_FLAG;
|
||||||
|
|
||||||
this.sent = System.currentTimeMillis();
|
this.sent = (int) (System.currentTimeMillis()/1000);
|
||||||
this.payload = payload;
|
this.payload = payload;
|
||||||
|
this.flags = (byte) flags;
|
||||||
|
this.decrypted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Message(byte flags, long sent, long ttl, byte[] envelopeHash) {
|
public Message(byte flags, int sent, int ttl, byte[] envelopeHash) {
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
this.sent = sent;
|
this.sent = sent;
|
||||||
this.ttl = ttl;
|
this.ttl = ttl;
|
||||||
this.envelopeHash = envelopeHash;
|
this.envelopeHash = envelopeHash;
|
||||||
|
this.decrypted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Envelope wrap(long pow, Options options) {
|
public Envelope wrap(long pow, Options options) {
|
||||||
@ -67,9 +75,18 @@ public class Message extends ShhMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Envelope e = new Envelope(options.getTtl(), options.getTopics(), this);
|
Envelope e = new Envelope(options.getTtl(), options.getTopics(), this);
|
||||||
|
e.seal(pow);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTo(byte[] to) {
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
public byte getFlags() {
|
public byte getFlags() {
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
@ -103,6 +120,7 @@ public class Message extends ShhMessage {
|
|||||||
ECKey key = ECKey.fromPublicOnly(toPublicKey);
|
ECKey key = ECKey.fromPublicOnly(toPublicKey);
|
||||||
ECPoint pubKeyPoint = key.getPubKeyPoint();
|
ECPoint pubKeyPoint = key.getPubKeyPoint();
|
||||||
payload = ECIESCoder.encrypt(pubKeyPoint, payload);
|
payload = ECIESCoder.encrypt(pubKeyPoint, payload);
|
||||||
|
this.decrypted = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -111,6 +129,8 @@ public class Message extends ShhMessage {
|
|||||||
public boolean decrypt(ECKey privateKey) {
|
public boolean decrypt(ECKey privateKey) {
|
||||||
try {
|
try {
|
||||||
payload = ECIESCoder.decrypt(privateKey.getPrivKey(), payload);
|
payload = ECIESCoder.decrypt(privateKey.getPrivKey(), payload);
|
||||||
|
this.decrypted = false;
|
||||||
|
setTo(privateKey.decompress().getPubKey());
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("The message payload isn't encrypted or something is wrong");
|
System.out.println("The message payload isn't encrypted or something is wrong");
|
||||||
@ -159,6 +179,14 @@ public class Message extends ShhMessage {
|
|||||||
return outKey;
|
return outKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getPubKey() {
|
||||||
|
ECKey key = recover();
|
||||||
|
if (key != null) {
|
||||||
|
return key.decompress().getPubKey();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] hash() {
|
private byte[] hash() {
|
||||||
return sha3(merge(new byte[]{flags}, payload));
|
return sha3(merge(new byte[]{flags}, payload));
|
||||||
}
|
}
|
||||||
@ -180,7 +208,20 @@ public class Message extends ShhMessage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.toString();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("[");
|
||||||
|
sb.append(" flags=" + Hex.toHexString(new byte[]{flags}));
|
||||||
|
if (signature != null) {
|
||||||
|
sb.append(" signature=" + Hex.toHexString(signature));
|
||||||
|
}
|
||||||
|
if (payload != null) {
|
||||||
|
sb.append(" payload=" + new String(this.payload, Charset.forName("UTF-8")));
|
||||||
|
}
|
||||||
|
if (getPubKey() != null) {
|
||||||
|
sb.append(" publicKey=" + Hex.toHexString(getPubKey()));
|
||||||
|
}
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,19 @@ package org.ethereum.net.shh;
|
|||||||
import org.ethereum.crypto.ECKey;
|
import org.ethereum.crypto.ECKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by kest on 6/13/15.
|
* @author by Konstantin Shabalin
|
||||||
*/
|
*/
|
||||||
public class Options {
|
public class Options {
|
||||||
|
|
||||||
|
public static int DEFAULT_TTL = 100;
|
||||||
|
public static int DEFAULT_POW = 50;
|
||||||
|
|
||||||
private ECKey privateKey;
|
private ECKey privateKey;
|
||||||
private byte[] toPublicKey;
|
private byte[] toPublicKey;
|
||||||
private Topic[] topics;
|
private Topic[] topics;
|
||||||
private long ttl;
|
private int ttl;
|
||||||
|
|
||||||
public Options(ECKey privateKey, byte[] toPublicKey, Topic[] topics, long ttl) {
|
public Options(ECKey privateKey, byte[] toPublicKey, Topic[] topics, int ttl) {
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
this.toPublicKey = toPublicKey;
|
this.toPublicKey = toPublicKey;
|
||||||
this.topics = topics;
|
this.topics = topics;
|
||||||
@ -42,11 +46,11 @@ public class Options {
|
|||||||
this.topics = topics;
|
this.topics = topics;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTtl() {
|
public int getTtl() {
|
||||||
return ttl;
|
return ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTtl(long ttl) {
|
public void setTtl(int ttl) {
|
||||||
this.ttl = ttl;
|
this.ttl = ttl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package org.ethereum.net.shh;
|
package org.ethereum.net.shh;
|
||||||
|
|
||||||
import org.ethereum.listener.EthereumListener;
|
import org.ethereum.crypto.ECKey;
|
||||||
|
import org.ethereum.facade.Blockchain;
|
||||||
|
import org.ethereum.manager.WorldManager;
|
||||||
import org.ethereum.net.MessageQueue;
|
import org.ethereum.net.MessageQueue;
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
|
||||||
|
import org.ethereum.net.eth.*;
|
||||||
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -18,25 +22,32 @@ import javax.inject.Inject;
|
|||||||
*/
|
*/
|
||||||
public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
||||||
|
|
||||||
public final static byte VERSION = 1;
|
public final static byte VERSION = 2;
|
||||||
private MessageQueue msgQueue = null;
|
private MessageQueue msgQueue = null;
|
||||||
|
private ECKey privKey;
|
||||||
|
|
||||||
|
private Whisper whisper;
|
||||||
|
|
||||||
private boolean active = false;
|
private boolean active = false;
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger("net");
|
private final static Logger logger = LoggerFactory.getLogger("net");
|
||||||
|
|
||||||
|
|
||||||
public EthereumListener listener;
|
WorldManager worldManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ShhHandler(EthereumListener listener) {
|
public ShhHandler(WorldManager worldManager) {
|
||||||
this.listener = listener;
|
this.worldManager = worldManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShhHandler(MessageQueue msgQueue) {
|
public ShhHandler(MessageQueue msgQueue) {
|
||||||
this.msgQueue = msgQueue;
|
this.msgQueue = msgQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPrivKey(ECKey privKey) {
|
||||||
|
this.privKey = privKey;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelRead0(final ChannelHandlerContext ctx, ShhMessage msg) throws InterruptedException {
|
public void channelRead0(final ChannelHandlerContext ctx, ShhMessage msg) throws InterruptedException {
|
||||||
|
|
||||||
@ -45,12 +56,14 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
|||||||
if (ShhMessageCodes.inRange(msg.getCommand().asByte()))
|
if (ShhMessageCodes.inRange(msg.getCommand().asByte()))
|
||||||
logger.info("ShhHandler invoke: [{}]", msg.getCommand());
|
logger.info("ShhHandler invoke: [{}]", msg.getCommand());
|
||||||
|
|
||||||
listener.trace(String.format("ShhHandler invoke: [%s]", msg.getCommand()));
|
worldManager.getListener().trace(String.format("ShhHandler invoke: [%s]", msg.getCommand()));
|
||||||
|
|
||||||
switch (msg.getCommand()) {
|
switch (msg.getCommand()) {
|
||||||
case STATUS:
|
case STATUS:
|
||||||
|
worldManager.getListener().trace("[Recv: " + msg + "]");
|
||||||
break;
|
break;
|
||||||
case MESSAGE:
|
case MESSAGE:
|
||||||
|
whisper.processEnvelope((Envelope) msg);
|
||||||
break;
|
break;
|
||||||
case ADD_FILTER:
|
case ADD_FILTER:
|
||||||
break;
|
break;
|
||||||
@ -78,10 +91,25 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
|||||||
|
|
||||||
public void activate() {
|
public void activate() {
|
||||||
logger.info("SHH protocol activated");
|
logger.info("SHH protocol activated");
|
||||||
listener.trace("SHH protocol activated");
|
worldManager.getListener().trace("SHH protocol activated");
|
||||||
|
whisper = new Whisper(msgQueue);
|
||||||
|
sendStatus();
|
||||||
this.active = true;
|
this.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendStatus() {
|
||||||
|
byte protocolVersion = ShhHandler.VERSION;
|
||||||
|
StatusMessage msg = new StatusMessage(protocolVersion);
|
||||||
|
msgQueue.sendMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processEnvelop(Envelope envelope) {
|
||||||
|
if (!envelope.isEmpty()) {
|
||||||
|
Message m = envelope.open(privKey);
|
||||||
|
logger.info("ShhHandler invoke: [{}]", m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package org.ethereum.net.shh;
|
||||||
|
|
||||||
|
import org.ethereum.util.RLP;
|
||||||
|
import org.ethereum.util.RLPList;
|
||||||
|
|
||||||
|
import static org.ethereum.net.shh.ShhMessageCodes.STATUS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author by Konstantin Shabalin
|
||||||
|
*/
|
||||||
|
public class StatusMessage extends ShhMessage {
|
||||||
|
|
||||||
|
private byte protocolVersion;
|
||||||
|
|
||||||
|
public StatusMessage(byte[] encoded) {
|
||||||
|
super(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatusMessage(byte protocolVersion) {
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
|
this.parsed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encode() {
|
||||||
|
byte[] protocolVersion = RLP.encodeByte(this.protocolVersion);
|
||||||
|
this.encoded = RLP.encodeList(protocolVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parse() {
|
||||||
|
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||||
|
this.protocolVersion = paramsList.get(0).getRLPData()[0];
|
||||||
|
parsed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getEncoded() {
|
||||||
|
if (encoded == null) encode();
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getAnswerMessage() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShhMessageCodes getCommand() {
|
||||||
|
return STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (!parsed) parse();
|
||||||
|
return "[" + this.getCommand().name() +
|
||||||
|
" protocolVersion=" + this.protocolVersion + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
package org.ethereum.net.shh;
|
package org.ethereum.net.shh;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static org.ethereum.crypto.HashUtil.sha3;
|
import static org.ethereum.crypto.HashUtil.sha3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by kest on 6/12/15.
|
* @author by Konstantin Shabalin
|
||||||
*/
|
*/
|
||||||
public class Topic {
|
public class Topic {
|
||||||
|
|
||||||
@ -11,15 +13,37 @@ public class Topic {
|
|||||||
private byte[] topic = new byte[4];
|
private byte[] topic = new byte[4];
|
||||||
|
|
||||||
public Topic(byte[] data) {
|
public Topic(byte[] data) {
|
||||||
byte[] topic = sha3(data);
|
this.topic = data;
|
||||||
System.arraycopy(topic, 0, this.topic, 0, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Topic(String data) {
|
public Topic(String data) {
|
||||||
this(data.getBytes());
|
this.topic = buildTopic(data.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getBytes() {
|
public byte[] getBytes() {
|
||||||
return topic;
|
return topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] buildTopic(byte[] data) {
|
||||||
|
byte[] hash = sha3(data);
|
||||||
|
byte[] topic = new byte[4];
|
||||||
|
System.arraycopy(hash, 0, topic, 0, 4);
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Topic[] createTopics(String[] topicsString) {
|
||||||
|
Topic[] topics = new Topic[topicsString.length];
|
||||||
|
for (int i = 0; i < topicsString.length; i++) {
|
||||||
|
topics[i] = new Topic(topicsString[i]);
|
||||||
|
}
|
||||||
|
return topics;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) return false;
|
||||||
|
if (obj == this) return true;
|
||||||
|
if (!(obj instanceof Topic))return false;
|
||||||
|
return Arrays.equals(this.topic, ((Topic) obj).getBytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package org.ethereum.net.shh;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TopicMatcher {
|
||||||
|
private List<List<Topic>> conditions = new ArrayList<>();
|
||||||
|
|
||||||
|
public TopicMatcher(Topic[] inputTopics) {
|
||||||
|
for (Topic t : inputTopics) {
|
||||||
|
List<Topic> topics = new ArrayList<>();
|
||||||
|
topics.add(t);
|
||||||
|
conditions.add(topics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopicMatcher(String[] topicStrings) {
|
||||||
|
for (String s : topicStrings) {
|
||||||
|
List<Topic> topics = new ArrayList<>();
|
||||||
|
for (String t : s.split(" ")) {
|
||||||
|
topics.add(new Topic(t));
|
||||||
|
}
|
||||||
|
conditions.add(topics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(Topic[] topics) {
|
||||||
|
if (conditions.size() > topics.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < conditions.size() && i < topics.length; i++) {
|
||||||
|
if (conditions.get(i).size() > 0) {
|
||||||
|
if (!conditions.get(i).contains(topics[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Topic> getTopics() {
|
||||||
|
List<Topic> topics = new ArrayList<>();
|
||||||
|
for (List<Topic> topicsList : conditions) {
|
||||||
|
topics.addAll(topicsList);
|
||||||
|
}
|
||||||
|
return topics;
|
||||||
|
}
|
||||||
|
}
|
124
ethereumj-core/src/main/java/org/ethereum/net/shh/Whisper.java
Normal file
124
ethereumj-core/src/main/java/org/ethereum/net/shh/Whisper.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package org.ethereum.net.shh;
|
||||||
|
|
||||||
|
|
||||||
|
import org.ethereum.crypto.ECKey;
|
||||||
|
import org.ethereum.net.MessageQueue;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Whisper {
|
||||||
|
|
||||||
|
private MessageQueue msgQueue = null;
|
||||||
|
|
||||||
|
private Set<Filter> filters = new HashSet<>();
|
||||||
|
|
||||||
|
private Set<Message> messages = new HashSet<>();
|
||||||
|
private Set<Message> known = new HashSet<>();
|
||||||
|
|
||||||
|
private Map<String, ECKey> identities = new HashMap<>();
|
||||||
|
|
||||||
|
public Whisper(MessageQueue messageQueue) {
|
||||||
|
this.msgQueue = messageQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void post(String from, String to, String[] topics, String payload, int ttl, int pow) {
|
||||||
|
|
||||||
|
Topic[] topicList = Topic.createTopics(topics);
|
||||||
|
|
||||||
|
Message m = new Message(payload.getBytes());
|
||||||
|
|
||||||
|
ECKey key = null;
|
||||||
|
|
||||||
|
if (from != null && !from.isEmpty()) {
|
||||||
|
key = getIdentity(from);
|
||||||
|
if (key == null) {
|
||||||
|
throw new Error(String.format("Unknown identity to send from %s", from));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Options options = new Options(
|
||||||
|
key,
|
||||||
|
Hex.decode(to),
|
||||||
|
topicList,
|
||||||
|
ttl
|
||||||
|
);
|
||||||
|
|
||||||
|
Envelope e = m.wrap(pow, options);
|
||||||
|
|
||||||
|
addMessage(m, e.getTopics());
|
||||||
|
msgQueue.sendMessage(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processEnvelope(Envelope e) {
|
||||||
|
Message m = open(e);
|
||||||
|
if (m == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addMessage(m, e.getTopics());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message open(Envelope e) {
|
||||||
|
|
||||||
|
Message m;
|
||||||
|
|
||||||
|
for (ECKey key : identities.values()) {
|
||||||
|
m = e.open(key);
|
||||||
|
if (m != null) {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m = e.open(null);
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void watch(Filter f) {
|
||||||
|
filters.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unwatch(Filter f) {
|
||||||
|
filters.remove(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMessage(Message m, Topic[] topics) {
|
||||||
|
known.add(m);
|
||||||
|
matchMessage(m, topics);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Filter createFilter(byte[] to, byte[] from, Topic[] topics) {
|
||||||
|
TopicMatcher topicMatcher = new TopicMatcher(topics);
|
||||||
|
Filter f = new Filter(to, from, topicMatcher);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void matchMessage(Message m, Topic[] topics) {
|
||||||
|
Filter msgFilter = createFilter(m.getTo(), m.getPubKey(), topics);
|
||||||
|
for (Filter f : filters) {
|
||||||
|
if (f.match(msgFilter)) {
|
||||||
|
f.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ECKey newIdentity() {
|
||||||
|
ECKey key = new ECKey().decompress();
|
||||||
|
identities.put(Hex.toHexString(key.getPubKey()), key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ECKey getIdentity(String keyHexString) {
|
||||||
|
if (identities.containsKey(keyHexString)) {
|
||||||
|
return identities.get(keyHexString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Message> getAllKnownMessages() {
|
||||||
|
List<Message> messageList = new ArrayList<>();
|
||||||
|
messageList.addAll(known);
|
||||||
|
return messageList;
|
||||||
|
}
|
||||||
|
}
|
@ -123,6 +123,7 @@ public class MessageCodec extends ByteToMessageCodec<Message> {
|
|||||||
loggerNet.info("RLPX protocol activated");
|
loggerNet.info("RLPX protocol activated");
|
||||||
|
|
||||||
myKey = new ECKey().decompress();
|
myKey = new ECKey().decompress();
|
||||||
|
channel.getShhHandler().setPrivKey(myKey);
|
||||||
byte[] nodeIdWithFormat = myKey.getPubKey();
|
byte[] nodeIdWithFormat = myKey.getPubKey();
|
||||||
nodeId = new byte[nodeIdWithFormat.length - 1];
|
nodeId = new byte[nodeIdWithFormat.length - 1];
|
||||||
System.arraycopy(nodeIdWithFormat, 1, nodeId, 0, nodeId.length);
|
System.arraycopy(nodeIdWithFormat, 1, nodeId, 0, nodeId.length);
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
package org.ethereum.serpent;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.ANTLRInputStream;
|
|
||||||
import org.antlr.v4.runtime.BaseErrorListener;
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.antlr.v4.runtime.CommonTokenStream;
|
|
||||||
import org.antlr.v4.runtime.DiagnosticErrorListener;
|
|
||||||
import org.antlr.v4.runtime.Lexer;
|
|
||||||
import org.antlr.v4.runtime.Parser;
|
|
||||||
import org.antlr.v4.runtime.RecognitionException;
|
|
||||||
import org.antlr.v4.runtime.Recognizer;
|
|
||||||
import org.antlr.v4.runtime.TokenStream;
|
|
||||||
import org.antlr.v4.runtime.atn.PredictionMode;
|
|
||||||
import org.antlr.v4.runtime.misc.Nullable;
|
|
||||||
|
|
||||||
public class ParserUtils {
|
|
||||||
private ParserUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <L extends Lexer> L getLexer(Class<L> lexerClass, String source) {
|
|
||||||
CharStream input = new ANTLRInputStream(source);
|
|
||||||
L lexer;
|
|
||||||
try {
|
|
||||||
lexer = lexerClass.getConstructor(CharStream.class).newInstance(input);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalArgumentException("couldn't invoke lexer constructor", e);
|
|
||||||
}
|
|
||||||
lexer.addErrorListener(new AntlrFailureListener());
|
|
||||||
return lexer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <P extends Parser> P getParser(Class<? extends Lexer> lexerClass, Class<P> parserClass, String
|
|
||||||
source) {
|
|
||||||
Lexer lexer = getLexer(lexerClass, source);
|
|
||||||
TokenStream tokens = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
P parser;
|
|
||||||
try {
|
|
||||||
parser = parserClass.getConstructor(TokenStream.class).newInstance(tokens);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalArgumentException("couldn't invoke parser constructor", e);
|
|
||||||
}
|
|
||||||
parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
|
|
||||||
parser.removeErrorListeners(); // don't spit to stderr
|
|
||||||
parser.addErrorListener(new DiagnosticErrorListener());
|
|
||||||
parser.addErrorListener(new AntlrFailureListener());
|
|
||||||
|
|
||||||
return parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class AntlrFailureListener extends BaseErrorListener {
|
|
||||||
@Override
|
|
||||||
public void syntaxError(Recognizer<?, ?> recognizer, @Nullable Object offendingSymbol, int line,
|
|
||||||
int charPositionInLine, String msg, @Nullable RecognitionException e) {
|
|
||||||
throw new AntlrParseException(line, charPositionInLine, msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AntlrParseException extends RuntimeException {
|
|
||||||
public AntlrParseException(int line, int posInLine, String msg, Throwable cause) {
|
|
||||||
// posInLine comes in 0-indexed, but we want to 1-index it so it lines up with what editors say (they
|
|
||||||
// tend to 1-index)
|
|
||||||
super(String.format("at line %d column %d: %s", line, posInLine + 1, msg), cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,227 +0,0 @@
|
|||||||
package org.ethereum.serpent;
|
|
||||||
|
|
||||||
import org.ethereum.util.ByteUtil;
|
|
||||||
import org.ethereum.vm.OpCode;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
|
||||||
|
|
||||||
import org.spongycastle.util.Arrays;
|
|
||||||
import org.spongycastle.util.BigIntegers;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Roman Mandeleil
|
|
||||||
* @since 13.05.14
|
|
||||||
*/
|
|
||||||
public class SerpentCompiler {
|
|
||||||
|
|
||||||
public static String compile(String code) {
|
|
||||||
SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
|
|
||||||
code);
|
|
||||||
ParseTree tree = parser.parse();
|
|
||||||
|
|
||||||
String result = new SerpentToAssemblyCompiler().visit(tree);
|
|
||||||
result = result.replaceAll("\\s+", " ");
|
|
||||||
result = result.trim();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String compileFullNotion(String code) {
|
|
||||||
SerpentParser parser = ParserUtils.getParser(SerpentLexer.class,
|
|
||||||
SerpentParser.class, code);
|
|
||||||
ParseTree tree = parser.parse_init_code_block();
|
|
||||||
|
|
||||||
String result = new SerpentToAssemblyCompiler().visit(tree);
|
|
||||||
result = result.replaceAll("\\s+", " ");
|
|
||||||
result = result.trim();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] compileFullNotionAssemblyToMachine(String code) {
|
|
||||||
byte[] initCode = compileAssemblyToMachine(extractInitBlock(code));
|
|
||||||
byte[] codeCode = compileAssemblyToMachine(extractCodeBlock(code));
|
|
||||||
return encodeMachineCodeForVMRun(codeCode, initCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String extractInitBlock(String code) {
|
|
||||||
String result = "";
|
|
||||||
Pattern pattern = Pattern.compile("\\[init (.*?) init\\]");
|
|
||||||
Matcher matcher = pattern.matcher(code);
|
|
||||||
if (matcher.find()) {
|
|
||||||
result = matcher.group(1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String extractCodeBlock(String code) {
|
|
||||||
String result = "";
|
|
||||||
Pattern pattern = Pattern.compile("\\[code (.*?) code\\]");
|
|
||||||
Matcher matcher = pattern.matcher(code);
|
|
||||||
if (matcher.find()) {
|
|
||||||
result = matcher.group(1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] compileAssemblyToMachine(String code) {
|
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
String[] lexaArr = code.split("\\s+");
|
|
||||||
|
|
||||||
List<String> lexaList = new ArrayList<>();
|
|
||||||
Collections.addAll(lexaList, lexaArr);
|
|
||||||
|
|
||||||
// Encode push_n numbers
|
|
||||||
boolean skipping = false;
|
|
||||||
for (int i = 0; i < lexaList.size(); ++i) {
|
|
||||||
|
|
||||||
String lexa = lexaList.get(i);
|
|
||||||
|
|
||||||
{ // skipping the [asm asm] block
|
|
||||||
if (lexa.equals("asm]")) {
|
|
||||||
skipping = false;
|
|
||||||
lexaList.remove(i);
|
|
||||||
--i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (lexa.equals("[asm")) {
|
|
||||||
skipping = true;
|
|
||||||
lexaList.remove(i);
|
|
||||||
--i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (skipping)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OpCode.contains(lexa) ||
|
|
||||||
lexa.contains("REF_") ||
|
|
||||||
lexa.contains("LABEL_")) continue;
|
|
||||||
|
|
||||||
int bytesNum = ByteUtil.numBytes(lexa);
|
|
||||||
|
|
||||||
String num = lexaList.remove(i);
|
|
||||||
BigInteger bNum = new BigInteger(num);
|
|
||||||
byte[] bytes = BigIntegers.asUnsignedByteArray(bNum);
|
|
||||||
if (bytes.length == 0) bytes = new byte[]{0};
|
|
||||||
|
|
||||||
for (int j = bytes.length; j > 0; --j) {
|
|
||||||
lexaList.add(i, (bytes[j - 1] & 0xFF) + "");
|
|
||||||
}
|
|
||||||
lexaList.add(i, "PUSH" + bytesNum);
|
|
||||||
i = i + bytesNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode ref for 5 bytes
|
|
||||||
for (int i = 0; i < lexaList.size(); ++i) {
|
|
||||||
|
|
||||||
String lexa = lexaList.get(i);
|
|
||||||
if (!lexa.contains("REF_")) continue;
|
|
||||||
lexaList.add(i + 1, lexa);
|
|
||||||
lexaList.add(i + 2, lexa);
|
|
||||||
lexaList.add(i + 3, lexa);
|
|
||||||
lexaList.add(i + 4, lexa);
|
|
||||||
i += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calc label pos & remove labels
|
|
||||||
Map<String, Integer> labels = new HashMap<>();
|
|
||||||
|
|
||||||
for (int i = 0; i < lexaList.size(); ++i) {
|
|
||||||
|
|
||||||
String lexa = lexaList.get(i);
|
|
||||||
if (!lexa.contains("LABEL_")) continue;
|
|
||||||
|
|
||||||
String label = lexaList.remove(i);
|
|
||||||
String labelNum = label.split("LABEL_")[1];
|
|
||||||
|
|
||||||
int labelPos = i;
|
|
||||||
|
|
||||||
labels.put(labelNum, labelPos);
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode all ref occurrence
|
|
||||||
for (int i = 0; i < lexaList.size(); ++i) {
|
|
||||||
|
|
||||||
String lexa = lexaList.get(i);
|
|
||||||
if (!lexa.contains("REF_")) continue;
|
|
||||||
|
|
||||||
String ref = lexaList.remove(i);
|
|
||||||
lexaList.remove(i);
|
|
||||||
lexaList.remove(i);
|
|
||||||
lexaList.remove(i);
|
|
||||||
lexaList.remove(i);
|
|
||||||
String labelNum = ref.split("REF_")[1];
|
|
||||||
|
|
||||||
Integer pos = labels.get(labelNum);
|
|
||||||
int bytesNum = ByteUtil.numBytes(pos.toString());
|
|
||||||
|
|
||||||
lexaList.add(i, pos.toString());
|
|
||||||
|
|
||||||
for (int j = 0; j < (4 - bytesNum); ++j)
|
|
||||||
lexaList.add(i, "0");
|
|
||||||
|
|
||||||
lexaList.add(i, "PUSH4");
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String lexa : lexaList) {
|
|
||||||
|
|
||||||
if (OpCode.contains(lexa))
|
|
||||||
baos.write(OpCode.byteVal(lexa));
|
|
||||||
else {
|
|
||||||
// TODO: support for number more than one byte
|
|
||||||
baos.write(Integer.parseInt(lexa) & 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// wrap plan
|
|
||||||
// 1) that is the code
|
|
||||||
// 2) need to wrap it with PUSH1 (codesize) PUSH1 (codestart) 000 CODECOPY 000 PUSH1 (codesize) _fURN
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return encoded bytes.
|
|
||||||
*/
|
|
||||||
public static byte[] encodeMachineCodeForVMRun(byte[] code, byte[] init) {
|
|
||||||
|
|
||||||
if (code == null || code.length == 0) throw new RuntimeException("code can't be empty code: " + code);
|
|
||||||
|
|
||||||
int numBytes = ByteUtil.numBytes(code.length + "");
|
|
||||||
byte[] lenBytes = BigIntegers.asUnsignedByteArray(BigInteger.valueOf(code.length));
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (byte lenByte : lenBytes) {
|
|
||||||
sb.append(lenByte).append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// calc real code start position (after the init header)
|
|
||||||
int pos = 10 + numBytes * 2;
|
|
||||||
if (init != null) pos += init.length;
|
|
||||||
|
|
||||||
// @push_len @len PUSH1 @src_start PUSH1 0 CODECOPY @push_len @len 0 PUSH1 0 RETURN
|
|
||||||
String header = String.format("[asm %s %s PUSH1 %d PUSH1 0 CODECOPY %s %s PUSH1 0 RETURN asm]",
|
|
||||||
"PUSH" + numBytes, sb.toString(), pos, "PUSH" + numBytes, sb.toString());
|
|
||||||
|
|
||||||
byte[] headerMachine = compileAssemblyToMachine(header);
|
|
||||||
|
|
||||||
return init != null ? Arrays.concatenate(init, headerMachine, code) :
|
|
||||||
Arrays.concatenate(headerMachine, code);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,778 +0,0 @@
|
|||||||
package org.ethereum.serpent;
|
|
||||||
|
|
||||||
import org.ethereum.crypto.HashUtil;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.misc.NotNull;
|
|
||||||
|
|
||||||
import org.spongycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Roman Mandeleil
|
|
||||||
* @since 05.05.14
|
|
||||||
*/
|
|
||||||
public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
|
||||||
|
|
||||||
private int labelIndex = 0;
|
|
||||||
private List<String> vars = new ArrayList<>();
|
|
||||||
|
|
||||||
private Map<String, Integer> arraysSize = new HashMap<>();
|
|
||||||
private List<String> arraysIndex = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitParse(@NotNull SerpentParser.ParseContext ctx) {
|
|
||||||
|
|
||||||
String codeBlock = visit(ctx.block());
|
|
||||||
int memSize = vars.size() * 32 - (vars.size() > 0 ? 1 : 0);
|
|
||||||
|
|
||||||
String initMemCodeBlock = "";
|
|
||||||
if (!arraysSize.isEmpty() && vars.size() > 0)
|
|
||||||
initMemCodeBlock = String.format(" 0 %d MSTORE8 ", memSize);
|
|
||||||
|
|
||||||
if (memSize == 0)
|
|
||||||
codeBlock = codeBlock.replace("@vars_table@", "0");
|
|
||||||
else
|
|
||||||
codeBlock = codeBlock.replace("@vars_table@", memSize + 1 + "");
|
|
||||||
|
|
||||||
return initMemCodeBlock + codeBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitParse_init_code_block(@NotNull SerpentParser.Parse_init_code_blockContext ctx) {
|
|
||||||
|
|
||||||
String initBlock = visit(ctx.block(0));
|
|
||||||
int memSize = vars.size() * 32 - (vars.size() > 0 ? 1 : 0);
|
|
||||||
|
|
||||||
String initMemInitBlock = "";
|
|
||||||
if (!arraysSize.isEmpty() && vars.size() > 0)
|
|
||||||
initMemInitBlock = String.format(" 0 %d MSTORE8 ", memSize);
|
|
||||||
|
|
||||||
if (memSize == 0)
|
|
||||||
initBlock = initBlock.replace("@vars_table@", "0");
|
|
||||||
else
|
|
||||||
initBlock = initBlock.replace("@vars_table@", memSize + 1 + "");
|
|
||||||
|
|
||||||
vars.clear();
|
|
||||||
String codeBlock = visit(ctx.block(1));
|
|
||||||
memSize = vars.size() * 32 - (vars.size() > 0 ? 1 : 0);
|
|
||||||
|
|
||||||
if (memSize == 0)
|
|
||||||
codeBlock = codeBlock.replace("@vars_table@", "0");
|
|
||||||
else
|
|
||||||
codeBlock = codeBlock.replace("@vars_table@", memSize + 1 + "");
|
|
||||||
|
|
||||||
|
|
||||||
String initMemCodeBlock = "";
|
|
||||||
if (!arraysSize.isEmpty() && vars.size() > 0)
|
|
||||||
initMemCodeBlock = String.format(" 0 %d MSTORE8 ", memSize);
|
|
||||||
|
|
||||||
return String.format(" [init %s %s init] [code %s %s code] ", initMemInitBlock, initBlock,
|
|
||||||
initMemCodeBlock, codeBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitIf_elif_else_stmt(@NotNull SerpentParser.If_elif_else_stmtContext ctx) {
|
|
||||||
|
|
||||||
StringBuilder retCode = new StringBuilder();
|
|
||||||
|
|
||||||
int endOfStmtLabel = labelIndex++;
|
|
||||||
|
|
||||||
// if body
|
|
||||||
SerpentParser.BlockContext ifBlock = (SerpentParser.BlockContext) ctx.getChild(4);
|
|
||||||
String blockCode = visitBlock(ifBlock);
|
|
||||||
String ifCond = visitCondition(ctx.condition(0));
|
|
||||||
|
|
||||||
int nextLabel = labelIndex++;
|
|
||||||
|
|
||||||
// if_cond [NOT REF_X JUMPI] if_body [REF_Y JUMP LABEL_X] Y=total_end
|
|
||||||
retCode.append(ifCond).
|
|
||||||
append(" NOT REF_").append(nextLabel).append(" JUMPI ").
|
|
||||||
append(blockCode).
|
|
||||||
append("REF_").append(endOfStmtLabel).
|
|
||||||
append(" JUMP LABEL_").append(nextLabel).append(" ");
|
|
||||||
|
|
||||||
// traverse the children and find out all [elif] and [else] that exist
|
|
||||||
int count = ctx.condition().size();
|
|
||||||
|
|
||||||
// traverse all 'elif' statements
|
|
||||||
int i = 1; // define i here for 'else' option
|
|
||||||
for (; i < count; ++i) {
|
|
||||||
|
|
||||||
// if the condition much at the end jump out of the main if
|
|
||||||
// append to general retCode
|
|
||||||
// TODO: [NOT REF_X JUMPI] elif_body [REF_Y JUMP LABEL_X] Y=total_end
|
|
||||||
// TODO extract the condition and the body
|
|
||||||
nextLabel = labelIndex++;
|
|
||||||
|
|
||||||
// elif condition
|
|
||||||
String elifCond = visitCondition(ctx.condition(i));
|
|
||||||
|
|
||||||
// elif body
|
|
||||||
String elifBlockCode = visitBlock(ctx.block(i));
|
|
||||||
|
|
||||||
retCode.append(elifCond).
|
|
||||||
append(" NOT REF_").append(nextLabel).append(" JUMPI ").
|
|
||||||
append(elifBlockCode).
|
|
||||||
append("REF_").append(endOfStmtLabel).append(" JUMP LABEL_").
|
|
||||||
append(nextLabel).append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if there is 'else'
|
|
||||||
if (ctx.block(i) != null) {
|
|
||||||
|
|
||||||
// body
|
|
||||||
String elseBlockCode = visitBlock(ctx.block(i));
|
|
||||||
|
|
||||||
// append to general retCode
|
|
||||||
retCode.append(elseBlockCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// [LABEL_Y] Y = end of statement
|
|
||||||
retCode.append("LABEL_").append(endOfStmtLabel).append(" ");
|
|
||||||
|
|
||||||
return retCode.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitWhile_stmt(@NotNull SerpentParser.While_stmtContext ctx) {
|
|
||||||
|
|
||||||
int whileStartRef = labelIndex++;
|
|
||||||
int whileEndRef = labelIndex++;
|
|
||||||
|
|
||||||
// elif condition
|
|
||||||
SerpentParser.ConditionContext whileCondition = (SerpentParser.ConditionContext)
|
|
||||||
ctx.getChild(1);
|
|
||||||
|
|
||||||
// elif body
|
|
||||||
SerpentParser.BlockContext whileBlock = (SerpentParser.BlockContext)
|
|
||||||
ctx.getChild(4);
|
|
||||||
|
|
||||||
return String.format(" LABEL_%d %s NOT REF_%d JUMPI %s REF_%d JUMP LABEL_%d ",
|
|
||||||
whileStartRef, visitCondition(whileCondition), whileEndRef, visitBlock(whileBlock),
|
|
||||||
whileStartRef, whileEndRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitBlock(@NotNull SerpentParser.BlockContext ctx) {
|
|
||||||
|
|
||||||
return super.visitBlock(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitCondition(@NotNull SerpentParser.ConditionContext ctx) {
|
|
||||||
return super.visitCondition(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitGet_var(@NotNull SerpentParser.Get_varContext ctx) {
|
|
||||||
|
|
||||||
String varName = ctx.VAR().toString();
|
|
||||||
int addr;
|
|
||||||
|
|
||||||
addr = vars.indexOf(varName);
|
|
||||||
if (addr == -1) {
|
|
||||||
throw new UnassignVarException(varName);
|
|
||||||
}
|
|
||||||
return String.format(" %d MLOAD ", addr * 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitAssign(@NotNull SerpentParser.AssignContext ctx) {
|
|
||||||
|
|
||||||
String varName = ctx.VAR().toString();
|
|
||||||
|
|
||||||
// msg assigned has two arrays to calc
|
|
||||||
if (ctx.msg_func() != null) {
|
|
||||||
|
|
||||||
return visitMsg_func(ctx.msg_func(), varName);
|
|
||||||
} else if (ctx.arr_def() != null) {
|
|
||||||
// if it's an array the all management is different
|
|
||||||
String arrayCode = visitArr_def(ctx.arr_def());
|
|
||||||
|
|
||||||
// calc the pointer addr
|
|
||||||
int pos = getArraySize(arrayCode);
|
|
||||||
arraysSize.put(varName, pos);
|
|
||||||
arraysIndex.add(varName);
|
|
||||||
|
|
||||||
return arrayCode;
|
|
||||||
} else {
|
|
||||||
String expression = visitExpression(ctx.expression());
|
|
||||||
int addr = vars.indexOf(varName);
|
|
||||||
if (addr == -1) {
|
|
||||||
addr = vars.size();
|
|
||||||
vars.add(varName);
|
|
||||||
}
|
|
||||||
return String.format(" %s %d MSTORE ", expression, addr * 32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitContract_storage_load(@NotNull SerpentParser.Contract_storage_loadContext ctx) {
|
|
||||||
|
|
||||||
String operand0 = visitExpression(ctx.expression());
|
|
||||||
|
|
||||||
return String.format(" %s SLOAD ", operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitContract_storage_assign(@NotNull SerpentParser.Contract_storage_assignContext ctx) {
|
|
||||||
|
|
||||||
String operand0 = visitExpression(ctx.expression(0));
|
|
||||||
String operand1 = visitExpression(ctx.expression(1));
|
|
||||||
|
|
||||||
return String.format(" %s %s SSTORE ", operand1, operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitInt_val(@NotNull SerpentParser.Int_valContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.OP_NOT() != null)
|
|
||||||
return visitExpression(ctx.expression()) + " NOT";
|
|
||||||
|
|
||||||
if (ctx.expression() != null)
|
|
||||||
return visitExpression(ctx.expression());
|
|
||||||
|
|
||||||
if (ctx.get_var() != null)
|
|
||||||
return visitGet_var(ctx.get_var());
|
|
||||||
|
|
||||||
if (ctx.hex_num() != null)
|
|
||||||
return hexStringToDecimalString(ctx.hex_num().getText());
|
|
||||||
|
|
||||||
if (ctx.special_func() != null)
|
|
||||||
return visitSpecial_func(ctx.special_func());
|
|
||||||
|
|
||||||
if (ctx.msg_data() != null)
|
|
||||||
return visitMsg_data(ctx.msg_data());
|
|
||||||
|
|
||||||
if (ctx.contract_storage_load() != null)
|
|
||||||
return visitContract_storage_load(ctx.contract_storage_load());
|
|
||||||
|
|
||||||
if (ctx.send_func() != null)
|
|
||||||
return visitSend_func(ctx.send_func());
|
|
||||||
|
|
||||||
if (ctx.array_retreive() != null)
|
|
||||||
return visitArray_retreive(ctx.array_retreive());
|
|
||||||
|
|
||||||
return ctx.INT().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitArr_def(@NotNull SerpentParser.Arr_defContext ctx) {
|
|
||||||
|
|
||||||
List<SerpentParser.Int_valContext> numElements = ctx.int_val();
|
|
||||||
int arraySize = numElements.size() * 32 + 32;
|
|
||||||
|
|
||||||
StringBuffer arrayInit = new StringBuffer();
|
|
||||||
int i = 32;
|
|
||||||
for (SerpentParser.Int_valContext int_val : ctx.int_val()) {
|
|
||||||
|
|
||||||
arrayInit.append(String.format(" DUP %d ADD %s SWAP MSTORE ", i, visit(int_val)));
|
|
||||||
i += 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
return String.format(" MSIZE 32 ADD MSIZE %s %d SWAP MSTORE ", arrayInit, arraySize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitArray_assign(@NotNull SerpentParser.Array_assignContext ctx) {
|
|
||||||
|
|
||||||
int order = this.arraysIndex.indexOf(ctx.VAR().toString());
|
|
||||||
if (order == -1) {
|
|
||||||
throw new Error("array with that name was not defined");
|
|
||||||
}
|
|
||||||
|
|
||||||
//calcAllocatedBefore();
|
|
||||||
int allocSize = 0;
|
|
||||||
for (int i = 0; i < order; ++i) {
|
|
||||||
String var = arraysIndex.get(i);
|
|
||||||
allocSize += arraysSize.get(var);
|
|
||||||
}
|
|
||||||
|
|
||||||
String index = visit(ctx.int_val());
|
|
||||||
String assignValue = visit(ctx.expression());
|
|
||||||
|
|
||||||
return String.format(" %s 32 %s MUL 32 ADD %d ADD @vars_table@ ADD MSTORE ", assignValue, index, allocSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitArray_retreive(@NotNull SerpentParser.Array_retreiveContext ctx) {
|
|
||||||
|
|
||||||
int order = this.arraysIndex.indexOf(ctx.VAR().toString());
|
|
||||||
if (order == -1) {
|
|
||||||
throw new Error("array with that name was not defined");
|
|
||||||
}
|
|
||||||
|
|
||||||
int allocSize = 32;
|
|
||||||
for (int i = 0; i < order; ++i) {
|
|
||||||
String var = arraysIndex.get(i);
|
|
||||||
allocSize += arraysSize.get(var);
|
|
||||||
}
|
|
||||||
|
|
||||||
String index = visit(ctx.int_val());
|
|
||||||
|
|
||||||
return String.format(" 32 %s MUL %d ADD @vars_table@ ADD MLOAD ", index, allocSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitMul_expr(@NotNull SerpentParser.Mul_exprContext ctx) {
|
|
||||||
if (ctx.mul_expr() == null) return visit(ctx.int_val());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.int_val());
|
|
||||||
String operand1 = visit(ctx.mul_expr());
|
|
||||||
|
|
||||||
switch (ctx.OP_MUL().getText().toLowerCase()) {
|
|
||||||
case "*":
|
|
||||||
return operand0 + " " + operand1 + " MUL";
|
|
||||||
case "/":
|
|
||||||
return operand0 + " " + operand1 + " DIV";
|
|
||||||
case "^":
|
|
||||||
return operand0 + " " + operand1 + " EXP";
|
|
||||||
case "%":
|
|
||||||
return operand0 + " " + operand1 + " MOD";
|
|
||||||
case "#/":
|
|
||||||
return operand0 + " " + operand1 + " SDIV";
|
|
||||||
case "#%":
|
|
||||||
return operand0 + " " + operand1 + " SMOD";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_MUL().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitAdd_expr(@NotNull SerpentParser.Add_exprContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.add_expr() == null) return visit(ctx.mul_expr());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.mul_expr());
|
|
||||||
String operand1 = visit(ctx.add_expr());
|
|
||||||
|
|
||||||
switch (ctx.OP_ADD().getText().toLowerCase()) {
|
|
||||||
case "+":
|
|
||||||
return operand0 + " " + operand1 + " ADD";
|
|
||||||
case "-":
|
|
||||||
return operand0 + " " + operand1 + " SUB";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_ADD().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitRel_exp(@NotNull SerpentParser.Rel_expContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.rel_exp() == null) return visit(ctx.add_expr());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.rel_exp());
|
|
||||||
String operand1 = visit(ctx.add_expr());
|
|
||||||
|
|
||||||
switch (ctx.OP_REL().getText().toLowerCase()) {
|
|
||||||
case "<":
|
|
||||||
return operand1 + " " + operand0 + " LT";
|
|
||||||
case ">":
|
|
||||||
return operand1 + " " + operand0 + " GT";
|
|
||||||
case ">=":
|
|
||||||
return operand1 + " " + operand0 + " LT NOT";
|
|
||||||
case "<=":
|
|
||||||
return operand1 + " " + operand0 + " GT NOT";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_REL().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitEq_exp(@NotNull SerpentParser.Eq_expContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.eq_exp() == null) return visit(ctx.rel_exp());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.rel_exp());
|
|
||||||
String operand1 = visit(ctx.eq_exp());
|
|
||||||
|
|
||||||
switch (ctx.OP_EQ().getText().toLowerCase()) {
|
|
||||||
case "==":
|
|
||||||
return operand0 + " " + operand1 + " EQ";
|
|
||||||
case "!=":
|
|
||||||
return operand0 + " " + operand1 + " EQ NOT";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_EQ().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitAnd_exp(@NotNull SerpentParser.And_expContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.and_exp() == null) return visit(ctx.eq_exp());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.eq_exp());
|
|
||||||
String operand1 = visit(ctx.and_exp());
|
|
||||||
|
|
||||||
switch (ctx.OP_AND().getText().toLowerCase()) {
|
|
||||||
case "&":
|
|
||||||
return operand0 + " " + operand1 + " AND";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_AND().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitEx_or_exp(@NotNull SerpentParser.Ex_or_expContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.ex_or_exp() == null) return visit(ctx.and_exp());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.and_exp());
|
|
||||||
String operand1 = visit(ctx.ex_or_exp());
|
|
||||||
|
|
||||||
switch (ctx.OP_EX_OR().getText().toLowerCase()) {
|
|
||||||
case "xor":
|
|
||||||
return operand0 + " " + operand1 + " XOR";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_EX_OR().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitIn_or_exp(@NotNull SerpentParser.In_or_expContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.in_or_exp() == null) return visit(ctx.ex_or_exp());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.ex_or_exp());
|
|
||||||
String operand1 = visit(ctx.in_or_exp());
|
|
||||||
|
|
||||||
switch (ctx.OP_IN_OR().getText().toLowerCase()) {
|
|
||||||
case "|":
|
|
||||||
return operand0 + " " + operand1 + " OR";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_IN_OR().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitLog_and_exp(@NotNull SerpentParser.Log_and_expContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.log_and_exp() == null) return visit(ctx.in_or_exp());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.in_or_exp());
|
|
||||||
String operand1 = visit(ctx.log_and_exp());
|
|
||||||
|
|
||||||
switch (ctx.OP_LOG_AND().getText().toLowerCase()) {
|
|
||||||
case "and":
|
|
||||||
return operand0 + " " + operand1 + " NOT NOT MUL";
|
|
||||||
case "&&":
|
|
||||||
return operand0 + " " + operand1 + " NOT NOT MUL";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_LOG_AND().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitLog_or_exp(@NotNull SerpentParser.Log_or_expContext ctx) {
|
|
||||||
|
|
||||||
if (ctx.log_or_exp() == null) return visit(ctx.log_and_exp());
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.log_and_exp());
|
|
||||||
String operand1 = visit(ctx.log_or_exp());
|
|
||||||
|
|
||||||
switch (ctx.OP_LOG_OR().getText().toLowerCase()) {
|
|
||||||
case "||":
|
|
||||||
return operand0 + " " + operand1 + " DUP 4 PC ADD JUMPI POP SWAP POP";
|
|
||||||
case "or":
|
|
||||||
return operand0 + " " + operand1 + " DUP 4 PC ADD JUMPI POP SWAP POP";
|
|
||||||
default:
|
|
||||||
throw new UnknownOperandException(ctx.OP_LOG_OR().getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitMsg_sender(@NotNull SerpentParser.Msg_senderContext ctx) {
|
|
||||||
return "CALLER";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitMsg_datasize(@NotNull SerpentParser.Msg_datasizeContext ctx) {
|
|
||||||
return "32 CALLDATASIZE DIV ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitMsg_value(@NotNull SerpentParser.Msg_valueContext ctx) {
|
|
||||||
return " CALLVALUE ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitContract_balance(@NotNull SerpentParser.Contract_balanceContext ctx) {
|
|
||||||
return " BALANCE ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitContract_address(@NotNull SerpentParser.Contract_addressContext ctx) {
|
|
||||||
return " ADDRESS ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitTx_origin(@NotNull SerpentParser.Tx_originContext ctx) {
|
|
||||||
return " ORIGIN ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitBlock_timestamp(@NotNull SerpentParser.Block_timestampContext ctx) {
|
|
||||||
return " TIMESTAMP ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitBlock_number(@NotNull SerpentParser.Block_numberContext ctx) {
|
|
||||||
return " NUMBER ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitTx_gas(@NotNull SerpentParser.Tx_gasContext ctx) {
|
|
||||||
return " GAS ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitBlock_difficulty(@NotNull SerpentParser.Block_difficultyContext ctx) {
|
|
||||||
return " DIFFICULTY ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitBlock_coinbase(@NotNull SerpentParser.Block_coinbaseContext ctx) {
|
|
||||||
return " COINBASE ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitTx_gasprice(@NotNull SerpentParser.Tx_gaspriceContext ctx) {
|
|
||||||
return " GASPRICE ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitBlock_prevhash(@NotNull SerpentParser.Block_prevhashContext ctx) {
|
|
||||||
return " PREVHASH ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitBlock_gaslimit(@NotNull SerpentParser.Block_gaslimitContext ctx) {
|
|
||||||
return " GASLIMIT ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitRet_func_1(@NotNull SerpentParser.Ret_func_1Context ctx) {
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.expression());
|
|
||||||
|
|
||||||
return String.format(" %s MSIZE SWAP MSIZE MSTORE 32 SWAP RETURN ", operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitRet_func_2(@NotNull SerpentParser.Ret_func_2Context ctx) {
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.expression(0));
|
|
||||||
String operand1 = visit(ctx.expression(1));
|
|
||||||
|
|
||||||
return String.format(" %s 32 MUL %s RETURN ", operand1, operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitSuicide_func(@NotNull SerpentParser.Suicide_funcContext ctx) {
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.expression());
|
|
||||||
|
|
||||||
return String.format(" %s SUICIDE ", operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitStop_func(@NotNull SerpentParser.Stop_funcContext ctx) {
|
|
||||||
return " STOP ";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitMsg_data(@NotNull SerpentParser.Msg_dataContext ctx) {
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.expression());
|
|
||||||
|
|
||||||
return String.format("%s 32 MUL CALLDATALOAD ", operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String visitMsg_func(@NotNull SerpentParser.Msg_funcContext ctx, String varName) {
|
|
||||||
|
|
||||||
// msg_func: 'msg' '(' int_val ',' int_val ',' int_val ',' arr_def ',' int_val ',' int_val')' ;
|
|
||||||
// msg_func: 'msg' '(' [gas] ',' [to] ',' [value] ',' arr_def ',' [in_len] ',' [out_len]')' ;
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.int_val(0));
|
|
||||||
String operand1 = visit(ctx.int_val(1));
|
|
||||||
String operand2 = visit(ctx.int_val(2));
|
|
||||||
|
|
||||||
String loadInData = visit(ctx.arr_def());
|
|
||||||
|
|
||||||
String inSizeCallParam = visit(ctx.int_val(3));
|
|
||||||
String outSizeCallParam = visit(ctx.int_val(4));
|
|
||||||
|
|
||||||
// TODO: 1. allocate out_memory and push ptr
|
|
||||||
// TODO: 2. push ptr for in_memory allocated
|
|
||||||
|
|
||||||
String randomArrayName = new String(HashUtil.randomPeerId());
|
|
||||||
|
|
||||||
int inSize = Integer.parseInt(inSizeCallParam);
|
|
||||||
int outSize = Integer.parseInt(outSizeCallParam);
|
|
||||||
|
|
||||||
arraysSize.put(randomArrayName, inSize * 32 + 32);
|
|
||||||
arraysIndex.add(randomArrayName);
|
|
||||||
|
|
||||||
int outSizeVal = outSize * 32 + 32;
|
|
||||||
arraysSize.put(varName, outSize * 32 + 32);
|
|
||||||
arraysIndex.add(varName);
|
|
||||||
|
|
||||||
// [OUTDATASIZE] [OUTDATASTART] [INDATASIZE] [INDATASTART] [VALUE] [TO] [GAS] CALL
|
|
||||||
// [OUTDATASIZE] [OUTDATASTART] [INDATASIZE] [INDATASTART] ***ARR_IN_SET*** [VALUE] [TO] [GAS] CALL
|
|
||||||
//X_X = [ 32 + 128 + 6 * 32 ] = [ var_table_size + in_arr_size + out_arr_size ]
|
|
||||||
|
|
||||||
// this code allocates the memory block for the out data,
|
|
||||||
// and saves the size in typical array format [size, element_1, element_2, ...]
|
|
||||||
String outArrSet = String.format(" %d MSIZE MSTORE 0 %d MSIZE ADD MSTORE8 ", outSizeVal, outSizeVal - 32);
|
|
||||||
|
|
||||||
return String.format("%d MSIZE %s %d %s %s %s %s CALL ",
|
|
||||||
outSizeVal, outArrSet, inSize * 32, loadInData, operand2, operand1, operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitSend_func(@NotNull SerpentParser.Send_funcContext ctx) {
|
|
||||||
|
|
||||||
String operand0 = visit(ctx.int_val(0));
|
|
||||||
String operand1 = visit(ctx.int_val(1));
|
|
||||||
String operand2 = visit(ctx.int_val(2));
|
|
||||||
|
|
||||||
// OUTDATASIZE OUTDATASTART INDATASIZE INDATASTART VALUE TO GAS CALL
|
|
||||||
return String.format("0 0 0 0 %s %s %s CALL ", operand2, operand1, operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitCreate_func(@NotNull SerpentParser.Create_funcContext ctx) {
|
|
||||||
String operand0 = visit(ctx.int_val(0));
|
|
||||||
String operand1 = visit(ctx.int_val(1));
|
|
||||||
String operand2 = visit(ctx.int_val(2));
|
|
||||||
|
|
||||||
// MEM_SIZE MEM_START GAS CREATE
|
|
||||||
return String.format(" %s %s %s CREATE ", operand2, operand1, operand0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitAsm(@NotNull SerpentParser.AsmContext ctx) {
|
|
||||||
|
|
||||||
int size = ctx.asm_symbol().getChildCount();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
|
|
||||||
String symbol = ctx.asm_symbol().children.get(i).toString();
|
|
||||||
symbol = symbol.trim();
|
|
||||||
|
|
||||||
// exclude all that is not an assembly code
|
|
||||||
if (symbol.equals("[asm") || symbol.equals("asm]") || symbol.equals("\n")) continue;
|
|
||||||
|
|
||||||
boolean match = Pattern.matches("[0-9]+", symbol);
|
|
||||||
if (match) {
|
|
||||||
|
|
||||||
int byteVal = Integer.parseInt(symbol);
|
|
||||||
if (byteVal > 255 || byteVal < 0)
|
|
||||||
throw new Error("In the [asm asm] block should be placed only byte range numbers");
|
|
||||||
}
|
|
||||||
|
|
||||||
match = Pattern.matches("0[xX][0-9a-fA-F]+", symbol);
|
|
||||||
if (match) {
|
|
||||||
|
|
||||||
int byteVal = Integer.parseInt(symbol.substring(2), 16);
|
|
||||||
if (byteVal > 255 || byteVal < 0)
|
|
||||||
throw new Error("In the [asm asm] block should be placed only byte range numbers");
|
|
||||||
symbol = byteVal + "";
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append(symbol).append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return "[asm " + sb.toString() + " asm]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String aggregateResult(String aggregate, String nextResult) {
|
|
||||||
return aggregate + nextResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String defaultResult() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param hexNum should be in form '0x34fabd34....'
|
|
||||||
*/
|
|
||||||
private String hexStringToDecimalString(String hexNum) {
|
|
||||||
String digits = hexNum.substring(2);
|
|
||||||
if (digits.length() % 2 != 0) digits = "0" + digits;
|
|
||||||
byte[] numberBytes = Hex.decode(digits);
|
|
||||||
return (new BigInteger(1, numberBytes)).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class UnknownOperandException extends RuntimeException {
|
|
||||||
public UnknownOperandException(String name) {
|
|
||||||
super("unknown operand: " + name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class UnassignVarException extends RuntimeException {
|
|
||||||
public UnassignVarException(String name) {
|
|
||||||
super("attempt to access not assigned variable: " + name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Integer getMsgOutputArraySize(String code) {
|
|
||||||
|
|
||||||
String result = "0";
|
|
||||||
Pattern pattern = Pattern.compile("<out_size ([0-9])* out_size>");
|
|
||||||
Matcher matcher = pattern.matcher(code.trim());
|
|
||||||
if (matcher.find()) {
|
|
||||||
|
|
||||||
String group = matcher.group(0);
|
|
||||||
result = group.replaceAll("<out_size ([0-9]*) out_size>", "$1").trim();
|
|
||||||
}
|
|
||||||
return Integer.parseInt(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Integer getMsgInputArraySize(String code) {
|
|
||||||
|
|
||||||
String result = "0";
|
|
||||||
Pattern pattern = Pattern.compile("<in_size ([0-9])* in_size>");
|
|
||||||
Matcher matcher = pattern.matcher(code.trim());
|
|
||||||
if (matcher.find()) {
|
|
||||||
|
|
||||||
String group = matcher.group(0);
|
|
||||||
result = group.replaceAll("<in_size ([0-9]*) in_size>", "$1").trim();
|
|
||||||
}
|
|
||||||
return Integer.parseInt(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String cleanMsgString(String code) {
|
|
||||||
return code.replaceAll("<(.*?)>", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After the array deff code is set
|
|
||||||
* extract the size out of code string
|
|
||||||
*/
|
|
||||||
private static Integer getArraySize(String code) {
|
|
||||||
|
|
||||||
String result = "0";
|
|
||||||
Pattern pattern = Pattern.compile(" [0-9]* SWAP MSTORE$");
|
|
||||||
Matcher matcher = pattern.matcher(code.trim());
|
|
||||||
if (matcher.find()) {
|
|
||||||
|
|
||||||
String group = matcher.group(0);
|
|
||||||
result = group.replace("SWAP MSTORE", "").trim();
|
|
||||||
}
|
|
||||||
return Integer.parseInt(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -21,7 +21,7 @@ import static org.ethereum.util.Value.fromRlpEncoded;
|
|||||||
*/
|
*/
|
||||||
public class Cache {
|
public class Cache {
|
||||||
|
|
||||||
private static final Logger gLogger = LoggerFactory.getLogger("general");
|
private static final Logger logger = LoggerFactory.getLogger("general");
|
||||||
|
|
||||||
private final KeyValueDataSource dataSource;
|
private final KeyValueDataSource dataSource;
|
||||||
private Map<ByteArrayWrapper, Node> nodes = new ConcurrentHashMap<>();
|
private Map<ByteArrayWrapper, Node> nodes = new ConcurrentHashMap<>();
|
||||||
@ -99,7 +99,7 @@ public class Cache {
|
|||||||
|
|
||||||
float flushSize = (float) totalSize / 1048576;
|
float flushSize = (float) totalSize / 1048576;
|
||||||
float flushTime = (float) (finish - start) / 1_000_000;
|
float flushTime = (float) (finish - start) / 1_000_000;
|
||||||
gLogger.info(format("Flush state in: %02.2f ms, %d nodes, %02.2fMB", flushTime, batch.size(), flushSize));
|
logger.info(format("Flush state in: %02.2f ms, %d nodes, %02.2fMB", flushTime, batch.size(), flushSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undo() {
|
public void undo() {
|
||||||
|
@ -17,6 +17,7 @@ import static java.util.Arrays.copyOfRange;
|
|||||||
import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH;
|
import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH;
|
||||||
import static org.ethereum.util.ByteUtil.*;
|
import static org.ethereum.util.ByteUtil.*;
|
||||||
import static org.ethereum.util.CompactEncoder.*;
|
import static org.ethereum.util.CompactEncoder.*;
|
||||||
|
import static org.ethereum.util.RLP.calcElementPrefixSize;
|
||||||
import static org.spongycastle.util.Arrays.concatenate;
|
import static org.spongycastle.util.Arrays.concatenate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -519,7 +520,7 @@ public class TrieImpl implements Trie {
|
|||||||
keysTotalSize += keyBytes.length;
|
keysTotalSize += keyBytes.length;
|
||||||
|
|
||||||
byte[] valBytes = map.get(key).getValue().getData();
|
byte[] valBytes = map.get(key).getValue().getData();
|
||||||
valsTotalSize += valBytes.length;
|
valsTotalSize += valBytes.length + calcElementPrefixSize(valBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] root = null;
|
byte[] root = null;
|
||||||
@ -568,7 +569,7 @@ public class TrieImpl implements Trie {
|
|||||||
|
|
||||||
k_1 += key.getData().length;
|
k_1 += key.getData().length;
|
||||||
|
|
||||||
byte[] valBytes = map.get(key).getValue().getData();
|
byte[] valBytes = RLP.encodeElement( map.get(key).getValue().getData() );
|
||||||
|
|
||||||
System.arraycopy(valBytes, 0, rlpData,
|
System.arraycopy(valBytes, 0, rlpData,
|
||||||
listHeader.length + keysHeader.length + keysTotalSize + valsHeader.length + k_2,
|
listHeader.length + keysHeader.length + keysTotalSize + valsHeader.length + k_2,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package org.ethereum.util;
|
package org.ethereum.util;
|
||||||
|
|
||||||
import org.ethereum.db.ByteArrayWrapper;
|
import org.ethereum.db.ByteArrayWrapper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -42,6 +44,9 @@ import static org.spongycastle.util.BigIntegers.asUnsignedByteArray;
|
|||||||
*/
|
*/
|
||||||
public class RLP {
|
public class RLP {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger("rlp");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow for content up to size of 2^64 bytes *
|
* Allow for content up to size of 2^64 bytes *
|
||||||
*/
|
*/
|
||||||
@ -477,6 +482,10 @@ public class RLP {
|
|||||||
int pos = startPos;
|
int pos = startPos;
|
||||||
|
|
||||||
while (pos < endPos) {
|
while (pos < endPos) {
|
||||||
|
|
||||||
|
logger.debug("fullTraverse: level: " + level + " startPos: " + pos + " endPos: " + endPos);
|
||||||
|
|
||||||
|
|
||||||
// It's a list with a payload more than 55 bytes
|
// It's a list with a payload more than 55 bytes
|
||||||
// data[0] - 0xF7 = how many next bytes allocated
|
// data[0] - 0xF7 = how many next bytes allocated
|
||||||
// for the length of the list
|
// for the length of the list
|
||||||
@ -784,6 +793,31 @@ public class RLP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int calcElementPrefixSize(byte[] srcData) {
|
||||||
|
|
||||||
|
if (isNullOrZeroArray(srcData))
|
||||||
|
return 0;
|
||||||
|
else if (isSingleZero(srcData))
|
||||||
|
return 0;
|
||||||
|
else if (srcData.length == 1 && (srcData[0] & 0xFF) < 0x80) {
|
||||||
|
return 0;
|
||||||
|
} else if (srcData.length < SIZE_THRESHOLD) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
// length of length = BX
|
||||||
|
// prefix = [BX, [length]]
|
||||||
|
int tmpLength = srcData.length;
|
||||||
|
byte byteNum = 0;
|
||||||
|
while (tmpLength != 0) {
|
||||||
|
++byteNum;
|
||||||
|
tmpLength = tmpLength >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1 + byteNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static byte[] encodeListHeader(int size) {
|
public static byte[] encodeListHeader(int size) {
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
@ -973,5 +1007,4 @@ public class RLP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -19,15 +19,28 @@ public class Value {
|
|||||||
private byte[] rlp;
|
private byte[] rlp;
|
||||||
private byte[] sha3;
|
private byte[] sha3;
|
||||||
|
|
||||||
|
private boolean decoded = false;
|
||||||
|
|
||||||
public static Value fromRlpEncoded(byte[] data) {
|
public static Value fromRlpEncoded(byte[] data) {
|
||||||
|
|
||||||
if (data != null && data.length != 0) {
|
if (data != null && data.length != 0) {
|
||||||
return new Value(RLP.decode(data, 0).getDecoded());
|
Value v = new Value();
|
||||||
|
v.init(data);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Value(){
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(byte[] rlp){
|
||||||
|
this.rlp = rlp;
|
||||||
|
}
|
||||||
|
|
||||||
public Value(Object obj) {
|
public Value(Object obj) {
|
||||||
|
|
||||||
|
this.decoded = true;
|
||||||
if (obj == null) return;
|
if (obj == null) return;
|
||||||
|
|
||||||
if (obj instanceof Value) {
|
if (obj instanceof Value) {
|
||||||
@ -42,15 +55,18 @@ public class Value {
|
|||||||
* *****************/
|
* *****************/
|
||||||
|
|
||||||
public Object asObj() {
|
public Object asObj() {
|
||||||
|
decode();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Object> asList() {
|
public List<Object> asList() {
|
||||||
|
decode();
|
||||||
Object[] valueArray = (Object[]) value;
|
Object[] valueArray = (Object[]) value;
|
||||||
return Arrays.asList(valueArray);
|
return Arrays.asList(valueArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int asInt() {
|
public int asInt() {
|
||||||
|
decode();
|
||||||
if (isInt()) {
|
if (isInt()) {
|
||||||
return (Integer) value;
|
return (Integer) value;
|
||||||
} else if (isBytes()) {
|
} else if (isBytes()) {
|
||||||
@ -60,6 +76,7 @@ public class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long asLong() {
|
public long asLong() {
|
||||||
|
decode();
|
||||||
if (isLong()) {
|
if (isLong()) {
|
||||||
return (Long) value;
|
return (Long) value;
|
||||||
} else if (isBytes()) {
|
} else if (isBytes()) {
|
||||||
@ -69,10 +86,12 @@ public class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BigInteger asBigInt() {
|
public BigInteger asBigInt() {
|
||||||
|
decode();
|
||||||
return (BigInteger) value;
|
return (BigInteger) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String asString() {
|
public String asString() {
|
||||||
|
decode();
|
||||||
if (isBytes()) {
|
if (isBytes()) {
|
||||||
return new String((byte[]) value);
|
return new String((byte[]) value);
|
||||||
} else if (isString()) {
|
} else if (isString()) {
|
||||||
@ -82,6 +101,7 @@ public class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] asBytes() {
|
public byte[] asBytes() {
|
||||||
|
decode();
|
||||||
if (isBytes()) {
|
if (isBytes()) {
|
||||||
return (byte[]) value;
|
return (byte[]) value;
|
||||||
} else if (isString()) {
|
} else if (isString()) {
|
||||||
@ -122,6 +142,13 @@ public class Value {
|
|||||||
* Utility
|
* Utility
|
||||||
* *****************/
|
* *****************/
|
||||||
|
|
||||||
|
public void decode(){
|
||||||
|
if (!this.decoded) {
|
||||||
|
this.value = RLP.decode(rlp, 0).getDecoded();
|
||||||
|
this.decoded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] encode() {
|
public byte[] encode() {
|
||||||
if (rlp == null)
|
if (rlp == null)
|
||||||
rlp = RLP.encode(value);
|
rlp = RLP.encode(value);
|
||||||
@ -143,32 +170,39 @@ public class Value {
|
|||||||
* *****************/
|
* *****************/
|
||||||
|
|
||||||
public boolean isList() {
|
public boolean isList() {
|
||||||
|
decode();
|
||||||
return value != null && value.getClass().isArray() && !value.getClass().getComponentType().isPrimitive();
|
return value != null && value.getClass().isArray() && !value.getClass().getComponentType().isPrimitive();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isString() {
|
public boolean isString() {
|
||||||
|
decode();
|
||||||
return value instanceof String;
|
return value instanceof String;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInt() {
|
public boolean isInt() {
|
||||||
|
decode();
|
||||||
return value instanceof Integer;
|
return value instanceof Integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLong() {
|
public boolean isLong() {
|
||||||
|
decode();
|
||||||
return value instanceof Long;
|
return value instanceof Long;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBigInt() {
|
public boolean isBigInt() {
|
||||||
|
decode();
|
||||||
return value instanceof BigInteger;
|
return value instanceof BigInteger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBytes() {
|
public boolean isBytes() {
|
||||||
|
decode();
|
||||||
return value instanceof byte[];
|
return value instanceof byte[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's only if the isBytes() = true;
|
// it's only if the isBytes() = true;
|
||||||
public boolean isReadableString() {
|
public boolean isReadableString() {
|
||||||
|
|
||||||
|
decode();
|
||||||
int readableChars = 0;
|
int readableChars = 0;
|
||||||
byte[] data = (byte[]) value;
|
byte[] data = (byte[]) value;
|
||||||
|
|
||||||
@ -186,6 +220,7 @@ public class Value {
|
|||||||
// it's only if the isBytes() = true;
|
// it's only if the isBytes() = true;
|
||||||
public boolean isHexString() {
|
public boolean isHexString() {
|
||||||
|
|
||||||
|
decode();
|
||||||
int hexChars = 0;
|
int hexChars = 0;
|
||||||
byte[] data = (byte[]) value;
|
byte[] data = (byte[]) value;
|
||||||
|
|
||||||
@ -200,14 +235,17 @@ public class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isHashCode() {
|
public boolean isHashCode() {
|
||||||
|
decode();
|
||||||
return this.asBytes().length == 32;
|
return this.asBytes().length == 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNull() {
|
public boolean isNull() {
|
||||||
|
decode();
|
||||||
return value == null;
|
return value == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
|
decode();
|
||||||
if (isNull()) return true;
|
if (isNull()) return true;
|
||||||
if (isBytes() && asBytes().length == 0) return true;
|
if (isBytes() && asBytes().length == 0) return true;
|
||||||
if (isList() && asList().isEmpty()) return true;
|
if (isList() && asList().isEmpty()) return true;
|
||||||
@ -217,6 +255,7 @@ public class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int length() {
|
public int length() {
|
||||||
|
decode();
|
||||||
if (isList()) {
|
if (isList()) {
|
||||||
return asList().size();
|
return asList().size();
|
||||||
} else if (isBytes()) {
|
} else if (isBytes()) {
|
||||||
@ -229,6 +268,7 @@ public class Value {
|
|||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
||||||
|
decode();
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
if (isList()) {
|
if (isList()) {
|
||||||
@ -296,7 +336,7 @@ public class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int countBranchNodes() {
|
public int countBranchNodes() {
|
||||||
|
decode();
|
||||||
if (this.isList()) {
|
if (this.isList()) {
|
||||||
List<Object> objList = this.asList();
|
List<Object> objList = this.asList();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -360,8 +360,6 @@ public class Program {
|
|||||||
Program program = new Program(programCode, programInvoke);
|
Program program = new Program(programCode, programInvoke);
|
||||||
vm.play(program);
|
vm.play(program);
|
||||||
result = program.getResult();
|
result = program.getResult();
|
||||||
this.result.addDeleteAccounts(result.getDeleteAccounts());
|
|
||||||
this.result.addLogInfos(result.getLogInfoList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.getException() != null) {
|
if (result.getException() != null) {
|
||||||
@ -394,6 +392,8 @@ public class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
track.commit();
|
track.commit();
|
||||||
|
this.result.addDeleteAccounts(result.getDeleteAccounts());
|
||||||
|
this.result.addLogInfos(result.getLogInfoList());
|
||||||
|
|
||||||
// IN SUCCESS PUSH THE ADDRESS INTO THE STACK
|
// IN SUCCESS PUSH THE ADDRESS INTO THE STACK
|
||||||
stackPush(new DataWord(newAddress));
|
stackPush(new DataWord(newAddress));
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
# Root logger option
|
# Root logger option
|
||||||
log4j.rootLogger=DEBUG, stdout, file
|
log4j.rootLogger=DEBUG, stdout, file
|
||||||
log4j.logger.dump=TRACE, DUMP
|
|
||||||
|
|
||||||
# Direct log messages to stdout
|
# Direct log messages to stdout
|
||||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||||
@ -9,16 +8,12 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
|||||||
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss.SSS} [%c{1}] %m%n
|
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss.SSS} [%c{1}] %m%n
|
||||||
log4j.appender.stdout.Threshold=INFO
|
log4j.appender.stdout.Threshold=INFO
|
||||||
|
|
||||||
# Direct log messages to stdout
|
|
||||||
log4j.appender.DUMP=org.apache.log4j.ConsoleAppender
|
|
||||||
log4j.appender.DUMP.Target=System.out
|
|
||||||
log4j.appender.DUMP.layout=org.apache.log4j.PatternLayout
|
|
||||||
|
|
||||||
log4j.appender.file=org.apache.log4j.rolling.RollingFileAppender
|
log4j.appender.file=org.apache.log4j.rolling.RollingFileAppender
|
||||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||||
log4j.appender.file.layout.ConversionPattern= %d{HH:mm:ss} [%c{1}] %m%n
|
log4j.appender.file.layout.ConversionPattern= %d{HH:mm:ss} [%c{1}] %m%n
|
||||||
log4j.appender.file.RollingPolicy=org.apache.log4j.rolling.TimeBasedRollingPolicy
|
log4j.appender.file.RollingPolicy=org.apache.log4j.rolling.TimeBasedRollingPolicy
|
||||||
log4j.appender.file.RollingPolicy.FileNamePattern=./logs/ethereum_%d{yyyy-MM-dd}_h%d{HH}.log
|
log4j.appender.file.RollingPolicy.FileNamePattern=./logs/ethereum_%d{yyyy-MM-dd}_h%d{HH}.log
|
||||||
|
log4j.appender.file.Threshold=ERROR
|
||||||
|
|
||||||
# filter noisy classes
|
# filter noisy classes
|
||||||
log4j.logger.block = ERROR
|
log4j.logger.block = ERROR
|
||||||
@ -44,6 +39,8 @@ log4j.logger.gas = ERROR
|
|||||||
log4j.logger.cli = ERROR
|
log4j.logger.cli = ERROR
|
||||||
log4j.logger.TCK-Test = ERROR
|
log4j.logger.TCK-Test = ERROR
|
||||||
log4j.logger.execute = ERROR
|
log4j.logger.execute = ERROR
|
||||||
|
log4j.logger.rlp = ERROR
|
||||||
|
|
||||||
|
|
||||||
log4j.logger.org.springframework = ERROR
|
log4j.logger.org.springframework = ERROR
|
||||||
log4j.logger.org.hibernate = ERROR
|
log4j.logger.org.hibernate = ERROR
|
||||||
|
@ -185,7 +185,7 @@ root.hash.start = -1
|
|||||||
peer.capabilities = eth, shh
|
peer.capabilities = eth, shh
|
||||||
|
|
||||||
# Key value data source values: [leveldb/redis/mapdb]
|
# Key value data source values: [leveldb/redis/mapdb]
|
||||||
keyvalue.datasource = mapdb
|
keyvalue.datasource = leveldb
|
||||||
|
|
||||||
# Redis cloud enabled flag.
|
# Redis cloud enabled flag.
|
||||||
# Allows using RedisConnection for creating cloud based data structures.
|
# Allows using RedisConnection for creating cloud based data structures.
|
||||||
@ -198,8 +198,10 @@ blockchain.only=false
|
|||||||
# from a rlp lines
|
# from a rlp lines
|
||||||
# file and not for
|
# file and not for
|
||||||
# the net
|
# the net
|
||||||
blocks.loader=
|
#blocks.loader=E:\\temp\\_poc-9-blocks\\poc-9-blocks-start-476891.dmp
|
||||||
#E:\\temp\\_poc-9-blocks\\poc-9-492k_.dmp
|
#blocks.loader=E:\\temp\\_poc-9-blocks\\poc-9-492k_.dmp
|
||||||
|
#blocks.loader=E:\\temp\\_poc-9-blocks\\poc-9-st-530k.dmp
|
||||||
|
#blocks.loader=E:\\temp\\_poc-9-blocks\\poc-9-619k.dmp
|
||||||
|
|
||||||
flush.batch.size=5000
|
flush.batch.size=10000
|
||||||
flush.ignore.consensus=false
|
flush.ignore.consensus=false
|
@ -89,11 +89,11 @@ public class BlockTest {
|
|||||||
JSONParser parser = new JSONParser();
|
JSONParser parser = new JSONParser();
|
||||||
JSONObject genesisMap = (JSONObject) parser.parse(TEST_GENESIS);
|
JSONObject genesisMap = (JSONObject) parser.parse(TEST_GENESIS);
|
||||||
|
|
||||||
Set<String> keys = genesisMap.keySet();
|
Set keys = genesisMap.keySet();
|
||||||
|
|
||||||
Trie state = new SecureTrie(null);
|
Trie state = new SecureTrie(null);
|
||||||
|
|
||||||
for (String key : keys) {
|
for (Object key : keys) {
|
||||||
|
|
||||||
JSONObject val = (JSONObject) genesisMap.get(key);
|
JSONObject val = (JSONObject) genesisMap.get(key);
|
||||||
String denom = (String) val.keySet().toArray()[0];
|
String denom = (String) val.keySet().toArray()[0];
|
||||||
@ -102,7 +102,7 @@ public class BlockTest {
|
|||||||
BigInteger wei = Denomination.valueOf(denom.toUpperCase()).value().multiply(new BigInteger(value));
|
BigInteger wei = Denomination.valueOf(denom.toUpperCase()).value().multiply(new BigInteger(value));
|
||||||
|
|
||||||
AccountState acctState = new AccountState(BigInteger.ZERO, wei);
|
AccountState acctState = new AccountState(BigInteger.ZERO, wei);
|
||||||
state.update(Hex.decode(key), acctState.getEncoded());
|
state.update(Hex.decode(key.toString()), acctState.getEncoded());
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("root: " + Hex.toHexString(state.getRootHash()));
|
logger.info("root: " + Hex.toHexString(state.getRootHash()));
|
||||||
|
@ -151,69 +151,5 @@ public class ContractDetailsTest {
|
|||||||
Hex.toHexString(contractDetails_.get(new DataWord(key_13)).getData()));
|
Hex.toHexString(contractDetails_.get(new DataWord(key_13)).getData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test @Ignore("cause it's heavy")
|
|
||||||
public void test___1() throws URISyntaxException, IOException {
|
|
||||||
|
|
||||||
// 13dc5836cd5638d0b81a1ba8377a7852d41b5bbe: saved on #490281
|
|
||||||
|
|
||||||
// found on block: #501570
|
|
||||||
// account.getStateRoot = d7b597b334b78c63ddf7beafc96484f5604472c40d438ea514882fab0813f074
|
|
||||||
|
|
||||||
// (!!!) next step is to find out why on #501595 the root changes
|
|
||||||
|
|
||||||
|
|
||||||
URL scenario_ = ClassLoader
|
|
||||||
.getSystemResource("rlp/contract-on-501570.rlp");
|
|
||||||
|
|
||||||
|
|
||||||
URL scenario1 = ClassLoader
|
|
||||||
.getSystemResource("rlp/contract-on-505829.rlp");
|
|
||||||
|
|
||||||
File file = new File(scenario1.toURI());
|
|
||||||
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
|
|
||||||
String rlpString = strData.get(0);
|
|
||||||
byte[] rlp = Hex.decode(rlpString);
|
|
||||||
ContractDetailsImpl contractDetails = new ContractDetailsImpl(rlp);
|
|
||||||
|
|
||||||
File file_ = new File(scenario_.toURI());
|
|
||||||
List<String> strData_ = Files.readAllLines(file_.toPath(), StandardCharsets.UTF_8);
|
|
||||||
String rlpString_ = strData_.get(0);
|
|
||||||
byte[] rlp_ = Hex.decode(rlpString_);
|
|
||||||
ContractDetailsImpl contractDetails_ = new ContractDetailsImpl(rlp_);
|
|
||||||
|
|
||||||
|
|
||||||
contractDetails.put(new DataWord("5df1567644a3c48bf9a1b9d2e185cb9731053ab04882571d2d46c27935d11f1d"),
|
|
||||||
new DataWord("0000000000000000000000000000000000000000000000000000000000000000"));
|
|
||||||
|
|
||||||
System.out.println(Hex.toHexString(contractDetails.getStorageHash()));
|
|
||||||
|
|
||||||
// contractDetails.getStorage();
|
|
||||||
byte[] rlp_after = contractDetails.getEncoded();
|
|
||||||
ContractDetailsImpl contractDetails2 = new ContractDetailsImpl(rlp_after);
|
|
||||||
String root2 = Hex.toHexString(contractDetails2.getStorageHash());
|
|
||||||
|
|
||||||
System.out.println(root2);
|
|
||||||
|
|
||||||
byte[] rlp_after_2 = contractDetails2.getEncoded();
|
|
||||||
ContractDetailsImpl contractDetails3 = new ContractDetailsImpl(rlp_after_2);
|
|
||||||
String root3 = Hex.toHexString(contractDetails3.getStorageHash());
|
|
||||||
|
|
||||||
System.out.println(root3);
|
|
||||||
|
|
||||||
Set<DataWord> keys = contractDetails_.getStorage().keySet();
|
|
||||||
|
|
||||||
System.out.println( Hex.toHexString( contractDetails_.getStorageHash() ));
|
|
||||||
System.out.println( Hex.toHexString( contractDetails.getStorageHash() ));
|
|
||||||
|
|
||||||
for (DataWord key : keys){
|
|
||||||
|
|
||||||
DataWord val = contractDetails.get(key);
|
|
||||||
DataWord val_ = contractDetails_.get(key);
|
|
||||||
|
|
||||||
if (!val.equals(val_)) System.out.println(key + ":" + val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
package org.ethereum.net.shh;
|
||||||
|
|
||||||
|
import org.ethereum.crypto.ECKey;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class FilterTest {
|
||||||
|
|
||||||
|
byte[] to = new ECKey().decompress().getPubKey();
|
||||||
|
byte[] from = new ECKey().decompress().getPubKey();
|
||||||
|
String[] topics = {"topic1", "topic2", "topic3", "topic4"};
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
Filter matcher = new Filter(null, null, new TopicMatcher(new String[]{}));
|
||||||
|
Filter message = new Filter(to, from, new TopicMatcher(topics));
|
||||||
|
|
||||||
|
assertTrue(matcher.match(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
Filter matcher = new Filter(to, null, new TopicMatcher(new String[]{}));
|
||||||
|
Filter message = new Filter(to, from, new TopicMatcher(topics));
|
||||||
|
|
||||||
|
assertTrue(matcher.match(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test3() {
|
||||||
|
Filter matcher = new Filter(to, null, new TopicMatcher(new String[]{}));
|
||||||
|
Filter message = new Filter(null, from, new TopicMatcher(topics));
|
||||||
|
|
||||||
|
assertTrue(!matcher.match(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test4() {
|
||||||
|
Filter matcher = new Filter(null, from, new TopicMatcher(new String[]{}));
|
||||||
|
Filter message = new Filter(to, from, new TopicMatcher(topics));
|
||||||
|
|
||||||
|
assertTrue(matcher.match(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test5() {
|
||||||
|
Filter matcher = new Filter(null, from, new TopicMatcher(new String[]{}));
|
||||||
|
Filter message = new Filter(to, null, new TopicMatcher(topics));
|
||||||
|
|
||||||
|
assertTrue(!matcher.match(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test6() {
|
||||||
|
Filter matcher = new Filter(null, from, new TopicMatcher(topics));
|
||||||
|
Filter message = new Filter(to, from, new TopicMatcher(topics));
|
||||||
|
|
||||||
|
assertTrue(matcher.match(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test7() {
|
||||||
|
Filter matcher = new Filter(null, null, new TopicMatcher(topics));
|
||||||
|
Filter message = new Filter(to, from, new TopicMatcher(new String[]{}));
|
||||||
|
|
||||||
|
assertTrue(!matcher.match(message));
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ package org.ethereum.net.shh;
|
|||||||
import org.ethereum.crypto.ECKey;
|
import org.ethereum.crypto.ECKey;
|
||||||
import org.ethereum.util.RLP;
|
import org.ethereum.util.RLP;
|
||||||
import org.ethereum.util.RLPList;
|
import org.ethereum.util.RLPList;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@ -14,14 +13,14 @@ import static org.junit.Assert.assertNotEquals;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by kest on 6/13/15.
|
* @author by Konstantin Shabalin
|
||||||
*/
|
*/
|
||||||
public class ShhTest {
|
public class ShhTest {
|
||||||
|
|
||||||
private byte[] payload = "Hello whisper!".getBytes();
|
private byte[] payload = "Hello whisper!".getBytes();
|
||||||
private ECKey privKey = ECKey.fromPrivate(BigInteger.TEN);
|
private ECKey privKey = ECKey.fromPrivate(BigInteger.TEN);
|
||||||
private byte[] pubKey = privKey.decompress().getPubKey();
|
private byte[] pubKey = privKey.decompress().getPubKey();
|
||||||
private long ttl = 10000;
|
private int ttl = 10000;
|
||||||
private Topic[] topics = new Topic[]{
|
private Topic[] topics = new Topic[]{
|
||||||
new Topic("topic 1"),
|
new Topic("topic 1"),
|
||||||
new Topic("topic 2"),
|
new Topic("topic 2"),
|
||||||
@ -32,7 +31,7 @@ public class ShhTest {
|
|||||||
public void test1() {
|
public void test1() {
|
||||||
Message sent = new Message(payload);
|
Message sent = new Message(payload);
|
||||||
Options options = new Options(null, null, topics, ttl);
|
Options options = new Options(null, null, topics, ttl);
|
||||||
Envelope e = sent.wrap(0, options);
|
Envelope e = sent.wrap(Options.DEFAULT_POW, options);
|
||||||
|
|
||||||
RLPList rlpList = RLP.decode2(e.getEncoded());
|
RLPList rlpList = RLP.decode2(e.getEncoded());
|
||||||
RLPList.recursivePrint(rlpList);
|
RLPList.recursivePrint(rlpList);
|
||||||
@ -52,7 +51,7 @@ public class ShhTest {
|
|||||||
public void test2() {
|
public void test2() {
|
||||||
Message sent = new Message(payload);
|
Message sent = new Message(payload);
|
||||||
Options options = new Options(privKey, null, topics, ttl);
|
Options options = new Options(privKey, null, topics, ttl);
|
||||||
Envelope e = sent.wrap(0, options);
|
Envelope e = sent.wrap(Options.DEFAULT_POW, options);
|
||||||
|
|
||||||
assertEquals(Hex.toHexString(e.getData()), Hex.toHexString(sent.getBytes()));
|
assertEquals(Hex.toHexString(e.getData()), Hex.toHexString(sent.getBytes()));
|
||||||
assertEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
assertEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
||||||
@ -68,7 +67,7 @@ public class ShhTest {
|
|||||||
public void test3() {
|
public void test3() {
|
||||||
Message sent = new Message(payload);
|
Message sent = new Message(payload);
|
||||||
Options options = new Options(null, pubKey, topics, ttl);
|
Options options = new Options(null, pubKey, topics, ttl);
|
||||||
Envelope e = sent.wrap(0, options);
|
Envelope e = sent.wrap(Options.DEFAULT_POW, options);
|
||||||
|
|
||||||
assertEquals(Hex.toHexString(e.getData()), Hex.toHexString(sent.getBytes()));
|
assertEquals(Hex.toHexString(e.getData()), Hex.toHexString(sent.getBytes()));
|
||||||
assertNotEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
assertNotEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
||||||
@ -86,7 +85,7 @@ public class ShhTest {
|
|||||||
public void test4() {
|
public void test4() {
|
||||||
Message sent = new Message(payload);
|
Message sent = new Message(payload);
|
||||||
Options options = new Options(privKey, pubKey, topics, ttl);
|
Options options = new Options(privKey, pubKey, topics, ttl);
|
||||||
Envelope e = sent.wrap(0, options);
|
Envelope e = sent.wrap(Options.DEFAULT_POW, options);
|
||||||
|
|
||||||
assertEquals(Hex.toHexString(e.getData()), Hex.toHexString(sent.getBytes()));
|
assertEquals(Hex.toHexString(e.getData()), Hex.toHexString(sent.getBytes()));
|
||||||
assertNotEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
assertNotEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
||||||
@ -100,4 +99,6 @@ public class ShhTest {
|
|||||||
assertEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
assertEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
||||||
assertEquals(Hex.toHexString(pubKey), Hex.toHexString(recovered.decompress().getPubKey()));
|
assertEquals(Hex.toHexString(pubKey), Hex.toHexString(recovered.decompress().getPubKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package org.ethereum.net.shh;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class TopicTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1(){
|
||||||
|
Topic topic = new Topic("cow");
|
||||||
|
assertEquals("c85ef7d7", Hex.toHexString(topic.getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2(){
|
||||||
|
Topic topic = new Topic("cowcowcow");
|
||||||
|
assertEquals("25068349", Hex.toHexString(topic.getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,6 +18,8 @@ import org.junit.Test;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Roman Mandeleil
|
* @author Roman Mandeleil
|
||||||
* @since 15.10.2014
|
* @since 15.10.2014
|
||||||
@ -39,61 +41,59 @@ public class AdaptiveMessageIdsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void test1() {
|
public void test1() {
|
||||||
|
|
||||||
Assert.assertEquals(7, P2pMessageCodes.values().length);
|
assertEquals(7, P2pMessageCodes.values().length);
|
||||||
|
|
||||||
Assert.assertEquals(0, P2pMessageCodes.HELLO.asByte());
|
assertEquals(0, P2pMessageCodes.HELLO.asByte());
|
||||||
Assert.assertEquals(1, P2pMessageCodes.DISCONNECT.asByte());
|
assertEquals(1, P2pMessageCodes.DISCONNECT.asByte());
|
||||||
Assert.assertEquals(2, P2pMessageCodes.PING.asByte());
|
assertEquals(2, P2pMessageCodes.PING.asByte());
|
||||||
Assert.assertEquals(3, P2pMessageCodes.PONG.asByte());
|
assertEquals(3, P2pMessageCodes.PONG.asByte());
|
||||||
Assert.assertEquals(4, P2pMessageCodes.GET_PEERS.asByte());
|
assertEquals(4, P2pMessageCodes.GET_PEERS.asByte());
|
||||||
Assert.assertEquals(5, P2pMessageCodes.PEERS.asByte());
|
assertEquals(5, P2pMessageCodes.PEERS.asByte());
|
||||||
Assert.assertEquals(15, P2pMessageCodes.USER.asByte());
|
assertEquals(15, P2pMessageCodes.USER.asByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test2() {
|
public void test2() {
|
||||||
|
|
||||||
Assert.assertEquals(9, EthMessageCodes.values().length);
|
assertEquals(8, EthMessageCodes.values().length);
|
||||||
|
|
||||||
Assert.assertEquals(0, EthMessageCodes.STATUS.asByte());
|
assertEquals(0, EthMessageCodes.STATUS.asByte());
|
||||||
Assert.assertEquals(1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
assertEquals(1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||||
Assert.assertEquals(2, EthMessageCodes.TRANSACTIONS.asByte());
|
assertEquals(2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||||
Assert.assertEquals(3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
assertEquals(3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||||
Assert.assertEquals(4, EthMessageCodes.BLOCK_HASHES.asByte());
|
assertEquals(4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||||
Assert.assertEquals(5, EthMessageCodes.GET_BLOCKS.asByte());
|
assertEquals(5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||||
Assert.assertEquals(6, EthMessageCodes.BLOCKS.asByte());
|
assertEquals(6, EthMessageCodes.BLOCKS.asByte());
|
||||||
Assert.assertEquals(7, EthMessageCodes.NEW_BLOCK.asByte());
|
assertEquals(7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||||
Assert.assertEquals(8, EthMessageCodes.PACKET_COUNT.asByte());
|
|
||||||
|
|
||||||
EthMessageCodes.setOffset((byte) 0x10);
|
EthMessageCodes.setOffset((byte) 0x10);
|
||||||
Assert.assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||||
Assert.assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||||
Assert.assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||||
Assert.assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||||
Assert.assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||||
Assert.assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||||
Assert.assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||||
Assert.assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||||
Assert.assertEquals(0x10 + 8, EthMessageCodes.PACKET_COUNT.asByte());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test3() {
|
public void test3() {
|
||||||
|
|
||||||
Assert.assertEquals(5, ShhMessageCodes.values().length);
|
assertEquals(5, ShhMessageCodes.values().length);
|
||||||
|
|
||||||
Assert.assertEquals(0, ShhMessageCodes.STATUS.asByte());
|
assertEquals(0, ShhMessageCodes.STATUS.asByte());
|
||||||
Assert.assertEquals(1, ShhMessageCodes.MESSAGE.asByte());
|
assertEquals(1, ShhMessageCodes.MESSAGE.asByte());
|
||||||
Assert.assertEquals(2, ShhMessageCodes.ADD_FILTER.asByte());
|
assertEquals(2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||||
Assert.assertEquals(3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
assertEquals(3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||||
Assert.assertEquals(4, ShhMessageCodes.PACKET_COUNT.asByte());
|
assertEquals(4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||||
|
|
||||||
ShhMessageCodes.setOffset((byte) 0x20);
|
ShhMessageCodes.setOffset((byte) 0x20);
|
||||||
Assert.assertEquals(0x20 + 0, ShhMessageCodes.STATUS.asByte());
|
assertEquals(0x20 + 0, ShhMessageCodes.STATUS.asByte());
|
||||||
Assert.assertEquals(0x20 + 1, ShhMessageCodes.MESSAGE.asByte());
|
assertEquals(0x20 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||||
Assert.assertEquals(0x20 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
assertEquals(0x20 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||||
Assert.assertEquals(0x20 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
assertEquals(0x20 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||||
Assert.assertEquals(0x20 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
assertEquals(0x20 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -106,21 +106,20 @@ public class AdaptiveMessageIdsTest {
|
|||||||
new Capability(Capability.SHH, ShhHandler.VERSION));
|
new Capability(Capability.SHH, ShhHandler.VERSION));
|
||||||
p2pHandler.adaptMessageIds(capabilities);
|
p2pHandler.adaptMessageIds(capabilities);
|
||||||
|
|
||||||
Assert.assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||||
Assert.assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||||
Assert.assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||||
Assert.assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||||
Assert.assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||||
Assert.assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||||
Assert.assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||||
Assert.assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||||
Assert.assertEquals(0x10 + 8, EthMessageCodes.PACKET_COUNT.asByte());
|
|
||||||
|
|
||||||
Assert.assertEquals(0x19 + 0, ShhMessageCodes.STATUS.asByte());
|
assertEquals(0x18 + 0, ShhMessageCodes.STATUS.asByte());
|
||||||
Assert.assertEquals(0x19 + 1, ShhMessageCodes.MESSAGE.asByte());
|
assertEquals(0x18 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||||
Assert.assertEquals(0x19 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
assertEquals(0x18 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||||
Assert.assertEquals(0x19 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
assertEquals(0x18 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||||
Assert.assertEquals(0x19 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
assertEquals(0x18 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // Capabilities should be read in alphabetical order
|
@Test // Capabilities should be read in alphabetical order
|
||||||
@ -133,20 +132,19 @@ public class AdaptiveMessageIdsTest {
|
|||||||
new Capability(Capability.ETH, EthHandler.VERSION));
|
new Capability(Capability.ETH, EthHandler.VERSION));
|
||||||
p2pHandler.adaptMessageIds(capabilities);
|
p2pHandler.adaptMessageIds(capabilities);
|
||||||
|
|
||||||
Assert.assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||||
Assert.assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||||
Assert.assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||||
Assert.assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||||
Assert.assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||||
Assert.assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||||
Assert.assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||||
Assert.assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||||
Assert.assertEquals(0x10 + 8, EthMessageCodes.PACKET_COUNT.asByte());
|
|
||||||
|
|
||||||
Assert.assertEquals(0x19 + 0, ShhMessageCodes.STATUS.asByte());
|
assertEquals(0x18 + 0, ShhMessageCodes.STATUS.asByte());
|
||||||
Assert.assertEquals(0x19 + 1, ShhMessageCodes.MESSAGE.asByte());
|
assertEquals(0x18 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||||
Assert.assertEquals(0x19 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
assertEquals(0x18 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||||
Assert.assertEquals(0x19 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
assertEquals(0x18 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||||
Assert.assertEquals(0x19 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
assertEquals(0x18 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
package org.ethereum.serpent;
|
|
||||||
|
|
||||||
import org.ethereum.serpent.SerpentCompiler;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.spongycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Roman Mandeleil
|
|
||||||
* @since 28.05.2014
|
|
||||||
*/
|
|
||||||
public class MachineCompileTest {
|
|
||||||
|
|
||||||
@Test // very simple contract
|
|
||||||
public void test1() {
|
|
||||||
|
|
||||||
String code = "a=2";
|
|
||||||
String expected = "6005600c60003960056000f36002600052";
|
|
||||||
String asm = SerpentCompiler.compile(code);
|
|
||||||
byte[] machineCode = SerpentCompiler.compileAssemblyToMachine(asm);
|
|
||||||
byte[] vmReadyCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null);
|
|
||||||
|
|
||||||
String result = Hex.toHexString(vmReadyCode);
|
|
||||||
assertEquals(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // contract for 256 bytes (len 2 bytes)
|
|
||||||
public void test2() {
|
|
||||||
|
|
||||||
String code = "a=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\na=2\n[asm PUSH10 asm]";
|
|
||||||
String expected = "610100600e6000396101006000f360026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005260026000526002600052600260005269";
|
|
||||||
String asm = SerpentCompiler.compile(code);
|
|
||||||
byte[] machineCode = SerpentCompiler.compileAssemblyToMachine(asm);
|
|
||||||
byte[] vmReadyCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null);
|
|
||||||
|
|
||||||
String result = Hex.toHexString(vmReadyCode);
|
|
||||||
|
|
||||||
assertEquals(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // contract for if jump
|
|
||||||
public void test3() {
|
|
||||||
|
|
||||||
String code = "a=2\n" +
|
|
||||||
"if a>0:\n" +
|
|
||||||
" b = 3\n" +
|
|
||||||
"else: \n" +
|
|
||||||
" c = 4";
|
|
||||||
// String expected = "610100600e6000396101006000f260026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005469";
|
|
||||||
String asm = SerpentCompiler.compile(code);
|
|
||||||
byte[] machineCode = SerpentCompiler.compileAssemblyToMachine(asm);
|
|
||||||
byte[] vmReadyCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null);
|
|
||||||
|
|
||||||
System.out.println(asm);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1397,6 +1397,11 @@ public class TrieTest {
|
|||||||
String root2 = Hex.toHexString(trie2.getRootHash());
|
String root2 = Hex.toHexString(trie2.getRootHash());
|
||||||
assertEquals("d7b597b334b78c63ddf7beafc96484f5604472c40d438ea514882fab0813f074", root2);
|
assertEquals("d7b597b334b78c63ddf7beafc96484f5604472c40d438ea514882fab0813f074", root2);
|
||||||
|
|
||||||
|
String dump1 = trie.getTrieDump();
|
||||||
|
String dump2 = trie2.getTrieDump();
|
||||||
|
|
||||||
|
assertEquals(dump1, dump2);
|
||||||
|
|
||||||
// bug that updates the value somewhere before 505k flush
|
// bug that updates the value somewhere before 505k flush
|
||||||
trie2.update(Hex.decode("8c8998c70d860b06ebe80ce22500ec1192083a59ca111194cf2a7612d84b0e2a"), RLP.encodeElement(Hex.decode("0166")));
|
trie2.update(Hex.decode("8c8998c70d860b06ebe80ce22500ec1192083a59ca111194cf2a7612d84b0e2a"), RLP.encodeElement(Hex.decode("0166")));
|
||||||
String root3 = Hex.toHexString(trie2.getRootHash());
|
String root3 = Hex.toHexString(trie2.getRootHash());
|
||||||
|
@ -141,8 +141,8 @@ root.hash.start = -1
|
|||||||
# if set true, json tests will be loaded from local repository
|
# if set true, json tests will be loaded from local repository
|
||||||
GitHubTests.VMTest.loadLocal = false
|
GitHubTests.VMTest.loadLocal = false
|
||||||
|
|
||||||
# Key value data source values: [leveldb/redis]
|
# Key value data source values: [leveldb/redis/mapdb]
|
||||||
keyvalue.datasource = leveldb
|
keyvalue.datasource = mapdb
|
||||||
|
|
||||||
# structured trace
|
# structured trace
|
||||||
# is the trace being
|
# is the trace being
|
||||||
|
Loading…
x
Reference in New Issue
Block a user