mirror of
https://github.com/status-im/ethereumj-personal.git
synced 2025-02-19 15:14:14 +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 EthereumConnector ethereum = null;
|
||||
public String log="";
|
||||
|
||||
@Override public void onCreate() {
|
||||
|
||||
|
@ -154,8 +154,13 @@ public class RemoteMainActivity extends ActionBarActivity implements ActivityInt
|
||||
|
||||
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) {
|
||||
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: "redis.clients", module: "jedis"
|
||||
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"
|
||||
|
@ -51,7 +51,7 @@
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
<logger name="db" level="ERROR">
|
||||
<logger name="db" level="DEBUG">
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
@ -87,7 +87,7 @@
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
<logger name="general" level="ERROR">
|
||||
<logger name="general" level="DEBUG">
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
@ -99,19 +99,19 @@
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
<logger name="main" level="ERROR">
|
||||
<logger name="main" level="DEBUG">
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
<logger name="state" level="ERROR">
|
||||
<logger name="state" level="DEBUG">
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
<logger name="repository" level="ERROR">
|
||||
<logger name="repository" level="DEBUG">
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
<logger name="blockchain" level="ERROR">
|
||||
<logger name="blockchain" level="DEBUG">
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
@ -127,7 +127,7 @@
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
<logger name="hsqldb.db" level="ERROR">
|
||||
<logger name="hsqldb.db" level="DEBUG">
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
@ -135,7 +135,7 @@
|
||||
<appender-ref ref="logcat" />
|
||||
</logger>
|
||||
|
||||
<root level="INFO">
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="logcat" />
|
||||
</root>
|
||||
|
||||
|
@ -19,7 +19,9 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
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
|
||||
@ -55,6 +57,7 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
||||
logger.debug("Opening database");
|
||||
File dbLocation = new File(SystemProperties.CONFIG.databaseDir());
|
||||
File fileLocation = new File(dbLocation, name);
|
||||
if (!dbLocation.exists()) dbLocation.mkdirs();
|
||||
|
||||
if (SystemProperties.CONFIG.databaseReset()) {
|
||||
destroyDB(fileLocation);
|
||||
|
@ -137,8 +137,8 @@ public class EthereumModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
ShhHandler provideShhHandler(EthereumListener listener) {
|
||||
return new ShhHandler(listener);
|
||||
ShhHandler provideShhHandler(WorldManager worldManager) {
|
||||
return new ShhHandler(worldManager);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
@ -5,7 +5,7 @@ import com.thetransactioncompany.jsonrpc2.server.*;
|
||||
import org.ethereum.android.jsonrpc.full.JsonRpcServerMethod;
|
||||
import org.ethereum.core.AccountState;
|
||||
import org.ethereum.facade.Ethereum;
|
||||
import org.ethereum.serpent.SerpentCompiler;
|
||||
//import org.ethereum.serpent.SerpentCompiler;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
@ -35,12 +35,12 @@ public class eth_compileSerpent extends JsonRpcServerMethod {
|
||||
Pattern pattern = Pattern.compile("(.*?)init:(.*?)code:(.*?)", Pattern.DOTALL);
|
||||
Matcher matcher = pattern.matcher(code);
|
||||
if (matcher.find()) {
|
||||
asmResult = SerpentCompiler.compileFullNotion(code);
|
||||
machineCode = SerpentCompiler.compileFullNotionAssemblyToMachine(asmResult);
|
||||
//asmResult = SerpentCompiler.compileFullNotion(code);
|
||||
//machineCode = SerpentCompiler.compileFullNotionAssemblyToMachine(asmResult);
|
||||
} else {
|
||||
asmResult = SerpentCompiler.compile(code);
|
||||
machineCode = SerpentCompiler.compileAssemblyToMachine(asmResult);
|
||||
machineCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null);
|
||||
//asmResult = SerpentCompiler.compile(code);
|
||||
//machineCode = SerpentCompiler.compileAssemblyToMachine(asmResult);
|
||||
//machineCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null);
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
return new JSONRPC2Response(JSONRPC2Error.INTERNAL_ERROR, req.getID());
|
||||
|
@ -444,7 +444,7 @@ public class EthereumRemoteService extends EthereumService {
|
||||
String identifier = ((Bundle)message.obj).getString("identifier");
|
||||
clientListeners.put(identifier, message.replyTo);
|
||||
Bundle data = message.getData();
|
||||
data.setClassLoader(EnumSet.class.getClassLoader());
|
||||
data.setClassLoader(EventFlag.class.getClassLoader());
|
||||
EnumSet<EventFlag> flags = (EnumSet<EventFlag>)data.getSerializable("flags");
|
||||
EnumSet<EventFlag> list = (flags == null || flags.contains(EventFlag.EVENT_ALL)) ? EnumSet.allOf(EventFlag.class) : flags;
|
||||
for (EventFlag flag: list) {
|
||||
|
@ -54,7 +54,13 @@ public class PendingTransactionsEventData extends EventData {
|
||||
private PendingTransactionsEventData(Parcel 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 'jacoco'
|
||||
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.jfrog.bintray' version '1.0'
|
||||
}
|
||||
@ -30,7 +29,7 @@ repositories {
|
||||
sourceCompatibility = 1.7
|
||||
|
||||
mainClassName = 'org.ethereum.Start'
|
||||
applicationDefaultJvmArgs = ["-server", "-Xss32m"]
|
||||
applicationDefaultJvmArgs = ["-server", "-Xss32m", "-Xms3500m"]
|
||||
|
||||
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){
|
||||
options.warnings = false
|
||||
@ -108,10 +90,6 @@ test {
|
||||
systemProperty "file.encoding", "UTF-8"
|
||||
}
|
||||
|
||||
configurations {
|
||||
compile.extendsFrom antlr4
|
||||
}
|
||||
|
||||
ext {
|
||||
slf4jVersion = '1.7.12'
|
||||
leveldbVersion = '0.7'
|
||||
@ -133,9 +111,10 @@ dependencies {
|
||||
|
||||
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 "org.antlr:antlr4-runtime:4.5" // for serpent compilation
|
||||
compile "com.yuvalshavit:antlr-denter:1.1"
|
||||
compile "org.javassist:javassist:3.15.0-GA"
|
||||
compile "org.slf4j:slf4j-api:${slf4jVersion}"
|
||||
compile "log4j:log4j:${log4jVersion}"
|
||||
@ -149,7 +128,9 @@ dependencies {
|
||||
compile "commons-dbcp:commons-dbcp:1.4"
|
||||
compile "redis.clients:jedis:2.6.0"
|
||||
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 "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)) {
|
||||
repository.flush();
|
||||
blockStore.flush();
|
||||
System.gc();
|
||||
}
|
||||
|
||||
// Remove all wallet transactions as they already approved by the net
|
||||
@ -322,7 +323,7 @@ public class BlockchainImpl implements Blockchain {
|
||||
private boolean needFlush(Block block) {
|
||||
boolean isBatchReached = block.getNumber() % CONFIG.flushBatchSize() == 0;
|
||||
boolean isConsensus = CONFIG.flushIgnoreConsensus() || adminInfo.isConsensus();
|
||||
|
||||
|
||||
return isConsensus && isBatchReached;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
} catch (Throwable e) {
|
||||
|
||||
|
@ -1,24 +1,19 @@
|
||||
package org.ethereum.datasource;
|
||||
|
||||
import org.ethereum.config.SystemProperties;
|
||||
|
||||
import org.iq80.leveldb.CompressionType;
|
||||
import org.iq80.leveldb.DB;
|
||||
import org.iq80.leveldb.DBIterator;
|
||||
import org.iq80.leveldb.Options;
|
||||
import org.iq80.leveldb.WriteBatch;
|
||||
|
||||
import org.iq80.leveldb.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
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
|
||||
@ -55,6 +50,7 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
||||
File dbLocation = new File(System.getProperty("user.dir") + "/" +
|
||||
SystemProperties.CONFIG.databaseDir() + "/");
|
||||
File fileLocation = new File(dbLocation, name);
|
||||
if (!dbLocation.exists()) dbLocation.mkdirs();
|
||||
|
||||
if (SystemProperties.CONFIG.databaseReset()) {
|
||||
destroyDB(fileLocation);
|
||||
@ -104,26 +100,33 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
||||
|
||||
@Override
|
||||
public Set<byte[]> keys() {
|
||||
try {
|
||||
try (DBIterator dbIterator = db.iterator()) {
|
||||
Set<byte[]> keys = new HashSet<>();
|
||||
while (dbIterator.hasNext()) {
|
||||
keys.add(dbIterator.next().getKey());
|
||||
}
|
||||
|
||||
DBIterator dbIterator = db.iterator();
|
||||
Set<byte[]> keys = new HashSet<>();
|
||||
while (dbIterator.hasNext()) {
|
||||
|
||||
Map.Entry<byte[], byte[]> entry = dbIterator.next();
|
||||
keys.add(entry.getKey());
|
||||
return keys;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBatch(Map<byte[], byte[]> rows) {
|
||||
try {
|
||||
try (WriteBatch batch = db.createWriteBatch()) {
|
||||
for (Map.Entry<byte[], byte[]> row : rows.entrySet()) {
|
||||
batch.put(row.getKey(), row.getValue());
|
||||
}
|
||||
|
||||
WriteBatch batch = db.createWriteBatch();
|
||||
|
||||
for (Map.Entry<byte[], byte[]> row : rows.entrySet())
|
||||
batch.put(row.getKey(), row.getValue());
|
||||
|
||||
db.write(batch);
|
||||
db.write(batch);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,25 +2,22 @@ package org.ethereum.datasource.mapdb;
|
||||
|
||||
import org.ethereum.config.SystemProperties;
|
||||
import org.ethereum.datasource.KeyValueDataSource;
|
||||
import org.ethereum.db.ByteArrayWrapper;
|
||||
import org.mapdb.DB;
|
||||
import org.mapdb.DBMaker;
|
||||
import org.mapdb.HTreeMap;
|
||||
import org.mapdb.Serializer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.lang.System.getProperty;
|
||||
import static org.ethereum.util.ByteUtil.wrap;
|
||||
|
||||
public class MapDBDataSource implements KeyValueDataSource {
|
||||
|
||||
private static final int BATCH_SIZE = 1024 * 1000 * 10;
|
||||
|
||||
|
||||
private DB db;
|
||||
private HTreeMap<ByteArrayWrapper, byte[]> map;
|
||||
private Map<byte[], byte[]> map;
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
@ -30,16 +27,16 @@ public class MapDBDataSource implements KeyValueDataSource {
|
||||
dbLocation.mkdirs();
|
||||
}
|
||||
|
||||
db = DBMaker.newFileDB(new File(dbLocation, name))
|
||||
.asyncWriteEnable()
|
||||
.mmapFileEnableIfSupported()
|
||||
// .compressionEnable()
|
||||
.cacheDisable()
|
||||
// .asyncWriteFlushDelay(1000)
|
||||
|
||||
db = DBMaker.fileDB(new File(dbLocation, name))
|
||||
.transactionDisable()
|
||||
.closeOnJvmShutdown()
|
||||
.make();
|
||||
|
||||
this.map = db.createHashMap(name).makeOrGet();
|
||||
this.map = db.hashMapCreate(name)
|
||||
.keySerializer(Serializer.BYTE_ARRAY)
|
||||
.valueSerializer(Serializer.BYTE_ARRAY)
|
||||
.makeOrGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -49,13 +46,13 @@ public class MapDBDataSource implements KeyValueDataSource {
|
||||
|
||||
@Override
|
||||
public byte[] get(byte[] key) {
|
||||
return map.get(wrap(key));
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] put(byte[] key, byte[] value) {
|
||||
try {
|
||||
return map.put(wrap(key), value);
|
||||
return map.put(key, value);
|
||||
} finally {
|
||||
db.commit();
|
||||
}
|
||||
@ -72,11 +69,7 @@ public class MapDBDataSource implements KeyValueDataSource {
|
||||
|
||||
@Override
|
||||
public Set<byte[]> keys() {
|
||||
HashSet<byte[]> result = new HashSet<>();
|
||||
for (ByteArrayWrapper key : map.keySet()) {
|
||||
result.add(key.getData());
|
||||
}
|
||||
return result;
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,8 +79,8 @@ public class MapDBDataSource implements KeyValueDataSource {
|
||||
for (byte[] key : rows.keySet()) {
|
||||
byte[] value = rows.get(key);
|
||||
savedSize += value.length;
|
||||
|
||||
map.put(wrap(key), value);
|
||||
|
||||
map.put(key, value);
|
||||
if (savedSize > BATCH_SIZE) {
|
||||
db.commit();
|
||||
savedSize = 0;
|
||||
|
@ -28,6 +28,8 @@ public interface Database {
|
||||
*/
|
||||
public void delete(byte[] key);
|
||||
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Close the database connection
|
||||
*/
|
||||
|
@ -64,6 +64,11 @@ public class DatabaseImpl implements Database {
|
||||
return this.keyValueDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
keyValueDataSource.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
|
@ -4,6 +4,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@ -11,7 +13,6 @@ import java.util.Set;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.ethereum.util.ByteUtil.wrap;
|
||||
import static org.spongycastle.util.encoders.Hex.decode;
|
||||
|
||||
public class DetailsDataStore {
|
||||
|
||||
@ -64,15 +65,10 @@ public class DetailsDataStore {
|
||||
public void flush() {
|
||||
long keys = cache.size();
|
||||
|
||||
ByteArrayWrapper largeDetailsKey = wrap(decode("b61662398570293e4f0d25525e2b3002b7fe0836"));
|
||||
ContractDetails largeDetails = cache.get(largeDetailsKey);
|
||||
|
||||
long start = System.nanoTime();
|
||||
long totalSize = flushInternal();
|
||||
long finish = System.nanoTime();
|
||||
|
||||
if (largeDetails != null) cache.put(largeDetailsKey, largeDetails);
|
||||
|
||||
float flushSize = (float) totalSize / 1_048_576;
|
||||
float flushTime = (float) (finish - start) / 1_000_000;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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() {
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -124,8 +124,8 @@ public class EthereumModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
ShhHandler provideShhHandler(EthereumListener listener) {
|
||||
return new ShhHandler(listener);
|
||||
ShhHandler provideShhHandler(WorldManager worldManager) {
|
||||
return new ShhHandler(worldManager);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
@ -62,12 +62,13 @@ public class BlockLoader {
|
||||
if (block.getNumber() % 10000 == 0)
|
||||
System.out.println("Skipping block #" + block.getNumber());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println(" * Done * ");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -148,8 +148,6 @@ public class EthHandler extends SimpleChannelInboundHandler<EthMessage> {
|
||||
case NEW_BLOCK:
|
||||
msgQueue.receivedMessage(msg);
|
||||
processNewBlock((NewBlockMessage) msg);
|
||||
case PACKET_COUNT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -74,12 +74,8 @@ public enum EthMessageCodes {
|
||||
* in the list (following the message ID) is a block in the format described
|
||||
* in the main Ethereum specification.
|
||||
*/
|
||||
NEW_BLOCK(0x07),
|
||||
NEW_BLOCK(0x07);
|
||||
|
||||
/**
|
||||
* [+0x08
|
||||
*/
|
||||
PACKET_COUNT(0X08);
|
||||
|
||||
static byte OFFSET = 0;
|
||||
private int cmd;
|
||||
@ -101,7 +97,7 @@ public enum EthMessageCodes {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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;
|
||||
|
||||
import org.ethereum.net.eth.BlockHashesMessage;
|
||||
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.eth.*;
|
||||
import org.ethereum.net.p2p.DisconnectMessage;
|
||||
import org.ethereum.net.p2p.HelloMessage;
|
||||
import org.ethereum.net.p2p.P2pMessageCodes;
|
||||
import org.ethereum.net.p2p.PeersMessage;
|
||||
import org.ethereum.net.shh.Envelope;
|
||||
import org.ethereum.net.shh.ShhMessageCodes;
|
||||
import org.ethereum.util.RLP;
|
||||
|
||||
/**
|
||||
* Factory to create protocol message objects based on the RLP encoded data
|
||||
@ -62,8 +54,6 @@ public class MessageFactory {
|
||||
return new BlocksMessage(encoded);
|
||||
case NEW_BLOCK:
|
||||
return new NewBlockMessage(encoded);
|
||||
case PACKET_COUNT:
|
||||
return new PacketCountMessage(encoded);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,9 +62,9 @@ public class MessageFactory {
|
||||
ShhMessageCodes receivedCommand = ShhMessageCodes.fromByte(code);
|
||||
switch (receivedCommand) {
|
||||
case STATUS:
|
||||
break;
|
||||
return new org.ethereum.net.shh.StatusMessage(encoded);
|
||||
case MESSAGE:
|
||||
break;
|
||||
return new Envelope(encoded);
|
||||
case ADD_FILTER:
|
||||
break;
|
||||
case REMOVE_FILTER:
|
||||
|
@ -211,9 +211,9 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
capability.getVersion() == ShhHandler.VERSION) {
|
||||
|
||||
// Activate ShhHandler for this peer
|
||||
// ShhHandler shhHandler =
|
||||
// (ShhHandler) ctx.pipeline().get(Capability.SHH);
|
||||
// shhHandler.activate();
|
||||
ShhHandler shhHandler = channel.getShhHandler();
|
||||
ctx.pipeline().addLast(Capability.SHH, shhHandler);
|
||||
shhHandler.activate();
|
||||
}
|
||||
capInCommon.add(capability);
|
||||
}
|
||||
@ -256,17 +256,17 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
public void adaptMessageIds(List<Capability> capabilities) {
|
||||
|
||||
Collections.sort(capabilities);
|
||||
byte offset = (byte) (P2pMessageCodes.USER.asByte() + 1);
|
||||
int offset = P2pMessageCodes.USER.asByte() + 1;
|
||||
|
||||
for (Capability capability : capabilities) {
|
||||
|
||||
if (capability.getName().equals(Capability.ETH)) {
|
||||
EthMessageCodes.setOffset(offset);
|
||||
EthMessageCodes.setOffset((byte)offset);
|
||||
offset += EthMessageCodes.values().length;
|
||||
}
|
||||
|
||||
if (capability.getName().equals(Capability.SHH)) {
|
||||
ShhMessageCodes.setOffset(offset);
|
||||
ShhMessageCodes.setOffset((byte)offset);
|
||||
offset += ShhMessageCodes.values().length;
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,12 @@ import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import org.antlr.v4.runtime.misc.Triple;
|
||||
import org.ethereum.crypto.ECKey;
|
||||
import org.ethereum.net.rlpx.*;
|
||||
import org.ethereum.net.rlpx.discover.table.KademliaOptions;
|
||||
import org.ethereum.net.rlpx.discover.table.NodeTable;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -7,22 +7,18 @@ import org.ethereum.util.RLPElement;
|
||||
import org.ethereum.util.RLPList;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import java.util.*;
|
||||
|
||||
import static org.ethereum.net.shh.ShhMessageCodes.MESSAGE;
|
||||
import static org.ethereum.crypto.HashUtil.sha3;
|
||||
|
||||
/**
|
||||
* Created by kest on 6/12/15.
|
||||
* @author by Konstantin Shabalin
|
||||
*/
|
||||
public class Envelope extends ShhMessage {
|
||||
|
||||
private long expire;
|
||||
private long ttl;
|
||||
private int expire;
|
||||
private int ttl;
|
||||
|
||||
private Topic[] topics;
|
||||
private byte[] data;
|
||||
@ -33,8 +29,8 @@ public class Envelope extends ShhMessage {
|
||||
super(encoded);
|
||||
}
|
||||
|
||||
public Envelope(long ttl, Topic[] topics, Message msg) {
|
||||
this.expire = System.currentTimeMillis() + ttl;
|
||||
public Envelope(int ttl, Topic[] topics, Message msg) {
|
||||
this.expire = (int)(System.currentTimeMillis()/1000 + ttl);
|
||||
this.ttl = ttl;
|
||||
this.topics = topics;
|
||||
this.data = msg.getBytes();
|
||||
@ -45,12 +41,14 @@ public class Envelope extends ShhMessage {
|
||||
if (!parsed) {
|
||||
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());
|
||||
|
||||
if ((m.getFlags() & Message.SIGNATURE_FLAG) == Message.SIGNATURE_FLAG) {
|
||||
if ((flags & Message.SIGNATURE_FLAG) == Message.SIGNATURE_FLAG) {
|
||||
if (data.length < Message.SIGNATURE_LENGTH) {
|
||||
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;
|
||||
}
|
||||
|
||||
m.decrypt(privKey);
|
||||
if (!m.decrypt(privKey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
if (encoded == null) encode();
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
if (isEmpty()) return;
|
||||
|
||||
this.expire = ByteUtil.byteArrayToLong(paramsList.get(0).getRLPData());
|
||||
this.ttl = ByteUtil.byteArrayToLong(paramsList.get(1).getRLPData());
|
||||
RLPList paramsList = (RLPList)((RLPList) RLP.decode2(encoded).get(0)).get(0);
|
||||
|
||||
this.expire = ByteUtil.byteArrayToInt(paramsList.get(0).getRLPData());
|
||||
this.ttl = ByteUtil.byteArrayToInt(paramsList.get(1).getRLPData());
|
||||
|
||||
List<Topic> topics = new ArrayList<>();
|
||||
RLPList topicsList = (RLPList) RLP.decode2(paramsList.get(2).getRLPData()).get(0);
|
||||
@ -98,7 +100,7 @@ public class Envelope extends ShhMessage {
|
||||
|
||||
private void encode() {
|
||||
byte[] expire = RLP.encode(this.expire);
|
||||
byte[] ttl = RLP.encode(this.expire);
|
||||
byte[] ttl = RLP.encode(this.ttl);
|
||||
|
||||
List<byte[]> topics = new Vector<>();
|
||||
for (Topic t : this.topics) {
|
||||
@ -110,38 +112,48 @@ public class Envelope extends ShhMessage {
|
||||
byte[] data = RLP.encodeElement(this.data);
|
||||
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) {
|
||||
byte[] d = new byte[64];
|
||||
Arrays.fill(d, (byte) 0);
|
||||
byte[] rlp = encodeWithoutNonce();
|
||||
encode();
|
||||
byte[] rlp = this.encoded;
|
||||
int l = rlp.length < 32 ? rlp.length : 32;
|
||||
System.arraycopy(rlp, 0, d, 0, l);
|
||||
|
||||
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() {
|
||||
@ -177,6 +189,22 @@ public class Envelope extends ShhMessage {
|
||||
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
|
||||
public ShhMessageCodes getCommand() {
|
||||
return MESSAGE;
|
||||
@ -195,6 +223,17 @@ public class Envelope extends ShhMessage {
|
||||
|
||||
@Override
|
||||
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.math.ec.ECPoint;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Random;
|
||||
|
||||
@ -14,20 +16,23 @@ import static org.ethereum.net.shh.ShhMessageCodes.MESSAGE;
|
||||
import static org.ethereum.util.ByteUtil.merge;
|
||||
|
||||
/**
|
||||
* Created by kest on 6/12/15.
|
||||
* @author by Konstantin Shabalin
|
||||
*/
|
||||
public class Message extends ShhMessage {
|
||||
|
||||
private byte flags;
|
||||
private byte[] signature;
|
||||
private byte[] payload;
|
||||
private byte[] to;
|
||||
|
||||
private long sent;
|
||||
private long ttl;
|
||||
private int sent;
|
||||
private int ttl;
|
||||
|
||||
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 Message(byte[] encoded) {
|
||||
@ -39,21 +44,24 @@ public class Message extends ShhMessage {
|
||||
Random r = new Random();
|
||||
byte[] randByte = new byte[1];
|
||||
r.nextBytes(randByte);
|
||||
flags = randByte[0];
|
||||
if (flags < 0) {
|
||||
flags = (byte)(flags & 0xF);
|
||||
}
|
||||
int flags = r.nextInt(256);
|
||||
// if (flags < 0) {
|
||||
// flags = (byte)(flags & 0xF);
|
||||
// }
|
||||
flags &= ~SIGNATURE_FLAG;
|
||||
|
||||
this.sent = System.currentTimeMillis();
|
||||
this.sent = (int) (System.currentTimeMillis()/1000);
|
||||
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.sent = sent;
|
||||
this.ttl = ttl;
|
||||
this.envelopeHash = envelopeHash;
|
||||
this.decrypted = false;
|
||||
}
|
||||
|
||||
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);
|
||||
e.seal(pow);
|
||||
return e;
|
||||
}
|
||||
|
||||
public byte[] getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public void setTo(byte[] to) {
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public byte getFlags() {
|
||||
return flags;
|
||||
}
|
||||
@ -103,6 +120,7 @@ public class Message extends ShhMessage {
|
||||
ECKey key = ECKey.fromPublicOnly(toPublicKey);
|
||||
ECPoint pubKeyPoint = key.getPubKeyPoint();
|
||||
payload = ECIESCoder.encrypt(pubKeyPoint, payload);
|
||||
this.decrypted = true;
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
@ -111,6 +129,8 @@ public class Message extends ShhMessage {
|
||||
public boolean decrypt(ECKey privateKey) {
|
||||
try {
|
||||
payload = ECIESCoder.decrypt(privateKey.getPrivKey(), payload);
|
||||
this.decrypted = false;
|
||||
setTo(privateKey.decompress().getPubKey());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
System.out.println("The message payload isn't encrypted or something is wrong");
|
||||
@ -159,6 +179,14 @@ public class Message extends ShhMessage {
|
||||
return outKey;
|
||||
}
|
||||
|
||||
public byte[] getPubKey() {
|
||||
ECKey key = recover();
|
||||
if (key != null) {
|
||||
return key.decompress().getPubKey();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] hash() {
|
||||
return sha3(merge(new byte[]{flags}, payload));
|
||||
}
|
||||
@ -180,7 +208,20 @@ public class Message extends ShhMessage {
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
/**
|
||||
* Created by kest on 6/13/15.
|
||||
* @author by Konstantin Shabalin
|
||||
*/
|
||||
public class Options {
|
||||
|
||||
public static int DEFAULT_TTL = 100;
|
||||
public static int DEFAULT_POW = 50;
|
||||
|
||||
private ECKey privateKey;
|
||||
private byte[] toPublicKey;
|
||||
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.toPublicKey = toPublicKey;
|
||||
this.topics = topics;
|
||||
@ -42,11 +46,11 @@ public class Options {
|
||||
this.topics = topics;
|
||||
}
|
||||
|
||||
public long getTtl() {
|
||||
public int getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
public void setTtl(long ttl) {
|
||||
public void setTtl(int ttl) {
|
||||
this.ttl = ttl;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
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 io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
import org.ethereum.net.eth.*;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -18,25 +22,32 @@ import javax.inject.Inject;
|
||||
*/
|
||||
public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
||||
|
||||
public final static byte VERSION = 1;
|
||||
public final static byte VERSION = 2;
|
||||
private MessageQueue msgQueue = null;
|
||||
private ECKey privKey;
|
||||
|
||||
private Whisper whisper;
|
||||
|
||||
private boolean active = false;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger("net");
|
||||
|
||||
|
||||
public EthereumListener listener;
|
||||
WorldManager worldManager;
|
||||
|
||||
@Inject
|
||||
public ShhHandler(EthereumListener listener) {
|
||||
this.listener = listener;
|
||||
public ShhHandler(WorldManager worldManager) {
|
||||
this.worldManager = worldManager;
|
||||
}
|
||||
|
||||
public ShhHandler(MessageQueue msgQueue) {
|
||||
this.msgQueue = msgQueue;
|
||||
}
|
||||
|
||||
public void setPrivKey(ECKey privKey) {
|
||||
this.privKey = privKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
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()))
|
||||
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()) {
|
||||
case STATUS:
|
||||
worldManager.getListener().trace("[Recv: " + msg + "]");
|
||||
break;
|
||||
case MESSAGE:
|
||||
whisper.processEnvelope((Envelope) msg);
|
||||
break;
|
||||
case ADD_FILTER:
|
||||
break;
|
||||
@ -78,10 +91,25 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
||||
|
||||
public void activate() {
|
||||
logger.info("SHH protocol activated");
|
||||
listener.trace("SHH protocol activated");
|
||||
worldManager.getListener().trace("SHH protocol activated");
|
||||
whisper = new Whisper(msgQueue);
|
||||
sendStatus();
|
||||
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() {
|
||||
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;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.ethereum.crypto.HashUtil.sha3;
|
||||
|
||||
/**
|
||||
* Created by kest on 6/12/15.
|
||||
* @author by Konstantin Shabalin
|
||||
*/
|
||||
public class Topic {
|
||||
|
||||
@ -11,15 +13,37 @@ public class Topic {
|
||||
private byte[] topic = new byte[4];
|
||||
|
||||
public Topic(byte[] data) {
|
||||
byte[] topic = sha3(data);
|
||||
System.arraycopy(topic, 0, this.topic, 0, 4);
|
||||
this.topic = data;
|
||||
}
|
||||
|
||||
public Topic(String data) {
|
||||
this(data.getBytes());
|
||||
this.topic = buildTopic(data.getBytes());
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
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");
|
||||
|
||||
myKey = new ECKey().decompress();
|
||||
channel.getShhHandler().setPrivKey(myKey);
|
||||
byte[] nodeIdWithFormat = myKey.getPubKey();
|
||||
nodeId = new byte[nodeIdWithFormat.length - 1];
|
||||
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 {
|
||||
|
||||
private static final Logger gLogger = LoggerFactory.getLogger("general");
|
||||
private static final Logger logger = LoggerFactory.getLogger("general");
|
||||
|
||||
private final KeyValueDataSource dataSource;
|
||||
private Map<ByteArrayWrapper, Node> nodes = new ConcurrentHashMap<>();
|
||||
@ -56,7 +56,7 @@ public class Cache {
|
||||
if (node == null) {
|
||||
byte[] data = this.dataSource.get(key);
|
||||
node = new Node(fromRlpEncoded(data), false);
|
||||
|
||||
|
||||
this.nodes.put(wrappedKey, node);
|
||||
}
|
||||
|
||||
@ -80,10 +80,10 @@ public class Cache {
|
||||
Map<byte[], byte[]> batch = new HashMap<>();
|
||||
for (ByteArrayWrapper key : this.nodes.keySet()) {
|
||||
Node node = this.nodes.get(key);
|
||||
|
||||
|
||||
if (node.isDirty()) {
|
||||
node.setDirty(false);
|
||||
|
||||
|
||||
byte[] value = node.getValue().encode();
|
||||
batch.put(key.getData(), value);
|
||||
|
||||
@ -96,10 +96,10 @@ public class Cache {
|
||||
this.nodes.clear();
|
||||
|
||||
long finish = System.nanoTime();
|
||||
|
||||
|
||||
float flushSize = (float) totalSize / 1048576;
|
||||
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() {
|
||||
|
@ -17,6 +17,7 @@ import static java.util.Arrays.copyOfRange;
|
||||
import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH;
|
||||
import static org.ethereum.util.ByteUtil.*;
|
||||
import static org.ethereum.util.CompactEncoder.*;
|
||||
import static org.ethereum.util.RLP.calcElementPrefixSize;
|
||||
import static org.spongycastle.util.Arrays.concatenate;
|
||||
|
||||
/**
|
||||
@ -519,7 +520,7 @@ public class TrieImpl implements Trie {
|
||||
keysTotalSize += keyBytes.length;
|
||||
|
||||
byte[] valBytes = map.get(key).getValue().getData();
|
||||
valsTotalSize += valBytes.length;
|
||||
valsTotalSize += valBytes.length + calcElementPrefixSize(valBytes);
|
||||
}
|
||||
|
||||
byte[] root = null;
|
||||
@ -568,7 +569,7 @@ public class TrieImpl implements Trie {
|
||||
|
||||
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,
|
||||
listHeader.length + keysHeader.length + keysTotalSize + valsHeader.length + k_2,
|
||||
|
@ -1,6 +1,8 @@
|
||||
package org.ethereum.util;
|
||||
|
||||
import org.ethereum.db.ByteArrayWrapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -42,6 +44,9 @@ import static org.spongycastle.util.BigIntegers.asUnsignedByteArray;
|
||||
*/
|
||||
public class RLP {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("rlp");
|
||||
|
||||
|
||||
/**
|
||||
* Allow for content up to size of 2^64 bytes *
|
||||
*/
|
||||
@ -477,6 +482,10 @@ public class RLP {
|
||||
int pos = startPos;
|
||||
|
||||
while (pos < endPos) {
|
||||
|
||||
logger.debug("fullTraverse: level: " + level + " startPos: " + pos + " endPos: " + endPos);
|
||||
|
||||
|
||||
// It's a list with a payload more than 55 bytes
|
||||
// data[0] - 0xF7 = how many next bytes allocated
|
||||
// for the length of the list
|
||||
@ -749,7 +758,7 @@ public class RLP {
|
||||
|
||||
if (isNullOrZeroArray(srcData))
|
||||
return new byte[]{(byte) OFFSET_SHORT_ITEM};
|
||||
else if(isSingleZero(srcData))
|
||||
else if (isSingleZero(srcData))
|
||||
return new byte[]{00};
|
||||
else if (srcData.length == 1 && (srcData[0] & 0xFF) < 0x80) {
|
||||
return srcData;
|
||||
@ -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) {
|
||||
|
||||
if (size == 0) {
|
||||
@ -828,9 +862,9 @@ public class RLP {
|
||||
if (length < SIZE_THRESHOLD) {
|
||||
|
||||
if (length == 0)
|
||||
return new byte[] {(byte)0x80};
|
||||
return new byte[]{(byte) 0x80};
|
||||
else
|
||||
return new byte[] {(byte)(0x80 + length)};
|
||||
return new byte[]{(byte) (0x80 + length)};
|
||||
|
||||
} else {
|
||||
|
||||
@ -857,11 +891,11 @@ public class RLP {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] encodeSet(Set<ByteArrayWrapper> data){
|
||||
public static byte[] encodeSet(Set<ByteArrayWrapper> data) {
|
||||
|
||||
int dataLength = 0;
|
||||
Set<byte[]> encodedElements = new HashSet<>();
|
||||
for (ByteArrayWrapper element : data){
|
||||
for (ByteArrayWrapper element : data) {
|
||||
|
||||
byte[] encodedElement = RLP.encodeElement(element.getData());
|
||||
dataLength += encodedElement.length;
|
||||
@ -875,7 +909,7 @@ public class RLP {
|
||||
System.arraycopy(listHeader, 0, output, 0, listHeader.length);
|
||||
|
||||
int cummStart = listHeader.length;
|
||||
for (byte[] element : encodedElements){
|
||||
for (byte[] element : encodedElements) {
|
||||
System.arraycopy(element, 0, output, cummStart, element.length);
|
||||
cummStart += element.length;
|
||||
}
|
||||
@ -973,5 +1007,4 @@ public class RLP {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -19,15 +19,28 @@ public class Value {
|
||||
private byte[] rlp;
|
||||
private byte[] sha3;
|
||||
|
||||
private boolean decoded = false;
|
||||
|
||||
public static Value fromRlpEncoded(byte[] data) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public Value(){
|
||||
}
|
||||
|
||||
public void init(byte[] rlp){
|
||||
this.rlp = rlp;
|
||||
}
|
||||
|
||||
public Value(Object obj) {
|
||||
|
||||
this.decoded = true;
|
||||
if (obj == null) return;
|
||||
|
||||
if (obj instanceof Value) {
|
||||
@ -42,15 +55,18 @@ public class Value {
|
||||
* *****************/
|
||||
|
||||
public Object asObj() {
|
||||
decode();
|
||||
return value;
|
||||
}
|
||||
|
||||
public List<Object> asList() {
|
||||
decode();
|
||||
Object[] valueArray = (Object[]) value;
|
||||
return Arrays.asList(valueArray);
|
||||
}
|
||||
|
||||
public int asInt() {
|
||||
decode();
|
||||
if (isInt()) {
|
||||
return (Integer) value;
|
||||
} else if (isBytes()) {
|
||||
@ -60,6 +76,7 @@ public class Value {
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
decode();
|
||||
if (isLong()) {
|
||||
return (Long) value;
|
||||
} else if (isBytes()) {
|
||||
@ -69,10 +86,12 @@ public class Value {
|
||||
}
|
||||
|
||||
public BigInteger asBigInt() {
|
||||
decode();
|
||||
return (BigInteger) value;
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
decode();
|
||||
if (isBytes()) {
|
||||
return new String((byte[]) value);
|
||||
} else if (isString()) {
|
||||
@ -82,6 +101,7 @@ public class Value {
|
||||
}
|
||||
|
||||
public byte[] asBytes() {
|
||||
decode();
|
||||
if (isBytes()) {
|
||||
return (byte[]) value;
|
||||
} else if (isString()) {
|
||||
@ -122,6 +142,13 @@ public class Value {
|
||||
* Utility
|
||||
* *****************/
|
||||
|
||||
public void decode(){
|
||||
if (!this.decoded) {
|
||||
this.value = RLP.decode(rlp, 0).getDecoded();
|
||||
this.decoded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] encode() {
|
||||
if (rlp == null)
|
||||
rlp = RLP.encode(value);
|
||||
@ -143,32 +170,39 @@ public class Value {
|
||||
* *****************/
|
||||
|
||||
public boolean isList() {
|
||||
decode();
|
||||
return value != null && value.getClass().isArray() && !value.getClass().getComponentType().isPrimitive();
|
||||
}
|
||||
|
||||
public boolean isString() {
|
||||
decode();
|
||||
return value instanceof String;
|
||||
}
|
||||
|
||||
public boolean isInt() {
|
||||
decode();
|
||||
return value instanceof Integer;
|
||||
}
|
||||
|
||||
public boolean isLong() {
|
||||
decode();
|
||||
return value instanceof Long;
|
||||
}
|
||||
|
||||
public boolean isBigInt() {
|
||||
decode();
|
||||
return value instanceof BigInteger;
|
||||
}
|
||||
|
||||
public boolean isBytes() {
|
||||
decode();
|
||||
return value instanceof byte[];
|
||||
}
|
||||
|
||||
// it's only if the isBytes() = true;
|
||||
public boolean isReadableString() {
|
||||
|
||||
decode();
|
||||
int readableChars = 0;
|
||||
byte[] data = (byte[]) value;
|
||||
|
||||
@ -186,6 +220,7 @@ public class Value {
|
||||
// it's only if the isBytes() = true;
|
||||
public boolean isHexString() {
|
||||
|
||||
decode();
|
||||
int hexChars = 0;
|
||||
byte[] data = (byte[]) value;
|
||||
|
||||
@ -200,14 +235,17 @@ public class Value {
|
||||
}
|
||||
|
||||
public boolean isHashCode() {
|
||||
decode();
|
||||
return this.asBytes().length == 32;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
decode();
|
||||
return value == null;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
decode();
|
||||
if (isNull()) return true;
|
||||
if (isBytes() && asBytes().length == 0) return true;
|
||||
if (isList() && asList().isEmpty()) return true;
|
||||
@ -217,6 +255,7 @@ public class Value {
|
||||
}
|
||||
|
||||
public int length() {
|
||||
decode();
|
||||
if (isList()) {
|
||||
return asList().size();
|
||||
} else if (isBytes()) {
|
||||
@ -229,6 +268,7 @@ public class Value {
|
||||
|
||||
public String toString() {
|
||||
|
||||
decode();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
if (isList()) {
|
||||
@ -296,7 +336,7 @@ public class Value {
|
||||
}
|
||||
|
||||
public int countBranchNodes() {
|
||||
|
||||
decode();
|
||||
if (this.isList()) {
|
||||
List<Object> objList = this.asList();
|
||||
int i = 0;
|
||||
|
@ -360,8 +360,6 @@ public class Program {
|
||||
Program program = new Program(programCode, programInvoke);
|
||||
vm.play(program);
|
||||
result = program.getResult();
|
||||
this.result.addDeleteAccounts(result.getDeleteAccounts());
|
||||
this.result.addLogInfos(result.getLogInfoList());
|
||||
}
|
||||
|
||||
if (result.getException() != null) {
|
||||
@ -394,6 +392,8 @@ public class Program {
|
||||
}
|
||||
|
||||
track.commit();
|
||||
this.result.addDeleteAccounts(result.getDeleteAccounts());
|
||||
this.result.addLogInfos(result.getLogInfoList());
|
||||
|
||||
// IN SUCCESS PUSH THE ADDRESS INTO THE STACK
|
||||
stackPush(new DataWord(newAddress));
|
||||
|
@ -1,6 +1,5 @@
|
||||
# Root logger option
|
||||
log4j.rootLogger=DEBUG, stdout, file
|
||||
log4j.logger.dump=TRACE, DUMP
|
||||
|
||||
# Direct log messages to stdout
|
||||
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.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.layout=org.apache.log4j.PatternLayout
|
||||
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.FileNamePattern=./logs/ethereum_%d{yyyy-MM-dd}_h%d{HH}.log
|
||||
log4j.appender.file.Threshold=ERROR
|
||||
|
||||
# filter noisy classes
|
||||
log4j.logger.block = ERROR
|
||||
@ -44,6 +39,8 @@ log4j.logger.gas = ERROR
|
||||
log4j.logger.cli = ERROR
|
||||
log4j.logger.TCK-Test = ERROR
|
||||
log4j.logger.execute = ERROR
|
||||
log4j.logger.rlp = ERROR
|
||||
|
||||
|
||||
log4j.logger.org.springframework = ERROR
|
||||
log4j.logger.org.hibernate = ERROR
|
||||
|
@ -185,7 +185,7 @@ root.hash.start = -1
|
||||
peer.capabilities = eth, shh
|
||||
|
||||
# Key value data source values: [leveldb/redis/mapdb]
|
||||
keyvalue.datasource = mapdb
|
||||
keyvalue.datasource = leveldb
|
||||
|
||||
# Redis cloud enabled flag.
|
||||
# Allows using RedisConnection for creating cloud based data structures.
|
||||
@ -198,8 +198,10 @@ blockchain.only=false
|
||||
# from a rlp lines
|
||||
# file and not for
|
||||
# the net
|
||||
blocks.loader=
|
||||
#E:\\temp\\_poc-9-blocks\\poc-9-492k_.dmp
|
||||
#blocks.loader=E:\\temp\\_poc-9-blocks\\poc-9-blocks-start-476891.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
|
@ -89,11 +89,11 @@ public class BlockTest {
|
||||
JSONParser parser = new JSONParser();
|
||||
JSONObject genesisMap = (JSONObject) parser.parse(TEST_GENESIS);
|
||||
|
||||
Set<String> keys = genesisMap.keySet();
|
||||
Set keys = genesisMap.keySet();
|
||||
|
||||
Trie state = new SecureTrie(null);
|
||||
|
||||
for (String key : keys) {
|
||||
for (Object key : keys) {
|
||||
|
||||
JSONObject val = (JSONObject) genesisMap.get(key);
|
||||
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));
|
||||
|
||||
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()));
|
||||
|
@ -151,69 +151,5 @@ public class ContractDetailsTest {
|
||||
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.util.RLP;
|
||||
import org.ethereum.util.RLPList;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
@ -14,14 +13,14 @@ import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Created by kest on 6/13/15.
|
||||
* @author by Konstantin Shabalin
|
||||
*/
|
||||
public class ShhTest {
|
||||
|
||||
private byte[] payload = "Hello whisper!".getBytes();
|
||||
private ECKey privKey = ECKey.fromPrivate(BigInteger.TEN);
|
||||
private byte[] pubKey = privKey.decompress().getPubKey();
|
||||
private long ttl = 10000;
|
||||
private int ttl = 10000;
|
||||
private Topic[] topics = new Topic[]{
|
||||
new Topic("topic 1"),
|
||||
new Topic("topic 2"),
|
||||
@ -32,7 +31,7 @@ public class ShhTest {
|
||||
public void test1() {
|
||||
Message sent = new Message(payload);
|
||||
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.recursivePrint(rlpList);
|
||||
@ -52,7 +51,7 @@ public class ShhTest {
|
||||
public void test2() {
|
||||
Message sent = new Message(payload);
|
||||
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(sent.getPayload()), Hex.toHexString(payload));
|
||||
@ -68,7 +67,7 @@ public class ShhTest {
|
||||
public void test3() {
|
||||
Message sent = new Message(payload);
|
||||
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()));
|
||||
assertNotEquals(Hex.toHexString(sent.getPayload()), Hex.toHexString(payload));
|
||||
@ -86,7 +85,7 @@ public class ShhTest {
|
||||
public void test4() {
|
||||
Message sent = new Message(payload);
|
||||
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()));
|
||||
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(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.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Roman Mandeleil
|
||||
* @since 15.10.2014
|
||||
@ -39,61 +41,59 @@ public class AdaptiveMessageIdsTest {
|
||||
@Test
|
||||
public void test1() {
|
||||
|
||||
Assert.assertEquals(7, P2pMessageCodes.values().length);
|
||||
assertEquals(7, P2pMessageCodes.values().length);
|
||||
|
||||
Assert.assertEquals(0, P2pMessageCodes.HELLO.asByte());
|
||||
Assert.assertEquals(1, P2pMessageCodes.DISCONNECT.asByte());
|
||||
Assert.assertEquals(2, P2pMessageCodes.PING.asByte());
|
||||
Assert.assertEquals(3, P2pMessageCodes.PONG.asByte());
|
||||
Assert.assertEquals(4, P2pMessageCodes.GET_PEERS.asByte());
|
||||
Assert.assertEquals(5, P2pMessageCodes.PEERS.asByte());
|
||||
Assert.assertEquals(15, P2pMessageCodes.USER.asByte());
|
||||
assertEquals(0, P2pMessageCodes.HELLO.asByte());
|
||||
assertEquals(1, P2pMessageCodes.DISCONNECT.asByte());
|
||||
assertEquals(2, P2pMessageCodes.PING.asByte());
|
||||
assertEquals(3, P2pMessageCodes.PONG.asByte());
|
||||
assertEquals(4, P2pMessageCodes.GET_PEERS.asByte());
|
||||
assertEquals(5, P2pMessageCodes.PEERS.asByte());
|
||||
assertEquals(15, P2pMessageCodes.USER.asByte());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
|
||||
Assert.assertEquals(9, EthMessageCodes.values().length);
|
||||
assertEquals(8, EthMessageCodes.values().length);
|
||||
|
||||
Assert.assertEquals(0, EthMessageCodes.STATUS.asByte());
|
||||
Assert.assertEquals(1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||
Assert.assertEquals(2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||
Assert.assertEquals(3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||
Assert.assertEquals(4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||
Assert.assertEquals(5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||
Assert.assertEquals(6, EthMessageCodes.BLOCKS.asByte());
|
||||
Assert.assertEquals(7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||
Assert.assertEquals(8, EthMessageCodes.PACKET_COUNT.asByte());
|
||||
assertEquals(0, EthMessageCodes.STATUS.asByte());
|
||||
assertEquals(1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||
assertEquals(2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||
assertEquals(3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||
assertEquals(4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||
assertEquals(5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||
assertEquals(6, EthMessageCodes.BLOCKS.asByte());
|
||||
assertEquals(7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||
|
||||
EthMessageCodes.setOffset((byte) 0x10);
|
||||
Assert.assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||
Assert.assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||
Assert.assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||
Assert.assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||
Assert.assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||
Assert.assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||
Assert.assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||
Assert.assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||
Assert.assertEquals(0x10 + 8, EthMessageCodes.PACKET_COUNT.asByte());
|
||||
assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||
assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||
assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||
assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||
assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||
assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||
assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||
assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
|
||||
Assert.assertEquals(5, ShhMessageCodes.values().length);
|
||||
assertEquals(5, ShhMessageCodes.values().length);
|
||||
|
||||
Assert.assertEquals(0, ShhMessageCodes.STATUS.asByte());
|
||||
Assert.assertEquals(1, ShhMessageCodes.MESSAGE.asByte());
|
||||
Assert.assertEquals(2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||
Assert.assertEquals(3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||
Assert.assertEquals(4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||
assertEquals(0, ShhMessageCodes.STATUS.asByte());
|
||||
assertEquals(1, ShhMessageCodes.MESSAGE.asByte());
|
||||
assertEquals(2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||
assertEquals(3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||
assertEquals(4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||
|
||||
ShhMessageCodes.setOffset((byte) 0x20);
|
||||
Assert.assertEquals(0x20 + 0, ShhMessageCodes.STATUS.asByte());
|
||||
Assert.assertEquals(0x20 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||
Assert.assertEquals(0x20 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||
Assert.assertEquals(0x20 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||
Assert.assertEquals(0x20 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||
assertEquals(0x20 + 0, ShhMessageCodes.STATUS.asByte());
|
||||
assertEquals(0x20 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||
assertEquals(0x20 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||
assertEquals(0x20 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||
assertEquals(0x20 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -106,21 +106,20 @@ public class AdaptiveMessageIdsTest {
|
||||
new Capability(Capability.SHH, ShhHandler.VERSION));
|
||||
p2pHandler.adaptMessageIds(capabilities);
|
||||
|
||||
Assert.assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||
Assert.assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||
Assert.assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||
Assert.assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||
Assert.assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||
Assert.assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||
Assert.assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||
Assert.assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||
Assert.assertEquals(0x10 + 8, EthMessageCodes.PACKET_COUNT.asByte());
|
||||
assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||
assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||
assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||
assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||
assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||
assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||
assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||
assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||
|
||||
Assert.assertEquals(0x19 + 0, ShhMessageCodes.STATUS.asByte());
|
||||
Assert.assertEquals(0x19 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||
Assert.assertEquals(0x19 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||
Assert.assertEquals(0x19 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||
Assert.assertEquals(0x19 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||
assertEquals(0x18 + 0, ShhMessageCodes.STATUS.asByte());
|
||||
assertEquals(0x18 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||
assertEquals(0x18 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||
assertEquals(0x18 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||
assertEquals(0x18 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||
}
|
||||
|
||||
@Test // Capabilities should be read in alphabetical order
|
||||
@ -133,20 +132,19 @@ public class AdaptiveMessageIdsTest {
|
||||
new Capability(Capability.ETH, EthHandler.VERSION));
|
||||
p2pHandler.adaptMessageIds(capabilities);
|
||||
|
||||
Assert.assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||
Assert.assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||
Assert.assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||
Assert.assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||
Assert.assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||
Assert.assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||
Assert.assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||
Assert.assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||
Assert.assertEquals(0x10 + 8, EthMessageCodes.PACKET_COUNT.asByte());
|
||||
assertEquals(0x10 + 0, EthMessageCodes.STATUS.asByte());
|
||||
assertEquals(0x10 + 1, EthMessageCodes.GET_TRANSACTIONS.asByte());
|
||||
assertEquals(0x10 + 2, EthMessageCodes.TRANSACTIONS.asByte());
|
||||
assertEquals(0x10 + 3, EthMessageCodes.GET_BLOCK_HASHES.asByte());
|
||||
assertEquals(0x10 + 4, EthMessageCodes.BLOCK_HASHES.asByte());
|
||||
assertEquals(0x10 + 5, EthMessageCodes.GET_BLOCKS.asByte());
|
||||
assertEquals(0x10 + 6, EthMessageCodes.BLOCKS.asByte());
|
||||
assertEquals(0x10 + 7, EthMessageCodes.NEW_BLOCK.asByte());
|
||||
|
||||
Assert.assertEquals(0x19 + 0, ShhMessageCodes.STATUS.asByte());
|
||||
Assert.assertEquals(0x19 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||
Assert.assertEquals(0x19 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||
Assert.assertEquals(0x19 + 3, ShhMessageCodes.REMOVE_FILTER.asByte());
|
||||
Assert.assertEquals(0x19 + 4, ShhMessageCodes.PACKET_COUNT.asByte());
|
||||
assertEquals(0x18 + 0, ShhMessageCodes.STATUS.asByte());
|
||||
assertEquals(0x18 + 1, ShhMessageCodes.MESSAGE.asByte());
|
||||
assertEquals(0x18 + 2, ShhMessageCodes.ADD_FILTER.asByte());
|
||||
assertEquals(0x18 + 3, ShhMessageCodes.REMOVE_FILTER.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());
|
||||
assertEquals("d7b597b334b78c63ddf7beafc96484f5604472c40d438ea514882fab0813f074", root2);
|
||||
|
||||
String dump1 = trie.getTrieDump();
|
||||
String dump2 = trie2.getTrieDump();
|
||||
|
||||
assertEquals(dump1, dump2);
|
||||
|
||||
// bug that updates the value somewhere before 505k flush
|
||||
trie2.update(Hex.decode("8c8998c70d860b06ebe80ce22500ec1192083a59ca111194cf2a7612d84b0e2a"), RLP.encodeElement(Hex.decode("0166")));
|
||||
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
|
||||
GitHubTests.VMTest.loadLocal = false
|
||||
|
||||
# Key value data source values: [leveldb/redis]
|
||||
keyvalue.datasource = leveldb
|
||||
# Key value data source values: [leveldb/redis/mapdb]
|
||||
keyvalue.datasource = mapdb
|
||||
|
||||
# structured trace
|
||||
# is the trace being
|
||||
|
Loading…
x
Reference in New Issue
Block a user