mirror of
https://github.com/status-im/ethereumj-personal.git
synced 2025-02-26 18:50:28 +00:00
Convert tabs to spaces
Prior to this change, 78% of lines in .java files with leading whitespace used four-space indentation, while 22% used tabs.
This commit is contained in:
parent
c7cb5231fe
commit
0827fb5c8f
@ -1,12 +1,12 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.ethereum</groupId>
|
||||
<artifactId>ethereumj</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.7.14</version>
|
||||
<name>EthereumJ</name>
|
||||
<url>http://www.ethereumj.org</url>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.ethereum</groupId>
|
||||
<artifactId>ethereumj</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.7.14</version>
|
||||
<name>EthereumJ</name>
|
||||
<url>http://www.ethereumj.org</url>
|
||||
|
||||
<!--
|
||||
* Install jar with sources to the local maven repository
|
||||
@ -17,64 +17,64 @@
|
||||
|
||||
-->
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Roman Mandeleil</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Nick Savers</name>
|
||||
</developer>
|
||||
</developers>
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Roman Mandeleil</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Nick Savers</name>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/ethereum/ethereumj.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/ethereum/ethereumj.git</developerConnection>
|
||||
<url>https://github.com/ethereum/ethereumj</url>
|
||||
</scm>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/ethereum/ethereumj.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/ethereum/ethereumj.git</developerConnection>
|
||||
<url>https://github.com/ethereum/ethereumj</url>
|
||||
</scm>
|
||||
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- Third-party dependencies -->
|
||||
<junit.version>4.11</junit.version>
|
||||
<slf4j.version>1.7.7</slf4j.version>
|
||||
<leveldb.version>0.7</leveldb.version>
|
||||
<spongycastle.version>1.51.0.0</spongycastle.version>
|
||||
<generated.sourceDirectory>gen</generated.sourceDirectory>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- Third-party dependencies -->
|
||||
<junit.version>4.11</junit.version>
|
||||
<slf4j.version>1.7.7</slf4j.version>
|
||||
<leveldb.version>0.7</leveldb.version>
|
||||
<spongycastle.version>1.51.0.0</spongycastle.version>
|
||||
<generated.sourceDirectory>gen</generated.sourceDirectory>
|
||||
|
||||
<github.global.server>github</github.global.server>
|
||||
</properties>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.0.23.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Spongy Castle for SHA3 and SECP256K1 -->
|
||||
<dependency>
|
||||
<groupId>com.madgag.spongycastle</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${spongycastle.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.iq80.leveldb</groupId>
|
||||
<artifactId>leveldb</artifactId>
|
||||
<version>${leveldb.version}</version>
|
||||
</dependency>
|
||||
<!-- Added Cedarsoft for DeepEquals function -->
|
||||
<dependency>
|
||||
<groupId>com.cedarsoftware</groupId>
|
||||
<artifactId>java-util</artifactId>
|
||||
<version>1.8.0</version>
|
||||
</dependency>
|
||||
<!-- For Serpent compile -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.0.23.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Spongy Castle for SHA3 and SECP256K1 -->
|
||||
<dependency>
|
||||
<groupId>com.madgag.spongycastle</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${spongycastle.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.iq80.leveldb</groupId>
|
||||
<artifactId>leveldb</artifactId>
|
||||
<version>${leveldb.version}</version>
|
||||
</dependency>
|
||||
<!-- Added Cedarsoft for DeepEquals function -->
|
||||
<dependency>
|
||||
<groupId>com.cedarsoftware</groupId>
|
||||
<artifactId>java-util</artifactId>
|
||||
<version>1.8.0</version>
|
||||
</dependency>
|
||||
<!-- For Serpent compile -->
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
@ -228,10 +228,10 @@
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<build>
|
||||
|
||||
|
||||
<plugins>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||
@ -322,30 +322,30 @@
|
||||
</plugin>
|
||||
|
||||
|
||||
<plugin>
|
||||
<groupId>org.eluder.coveralls</groupId>
|
||||
<artifactId>coveralls-maven-plugin</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.7.1.201405082137</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>org/ethereum/gui/**/*.class</exclude>
|
||||
<exclude>org/ethereum/**/*Test.class</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eluder.coveralls</groupId>
|
||||
<artifactId>coveralls-maven-plugin</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.7.1.201405082137</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>org/ethereum/gui/**/*.class</exclude>
|
||||
<exclude>org/ethereum/**/*Test.class</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!--
|
||||
<plugin>
|
||||
@ -401,8 +401,8 @@
|
||||
|
||||
|
||||
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
<plugin>
|
||||
@ -418,7 +418,7 @@
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<versionRange>[2.0,)</versionRange>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
<goal>copy-dependencies</goal>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
@ -427,17 +427,17 @@
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<versionRange>[0.7.1.201405082137,)</versionRange>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<versionRange>[0.7.1.201405082137,)</versionRange>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
@ -445,6 +445,6 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
@ -18,31 +18,31 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
public class SystemProperties {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger("general");
|
||||
private static Logger logger = LoggerFactory.getLogger("general");
|
||||
|
||||
private static int DEFAULT_TX_APPROVE_TIMEOUT = 10;
|
||||
private static String DEFAULT_DISCOVERY_PEER_LIST = "poc-7.ethdev.com:30303";
|
||||
private static String DEFAULT_ACTIVE_PEER_IP = "poc-7.ethdev.com";
|
||||
private static int DEFAULT_ACTIVE_PORT = 30303;
|
||||
private static String DEFAULT_SAMPLES_DIR = "samples";
|
||||
private static String DEFAULT_COINBASE_SECRET = "monkey";
|
||||
private static int DEFAULT_ACTIVE_PEER_CHANNEL_TIMEOUT = 5;
|
||||
private static Boolean DEFAULT_DB_RESET = false;
|
||||
private static Boolean DEFAULT_DUMP_FULL = false;
|
||||
private static Boolean DEFAULT_RECORD_BLOCKS = false;
|
||||
private static String DEFAULT_DUMP_DIR = "dmp";
|
||||
private static String DEFAULT_DUMP_STYLE = "standard+";
|
||||
private static Integer DEFAULT_VMTRACE_BLOCK = 0;
|
||||
private static String DEFAULT_DATABASE_DIR = System.getProperty("user.dir");
|
||||
private static Boolean DEFAULT_DUMP_CLEAN_ON_RESTART = true;
|
||||
private static Boolean DEFAULT_PLAY_VM = true;
|
||||
private static Boolean DEFAULT_BLOCKCHAIN_ONLY = false;
|
||||
private static int DEFAULT_TRACE_STARTBLOCK = -1;
|
||||
private static int DEFAULT_MAX_HASHES_ASK = -1; // unlimited
|
||||
private static int DEFAULT_MAX_BLOCKS_ASK = 10;
|
||||
private static int DEFAULT_MAX_BLOCKS_QUEUED = 300;
|
||||
private static String DEFAULT_PROJECT_VERSION = "";
|
||||
private static String DEFAULT_HELLO_PHRASE = "Dev";
|
||||
private static int DEFAULT_TX_APPROVE_TIMEOUT = 10;
|
||||
private static String DEFAULT_DISCOVERY_PEER_LIST = "poc-7.ethdev.com:30303";
|
||||
private static String DEFAULT_ACTIVE_PEER_IP = "poc-7.ethdev.com";
|
||||
private static int DEFAULT_ACTIVE_PORT = 30303;
|
||||
private static String DEFAULT_SAMPLES_DIR = "samples";
|
||||
private static String DEFAULT_COINBASE_SECRET = "monkey";
|
||||
private static int DEFAULT_ACTIVE_PEER_CHANNEL_TIMEOUT = 5;
|
||||
private static Boolean DEFAULT_DB_RESET = false;
|
||||
private static Boolean DEFAULT_DUMP_FULL = false;
|
||||
private static Boolean DEFAULT_RECORD_BLOCKS = false;
|
||||
private static String DEFAULT_DUMP_DIR = "dmp";
|
||||
private static String DEFAULT_DUMP_STYLE = "standard+";
|
||||
private static Integer DEFAULT_VMTRACE_BLOCK = 0;
|
||||
private static String DEFAULT_DATABASE_DIR = System.getProperty("user.dir");
|
||||
private static Boolean DEFAULT_DUMP_CLEAN_ON_RESTART = true;
|
||||
private static Boolean DEFAULT_PLAY_VM = true;
|
||||
private static Boolean DEFAULT_BLOCKCHAIN_ONLY = false;
|
||||
private static int DEFAULT_TRACE_STARTBLOCK = -1;
|
||||
private static int DEFAULT_MAX_HASHES_ASK = -1; // unlimited
|
||||
private static int DEFAULT_MAX_BLOCKS_ASK = 10;
|
||||
private static int DEFAULT_MAX_BLOCKS_QUEUED = 300;
|
||||
private static String DEFAULT_PROJECT_VERSION = "";
|
||||
private static String DEFAULT_HELLO_PHRASE = "Dev";
|
||||
private static Boolean DEFAULT_VM_TRACE = false;
|
||||
private static String DEFAULT_VM_TRACE_DIR = "dmp";
|
||||
private static int DEFAULT_PEER_LISTEN_PORT = 30303;
|
||||
@ -52,117 +52,117 @@ public class SystemProperties {
|
||||
|
||||
private static List<String> DEFAULT_PROTOCOL_LIST = Arrays.asList("eth", "shh");
|
||||
|
||||
public static SystemProperties CONFIG = new SystemProperties();
|
||||
private Properties prop = new Properties();
|
||||
private InputStream input = null;
|
||||
public static SystemProperties CONFIG = new SystemProperties();
|
||||
private Properties prop = new Properties();
|
||||
private InputStream input = null;
|
||||
|
||||
|
||||
public SystemProperties() {
|
||||
public SystemProperties() {
|
||||
|
||||
try {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String fileName = userDir + "/config/system.properties";
|
||||
File file = new File(fileName);
|
||||
try {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String fileName = userDir + "/config/system.properties";
|
||||
File file = new File(fileName);
|
||||
|
||||
if (file.exists()) {
|
||||
if (file.exists()) {
|
||||
logger.info("config loaded from {}", fileName);
|
||||
input = new FileInputStream(file);
|
||||
} else {
|
||||
fileName = "system.properties";
|
||||
input = SystemProperties.class.getClassLoader()
|
||||
.getResourceAsStream(fileName);
|
||||
if (input == null) {
|
||||
logger.error("Sorry, unable to find {}", fileName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// load a properties file from class path, inside static method
|
||||
prop.load(input);
|
||||
input = new FileInputStream(file);
|
||||
} else {
|
||||
fileName = "system.properties";
|
||||
input = SystemProperties.class.getClassLoader()
|
||||
.getResourceAsStream(fileName);
|
||||
if (input == null) {
|
||||
logger.error("Sorry, unable to find {}", fileName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// load a properties file from class path, inside static method
|
||||
prop.load(input);
|
||||
|
||||
} catch (IOException ex) {
|
||||
logger.error(ex.getMessage(), ex);
|
||||
} finally {
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
logger.error(ex.getMessage(), ex);
|
||||
} finally {
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean peerDiscovery() {
|
||||
if (prop.isEmpty()) return true;
|
||||
return Boolean.parseBoolean(prop.getProperty("peer.discovery"));
|
||||
}
|
||||
public boolean peerDiscovery() {
|
||||
if (prop.isEmpty()) return true;
|
||||
return Boolean.parseBoolean(prop.getProperty("peer.discovery"));
|
||||
}
|
||||
|
||||
public int peerDiscoveryWorkers() {
|
||||
if (prop.isEmpty()) return 2;
|
||||
return Integer.parseInt(prop.getProperty("peer.discovery.workers"));
|
||||
}
|
||||
public int peerDiscoveryWorkers() {
|
||||
if (prop.isEmpty()) return 2;
|
||||
return Integer.parseInt(prop.getProperty("peer.discovery.workers"));
|
||||
}
|
||||
|
||||
public int peerConnectionTimeout() {
|
||||
if (prop.isEmpty()) return 10000;
|
||||
return Integer.parseInt(prop.getProperty("peer.connection.timeout")) * 1000;
|
||||
}
|
||||
public int peerConnectionTimeout() {
|
||||
if (prop.isEmpty()) return 10000;
|
||||
return Integer.parseInt(prop.getProperty("peer.connection.timeout")) * 1000;
|
||||
}
|
||||
|
||||
public int transactionApproveTimeout() {
|
||||
if (prop.isEmpty()) return DEFAULT_TX_APPROVE_TIMEOUT;
|
||||
return Integer.parseInt(prop.getProperty("transaction.approve.timeout"));
|
||||
}
|
||||
public int transactionApproveTimeout() {
|
||||
if (prop.isEmpty()) return DEFAULT_TX_APPROVE_TIMEOUT;
|
||||
return Integer.parseInt(prop.getProperty("transaction.approve.timeout"));
|
||||
}
|
||||
|
||||
public String peerDiscoveryIPList() {
|
||||
if (prop.isEmpty()) return DEFAULT_DISCOVERY_PEER_LIST;
|
||||
return prop.getProperty("peer.discovery.ip.list");
|
||||
}
|
||||
public String peerDiscoveryIPList() {
|
||||
if (prop.isEmpty()) return DEFAULT_DISCOVERY_PEER_LIST;
|
||||
return prop.getProperty("peer.discovery.ip.list");
|
||||
}
|
||||
|
||||
public boolean databaseReset() {
|
||||
if (prop.isEmpty()) return DEFAULT_DB_RESET;
|
||||
return Boolean.parseBoolean(prop.getProperty("database.reset"));
|
||||
}
|
||||
public boolean databaseReset() {
|
||||
if (prop.isEmpty()) return DEFAULT_DB_RESET;
|
||||
return Boolean.parseBoolean(prop.getProperty("database.reset"));
|
||||
}
|
||||
|
||||
public void setDatabaseReset(Boolean reset){
|
||||
prop.setProperty("database.reset", reset.toString());
|
||||
}
|
||||
|
||||
public String activePeerIP() {
|
||||
if (prop.isEmpty()) return DEFAULT_ACTIVE_PEER_IP;
|
||||
return prop.getProperty("peer.active.ip");
|
||||
}
|
||||
public String activePeerIP() {
|
||||
if (prop.isEmpty()) return DEFAULT_ACTIVE_PEER_IP;
|
||||
return prop.getProperty("peer.active.ip");
|
||||
}
|
||||
|
||||
public void setActivePeerIP(String host){
|
||||
prop.setProperty("peer.active.ip", host.toString());
|
||||
}
|
||||
|
||||
public int activePeerPort() {
|
||||
if (prop.isEmpty()) return DEFAULT_ACTIVE_PORT;
|
||||
return Integer.parseInt(prop.getProperty("peer.active.port"));
|
||||
}
|
||||
public int activePeerPort() {
|
||||
if (prop.isEmpty()) return DEFAULT_ACTIVE_PORT;
|
||||
return Integer.parseInt(prop.getProperty("peer.active.port"));
|
||||
}
|
||||
|
||||
public void setActivePeerPort(Integer port){
|
||||
prop.setProperty("peer.active.port", port.toString());
|
||||
}
|
||||
|
||||
public String samplesDir() {
|
||||
if (prop.isEmpty()) return DEFAULT_SAMPLES_DIR;
|
||||
return prop.getProperty("samples.dir");
|
||||
}
|
||||
public String samplesDir() {
|
||||
if (prop.isEmpty()) return DEFAULT_SAMPLES_DIR;
|
||||
return prop.getProperty("samples.dir");
|
||||
}
|
||||
|
||||
public String coinbaseSecret() {
|
||||
if (prop.isEmpty()) return DEFAULT_COINBASE_SECRET;
|
||||
return prop.getProperty("coinbase.secret");
|
||||
}
|
||||
public String coinbaseSecret() {
|
||||
if (prop.isEmpty()) return DEFAULT_COINBASE_SECRET;
|
||||
return prop.getProperty("coinbase.secret");
|
||||
}
|
||||
|
||||
public Integer peerChannelReadTimeout() {
|
||||
if (prop.isEmpty()) return DEFAULT_ACTIVE_PEER_CHANNEL_TIMEOUT;
|
||||
return Integer.parseInt(prop.getProperty("peer.channel.read.timeout"));
|
||||
}
|
||||
public Integer peerChannelReadTimeout() {
|
||||
if (prop.isEmpty()) return DEFAULT_ACTIVE_PEER_CHANNEL_TIMEOUT;
|
||||
return Integer.parseInt(prop.getProperty("peer.channel.read.timeout"));
|
||||
}
|
||||
|
||||
public Integer traceStartBlock() {
|
||||
if (prop.isEmpty()) return DEFAULT_TRACE_STARTBLOCK;
|
||||
return Integer.parseInt(prop.getProperty("trace.startblock"));
|
||||
}
|
||||
public Integer traceStartBlock() {
|
||||
if (prop.isEmpty()) return DEFAULT_TRACE_STARTBLOCK;
|
||||
return Integer.parseInt(prop.getProperty("trace.startblock"));
|
||||
}
|
||||
|
||||
public Boolean recordBlocks() {
|
||||
if (prop.isEmpty()) return DEFAULT_RECORD_BLOCKS;
|
||||
@ -170,82 +170,82 @@ public class SystemProperties {
|
||||
}
|
||||
|
||||
|
||||
public Boolean dumpFull() {
|
||||
if (prop.isEmpty()) return DEFAULT_DUMP_FULL;
|
||||
return Boolean.parseBoolean(prop.getProperty("dump.full"));
|
||||
}
|
||||
public Boolean dumpFull() {
|
||||
if (prop.isEmpty()) return DEFAULT_DUMP_FULL;
|
||||
return Boolean.parseBoolean(prop.getProperty("dump.full"));
|
||||
}
|
||||
|
||||
public String dumpDir() {
|
||||
if (prop.isEmpty()) return DEFAULT_DUMP_DIR;
|
||||
return prop.getProperty("dump.dir");
|
||||
}
|
||||
public String dumpDir() {
|
||||
if (prop.isEmpty()) return DEFAULT_DUMP_DIR;
|
||||
return prop.getProperty("dump.dir");
|
||||
}
|
||||
|
||||
public String dumpStyle() {
|
||||
if (prop.isEmpty()) return DEFAULT_DUMP_STYLE;
|
||||
return prop.getProperty("dump.style");
|
||||
}
|
||||
public String dumpStyle() {
|
||||
if (prop.isEmpty()) return DEFAULT_DUMP_STYLE;
|
||||
return prop.getProperty("dump.style");
|
||||
}
|
||||
|
||||
public Integer dumpBlock() {
|
||||
if (prop.isEmpty()) return DEFAULT_VMTRACE_BLOCK;
|
||||
return Integer.parseInt(prop.getProperty("dump.block"));
|
||||
}
|
||||
public Integer dumpBlock() {
|
||||
if (prop.isEmpty()) return DEFAULT_VMTRACE_BLOCK;
|
||||
return Integer.parseInt(prop.getProperty("dump.block"));
|
||||
}
|
||||
|
||||
public String databaseDir() {
|
||||
if (prop.isEmpty()) return DEFAULT_DATABASE_DIR;
|
||||
return prop.getProperty("database.dir");
|
||||
}
|
||||
public String databaseDir() {
|
||||
if (prop.isEmpty()) return DEFAULT_DATABASE_DIR;
|
||||
return prop.getProperty("database.dir");
|
||||
}
|
||||
|
||||
public void setDataBaseDir(String dataBaseDir){
|
||||
prop.setProperty("database.dir", dataBaseDir);
|
||||
}
|
||||
|
||||
public Boolean dumpCleanOnRestart() {
|
||||
if (prop.isEmpty()) return DEFAULT_DUMP_CLEAN_ON_RESTART;
|
||||
return Boolean.parseBoolean(prop.getProperty("dump.clean.on.restart"));
|
||||
}
|
||||
public Boolean dumpCleanOnRestart() {
|
||||
if (prop.isEmpty()) return DEFAULT_DUMP_CLEAN_ON_RESTART;
|
||||
return Boolean.parseBoolean(prop.getProperty("dump.clean.on.restart"));
|
||||
}
|
||||
|
||||
public Boolean playVM() {
|
||||
if (prop.isEmpty()) return DEFAULT_PLAY_VM;
|
||||
return Boolean.parseBoolean(prop.getProperty("play.vm"));
|
||||
}
|
||||
public Boolean playVM() {
|
||||
if (prop.isEmpty()) return DEFAULT_PLAY_VM;
|
||||
return Boolean.parseBoolean(prop.getProperty("play.vm"));
|
||||
}
|
||||
|
||||
public Boolean blockChainOnly() {
|
||||
if (prop.isEmpty()) return DEFAULT_BLOCKCHAIN_ONLY;
|
||||
return Boolean.parseBoolean(prop.getProperty("blockchain.only"));
|
||||
}
|
||||
public Boolean blockChainOnly() {
|
||||
if (prop.isEmpty()) return DEFAULT_BLOCKCHAIN_ONLY;
|
||||
return Boolean.parseBoolean(prop.getProperty("blockchain.only"));
|
||||
}
|
||||
|
||||
public Integer maxHashesAsk() {
|
||||
if (prop.isEmpty()) return DEFAULT_MAX_HASHES_ASK;
|
||||
return Integer.parseInt(prop.getProperty("max.hashes.ask"));
|
||||
}
|
||||
public Integer maxHashesAsk() {
|
||||
if (prop.isEmpty()) return DEFAULT_MAX_HASHES_ASK;
|
||||
return Integer.parseInt(prop.getProperty("max.hashes.ask"));
|
||||
}
|
||||
|
||||
public Integer maxBlocksAsk() {
|
||||
if (prop.isEmpty()) return DEFAULT_MAX_BLOCKS_ASK;
|
||||
return Integer.parseInt(prop.getProperty("max.blocks.ask"));
|
||||
}
|
||||
public Integer maxBlocksAsk() {
|
||||
if (prop.isEmpty()) return DEFAULT_MAX_BLOCKS_ASK;
|
||||
return Integer.parseInt(prop.getProperty("max.blocks.ask"));
|
||||
}
|
||||
|
||||
public Integer maxBlocksQueued() {
|
||||
if (prop.isEmpty()) return DEFAULT_MAX_BLOCKS_QUEUED;
|
||||
return Integer.parseInt(prop.getProperty("max.blocks.queued"));
|
||||
}
|
||||
public Integer maxBlocksQueued() {
|
||||
if (prop.isEmpty()) return DEFAULT_MAX_BLOCKS_QUEUED;
|
||||
return Integer.parseInt(prop.getProperty("max.blocks.queued"));
|
||||
}
|
||||
|
||||
public String projectVersion() {
|
||||
if (prop.isEmpty()) return DEFAULT_PROJECT_VERSION;
|
||||
return prop.getProperty("project.version");
|
||||
}
|
||||
public String projectVersion() {
|
||||
if (prop.isEmpty()) return DEFAULT_PROJECT_VERSION;
|
||||
return prop.getProperty("project.version");
|
||||
}
|
||||
|
||||
public String helloPhrase() {
|
||||
if (prop.isEmpty()) return DEFAULT_HELLO_PHRASE;
|
||||
return prop.getProperty("hello.phrase");
|
||||
}
|
||||
public String helloPhrase() {
|
||||
if (prop.isEmpty()) return DEFAULT_HELLO_PHRASE;
|
||||
return prop.getProperty("hello.phrase");
|
||||
}
|
||||
|
||||
public String rootHashStart() {
|
||||
if (prop.isEmpty()) return null;
|
||||
String hash = prop.getProperty("root.hash.start");
|
||||
if (hash == null || hash.equals("-1"))
|
||||
return null;
|
||||
return hash;
|
||||
}
|
||||
public String rootHashStart() {
|
||||
if (prop.isEmpty()) return null;
|
||||
String hash = prop.getProperty("root.hash.start");
|
||||
if (hash == null || hash.equals("-1"))
|
||||
return null;
|
||||
return hash;
|
||||
}
|
||||
|
||||
public List<String> peerCapabilities(){
|
||||
if (prop.isEmpty()) return DEFAULT_PROTOCOL_LIST;
|
||||
@ -272,28 +272,28 @@ public class SystemProperties {
|
||||
prop.setProperty("peer.listen.port", port.toString());
|
||||
}
|
||||
|
||||
public void print() {
|
||||
Enumeration<?> e = prop.propertyNames();
|
||||
while (e.hasMoreElements()) {
|
||||
String key = (String) e.nextElement();
|
||||
String value = prop.getProperty(key);
|
||||
if (!key.equals("null"))
|
||||
logger.info("Key: " + key + ", Value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Testing
|
||||
*
|
||||
*/
|
||||
public boolean vmTestLoadLocal() {
|
||||
public void print() {
|
||||
Enumeration<?> e = prop.propertyNames();
|
||||
while (e.hasMoreElements()) {
|
||||
String key = (String) e.nextElement();
|
||||
String value = prop.getProperty(key);
|
||||
if (!key.equals("null"))
|
||||
logger.info("Key: " + key + ", Value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Testing
|
||||
*
|
||||
*/
|
||||
public boolean vmTestLoadLocal() {
|
||||
if (prop.isEmpty() || !prop.containsKey("GitHubTests.VMTest.loadLocal")) return DEFAULT_VMTEST_LOAD_LOCAL;
|
||||
return Boolean.parseBoolean(prop.getProperty("GitHubTests.VMTest.loadLocal"));
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
SystemProperties systemProperties = new SystemProperties();
|
||||
systemProperties.print();
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
SystemProperties systemProperties = new SystemProperties();
|
||||
systemProperties.print();
|
||||
}
|
||||
}
|
@ -18,8 +18,8 @@ import org.springframework.stereotype.Component;
|
||||
@Scope("prototype")
|
||||
public class Account {
|
||||
|
||||
private ECKey ecKey;
|
||||
private byte[] address;
|
||||
private ECKey ecKey;
|
||||
private byte[] address;
|
||||
|
||||
private Set<Transaction> pendingTransactions =
|
||||
Collections.synchronizedSet(new HashSet<Transaction>());
|
||||
@ -27,18 +27,18 @@ public class Account {
|
||||
@Autowired
|
||||
WorldManager worldManager;
|
||||
|
||||
public Account() {
|
||||
}
|
||||
public Account() {
|
||||
}
|
||||
|
||||
public void init(){
|
||||
this.ecKey = new ECKey(Utils.getRandom());
|
||||
address = this.ecKey.getAddress();
|
||||
}
|
||||
|
||||
public void init(ECKey ecKey) {
|
||||
this.ecKey = ecKey;
|
||||
public void init(ECKey ecKey) {
|
||||
this.ecKey = ecKey;
|
||||
address = this.ecKey.getAddress();
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger getNonce(){
|
||||
AccountState accountState =
|
||||
@ -82,16 +82,16 @@ public class Account {
|
||||
return ecKey;
|
||||
}
|
||||
|
||||
public byte[] getAddress() {
|
||||
return address;
|
||||
}
|
||||
public byte[] getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(byte[] address) {
|
||||
this.address = address;
|
||||
}
|
||||
public void setAddress(byte[] address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Set<Transaction> getPendingTransactins() {
|
||||
return this.pendingTransactions;
|
||||
return this.pendingTransactions;
|
||||
}
|
||||
|
||||
public void addPendingTransaction(Transaction transaction){
|
||||
|
@ -57,13 +57,13 @@ public class AccountState {
|
||||
public AccountState(byte[] rlpData) {
|
||||
this.rlpEncoded = rlpData;
|
||||
|
||||
RLPList items = (RLPList) RLP.decode2(rlpEncoded).get(0);
|
||||
this.nonce = items.get(0).getRLPData() == null ? BigInteger.ZERO
|
||||
: new BigInteger(1, items.get(0).getRLPData());
|
||||
this.balance = items.get(1).getRLPData() == null ? BigInteger.ZERO
|
||||
: new BigInteger(1, items.get(1).getRLPData());
|
||||
this.stateRoot = items.get(2).getRLPData();
|
||||
this.codeHash = items.get(3).getRLPData();
|
||||
RLPList items = (RLPList) RLP.decode2(rlpEncoded).get(0);
|
||||
this.nonce = items.get(0).getRLPData() == null ? BigInteger.ZERO
|
||||
: new BigInteger(1, items.get(0).getRLPData());
|
||||
this.balance = items.get(1).getRLPData() == null ? BigInteger.ZERO
|
||||
: new BigInteger(1, items.get(1).getRLPData());
|
||||
this.stateRoot = items.get(2).getRLPData();
|
||||
this.codeHash = items.get(3).getRLPData();
|
||||
}
|
||||
|
||||
public BigInteger getNonce() {
|
||||
@ -110,21 +110,21 @@ public class AccountState {
|
||||
return this.balance;
|
||||
}
|
||||
|
||||
public void subFromBalance(BigInteger value) {
|
||||
public void subFromBalance(BigInteger value) {
|
||||
if (value.signum() != 0) rlpEncoded = null;
|
||||
this.balance = balance.subtract(value);
|
||||
setDirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
if(rlpEncoded == null) {
|
||||
byte[] nonce = RLP.encodeBigInteger(this.nonce);
|
||||
byte[] balance = RLP.encodeBigInteger(this.balance);
|
||||
byte[] stateRoot = RLP.encodeElement(this.stateRoot);
|
||||
byte[] codeHash = RLP.encodeElement(this.codeHash);
|
||||
this.rlpEncoded = RLP.encodeList(nonce, balance, stateRoot, codeHash);
|
||||
}
|
||||
return rlpEncoded;
|
||||
if(rlpEncoded == null) {
|
||||
byte[] nonce = RLP.encodeBigInteger(this.nonce);
|
||||
byte[] balance = RLP.encodeBigInteger(this.balance);
|
||||
byte[] stateRoot = RLP.encodeElement(this.stateRoot);
|
||||
byte[] codeHash = RLP.encodeElement(this.codeHash);
|
||||
this.rlpEncoded = RLP.encodeList(nonce, balance, stateRoot, codeHash);
|
||||
}
|
||||
return rlpEncoded;
|
||||
}
|
||||
|
||||
public void setDirty(boolean dirty) {
|
||||
@ -156,10 +156,10 @@ public class AccountState {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String ret = " Nonce: " + this.getNonce().toString() + "\n" +
|
||||
" Balance: " + getBalance() + "\n" +
|
||||
" State Root: " + Hex.toHexString(this.getStateRoot()) + "\n" +
|
||||
" Code Hash: " + Hex.toHexString(this.getCodeHash());
|
||||
return ret;
|
||||
String ret = " Nonce: " + this.getNonce().toString() + "\n" +
|
||||
" Balance: " + getBalance() + "\n" +
|
||||
" State Root: " + Hex.toHexString(this.getStateRoot()) + "\n" +
|
||||
" Code Hash: " + Hex.toHexString(this.getCodeHash());
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -29,25 +29,25 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
*/
|
||||
public class Block {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("block");
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("block");
|
||||
|
||||
public static BigInteger BLOCK_REWARD = BigInteger.valueOf(1500000000000000000L);
|
||||
public static BigInteger UNCLE_REWARD = BLOCK_REWARD.multiply(
|
||||
BigInteger.valueOf(15)).divide(BigInteger.valueOf(16));
|
||||
public static BigInteger INCLUSION_REWARD = Block.BLOCK_REWARD
|
||||
.divide(BigInteger.valueOf(32));
|
||||
public static BigInteger UNCLE_REWARD = BLOCK_REWARD.multiply(
|
||||
BigInteger.valueOf(15)).divide(BigInteger.valueOf(16));
|
||||
public static BigInteger INCLUSION_REWARD = Block.BLOCK_REWARD
|
||||
.divide(BigInteger.valueOf(32));
|
||||
|
||||
private BlockHeader header;
|
||||
|
||||
private BlockHeader header;
|
||||
|
||||
/* Transactions */
|
||||
private List<Transaction> transactionsList = new CopyOnWriteArrayList<>();
|
||||
|
||||
/* Uncles */
|
||||
private List<Transaction> transactionsList = new CopyOnWriteArrayList<>();
|
||||
|
||||
/* Uncles */
|
||||
private List<BlockHeader> uncleList = new CopyOnWriteArrayList<>();
|
||||
|
||||
/* Private */
|
||||
|
||||
private byte[] rlpEncoded;
|
||||
/* Private */
|
||||
|
||||
private byte[] rlpEncoded;
|
||||
private boolean parsed = false;
|
||||
|
||||
private Trie txsState;
|
||||
@ -55,20 +55,20 @@ public class Block {
|
||||
/* Constructors */
|
||||
|
||||
public Block(byte[] rawData) {
|
||||
logger.debug("new from [" + Hex.toHexString(rawData) + "]");
|
||||
logger.debug("new from [" + Hex.toHexString(rawData) + "]");
|
||||
this.rlpEncoded = rawData;
|
||||
this.parsed = false;
|
||||
}
|
||||
|
||||
public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] logsBloom,
|
||||
byte[] difficulty, long number, long gasLimit,
|
||||
long gasUsed, long timestamp, byte[] extraData, byte[] nonce,
|
||||
List<Transaction> transactionsList, List<BlockHeader> uncleList) {
|
||||
this.header = new BlockHeader(parentHash, unclesHash, coinbase, logsBloom,
|
||||
difficulty, number, gasLimit, gasUsed,
|
||||
timestamp, extraData, nonce);
|
||||
public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] logsBloom,
|
||||
byte[] difficulty, long number, long gasLimit,
|
||||
long gasUsed, long timestamp, byte[] extraData, byte[] nonce,
|
||||
List<Transaction> transactionsList, List<BlockHeader> uncleList) {
|
||||
this.header = new BlockHeader(parentHash, unclesHash, coinbase, logsBloom,
|
||||
difficulty, number, gasLimit, gasUsed,
|
||||
timestamp, extraData, nonce);
|
||||
|
||||
this.transactionsList = transactionsList;
|
||||
this.transactionsList = transactionsList;
|
||||
if (this.transactionsList == null){
|
||||
this.transactionsList = new CopyOnWriteArrayList<Transaction>();
|
||||
}
|
||||
@ -112,24 +112,24 @@ public class Block {
|
||||
|
||||
public byte[] getHash() {
|
||||
if (!parsed) parseRLP();
|
||||
return HashUtil.sha3(this.header.getEncoded());
|
||||
return HashUtil.sha3(this.header.getEncoded());
|
||||
}
|
||||
|
||||
|
||||
public byte[] calcDifficulty() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.calcDifficulty();
|
||||
}
|
||||
public byte[] calcDifficulty() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.calcDifficulty();
|
||||
}
|
||||
|
||||
public boolean validateNonce() {
|
||||
if (!parsed) parseRLP();
|
||||
public boolean validateNonce() {
|
||||
if (!parsed) parseRLP();
|
||||
BigInteger max = BigInteger.valueOf(2).pow(256);
|
||||
byte[] target = BigIntegers.asUnsignedByteArray(32, max.divide(new BigInteger(1, this.getDifficulty())));
|
||||
byte[] hash = HashUtil.sha3(this.getEncodedWithoutNonce());
|
||||
byte[] concat = Arrays.concatenate(hash, this.getNonce());
|
||||
byte[] result = HashUtil.sha3(concat);
|
||||
return FastByteComparisons.compareTo(result, 0, 32, target, 0, 32) < 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public byte[] getParentHash() {
|
||||
@ -174,10 +174,10 @@ public class Block {
|
||||
|
||||
public BigInteger getCumulativeDifficulty() {
|
||||
if (!parsed) parseRLP();
|
||||
BigInteger calcDifficulty = new BigInteger(1, this.header.getDifficulty());
|
||||
BigInteger calcDifficulty = new BigInteger(1, this.header.getDifficulty());
|
||||
for (BlockHeader uncle : uncleList) {
|
||||
calcDifficulty = calcDifficulty.add(new BigInteger(1, uncle.getDifficulty()));
|
||||
}
|
||||
}
|
||||
return calcDifficulty;
|
||||
}
|
||||
|
||||
@ -187,21 +187,21 @@ public class Block {
|
||||
}
|
||||
|
||||
public long getNumber() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.getNumber();
|
||||
}
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.getNumber();
|
||||
}
|
||||
|
||||
public long getGasLimit() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.getGasLimit();
|
||||
}
|
||||
public long getGasLimit() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.getGasLimit();
|
||||
}
|
||||
|
||||
public long getGasUsed() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.getGasUsed();
|
||||
}
|
||||
public long getGasUsed() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.getGasUsed();
|
||||
}
|
||||
|
||||
public byte[] getExtraData() {
|
||||
public byte[] getExtraData() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.getExtraData();
|
||||
}
|
||||
@ -227,9 +227,9 @@ public class Block {
|
||||
}
|
||||
|
||||
private StringBuffer toStringBuff = new StringBuffer();
|
||||
// [parent_hash, uncles_hash, coinbase, state_root, tx_trie_root,
|
||||
// difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp,
|
||||
// extradata, nonce]
|
||||
// [parent_hash, uncles_hash, coinbase, state_root, tx_trie_root,
|
||||
// difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp,
|
||||
// extradata, nonce]
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@ -275,14 +275,14 @@ public class Block {
|
||||
|
||||
this.txsState = new TrieImpl(null);
|
||||
for (int i = 0; i < txTransactions.size(); i++) {
|
||||
RLPElement transactionRaw = txTransactions.get(i);
|
||||
RLPElement transactionRaw = txTransactions.get(i);
|
||||
this.transactionsList.add(new Transaction(transactionRaw.getRLPData()));
|
||||
this.txsState.update(RLP.encodeInt(i) , transactionRaw.getRLPData());
|
||||
}
|
||||
|
||||
String calculatedRoot = Hex.toHexString(txsState.getRootHash());
|
||||
if(!calculatedRoot.equals(Hex.toHexString(expectedRoot)))
|
||||
logger.error("Added tx receipts don't match the given txsStateRoot");
|
||||
logger.error("Added tx receipts don't match the given txsStateRoot");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,9 +294,9 @@ public class Block {
|
||||
return Arrays.areEqual(this.getHash(), block.getParentHash());
|
||||
}
|
||||
|
||||
public boolean isGenesis() {
|
||||
return this.header.isGenesis();
|
||||
}
|
||||
public boolean isGenesis() {
|
||||
return this.header.isGenesis();
|
||||
}
|
||||
|
||||
public boolean isEqual(Block block){
|
||||
return Arrays.areEqual(this.getHash(), block.getHash());
|
||||
@ -318,22 +318,22 @@ public class Block {
|
||||
this.getHeader().setUnclesHash( SHA3Helper.sha3( getUnclesEncoded() ));
|
||||
rlpEncoded = null;
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
if(rlpEncoded == null) {
|
||||
byte[] header = this.header.getEncoded();
|
||||
byte[] transactions = RLP.encodeList();
|
||||
byte[] uncles = getUnclesEncoded();
|
||||
this.rlpEncoded = RLP.encodeList(header, transactions, uncles);
|
||||
}
|
||||
return rlpEncoded;
|
||||
}
|
||||
|
||||
public byte[] getEncodedWithoutNonce() {
|
||||
if (!parsed) parseRLP();
|
||||
byte[] header = this.header.getEncodedWithoutNonce();
|
||||
|
||||
public byte[] getEncoded() {
|
||||
if(rlpEncoded == null) {
|
||||
byte[] header = this.header.getEncoded();
|
||||
byte[] transactions = RLP.encodeList();
|
||||
byte[] uncles = getUnclesEncoded();
|
||||
this.rlpEncoded = RLP.encodeList(header, transactions, uncles);
|
||||
}
|
||||
return rlpEncoded;
|
||||
}
|
||||
|
||||
public byte[] getEncodedWithoutNonce() {
|
||||
if (!parsed) parseRLP();
|
||||
byte[] header = this.header.getEncodedWithoutNonce();
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
public String getShortHash(){
|
||||
if (!parsed) parseRLP();
|
||||
|
@ -15,10 +15,10 @@ import static org.ethereum.util.ByteUtil.toHexString;
|
||||
* the basic information of a block
|
||||
*/
|
||||
public class BlockHeader {
|
||||
|
||||
|
||||
|
||||
/* The SHA3 256-bit hash of the parent block, in its entirety */
|
||||
private byte[] parentHash;
|
||||
private byte[] parentHash;
|
||||
/* The SHA3 256-bit hash of the uncles list portion of this block */
|
||||
private byte[] unclesHash;
|
||||
/* The 160-bit address to which all fees collected from the
|
||||
@ -70,7 +70,7 @@ public class BlockHeader {
|
||||
|
||||
this.txTrieRoot = rlpHeader.get(4).getRLPData();
|
||||
if(this.txTrieRoot == null)
|
||||
this.txTrieRoot = EMPTY_TRIE_HASH;
|
||||
this.txTrieRoot = EMPTY_TRIE_HASH;
|
||||
|
||||
this.recieptTrieRoot = rlpHeader.get(5).getRLPData();
|
||||
if(this.recieptTrieRoot == null)
|
||||
@ -84,10 +84,10 @@ public class BlockHeader {
|
||||
byte[] guBytes = rlpHeader.get(10).getRLPData();
|
||||
byte[] tsBytes = rlpHeader.get(11).getRLPData();
|
||||
|
||||
this.number = nrBytes == null ? 0 : (new BigInteger(1, nrBytes)).longValue();
|
||||
this.number = nrBytes == null ? 0 : (new BigInteger(1, nrBytes)).longValue();
|
||||
|
||||
this.gasLimit = glBytes == null ? 0 : (new BigInteger(1, glBytes)).longValue();
|
||||
this.gasUsed = guBytes == null ? 0 : (new BigInteger(1, guBytes)).longValue();
|
||||
this.gasLimit = glBytes == null ? 0 : (new BigInteger(1, glBytes)).longValue();
|
||||
this.gasUsed = guBytes == null ? 0 : (new BigInteger(1, guBytes)).longValue();
|
||||
this.timestamp = tsBytes == null ? 0 : (new BigInteger(1, tsBytes)).longValue();
|
||||
|
||||
this.extraData = rlpHeader.get(12).getRLPData();
|
||||
@ -95,7 +95,7 @@ public class BlockHeader {
|
||||
|
||||
}
|
||||
|
||||
public BlockHeader(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
|
||||
public BlockHeader(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
|
||||
byte[] logsBloom, byte[] difficulty, long number,
|
||||
long gasLimit, long gasUsed, long timestamp,
|
||||
byte[] extraData, byte[] nonce) {
|
||||
@ -112,62 +112,62 @@ public class BlockHeader {
|
||||
this.nonce = nonce;
|
||||
this.stateRoot = HashUtil.EMPTY_TRIE_HASH;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate Difficulty
|
||||
* See Yellow Paper: http://www.gavwood.com/Paper.pdf - page 5, 4.3.4 (24)
|
||||
* @return byte array value of the difficulty
|
||||
*/
|
||||
public byte[] calcDifficulty() {
|
||||
if (this.isGenesis())
|
||||
return Genesis.DIFFICULTY;
|
||||
else { //todo find the right way to calc difficulty
|
||||
// Block parent = this.getParent();
|
||||
// long parentDifficulty = new BigInteger(1, parent.getDifficulty()).longValue();
|
||||
// long newDifficulty = this.getTimestamp() < parent.getTimestamp() + 5 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10));
|
||||
// return BigIntegers.asUnsignedByteArray(BigInteger.valueOf(newDifficulty));
|
||||
/**
|
||||
* Calculate Difficulty
|
||||
* See Yellow Paper: http://www.gavwood.com/Paper.pdf - page 5, 4.3.4 (24)
|
||||
* @return byte array value of the difficulty
|
||||
*/
|
||||
public byte[] calcDifficulty() {
|
||||
if (this.isGenesis())
|
||||
return Genesis.DIFFICULTY;
|
||||
else { //todo find the right way to calc difficulty
|
||||
// Block parent = this.getParent();
|
||||
// long parentDifficulty = new BigInteger(1, parent.getDifficulty()).longValue();
|
||||
// long newDifficulty = this.getTimestamp() < parent.getTimestamp() + 5 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10));
|
||||
// return BigIntegers.asUnsignedByteArray(BigInteger.valueOf(newDifficulty));
|
||||
return this.getDifficulty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean isGenesis() {
|
||||
return this.getNumber() == Genesis.NUMBER;
|
||||
}
|
||||
public boolean isGenesis() {
|
||||
return this.getNumber() == Genesis.NUMBER;
|
||||
}
|
||||
|
||||
public byte[] getParentHash() {
|
||||
return parentHash;
|
||||
}
|
||||
public void setParentHash(byte[] parentHash) {
|
||||
this.parentHash = parentHash;
|
||||
}
|
||||
public byte[] getUnclesHash() {
|
||||
return unclesHash;
|
||||
}
|
||||
public void setUnclesHash(byte[] unclesHash) {
|
||||
this.unclesHash = unclesHash;
|
||||
}
|
||||
public byte[] getCoinbase() {
|
||||
return coinbase;
|
||||
}
|
||||
public void setCoinbase(byte[] coinbase) {
|
||||
this.coinbase = coinbase;
|
||||
}
|
||||
public byte[] getStateRoot() {
|
||||
return stateRoot;
|
||||
}
|
||||
public void setStateRoot(byte[] stateRoot) {
|
||||
this.stateRoot = stateRoot;
|
||||
}
|
||||
public byte[] getTxTrieRoot() {
|
||||
return txTrieRoot;
|
||||
}
|
||||
public void setTxTrieRoot(byte[] txTrieRoot) {
|
||||
this.txTrieRoot = txTrieRoot;
|
||||
}
|
||||
public byte[] getParentHash() {
|
||||
return parentHash;
|
||||
}
|
||||
public void setParentHash(byte[] parentHash) {
|
||||
this.parentHash = parentHash;
|
||||
}
|
||||
public byte[] getUnclesHash() {
|
||||
return unclesHash;
|
||||
}
|
||||
public void setUnclesHash(byte[] unclesHash) {
|
||||
this.unclesHash = unclesHash;
|
||||
}
|
||||
public byte[] getCoinbase() {
|
||||
return coinbase;
|
||||
}
|
||||
public void setCoinbase(byte[] coinbase) {
|
||||
this.coinbase = coinbase;
|
||||
}
|
||||
public byte[] getStateRoot() {
|
||||
return stateRoot;
|
||||
}
|
||||
public void setStateRoot(byte[] stateRoot) {
|
||||
this.stateRoot = stateRoot;
|
||||
}
|
||||
public byte[] getTxTrieRoot() {
|
||||
return txTrieRoot;
|
||||
}
|
||||
public void setTxTrieRoot(byte[] txTrieRoot) {
|
||||
this.txTrieRoot = txTrieRoot;
|
||||
}
|
||||
public byte[] getRecieptTrieRoot() {
|
||||
return recieptTrieRoot;
|
||||
}
|
||||
@ -176,126 +176,126 @@ public class BlockHeader {
|
||||
this.recieptTrieRoot = recieptTrieRoot;
|
||||
}
|
||||
public byte[] getDifficulty() {
|
||||
return difficulty;
|
||||
}
|
||||
public void setDifficulty(byte[] difficulty) {
|
||||
this.difficulty = difficulty;
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
public long getNumber() {
|
||||
return number;
|
||||
}
|
||||
public void setNumber(long number) {
|
||||
this.number = number;
|
||||
}
|
||||
public long getGasLimit() {
|
||||
return gasLimit;
|
||||
}
|
||||
public void setGasLimit(long gasLimit) {
|
||||
this.gasLimit = gasLimit;
|
||||
}
|
||||
public long getGasUsed() {
|
||||
return gasUsed;
|
||||
}
|
||||
public void setGasUsed(long gasUsed) {
|
||||
this.gasUsed = gasUsed;
|
||||
}
|
||||
public byte[] getExtraData() {
|
||||
return extraData;
|
||||
}
|
||||
public void setExtraData(byte[] extraData) {
|
||||
this.extraData = extraData;
|
||||
}
|
||||
public byte[] getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
public void setNonce(byte[] nonce) {
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
return this.getEncoded(true); // with nonce
|
||||
}
|
||||
|
||||
public byte[] getEncodedWithoutNonce() {
|
||||
return difficulty;
|
||||
}
|
||||
public void setDifficulty(byte[] difficulty) {
|
||||
this.difficulty = difficulty;
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
public long getNumber() {
|
||||
return number;
|
||||
}
|
||||
public void setNumber(long number) {
|
||||
this.number = number;
|
||||
}
|
||||
public long getGasLimit() {
|
||||
return gasLimit;
|
||||
}
|
||||
public void setGasLimit(long gasLimit) {
|
||||
this.gasLimit = gasLimit;
|
||||
}
|
||||
public long getGasUsed() {
|
||||
return gasUsed;
|
||||
}
|
||||
public void setGasUsed(long gasUsed) {
|
||||
this.gasUsed = gasUsed;
|
||||
}
|
||||
public byte[] getExtraData() {
|
||||
return extraData;
|
||||
}
|
||||
public void setExtraData(byte[] extraData) {
|
||||
this.extraData = extraData;
|
||||
}
|
||||
public byte[] getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
public void setNonce(byte[] nonce) {
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
return this.getEncoded(true); // with nonce
|
||||
}
|
||||
|
||||
public byte[] getEncodedWithoutNonce() {
|
||||
return this.getEncoded(false);
|
||||
}
|
||||
|
||||
public byte[] getEncoded(boolean withNonce) {
|
||||
byte[] parentHash = RLP.encodeElement(this.parentHash);
|
||||
}
|
||||
|
||||
public byte[] getEncoded(boolean withNonce) {
|
||||
byte[] parentHash = RLP.encodeElement(this.parentHash);
|
||||
|
||||
byte[] unclesHash = RLP.encodeElement(this.unclesHash);
|
||||
byte[] coinbase = RLP.encodeElement(this.coinbase);
|
||||
byte[] unclesHash = RLP.encodeElement(this.unclesHash);
|
||||
byte[] coinbase = RLP.encodeElement(this.coinbase);
|
||||
|
||||
byte[] stateRoot = RLP.encodeElement(this.stateRoot);
|
||||
byte[] stateRoot = RLP.encodeElement(this.stateRoot);
|
||||
|
||||
if (txTrieRoot == null) this.txTrieRoot = EMPTY_TRIE_HASH;
|
||||
byte[] txTrieRoot = RLP.encodeElement(this.txTrieRoot);
|
||||
byte[] txTrieRoot = RLP.encodeElement(this.txTrieRoot);
|
||||
|
||||
if (recieptTrieRoot == null) this.recieptTrieRoot = EMPTY_TRIE_HASH;
|
||||
byte[] recieptTrieRoot = RLP.encodeElement(this.recieptTrieRoot);
|
||||
byte[] recieptTrieRoot = RLP.encodeElement(this.recieptTrieRoot);
|
||||
|
||||
byte[] logsBloom = RLP.encodeElement(this.logsBloom);
|
||||
byte[] difficulty = RLP.encodeElement(this.difficulty);
|
||||
byte[] number = RLP.encodeBigInteger(BigInteger.valueOf(this.number));
|
||||
byte[] gasLimit = RLP.encodeBigInteger(BigInteger.valueOf(this.gasLimit));
|
||||
byte[] gasUsed = RLP.encodeBigInteger(BigInteger.valueOf(this.gasUsed));
|
||||
byte[] timestamp = RLP.encodeBigInteger(BigInteger.valueOf(this.timestamp));
|
||||
byte[] extraData = RLP.encodeElement(this.extraData);
|
||||
byte[] difficulty = RLP.encodeElement(this.difficulty);
|
||||
byte[] number = RLP.encodeBigInteger(BigInteger.valueOf(this.number));
|
||||
byte[] gasLimit = RLP.encodeBigInteger(BigInteger.valueOf(this.gasLimit));
|
||||
byte[] gasUsed = RLP.encodeBigInteger(BigInteger.valueOf(this.gasUsed));
|
||||
byte[] timestamp = RLP.encodeBigInteger(BigInteger.valueOf(this.timestamp));
|
||||
byte[] extraData = RLP.encodeElement(this.extraData);
|
||||
if(withNonce) {
|
||||
byte[] nonce = RLP.encodeElement(this.nonce);
|
||||
return RLP.encodeList(parentHash, unclesHash, coinbase,
|
||||
stateRoot, txTrieRoot, recieptTrieRoot, logsBloom, difficulty, number,
|
||||
gasLimit, gasUsed, timestamp, extraData, nonce);
|
||||
byte[] nonce = RLP.encodeElement(this.nonce);
|
||||
return RLP.encodeList(parentHash, unclesHash, coinbase,
|
||||
stateRoot, txTrieRoot, recieptTrieRoot, logsBloom, difficulty, number,
|
||||
gasLimit, gasUsed, timestamp, extraData, nonce);
|
||||
} else {
|
||||
return RLP.encodeList(parentHash, unclesHash, coinbase,
|
||||
stateRoot, txTrieRoot, recieptTrieRoot, logsBloom, difficulty, number,
|
||||
gasLimit, gasUsed, timestamp, extraData);
|
||||
return RLP.encodeList(parentHash, unclesHash, coinbase,
|
||||
stateRoot, txTrieRoot, recieptTrieRoot, logsBloom, difficulty, number,
|
||||
gasLimit, gasUsed, timestamp, extraData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private StringBuffer toStringBuff = new StringBuffer();
|
||||
|
||||
public String toString() {
|
||||
private StringBuffer toStringBuff = new StringBuffer();
|
||||
|
||||
public String toString() {
|
||||
|
||||
toStringBuff.setLength(0);
|
||||
toStringBuff.append(" parentHash=" + toHexString(parentHash)).append("\n");
|
||||
toStringBuff.append(" unclesHash=" + toHexString(unclesHash)).append("\n");
|
||||
toStringBuff.append(" coinbase=" + toHexString(coinbase)).append("\n");
|
||||
toStringBuff.append(" stateRoot=" + toHexString(stateRoot)).append("\n");
|
||||
toStringBuff.append(" txTrieHash=" + toHexString(txTrieRoot)).append("\n");
|
||||
toStringBuff.append(" reciptsTrieHash=" + toHexString(recieptTrieRoot)).append("\n");
|
||||
toStringBuff.append(" difficulty=" + toHexString(difficulty)).append("\n");
|
||||
toStringBuff.append(" number=" + number).append("\n");
|
||||
toStringBuff.append(" gasLimit=" + gasLimit).append("\n");
|
||||
toStringBuff.append(" gasUsed=" + gasUsed).append("\n");
|
||||
toStringBuff.append(" timestamp=" + timestamp + " (" + Utils.longToDateTime(timestamp) + ")").append("\n");
|
||||
toStringBuff.append(" extraData=" + toHexString(extraData)).append("\n");
|
||||
toStringBuff.append(" nonce=" + toHexString(nonce)).append("\n");
|
||||
toStringBuff.append(" stateRoot=" + toHexString(stateRoot)).append("\n");
|
||||
toStringBuff.append(" txTrieHash=" + toHexString(txTrieRoot)).append("\n");
|
||||
toStringBuff.append(" reciptsTrieHash=" + toHexString(recieptTrieRoot)).append("\n");
|
||||
toStringBuff.append(" difficulty=" + toHexString(difficulty)).append("\n");
|
||||
toStringBuff.append(" number=" + number).append("\n");
|
||||
toStringBuff.append(" gasLimit=" + gasLimit).append("\n");
|
||||
toStringBuff.append(" gasUsed=" + gasUsed).append("\n");
|
||||
toStringBuff.append(" timestamp=" + timestamp + " (" + Utils.longToDateTime(timestamp) + ")").append("\n");
|
||||
toStringBuff.append(" extraData=" + toHexString(extraData)).append("\n");
|
||||
toStringBuff.append(" nonce=" + toHexString(nonce)).append("\n");
|
||||
return toStringBuff.toString();
|
||||
}
|
||||
|
||||
public String toFlatString() {
|
||||
}
|
||||
|
||||
public String toFlatString() {
|
||||
toStringBuff.append(" parentHash=" + toHexString(parentHash)).append("");
|
||||
toStringBuff.append(" unclesHash=" + toHexString(unclesHash)).append("");
|
||||
toStringBuff.append(" coinbase=" + toHexString(coinbase)).append("");
|
||||
toStringBuff.append(" stateRoot=" + toHexString(stateRoot)).append("");
|
||||
toStringBuff.append(" txTrieHash=" + toHexString(txTrieRoot)).append("");
|
||||
toStringBuff.append(" difficulty=" + toHexString(difficulty)).append("");
|
||||
toStringBuff.append(" number=" + number).append("");
|
||||
toStringBuff.append(" gasLimit=" + gasLimit).append("");
|
||||
toStringBuff.append(" gasUsed=" + gasUsed).append("");
|
||||
toStringBuff.append(" timestamp=" + timestamp).append("");
|
||||
toStringBuff.append(" extraData=" + toHexString(extraData)).append("");
|
||||
toStringBuff.append(" nonce=" + toHexString(nonce)).append("");
|
||||
toStringBuff.append(" stateRoot=" + toHexString(stateRoot)).append("");
|
||||
toStringBuff.append(" txTrieHash=" + toHexString(txTrieRoot)).append("");
|
||||
toStringBuff.append(" difficulty=" + toHexString(difficulty)).append("");
|
||||
toStringBuff.append(" number=" + number).append("");
|
||||
toStringBuff.append(" gasLimit=" + gasLimit).append("");
|
||||
toStringBuff.append(" gasUsed=" + gasUsed).append("");
|
||||
toStringBuff.append(" timestamp=" + timestamp).append("");
|
||||
toStringBuff.append(" extraData=" + toHexString(extraData)).append("");
|
||||
toStringBuff.append(" nonce=" + toHexString(nonce)).append("");
|
||||
return toStringBuff.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ import static org.ethereum.core.Denomination.SZABO;
|
||||
* <li>Check that the proof of work on the block is valid.</li>
|
||||
* <li>Let S[0] be the STATE_ROOT of the previous block.</li>
|
||||
* <li>Let TX be the block's transaction list, with n transactions.
|
||||
* For all in in 0...n-1, set S[i+1] = APPLY(S[i],TX[i]).
|
||||
* For all in in 0...n-1, set S[i+1] = APPLY(S[i],TX[i]).
|
||||
* If any applications returns an error, or if the total gas consumed in the block
|
||||
* up until this point exceeds the GASLIMIT, return an error.</li>
|
||||
* <li>Let S_FINAL be S[n], but adding the block reward paid to the miner.</li>
|
||||
@ -64,14 +64,14 @@ public class BlockchainImpl implements Blockchain {
|
||||
/* A scalar value equal to the mininum limit of gas expenditure per block */
|
||||
private static long MIN_GAS_LIMIT = 125000L;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("blockchain");
|
||||
private static final Logger stateLogger = LoggerFactory.getLogger("state");
|
||||
|
||||
// to avoid using minGasPrice=0 from Genesis for the wallet
|
||||
private static final long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
|
||||
private static final Logger logger = LoggerFactory.getLogger("blockchain");
|
||||
private static final Logger stateLogger = LoggerFactory.getLogger("state");
|
||||
|
||||
// to avoid using minGasPrice=0 from Genesis for the wallet
|
||||
private static final long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
|
||||
|
||||
@Autowired
|
||||
private Repository repository;
|
||||
private Repository repository;
|
||||
private Repository track;
|
||||
|
||||
@Autowired
|
||||
@ -115,8 +115,8 @@ public class BlockchainImpl implements Blockchain {
|
||||
|
||||
@Override
|
||||
public Block getBlockByNumber(long blockNr) {
|
||||
return blockStore.getBlockByNumber(blockNr);
|
||||
}
|
||||
return blockStore.getBlockByNumber(blockNr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionReceipt getTransactionReceiptByHash(byte[] hash){
|
||||
@ -193,8 +193,8 @@ public class BlockchainImpl implements Blockchain {
|
||||
public void add(Block block) {
|
||||
|
||||
track = repository.startTracking();
|
||||
if (block == null)
|
||||
return;
|
||||
if (block == null)
|
||||
return;
|
||||
|
||||
// keep chain continuity
|
||||
if (!Arrays.equals(getBestBlock().getHash(),
|
||||
@ -300,7 +300,7 @@ public class BlockchainImpl implements Blockchain {
|
||||
private void processBlock(Block block) {
|
||||
|
||||
List<TransactionReceipt> receipts = new ArrayList<>();
|
||||
if(isValid(block)) {
|
||||
if(isValid(block)) {
|
||||
if (!block.isGenesis()) {
|
||||
if (!CONFIG.blockChainOnly()) {
|
||||
wallet.addTransactions(block.getTransactionsList());
|
||||
@ -309,26 +309,26 @@ public class BlockchainImpl implements Blockchain {
|
||||
}
|
||||
}
|
||||
this.storeBlock(block, receipts);
|
||||
} else {
|
||||
logger.warn("Invalid block with nr: {}", block.getNumber());
|
||||
}
|
||||
} else {
|
||||
logger.warn("Invalid block with nr: {}", block.getNumber());
|
||||
}
|
||||
}
|
||||
|
||||
private List<TransactionReceipt> applyBlock(Block block) {
|
||||
private List<TransactionReceipt> applyBlock(Block block) {
|
||||
|
||||
int i = 1;
|
||||
long totalGasUsed = 0;
|
||||
int i = 1;
|
||||
long totalGasUsed = 0;
|
||||
List<TransactionReceipt> reciepts = new ArrayList<>();
|
||||
|
||||
for (Transaction tx : block.getTransactionsList()) {
|
||||
stateLogger.info("apply block: [{}] tx: [{}] ", block.getNumber(), i);
|
||||
for (Transaction tx : block.getTransactionsList()) {
|
||||
stateLogger.info("apply block: [{}] tx: [{}] ", block.getNumber(), i);
|
||||
|
||||
TransactionExecutor executor = new TransactionExecutor(tx, block.getCoinbase(), track,
|
||||
programInvokeFactory, block);
|
||||
executor.execute();
|
||||
|
||||
TransactionReceipt receipt = executor.getReceipt();
|
||||
totalGasUsed += receipt.getCumulativeGasLong();
|
||||
totalGasUsed += receipt.getCumulativeGasLong();
|
||||
|
||||
track.commit();
|
||||
receipt.setCumulativeGas(totalGasUsed);
|
||||
@ -347,42 +347,42 @@ public class BlockchainImpl implements Blockchain {
|
||||
repository.dumpState(block, totalGasUsed, i++, tx.getHash());
|
||||
|
||||
reciepts.add(receipt);
|
||||
}
|
||||
}
|
||||
|
||||
this.addReward(block);
|
||||
this.addReward(block);
|
||||
this.updateTotalDifficulty(block);
|
||||
|
||||
track.commit();
|
||||
|
||||
if(block.getNumber() >= CONFIG.traceStartBlock())
|
||||
repository.dumpState(block, totalGasUsed, 0, null);
|
||||
repository.dumpState(block, totalGasUsed, 0, null);
|
||||
|
||||
return reciepts;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add reward to block- and every uncle coinbase
|
||||
* assuming the entire block is valid.
|
||||
*
|
||||
* @param block object containing the header and uncles
|
||||
*/
|
||||
private void addReward(Block block) {
|
||||
/**
|
||||
* Add reward to block- and every uncle coinbase
|
||||
* assuming the entire block is valid.
|
||||
*
|
||||
* @param block object containing the header and uncles
|
||||
*/
|
||||
private void addReward(Block block) {
|
||||
|
||||
// Add standard block reward
|
||||
BigInteger totalBlockReward = Block.BLOCK_REWARD;
|
||||
|
||||
// Add extra rewards based on number of uncles
|
||||
if(block.getUncleList().size() > 0) {
|
||||
for (BlockHeader uncle : block.getUncleList()) {
|
||||
track.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
|
||||
}
|
||||
totalBlockReward = totalBlockReward.add(Block.INCLUSION_REWARD
|
||||
.multiply(BigInteger.valueOf(block.getUncleList().size())));
|
||||
}
|
||||
// Add standard block reward
|
||||
BigInteger totalBlockReward = Block.BLOCK_REWARD;
|
||||
|
||||
// Add extra rewards based on number of uncles
|
||||
if(block.getUncleList().size() > 0) {
|
||||
for (BlockHeader uncle : block.getUncleList()) {
|
||||
track.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
|
||||
}
|
||||
totalBlockReward = totalBlockReward.add(Block.INCLUSION_REWARD
|
||||
.multiply(BigInteger.valueOf(block.getUncleList().size())));
|
||||
}
|
||||
track.addBalance(block.getCoinbase(), totalBlockReward);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void storeBlock(Block block, List<TransactionReceipt> receipts) {
|
||||
|
||||
/* Debug check to see if the state is still as expected */
|
||||
@ -391,7 +391,7 @@ public class BlockchainImpl implements Blockchain {
|
||||
String worldStateRootHash = Hex.toHexString(repository.getRoot());
|
||||
if(!blockStateRootHash.equals(worldStateRootHash)){
|
||||
|
||||
stateLogger.info("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
|
||||
stateLogger.info("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
|
||||
adminInfo.lostConsensus();
|
||||
|
||||
// in case of rollback hard move the root
|
||||
@ -402,12 +402,12 @@ public class BlockchainImpl implements Blockchain {
|
||||
}
|
||||
|
||||
blockStore.saveBlock(block, receipts);
|
||||
this.setBestBlock(block);
|
||||
this.setBestBlock(block);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("block added to the blockChain: index: [{}]", block.getNumber());
|
||||
logger.debug("block added to the blockChain: index: [{}]", block.getNumber());
|
||||
if (block.getNumber() % 100 == 0)
|
||||
logger.info("*** Last block added [ #{} ]", block.getNumber());
|
||||
logger.info("*** Last block added [ #{} ]", block.getNumber());
|
||||
}
|
||||
|
||||
|
||||
@ -426,8 +426,8 @@ public class BlockchainImpl implements Blockchain {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockQueue getQueue() {
|
||||
@Override
|
||||
public BlockQueue getQueue() {
|
||||
return blockQueue;
|
||||
}
|
||||
|
||||
@ -453,15 +453,15 @@ public class BlockchainImpl implements Blockchain {
|
||||
blockQueue.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getTotalDifficulty() {
|
||||
return totalDifficulty;
|
||||
}
|
||||
@Override
|
||||
public BigInteger getTotalDifficulty() {
|
||||
return totalDifficulty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTotalDifficulty(Block block) {
|
||||
this.totalDifficulty = totalDifficulty.add(block.getCumulativeDifficulty());
|
||||
}
|
||||
@Override
|
||||
public void updateTotalDifficulty(Block block) {
|
||||
this.totalDifficulty = totalDifficulty.add(block.getCumulativeDifficulty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTotalDifficulty(BigInteger totalDifficulty) {
|
||||
|
@ -4,60 +4,60 @@ import java.math.BigInteger;
|
||||
|
||||
public enum Denomination {
|
||||
|
||||
WEI(newBigInt(0)),
|
||||
ADA(newBigInt(3)),
|
||||
BABBAGE(newBigInt(6)),
|
||||
SHANNON(newBigInt(9)),
|
||||
SZABO(newBigInt(12)),
|
||||
FINNY(newBigInt(15)),
|
||||
ETHER(newBigInt(18)),
|
||||
EINSTEIN(newBigInt(21)),
|
||||
DOUGLAS(newBigInt(42));
|
||||
|
||||
private BigInteger amount;
|
||||
|
||||
private Denomination(BigInteger value) {
|
||||
this.amount = value;
|
||||
}
|
||||
WEI(newBigInt(0)),
|
||||
ADA(newBigInt(3)),
|
||||
BABBAGE(newBigInt(6)),
|
||||
SHANNON(newBigInt(9)),
|
||||
SZABO(newBigInt(12)),
|
||||
FINNY(newBigInt(15)),
|
||||
ETHER(newBigInt(18)),
|
||||
EINSTEIN(newBigInt(21)),
|
||||
DOUGLAS(newBigInt(42));
|
||||
|
||||
private BigInteger amount;
|
||||
|
||||
private Denomination(BigInteger value) {
|
||||
this.amount = value;
|
||||
}
|
||||
|
||||
public BigInteger value() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public long longValue() {
|
||||
return value().longValue();
|
||||
}
|
||||
public BigInteger value() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public long longValue() {
|
||||
return value().longValue();
|
||||
}
|
||||
|
||||
private static BigInteger newBigInt(int value) {
|
||||
return BigInteger.valueOf(10).pow(value);
|
||||
}
|
||||
|
||||
public static String toFriendlyString(BigInteger value) {
|
||||
if(value.compareTo(DOUGLAS.value()) == 1 || value.compareTo(DOUGLAS.value()) == 0) {
|
||||
return Float.toString(value.divide(DOUGLAS.value()).floatValue()) + " DOUGLAS";
|
||||
}
|
||||
else if(value.compareTo(EINSTEIN.value()) == 1 || value.compareTo(EINSTEIN.value()) == 0) {
|
||||
return Float.toString(value.divide(EINSTEIN.value()).floatValue()) + " EINSTEIN";
|
||||
}
|
||||
else if(value.compareTo(ETHER.value()) == 1 || value.compareTo(ETHER.value()) == 0) {
|
||||
return Float.toString(value.divide(ETHER.value()).floatValue()) + " ETHER";
|
||||
}
|
||||
else if(value.compareTo(FINNY.value()) == 1 || value.compareTo(FINNY.value()) == 0) {
|
||||
return Float.toString(value.divide(FINNY.value()).floatValue()) + " FINNY";
|
||||
}
|
||||
else if(value.compareTo(SZABO.value()) == 1 || value.compareTo(SZABO.value()) == 0) {
|
||||
return Float.toString(value.divide(SZABO.value()).floatValue()) + " SZABO";
|
||||
}
|
||||
else if(value.compareTo(SHANNON.value()) == 1 || value.compareTo(SHANNON.value()) == 0) {
|
||||
return Float.toString(value.divide(SHANNON.value()).floatValue()) + " SHANNON";
|
||||
}
|
||||
else if(value.compareTo(BABBAGE.value()) == 1 || value.compareTo(BABBAGE.value()) == 0) {
|
||||
return Float.toString(value.divide(BABBAGE.value()).floatValue()) + " BABBAGE";
|
||||
}
|
||||
else if(value.compareTo(ADA.value()) == 1 || value.compareTo(ADA.value()) == 0) {
|
||||
return Float.toString(value.divide(ADA.value()).floatValue()) + " ADA";
|
||||
}
|
||||
else
|
||||
return Float.toString(value.divide(WEI.value()).floatValue()) + " WEI";
|
||||
}
|
||||
private static BigInteger newBigInt(int value) {
|
||||
return BigInteger.valueOf(10).pow(value);
|
||||
}
|
||||
|
||||
public static String toFriendlyString(BigInteger value) {
|
||||
if(value.compareTo(DOUGLAS.value()) == 1 || value.compareTo(DOUGLAS.value()) == 0) {
|
||||
return Float.toString(value.divide(DOUGLAS.value()).floatValue()) + " DOUGLAS";
|
||||
}
|
||||
else if(value.compareTo(EINSTEIN.value()) == 1 || value.compareTo(EINSTEIN.value()) == 0) {
|
||||
return Float.toString(value.divide(EINSTEIN.value()).floatValue()) + " EINSTEIN";
|
||||
}
|
||||
else if(value.compareTo(ETHER.value()) == 1 || value.compareTo(ETHER.value()) == 0) {
|
||||
return Float.toString(value.divide(ETHER.value()).floatValue()) + " ETHER";
|
||||
}
|
||||
else if(value.compareTo(FINNY.value()) == 1 || value.compareTo(FINNY.value()) == 0) {
|
||||
return Float.toString(value.divide(FINNY.value()).floatValue()) + " FINNY";
|
||||
}
|
||||
else if(value.compareTo(SZABO.value()) == 1 || value.compareTo(SZABO.value()) == 0) {
|
||||
return Float.toString(value.divide(SZABO.value()).floatValue()) + " SZABO";
|
||||
}
|
||||
else if(value.compareTo(SHANNON.value()) == 1 || value.compareTo(SHANNON.value()) == 0) {
|
||||
return Float.toString(value.divide(SHANNON.value()).floatValue()) + " SHANNON";
|
||||
}
|
||||
else if(value.compareTo(BABBAGE.value()) == 1 || value.compareTo(BABBAGE.value()) == 0) {
|
||||
return Float.toString(value.divide(BABBAGE.value()).floatValue()) + " BABBAGE";
|
||||
}
|
||||
else if(value.compareTo(ADA.value()) == 1 || value.compareTo(ADA.value()) == 0) {
|
||||
return Float.toString(value.divide(ADA.value()).floatValue()) + " ADA";
|
||||
}
|
||||
else
|
||||
return Float.toString(value.divide(WEI.value()).floatValue()) + " WEI";
|
||||
}
|
||||
}
|
||||
|
@ -28,26 +28,26 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class Genesis extends Block {
|
||||
|
||||
public final static BigInteger PREMINE_AMOUNT = BigInteger.valueOf(2).pow(200);
|
||||
|
||||
public final static BigInteger PREMINE_AMOUNT = BigInteger.valueOf(2).pow(200);
|
||||
|
||||
private static String[] premine = new String[] {
|
||||
"51ba59315b3a95761d0863b05ccc7a7f54703d99",
|
||||
"e6716f9544a56c530d868e4bfbacb172315bdead", // # (J)
|
||||
"b9c015918bdaba24b4ff057a92a3873d6eb201be", // # (V)
|
||||
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // # (A)
|
||||
"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // # (M)
|
||||
"e6716f9544a56c530d868e4bfbacb172315bdead", // # (J)
|
||||
"b9c015918bdaba24b4ff057a92a3873d6eb201be", // # (V)
|
||||
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // # (A)
|
||||
"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // # (M)
|
||||
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // # (R)
|
||||
"6c386a4b26f73c802f34673f7248bb118f97424a", // # (HH)
|
||||
"e4157b34ea9615cfbde6b4fda419828124b70c78", // # (CH)
|
||||
"6c386a4b26f73c802f34673f7248bb118f97424a", // # (HH)
|
||||
"e4157b34ea9615cfbde6b4fda419828124b70c78", // # (CH)
|
||||
};
|
||||
|
||||
private static byte[] zeroHash256 = new byte[32];
|
||||
private static byte[] zeroHash160 = new byte[20];
|
||||
private static byte[] zeroHash512 = new byte[64];
|
||||
private static byte[] zeroHash256 = new byte[32];
|
||||
private static byte[] zeroHash160 = new byte[20];
|
||||
private static byte[] zeroHash512 = new byte[64];
|
||||
|
||||
public static byte[] PARENT_HASH = zeroHash256;
|
||||
public static byte[] UNCLES_HASH = EMPTY_LIST_HASH;
|
||||
public static byte[] COINBASE = zeroHash160;
|
||||
public static byte[] PARENT_HASH = zeroHash256;
|
||||
public static byte[] UNCLES_HASH = EMPTY_LIST_HASH;
|
||||
public static byte[] COINBASE = zeroHash160;
|
||||
public static byte[] LOG_BLOOM = zeroHash512;
|
||||
public static byte[] DIFFICULTY = BigInteger.valueOf(2).pow(17).toByteArray();
|
||||
public static long NUMBER = 0;
|
||||
@ -59,30 +59,30 @@ public class Genesis extends Block {
|
||||
|
||||
private static Block instance;
|
||||
|
||||
private Genesis() {
|
||||
super(PARENT_HASH, UNCLES_HASH, COINBASE, LOG_BLOOM, DIFFICULTY,
|
||||
NUMBER, GAS_LIMIT, GAS_USED, TIMESTAMP,
|
||||
EXTRA_DATA, NONCE, null, null);
|
||||
|
||||
Trie state = new TrieImpl(null);
|
||||
private Genesis() {
|
||||
super(PARENT_HASH, UNCLES_HASH, COINBASE, LOG_BLOOM, DIFFICULTY,
|
||||
NUMBER, GAS_LIMIT, GAS_USED, TIMESTAMP,
|
||||
EXTRA_DATA, NONCE, null, null);
|
||||
|
||||
Trie state = new TrieImpl(null);
|
||||
// The proof-of-concept series include a development pre-mine, making the state root hash
|
||||
// some value stateRoot. The latest documentation should be consulted for the value of the state root.
|
||||
for (String address : premine) {
|
||||
AccountState acctState = new AccountState(BigInteger.ZERO, PREMINE_AMOUNT);
|
||||
state.update(Hex.decode(address), acctState.getEncoded());
|
||||
for (String address : premine) {
|
||||
AccountState acctState = new AccountState(BigInteger.ZERO, PREMINE_AMOUNT);
|
||||
state.update(Hex.decode(address), acctState.getEncoded());
|
||||
}
|
||||
|
||||
setStateRoot(state.getRootHash());
|
||||
setStateRoot(state.getRootHash());
|
||||
}
|
||||
|
||||
public static Block getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Genesis();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public final static String[] getPremine() {
|
||||
return premine;
|
||||
}
|
||||
|
||||
public static Block getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Genesis();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public final static String[] getPremine() {
|
||||
return premine;
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ import static org.ethereum.util.ByteUtil.ZERO_BYTE_ARRAY;
|
||||
*/
|
||||
public class Transaction {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Transaction.class);
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Transaction.class);
|
||||
|
||||
/* SHA3 hash of the RLP encoded transaction */
|
||||
private byte[] hash;
|
||||
|
||||
@ -107,9 +107,9 @@ public class Transaction {
|
||||
this.data = transaction.get(5).getRLPData();
|
||||
// only parse signature in case tx is signed
|
||||
if(transaction.get(6).getRLPData() != null) {
|
||||
byte v = transaction.get(6).getRLPData()[0];
|
||||
byte[] r = transaction.get(7).getRLPData();
|
||||
byte[] s = transaction.get(8).getRLPData();
|
||||
byte v = transaction.get(6).getRLPData()[0];
|
||||
byte[] r = transaction.get(7).getRLPData();
|
||||
byte[] s = transaction.get(8).getRLPData();
|
||||
this.signature = ECDSASignature.fromComponents(r, s, v);
|
||||
} else {
|
||||
logger.debug("RLP encoded tx is not signed!");
|
||||
@ -215,16 +215,16 @@ public class Transaction {
|
||||
}
|
||||
|
||||
public byte[] getSender() {
|
||||
try {
|
||||
try {
|
||||
if (sendAddress == null) {
|
||||
ECKey key = ECKey.signatureToKey(getRawHash(), getSignature().toBase64());
|
||||
sendAddress = key.getAddress();
|
||||
}
|
||||
return sendAddress;
|
||||
} catch (SignatureException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
return sendAddress;
|
||||
} catch (SignatureException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void sign(byte[] privKeyBytes) throws MissingPrivateKeyException {
|
||||
@ -262,18 +262,18 @@ public class Transaction {
|
||||
// parse null as 0 for nonce
|
||||
byte[] nonce = null;
|
||||
if ( this.nonce == null || this.nonce.length == 1 && this.nonce[0] == 0){
|
||||
nonce = RLP.encodeElement(null);
|
||||
nonce = RLP.encodeElement(null);
|
||||
} else {
|
||||
nonce = RLP.encodeElement(this.nonce);
|
||||
nonce = RLP.encodeElement(this.nonce);
|
||||
}
|
||||
byte[] gasPrice = RLP.encodeElement(this.gasPrice);
|
||||
byte[] gasLimit = RLP.encodeElement(this.gasLimit);
|
||||
byte[] receiveAddress = RLP.encodeElement(this.receiveAddress);
|
||||
byte[] value = RLP.encodeElement(this.value);
|
||||
byte[] data = RLP.encodeElement(this.data);
|
||||
byte[] gasPrice = RLP.encodeElement(this.gasPrice);
|
||||
byte[] gasLimit = RLP.encodeElement(this.gasLimit);
|
||||
byte[] receiveAddress = RLP.encodeElement(this.receiveAddress);
|
||||
byte[] value = RLP.encodeElement(this.value);
|
||||
byte[] data = RLP.encodeElement(this.data);
|
||||
|
||||
rlpRaw = RLP.encodeList(nonce, gasPrice, gasLimit, receiveAddress,
|
||||
value, data);
|
||||
rlpRaw = RLP.encodeList(nonce, gasPrice, gasLimit, receiveAddress,
|
||||
value, data);
|
||||
return rlpRaw;
|
||||
}
|
||||
|
||||
@ -284,15 +284,15 @@ public class Transaction {
|
||||
// parse null as 0 for nonce
|
||||
byte[] nonce = null;
|
||||
if (this.nonce == null || this.nonce.length == 1 && this.nonce[0] == 0){
|
||||
nonce = RLP.encodeElement(null);
|
||||
nonce = RLP.encodeElement(null);
|
||||
} else {
|
||||
nonce = RLP.encodeElement(this.nonce);
|
||||
nonce = RLP.encodeElement(this.nonce);
|
||||
}
|
||||
byte[] gasPrice = RLP.encodeElement(this.gasPrice);
|
||||
byte[] gasLimit = RLP.encodeElement(this.gasLimit);
|
||||
byte[] receiveAddress = RLP.encodeElement(this.receiveAddress);
|
||||
byte[] value = RLP.encodeElement(this.value);
|
||||
byte[] data = RLP.encodeElement(this.data);
|
||||
byte[] gasPrice = RLP.encodeElement(this.gasPrice);
|
||||
byte[] gasLimit = RLP.encodeElement(this.gasLimit);
|
||||
byte[] receiveAddress = RLP.encodeElement(this.receiveAddress);
|
||||
byte[] value = RLP.encodeElement(this.value);
|
||||
byte[] data = RLP.encodeElement(this.data);
|
||||
|
||||
byte[] v, r, s;
|
||||
|
||||
@ -301,13 +301,13 @@ public class Transaction {
|
||||
r = RLP.encodeElement(BigIntegers.asUnsignedByteArray(signature.r));
|
||||
s = RLP.encodeElement(BigIntegers.asUnsignedByteArray(signature.s));
|
||||
} else {
|
||||
v = RLP.encodeElement(EMPTY_BYTE_ARRAY);
|
||||
r = RLP.encodeElement(EMPTY_BYTE_ARRAY);
|
||||
s = RLP.encodeElement(EMPTY_BYTE_ARRAY);
|
||||
v = RLP.encodeElement(EMPTY_BYTE_ARRAY);
|
||||
r = RLP.encodeElement(EMPTY_BYTE_ARRAY);
|
||||
s = RLP.encodeElement(EMPTY_BYTE_ARRAY);
|
||||
}
|
||||
|
||||
this.rlpEncoded = RLP.encodeList(nonce, gasPrice, gasLimit,
|
||||
receiveAddress, value, data, v, r, s);
|
||||
this.rlpEncoded = RLP.encodeList(nonce, gasPrice, gasLimit,
|
||||
receiveAddress, value, data, v, r, s);
|
||||
|
||||
this.hash = this.getHash();
|
||||
|
||||
|
@ -62,7 +62,7 @@ public class TransactionExecutor {
|
||||
|
||||
// VALIDATE THE SENDER
|
||||
byte[] senderAddress = tx.getSender();
|
||||
// AccountState senderAccount = repository.getAccountState(senderAddress);
|
||||
// AccountState senderAccount = repository.getAccountState(senderAddress);
|
||||
logger.info("tx.sender: [{}]", Hex.toHexString(tx.getSender()));
|
||||
|
||||
// VALIDATE THE NONCE
|
||||
|
@ -35,12 +35,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
@Component
|
||||
public class Wallet {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger("wallet");
|
||||
private Logger logger = LoggerFactory.getLogger("wallet");
|
||||
|
||||
// TODO: a) the values I need to keep for address state is balance & nonce & ECKey
|
||||
// TODO: b) keep it to be easy accessed by the toAddress()
|
||||
// private HashMap<Address, BigInteger> rows = new HashMap<>();
|
||||
|
||||
|
||||
// This map of transaction designed
|
||||
// to approve the tx by external trusted peer
|
||||
private Map<String, WalletTransaction> walletTransactions = new ConcurrentHashMap<>();
|
||||
@ -119,7 +119,7 @@ public class Wallet {
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* 1) the dialog put a pending transaction on the list
|
||||
* 1) the dialog put a pending transaction on the list
|
||||
* 2) the dialog send the transaction to a net
|
||||
* 3) wherever the transaction got in from the wire it will change to approve state
|
||||
* 4) only after the approve a) Wallet state changes
|
||||
@ -130,12 +130,12 @@ public class Wallet {
|
||||
logger.info("pending transaction placed hash: {}", hash );
|
||||
|
||||
WalletTransaction walletTransaction = this.walletTransactions.get(hash);
|
||||
if (walletTransaction != null)
|
||||
walletTransaction.incApproved();
|
||||
else {
|
||||
walletTransaction = new WalletTransaction(transaction);
|
||||
this.walletTransactions.put(hash, walletTransaction);
|
||||
}
|
||||
if (walletTransaction != null)
|
||||
walletTransaction.incApproved();
|
||||
else {
|
||||
walletTransaction = new WalletTransaction(transaction);
|
||||
this.walletTransactions.put(hash, walletTransaction);
|
||||
}
|
||||
|
||||
this.applyTransaction(transaction);
|
||||
|
||||
@ -143,17 +143,17 @@ public class Wallet {
|
||||
}
|
||||
|
||||
public void addTransactions(List<Transaction> transactions) {
|
||||
for (Transaction transaction : transactions) {
|
||||
this.addTransaction(transaction);
|
||||
}
|
||||
for (Transaction transaction : transactions) {
|
||||
this.addTransaction(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTransactions(List<Transaction> transactions) {
|
||||
for (Transaction tx : transactions) {
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("pending cleanup: tx.hash: [{}]", Hex.toHexString(tx.getHash()));
|
||||
this.removeTransaction(tx);
|
||||
}
|
||||
for (Transaction tx : transactions) {
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("pending cleanup: tx.hash: [{}]", Hex.toHexString(tx.getHash()));
|
||||
this.removeTransaction(tx);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTransaction(Transaction transaction) {
|
||||
@ -179,15 +179,15 @@ public class Wallet {
|
||||
|
||||
byte[] receiveAddress = transaction.getReceiveAddress();
|
||||
if(receiveAddress != null) {
|
||||
Account receiver = rows.get(Hex.toHexString(receiveAddress));
|
||||
if (receiver != null) {
|
||||
receiver.addPendingTransaction(transaction);
|
||||
|
||||
logger.info("Pending transaction added to " +
|
||||
"\n account: [{}], " +
|
||||
"\n tx: [{}]",
|
||||
Hex.toHexString(receiver.getAddress()), Hex.toHexString(transaction.getHash()));
|
||||
}
|
||||
Account receiver = rows.get(Hex.toHexString(receiveAddress));
|
||||
if (receiver != null) {
|
||||
receiver.addPendingTransaction(transaction);
|
||||
|
||||
logger.info("Pending transaction added to " +
|
||||
"\n account: [{}], " +
|
||||
"\n tx: [{}]",
|
||||
Hex.toHexString(receiver.getAddress()), Hex.toHexString(transaction.getHash()));
|
||||
}
|
||||
}
|
||||
this.notifyListeners();
|
||||
}
|
||||
@ -207,7 +207,7 @@ public class Wallet {
|
||||
*/
|
||||
public void load() throws IOException, SAXException, ParserConfigurationException {
|
||||
|
||||
/**
|
||||
/**
|
||||
|
||||
<wallet high="8933">
|
||||
<row id=1>
|
||||
@ -330,8 +330,8 @@ public class Wallet {
|
||||
}
|
||||
|
||||
private void notifyListeners() {
|
||||
for (WalletListener listener : listeners)
|
||||
listener.valueChanged();
|
||||
for (WalletListener listener : listeners)
|
||||
listener.valueChanged();
|
||||
}
|
||||
|
||||
public interface WalletListener{
|
||||
|
@ -69,8 +69,8 @@ import org.spongycastle.util.encoders.Hex;
|
||||
* See <a href="https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/com/google/bitcoin/core/ECKey.java">bitcoinj on GitHub</a>
|
||||
*/
|
||||
public class ECKey implements Serializable {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ECKey.class);
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ECKey.class);
|
||||
|
||||
/** The parameters of the secp256k1 curve that Ethereum uses. */
|
||||
public static final ECDomainParameters CURVE;
|
||||
|
||||
@ -126,7 +126,7 @@ public class ECKey implements Serializable {
|
||||
public ECKey(@Nullable BigInteger priv, ECPoint pub) {
|
||||
this.priv = priv;
|
||||
if(pub == null)
|
||||
throw new IllegalArgumentException("Public key may not be null");
|
||||
throw new IllegalArgumentException("Public key may not be null");
|
||||
this.pub = pub;
|
||||
}
|
||||
|
||||
@ -237,8 +237,8 @@ public class ECKey implements Serializable {
|
||||
/** Gets the hash160 form of the public key (as seen in addresses). */
|
||||
public byte[] getAddress() {
|
||||
if (pubKeyHash == null) {
|
||||
byte[] pubBytes = this.pub.getEncoded(false);
|
||||
pubKeyHash = HashUtil.sha3omit12(Arrays.copyOfRange(pubBytes, 1, pubBytes.length));
|
||||
byte[] pubBytes = this.pub.getEncoded(false);
|
||||
pubKeyHash = HashUtil.sha3omit12(Arrays.copyOfRange(pubBytes, 1, pubBytes.length));
|
||||
}
|
||||
return pubKeyHash;
|
||||
}
|
||||
@ -317,9 +317,9 @@ public class ECKey implements Serializable {
|
||||
}
|
||||
|
||||
public static ECDSASignature fromComponents(byte[] r, byte[] s, byte v) {
|
||||
ECDSASignature signature = fromComponents(r, s);
|
||||
signature.v = v;
|
||||
return signature;
|
||||
ECDSASignature signature = fromComponents(r, s);
|
||||
signature.v = v;
|
||||
return signature;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -343,11 +343,11 @@ public class ECKey implements Serializable {
|
||||
}
|
||||
|
||||
public String toBase64() {
|
||||
byte[] sigData = new byte[65]; // 1 header + 32 bytes for R + 32 bytes for S
|
||||
sigData[0] = v;
|
||||
System.arraycopy(bigIntegerToBytes(this.r, 32), 0, sigData, 1, 32);
|
||||
System.arraycopy(bigIntegerToBytes(this.s, 32), 0, sigData, 33, 32);
|
||||
return new String(Base64.encode(sigData), Charset.forName("UTF-8"));
|
||||
byte[] sigData = new byte[65]; // 1 header + 32 bytes for R + 32 bytes for S
|
||||
sigData[0] = v;
|
||||
System.arraycopy(bigIntegerToBytes(this.r, 32), 0, sigData, 1, 32);
|
||||
System.arraycopy(bigIntegerToBytes(this.s, 32), 0, sigData, 33, 32);
|
||||
return new String(Base64.encode(sigData), Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -472,7 +472,7 @@ public class ECKey implements Serializable {
|
||||
return signer.verifySignature(data, signature.r, signature.s);
|
||||
} catch (NullPointerException npe) {
|
||||
// Bouncy Castle contains a bug that can cause NPEs given specially crafted signatures.
|
||||
// Those signatures are inherently invalid/attack sigs so we just fail them here rather than crash the thread.
|
||||
// Those signatures are inherently invalid/attack sigs so we just fail them here rather than crash the thread.
|
||||
logger.error("Caught NPE inside bouncy castle", npe);
|
||||
return false;
|
||||
}
|
||||
|
@ -35,10 +35,10 @@ public class HashUtil {
|
||||
}
|
||||
|
||||
public static byte[] sha256(byte[] input) {
|
||||
return sha256digest.digest(input);
|
||||
return sha256digest.digest(input);
|
||||
}
|
||||
|
||||
public static byte[] sha3(byte[] input) {
|
||||
public static byte[] sha3(byte[] input) {
|
||||
ByteArrayWrapper inputByteArray = new ByteArrayWrapper(input);
|
||||
byte[] result = sha3Cache.get(inputByteArray);
|
||||
if(result != null)
|
||||
@ -46,17 +46,17 @@ public class HashUtil {
|
||||
result = SHA3Helper.sha3(input);
|
||||
sha3Cache.put(inputByteArray, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static byte[] ripemd160(byte[] message) {
|
||||
Digest digest = new RIPEMD160Digest();
|
||||
Digest digest = new RIPEMD160Digest();
|
||||
if (message != null) {
|
||||
byte[] resBuf = new byte[digest.getDigestSize()];
|
||||
digest.update(message, 0, message.length);
|
||||
digest.doFinal(resBuf, 0);
|
||||
return resBuf;
|
||||
}
|
||||
throw new NullPointerException("Can't hash a NULL value");
|
||||
byte[] resBuf = new byte[digest.getDigestSize()];
|
||||
digest.update(message, 0, message.length);
|
||||
digest.doFinal(resBuf, 0);
|
||||
return resBuf;
|
||||
}
|
||||
throw new NullPointerException("Can't hash a NULL value");
|
||||
}
|
||||
|
||||
|
||||
@ -64,8 +64,8 @@ public class HashUtil {
|
||||
* Calculates RIGTMOST160(SHA3(input)). This is used in address calculations.
|
||||
*/
|
||||
public static byte[] sha3omit12(byte[] input) {
|
||||
byte[] hash = sha3(input);
|
||||
return copyOfRange(hash, 12, hash.length);
|
||||
byte[] hash = sha3(input);
|
||||
return copyOfRange(hash, 12, hash.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,9 +6,9 @@ import org.spongycastle.crypto.digests.SHA3Digest;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
public class SHA3Helper {
|
||||
|
||||
private static int DEFAULT_SIZE = 256;
|
||||
|
||||
|
||||
private static int DEFAULT_SIZE = 256;
|
||||
|
||||
public static String sha3String(String message) {
|
||||
return sha3String(message, new SHA3Digest(DEFAULT_SIZE), true);
|
||||
}
|
||||
@ -75,7 +75,7 @@ public class SHA3Helper {
|
||||
digest.doFinal(hash, 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
public enum Size {
|
||||
|
||||
S224(224),
|
||||
|
@ -11,38 +11,38 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class ByteArrayWrapper implements Comparable<ByteArrayWrapper> {
|
||||
|
||||
private final byte[] data;
|
||||
private final byte[] data;
|
||||
|
||||
public ByteArrayWrapper(byte[] data) {
|
||||
if (data == null)
|
||||
throw new NullPointerException("Data must not be null");
|
||||
this.data = data;
|
||||
}
|
||||
public ByteArrayWrapper(byte[] data) {
|
||||
if (data == null)
|
||||
throw new NullPointerException("Data must not be null");
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof ByteArrayWrapper))
|
||||
return false;
|
||||
byte[] otherData = ((ByteArrayWrapper) other).getData();
|
||||
return FastByteComparisons.compareTo(
|
||||
data, 0, data.length,
|
||||
otherData, 0, otherData.length) == 0;
|
||||
}
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof ByteArrayWrapper))
|
||||
return false;
|
||||
byte[] otherData = ((ByteArrayWrapper) other).getData();
|
||||
return FastByteComparisons.compareTo(
|
||||
data, 0, data.length,
|
||||
otherData, 0, otherData.length) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(data);
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ByteArrayWrapper o) {
|
||||
return FastByteComparisons.compareTo(
|
||||
data, 0, data.length,
|
||||
o.getData(), 0, o.getData().length);
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
@Override
|
||||
public int compareTo(ByteArrayWrapper o) {
|
||||
return FastByteComparisons.compareTo(
|
||||
data, 0, data.length,
|
||||
o.getData(), 0, o.getData().length);
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -32,15 +32,15 @@ public class ContractDetails {
|
||||
|
||||
public ContractDetails() {
|
||||
}
|
||||
|
||||
|
||||
public ContractDetails(byte[] rlpCode) {
|
||||
decode(rlpCode);
|
||||
}
|
||||
|
||||
public ContractDetails(Map<DataWord, DataWord> storage, byte[] code) {
|
||||
}
|
||||
public ContractDetails(Map<DataWord, DataWord> storage, byte[] code) {
|
||||
}
|
||||
|
||||
public void put(DataWord key, DataWord value) {
|
||||
public void put(DataWord key, DataWord value) {
|
||||
|
||||
if (value.equals(DataWord.ZERO)) {
|
||||
|
||||
@ -64,21 +64,21 @@ public class ContractDetails {
|
||||
|
||||
this.setDirty(true);
|
||||
this.rlpEncoded = null;
|
||||
}
|
||||
}
|
||||
|
||||
public DataWord get(DataWord key) {
|
||||
public DataWord get(DataWord key) {
|
||||
|
||||
if (storageKeys.size() == 0)
|
||||
return null;
|
||||
if (storageKeys.size() == 0)
|
||||
return null;
|
||||
|
||||
int foundIndex = storageKeys.indexOf(key);
|
||||
if (foundIndex != -1) {
|
||||
int foundIndex = storageKeys.indexOf(key);
|
||||
if (foundIndex != -1) {
|
||||
DataWord value = storageValues.get(foundIndex);
|
||||
return value.clone();
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] getCode() {
|
||||
return code;
|
||||
@ -92,47 +92,47 @@ public class ContractDetails {
|
||||
|
||||
public byte[] getStorageHash() {
|
||||
|
||||
storageTrie = new TrieImpl(null);
|
||||
storageTrie = new TrieImpl(null);
|
||||
// calc the trie for root hash
|
||||
for (int i = 0; i < storageKeys.size(); ++i){
|
||||
storageTrie.update(storageKeys.get(i).getData(), RLP
|
||||
.encodeElement(storageValues.get(i).getNoLeadZeroesData()));
|
||||
storageTrie.update(storageKeys.get(i).getData(), RLP
|
||||
.encodeElement(storageValues.get(i).getNoLeadZeroesData()));
|
||||
}
|
||||
return storageTrie.getRootHash();
|
||||
}
|
||||
|
||||
public void decode(byte[] rlpCode) {
|
||||
RLPList data = RLP.decode2(rlpCode);
|
||||
RLPList rlpList = (RLPList) data.get(0);
|
||||
public void decode(byte[] rlpCode) {
|
||||
RLPList data = RLP.decode2(rlpCode);
|
||||
RLPList rlpList = (RLPList) data.get(0);
|
||||
|
||||
RLPList keys = (RLPList) rlpList.get(0);
|
||||
RLPList values = (RLPList) rlpList.get(1);
|
||||
RLPElement code = (RLPElement) rlpList.get(2);
|
||||
RLPList keys = (RLPList) rlpList.get(0);
|
||||
RLPList values = (RLPList) rlpList.get(1);
|
||||
RLPElement code = (RLPElement) rlpList.get(2);
|
||||
|
||||
if (keys.size() > 0) {
|
||||
storageKeys = new ArrayList<>();
|
||||
storageValues = new ArrayList<>();
|
||||
}
|
||||
if (keys.size() > 0) {
|
||||
storageKeys = new ArrayList<>();
|
||||
storageValues = new ArrayList<>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
RLPItem rlpItem = (RLPItem) keys.get(i);
|
||||
storageKeys.add(new DataWord(rlpItem.getRLPData()));
|
||||
}
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
RLPItem rlpItem = (RLPItem) keys.get(i);
|
||||
storageKeys.add(new DataWord(rlpItem.getRLPData()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < values.size(); ++i) {
|
||||
RLPItem rlpItem = (RLPItem) values.get(i);
|
||||
storageValues.add(new DataWord(rlpItem.getRLPData()));
|
||||
}
|
||||
for (int i = 0; i < values.size(); ++i) {
|
||||
RLPItem rlpItem = (RLPItem) values.get(i);
|
||||
storageValues.add(new DataWord(rlpItem.getRLPData()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
DataWord key = storageKeys.get(i);
|
||||
DataWord value = storageValues.get(i);
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
DataWord key = storageKeys.get(i);
|
||||
DataWord value = storageValues.get(i);
|
||||
storageTrie.update(key.getData(), RLP.encodeElement(value.getNoLeadZeroesData()));
|
||||
}
|
||||
}
|
||||
|
||||
this.code = (code.getRLPData() == null) ? ByteUtil.EMPTY_BYTE_ARRAY : code.getRLPData();
|
||||
this.rlpEncoded = rlpCode;
|
||||
}
|
||||
this.code = (code.getRLPData() == null) ? ByteUtil.EMPTY_BYTE_ARRAY : code.getRLPData();
|
||||
this.rlpEncoded = rlpCode;
|
||||
}
|
||||
|
||||
public void setDirty(boolean dirty) {
|
||||
this.dirty = dirty;
|
||||
@ -151,38 +151,38 @@ public class ContractDetails {
|
||||
}
|
||||
|
||||
|
||||
public byte[] getEncoded() {
|
||||
public byte[] getEncoded() {
|
||||
|
||||
if (rlpEncoded == null) {
|
||||
if (rlpEncoded == null) {
|
||||
|
||||
int size = storageKeys == null ? 0 : storageKeys.size();
|
||||
int size = storageKeys == null ? 0 : storageKeys.size();
|
||||
|
||||
byte[][] keys = new byte[size][];
|
||||
byte[][] values = new byte[size][];
|
||||
byte[][] keys = new byte[size][];
|
||||
byte[][] values = new byte[size][];
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
DataWord key = storageKeys.get(i);
|
||||
keys[i] = RLP.encodeElement(key.getData());
|
||||
}
|
||||
for (int i = 0; i < size; ++i) {
|
||||
DataWord value = storageValues.get(i);
|
||||
values[i] = RLP.encodeElement(value.getNoLeadZeroesData());
|
||||
}
|
||||
for (int i = 0; i < size; ++i) {
|
||||
DataWord key = storageKeys.get(i);
|
||||
keys[i] = RLP.encodeElement(key.getData());
|
||||
}
|
||||
for (int i = 0; i < size; ++i) {
|
||||
DataWord value = storageValues.get(i);
|
||||
values[i] = RLP.encodeElement(value.getNoLeadZeroesData());
|
||||
}
|
||||
|
||||
byte[] rlpKeysList = RLP.encodeList(keys);
|
||||
byte[] rlpValuesList = RLP.encodeList(values);
|
||||
byte[] rlpCode = RLP.encodeElement(code);
|
||||
byte[] rlpKeysList = RLP.encodeList(keys);
|
||||
byte[] rlpValuesList = RLP.encodeList(values);
|
||||
byte[] rlpCode = RLP.encodeElement(code);
|
||||
|
||||
this.rlpEncoded = RLP.encodeList(rlpKeysList, rlpValuesList, rlpCode);
|
||||
}
|
||||
return rlpEncoded;
|
||||
}
|
||||
this.rlpEncoded = RLP.encodeList(rlpKeysList, rlpValuesList, rlpCode);
|
||||
}
|
||||
return rlpEncoded;
|
||||
}
|
||||
|
||||
public Map<DataWord, DataWord> getStorage() {
|
||||
Map<DataWord, DataWord> storage = new HashMap<>();
|
||||
for (int i = 0; storageKeys != null && i < storageKeys.size(); ++i) {
|
||||
storage.put(storageKeys.get(i), storageValues.get(i));
|
||||
}
|
||||
for (int i = 0; storageKeys != null && i < storageKeys.size(); ++i) {
|
||||
storage.put(storageKeys.get(i), storageValues.get(i));
|
||||
}
|
||||
return Collections.unmodifiableMap(storage);
|
||||
}
|
||||
|
||||
|
@ -4,28 +4,28 @@ package org.ethereum.db;
|
||||
* Ethereum generic database interface
|
||||
*/
|
||||
public interface Database {
|
||||
|
||||
/**
|
||||
* Get value from database
|
||||
*
|
||||
* @param key for which to retrieve the value
|
||||
* @return the value for the given key
|
||||
*/
|
||||
public byte[] get(byte[] key);
|
||||
|
||||
/**
|
||||
* Insert value into database
|
||||
*
|
||||
* @param key for the given value
|
||||
* @param value to insert
|
||||
*/
|
||||
public void put(byte[] key, byte[] value);
|
||||
/**
|
||||
* Get value from database
|
||||
*
|
||||
* @param key for which to retrieve the value
|
||||
* @return the value for the given key
|
||||
*/
|
||||
public byte[] get(byte[] key);
|
||||
|
||||
/**
|
||||
* Delete key/value pair from database
|
||||
*
|
||||
* @param key for which to delete the value
|
||||
*/
|
||||
/**
|
||||
* Insert value into database
|
||||
*
|
||||
* @param key for the given value
|
||||
* @param value to insert
|
||||
*/
|
||||
public void put(byte[] key, byte[] value);
|
||||
|
||||
/**
|
||||
* Delete key/value pair from database
|
||||
*
|
||||
* @param key for which to delete the value
|
||||
*/
|
||||
public void delete(byte[] key);
|
||||
|
||||
/**
|
||||
|
@ -19,39 +19,39 @@ import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
/**
|
||||
* Generic interface for Ethereum database
|
||||
*
|
||||
* LevelDB key/value pair DB implementation will be used.
|
||||
*
|
||||
* LevelDB key/value pair DB implementation will be used.
|
||||
* Choice must be made between:
|
||||
* Pure Java: https://github.com/dain/leveldb
|
||||
* JNI binding: https://github.com/fusesource/leveldbjni
|
||||
* Pure Java: https://github.com/dain/leveldb
|
||||
* JNI binding: https://github.com/fusesource/leveldbjni
|
||||
*/
|
||||
public class DatabaseImpl implements Database {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("db");
|
||||
private DB db;
|
||||
private String name;
|
||||
|
||||
public DatabaseImpl(String name) {
|
||||
// Initialize Database
|
||||
private static final Logger logger = LoggerFactory.getLogger("db");
|
||||
private DB db;
|
||||
private String name;
|
||||
|
||||
public DatabaseImpl(String name) {
|
||||
// Initialize Database
|
||||
this.name = name;
|
||||
Options options = new Options();
|
||||
options.createIfMissing(true);
|
||||
options.compressionType(CompressionType.NONE);
|
||||
try {
|
||||
logger.debug("Opening database");
|
||||
Options options = new Options();
|
||||
options.createIfMissing(true);
|
||||
options.compressionType(CompressionType.NONE);
|
||||
try {
|
||||
logger.debug("Opening database");
|
||||
File dbLocation = new File(System.getProperty("user.dir") + "/" +
|
||||
SystemProperties.CONFIG.databaseDir() + "/");
|
||||
File fileLocation = new File(dbLocation, name);
|
||||
|
||||
if(SystemProperties.CONFIG.databaseReset()) {
|
||||
destroyDB(fileLocation);
|
||||
}
|
||||
if(SystemProperties.CONFIG.databaseReset()) {
|
||||
destroyDB(fileLocation);
|
||||
}
|
||||
|
||||
logger.debug("Initializing new or existing database: '{}'", name);
|
||||
db = factory.open(fileLocation, options);
|
||||
// logger.debug("Showing database stats");
|
||||
// String stats = DATABASE.getProperty("leveldb.stats");
|
||||
// logger.debug(stats);
|
||||
logger.debug("Initializing new or existing database: '{}'", name);
|
||||
db = factory.open(fileLocation, options);
|
||||
// logger.debug("Showing database stats");
|
||||
// String stats = DATABASE.getProperty("leveldb.stats");
|
||||
// logger.debug(stats);
|
||||
|
||||
if (logger.isTraceEnabled()){
|
||||
|
||||
@ -66,52 +66,52 @@ public class DatabaseImpl implements Database {
|
||||
iter.next();
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
logger.error(ioe.getMessage(), ioe);
|
||||
throw new RuntimeException("Can't initialize database");
|
||||
}
|
||||
}
|
||||
|
||||
public void destroyDB(File fileLocation) {
|
||||
logger.debug("Destroying existing database");
|
||||
Options options = new Options();
|
||||
try {
|
||||
factory.destroy(fileLocation, options);
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(byte[] key) {
|
||||
return db.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(byte[] key, byte[] value) {
|
||||
} catch (IOException ioe) {
|
||||
logger.error(ioe.getMessage(), ioe);
|
||||
throw new RuntimeException("Can't initialize database");
|
||||
}
|
||||
}
|
||||
|
||||
public void destroyDB(File fileLocation) {
|
||||
logger.debug("Destroying existing database");
|
||||
Options options = new Options();
|
||||
try {
|
||||
factory.destroy(fileLocation, options);
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] get(byte[] key) {
|
||||
return db.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(byte[] key, byte[] value) {
|
||||
|
||||
if(logger.isDebugEnabled())
|
||||
logger.debug("put: key: [{}], value: [{}]",
|
||||
Hex.toHexString(key),
|
||||
Hex.toHexString(value));
|
||||
db.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(byte[] key) {
|
||||
db.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(byte[] key) {
|
||||
if(logger.isDebugEnabled())
|
||||
logger.debug("delete: key: [{}]");
|
||||
|
||||
db.delete(key);
|
||||
}
|
||||
|
||||
public DBIterator iterator() {
|
||||
return db.iterator();
|
||||
}
|
||||
|
||||
public DB getDb() {
|
||||
return this.db;
|
||||
}
|
||||
db.delete(key);
|
||||
}
|
||||
|
||||
public DBIterator iterator() {
|
||||
return db.iterator();
|
||||
}
|
||||
|
||||
public DB getDb() {
|
||||
return this.db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
@ -123,15 +123,15 @@ public class DatabaseImpl implements Database {
|
||||
}
|
||||
}
|
||||
|
||||
public List<ByteArrayWrapper> dumpKeys() {
|
||||
DBIterator iterator = getDb().iterator();
|
||||
ArrayList<ByteArrayWrapper> keys = new ArrayList<>();
|
||||
public List<ByteArrayWrapper> dumpKeys() {
|
||||
DBIterator iterator = getDb().iterator();
|
||||
ArrayList<ByteArrayWrapper> keys = new ArrayList<>();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ByteArrayWrapper key = new ByteArrayWrapper(iterator.next().getKey());
|
||||
keys.add(key);
|
||||
}
|
||||
Collections.sort((List<ByteArrayWrapper>) keys);
|
||||
return keys;
|
||||
}
|
||||
while (iterator.hasNext()) {
|
||||
ByteArrayWrapper key = new ByteArrayWrapper(iterator.next().getKey());
|
||||
keys.add(key);
|
||||
}
|
||||
Collections.sort((List<ByteArrayWrapper>) keys);
|
||||
return keys;
|
||||
}
|
||||
}
|
@ -43,10 +43,10 @@ public class RepositoryImpl implements Repository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("repository");
|
||||
|
||||
private Trie worldState;
|
||||
private Trie worldState;
|
||||
|
||||
private DatabaseImpl detailsDB = null;
|
||||
private DatabaseImpl stateDB = null;
|
||||
private DatabaseImpl detailsDB = null;
|
||||
private DatabaseImpl stateDB = null;
|
||||
|
||||
public RepositoryImpl() {
|
||||
this(DETAILS_DB, STATE_DB);
|
||||
@ -54,8 +54,8 @@ public class RepositoryImpl implements Repository {
|
||||
|
||||
public RepositoryImpl(String detailsDbName, String stateDbName) {
|
||||
detailsDB = new DatabaseImpl(detailsDbName);
|
||||
stateDB = new DatabaseImpl(stateDbName);
|
||||
worldState = new TrieImpl(stateDB.getDb());
|
||||
stateDB = new DatabaseImpl(stateDbName);
|
||||
worldState = new TrieImpl(stateDB.getDb());
|
||||
}
|
||||
|
||||
|
||||
@ -63,8 +63,8 @@ public class RepositoryImpl implements Repository {
|
||||
public void reset() {
|
||||
close();
|
||||
detailsDB = new DatabaseImpl(DETAILS_DB);
|
||||
stateDB = new DatabaseImpl(STATE_DB);
|
||||
worldState = new TrieImpl(stateDB.getDb());
|
||||
stateDB = new DatabaseImpl(STATE_DB);
|
||||
worldState = new TrieImpl(stateDB.getDb());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,20 +49,20 @@ public class TrackDatabase implements Database {
|
||||
|
||||
public void put(byte[] key, byte[] value) {
|
||||
if (trackingChanges) {
|
||||
ByteArrayWrapper wKey = new ByteArrayWrapper(key);
|
||||
changes.put(wKey, value);
|
||||
ByteArrayWrapper wKey = new ByteArrayWrapper(key);
|
||||
changes.put(wKey, value);
|
||||
} else {
|
||||
db.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] get(byte[] key) {
|
||||
if(trackingChanges) {
|
||||
ByteArrayWrapper wKey = new ByteArrayWrapper(key);
|
||||
if(trackingChanges) {
|
||||
ByteArrayWrapper wKey = new ByteArrayWrapper(key);
|
||||
if (deletes.contains(wKey)) return null;
|
||||
if (changes.get(wKey) != null) return changes.get(wKey);
|
||||
}
|
||||
return db.get(key);
|
||||
return db.get(key);
|
||||
}
|
||||
|
||||
/** Delete object (key) from db **/
|
||||
|
@ -13,7 +13,7 @@ import org.ethereum.core.Genesis;
|
||||
|
||||
public interface Blockchain {
|
||||
|
||||
public static final byte[] GENESIS_HASH = Genesis.getInstance().getHash();
|
||||
public static final byte[] GENESIS_HASH = Genesis.getInstance().getHash();
|
||||
|
||||
public long getSize();
|
||||
public void add(Block block);
|
||||
@ -26,10 +26,10 @@ public interface Blockchain {
|
||||
public boolean hasParentOnTheChain(Block block);
|
||||
public void reset();
|
||||
public void close();
|
||||
public void updateTotalDifficulty(Block block);
|
||||
public void updateTotalDifficulty(Block block);
|
||||
public BigInteger getTotalDifficulty();
|
||||
public void setTotalDifficulty(BigInteger totalDifficulty);
|
||||
public byte[] getBestBlockHash();
|
||||
public byte[] getBestBlockHash();
|
||||
public List<byte[]> getListOfHashesStartFrom(byte[] hash, int qty);
|
||||
|
||||
TransactionReceipt getTransactionReceiptByHash(byte[] hash);
|
||||
|
@ -101,7 +101,7 @@ public class EthereumImpl implements Ethereum {
|
||||
final Set<PeerInfo> peers = worldManager.getPeerDiscovery().getPeers();
|
||||
synchronized (peers) {
|
||||
for (PeerInfo peer : peers) { // it blocks until a peer is available.
|
||||
if (peer.isOnline() && !excludePeers.contains(peer)) {
|
||||
if (peer.isOnline() && !excludePeers.contains(peer)) {
|
||||
logger.info("Found peer: {}", peer.toString());
|
||||
if (listener != null)
|
||||
listener.trace(String.format("Found online peer: [ %s ]", peer.toString()));
|
||||
@ -115,14 +115,14 @@ public class EthereumImpl implements Ethereum {
|
||||
@Override
|
||||
public PeerInfo waitForOnlinePeer() {
|
||||
PeerInfo peer = null;
|
||||
while (peer == null) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
peer = this.findOnlinePeer();
|
||||
}
|
||||
while (peer == null) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
peer = this.findOnlinePeer();
|
||||
}
|
||||
return peer;
|
||||
}
|
||||
|
||||
@ -148,11 +148,11 @@ public class EthereumImpl implements Ethereum {
|
||||
|
||||
@Override
|
||||
public void connect(String ip, int port) {
|
||||
logger.info("Connecting to: {}:{}", ip, port);
|
||||
logger.info("Connecting to: {}:{}", ip, port);
|
||||
|
||||
PeerClient peerClient = worldManager.getActivePeer();
|
||||
if (peerClient == null)
|
||||
peerClient = ctx.getBean(PeerClient.class);
|
||||
peerClient = ctx.getBean(PeerClient.class);
|
||||
worldManager.setActivePeer(peerClient);
|
||||
|
||||
peerClient.connect(ip, port);
|
||||
|
@ -19,13 +19,13 @@ import java.util.HashMap;
|
||||
|
||||
public interface Repository {
|
||||
|
||||
/**
|
||||
* Create a new account in the database
|
||||
*
|
||||
* @param addr of the contract
|
||||
* @return newly created account state
|
||||
*/
|
||||
public AccountState createAccount(byte[] addr);
|
||||
/**
|
||||
* Create a new account in the database
|
||||
*
|
||||
* @param addr of the contract
|
||||
* @return newly created account state
|
||||
*/
|
||||
public AccountState createAccount(byte[] addr);
|
||||
|
||||
|
||||
/**
|
||||
@ -34,13 +34,13 @@ public interface Repository {
|
||||
* false otherwise
|
||||
*/
|
||||
public boolean isExist(byte[] addr);
|
||||
|
||||
/**
|
||||
* Retrieve an account
|
||||
*
|
||||
* @param addr of the account
|
||||
* @return account state as stored in the database
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieve an account
|
||||
*
|
||||
* @param addr of the account
|
||||
* @return account state as stored in the database
|
||||
*/
|
||||
public AccountState getAccountState(byte[] addr);
|
||||
|
||||
/**
|
||||
@ -143,7 +143,7 @@ public interface Repository {
|
||||
* @param gasUsed the amount of gas used in the block until that point
|
||||
* @param txNumber is the number of the transaction for which the dump has to be made
|
||||
* @param txHash is the hash of the given transaction.
|
||||
* If null, the block state post coinbase reward is dumped.
|
||||
* If null, the block state post coinbase reward is dumped.
|
||||
*/
|
||||
public void dumpState(Block block, long gasUsed, int txNumber, byte[] txHash);
|
||||
|
||||
|
@ -19,47 +19,47 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
*/
|
||||
public class EtherObjectMapper extends ObjectMapper {
|
||||
|
||||
@Override
|
||||
public String writeValueAsString(Object value)
|
||||
throws JsonProcessingException {
|
||||
// alas, we have to pull the recycler directly here...
|
||||
SegmentedStringWriter sw = new SegmentedStringWriter(_jsonFactory._getBufferRecycler());
|
||||
try {
|
||||
JsonGenerator ge = _jsonFactory.createGenerator(sw);
|
||||
// set ethereum custom pretty printer
|
||||
EtherPrettyPrinter pp = new EtherPrettyPrinter();
|
||||
ge.setPrettyPrinter(pp);
|
||||
|
||||
_configAndWriteValue(ge, value);
|
||||
} catch (JsonProcessingException e) { // to support [JACKSON-758]
|
||||
throw e;
|
||||
} catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
|
||||
throw JsonMappingException.fromUnexpectedIOE(e);
|
||||
}
|
||||
return sw.getAndClear();
|
||||
}
|
||||
|
||||
/**
|
||||
* An extended {@link com.fasterxml.jackson.core.util.DefaultPrettyPrinter} class to customize
|
||||
* an ethereum {@link com.fasterxml.jackson.core.PrettyPrinter Pretty Printer} Generator
|
||||
*
|
||||
* @author Alon Muroch
|
||||
*
|
||||
*/
|
||||
public class EtherPrettyPrinter extends DefaultPrettyPrinter {
|
||||
@Override
|
||||
public String writeValueAsString(Object value)
|
||||
throws JsonProcessingException {
|
||||
// alas, we have to pull the recycler directly here...
|
||||
SegmentedStringWriter sw = new SegmentedStringWriter(_jsonFactory._getBufferRecycler());
|
||||
try {
|
||||
JsonGenerator ge = _jsonFactory.createGenerator(sw);
|
||||
// set ethereum custom pretty printer
|
||||
EtherPrettyPrinter pp = new EtherPrettyPrinter();
|
||||
ge.setPrettyPrinter(pp);
|
||||
|
||||
_configAndWriteValue(ge, value);
|
||||
} catch (JsonProcessingException e) { // to support [JACKSON-758]
|
||||
throw e;
|
||||
} catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
|
||||
throw JsonMappingException.fromUnexpectedIOE(e);
|
||||
}
|
||||
return sw.getAndClear();
|
||||
}
|
||||
|
||||
/**
|
||||
* An extended {@link com.fasterxml.jackson.core.util.DefaultPrettyPrinter} class to customize
|
||||
* an ethereum {@link com.fasterxml.jackson.core.PrettyPrinter Pretty Printer} Generator
|
||||
*
|
||||
* @author Alon Muroch
|
||||
*
|
||||
*/
|
||||
public class EtherPrettyPrinter extends DefaultPrettyPrinter {
|
||||
|
||||
public EtherPrettyPrinter() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeObjectFieldValueSeparator(JsonGenerator jg)
|
||||
throws IOException, JsonGenerationException {
|
||||
/**
|
||||
* Custom object separator (Default is " : ") to make it easier to compare state dumps with other
|
||||
* ethereum client implementations
|
||||
*/
|
||||
jg.writeRaw(": ");
|
||||
}
|
||||
}
|
||||
public EtherPrettyPrinter() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeObjectFieldValueSeparator(JsonGenerator jg)
|
||||
throws IOException, JsonGenerationException {
|
||||
/**
|
||||
* Custom object separator (Default is " : ") to make it easier to compare state dumps with other
|
||||
* ethereum client implementations
|
||||
*/
|
||||
jg.writeRaw(": ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,24 +17,24 @@ import java.util.*;
|
||||
|
||||
/**
|
||||
* JSON Helper class to format data into ObjectNodes
|
||||
* to match PyEthereum blockstate output
|
||||
* to match PyEthereum blockstate output
|
||||
*
|
||||
* Dump format:
|
||||
* {
|
||||
* "address":
|
||||
* {
|
||||
* "nonce": "n1",
|
||||
* "balance": "b1",
|
||||
* "stateRoot": "s1",
|
||||
* "codeHash": "c1",
|
||||
* "code": "c2",
|
||||
* "storage":
|
||||
* {
|
||||
* "key1": "value1",
|
||||
* "key2": "value2"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* "address":
|
||||
* {
|
||||
* "nonce": "n1",
|
||||
* "balance": "b1",
|
||||
* "stateRoot": "s1",
|
||||
* "codeHash": "c1",
|
||||
* "code": "c2",
|
||||
* "storage":
|
||||
* {
|
||||
* "key1": "value1",
|
||||
* "key2": "value2"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* www.ethereumJ.com
|
||||
*
|
||||
@ -43,17 +43,17 @@ import java.util.*;
|
||||
*/
|
||||
public class JSONHelper {
|
||||
|
||||
public static void dumpState(ObjectNode statesNode, String address, AccountState state, ContractDetails details) {
|
||||
public static void dumpState(ObjectNode statesNode, String address, AccountState state, ContractDetails details) {
|
||||
|
||||
List<DataWord> storageKeys = new ArrayList<>(details.getStorage().keySet());
|
||||
Collections.sort((List<DataWord>) storageKeys);
|
||||
Collections.sort((List<DataWord>) storageKeys);
|
||||
|
||||
ObjectNode account = statesNode.objectNode();
|
||||
ObjectNode storage = statesNode.objectNode();
|
||||
|
||||
for (DataWord key : storageKeys) {
|
||||
storage.put("0x" + Hex.toHexString(key.getData()),
|
||||
"0x" + Hex.toHexString(details.getStorage().get(key).getNoLeadZeroesData()));
|
||||
storage.put("0x" + Hex.toHexString(key.getData()),
|
||||
"0x" + Hex.toHexString(details.getStorage().get(key).getNoLeadZeroesData()));
|
||||
}
|
||||
account.put("balance", state.getBalance() == null ? "0" : state.getBalance().toString());
|
||||
// account.put("codeHash", details.getCodeHash() == null ? "0x" : "0x" + Hex.toHexString(details.getCodeHash()));
|
||||
@ -65,17 +65,17 @@ public class JSONHelper {
|
||||
statesNode.put(address, account);
|
||||
}
|
||||
|
||||
public static void dumpBlock(ObjectNode blockNode, Block block,
|
||||
long gasUsed, byte[] state, List<ByteArrayWrapper> keys,
|
||||
Repository repository) {
|
||||
|
||||
blockNode.put("coinbase", Hex.toHexString(block.getCoinbase()));
|
||||
blockNode.put("difficulty", new BigInteger(1, block.calcDifficulty()).toString());
|
||||
blockNode.put("extra_data", "0x");
|
||||
blockNode.put("gas_used", String.valueOf(gasUsed));
|
||||
blockNode.put("nonce", "0x" + Hex.toHexString(block.getNonce()));
|
||||
blockNode.put("number", String.valueOf(block.getNumber()));
|
||||
blockNode.put("prevhash", "0x" + Hex.toHexString(block.getParentHash()));
|
||||
public static void dumpBlock(ObjectNode blockNode, Block block,
|
||||
long gasUsed, byte[] state, List<ByteArrayWrapper> keys,
|
||||
Repository repository) {
|
||||
|
||||
blockNode.put("coinbase", Hex.toHexString(block.getCoinbase()));
|
||||
blockNode.put("difficulty", new BigInteger(1, block.calcDifficulty()).toString());
|
||||
blockNode.put("extra_data", "0x");
|
||||
blockNode.put("gas_used", String.valueOf(gasUsed));
|
||||
blockNode.put("nonce", "0x" + Hex.toHexString(block.getNonce()));
|
||||
blockNode.put("number", String.valueOf(block.getNumber()));
|
||||
blockNode.put("prevhash", "0x" + Hex.toHexString(block.getParentHash()));
|
||||
|
||||
ObjectNode statesNode = blockNode.objectNode();
|
||||
for (ByteArrayWrapper key : keys) {
|
||||
@ -95,8 +95,8 @@ public class JSONHelper {
|
||||
blockNode.put("tx_list_root", ByteUtil.toHexString(block.getTxTrieRoot()));
|
||||
blockNode.put("uncles_hash", "0x" + Hex.toHexString(block.getUnclesHash()));
|
||||
|
||||
// JSONHelper.dumpTransactions(blockNode,
|
||||
// stateRoot, codeHash, code, storage);
|
||||
// JSONHelper.dumpTransactions(blockNode,
|
||||
// stateRoot, codeHash, code, storage);
|
||||
}
|
||||
|
||||
}
|
@ -15,28 +15,28 @@ import org.ethereum.config.SystemProperties;
|
||||
public class JSONReader {
|
||||
|
||||
public static String loadJSON(String filename) {
|
||||
String json = "";
|
||||
if(!SystemProperties.CONFIG.vmTestLoadLocal())
|
||||
json = getFromUrl("https://raw.githubusercontent.com/ethereum/tests/develop/" + filename);
|
||||
return json == "" ? json = getFromLocal(filename) : json;
|
||||
String json = "";
|
||||
if(!SystemProperties.CONFIG.vmTestLoadLocal())
|
||||
json = getFromUrl("https://raw.githubusercontent.com/ethereum/tests/develop/" + filename);
|
||||
return json == "" ? json = getFromLocal(filename) : json;
|
||||
}
|
||||
|
||||
public static String getFromLocal(String filename) {
|
||||
System.out.println("Loading local file: " + filename);
|
||||
try {
|
||||
if(System.getProperty("ETHEREUM_TEST_PATH") == null) {
|
||||
System.out.println("ETHEREUM_TEST_PATH is not passed as a VM argument, please make sure you pass it with the correct path");
|
||||
return "";
|
||||
}
|
||||
System.out.println("From: " + System.getProperty("ETHEREUM_TEST_PATH"));
|
||||
File vmTestFile = new File(System.getProperty("ETHEREUM_TEST_PATH") + filename);
|
||||
return new String(Files.readAllBytes(vmTestFile.toPath()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("Loading local file: " + filename);
|
||||
try {
|
||||
if(System.getProperty("ETHEREUM_TEST_PATH") == null) {
|
||||
System.out.println("ETHEREUM_TEST_PATH is not passed as a VM argument, please make sure you pass it with the correct path");
|
||||
return "";
|
||||
}
|
||||
System.out.println("From: " + System.getProperty("ETHEREUM_TEST_PATH"));
|
||||
File vmTestFile = new File(System.getProperty("ETHEREUM_TEST_PATH") + filename);
|
||||
return new String(Files.readAllBytes(vmTestFile.toPath()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
public static String getFromUrl(String urlToRead) {
|
||||
URL url;
|
||||
HttpURLConnection conn;
|
||||
|
@ -14,9 +14,9 @@ import org.json.simple.JSONObject;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
public class Logs {
|
||||
List<LogInfo> logs = new ArrayList<>();
|
||||
|
||||
public Logs(JSONArray jLogs) {
|
||||
List<LogInfo> logs = new ArrayList<>();
|
||||
|
||||
public Logs(JSONArray jLogs) {
|
||||
|
||||
for (int i = 0; i < jLogs.size(); ++i){
|
||||
|
||||
@ -35,7 +35,7 @@ public class Logs {
|
||||
LogInfo li = new LogInfo(address, topics, data);
|
||||
logs.add(li);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Iterator<LogInfo> getIterator(){
|
||||
|
@ -60,24 +60,24 @@ public class TestCase {
|
||||
JSONObject preJSON = (JSONObject)testCaseJSONObj.get("pre");
|
||||
JSONObject postJSON = new JSONObject();
|
||||
if(testCaseJSONObj.containsKey("post")) // in cases where there is no post dictionary (when testing for exceptions for example)
|
||||
postJSON = (JSONObject)testCaseJSONObj.get("post");
|
||||
postJSON = (JSONObject)testCaseJSONObj.get("post");
|
||||
JSONArray callCreates = new JSONArray();
|
||||
if(testCaseJSONObj.containsKey("callcreates"))
|
||||
callCreates = (JSONArray)testCaseJSONObj.get("callcreates");
|
||||
callCreates = (JSONArray)testCaseJSONObj.get("callcreates");
|
||||
|
||||
JSONArray logsJSON = new JSONArray();
|
||||
if(testCaseJSONObj.containsKey("logs"))
|
||||
logsJSON = (JSONArray)testCaseJSONObj.get("logs");
|
||||
logsJSON = (JSONArray)testCaseJSONObj.get("logs");
|
||||
logs = new Logs(logsJSON);
|
||||
|
||||
String gasString = "0";
|
||||
if(testCaseJSONObj.containsKey("gas"))
|
||||
gasString = testCaseJSONObj.get("gas").toString();
|
||||
gasString = testCaseJSONObj.get("gas").toString();
|
||||
this.gas = ByteUtil.bigIntegerToBytes(new BigInteger(gasString));
|
||||
|
||||
String outString = null;
|
||||
if(testCaseJSONObj.containsKey("out"))
|
||||
outString = testCaseJSONObj.get("out").toString();
|
||||
outString = testCaseJSONObj.get("out").toString();
|
||||
if (outString != null && outString.length() > 2)
|
||||
this.out = Hex.decode(outString.substring(2));
|
||||
else
|
||||
@ -124,7 +124,7 @@ public class TestCase {
|
||||
}
|
||||
|
||||
public Logs getLogs() {
|
||||
return logs;
|
||||
return logs;
|
||||
}
|
||||
|
||||
public byte[] getGas() {
|
||||
|
@ -33,7 +33,7 @@ public class TestRunner {
|
||||
private ProgramTrace trace = null;
|
||||
|
||||
public List<String> runTestSuite(TestSuite testSuite) {
|
||||
|
||||
|
||||
Iterator<TestCase> testIterator = testSuite.iterator();
|
||||
List<String> resultCollector = new ArrayList<>();
|
||||
|
||||
@ -137,174 +137,174 @@ public class TestRunner {
|
||||
logger.info("--------- PRE ---------");
|
||||
RepositoryDummy repository = loadRepository(testCase.getPre());
|
||||
|
||||
try {
|
||||
try {
|
||||
|
||||
|
||||
/* 2. Create ProgramInvoke - Env/Exec */
|
||||
Env env = testCase.getEnv();
|
||||
Exec exec = testCase.getExec();
|
||||
Logs logs = testCase.getLogs();
|
||||
/* 2. Create ProgramInvoke - Env/Exec */
|
||||
Env env = testCase.getEnv();
|
||||
Exec exec = testCase.getExec();
|
||||
Logs logs = testCase.getLogs();
|
||||
|
||||
byte[] address = exec.getAddress();
|
||||
byte[] origin = exec.getOrigin();
|
||||
byte[] caller = exec.getCaller();
|
||||
byte[] balance = ByteUtil.bigIntegerToBytes(repository.getBalance(exec.getAddress()));
|
||||
byte[] gasPrice = exec.getGasPrice();
|
||||
byte[] gas = exec.getGas();
|
||||
byte[] callValue = exec.getValue();
|
||||
byte[] msgData = exec.getData();
|
||||
byte[] lastHash = env.getPreviousHash();
|
||||
byte[] coinbase = env.getCurrentCoinbase();
|
||||
long timestamp = new BigInteger(env.getCurrentTimestamp()).longValue();
|
||||
long number = new BigInteger(env.getCurrentNumber()).longValue();
|
||||
byte[] difficulty = env.getCurrentDifficlty();
|
||||
long gaslimit = new BigInteger(env.getCurrentGasLimit()).longValue();
|
||||
byte[] address = exec.getAddress();
|
||||
byte[] origin = exec.getOrigin();
|
||||
byte[] caller = exec.getCaller();
|
||||
byte[] balance = ByteUtil.bigIntegerToBytes(repository.getBalance(exec.getAddress()));
|
||||
byte[] gasPrice = exec.getGasPrice();
|
||||
byte[] gas = exec.getGas();
|
||||
byte[] callValue = exec.getValue();
|
||||
byte[] msgData = exec.getData();
|
||||
byte[] lastHash = env.getPreviousHash();
|
||||
byte[] coinbase = env.getCurrentCoinbase();
|
||||
long timestamp = new BigInteger(env.getCurrentTimestamp()).longValue();
|
||||
long number = new BigInteger(env.getCurrentNumber()).longValue();
|
||||
byte[] difficulty = env.getCurrentDifficlty();
|
||||
long gaslimit = new BigInteger(env.getCurrentGasLimit()).longValue();
|
||||
|
||||
// Origin and caller need to exist in order to be able to execute
|
||||
if(repository.getAccountState(origin) == null)
|
||||
repository.createAccount(origin);
|
||||
if(repository.getAccountState(caller) == null)
|
||||
repository.createAccount(caller);
|
||||
// Origin and caller need to exist in order to be able to execute
|
||||
if(repository.getAccountState(origin) == null)
|
||||
repository.createAccount(origin);
|
||||
if(repository.getAccountState(caller) == null)
|
||||
repository.createAccount(caller);
|
||||
|
||||
ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance,
|
||||
gasPrice, gas, callValue, msgData, lastHash, coinbase,
|
||||
timestamp, number, difficulty, gaslimit, repository, true);
|
||||
ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance,
|
||||
gasPrice, gas, callValue, msgData, lastHash, coinbase,
|
||||
timestamp, number, difficulty, gaslimit, repository, true);
|
||||
|
||||
/* 3. Create Program - exec.code */
|
||||
/* 4. run VM */
|
||||
VM vm = new VM();
|
||||
Program program = new Program(exec.getCode(), programInvoke);
|
||||
boolean vmDidThrowAnEception = false;
|
||||
RuntimeException e = null;
|
||||
try {
|
||||
while(!program.isStopped())
|
||||
vm.step(program);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
vmDidThrowAnEception = true;
|
||||
e = ex;
|
||||
}
|
||||
/* 3. Create Program - exec.code */
|
||||
/* 4. run VM */
|
||||
VM vm = new VM();
|
||||
Program program = new Program(exec.getCode(), programInvoke);
|
||||
boolean vmDidThrowAnEception = false;
|
||||
RuntimeException e = null;
|
||||
try {
|
||||
while(!program.isStopped())
|
||||
vm.step(program);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
vmDidThrowAnEception = true;
|
||||
e = ex;
|
||||
}
|
||||
program.saveProgramTraceToFile(testCase.getName());
|
||||
|
||||
if(testCase.getPost().size() == 0) {
|
||||
if(vmDidThrowAnEception != true) {
|
||||
String output =
|
||||
String.format("VM was expected to throw an exception");
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
else
|
||||
logger.info("VM did throw an exception: " + e.toString());
|
||||
if(vmDidThrowAnEception != true) {
|
||||
String output =
|
||||
String.format("VM was expected to throw an exception");
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
else
|
||||
logger.info("VM did throw an exception: " + e.toString());
|
||||
}
|
||||
else {
|
||||
if(vmDidThrowAnEception) {
|
||||
String output =
|
||||
String.format("VM threw an unexpected exception: " + e.toString());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
return results;
|
||||
}
|
||||
if(vmDidThrowAnEception) {
|
||||
String output =
|
||||
String.format("VM threw an unexpected exception: " + e.toString());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
return results;
|
||||
}
|
||||
|
||||
this.trace = program.getProgramTrace();
|
||||
this.trace = program.getProgramTrace();
|
||||
|
||||
System.out.println("--------- POST --------");
|
||||
/* 5. Assert Post values */
|
||||
for (ByteArrayWrapper key : testCase.getPost().keySet()) {
|
||||
System.out.println("--------- POST --------");
|
||||
/* 5. Assert Post values */
|
||||
for (ByteArrayWrapper key : testCase.getPost().keySet()) {
|
||||
|
||||
AccountState accountState = testCase.getPost().get(key);
|
||||
AccountState accountState = testCase.getPost().get(key);
|
||||
|
||||
long expectedNonce = accountState.getNonceLong();
|
||||
BigInteger expectedBalance = accountState.getBigIntegerBalance();
|
||||
byte[] expectedCode = accountState.getCode();
|
||||
long expectedNonce = accountState.getNonceLong();
|
||||
BigInteger expectedBalance = accountState.getBigIntegerBalance();
|
||||
byte[] expectedCode = accountState.getCode();
|
||||
|
||||
boolean accountExist = (null != repository.getAccountState(key.getData()));
|
||||
if (!accountExist) {
|
||||
boolean accountExist = (null != repository.getAccountState(key.getData()));
|
||||
if (!accountExist) {
|
||||
|
||||
String output =
|
||||
String.format("The expected account does not exist. key: [ %s ]",
|
||||
Hex.toHexString(key.getData()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
continue;
|
||||
}
|
||||
String output =
|
||||
String.format("The expected account does not exist. key: [ %s ]",
|
||||
Hex.toHexString(key.getData()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
continue;
|
||||
}
|
||||
|
||||
long actualNonce = repository.getNonce(key.getData()).longValue();
|
||||
BigInteger actualBalance = repository.getBalance(key.getData());
|
||||
byte[] actualCode = repository.getCode(key.getData());
|
||||
if (actualCode == null) actualCode = "".getBytes();
|
||||
long actualNonce = repository.getNonce(key.getData()).longValue();
|
||||
BigInteger actualBalance = repository.getBalance(key.getData());
|
||||
byte[] actualCode = repository.getCode(key.getData());
|
||||
if (actualCode == null) actualCode = "".getBytes();
|
||||
|
||||
if (expectedNonce != actualNonce) {
|
||||
if (expectedNonce != actualNonce) {
|
||||
|
||||
String output =
|
||||
String.format("The nonce result is different. key: [ %s ], expectedNonce: [ %d ] is actualNonce: [ %d ] ",
|
||||
Hex.toHexString(key.getData()), expectedNonce, actualNonce);
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
String output =
|
||||
String.format("The nonce result is different. key: [ %s ], expectedNonce: [ %d ] is actualNonce: [ %d ] ",
|
||||
Hex.toHexString(key.getData()), expectedNonce, actualNonce);
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
if (!expectedBalance.equals(actualBalance)) {
|
||||
if (!expectedBalance.equals(actualBalance)) {
|
||||
|
||||
String output =
|
||||
String.format("The balance result is different. key: [ %s ], expectedBalance: [ %s ] is actualBalance: [ %s ] ",
|
||||
Hex.toHexString(key.getData()), expectedBalance.toString(), actualBalance.toString());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
String output =
|
||||
String.format("The balance result is different. key: [ %s ], expectedBalance: [ %s ] is actualBalance: [ %s ] ",
|
||||
Hex.toHexString(key.getData()), expectedBalance.toString(), actualBalance.toString());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
if (!Arrays.equals(expectedCode, actualCode)) {
|
||||
if (!Arrays.equals(expectedCode, actualCode)) {
|
||||
|
||||
String output =
|
||||
String.format("The code result is different. account: [ %s ], expectedCode: [ %s ] is actualCode: [ %s ] ",
|
||||
Hex.toHexString(key.getData()),
|
||||
Hex.toHexString(expectedCode),
|
||||
Hex.toHexString(actualCode));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
String output =
|
||||
String.format("The code result is different. account: [ %s ], expectedCode: [ %s ] is actualCode: [ %s ] ",
|
||||
Hex.toHexString(key.getData()),
|
||||
Hex.toHexString(expectedCode),
|
||||
Hex.toHexString(actualCode));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
// assert storage
|
||||
Map<DataWord, DataWord> storage = accountState.getStorage();
|
||||
for (DataWord storageKey : storage.keySet()) {
|
||||
// assert storage
|
||||
Map<DataWord, DataWord> storage = accountState.getStorage();
|
||||
for (DataWord storageKey : storage.keySet()) {
|
||||
|
||||
byte[] expectedStValue = storage.get(storageKey).getData();
|
||||
byte[] expectedStValue = storage.get(storageKey).getData();
|
||||
|
||||
ContractDetails contractDetails =
|
||||
program.getResult().getRepository().getContractDetails(accountState.getAddress());
|
||||
ContractDetails contractDetails =
|
||||
program.getResult().getRepository().getContractDetails(accountState.getAddress());
|
||||
|
||||
if (contractDetails == null) {
|
||||
if (contractDetails == null) {
|
||||
|
||||
String output =
|
||||
String.format("Storage raw doesn't exist: key [ %s ], expectedValue: [ %s ]",
|
||||
Hex.toHexString(storageKey.getData()),
|
||||
Hex.toHexString(expectedStValue)
|
||||
);
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
continue;
|
||||
}
|
||||
String output =
|
||||
String.format("Storage raw doesn't exist: key [ %s ], expectedValue: [ %s ]",
|
||||
Hex.toHexString(storageKey.getData()),
|
||||
Hex.toHexString(expectedStValue)
|
||||
);
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<DataWord, DataWord> testStorage = contractDetails.getStorage();
|
||||
DataWord actualValue = testStorage.get(new DataWord(storageKey.getData()));
|
||||
Map<DataWord, DataWord> testStorage = contractDetails.getStorage();
|
||||
DataWord actualValue = testStorage.get(new DataWord(storageKey.getData()));
|
||||
|
||||
if (actualValue == null ||
|
||||
if (actualValue == null ||
|
||||
!Arrays.equals(expectedStValue, actualValue.getNoLeadZeroesData())) {
|
||||
|
||||
String output =
|
||||
String.format("Storage value different: key [ %s ], expectedValue: [ %s ], actualValue: [ %s ]",
|
||||
Hex.toHexString(storageKey.getData()),
|
||||
Hex.toHexString(expectedStValue),
|
||||
actualValue == null ? "" : Hex.toHexString(actualValue.getNoLeadZeroesData()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
}
|
||||
String output =
|
||||
String.format("Storage value different: key [ %s ], expectedValue: [ %s ], actualValue: [ %s ]",
|
||||
Hex.toHexString(storageKey.getData()),
|
||||
Hex.toHexString(expectedStValue),
|
||||
actualValue == null ? "" : Hex.toHexString(actualValue.getNoLeadZeroesData()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
}
|
||||
|
||||
/* asset logs */
|
||||
List<LogInfo> logResult = program.getResult().getLogInfoList();
|
||||
/* asset logs */
|
||||
List<LogInfo> logResult = program.getResult().getLogInfoList();
|
||||
|
||||
Iterator<LogInfo> postLogs = logs.getIterator();
|
||||
Iterator<LogInfo> postLogs = logs.getIterator();
|
||||
int i = 0;
|
||||
while(postLogs.hasNext()) {
|
||||
while(postLogs.hasNext()) {
|
||||
|
||||
LogInfo expectedLogInfo = postLogs.next();
|
||||
|
||||
@ -313,25 +313,25 @@ public class TestRunner {
|
||||
foundLogInfo = logResult.get(i);
|
||||
|
||||
if(foundLogInfo == null) {
|
||||
String output =
|
||||
String.format("Expected log [ %s ]", expectedLogInfo.toString());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
else {
|
||||
if(!Arrays.equals(expectedLogInfo.getAddress(), foundLogInfo.getAddress())) {
|
||||
String output =
|
||||
String.format("Expected address [ %s ], found [ %s ]", Hex.toHexString(expectedLogInfo.getAddress()), Hex.toHexString(foundLogInfo.getAddress()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
String output =
|
||||
String.format("Expected log [ %s ]", expectedLogInfo.toString());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
else {
|
||||
if(!Arrays.equals(expectedLogInfo.getAddress(), foundLogInfo.getAddress())) {
|
||||
String output =
|
||||
String.format("Expected address [ %s ], found [ %s ]", Hex.toHexString(expectedLogInfo.getAddress()), Hex.toHexString(foundLogInfo.getAddress()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
if(!Arrays.equals(expectedLogInfo.getData(), foundLogInfo.getData())) {
|
||||
String output =
|
||||
String.format("Expected data [ %s ], found [ %s ]", Hex.toHexString(expectedLogInfo.getData()), Hex.toHexString(foundLogInfo.getData()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
if(!Arrays.equals(expectedLogInfo.getData(), foundLogInfo.getData())) {
|
||||
String output =
|
||||
String.format("Expected data [ %s ], found [ %s ]", Hex.toHexString(expectedLogInfo.getData()), Hex.toHexString(foundLogInfo.getData()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
if(!expectedLogInfo.getBloom().equals(foundLogInfo.getBloom())) {
|
||||
String output =
|
||||
@ -342,154 +342,154 @@ public class TestRunner {
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
if(expectedLogInfo.getTopics().size() != foundLogInfo.getTopics().size()) {
|
||||
String output =
|
||||
String.format("Expected number of topics [ %d ], found [ %d ]", expectedLogInfo.getTopics().size(), foundLogInfo.getTopics().size());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
else {
|
||||
int j=0;
|
||||
for(DataWord topic: expectedLogInfo.getTopics()) {
|
||||
byte[] foundTopic = foundLogInfo.getTopics().get(j).getData();
|
||||
if(expectedLogInfo.getTopics().size() != foundLogInfo.getTopics().size()) {
|
||||
String output =
|
||||
String.format("Expected number of topics [ %d ], found [ %d ]", expectedLogInfo.getTopics().size(), foundLogInfo.getTopics().size());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
else {
|
||||
int j=0;
|
||||
for(DataWord topic: expectedLogInfo.getTopics()) {
|
||||
byte[] foundTopic = foundLogInfo.getTopics().get(j).getData();
|
||||
|
||||
if(!Arrays.equals(topic.getData(), foundTopic)) {
|
||||
String output =
|
||||
String.format("Expected topic [ %s ], found [ %s ]", Hex.toHexString(topic.getData()), Hex.toHexString(foundTopic));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
if(!Arrays.equals(topic.getData(), foundTopic)) {
|
||||
String output =
|
||||
String.format("Expected topic [ %s ], found [ %s ]", Hex.toHexString(topic.getData()), Hex.toHexString(foundTopic));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: assert that you have no extra accounts in the repository
|
||||
// TODO: -> basically the deleted by suicide should be deleted
|
||||
// TODO: -> and no unexpected created
|
||||
// TODO: assert that you have no extra accounts in the repository
|
||||
// TODO: -> basically the deleted by suicide should be deleted
|
||||
// TODO: -> and no unexpected created
|
||||
|
||||
List<org.ethereum.vm.CallCreate> resultCallCreates =
|
||||
program.getResult().getCallCreateList();
|
||||
List<org.ethereum.vm.CallCreate> resultCallCreates =
|
||||
program.getResult().getCallCreateList();
|
||||
|
||||
// assert call creates
|
||||
for (int i = 0; i < testCase.getCallCreateList().size(); ++i) {
|
||||
// assert call creates
|
||||
for (int i = 0; i < testCase.getCallCreateList().size(); ++i) {
|
||||
|
||||
org.ethereum.vm.CallCreate resultCallCreate = null;
|
||||
if (resultCallCreates != null && resultCallCreates.size() > i) {
|
||||
resultCallCreate = resultCallCreates.get(i);
|
||||
}
|
||||
org.ethereum.vm.CallCreate resultCallCreate = null;
|
||||
if (resultCallCreates != null && resultCallCreates.size() > i) {
|
||||
resultCallCreate = resultCallCreates.get(i);
|
||||
}
|
||||
|
||||
CallCreate expectedCallCreate = testCase.getCallCreateList().get(i);
|
||||
CallCreate expectedCallCreate = testCase.getCallCreateList().get(i);
|
||||
|
||||
if (resultCallCreate == null && expectedCallCreate != null) {
|
||||
if (resultCallCreate == null && expectedCallCreate != null) {
|
||||
|
||||
String output =
|
||||
String.format("Missing call/create invoke: to: [ %s ], data: [ %s ], gas: [ %s ], value: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getDestination()),
|
||||
Hex.toHexString(expectedCallCreate.getData()),
|
||||
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
||||
Hex.toHexString(expectedCallCreate.getValue()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
String output =
|
||||
String.format("Missing call/create invoke: to: [ %s ], data: [ %s ], gas: [ %s ], value: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getDestination()),
|
||||
Hex.toHexString(expectedCallCreate.getData()),
|
||||
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
||||
Hex.toHexString(expectedCallCreate.getValue()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean assertDestination = Arrays.equals(
|
||||
expectedCallCreate.getDestination(),
|
||||
resultCallCreate.getDestination());
|
||||
if (!assertDestination) {
|
||||
boolean assertDestination = Arrays.equals(
|
||||
expectedCallCreate.getDestination(),
|
||||
resultCallCreate.getDestination());
|
||||
if (!assertDestination) {
|
||||
|
||||
String output =
|
||||
String.format("Call/Create destination is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getDestination()),
|
||||
Hex.toHexString(resultCallCreate.getDestination()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
String output =
|
||||
String.format("Call/Create destination is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getDestination()),
|
||||
Hex.toHexString(resultCallCreate.getDestination()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
boolean assertData = Arrays.equals(
|
||||
expectedCallCreate.getData(),
|
||||
resultCallCreate.getData());
|
||||
if (!assertData) {
|
||||
boolean assertData = Arrays.equals(
|
||||
expectedCallCreate.getData(),
|
||||
resultCallCreate.getData());
|
||||
if (!assertData) {
|
||||
|
||||
String output =
|
||||
String.format("Call/Create data is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getData()),
|
||||
Hex.toHexString(resultCallCreate.getData()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
String output =
|
||||
String.format("Call/Create data is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getData()),
|
||||
Hex.toHexString(resultCallCreate.getData()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
boolean assertGasLimit = Arrays.equals(
|
||||
expectedCallCreate.getGasLimit(),
|
||||
resultCallCreate.getGasLimit());
|
||||
if (!assertGasLimit) {
|
||||
String output =
|
||||
String.format("Call/Create gasLimit is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
||||
Hex.toHexString(resultCallCreate.getGasLimit()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
boolean assertGasLimit = Arrays.equals(
|
||||
expectedCallCreate.getGasLimit(),
|
||||
resultCallCreate.getGasLimit());
|
||||
if (!assertGasLimit) {
|
||||
String output =
|
||||
String.format("Call/Create gasLimit is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
||||
Hex.toHexString(resultCallCreate.getGasLimit()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
boolean assertValue = Arrays.equals(
|
||||
expectedCallCreate.getValue(),
|
||||
resultCallCreate.getValue());
|
||||
if (!assertValue) {
|
||||
String output =
|
||||
String.format("Call/Create value is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getValue()),
|
||||
Hex.toHexString(resultCallCreate.getValue()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
}
|
||||
boolean assertValue = Arrays.equals(
|
||||
expectedCallCreate.getValue(),
|
||||
resultCallCreate.getValue());
|
||||
if (!assertValue) {
|
||||
String output =
|
||||
String.format("Call/Create value is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getValue()),
|
||||
Hex.toHexString(resultCallCreate.getValue()));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
}
|
||||
|
||||
// assert out
|
||||
byte[] expectedHReturn = testCase.getOut();
|
||||
byte[] actualHReturn = EMPTY_BYTE_ARRAY;
|
||||
if (program.getResult().getHReturn() != null) {
|
||||
actualHReturn = program.getResult().getHReturn().array();
|
||||
}
|
||||
// assert out
|
||||
byte[] expectedHReturn = testCase.getOut();
|
||||
byte[] actualHReturn = EMPTY_BYTE_ARRAY;
|
||||
if (program.getResult().getHReturn() != null) {
|
||||
actualHReturn = program.getResult().getHReturn().array();
|
||||
}
|
||||
|
||||
if (!Arrays.equals(expectedHReturn, actualHReturn)) {
|
||||
if (!Arrays.equals(expectedHReturn, actualHReturn)) {
|
||||
|
||||
String output =
|
||||
String.format("HReturn is different. Expected hReturn: [ %s ], actual hReturn: [ %s ]",
|
||||
Hex.toHexString(expectedHReturn),
|
||||
Hex.toHexString(actualHReturn));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
String output =
|
||||
String.format("HReturn is different. Expected hReturn: [ %s ], actual hReturn: [ %s ]",
|
||||
Hex.toHexString(expectedHReturn),
|
||||
Hex.toHexString(actualHReturn));
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
|
||||
// assert gas
|
||||
BigInteger expectedGas = new BigInteger(testCase.getGas());
|
||||
BigInteger actualGas = new BigInteger(gas).subtract(BigInteger.valueOf(program.getResult().getGasUsed()));
|
||||
// assert gas
|
||||
BigInteger expectedGas = new BigInteger(testCase.getGas());
|
||||
BigInteger actualGas = new BigInteger(gas).subtract(BigInteger.valueOf(program.getResult().getGasUsed()));
|
||||
|
||||
if (!expectedGas.equals(actualGas)) {
|
||||
if (!expectedGas.equals(actualGas)) {
|
||||
|
||||
String output =
|
||||
String.format("Gas remaining is different. Expected gas remaining: [ %s ], actual gas remaining: [ %s ]",
|
||||
expectedGas.toString() ,
|
||||
actualGas.toString());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
/*
|
||||
* end of if(testCase.getPost().size() == 0)
|
||||
*/
|
||||
String output =
|
||||
String.format("Gas remaining is different. Expected gas remaining: [ %s ], actual gas remaining: [ %s ]",
|
||||
expectedGas.toString() ,
|
||||
actualGas.toString());
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
}
|
||||
/*
|
||||
* end of if(testCase.getPost().size() == 0)
|
||||
*/
|
||||
}
|
||||
|
||||
return results;
|
||||
} finally {
|
||||
// repository.close();
|
||||
}
|
||||
return results;
|
||||
} finally {
|
||||
// repository.close();
|
||||
}
|
||||
}
|
||||
|
||||
public org.ethereum.core.Transaction createTransaction(Transaction tx){
|
||||
@ -513,7 +513,7 @@ public class TestRunner {
|
||||
|
||||
RepositoryDummy track = new RepositoryDummy();
|
||||
|
||||
/* 1. Store pre-exist accounts - Pre */
|
||||
/* 1. Store pre-exist accounts - Pre */
|
||||
for (ByteArrayWrapper key : pre.keySet()) {
|
||||
|
||||
AccountState accountState = pre.get(key);
|
||||
|
@ -35,13 +35,13 @@ public class WorldManager {
|
||||
private static final Logger logger = LoggerFactory.getLogger("general");
|
||||
|
||||
@Autowired
|
||||
private Blockchain blockchain;
|
||||
private Blockchain blockchain;
|
||||
|
||||
@Autowired
|
||||
private Repository repository;
|
||||
private Repository repository;
|
||||
|
||||
@Autowired
|
||||
private Wallet wallet;
|
||||
private Wallet wallet;
|
||||
|
||||
@Autowired
|
||||
private PeerClient activePeer;
|
||||
@ -72,7 +72,7 @@ public class WorldManager {
|
||||
byte[] cbAddr = HashUtil.sha3(secret.getBytes());
|
||||
wallet.importKey(cbAddr);
|
||||
}
|
||||
|
||||
|
||||
public void addListener(EthereumListener listener) {
|
||||
logger.info("Ethereum listener added");
|
||||
((EthereumListenerWrapper)this.listener).addListener(listener);
|
||||
@ -109,7 +109,7 @@ public class WorldManager {
|
||||
}
|
||||
|
||||
public PeerDiscovery getPeerDiscovery() {
|
||||
return peerDiscovery;
|
||||
return peerDiscovery;
|
||||
}
|
||||
|
||||
public EthereumListener getListener() {
|
||||
@ -117,20 +117,20 @@ public class WorldManager {
|
||||
}
|
||||
|
||||
public void setWallet(Wallet wallet) {
|
||||
this.wallet = wallet;
|
||||
this.wallet = wallet;
|
||||
}
|
||||
|
||||
public Repository getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
public Blockchain getBlockchain() {
|
||||
return blockchain;
|
||||
}
|
||||
|
||||
public Wallet getWallet() {
|
||||
return wallet;
|
||||
}
|
||||
public Repository getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
public Blockchain getBlockchain() {
|
||||
return blockchain;
|
||||
}
|
||||
|
||||
public Wallet getWallet() {
|
||||
return wallet;
|
||||
}
|
||||
|
||||
public void setActivePeer(PeerClient peer) {
|
||||
this.activePeer = peer;
|
||||
@ -141,10 +141,10 @@ public class WorldManager {
|
||||
}
|
||||
|
||||
public Set<Transaction> getPendingTransactions() {
|
||||
return pendingTransactions;
|
||||
return pendingTransactions;
|
||||
}
|
||||
|
||||
public boolean isBlockchainLoading(){
|
||||
public boolean isBlockchainLoading(){
|
||||
return blockchain.getQueue().size() > 2;
|
||||
}
|
||||
|
||||
|
@ -34,38 +34,38 @@ public class Miner {
|
||||
private boolean stop = false;
|
||||
|
||||
|
||||
/**
|
||||
* Adds a nonce to given block which complies with the given difficulty
|
||||
*
|
||||
* For the PoC series, we use a simplified proof-of-work.
|
||||
* This is not ASIC resistant and is meant merely as a placeholder.
|
||||
* It utilizes the bare SHA3 hash function to secure the block chain by requiring
|
||||
* the SHA3 hash of the concatenation of the nonce and the header’s SHA3 hash to be
|
||||
* sufficiently low. It is formally defined as PoW:
|
||||
*
|
||||
* PoW(H, n) ≡ BE(SHA3(SHA3(RLP(H!n)) ◦ n))
|
||||
*
|
||||
* where:
|
||||
* RLP(H!n) is the RLP encoding of the block header H, not including the
|
||||
* final nonce component;
|
||||
* SHA3 is the SHA3 hash function accepting an arbitrary length series of
|
||||
* bytes and evaluating to a series of 32 bytes (i.e. 256-bit);
|
||||
* n is the nonce, a series of 32 bytes;
|
||||
* o is the series concatenation operator;
|
||||
* BE(X) evaluates to the value equal to X when interpreted as a
|
||||
* big-endian-encoded integer.
|
||||
*
|
||||
* @param newBlock without a valid nonce
|
||||
* @param difficulty - the mining difficulty
|
||||
* @return true if valid nonce has been added to the block
|
||||
*/
|
||||
public boolean mine(Block newBlock, byte[] difficulty) {
|
||||
/**
|
||||
* Adds a nonce to given block which complies with the given difficulty
|
||||
*
|
||||
* For the PoC series, we use a simplified proof-of-work.
|
||||
* This is not ASIC resistant and is meant merely as a placeholder.
|
||||
* It utilizes the bare SHA3 hash function to secure the block chain by requiring
|
||||
* the SHA3 hash of the concatenation of the nonce and the header’s SHA3 hash to be
|
||||
* sufficiently low. It is formally defined as PoW:
|
||||
*
|
||||
* PoW(H, n) ≡ BE(SHA3(SHA3(RLP(H!n)) ◦ n))
|
||||
*
|
||||
* where:
|
||||
* RLP(H!n) is the RLP encoding of the block header H, not including the
|
||||
* final nonce component;
|
||||
* SHA3 is the SHA3 hash function accepting an arbitrary length series of
|
||||
* bytes and evaluating to a series of 32 bytes (i.e. 256-bit);
|
||||
* n is the nonce, a series of 32 bytes;
|
||||
* o is the series concatenation operator;
|
||||
* BE(X) evaluates to the value equal to X when interpreted as a
|
||||
* big-endian-encoded integer.
|
||||
*
|
||||
* @param newBlock without a valid nonce
|
||||
* @param difficulty - the mining difficulty
|
||||
* @return true if valid nonce has been added to the block
|
||||
*/
|
||||
public boolean mine(Block newBlock, byte[] difficulty) {
|
||||
|
||||
// eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; }
|
||||
stop = false;
|
||||
BigInteger max = BigInteger.valueOf(2).pow(255);
|
||||
byte[] target = BigIntegers.asUnsignedByteArray(32,
|
||||
max.divide(new BigInteger(1, difficulty)));
|
||||
BigInteger max = BigInteger.valueOf(2).pow(255);
|
||||
byte[] target = BigIntegers.asUnsignedByteArray(32,
|
||||
max.divide(new BigInteger(1, difficulty)));
|
||||
|
||||
|
||||
long newGasLimit = Math.max(125000,
|
||||
@ -74,10 +74,10 @@ public class Miner {
|
||||
|
||||
byte[] hash = SHA3Helper.sha3(newBlock.getEncodedWithoutNonce());
|
||||
|
||||
byte[] testNonce = new byte[32];
|
||||
byte[] concat;
|
||||
|
||||
while(ByteUtil.increment(testNonce) && !stop) {
|
||||
byte[] testNonce = new byte[32];
|
||||
byte[] concat;
|
||||
|
||||
while(ByteUtil.increment(testNonce) && !stop) {
|
||||
|
||||
if (testNonce[31] == 0 && testNonce[30] == 0){
|
||||
System.out.println("mining: " + new BigInteger(1, testNonce));
|
||||
@ -85,15 +85,15 @@ public class Miner {
|
||||
|
||||
if (testNonce[31] == 0)
|
||||
sleep();
|
||||
concat = Arrays.concatenate(hash, testNonce);
|
||||
byte[] result = SHA3Helper.sha3(concat);
|
||||
if(FastByteComparisons.compareTo(result, 0, 32, target, 0, 32) < 0) {
|
||||
newBlock.setNonce(testNonce);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // couldn't find a valid nonce
|
||||
}
|
||||
concat = Arrays.concatenate(hash, testNonce);
|
||||
byte[] result = SHA3Helper.sha3(concat);
|
||||
if(FastByteComparisons.compareTo(result, 0, 32, target, 0, 32) < 0) {
|
||||
newBlock.setNonce(testNonce);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // couldn't find a valid nonce
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
stop = true;
|
||||
|
@ -25,42 +25,42 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
@Component
|
||||
public class BlockQueue {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("blockqueue");
|
||||
private static final Logger logger = LoggerFactory.getLogger("blockqueue");
|
||||
|
||||
/** The list of hashes of the heaviest chain on the network,
|
||||
* for which this client doesn't have the blocks yet */
|
||||
private Deque<byte[]> blockHashQueue = new ArrayDeque<>();
|
||||
|
||||
/** Queue with blocks to be validated and added to the blockchain */
|
||||
private Queue<Block> blockReceivedQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
/** Highest known total difficulty, representing the heaviest chain on the network */
|
||||
/** The list of hashes of the heaviest chain on the network,
|
||||
* for which this client doesn't have the blocks yet */
|
||||
private Deque<byte[]> blockHashQueue = new ArrayDeque<>();
|
||||
|
||||
/** Queue with blocks to be validated and added to the blockchain */
|
||||
private Queue<Block> blockReceivedQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
/** Highest known total difficulty, representing the heaviest chain on the network */
|
||||
private BigInteger highestTotalDifficulty;
|
||||
|
||||
/** Last block in the queue to be processed */
|
||||
private Block lastBlock;
|
||||
private Block lastBlock;
|
||||
|
||||
private Timer timer = new Timer("BlockQueueTimer");
|
||||
private Timer timer = new Timer("BlockQueueTimer");
|
||||
|
||||
@Autowired
|
||||
Blockchain blockchain;
|
||||
|
||||
public BlockQueue() {
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
public void run() {
|
||||
nudgeQueue();
|
||||
}
|
||||
}, 10, 10);
|
||||
}
|
||||
public BlockQueue() {
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
public void run() {
|
||||
nudgeQueue();
|
||||
}
|
||||
}, 10, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing the queue adding blocks to the chain.
|
||||
*/
|
||||
private void nudgeQueue() {
|
||||
if (blockReceivedQueue.isEmpty())
|
||||
return;
|
||||
|
||||
logger.info("BlockQueue size: {}", blockReceivedQueue.size());
|
||||
/**
|
||||
* Processing the queue adding blocks to the chain.
|
||||
*/
|
||||
private void nudgeQueue() {
|
||||
if (blockReceivedQueue.isEmpty())
|
||||
return;
|
||||
|
||||
logger.info("BlockQueue size: {}", blockReceivedQueue.size());
|
||||
while(!blockReceivedQueue.isEmpty()){
|
||||
Block block = blockReceivedQueue.poll();
|
||||
|
||||
@ -68,27 +68,27 @@ public class BlockQueue {
|
||||
blockchain.tryToConnect(block);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of blocks to the processing queue.
|
||||
* The list is validated by making sure the first block in the received list of blocks
|
||||
* is the next expected block number of the queue.
|
||||
*
|
||||
* The queue is configured to contain a maximum number of blocks to avoid memory issues
|
||||
* If the list exceeds that, the rest of the received blocks in the list are discarded.
|
||||
*
|
||||
* @param blockList - the blocks received from a peer to be added to the queue
|
||||
*/
|
||||
public void addBlocks(List<Block> blockList) {
|
||||
/**
|
||||
* Add a list of blocks to the processing queue.
|
||||
* The list is validated by making sure the first block in the received list of blocks
|
||||
* is the next expected block number of the queue.
|
||||
*
|
||||
* The queue is configured to contain a maximum number of blocks to avoid memory issues
|
||||
* If the list exceeds that, the rest of the received blocks in the list are discarded.
|
||||
*
|
||||
* @param blockList - the blocks received from a peer to be added to the queue
|
||||
*/
|
||||
public void addBlocks(List<Block> blockList) {
|
||||
|
||||
blockReceivedQueue.addAll(blockList);
|
||||
lastBlock = blockList.get(blockList.size() - 1);
|
||||
|
||||
logger.info("Blocks waiting to be proceed: queue.size: [{}] lastBlock.number: [{}]" ,
|
||||
blockReceivedQueue.size(),
|
||||
logger.info("Blocks waiting to be proceed: queue.size: [{}] lastBlock.number: [{}]" ,
|
||||
blockReceivedQueue.size(),
|
||||
lastBlock.getNumber());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adding single block to the queue usually
|
||||
@ -104,49 +104,49 @@ public class BlockQueue {
|
||||
blockReceivedQueue.size(),
|
||||
lastBlock.getNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last block in the queue. If the queue is empty,
|
||||
* this will return the last block added to the blockchain.
|
||||
*
|
||||
* @return The last known block this client on the network
|
||||
* and will never return <code>null</code> as there is
|
||||
* always the Genesis block at the start of the chain.
|
||||
*/
|
||||
public Block getLastBlock() {
|
||||
if (blockReceivedQueue.isEmpty())
|
||||
return blockchain.getBestBlock();
|
||||
return lastBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last block in the queue. If the queue is empty,
|
||||
* this will return the last block added to the blockchain.
|
||||
*
|
||||
* @return The last known block this client on the network
|
||||
* and will never return <code>null</code> as there is
|
||||
* always the Genesis block at the start of the chain.
|
||||
*/
|
||||
public Block getLastBlock() {
|
||||
if (blockReceivedQueue.isEmpty())
|
||||
return blockchain.getBestBlock();
|
||||
return lastBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the queue of hashes of blocks to be retrieved
|
||||
* and add the best hash to the top of the queue
|
||||
*
|
||||
* @param hash - the best hash
|
||||
*/
|
||||
public void setBestHash(byte[] hash) {
|
||||
blockHashQueue.clear();
|
||||
blockHashQueue.addLast(hash);
|
||||
}
|
||||
/**
|
||||
* Reset the queue of hashes of blocks to be retrieved
|
||||
* and add the best hash to the top of the queue
|
||||
*
|
||||
* @param hash - the best hash
|
||||
*/
|
||||
public void setBestHash(byte[] hash) {
|
||||
blockHashQueue.clear();
|
||||
blockHashQueue.addLast(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last added hash to the queue representing
|
||||
* the latest known block on the network
|
||||
*
|
||||
* @return The best hash on the network known to the client
|
||||
*/
|
||||
public byte[] getBestHash() {
|
||||
return blockHashQueue.peekLast();
|
||||
}
|
||||
/**
|
||||
* Returns the last added hash to the queue representing
|
||||
* the latest known block on the network
|
||||
*
|
||||
* @return The best hash on the network known to the client
|
||||
*/
|
||||
public byte[] getBestHash() {
|
||||
return blockHashQueue.peekLast();
|
||||
}
|
||||
|
||||
public void addHash(byte[] hash) {
|
||||
blockHashQueue.addLast(hash);
|
||||
public void addHash(byte[] hash) {
|
||||
blockHashQueue.addLast(hash);
|
||||
|
||||
if (logger.isTraceEnabled()){
|
||||
logger.trace("Adding hash to a hashQueue: [{}]" , Hex.toHexString(hash));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void returnHashes(List<byte[]> hashes){
|
||||
|
||||
@ -158,20 +158,20 @@ public class BlockQueue {
|
||||
public void addNewBlockHash(byte[] hash){
|
||||
blockHashQueue.addFirst(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of hashes from blocks that still need to be downloaded.
|
||||
*
|
||||
* @return A list of hashes for which blocks need to be retrieved.
|
||||
*/
|
||||
public List<byte[]> getHashes() {
|
||||
|
||||
/**
|
||||
* Return a list of hashes from blocks that still need to be downloaded.
|
||||
*
|
||||
* @return A list of hashes for which blocks need to be retrieved.
|
||||
*/
|
||||
public List<byte[]> getHashes() {
|
||||
|
||||
List<byte[]> hashes = new ArrayList<>();
|
||||
while (!blockHashQueue.isEmpty() && hashes.size() < CONFIG.maxBlocksAsk()) {
|
||||
hashes.add(blockHashQueue.removeLast());
|
||||
}
|
||||
return hashes;
|
||||
}
|
||||
List<byte[]> hashes = new ArrayList<>();
|
||||
while (!blockHashQueue.isEmpty() && hashes.size() < CONFIG.maxBlocksAsk()) {
|
||||
hashes.add(blockHashQueue.removeLast());
|
||||
}
|
||||
return hashes;
|
||||
}
|
||||
|
||||
// a bit ugly but really gives
|
||||
// good result
|
||||
@ -179,39 +179,39 @@ public class BlockQueue {
|
||||
logger.info("Block hashes list size: [{}]", blockHashQueue.size());
|
||||
}
|
||||
|
||||
private class BlockByIndexComparator implements Comparator<Block> {
|
||||
private class BlockByIndexComparator implements Comparator<Block> {
|
||||
|
||||
@Override
|
||||
public int compare(Block o1, Block o2) {
|
||||
@Override
|
||||
public int compare(Block o1, Block o2) {
|
||||
|
||||
if (o1 == null || o2 == null)
|
||||
throw new NullPointerException();
|
||||
if (o1 == null || o2 == null)
|
||||
throw new NullPointerException();
|
||||
|
||||
if (o1.getNumber() > o2.getNumber())
|
||||
return 1;
|
||||
if (o1.getNumber() < o2.getNumber())
|
||||
return -1;
|
||||
if (o1.getNumber() > o2.getNumber())
|
||||
return 1;
|
||||
if (o1.getNumber() < o2.getNumber())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger getHighestTotalDifficulty() {
|
||||
return highestTotalDifficulty;
|
||||
}
|
||||
return highestTotalDifficulty;
|
||||
}
|
||||
|
||||
public void setHighestTotalDifficulty(BigInteger highestTotalDifficulty) {
|
||||
this.highestTotalDifficulty = highestTotalDifficulty;
|
||||
}
|
||||
public void setHighestTotalDifficulty(BigInteger highestTotalDifficulty) {
|
||||
this.highestTotalDifficulty = highestTotalDifficulty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current number of blocks in the queue
|
||||
*
|
||||
* @return the current number of blocks in the queue
|
||||
*/
|
||||
public int size() {
|
||||
return blockReceivedQueue.size();
|
||||
}
|
||||
/**
|
||||
* Returns the current number of blocks in the queue
|
||||
*
|
||||
* @return the current number of blocks in the queue
|
||||
*/
|
||||
public int size() {
|
||||
return blockReceivedQueue.size();
|
||||
}
|
||||
|
||||
public boolean isHashesEmpty(){
|
||||
return blockHashQueue.size() == 0;
|
||||
@ -222,12 +222,12 @@ public class BlockQueue {
|
||||
this.blockReceivedQueue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel and purge the timer-thread that
|
||||
* processes the blocks in the queue
|
||||
*/
|
||||
public void close() {
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
}
|
||||
/**
|
||||
* Cancel and purge the timer-thread that
|
||||
* processes the blocks in the queue
|
||||
*/
|
||||
public void close() {
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
}
|
||||
}
|
||||
|
@ -16,17 +16,17 @@ import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* This class contains the logic for sending messages in a queue
|
||||
* This class contains the logic for sending messages in a queue
|
||||
*
|
||||
* Messages open by send and answered by receive of appropriate message
|
||||
* PING by PONG
|
||||
* GET_PEERS by PEERS
|
||||
* GET_TRANSACTIONS by TRANSACTIONS
|
||||
* GET_BLOCK_HASHES by BLOCK_HASHES
|
||||
* GET_BLOCKS by BLOCKS
|
||||
* Messages open by send and answered by receive of appropriate message
|
||||
* PING by PONG
|
||||
* GET_PEERS by PEERS
|
||||
* GET_TRANSACTIONS by TRANSACTIONS
|
||||
* GET_BLOCK_HASHES by BLOCK_HASHES
|
||||
* GET_BLOCKS by BLOCKS
|
||||
*
|
||||
* The following messages will not be answered:
|
||||
* PONG, PEERS, HELLO, STATUS, TRANSACTIONS, BLOCKS
|
||||
* The following messages will not be answered:
|
||||
* PONG, PEERS, HELLO, STATUS, TRANSACTIONS, BLOCKS
|
||||
*
|
||||
* @author Roman Mandeleil
|
||||
*/
|
||||
@ -34,11 +34,11 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
@Scope("prototype")
|
||||
public class MessageQueue {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("net");
|
||||
private static final Logger logger = LoggerFactory.getLogger("net");
|
||||
|
||||
private Queue<MessageRoundtrip> messageQueue = new ConcurrentLinkedQueue<>();
|
||||
private ChannelHandlerContext ctx = null;
|
||||
private final Timer timer = new Timer("MessageQueue");
|
||||
private Queue<MessageRoundtrip> messageQueue = new ConcurrentLinkedQueue<>();
|
||||
private ChannelHandlerContext ctx = null;
|
||||
private final Timer timer = new Timer("MessageQueue");
|
||||
|
||||
@Autowired
|
||||
WorldManager worldManager;
|
||||
@ -55,67 +55,67 @@ public class MessageQueue {
|
||||
}, 10, 10);
|
||||
}
|
||||
|
||||
public void sendMessage(Message msg) {
|
||||
public void sendMessage(Message msg) {
|
||||
|
||||
if (msg instanceof PingMessage && hasPing)
|
||||
return;
|
||||
if (msg instanceof PingMessage && !hasPing)
|
||||
hasPing = true;
|
||||
|
||||
messageQueue.add(new MessageRoundtrip(msg));
|
||||
}
|
||||
messageQueue.add(new MessageRoundtrip(msg));
|
||||
}
|
||||
|
||||
public void receivedMessage(Message msg) throws InterruptedException {
|
||||
public void receivedMessage(Message msg) throws InterruptedException {
|
||||
|
||||
worldManager.getListener().trace("[Recv: " + msg + "]");
|
||||
|
||||
if (messageQueue.peek() != null) {
|
||||
MessageRoundtrip messageRoundtrip = messageQueue.peek();
|
||||
Message waitingMessage = messageRoundtrip.getMsg();
|
||||
if (messageQueue.peek() != null) {
|
||||
MessageRoundtrip messageRoundtrip = messageQueue.peek();
|
||||
Message waitingMessage = messageRoundtrip.getMsg();
|
||||
|
||||
if (waitingMessage instanceof PingMessage) hasPing = false;
|
||||
|
||||
if (waitingMessage.getAnswerMessage() != null
|
||||
&& msg.getClass() == waitingMessage.getAnswerMessage()) {
|
||||
messageRoundtrip.answer();
|
||||
logger.debug("Message round trip covered: [{}] ",
|
||||
messageRoundtrip.getMsg().getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (waitingMessage.getAnswerMessage() != null
|
||||
&& msg.getClass() == waitingMessage.getAnswerMessage()) {
|
||||
messageRoundtrip.answer();
|
||||
logger.debug("Message round trip covered: [{}] ",
|
||||
messageRoundtrip.getMsg().getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeAnsweredMessage(MessageRoundtrip messageRoundtrip) {
|
||||
if (messageRoundtrip != null && messageRoundtrip.isAnswered())
|
||||
messageQueue.remove();
|
||||
}
|
||||
private void removeAnsweredMessage(MessageRoundtrip messageRoundtrip) {
|
||||
if (messageRoundtrip != null && messageRoundtrip.isAnswered())
|
||||
messageQueue.remove();
|
||||
}
|
||||
|
||||
private void nudgeQueue() {
|
||||
// remove last answered message on the queue
|
||||
removeAnsweredMessage(messageQueue.peek());
|
||||
// Now send the next message
|
||||
sendToWire(messageQueue.peek());
|
||||
}
|
||||
private void nudgeQueue() {
|
||||
// remove last answered message on the queue
|
||||
removeAnsweredMessage(messageQueue.peek());
|
||||
// Now send the next message
|
||||
sendToWire(messageQueue.peek());
|
||||
}
|
||||
|
||||
private void sendToWire(MessageRoundtrip messageRoundtrip) {
|
||||
private void sendToWire(MessageRoundtrip messageRoundtrip) {
|
||||
|
||||
if (messageRoundtrip != null && messageRoundtrip.getRetryTimes() == 0) {
|
||||
// TODO: retry logic || messageRoundtrip.hasToRetry()){
|
||||
if (messageRoundtrip != null && messageRoundtrip.getRetryTimes() == 0) {
|
||||
// TODO: retry logic || messageRoundtrip.hasToRetry()){
|
||||
|
||||
Message msg = messageRoundtrip.getMsg();
|
||||
Message msg = messageRoundtrip.getMsg();
|
||||
|
||||
EthereumListener listener = worldManager.getListener();
|
||||
listener.onSendMessage(msg);
|
||||
|
||||
ctx.writeAndFlush(msg);
|
||||
ctx.writeAndFlush(msg);
|
||||
|
||||
if (msg.getAnswerMessage() == null)
|
||||
messageQueue.remove();
|
||||
else {
|
||||
messageRoundtrip.incRetryTimes();
|
||||
messageRoundtrip.saveTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (msg.getAnswerMessage() == null)
|
||||
messageQueue.remove();
|
||||
else {
|
||||
messageRoundtrip.incRetryTimes();
|
||||
messageRoundtrip.saveTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void close(){
|
||||
timer.cancel();
|
||||
|
@ -12,41 +12,41 @@ import org.ethereum.net.message.Message;
|
||||
*/
|
||||
public class MessageRoundtrip {
|
||||
|
||||
private Message msg = null;
|
||||
long lastTimestamp = 0;
|
||||
long retryTimes = 0;
|
||||
boolean answered = false;
|
||||
private Message msg = null;
|
||||
long lastTimestamp = 0;
|
||||
long retryTimes = 0;
|
||||
boolean answered = false;
|
||||
|
||||
public MessageRoundtrip(Message msg) {
|
||||
this.msg = msg;
|
||||
saveTime();
|
||||
}
|
||||
public MessageRoundtrip(Message msg) {
|
||||
this.msg = msg;
|
||||
saveTime();
|
||||
}
|
||||
|
||||
public boolean isAnswered() {
|
||||
return answered;
|
||||
}
|
||||
public boolean isAnswered() {
|
||||
return answered;
|
||||
}
|
||||
|
||||
public void answer() {
|
||||
answered = true;
|
||||
}
|
||||
public void answer() {
|
||||
answered = true;
|
||||
}
|
||||
|
||||
public long getRetryTimes() {
|
||||
return retryTimes;
|
||||
}
|
||||
public long getRetryTimes() {
|
||||
return retryTimes;
|
||||
}
|
||||
|
||||
public void incRetryTimes() {
|
||||
++retryTimes;
|
||||
}
|
||||
public void incRetryTimes() {
|
||||
++retryTimes;
|
||||
}
|
||||
|
||||
public void saveTime() {
|
||||
lastTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
public void saveTime() {
|
||||
lastTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean hasToRetry() {
|
||||
return 20000 < System.currentTimeMillis() - lastTimestamp;
|
||||
}
|
||||
public boolean hasToRetry() {
|
||||
return 20000 < System.currentTimeMillis() - lastTimestamp;
|
||||
}
|
||||
|
||||
public Message getMsg() {
|
||||
return msg;
|
||||
}
|
||||
public Message getMsg() {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
@ -6,43 +6,43 @@ package org.ethereum.net.client;
|
||||
public class Capability implements Comparable<Capability> {
|
||||
|
||||
public final static String P2P = "p2p";
|
||||
public final static String ETH = "eth";
|
||||
public final static String SHH = "shh";
|
||||
|
||||
private String name;
|
||||
private byte version;
|
||||
public final static String ETH = "eth";
|
||||
public final static String SHH = "shh";
|
||||
|
||||
private String name;
|
||||
private byte version;
|
||||
|
||||
public Capability(String name, byte version) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public Capability(String name, byte version) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public byte getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof Capability)) return false;
|
||||
public byte getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof Capability)) return false;
|
||||
|
||||
Capability other = (Capability)obj;
|
||||
if (this.name == null)
|
||||
return other.name == null;
|
||||
else
|
||||
return this.name.equals(other.name) && this.version == other.version;
|
||||
}
|
||||
Capability other = (Capability)obj;
|
||||
if (this.name == null)
|
||||
return other.name == null;
|
||||
else
|
||||
return this.name.equals(other.name) && this.version == other.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Capability o) {
|
||||
return this.name.compareTo(o.name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name + ":" + version;
|
||||
}
|
||||
@Override
|
||||
public int compareTo(Capability o) {
|
||||
return this.name.compareTo(o.name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name + ":" + version;
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ public class PeerClient {
|
||||
|
||||
public void connect(String host, int port) {
|
||||
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
worldManager.getListener().trace("Connecting to: " + host + ":" + port);
|
||||
|
||||
try {
|
||||
@ -66,9 +66,9 @@ public class PeerClient {
|
||||
logger.debug("Connection is closed");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.debug("Exception: {} ({})", e.getMessage(), e.getClass().getName());
|
||||
logger.debug("Exception: {} ({})", e.getMessage(), e.getClass().getName());
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,66 +18,66 @@ import org.ethereum.util.Utils;
|
||||
*/
|
||||
public class BlockHashesMessage extends EthMessage {
|
||||
|
||||
/** List of block hashes from the peer ordered from child to parent */
|
||||
private List<byte[]> blockHashes;
|
||||
/** List of block hashes from the peer ordered from child to parent */
|
||||
private List<byte[]> blockHashes;
|
||||
|
||||
public BlockHashesMessage(byte[] payload) {
|
||||
super(payload);
|
||||
}
|
||||
public BlockHashesMessage(byte[] payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
public BlockHashesMessage(List<byte[]> blockHashes) {
|
||||
this.blockHashes = blockHashes;
|
||||
parsed = true;
|
||||
}
|
||||
public BlockHashesMessage(List<byte[]> blockHashes) {
|
||||
this.blockHashes = blockHashes;
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
blockHashes = new ArrayList<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
RLPItem rlpData = ((RLPItem) paramsList.get(i));
|
||||
blockHashes.add(rlpData.getRLPData());
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
blockHashes = new ArrayList<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
RLPItem rlpData = ((RLPItem) paramsList.get(i));
|
||||
blockHashes.add(rlpData.getRLPData());
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
List<byte[]> encodedElements = new ArrayList<>();
|
||||
encodedElements.add(RLP.encodeByte(BLOCK_HASHES.asByte()));
|
||||
for (byte[] blockHash : blockHashes)
|
||||
encodedElements.add(RLP.encodeElement(blockHash));
|
||||
byte[][] encodedElementArray = encodedElements
|
||||
.toArray(new byte[encodedElements.size()][]);
|
||||
this.encoded = RLP.encodeList(encodedElementArray);
|
||||
}
|
||||
private void encode() {
|
||||
List<byte[]> encodedElements = new ArrayList<>();
|
||||
encodedElements.add(RLP.encodeByte(BLOCK_HASHES.asByte()));
|
||||
for (byte[] blockHash : blockHashes)
|
||||
encodedElements.add(RLP.encodeElement(blockHash));
|
||||
byte[][] encodedElementArray = encodedElements
|
||||
.toArray(new byte[encodedElements.size()][]);
|
||||
this.encoded = RLP.encodeList(encodedElementArray);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<byte[]> getBlockHashes() {
|
||||
if (!parsed) parse();
|
||||
return blockHashes;
|
||||
}
|
||||
public List<byte[]> getBlockHashes() {
|
||||
if (!parsed) parse();
|
||||
return blockHashes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EthMessageCodes getCommand(){
|
||||
return EthMessageCodes.BLOCK_HASHES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
|
||||
StringBuffer sb = Utils.getHashlistShort(this.blockHashes);
|
||||
return "[" + this.getCommand().name() + sb.toString() + "] (" + this.blockHashes.size() + ")";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
|
||||
StringBuffer sb = Utils.getHashlistShort(this.blockHashes);
|
||||
return "[" + this.getCommand().name() + sb.toString() + "] (" + this.blockHashes.size() + ")";
|
||||
}
|
||||
}
|
||||
|
@ -17,28 +17,28 @@ import static org.ethereum.net.eth.EthMessageCodes.BLOCKS;
|
||||
*/
|
||||
public class BlocksMessage extends EthMessage {
|
||||
|
||||
private List<Block> blocks;
|
||||
private List<Block> blocks;
|
||||
|
||||
public BlocksMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
public BlocksMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
|
||||
public BlocksMessage(List<Block> blocks){
|
||||
this.blocks = blocks;
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
blocks = new ArrayList<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
RLPList rlpData = ((RLPList) paramsList.get(i));
|
||||
Block blockData = new Block(rlpData.getRLPData());
|
||||
blocks.add(blockData);
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
blocks = new ArrayList<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
RLPList rlpData = ((RLPList) paramsList.get(i));
|
||||
Block blockData = new Block(rlpData.getRLPData());
|
||||
blocks.add(blockData);
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
|
||||
@ -56,34 +56,34 @@ public class BlocksMessage extends EthMessage {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
public List<Block> getBlocks() {
|
||||
if (!parsed) parse();
|
||||
return blocks;
|
||||
}
|
||||
public List<Block> getBlocks() {
|
||||
if (!parsed) parse();
|
||||
return blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EthMessageCodes getCommand(){
|
||||
return EthMessageCodes.BLOCKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Block blockData : this.getBlocks()) {
|
||||
sb.append("\n ").append(blockData.toFlatString());
|
||||
}
|
||||
return "[" + getCommand().name() + sb.toString() + "]";
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Block blockData : this.getBlocks()) {
|
||||
sb.append("\n ").append(blockData.toFlatString());
|
||||
}
|
||||
return "[" + getCommand().name() + sb.toString() + "]";
|
||||
}
|
||||
}
|
@ -30,13 +30,13 @@ import static org.ethereum.net.message.StaticMessages.GET_TRANSACTIONS_MESSAGE;
|
||||
* <p>
|
||||
* Peers with 'eth' capability can send/receive:
|
||||
* <ul>
|
||||
* <li>STATUS : Announce their status to the peer</li>
|
||||
* <li>GET_TRANSACTIONS : Request a list of pending transactions</li>
|
||||
* <li>TRANSACTIONS : Send a list of pending transactions</li>
|
||||
* <li>GET_BLOCK_HASHES : Request a list of known block hashes</li>
|
||||
* <li>BLOCK_HASHES : Send a list of known block hashes</li>
|
||||
* <li>GET_BLOCKS : Request a list of blocks</li>
|
||||
* <li>BLOCKS : Send a list of blocks</li>
|
||||
* <li>STATUS : Announce their status to the peer</li>
|
||||
* <li>GET_TRANSACTIONS : Request a list of pending transactions</li>
|
||||
* <li>TRANSACTIONS : Send a list of pending transactions</li>
|
||||
* <li>GET_BLOCK_HASHES : Request a list of known block hashes</li>
|
||||
* <li>BLOCK_HASHES : Send a list of known block hashes</li>
|
||||
* <li>GET_BLOCKS : Request a list of blocks</li>
|
||||
* <li>BLOCKS : Send a list of blocks</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Component
|
||||
@ -78,7 +78,7 @@ public class EthHandler extends SimpleChannelInboundHandler<EthMessage> {
|
||||
}
|
||||
|
||||
public EthHandler(MessageQueue msgQueue, boolean peerDiscoveryMode) {
|
||||
this.peerDiscoveryMode = peerDiscoveryMode;
|
||||
this.peerDiscoveryMode = peerDiscoveryMode;
|
||||
this.msgQueue = msgQueue;
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ public class EthHandler extends SimpleChannelInboundHandler<EthMessage> {
|
||||
switch (msg.getCommand()) {
|
||||
case STATUS:
|
||||
msgQueue.receivedMessage(msg);
|
||||
processStatus((StatusMessage) msg, ctx);
|
||||
processStatus((StatusMessage) msg, ctx);
|
||||
break;
|
||||
case GET_TRANSACTIONS:
|
||||
// todo: eventually get_transaction is going deprecated
|
||||
@ -181,7 +181,7 @@ public class EthHandler extends SimpleChannelInboundHandler<EthMessage> {
|
||||
* <ul>
|
||||
* <li>checking if peer is using the same genesis, protocol and network</li>
|
||||
* <li>seeing if total difficulty is higher than total difficulty from all other peers</li>
|
||||
* <li>send GET_BLOCK_HASHES to this peer based on bestHash</li>
|
||||
* <li>send GET_BLOCK_HASHES to this peer based on bestHash</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param msg is the StatusMessage
|
||||
@ -201,7 +201,7 @@ public class EthHandler extends SimpleChannelInboundHandler<EthMessage> {
|
||||
if (!Arrays.equals(msg.getGenesisHash(), Blockchain.GENESIS_HASH)
|
||||
|| msg.getProtocolVersion() != EthHandler.VERSION) {
|
||||
logger.info("Removing EthHandler for {} due to protocol incompatibility", ctx.channel().remoteAddress());
|
||||
// msgQueue.sendMessage(new DisconnectMessage(ReasonCode.INCOMPATIBLE_NETWORK));
|
||||
// msgQueue.sendMessage(new DisconnectMessage(ReasonCode.INCOMPATIBLE_NETWORK));
|
||||
ctx.pipeline().remove(this); // Peer is not compatible for the 'eth' sub-protocol
|
||||
} else if (msg.getNetworkId() != EthHandler.NETWORK_ID)
|
||||
msgQueue.sendMessage(new DisconnectMessage(ReasonCode.INCOMPATIBLE_NETWORK));
|
||||
|
@ -4,8 +4,8 @@ import org.ethereum.net.eth.EthMessageCodes;
|
||||
import org.ethereum.net.message.Message;
|
||||
|
||||
public abstract class EthMessage extends Message {
|
||||
|
||||
public EthMessage() {}
|
||||
|
||||
public EthMessage() {}
|
||||
|
||||
public EthMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
|
@ -13,46 +13,46 @@ import java.util.Map;
|
||||
*/
|
||||
public enum EthMessageCodes {
|
||||
|
||||
/* Ethereum protocol */
|
||||
/* Ethereum protocol */
|
||||
|
||||
/** [0x00, [PROTOCOL_VERSION, NETWORK_ID, TD, BEST_HASH, GENESIS_HASH] <br>
|
||||
* Inform a peer of it's current ethereum state. This message should be
|
||||
* send after the initial handshake and prior to any ethereum related messages. */
|
||||
STATUS(0x00),
|
||||
/** [0x00, [PROTOCOL_VERSION, NETWORK_ID, TD, BEST_HASH, GENESIS_HASH] <br>
|
||||
* Inform a peer of it's current ethereum state. This message should be
|
||||
* send after the initial handshake and prior to any ethereum related messages. */
|
||||
STATUS(0x00),
|
||||
|
||||
/** [+0x01] Request the peer to send all transactions
|
||||
* currently in the queue. */
|
||||
GET_TRANSACTIONS(0x01),
|
||||
/** [+0x01] Request the peer to send all transactions
|
||||
* currently in the queue. */
|
||||
GET_TRANSACTIONS(0x01),
|
||||
|
||||
/** [+0x02, [nonce, receiving_address, value, ...], ...] <br>
|
||||
* Specify (a) transaction(s) that the peer should make sure is included
|
||||
* on its transaction queue. The items in the list (following the first item 0x12)
|
||||
* are transactions in the format described in the main Ethereum specification. */
|
||||
TRANSACTIONS(0x02),
|
||||
/** [+0x02, [nonce, receiving_address, value, ...], ...] <br>
|
||||
* Specify (a) transaction(s) that the peer should make sure is included
|
||||
* on its transaction queue. The items in the list (following the first item 0x12)
|
||||
* are transactions in the format described in the main Ethereum specification. */
|
||||
TRANSACTIONS(0x02),
|
||||
|
||||
/** [+0x03, [hash : B_32, maxBlocks: P]: <br>
|
||||
* Requests a BlockHashes message of at most maxBlocks entries,
|
||||
* of block hashes from the blockchain, starting at the parent of block hash.
|
||||
* Does not require the peer to give maxBlocks hashes -
|
||||
* they could give somewhat fewer. */
|
||||
GET_BLOCK_HASHES(0x03),
|
||||
/** [+0x03, [hash : B_32, maxBlocks: P]: <br>
|
||||
* Requests a BlockHashes message of at most maxBlocks entries,
|
||||
* of block hashes from the blockchain, starting at the parent of block hash.
|
||||
* Does not require the peer to give maxBlocks hashes -
|
||||
* they could give somewhat fewer. */
|
||||
GET_BLOCK_HASHES(0x03),
|
||||
|
||||
/** [+0x04, [hash_0: B_32, hash_1: B_32, ....]: <br>Gives a series of hashes
|
||||
* of blocks (each the child of the next). This implies that the blocks
|
||||
* are ordered from youngest to oldest. */
|
||||
BLOCK_HASHES(0x04),
|
||||
/** [+0x04, [hash_0: B_32, hash_1: B_32, ....]: <br>Gives a series of hashes
|
||||
* of blocks (each the child of the next). This implies that the blocks
|
||||
* are ordered from youngest to oldest. */
|
||||
BLOCK_HASHES(0x04),
|
||||
|
||||
/** [+0x05, [hash_0: B_32, hash_1: B_32, ....]: <br>Requests a Blocks message
|
||||
* detailing a number of blocks to be sent, each referred to by a hash. <br>
|
||||
* <b>Note:</b> Don't expect that the peer necessarily give you all these blocks
|
||||
* in a single message - you might have to re-request them. */
|
||||
GET_BLOCKS(0x05),
|
||||
/** [+0x05, [hash_0: B_32, hash_1: B_32, ....]: <br>Requests a Blocks message
|
||||
* detailing a number of blocks to be sent, each referred to by a hash. <br>
|
||||
* <b>Note:</b> Don't expect that the peer necessarily give you all these blocks
|
||||
* in a single message - you might have to re-request them. */
|
||||
GET_BLOCKS(0x05),
|
||||
|
||||
/** [+0x06, [block_header, transaction_list, uncle_list], ...] <br>
|
||||
* Specify (a) block(s) that the peer should know about.
|
||||
* The items in the list (following the first item, 0x13)
|
||||
* are blocks in the format described in the main Ethereum specification. */
|
||||
BLOCKS(0x06),
|
||||
/** [+0x06, [block_header, transaction_list, uncle_list], ...] <br>
|
||||
* Specify (a) block(s) that the peer should know about.
|
||||
* The items in the list (following the first item, 0x13)
|
||||
* are blocks in the format described in the main Ethereum specification. */
|
||||
BLOCKS(0x06),
|
||||
|
||||
/**
|
||||
* [+0x07 [blockHeader, transactionList, uncleList], totalDifficulty] <br>
|
||||
@ -81,18 +81,18 @@ public enum EthMessageCodes {
|
||||
}
|
||||
|
||||
public static EthMessageCodes fromByte(byte i) {
|
||||
EthMessageCodes type = intToTypeMap.get(i - OFFSET);
|
||||
EthMessageCodes type = intToTypeMap.get(i - OFFSET);
|
||||
return type;
|
||||
}
|
||||
|
||||
public static boolean inRange(byte code){
|
||||
return code >= STATUS.asByte() && code <= PACKET_COUNT.asByte();
|
||||
return code >= STATUS.asByte() && code <= PACKET_COUNT.asByte();
|
||||
}
|
||||
|
||||
public static void setOffset(byte offset){
|
||||
EthMessageCodes.OFFSET = offset;
|
||||
}
|
||||
public byte asByte() {
|
||||
return (byte) (cmd + OFFSET);
|
||||
return (byte) (cmd + OFFSET);
|
||||
}
|
||||
}
|
||||
|
@ -14,62 +14,62 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class GetBlockHashesMessage extends EthMessage {
|
||||
|
||||
/** The newest block hash from which to start sending older hashes */
|
||||
private byte[] bestHash;
|
||||
|
||||
/** The maximum number of blocks to return.
|
||||
* <b>Note:</b> the peer could return fewer. */
|
||||
private int maxBlocks;
|
||||
/** The newest block hash from which to start sending older hashes */
|
||||
private byte[] bestHash;
|
||||
|
||||
/** The maximum number of blocks to return.
|
||||
* <b>Note:</b> the peer could return fewer. */
|
||||
private int maxBlocks;
|
||||
|
||||
public GetBlockHashesMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
public GetBlockHashesMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
|
||||
public GetBlockHashesMessage(byte[] hash, int maxBlocks) {
|
||||
this.bestHash = hash;
|
||||
this.maxBlocks = maxBlocks;
|
||||
parsed = true;
|
||||
encode();
|
||||
}
|
||||
public GetBlockHashesMessage(byte[] hash, int maxBlocks) {
|
||||
this.bestHash = hash;
|
||||
this.maxBlocks = maxBlocks;
|
||||
parsed = true;
|
||||
encode();
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
byte[] command = RLP.encodeByte(GET_BLOCK_HASHES.asByte());
|
||||
byte[] hash = RLP.encodeElement(this.bestHash);
|
||||
byte[] maxBlocks = RLP.encodeInt(this.maxBlocks);
|
||||
this.encoded = RLP.encodeList(command, hash, maxBlocks);
|
||||
}
|
||||
private void encode() {
|
||||
byte[] command = RLP.encodeByte(GET_BLOCK_HASHES.asByte());
|
||||
byte[] hash = RLP.encodeElement(this.bestHash);
|
||||
byte[] maxBlocks = RLP.encodeInt(this.maxBlocks);
|
||||
this.encoded = RLP.encodeList(command, hash, maxBlocks);
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
this.bestHash = paramsList.get(1).getRLPData();
|
||||
byte[] maxBlocksBytes = paramsList.get(2).getRLPData();
|
||||
this.maxBlocks = ByteUtil.byteArrayToInt(maxBlocksBytes);
|
||||
this.bestHash = paramsList.get(1).getRLPData();
|
||||
byte[] maxBlocksBytes = paramsList.get(2).getRLPData();
|
||||
this.maxBlocks = ByteUtil.byteArrayToInt(maxBlocksBytes);
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if(encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if(encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<BlockHashesMessage> getAnswerMessage() {
|
||||
return BlockHashesMessage.class;
|
||||
}
|
||||
@Override
|
||||
public Class<BlockHashesMessage> getAnswerMessage() {
|
||||
return BlockHashesMessage.class;
|
||||
}
|
||||
|
||||
public byte[] getBestHash() {
|
||||
if (!parsed) parse();
|
||||
return bestHash;
|
||||
}
|
||||
public byte[] getBestHash() {
|
||||
if (!parsed) parse();
|
||||
return bestHash;
|
||||
}
|
||||
|
||||
public int getMaxBlocks() {
|
||||
if (!parsed) parse();
|
||||
return maxBlocks;
|
||||
}
|
||||
public int getMaxBlocks() {
|
||||
if (!parsed) parse();
|
||||
return maxBlocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EthMessageCodes getCommand(){
|
||||
@ -77,11 +77,11 @@ public class GetBlockHashesMessage extends EthMessage {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
return "[" + this.getCommand().name() +
|
||||
" bestHash=" + Hex.toHexString(bestHash) +
|
||||
" maxBlocks=" + maxBlocks + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
return "[" + this.getCommand().name() +
|
||||
" bestHash=" + Hex.toHexString(bestHash) +
|
||||
" maxBlocks=" + maxBlocks + "]";
|
||||
}
|
||||
}
|
@ -17,64 +17,64 @@ import static org.ethereum.net.eth.EthMessageCodes.GET_BLOCKS;
|
||||
*/
|
||||
public class GetBlocksMessage extends EthMessage {
|
||||
|
||||
/** List of block hashes for which to retrieve the blocks */
|
||||
private List<byte[]> blockHashes;
|
||||
/** List of block hashes for which to retrieve the blocks */
|
||||
private List<byte[]> blockHashes;
|
||||
|
||||
public GetBlocksMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
public GetBlocksMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
|
||||
public GetBlocksMessage(List<byte[]> blockHashes) {
|
||||
this.blockHashes = blockHashes;
|
||||
parsed = true;
|
||||
}
|
||||
public GetBlocksMessage(List<byte[]> blockHashes) {
|
||||
this.blockHashes = blockHashes;
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
blockHashes = new ArrayList<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
blockHashes.add(((RLPItem) paramsList.get(i)).getRLPData());
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
blockHashes = new ArrayList<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
blockHashes.add(((RLPItem) paramsList.get(i)).getRLPData());
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
List<byte[]> encodedElements = new ArrayList<>();
|
||||
encodedElements.add(RLP.encodeByte(GET_BLOCKS.asByte()));
|
||||
for (byte[] hash : blockHashes)
|
||||
encodedElements.add(RLP.encodeElement(hash));
|
||||
byte[][] encodedElementArray = encodedElements
|
||||
.toArray(new byte[encodedElements.size()][]);
|
||||
this.encoded = RLP.encodeList(encodedElementArray);
|
||||
}
|
||||
private void encode() {
|
||||
List<byte[]> encodedElements = new ArrayList<>();
|
||||
encodedElements.add(RLP.encodeByte(GET_BLOCKS.asByte()));
|
||||
for (byte[] hash : blockHashes)
|
||||
encodedElements.add(RLP.encodeElement(hash));
|
||||
byte[][] encodedElementArray = encodedElements
|
||||
.toArray(new byte[encodedElements.size()][]);
|
||||
this.encoded = RLP.encodeList(encodedElementArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<BlocksMessage> getAnswerMessage() {
|
||||
return BlocksMessage.class;
|
||||
}
|
||||
@Override
|
||||
public Class<BlocksMessage> getAnswerMessage() {
|
||||
return BlocksMessage.class;
|
||||
}
|
||||
|
||||
public List<byte[]> getBlockHashes() {
|
||||
if (!parsed) parse();
|
||||
return blockHashes;
|
||||
}
|
||||
public List<byte[]> getBlockHashes() {
|
||||
if (!parsed) parse();
|
||||
return blockHashes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EthMessageCodes getCommand(){
|
||||
return EthMessageCodes.GET_BLOCKS;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
|
||||
StringBuffer sb = Utils.getHashlistShort(this.blockHashes);
|
||||
return "[" + this.getCommand().name() + sb.toString() + "] (" + this.blockHashes.size() + ")";
|
||||
}
|
||||
StringBuffer sb = Utils.getHashlistShort(this.blockHashes);
|
||||
return "[" + this.getCommand().name() + sb.toString() + "] (" + this.blockHashes.size() + ")";
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class GetTransactionsMessage extends EthMessage {
|
||||
|
||||
/** GetTransactions message is always a the same single command payload */
|
||||
private final static byte[] FIXED_PAYLOAD = Hex.decode("C116");
|
||||
/** GetTransactions message is always a the same single command payload */
|
||||
private final static byte[] FIXED_PAYLOAD = Hex.decode("C116");
|
||||
|
||||
public byte[] getEncoded() {
|
||||
return FIXED_PAYLOAD;
|
||||
@ -30,7 +30,7 @@ public class GetTransactionsMessage extends EthMessage {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.getCommand().name() + "]";
|
||||
return "[" + this.getCommand().name() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,12 +12,12 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class NewBlockMessage extends EthMessage {
|
||||
|
||||
private Block block;
|
||||
private Block block;
|
||||
private byte[] difficulty;
|
||||
|
||||
public NewBlockMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
public NewBlockMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
|
||||
public NewBlockMessage(Block block, byte[] difficulty){
|
||||
this.block = block;
|
||||
@ -34,15 +34,15 @@ public class NewBlockMessage extends EthMessage {
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
RLPList blockRLP = ((RLPList) paramsList.get(1));
|
||||
block = new Block(blockRLP.getRLPData());
|
||||
difficulty = paramsList.get(2).getRLPData();
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Block getBlock(){
|
||||
if (!parsed) parse();
|
||||
@ -54,25 +54,25 @@ public class NewBlockMessage extends EthMessage {
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return encoded;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return encoded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EthMessageCodes getCommand(){
|
||||
return EthMessageCodes.NEW_BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
|
||||
String blockString = this.getBlock().toString();
|
||||
return "NEW_BLOCK [ " + blockString + "\n difficulty: " + Hex.toHexString(difficulty) + " ]";
|
||||
}
|
||||
}
|
||||
}
|
@ -20,25 +20,25 @@ public class PacketCountMessage extends EthMessage {
|
||||
|
||||
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 Class<PongMessage> getAnswerMessage() {
|
||||
return PongMessage.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EthMessageCodes getCommand(){
|
||||
return EthMessageCodes.PACKET_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + getCommand().name() + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + getCommand().name() + "]";
|
||||
}
|
||||
}
|
@ -42,23 +42,23 @@ public class StatusMessage extends EthMessage {
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
this.protocolVersion = ((RLPItem) paramsList.get(1)).getRLPData()[0];
|
||||
byte[] networkIdBytes = ((RLPItem) paramsList.get(2)).getRLPData();
|
||||
this.networkId = networkIdBytes == null ? 0 : networkIdBytes[0];
|
||||
this.totalDifficulty = ((RLPItem) paramsList.get(3)).getRLPData();
|
||||
this.bestHash = ((RLPItem) paramsList.get(4)).getRLPData();
|
||||
this.genesisHash = ((RLPItem) paramsList.get(5)).getRLPData();
|
||||
this.protocolVersion = ((RLPItem) paramsList.get(1)).getRLPData()[0];
|
||||
byte[] networkIdBytes = ((RLPItem) paramsList.get(2)).getRLPData();
|
||||
this.networkId = networkIdBytes == null ? 0 : networkIdBytes[0];
|
||||
this.totalDifficulty = ((RLPItem) paramsList.get(3)).getRLPData();
|
||||
this.bestHash = ((RLPItem) paramsList.get(4)).getRLPData();
|
||||
this.genesisHash = ((RLPItem) paramsList.get(5)).getRLPData();
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
byte[] command = RLP.encodeByte(STATUS.asByte());
|
||||
byte[] protocolVersion = RLP.encodeByte(this.protocolVersion);
|
||||
byte[] networkId = RLP.encodeByte(this.networkId);
|
||||
byte[] totalDifficulty = RLP.encodeElement(this.totalDifficulty);
|
||||
byte[] bestHash = RLP.encodeElement(this.bestHash);
|
||||
byte[] genesisHash = RLP.encodeElement(this.genesisHash);
|
||||
byte[] command = RLP.encodeByte(STATUS.asByte());
|
||||
byte[] protocolVersion = RLP.encodeByte(this.protocolVersion);
|
||||
byte[] networkId = RLP.encodeByte(this.networkId);
|
||||
byte[] totalDifficulty = RLP.encodeElement(this.totalDifficulty);
|
||||
byte[] bestHash = RLP.encodeElement(this.bestHash);
|
||||
byte[] genesisHash = RLP.encodeElement(this.genesisHash);
|
||||
|
||||
this.encoded = RLP.encodeList(command, protocolVersion, networkId,
|
||||
totalDifficulty, bestHash, genesisHash);
|
||||
|
@ -18,7 +18,7 @@ import java.util.Set;
|
||||
* @see org.ethereum.net.eth.EthMessageCodes#TRANSACTIONS
|
||||
*/
|
||||
public class TransactionsMessage extends EthMessage {
|
||||
|
||||
|
||||
private Set<Transaction> transactions;
|
||||
|
||||
public TransactionsMessage(byte[] encoded) {
|
||||
@ -38,9 +38,9 @@ public class TransactionsMessage extends EthMessage {
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
transactions = new HashSet<>();
|
||||
transactions = new HashSet<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
RLPList rlpTxData = (RLPList) paramsList.get(i);
|
||||
Transaction tx = new Transaction(rlpTxData.getRLPData());
|
||||
@ -50,19 +50,19 @@ public class TransactionsMessage extends EthMessage {
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
List<byte[]> encodedElements = new ArrayList<>();
|
||||
encodedElements.add(RLP.encodeByte(TRANSACTIONS.asByte()));
|
||||
for (Transaction tx : transactions)
|
||||
List<byte[]> encodedElements = new ArrayList<>();
|
||||
encodedElements.add(RLP.encodeByte(TRANSACTIONS.asByte()));
|
||||
for (Transaction tx : transactions)
|
||||
encodedElements.add(tx.getEncoded());
|
||||
byte[][] encodedElementArray = encodedElements
|
||||
.toArray(new byte[encodedElements.size()][]);
|
||||
byte[][] encodedElementArray = encodedElements
|
||||
.toArray(new byte[encodedElements.size()][]);
|
||||
this.encoded = RLP.encodeList(encodedElementArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
|
||||
|
||||
|
@ -12,7 +12,7 @@ public abstract class Message {
|
||||
protected byte[] encoded;
|
||||
protected byte code;
|
||||
|
||||
public Message() {}
|
||||
public Message() {}
|
||||
|
||||
public Message(byte[] encoded) {
|
||||
this.encoded = encoded;
|
||||
@ -24,14 +24,14 @@ public abstract class Message {
|
||||
*
|
||||
* @return RLP encoded byte array representation of this message
|
||||
*/
|
||||
public abstract byte[] getEncoded();
|
||||
|
||||
public abstract Class<?> getAnswerMessage();
|
||||
|
||||
/**
|
||||
* Returns the message in String format
|
||||
*
|
||||
* @return A string with all attributes of the message
|
||||
*/
|
||||
public abstract String toString();
|
||||
public abstract byte[] getEncoded();
|
||||
|
||||
public abstract Class<?> getAnswerMessage();
|
||||
|
||||
/**
|
||||
* Returns the message in String format
|
||||
*
|
||||
* @return A string with all attributes of the message
|
||||
*/
|
||||
public abstract String toString();
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import java.util.Map;
|
||||
*/
|
||||
public enum ReasonCode {
|
||||
|
||||
/** [0x00] Disconnect request by other peer */
|
||||
/** [0x00] Disconnect request by other peer */
|
||||
REQUESTED(0x00),
|
||||
|
||||
/** [0x01] */
|
||||
@ -37,7 +37,7 @@ public enum ReasonCode {
|
||||
PEER_QUITING(0x08),
|
||||
|
||||
/** [0xFF] Reason not specified */
|
||||
UNKNOWN(0xFF);
|
||||
UNKNOWN(0xFF);
|
||||
|
||||
private int reason;
|
||||
|
||||
@ -53,13 +53,13 @@ public enum ReasonCode {
|
||||
}
|
||||
|
||||
public static ReasonCode fromInt(int i) {
|
||||
ReasonCode type = intToTypeMap.get(Integer.valueOf(i));
|
||||
ReasonCode type = intToTypeMap.get(Integer.valueOf(i));
|
||||
if (type == null)
|
||||
return ReasonCode.UNKNOWN;
|
||||
return type;
|
||||
}
|
||||
|
||||
public byte asByte() {
|
||||
return (byte) reason;
|
||||
return (byte) reason;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package org.ethereum.net.message;
|
||||
|
||||
public abstract class ShhMessage extends Message {
|
||||
|
||||
public ShhMessage() {}
|
||||
public ShhMessage() {}
|
||||
|
||||
public ShhMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
|
@ -25,37 +25,37 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class StaticMessages {
|
||||
|
||||
public static final String PEER_ID = Hex.toHexString(HashUtil.randomPeerId());
|
||||
|
||||
public final static PingMessage PING_MESSAGE = new PingMessage();
|
||||
public final static PongMessage PONG_MESSAGE = new PongMessage();
|
||||
public final static HelloMessage HELLO_MESSAGE = generateHelloMessage();
|
||||
public final static GetPeersMessage GET_PEERS_MESSAGE = new GetPeersMessage();
|
||||
public final static GetTransactionsMessage GET_TRANSACTIONS_MESSAGE = new GetTransactionsMessage();
|
||||
public static final String PEER_ID = Hex.toHexString(HashUtil.randomPeerId());
|
||||
|
||||
public final static PingMessage PING_MESSAGE = new PingMessage();
|
||||
public final static PongMessage PONG_MESSAGE = new PongMessage();
|
||||
public final static HelloMessage HELLO_MESSAGE = generateHelloMessage();
|
||||
public final static GetPeersMessage GET_PEERS_MESSAGE = new GetPeersMessage();
|
||||
public final static GetTransactionsMessage GET_TRANSACTIONS_MESSAGE = new GetTransactionsMessage();
|
||||
|
||||
public static final byte[] SYNC_TOKEN = Hex.decode("22400891");
|
||||
public static final byte[] SYNC_TOKEN = Hex.decode("22400891");
|
||||
|
||||
private static HelloMessage generateHelloMessage() {
|
||||
String helloAnnouncement = buildHelloAnnouncement();
|
||||
byte p2pVersion = P2pHandler.VERSION;
|
||||
List<Capability> capabilities = Arrays.asList(
|
||||
new Capability(Capability.ETH, EthHandler.VERSION),
|
||||
new Capability(Capability.SHH, ShhHandler.VERSION));
|
||||
int listenPort = SystemProperties.CONFIG.listenPort();
|
||||
private static HelloMessage generateHelloMessage() {
|
||||
String helloAnnouncement = buildHelloAnnouncement();
|
||||
byte p2pVersion = P2pHandler.VERSION;
|
||||
List<Capability> capabilities = Arrays.asList(
|
||||
new Capability(Capability.ETH, EthHandler.VERSION),
|
||||
new Capability(Capability.SHH, ShhHandler.VERSION));
|
||||
int listenPort = SystemProperties.CONFIG.listenPort();
|
||||
|
||||
return new HelloMessage(p2pVersion, helloAnnouncement,
|
||||
capabilities, listenPort, PEER_ID);
|
||||
}
|
||||
return new HelloMessage(p2pVersion, helloAnnouncement,
|
||||
capabilities, listenPort, PEER_ID);
|
||||
}
|
||||
|
||||
private static String buildHelloAnnouncement() {
|
||||
String version = SystemProperties.CONFIG.projectVersion();
|
||||
String system = System.getProperty("os.name");
|
||||
if (system.contains(" "))
|
||||
system = system.substring(0, system.indexOf(" "));
|
||||
if (System.getProperty("java.vm.vendor").contains("Android"))
|
||||
system = "Android";
|
||||
String phrase = SystemProperties.CONFIG.helloPhrase();
|
||||
private static String buildHelloAnnouncement() {
|
||||
String version = SystemProperties.CONFIG.projectVersion();
|
||||
String system = System.getProperty("os.name");
|
||||
if (system.contains(" "))
|
||||
system = system.substring(0, system.indexOf(" "));
|
||||
if (System.getProperty("java.vm.vendor").contains("Android"))
|
||||
system = "Android";
|
||||
String phrase = SystemProperties.CONFIG.helloPhrase();
|
||||
|
||||
return String.format("Ethereum(J)/v%s/%s/%s/Java", version, phrase, system);
|
||||
}
|
||||
return String.format("Ethereum(J)/v%s/%s/%s/Java", version, phrase, system);
|
||||
}
|
||||
}
|
||||
|
@ -16,58 +16,58 @@ import static org.ethereum.net.message.ReasonCode.REQUESTED;
|
||||
*/
|
||||
public class DisconnectMessage extends P2pMessage {
|
||||
|
||||
private ReasonCode reason;
|
||||
private ReasonCode reason;
|
||||
|
||||
public DisconnectMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
public DisconnectMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
|
||||
public DisconnectMessage(ReasonCode reason) {
|
||||
this.reason = reason;
|
||||
parsed = true;
|
||||
}
|
||||
public DisconnectMessage(ReasonCode reason) {
|
||||
this.reason = reason;
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
byte[] reasonBytes = ((RLPItem) paramsList.get(1)).getRLPData();
|
||||
if (reasonBytes == null)
|
||||
this.reason = REQUESTED;
|
||||
else
|
||||
this.reason = ReasonCode.fromInt(reasonBytes[0]);
|
||||
byte[] reasonBytes = ((RLPItem) paramsList.get(1)).getRLPData();
|
||||
if (reasonBytes == null)
|
||||
this.reason = REQUESTED;
|
||||
else
|
||||
this.reason = ReasonCode.fromInt(reasonBytes[0]);
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
byte[] encodedCommand = RLP.encodeByte(DISCONNECT.asByte());
|
||||
byte[] encodedReason = RLP.encodeByte(this.reason.asByte());
|
||||
this.encoded = RLP.encodeList(encodedCommand, encodedReason);
|
||||
}
|
||||
private void encode() {
|
||||
byte[] encodedCommand = RLP.encodeByte(DISCONNECT.asByte());
|
||||
byte[] encodedReason = RLP.encodeByte(this.reason.asByte());
|
||||
this.encoded = RLP.encodeList(encodedCommand, encodedReason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P2pMessageCodes getCommand(){
|
||||
return P2pMessageCodes.DISCONNECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ReasonCode getReason() {
|
||||
if (!parsed) parse();
|
||||
return reason;
|
||||
}
|
||||
public ReasonCode getReason() {
|
||||
if (!parsed) parse();
|
||||
return reason;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
return "[" + this.getCommand().name() + " reason=" + reason + "]";
|
||||
}
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
return "[" + this.getCommand().name() + " reason=" + reason + "]";
|
||||
}
|
||||
}
|
@ -9,26 +9,26 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class GetPeersMessage extends P2pMessage {
|
||||
|
||||
/** GetPeers message is always a the same single command payload */
|
||||
private final static byte[] FIXED_PAYLOAD = Hex.decode("C104");
|
||||
/** GetPeers message is always a the same single command payload */
|
||||
private final static byte[] FIXED_PAYLOAD = Hex.decode("C104");
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return FIXED_PAYLOAD;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return FIXED_PAYLOAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P2pMessageCodes getCommand(){
|
||||
return P2pMessageCodes.GET_PEERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<PeersMessage> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Class<PeersMessage> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.getCommand().name() + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.getCommand().name() + "]";
|
||||
}
|
||||
}
|
@ -20,47 +20,47 @@ import java.util.List;
|
||||
*/
|
||||
public class HelloMessage extends P2pMessage {
|
||||
|
||||
/** The implemented version of the P2P protocol. */
|
||||
private byte p2pVersion;
|
||||
/** The underlying client. A user-readable string. */
|
||||
private String clientId;
|
||||
/** A peer-network capability code, readable ASCII and 3 letters.
|
||||
* Currently only "eth", "shh" and "bzz" are known. */
|
||||
private List<Capability> capabilities;
|
||||
/** The port on which the peer is listening for an incoming connection */
|
||||
private int listenPort;
|
||||
/** The identity and public key of the peer */
|
||||
private String peerId;
|
||||
/** The implemented version of the P2P protocol. */
|
||||
private byte p2pVersion;
|
||||
/** The underlying client. A user-readable string. */
|
||||
private String clientId;
|
||||
/** A peer-network capability code, readable ASCII and 3 letters.
|
||||
* Currently only "eth", "shh" and "bzz" are known. */
|
||||
private List<Capability> capabilities;
|
||||
/** The port on which the peer is listening for an incoming connection */
|
||||
private int listenPort;
|
||||
/** The identity and public key of the peer */
|
||||
private String peerId;
|
||||
|
||||
public HelloMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
public HelloMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
}
|
||||
|
||||
public HelloMessage(byte p2pVersion, String clientId,
|
||||
List<Capability> capabilities, int listenPort, String peerId) {
|
||||
this.p2pVersion = p2pVersion;
|
||||
this.clientId = clientId;
|
||||
this.capabilities = capabilities;
|
||||
this.listenPort = listenPort;
|
||||
this.peerId = peerId;
|
||||
this.parsed = true;
|
||||
}
|
||||
public HelloMessage(byte p2pVersion, String clientId,
|
||||
List<Capability> capabilities, int listenPort, String peerId) {
|
||||
this.p2pVersion = p2pVersion;
|
||||
this.clientId = clientId;
|
||||
this.capabilities = capabilities;
|
||||
this.listenPort = listenPort;
|
||||
this.peerId = peerId;
|
||||
this.parsed = true;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
// TODO: find out if it can be 0x00. Do we need to check for this?
|
||||
// The message does not distinguish between 0 and null,
|
||||
// so we check command code for null.
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
// TODO: find out if it can be 0x00. Do we need to check for this?
|
||||
// The message does not distinguish between 0 and null,
|
||||
// so we check command code for null.
|
||||
|
||||
byte[] p2pVersionBytes = ((RLPItem) paramsList.get(1)).getRLPData();
|
||||
this.p2pVersion = p2pVersionBytes != null ? p2pVersionBytes[0] : 0;
|
||||
byte[] p2pVersionBytes = ((RLPItem) paramsList.get(1)).getRLPData();
|
||||
this.p2pVersion = p2pVersionBytes != null ? p2pVersionBytes[0] : 0;
|
||||
|
||||
byte[] clientIdBytes = ((RLPItem) paramsList.get(2)).getRLPData();
|
||||
this.clientId = new String(clientIdBytes != null ? clientIdBytes : EMPTY_BYTE_ARRAY);
|
||||
byte[] clientIdBytes = ((RLPItem) paramsList.get(2)).getRLPData();
|
||||
this.clientId = new String(clientIdBytes != null ? clientIdBytes : EMPTY_BYTE_ARRAY);
|
||||
|
||||
RLPList capabilityList = (RLPList) paramsList.get(3);
|
||||
this.capabilities = new ArrayList<>();
|
||||
for (int i = 0; i < capabilityList.size(); i++) {
|
||||
RLPList capabilityList = (RLPList) paramsList.get(3);
|
||||
this.capabilities = new ArrayList<>();
|
||||
for (int i = 0; i < capabilityList.size(); i++) {
|
||||
|
||||
RLPElement capId = ((RLPList)capabilityList.get(i)).get(0);
|
||||
RLPElement capVersion = ((RLPList)capabilityList.get(i)).get(1);
|
||||
@ -69,66 +69,66 @@ public class HelloMessage extends P2pMessage {
|
||||
byte version = capVersion.getRLPData() == null ? 0 : capVersion.getRLPData()[0];
|
||||
|
||||
Capability cap = new Capability(name, version);
|
||||
this.capabilities.add(cap);
|
||||
}
|
||||
this.capabilities.add(cap);
|
||||
}
|
||||
|
||||
byte[] peerPortBytes = ((RLPItem) paramsList.get(4)).getRLPData();
|
||||
this.listenPort = ByteUtil.byteArrayToInt(peerPortBytes);
|
||||
byte[] peerPortBytes = ((RLPItem) paramsList.get(4)).getRLPData();
|
||||
this.listenPort = ByteUtil.byteArrayToInt(peerPortBytes);
|
||||
|
||||
byte[] peerIdBytes = ((RLPItem) paramsList.get(5)).getRLPData();
|
||||
this.peerId = Hex.toHexString(peerIdBytes);
|
||||
this.parsed = true;
|
||||
}
|
||||
byte[] peerIdBytes = ((RLPItem) paramsList.get(5)).getRLPData();
|
||||
this.peerId = Hex.toHexString(peerIdBytes);
|
||||
this.parsed = true;
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
byte[] command = RLP.encodeByte(HELLO.asByte());
|
||||
byte[] p2pVersion = RLP.encodeByte(this.p2pVersion);
|
||||
byte[] clientId = RLP.encodeString(this.clientId);
|
||||
byte[][] capabilities = new byte[this.capabilities.size()][];
|
||||
for (int i = 0; i < this.capabilities.size(); i++) {
|
||||
Capability capability = this.capabilities.get(i);
|
||||
capabilities[i] = RLP.encodeList(
|
||||
private void encode() {
|
||||
byte[] command = RLP.encodeByte(HELLO.asByte());
|
||||
byte[] p2pVersion = RLP.encodeByte(this.p2pVersion);
|
||||
byte[] clientId = RLP.encodeString(this.clientId);
|
||||
byte[][] capabilities = new byte[this.capabilities.size()][];
|
||||
for (int i = 0; i < this.capabilities.size(); i++) {
|
||||
Capability capability = this.capabilities.get(i);
|
||||
capabilities[i] = RLP.encodeList(
|
||||
RLP.encodeElement(capability.getName().getBytes()),
|
||||
RLP.encodeElement(new byte[] {capability.getVersion() }));
|
||||
}
|
||||
byte[] capabilityList = RLP.encodeList(capabilities);
|
||||
byte[] peerPort = RLP.encodeInt(this.listenPort);
|
||||
byte[] peerId = RLP.encodeElement(Hex.decode(this.peerId));
|
||||
}
|
||||
byte[] capabilityList = RLP.encodeList(capabilities);
|
||||
byte[] peerPort = RLP.encodeInt(this.listenPort);
|
||||
byte[] peerId = RLP.encodeElement(Hex.decode(this.peerId));
|
||||
|
||||
this.encoded = RLP.encodeList(command, p2pVersion, clientId,
|
||||
capabilityList, peerPort, peerId);
|
||||
}
|
||||
this.encoded = RLP.encodeList(command, p2pVersion, clientId,
|
||||
capabilityList, peerPort, peerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
|
||||
public byte getP2PVersion() {
|
||||
if (!parsed) parse();
|
||||
return p2pVersion;
|
||||
}
|
||||
public byte getP2PVersion() {
|
||||
if (!parsed) parse();
|
||||
return p2pVersion;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
if (!parsed) parse();
|
||||
return clientId;
|
||||
}
|
||||
public String getClientId() {
|
||||
if (!parsed) parse();
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public List<Capability> getCapabilities() {
|
||||
if (!parsed) parse();
|
||||
return capabilities;
|
||||
}
|
||||
public List<Capability> getCapabilities() {
|
||||
if (!parsed) parse();
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
public int getListenPort() {
|
||||
if (!parsed) parse();
|
||||
return listenPort;
|
||||
}
|
||||
public int getListenPort() {
|
||||
if (!parsed) parse();
|
||||
return listenPort;
|
||||
}
|
||||
|
||||
public String getPeerId() {
|
||||
if (!parsed) parse();
|
||||
return peerId;
|
||||
}
|
||||
public String getPeerId() {
|
||||
if (!parsed) parse();
|
||||
return peerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P2pMessageCodes getCommand(){
|
||||
@ -136,17 +136,17 @@ public class HelloMessage extends P2pMessage {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
return "[" + this.getCommand().name() + " p2pVersion="
|
||||
+ this.p2pVersion + " clientId=" + this.clientId
|
||||
+ " capabilities=[" + Joiner.on(" ").join(this.capabilities)
|
||||
+ "]" + " peerPort=" + this.listenPort + " peerId="
|
||||
+ this.peerId + "]";
|
||||
}
|
||||
public String toString() {
|
||||
if (!parsed) parse();
|
||||
return "[" + this.getCommand().name() + " p2pVersion="
|
||||
+ this.p2pVersion + " clientId=" + this.clientId
|
||||
+ " capabilities=[" + Joiner.on(" ").join(this.capabilities)
|
||||
+ "]" + " peerPort=" + this.listenPort + " peerId="
|
||||
+ this.peerId + "]";
|
||||
}
|
||||
}
|
@ -35,26 +35,26 @@ import org.springframework.stereotype.Component;
|
||||
*
|
||||
* Peers can send/receive
|
||||
* <ul>
|
||||
* <li>HELLO : Announce themselves to the network</li>
|
||||
* <li>DISCONNECT : Disconnect themselves from the network</li>
|
||||
* <li>GET_PEERS : Request a list of other knows peers</li>
|
||||
* <li>PEERS : Send a list of known peers</li>
|
||||
* <li>PING : Check if another peer is still alive</li>
|
||||
* <li>PONG : Confirm that they themselves are still alive</li>
|
||||
* <li>HELLO : Announce themselves to the network</li>
|
||||
* <li>DISCONNECT : Disconnect themselves from the network</li>
|
||||
* <li>GET_PEERS : Request a list of other knows peers</li>
|
||||
* <li>PEERS : Send a list of known peers</li>
|
||||
* <li>PING : Check if another peer is still alive</li>
|
||||
* <li>PONG : Confirm that they themselves are still alive</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Component
|
||||
@Scope("prototype")
|
||||
public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
|
||||
public final static byte VERSION = 2;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger("net");
|
||||
public final static byte VERSION = 2;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger("net");
|
||||
|
||||
private final Timer timer = new Timer("MessageTimer");
|
||||
private final Timer timer = new Timer("MessageTimer");
|
||||
|
||||
private MessageQueue msgQueue;
|
||||
private boolean tearDown = false;
|
||||
private MessageQueue msgQueue;
|
||||
private boolean tearDown = false;
|
||||
|
||||
private boolean active = false;
|
||||
private boolean peerDiscoveryMode = false;
|
||||
@ -70,10 +70,10 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
this.peerDiscoveryMode = false;
|
||||
}
|
||||
|
||||
public P2pHandler(MessageQueue msgQueue, boolean peerDiscoveryMode) {
|
||||
this.msgQueue = msgQueue;
|
||||
this.peerDiscoveryMode = peerDiscoveryMode;
|
||||
}
|
||||
public P2pHandler(MessageQueue msgQueue, boolean peerDiscoveryMode) {
|
||||
this.msgQueue = msgQueue;
|
||||
this.peerDiscoveryMode = peerDiscoveryMode;
|
||||
}
|
||||
|
||||
public void setWorldManager(WorldManager worldManager) {
|
||||
this.worldManager = worldManager;
|
||||
@ -84,13 +84,13 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
active = true;
|
||||
msgQueue.activate(ctx);
|
||||
// Send HELLO once when channel connection has been established
|
||||
msgQueue.sendMessage(HELLO_MESSAGE);
|
||||
startTimers();
|
||||
}
|
||||
// Send HELLO once when channel connection has been established
|
||||
msgQueue.sendMessage(HELLO_MESSAGE);
|
||||
startTimers();
|
||||
}
|
||||
|
||||
public void activate(){
|
||||
|
||||
@ -104,8 +104,8 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
return active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead0(final ChannelHandlerContext ctx, P2pMessage msg) throws InterruptedException {
|
||||
@Override
|
||||
public void channelRead0(final ChannelHandlerContext ctx, P2pMessage msg) throws InterruptedException {
|
||||
|
||||
if (!isActive()) return;
|
||||
|
||||
@ -114,29 +114,29 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
|
||||
worldManager.getListener().trace(String.format( "P2PHandler invoke: [%s]", msg.getCommand()));
|
||||
|
||||
switch (msg.getCommand()) {
|
||||
case HELLO:
|
||||
msgQueue.receivedMessage(msg);
|
||||
switch (msg.getCommand()) {
|
||||
case HELLO:
|
||||
msgQueue.receivedMessage(msg);
|
||||
setHandshake((HelloMessage) msg, ctx);
|
||||
sendGetPeers();
|
||||
break;
|
||||
case DISCONNECT:
|
||||
msgQueue.receivedMessage(msg);
|
||||
break;
|
||||
case PING:
|
||||
msgQueue.receivedMessage(msg);
|
||||
break;
|
||||
case DISCONNECT:
|
||||
msgQueue.receivedMessage(msg);
|
||||
break;
|
||||
case PING:
|
||||
msgQueue.receivedMessage(msg);
|
||||
ctx.writeAndFlush(PONG_MESSAGE);
|
||||
break;
|
||||
case PONG:
|
||||
msgQueue.receivedMessage(msg);
|
||||
break;
|
||||
case GET_PEERS:
|
||||
msgQueue.receivedMessage(msg);
|
||||
break;
|
||||
case PONG:
|
||||
msgQueue.receivedMessage(msg);
|
||||
break;
|
||||
case GET_PEERS:
|
||||
msgQueue.receivedMessage(msg);
|
||||
sendPeers(); // todo: implement session management for peer request
|
||||
break;
|
||||
case PEERS:
|
||||
msgQueue.receivedMessage(msg);
|
||||
processPeers(ctx, (PeersMessage) msg);
|
||||
break;
|
||||
case PEERS:
|
||||
msgQueue.receivedMessage(msg);
|
||||
processPeers(ctx, (PeersMessage) msg);
|
||||
|
||||
if (peerDiscoveryMode &&
|
||||
!handshakeHelloMessage.getCapabilities().contains(Capability.ETH)){
|
||||
@ -146,18 +146,18 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
ctx.disconnect().sync();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ctx.fireChannelRead(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
ctx.fireChannelRead(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
logger.info("channel inactive: ", ctx.toString());
|
||||
active = false;
|
||||
this.killTimers();
|
||||
}
|
||||
this.killTimers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
@ -170,7 +170,7 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
|
||||
private void processPeers(ChannelHandlerContext ctx, PeersMessage peersMessage) {
|
||||
worldManager.getPeerDiscovery().addPeers(peersMessage.getPeers());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendGetPeers(){
|
||||
msgQueue.sendMessage( StaticMessages.GET_PEERS_MESSAGE );
|
||||
@ -190,22 +190,22 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
new Peer(peer.getAddress(), peer.getPort(), peer.getPeerId());
|
||||
}
|
||||
|
||||
PeersMessage msg = new PeersMessage(peerSet);
|
||||
PeersMessage msg = new PeersMessage(peerSet);
|
||||
lastPeersSent = peers;
|
||||
msgQueue.sendMessage(msg);
|
||||
msgQueue.sendMessage(msg);
|
||||
}
|
||||
|
||||
|
||||
private void setHandshake(HelloMessage msg, ChannelHandlerContext ctx) {
|
||||
private void setHandshake(HelloMessage msg, ChannelHandlerContext ctx) {
|
||||
|
||||
this.handshakeHelloMessage = msg;
|
||||
if (msg.getP2PVersion() != P2pHandler.VERSION)
|
||||
msgQueue.sendMessage(new DisconnectMessage(ReasonCode.INCOMPATIBLE_PROTOCOL));
|
||||
else {
|
||||
List<Capability> capInCommon = new ArrayList<>();
|
||||
for (Capability capability : msg.getCapabilities()) {
|
||||
if (HELLO_MESSAGE.getCapabilities().contains(capability)) {
|
||||
if (capability.getName().equals(Capability.ETH)){
|
||||
if (msg.getP2PVersion() != P2pHandler.VERSION)
|
||||
msgQueue.sendMessage(new DisconnectMessage(ReasonCode.INCOMPATIBLE_PROTOCOL));
|
||||
else {
|
||||
List<Capability> capInCommon = new ArrayList<>();
|
||||
for (Capability capability : msg.getCapabilities()) {
|
||||
if (HELLO_MESSAGE.getCapabilities().contains(capability)) {
|
||||
if (capability.getName().equals(Capability.ETH)){
|
||||
|
||||
// Activate EthHandler for this peer
|
||||
EthHandler ethHandler =
|
||||
@ -221,21 +221,21 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
(ShhHandler)ctx.pipeline().get(Capability.SHH);
|
||||
shhHandler.activate();
|
||||
}
|
||||
capInCommon.add(capability);
|
||||
}
|
||||
}
|
||||
capInCommon.add(capability);
|
||||
}
|
||||
}
|
||||
adaptMessageIds(capInCommon);
|
||||
|
||||
InetAddress address = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();
|
||||
int port = msg.getListenPort();
|
||||
PeerInfo confirmedPeer = new PeerInfo(address, port, msg.getPeerId());
|
||||
confirmedPeer.setOnline(false);
|
||||
confirmedPeer.getCapabilities().addAll(msg.getCapabilities());
|
||||
InetAddress address = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();
|
||||
int port = msg.getListenPort();
|
||||
PeerInfo confirmedPeer = new PeerInfo(address, port, msg.getPeerId());
|
||||
confirmedPeer.setOnline(false);
|
||||
confirmedPeer.getCapabilities().addAll(msg.getCapabilities());
|
||||
|
||||
//todo calculate the Offsets
|
||||
worldManager.getPeerDiscovery().getPeers().add(confirmedPeer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* submit transaction to the network
|
||||
@ -256,7 +256,7 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
|
||||
public void adaptMessageIds(List<Capability> capabilities) {
|
||||
|
||||
Collections.sort(capabilities);
|
||||
Collections.sort(capabilities);
|
||||
byte offset = (byte) (P2pMessageCodes.USER.asByte() + 1);
|
||||
|
||||
for (Capability capability : capabilities) {
|
||||
@ -290,12 +290,12 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
|
||||
/*
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
public void run() {
|
||||
msgQueue.sendMessage(GET_PEERS_MESSAGE);
|
||||
msgQueue.sendMessage(GET_PEERS_MESSAGE);
|
||||
}
|
||||
}, 500, 25000);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public void killTimers(){
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
|
@ -5,7 +5,7 @@ import org.ethereum.net.p2p.P2pMessageCodes;
|
||||
|
||||
public abstract class P2pMessage extends Message {
|
||||
|
||||
public P2pMessage() {}
|
||||
public P2pMessage() {}
|
||||
|
||||
public P2pMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
|
@ -13,36 +13,36 @@ import java.util.Map;
|
||||
*/
|
||||
public enum P2pMessageCodes {
|
||||
|
||||
/* P2P protocol */
|
||||
/* P2P protocol */
|
||||
|
||||
/** [0x00, P2P_VERSION, CLIEND_ID, CAPS, LISTEN_PORT, CLIENT_ID] <br>
|
||||
* First packet sent over the connection, and sent once by both sides.
|
||||
* No other messages may be sent until a Hello is received. */
|
||||
HELLO(0x00),
|
||||
/** [0x00, P2P_VERSION, CLIEND_ID, CAPS, LISTEN_PORT, CLIENT_ID] <br>
|
||||
* First packet sent over the connection, and sent once by both sides.
|
||||
* No other messages may be sent until a Hello is received. */
|
||||
HELLO(0x00),
|
||||
|
||||
/** [0x01, REASON] <br>Inform the peer that a disconnection is imminent;
|
||||
* if received, a peer should disconnect immediately. When sending,
|
||||
* well-behaved hosts give their peers a fighting chance (read: wait 2 seconds)
|
||||
* to disconnect to before disconnecting themselves. */
|
||||
DISCONNECT(0x01),
|
||||
/** [0x01, REASON] <br>Inform the peer that a disconnection is imminent;
|
||||
* if received, a peer should disconnect immediately. When sending,
|
||||
* well-behaved hosts give their peers a fighting chance (read: wait 2 seconds)
|
||||
* to disconnect to before disconnecting themselves. */
|
||||
DISCONNECT(0x01),
|
||||
|
||||
/** [0x02] <br>Requests an immediate reply of Pong from the peer. */
|
||||
PING(0x02),
|
||||
/** [0x02] <br>Requests an immediate reply of Pong from the peer. */
|
||||
PING(0x02),
|
||||
|
||||
/** [0x03] <br>Reply to peer's Ping packet. */
|
||||
PONG(0x03),
|
||||
/** [0x03] <br>Reply to peer's Ping packet. */
|
||||
PONG(0x03),
|
||||
|
||||
/** [0x04] <br>Request the peer to enumerate some known peers
|
||||
* for us to connect to. This should include the peer itself. */
|
||||
GET_PEERS(0x04),
|
||||
/** [0x04] <br>Request the peer to enumerate some known peers
|
||||
* for us to connect to. This should include the peer itself. */
|
||||
GET_PEERS(0x04),
|
||||
|
||||
/** [0x05, [IP1, Port1, Id1], [IP2, Port2, Id2], ... ] <br>
|
||||
* Specifies a number of known peers. IP is a 4-byte array 'ABCD'
|
||||
* that should be interpreted as the IP address A.B.C.D.
|
||||
* Port is a 2-byte array that should be interpreted as a
|
||||
* 16-bit big-endian integer. Id is the 512-bit hash that acts
|
||||
* as the unique identifier of the node. */
|
||||
PEERS(0x05),
|
||||
/** [0x05, [IP1, Port1, Id1], [IP2, Port2, Id2], ... ] <br>
|
||||
* Specifies a number of known peers. IP is a 4-byte array 'ABCD'
|
||||
* that should be interpreted as the IP address A.B.C.D.
|
||||
* Port is a 2-byte array that should be interpreted as a
|
||||
* 16-bit big-endian integer. Id is the 512-bit hash that acts
|
||||
* as the unique identifier of the node. */
|
||||
PEERS(0x05),
|
||||
|
||||
|
||||
/**
|
||||
@ -65,7 +65,7 @@ public enum P2pMessageCodes {
|
||||
}
|
||||
|
||||
public static P2pMessageCodes fromByte(byte i) {
|
||||
P2pMessageCodes type = intToTypeMap.get(Integer.valueOf(i));
|
||||
P2pMessageCodes type = intToTypeMap.get(Integer.valueOf(i));
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -78,6 +78,6 @@ public enum P2pMessageCodes {
|
||||
}
|
||||
|
||||
public byte asByte() {
|
||||
return (byte) (cmd);
|
||||
return (byte) (cmd);
|
||||
}
|
||||
}
|
||||
|
@ -13,65 +13,65 @@ import java.util.List;
|
||||
*/
|
||||
public class Peer {
|
||||
|
||||
private InetAddress address;
|
||||
private int port;
|
||||
private String peerId;
|
||||
private InetAddress address;
|
||||
private int port;
|
||||
private String peerId;
|
||||
|
||||
private List<Capability> capabilities;
|
||||
private List<Capability> capabilities;
|
||||
|
||||
public Peer(InetAddress ip, int port, String peerId) {
|
||||
this.address = ip;
|
||||
this.port = port;
|
||||
this.peerId = peerId;
|
||||
this.capabilities = new ArrayList<>();
|
||||
}
|
||||
public Peer(InetAddress ip, int port, String peerId) {
|
||||
this.address = ip;
|
||||
this.port = port;
|
||||
this.peerId = peerId;
|
||||
this.capabilities = new ArrayList<>();
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getPeerId() {
|
||||
return peerId == null ? "" : peerId;
|
||||
}
|
||||
public String getPeerId() {
|
||||
return peerId == null ? "" : peerId;
|
||||
}
|
||||
|
||||
public List<Capability> getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
public List<Capability> getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
byte[] ip = RLP.encodeElement(this.address.getAddress());
|
||||
byte[] port = RLP.encodeInt(this.port);
|
||||
byte[] peerId = RLP.encodeElement(Hex.decode(this.peerId));
|
||||
byte[][] encodedCaps = new byte[this.capabilities.size()][];
|
||||
for (int i = 0; i < this.capabilities.size()*2; i++) {
|
||||
encodedCaps[i] = RLP.encodeString(this.capabilities.get(i).getName());
|
||||
encodedCaps[i] = RLP.encodeByte(this.capabilities.get(i).getVersion());
|
||||
}
|
||||
byte[] capabilities = RLP.encodeList(encodedCaps);
|
||||
return RLP.encodeList(ip, port, peerId, capabilities);
|
||||
}
|
||||
public byte[] getEncoded() {
|
||||
byte[] ip = RLP.encodeElement(this.address.getAddress());
|
||||
byte[] port = RLP.encodeInt(this.port);
|
||||
byte[] peerId = RLP.encodeElement(Hex.decode(this.peerId));
|
||||
byte[][] encodedCaps = new byte[this.capabilities.size()][];
|
||||
for (int i = 0; i < this.capabilities.size()*2; i++) {
|
||||
encodedCaps[i] = RLP.encodeString(this.capabilities.get(i).getName());
|
||||
encodedCaps[i] = RLP.encodeByte(this.capabilities.get(i).getVersion());
|
||||
}
|
||||
byte[] capabilities = RLP.encodeList(encodedCaps);
|
||||
return RLP.encodeList(ip, port, peerId, capabilities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[ip=" + getAddress().getHostAddress() +
|
||||
" port=" + getPort()
|
||||
+ " peerId=" + getPeerId() + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[ip=" + getAddress().getHostAddress() +
|
||||
" port=" + getPort()
|
||||
+ " peerId=" + getPeerId() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
Peer peerData = (Peer) obj;
|
||||
return peerData.peerId.equals(this.peerId)
|
||||
|| this.getAddress().equals(peerData.getAddress());
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
Peer peerData = (Peer) obj;
|
||||
return peerData.peerId.equals(this.peerId)
|
||||
|| this.getAddress().equals(peerData.getAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return -1; // override for equals function
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return -1; // override for equals function
|
||||
}
|
||||
}
|
||||
|
@ -21,81 +21,81 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class PeersMessage extends P2pMessage {
|
||||
|
||||
private boolean parsed = false;
|
||||
private boolean parsed = false;
|
||||
|
||||
private Set<Peer> peers;
|
||||
private Set<Peer> peers;
|
||||
|
||||
public PeersMessage(byte[] payload) {
|
||||
super(payload);
|
||||
}
|
||||
public PeersMessage(byte[] payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
public PeersMessage(Set<Peer> peers) {
|
||||
this.peers = peers;
|
||||
parsed = true;
|
||||
}
|
||||
public PeersMessage(Set<Peer> peers) {
|
||||
this.peers = peers;
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
private void parse() {
|
||||
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
|
||||
|
||||
peers = new LinkedHashSet<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
RLPList peerParams = (RLPList) paramsList.get(i);
|
||||
byte[] ipBytes = peerParams.get(0).getRLPData();
|
||||
byte[] portBytes = peerParams.get(1).getRLPData();
|
||||
byte[] peerIdRaw = peerParams.get(2).getRLPData();
|
||||
peers = new LinkedHashSet<>();
|
||||
for (int i = 1; i < paramsList.size(); ++i) {
|
||||
RLPList peerParams = (RLPList) paramsList.get(i);
|
||||
byte[] ipBytes = peerParams.get(0).getRLPData();
|
||||
byte[] portBytes = peerParams.get(1).getRLPData();
|
||||
byte[] peerIdRaw = peerParams.get(2).getRLPData();
|
||||
|
||||
try {
|
||||
int peerPort = ByteUtil.byteArrayToInt(portBytes);
|
||||
InetAddress address = InetAddress.getByAddress(ipBytes);
|
||||
try {
|
||||
int peerPort = ByteUtil.byteArrayToInt(portBytes);
|
||||
InetAddress address = InetAddress.getByAddress(ipBytes);
|
||||
|
||||
String peerId = peerIdRaw == null ? "" : Hex.toHexString(peerIdRaw);
|
||||
Peer peer = new Peer(address, peerPort, peerId);
|
||||
peers.add(peer);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException("Malformed ip", e);
|
||||
}
|
||||
}
|
||||
this.parsed = true;
|
||||
}
|
||||
peers.add(peer);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException("Malformed ip", e);
|
||||
}
|
||||
}
|
||||
this.parsed = true;
|
||||
}
|
||||
|
||||
private void encode() {
|
||||
byte[][] encodedByteArrays = new byte[this.peers.size() + 1][];
|
||||
encodedByteArrays[0] = RLP.encodeByte(this.getCommand().asByte());
|
||||
List<Peer> peerList = new ArrayList<>(this.peers);
|
||||
for (int i = 0; i < peerList.size(); i++) {
|
||||
encodedByteArrays[i + 1] = peerList.get(i).getEncoded();
|
||||
}
|
||||
this.encoded = RLP.encodeList(encodedByteArrays);
|
||||
}
|
||||
private void encode() {
|
||||
byte[][] encodedByteArrays = new byte[this.peers.size() + 1][];
|
||||
encodedByteArrays[0] = RLP.encodeByte(this.getCommand().asByte());
|
||||
List<Peer> peerList = new ArrayList<>(this.peers);
|
||||
for (int i = 0; i < peerList.size(); i++) {
|
||||
encodedByteArrays[i + 1] = peerList.get(i).getEncoded();
|
||||
}
|
||||
this.encoded = RLP.encodeList(encodedByteArrays);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoded == null) encode();
|
||||
return encoded;
|
||||
}
|
||||
|
||||
public Set<Peer> getPeers() {
|
||||
if (!parsed) this.parse();
|
||||
return peers;
|
||||
}
|
||||
public Set<Peer> getPeers() {
|
||||
if (!parsed) this.parse();
|
||||
return peers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P2pMessageCodes getCommand(){
|
||||
return P2pMessageCodes.PEERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!parsed) this.parse();
|
||||
public String toString() {
|
||||
if (!parsed) this.parse();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Peer peerData : peers) {
|
||||
sb.append("\n ").append(peerData);
|
||||
}
|
||||
return "[" + this.getCommand().name() + sb.toString() + "]";
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Peer peerData : peers) {
|
||||
sb.append("\n ").append(peerData);
|
||||
}
|
||||
return "[" + this.getCommand().name() + sb.toString() + "]";
|
||||
}
|
||||
}
|
@ -9,25 +9,25 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class PingMessage extends P2pMessage {
|
||||
|
||||
/** Ping message is always a the same single command payload */
|
||||
private static byte[] FIXED_PAYLOAD = Hex.decode("C102");
|
||||
/** Ping message is always a the same single command payload */
|
||||
private static byte[] FIXED_PAYLOAD = Hex.decode("C102");
|
||||
|
||||
public byte[] getEncoded() {
|
||||
return FIXED_PAYLOAD;
|
||||
}
|
||||
public byte[] getEncoded() {
|
||||
return FIXED_PAYLOAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<PongMessage> getAnswerMessage() {
|
||||
return PongMessage.class;
|
||||
}
|
||||
@Override
|
||||
public Class<PongMessage> getAnswerMessage() {
|
||||
return PongMessage.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P2pMessageCodes getCommand(){
|
||||
return P2pMessageCodes.PING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + getCommand().name() + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + getCommand().name() + "]";
|
||||
}
|
||||
}
|
@ -10,26 +10,26 @@ import org.spongycastle.util.encoders.Hex;
|
||||
*/
|
||||
public class PongMessage extends P2pMessage {
|
||||
|
||||
/** Pong message is always a the same single command payload */
|
||||
private static byte[] FIXED_PAYLOAD = Hex.decode("C103");
|
||||
/** Pong message is always a the same single command payload */
|
||||
private static byte[] FIXED_PAYLOAD = Hex.decode("C103");
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return FIXED_PAYLOAD;
|
||||
}
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return FIXED_PAYLOAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getAnswerMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P2pMessageCodes getCommand(){
|
||||
return P2pMessageCodes.PONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.getCommand().name() + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.getCommand().name() + "]";
|
||||
}
|
||||
}
|
@ -65,7 +65,7 @@ public class DiscoveryChannel {
|
||||
|
||||
public void connect(String host, int port) {
|
||||
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
worldManager.getListener().trace("Connecting to: " + host + ":" + port);
|
||||
|
||||
try {
|
||||
@ -123,10 +123,10 @@ public class DiscoveryChannel {
|
||||
logger.debug("Connection is closed");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.debug("Exception: {} ({})", e.getMessage(), e.getClass().getName());
|
||||
logger.debug("Exception: {} ({})", e.getMessage(), e.getClass().getName());
|
||||
throw new Error("Disconnnected");
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
workerGroup.shutdownGracefully();
|
||||
|
||||
if (!peerDiscoveryMode){
|
||||
// EthereumListener listener = WorldManager.getInstance().getListener();
|
||||
|
@ -22,38 +22,38 @@ import static org.ethereum.config.SystemProperties.CONFIG;
|
||||
@Component
|
||||
public class PeerDiscovery {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("peerdiscovery");
|
||||
private static final Logger logger = LoggerFactory.getLogger("peerdiscovery");
|
||||
|
||||
private final Set<PeerInfo> peers = Collections.synchronizedSet(new HashSet<PeerInfo>());
|
||||
|
||||
private PeerMonitorThread monitor;
|
||||
private ThreadFactory threadFactory;
|
||||
private ThreadPoolExecutor executorPool;
|
||||
private RejectedExecutionHandler rejectionHandler;
|
||||
private final Set<PeerInfo> peers = Collections.synchronizedSet(new HashSet<PeerInfo>());
|
||||
|
||||
private PeerMonitorThread monitor;
|
||||
private ThreadFactory threadFactory;
|
||||
private ThreadPoolExecutor executorPool;
|
||||
private RejectedExecutionHandler rejectionHandler;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext ctx;
|
||||
|
||||
|
||||
private final AtomicBoolean started = new AtomicBoolean(false);
|
||||
private final AtomicBoolean started = new AtomicBoolean(false);
|
||||
|
||||
public void start() {
|
||||
public void start() {
|
||||
|
||||
// RejectedExecutionHandler implementation
|
||||
rejectionHandler = new RejectionLogger();
|
||||
// RejectedExecutionHandler implementation
|
||||
rejectionHandler = new RejectionLogger();
|
||||
|
||||
// Get the ThreadFactory implementation to use
|
||||
threadFactory = Executors.defaultThreadFactory();
|
||||
// Get the ThreadFactory implementation to use
|
||||
threadFactory = Executors.defaultThreadFactory();
|
||||
|
||||
// creating the ThreadPoolExecutor
|
||||
executorPool = new ThreadPoolExecutor(CONFIG.peerDiscoveryWorkers(),
|
||||
// creating the ThreadPoolExecutor
|
||||
executorPool = new ThreadPoolExecutor(CONFIG.peerDiscoveryWorkers(),
|
||||
CONFIG.peerDiscoveryWorkers(), 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(
|
||||
1000), threadFactory, rejectionHandler);
|
||||
1000), threadFactory, rejectionHandler);
|
||||
|
||||
// start the monitoring thread
|
||||
monitor = new PeerMonitorThread(executorPool, 1, this);
|
||||
Thread monitorThread = new Thread(monitor);
|
||||
monitorThread.start();
|
||||
// start the monitoring thread
|
||||
monitor = new PeerMonitorThread(executorPool, 1, this);
|
||||
Thread monitorThread = new Thread(monitor);
|
||||
monitorThread.start();
|
||||
|
||||
// Initialize PeerData
|
||||
List<PeerInfo> peerDataList = parsePeerDiscoveryIpList(CONFIG.peerDiscoveryIPList());
|
||||
@ -65,23 +65,23 @@ public class PeerDiscovery {
|
||||
executorPool.execute(workerThread);
|
||||
}
|
||||
|
||||
started.set(true);
|
||||
}
|
||||
started.set(true);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
executorPool.shutdown();
|
||||
monitor.shutdown();
|
||||
started.set(false);
|
||||
}
|
||||
public void stop() {
|
||||
executorPool.shutdown();
|
||||
monitor.shutdown();
|
||||
started.set(false);
|
||||
}
|
||||
|
||||
public boolean isStarted() {
|
||||
return started.get();
|
||||
}
|
||||
|
||||
public boolean isStarted() {
|
||||
return started.get();
|
||||
}
|
||||
|
||||
public Set<PeerInfo> getPeers() {
|
||||
return peers;
|
||||
}
|
||||
|
||||
return peers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update list of known peers with new peers
|
||||
* This method checks for duplicate peer id's and addresses
|
||||
@ -90,7 +90,7 @@ public class PeerDiscovery {
|
||||
*/
|
||||
public void addPeers(Set<Peer> newPeers) {
|
||||
synchronized (peers) {
|
||||
for (final Peer newPeer : newPeers) {
|
||||
for (final Peer newPeer : newPeers) {
|
||||
PeerInfo peerInfo =
|
||||
new PeerInfo(newPeer.getAddress(), newPeer.getPort(), newPeer.getPeerId());
|
||||
if (started.get() && !peers.contains(peerInfo )){
|
||||
@ -107,13 +107,13 @@ public class PeerDiscovery {
|
||||
}
|
||||
}
|
||||
|
||||
private void startWorker(PeerInfo peerInfo) {
|
||||
private void startWorker(PeerInfo peerInfo) {
|
||||
|
||||
logger.debug("Add new peer for discovery: {}", peerInfo);
|
||||
logger.debug("Add new peer for discovery: {}", peerInfo);
|
||||
WorkerThread workerThread = ctx.getBean(WorkerThread.class);
|
||||
workerThread.init(peerInfo, executorPool);
|
||||
executorPool.execute(workerThread);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PeerInfo> parsePeerDiscoveryIpList(final String peerDiscoveryIpList){
|
||||
|
||||
|
@ -15,61 +15,61 @@ import java.util.List;
|
||||
*/
|
||||
public class PeerInfo {
|
||||
|
||||
private InetAddress address;
|
||||
private int port;
|
||||
private String peerId;
|
||||
private InetAddress address;
|
||||
private int port;
|
||||
private String peerId;
|
||||
|
||||
private List<Capability> capabilities;
|
||||
private List<Capability> capabilities;
|
||||
private HelloMessage handshakeHelloMessage;
|
||||
private StatusMessage statusMessage;
|
||||
|
||||
private transient boolean isOnline = false;
|
||||
private transient long lastCheckTime = 0;
|
||||
private transient boolean isOnline = false;
|
||||
private transient long lastCheckTime = 0;
|
||||
|
||||
public PeerInfo(InetAddress ip, int port, String peerId) {
|
||||
this.address = ip;
|
||||
this.port = port;
|
||||
this.peerId = peerId;
|
||||
this.capabilities = new ArrayList<>();
|
||||
}
|
||||
public PeerInfo(InetAddress ip, int port, String peerId) {
|
||||
this.address = ip;
|
||||
this.port = port;
|
||||
this.peerId = peerId;
|
||||
this.capabilities = new ArrayList<>();
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getPeerId() {
|
||||
return peerId == null ? "" : peerId;
|
||||
}
|
||||
public String getPeerId() {
|
||||
return peerId == null ? "" : peerId;
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
if (getCapabilities().size() < 0)
|
||||
return false;
|
||||
return isOnline;
|
||||
}
|
||||
public boolean isOnline() {
|
||||
if (getCapabilities().size() < 0)
|
||||
return false;
|
||||
return isOnline;
|
||||
}
|
||||
|
||||
public void setOnline(boolean online) {
|
||||
isOnline = online;
|
||||
}
|
||||
public void setOnline(boolean online) {
|
||||
isOnline = online;
|
||||
}
|
||||
|
||||
public long getLastCheckTime() {
|
||||
return lastCheckTime;
|
||||
}
|
||||
public long getLastCheckTime() {
|
||||
return lastCheckTime;
|
||||
}
|
||||
|
||||
public void setLastCheckTime(long lastCheckTime) {
|
||||
this.lastCheckTime = lastCheckTime;
|
||||
}
|
||||
public void setLastCheckTime(long lastCheckTime) {
|
||||
this.lastCheckTime = lastCheckTime;
|
||||
}
|
||||
|
||||
public List<Capability> getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
public List<Capability> getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@ -80,14 +80,14 @@ public class PeerInfo {
|
||||
.append(this.statusMessage == null ? "" : statusMessage + "\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
PeerInfo peerData = (PeerInfo) obj;
|
||||
return peerData.hashCode() == this.hashCode();
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
PeerInfo peerData = (PeerInfo) obj;
|
||||
return peerData.hashCode() == this.hashCode();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -7,52 +7,52 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
public class PeerMonitorThread implements Runnable {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger("peermonitor");
|
||||
private final static Logger logger = LoggerFactory.getLogger("peermonitor");
|
||||
private final PeerDiscovery peerDiscovery;
|
||||
|
||||
private ThreadPoolExecutor executor;
|
||||
private int seconds;
|
||||
private volatile boolean run = true;
|
||||
private StringBuffer toStringBuff = new StringBuffer();
|
||||
private int seconds;
|
||||
private volatile boolean run = true;
|
||||
private StringBuffer toStringBuff = new StringBuffer();
|
||||
|
||||
public PeerMonitorThread(ThreadPoolExecutor executor, int delay, PeerDiscovery peerDiscovery) {
|
||||
this.executor = executor;
|
||||
this.seconds = delay;
|
||||
public PeerMonitorThread(ThreadPoolExecutor executor, int delay, PeerDiscovery peerDiscovery) {
|
||||
this.executor = executor;
|
||||
this.seconds = delay;
|
||||
this.peerDiscovery = peerDiscovery;
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
this.run = false;
|
||||
}
|
||||
public void shutdown() {
|
||||
this.run = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (run) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
toStringBuff.setLength(0);
|
||||
toStringBuff.append("[monitor] [");
|
||||
toStringBuff.append(this.executor.getPoolSize());
|
||||
toStringBuff.append("/");
|
||||
toStringBuff.append(this.executor.getCorePoolSize());
|
||||
toStringBuff.append("] Active: ");
|
||||
toStringBuff.append(this.executor.getActiveCount());
|
||||
toStringBuff.append(", Completed: ");
|
||||
toStringBuff.append(this.executor.getCompletedTaskCount());
|
||||
toStringBuff.append(", Task: ");
|
||||
toStringBuff.append(this.executor.getTaskCount());
|
||||
toStringBuff.append(", isShutdown: ");
|
||||
toStringBuff.append(this.executor.isShutdown());
|
||||
toStringBuff.append(", isTerminated: ");
|
||||
toStringBuff.append(this.executor.isTerminated());
|
||||
toStringBuff.append(", peersDiscovered: ");
|
||||
toStringBuff.append(peerDiscovery.getPeers().size());
|
||||
logger.info(toStringBuff.toString());
|
||||
}
|
||||
try {
|
||||
Thread.sleep(seconds * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Thread interrupted", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
while (run) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
toStringBuff.setLength(0);
|
||||
toStringBuff.append("[monitor] [");
|
||||
toStringBuff.append(this.executor.getPoolSize());
|
||||
toStringBuff.append("/");
|
||||
toStringBuff.append(this.executor.getCorePoolSize());
|
||||
toStringBuff.append("] Active: ");
|
||||
toStringBuff.append(this.executor.getActiveCount());
|
||||
toStringBuff.append(", Completed: ");
|
||||
toStringBuff.append(this.executor.getCompletedTaskCount());
|
||||
toStringBuff.append(", Task: ");
|
||||
toStringBuff.append(this.executor.getTaskCount());
|
||||
toStringBuff.append(", isShutdown: ");
|
||||
toStringBuff.append(this.executor.isShutdown());
|
||||
toStringBuff.append(", isTerminated: ");
|
||||
toStringBuff.append(this.executor.isTerminated());
|
||||
toStringBuff.append(", peersDiscovered: ");
|
||||
toStringBuff.append(peerDiscovery.getPeers().size());
|
||||
logger.info(toStringBuff.toString());
|
||||
}
|
||||
try {
|
||||
Thread.sleep(seconds * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Thread interrupted", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -15,10 +15,10 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
*/
|
||||
public class RejectionLogger implements RejectedExecutionHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("wire");
|
||||
private static final Logger logger = LoggerFactory.getLogger("wire");
|
||||
|
||||
@Override
|
||||
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
|
||||
logger.warn(r.toString() + " is rejected");
|
||||
}
|
||||
@Override
|
||||
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
|
||||
logger.warn(r.toString() + " is rejected");
|
||||
}
|
||||
}
|
||||
|
@ -18,36 +18,36 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
@Scope("prototype")
|
||||
public class WorkerThread implements Runnable {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger("peerdiscovery");
|
||||
private final static Logger logger = LoggerFactory.getLogger("peerdiscovery");
|
||||
|
||||
private PeerInfo peerInfo;
|
||||
private ThreadPoolExecutor poolExecutor;
|
||||
private PeerInfo peerInfo;
|
||||
private ThreadPoolExecutor poolExecutor;
|
||||
private boolean running = true;
|
||||
|
||||
@Autowired
|
||||
ApplicationContext ctx;
|
||||
|
||||
public WorkerThread() {
|
||||
}
|
||||
public WorkerThread() {
|
||||
}
|
||||
|
||||
public void init(PeerInfo peer, ThreadPoolExecutor poolExecutor){
|
||||
this.peerInfo = peer;
|
||||
this.poolExecutor = poolExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.debug("{} start", Thread.currentThread().getName());
|
||||
@Override
|
||||
public void run() {
|
||||
logger.debug("{} start", Thread.currentThread().getName());
|
||||
processCommand();
|
||||
logger.debug("{} end", Thread.currentThread().getName());
|
||||
logger.debug("{} end", Thread.currentThread().getName());
|
||||
|
||||
sleep(1000);
|
||||
poolExecutor.execute(this);
|
||||
}
|
||||
poolExecutor.execute(this);
|
||||
}
|
||||
|
||||
private void processCommand() {
|
||||
private void processCommand() {
|
||||
|
||||
try {
|
||||
try {
|
||||
|
||||
DiscoveryChannel discoveryChannel = ctx.getBean(DiscoveryChannel.class);
|
||||
discoveryChannel.connect(peerInfo.getAddress().getHostAddress(), peerInfo.getPort());
|
||||
@ -59,18 +59,18 @@ public class WorkerThread implements Runnable {
|
||||
logger.info("Peer is online: [{}] ", peerInfo);
|
||||
|
||||
|
||||
} catch (Throwable e) {
|
||||
if (peerInfo.isOnline())
|
||||
logger.info("Peer: [{}] went offline, due to: [{}]", peerInfo
|
||||
.getAddress().getHostAddress(), e);
|
||||
peerInfo.setOnline(false);
|
||||
} finally {
|
||||
logger.info("Peer: " + peerInfo.toString() + " is "
|
||||
+ (peerInfo.isOnline() ? "online" : "offline"));
|
||||
peerInfo.setLastCheckTime(System.currentTimeMillis());
|
||||
} catch (Throwable e) {
|
||||
if (peerInfo.isOnline())
|
||||
logger.info("Peer: [{}] went offline, due to: [{}]", peerInfo
|
||||
.getAddress().getHostAddress(), e);
|
||||
peerInfo.setOnline(false);
|
||||
} finally {
|
||||
logger.info("Peer: " + peerInfo.toString() + " is "
|
||||
+ (peerInfo.isOnline() ? "online" : "offline"));
|
||||
peerInfo.setLastCheckTime(System.currentTimeMillis());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sleep(long milliseconds){
|
||||
|
||||
@ -82,8 +82,8 @@ public class WorkerThread implements Runnable {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Worker for: " + this.peerInfo.toString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Worker for: " + this.peerInfo.toString();
|
||||
}
|
||||
}
|
||||
|
@ -74,10 +74,10 @@ public class PeerServer {
|
||||
logger.debug("Connection is closed");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.debug("Exception: {} ({})", e.getMessage(), e.getClass().getName());
|
||||
logger.debug("Exception: {} ({})", e.getMessage(), e.getClass().getName());
|
||||
throw new Error("Server Disconnnected");
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
workerGroup.shutdownGracefully();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -21,12 +21,12 @@ import org.springframework.stereotype.Component;
|
||||
@Scope("prototype")
|
||||
public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
||||
|
||||
public final static byte VERSION = 1;
|
||||
public final static byte VERSION = 1;
|
||||
private MessageQueue msgQueue = null;
|
||||
|
||||
private boolean active = false;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger("net");
|
||||
private final static Logger logger = LoggerFactory.getLogger("net");
|
||||
|
||||
@Autowired
|
||||
WorldManager worldManager;
|
||||
@ -34,12 +34,12 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
||||
public ShhHandler(){
|
||||
}
|
||||
|
||||
public ShhHandler(MessageQueue msgQueue) {
|
||||
public ShhHandler(MessageQueue msgQueue) {
|
||||
this.msgQueue = msgQueue;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead0(final ChannelHandlerContext ctx, ShhMessage msg) throws InterruptedException {
|
||||
@Override
|
||||
public void channelRead0(final ChannelHandlerContext ctx, ShhMessage msg) throws InterruptedException {
|
||||
|
||||
if (!isActive()) return;
|
||||
|
||||
@ -48,7 +48,7 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
||||
|
||||
worldManager.getListener().trace(String.format( "ShhHandler invoke: [%s]", msg.getCommand()));
|
||||
|
||||
switch (msg.getCommand()) {
|
||||
switch (msg.getCommand()) {
|
||||
case STATUS:
|
||||
break;
|
||||
case MESSAGE:
|
||||
@ -60,10 +60,10 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
||||
case PACKET_COUNT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
logger.error(cause.getCause().toString());
|
||||
@ -74,7 +74,7 @@ public class ShhHandler extends SimpleChannelInboundHandler<ShhMessage> {
|
||||
@Override
|
||||
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||
active = false;
|
||||
logger.debug("handlerRemoved: ... ");
|
||||
logger.debug("handlerRemoved: ... ");
|
||||
}
|
||||
|
||||
public void activate(){
|
||||
|
@ -4,7 +4,7 @@ import org.ethereum.net.message.Message;
|
||||
|
||||
public abstract class ShhMessage extends Message {
|
||||
|
||||
public ShhMessage() {}
|
||||
public ShhMessage() {}
|
||||
|
||||
public ShhMessage(byte[] encoded) {
|
||||
super(encoded);
|
||||
|
@ -13,22 +13,22 @@ import java.util.Map;
|
||||
*/
|
||||
public enum ShhMessageCodes {
|
||||
|
||||
/* Whisper Protocol */
|
||||
/* Whisper Protocol */
|
||||
|
||||
/** [+0x00] */
|
||||
STATUS(0x00),
|
||||
STATUS(0x00),
|
||||
|
||||
/** [+0x01] */
|
||||
MESSAGE(0x01),
|
||||
/** [+0x01] */
|
||||
MESSAGE(0x01),
|
||||
|
||||
/** [+0x02] */
|
||||
ADD_FILTER(0x02),
|
||||
/** [+0x02] */
|
||||
ADD_FILTER(0x02),
|
||||
|
||||
/** [+0x03] */
|
||||
REMOVE_FILTER(0x03),
|
||||
/** [+0x03] */
|
||||
REMOVE_FILTER(0x03),
|
||||
|
||||
/** [+0x04] */
|
||||
PACKET_COUNT(0x04);
|
||||
/** [+0x04] */
|
||||
PACKET_COUNT(0x04);
|
||||
|
||||
static byte OFFSET = 0;
|
||||
private int cmd;
|
||||
@ -45,7 +45,7 @@ public enum ShhMessageCodes {
|
||||
}
|
||||
|
||||
public static ShhMessageCodes fromByte(byte i) {
|
||||
ShhMessageCodes type = intToTypeMap.get(i - OFFSET);
|
||||
ShhMessageCodes type = intToTypeMap.get(i - OFFSET);
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -62,6 +62,6 @@ public enum ShhMessageCodes {
|
||||
}
|
||||
|
||||
public byte asByte() {
|
||||
return (byte) (cmd + OFFSET);
|
||||
return (byte) (cmd + OFFSET);
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ import org.ethereum.core.Transaction;
|
||||
*/
|
||||
public class TransactionExecutor {
|
||||
|
||||
static {
|
||||
instance = new TransactionExecutor();
|
||||
}
|
||||
public static TransactionExecutor instance;
|
||||
private ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||
static {
|
||||
instance = new TransactionExecutor();
|
||||
}
|
||||
public static TransactionExecutor instance;
|
||||
private ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||
|
||||
public Future<Transaction> submitTransaction(TransactionTask task) {
|
||||
return executor.submit(task);
|
||||
}
|
||||
public Future<Transaction> submitTransaction(TransactionTask task) {
|
||||
return executor.submit(task);
|
||||
}
|
||||
}
|
||||
|
@ -18,36 +18,36 @@ import static java.lang.Thread.sleep;
|
||||
*/
|
||||
public class TransactionTask implements Callable<Transaction> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransactionTask.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransactionTask.class);
|
||||
|
||||
private Transaction tx;
|
||||
private Transaction tx;
|
||||
private WorldManager worldManager;
|
||||
|
||||
public TransactionTask(Transaction tx, WorldManager worldManager) {
|
||||
this.tx = tx;
|
||||
public TransactionTask(Transaction tx, WorldManager worldManager) {
|
||||
this.tx = tx;
|
||||
this.worldManager = worldManager;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction call() throws Exception {
|
||||
@Override
|
||||
public Transaction call() throws Exception {
|
||||
|
||||
try {
|
||||
logger.info("Call() tx: {}", tx.toString());
|
||||
try {
|
||||
logger.info("Call() tx: {}", tx.toString());
|
||||
|
||||
Wallet wallet = worldManager.getWallet();
|
||||
ChannelManager channelManager = worldManager.getChannelManager();
|
||||
|
||||
WalletTransaction walletTransaction = wallet.addByWalletTransaction(tx);
|
||||
channelManager.sendTransaction(tx);
|
||||
WalletTransaction walletTransaction = wallet.addByWalletTransaction(tx);
|
||||
channelManager.sendTransaction(tx);
|
||||
|
||||
while (walletTransaction.getApproved() < 1) {
|
||||
sleep(10);
|
||||
}
|
||||
logger.info("return approved: {}", walletTransaction.getApproved());
|
||||
} catch (Throwable th) {
|
||||
logger.warn("Exception caught: {}", th);
|
||||
while (walletTransaction.getApproved() < 1) {
|
||||
sleep(10);
|
||||
}
|
||||
logger.info("return approved: {}", walletTransaction.getApproved());
|
||||
} catch (Throwable th) {
|
||||
logger.warn("Exception caught: {}", th);
|
||||
worldManager.getWallet().removeTransaction(tx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -8,18 +8,18 @@ import org.ethereum.core.Transaction;
|
||||
*/
|
||||
public class WalletTransaction {
|
||||
|
||||
private Transaction tx;
|
||||
int approved = 0; // each time the tx got from the wire this value increased
|
||||
private Transaction tx;
|
||||
int approved = 0; // each time the tx got from the wire this value increased
|
||||
|
||||
public WalletTransaction(Transaction tx) {
|
||||
this.tx = tx;
|
||||
}
|
||||
public WalletTransaction(Transaction tx) {
|
||||
this.tx = tx;
|
||||
}
|
||||
|
||||
public void incApproved() {
|
||||
++this.approved;
|
||||
}
|
||||
public void incApproved() {
|
||||
++this.approved;
|
||||
}
|
||||
|
||||
public int getApproved() {
|
||||
return approved;
|
||||
}
|
||||
public int getApproved() {
|
||||
return approved;
|
||||
}
|
||||
}
|
||||
|
@ -30,60 +30,60 @@ public class MessageDecoder extends ByteToMessageDecoder {
|
||||
@Autowired
|
||||
WorldManager worldManager;
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
|
||||
if (!isValidEthereumPacket(in)) {
|
||||
return;
|
||||
}
|
||||
if (!isValidEthereumPacket(in)) {
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] encoded = new byte[in.readInt()];
|
||||
in.readBytes(encoded);
|
||||
|
||||
if (loggerWire.isDebugEnabled())
|
||||
loggerWire.debug("Encoded: [{}]", Hex.toHexString(encoded));
|
||||
byte[] encoded = new byte[in.readInt()];
|
||||
in.readBytes(encoded);
|
||||
|
||||
if (loggerWire.isDebugEnabled())
|
||||
loggerWire.debug("Encoded: [{}]", Hex.toHexString(encoded));
|
||||
|
||||
Message msg = MessageFactory.createMessage(encoded);
|
||||
Message msg = MessageFactory.createMessage(encoded);
|
||||
|
||||
if (loggerNet.isInfoEnabled())
|
||||
if (loggerNet.isInfoEnabled())
|
||||
loggerNet.info("From: \t{} \tRecv: \t{}", ctx.channel().remoteAddress(), msg);
|
||||
|
||||
EthereumListener listener = worldManager.getListener();
|
||||
listener.onRecvMessage(msg);
|
||||
|
||||
out.add(msg);
|
||||
out.add(msg);
|
||||
in.markReaderIndex();
|
||||
}
|
||||
|
||||
private boolean isValidEthereumPacket(ByteBuf in) {
|
||||
// Ethereum message is at least 8 bytes
|
||||
if (in.readableBytes() < 8)
|
||||
return false;
|
||||
|
||||
private boolean isValidEthereumPacket(ByteBuf in) {
|
||||
// Ethereum message is at least 8 bytes
|
||||
if (in.readableBytes() < 8)
|
||||
return false;
|
||||
|
||||
long syncToken = in.readUnsignedInt();
|
||||
long syncToken = in.readUnsignedInt();
|
||||
|
||||
if (!((syncToken >> 24 & 0xFF) == 0x22 &&
|
||||
(syncToken >> 16 & 0xFF) == 0x40 &&
|
||||
(syncToken >> 8 & 0xFF) == 0x08 &&
|
||||
(syncToken & 0xFF) == 0x91 )) {
|
||||
|
||||
// TODO: Drop frame and continue.
|
||||
// A collision can happen (although rare)
|
||||
// If this happens too often, it's an attack.
|
||||
// In that case, drop the peer.
|
||||
loggerWire.error("Abandon garbage, wrong sync token: [{}]", syncToken);
|
||||
}
|
||||
// TODO: Drop frame and continue.
|
||||
// A collision can happen (although rare)
|
||||
// If this happens too often, it's an attack.
|
||||
// In that case, drop the peer.
|
||||
loggerWire.error("Abandon garbage, wrong sync token: [{}]", syncToken);
|
||||
}
|
||||
|
||||
// Don't have the full message yet
|
||||
// Don't have the full message yet
|
||||
long msgSize = in.getInt(in.readerIndex());
|
||||
if (msgSize > in.readableBytes()) {
|
||||
loggerWire.trace("msg decode: magicBytes: [{}], readBytes: [{}] / msgSize: [{}] ",
|
||||
if (msgSize > in.readableBytes()) {
|
||||
loggerWire.trace("msg decode: magicBytes: [{}], readBytes: [{}] / msgSize: [{}] ",
|
||||
syncToken, in.readableBytes(), msgSize);
|
||||
in.resetReaderIndex();
|
||||
return false;
|
||||
}
|
||||
in.resetReaderIndex();
|
||||
return false;
|
||||
}
|
||||
|
||||
loggerWire.trace("Message fully constructed: readBytes: [{}] / msgSize: [{}]", in.readableBytes(), msgSize);
|
||||
return true;
|
||||
}
|
||||
loggerWire.trace("Message fully constructed: readBytes: [{}] / msgSize: [{}]", in.readableBytes(), msgSize);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -23,27 +23,27 @@ import org.springframework.stereotype.Component;
|
||||
@Scope("prototype")
|
||||
public class MessageEncoder extends MessageToByteEncoder<Message> {
|
||||
|
||||
private static final Logger loggerWire = LoggerFactory.getLogger("wire");
|
||||
private static final Logger loggerNet = LoggerFactory.getLogger("net");
|
||||
private static final Logger loggerWire = LoggerFactory.getLogger("wire");
|
||||
private static final Logger loggerNet = LoggerFactory.getLogger("net");
|
||||
|
||||
@Autowired
|
||||
WorldManager worldManager;
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
|
||||
|
||||
String output = String.format("To: \t%s \tSend: \t%s", ctx.channel().remoteAddress(), msg);
|
||||
worldManager.getListener().trace(output);
|
||||
|
||||
if (loggerNet.isInfoEnabled())
|
||||
if (loggerNet.isInfoEnabled())
|
||||
loggerNet.info("To: \t{} \tSend: \t{}", ctx.channel().remoteAddress(), msg);
|
||||
|
||||
byte[] encoded = msg.getEncoded();
|
||||
|
||||
if (loggerWire.isDebugEnabled())
|
||||
loggerWire.debug("Encoded: [{}]", Hex.toHexString(encoded));
|
||||
|
||||
out.capacity(encoded.length + 8);
|
||||
byte[] encoded = msg.getEncoded();
|
||||
|
||||
if (loggerWire.isDebugEnabled())
|
||||
loggerWire.debug("Encoded: [{}]", Hex.toHexString(encoded));
|
||||
|
||||
out.capacity(encoded.length + 8);
|
||||
out.writeBytes(StaticMessages.SYNC_TOKEN);
|
||||
out.writeBytes(ByteUtil.calcPacketLength(encoded));
|
||||
out.writeBytes(encoded);
|
||||
|
@ -36,8 +36,8 @@ public class SerpentCompiler {
|
||||
}
|
||||
|
||||
public static String compileFullNotion(String code) {
|
||||
SerpentParser parser = ParserUtils.getParser(SerpentLexer.class,
|
||||
SerpentParser.class, code);
|
||||
SerpentParser parser = ParserUtils.getParser(SerpentLexer.class,
|
||||
SerpentParser.class, code);
|
||||
ParseTree tree = parser.parse_init_code_block();
|
||||
|
||||
String result = new SerpentToAssemblyCompiler().visit(tree);
|
||||
@ -87,22 +87,22 @@ public class SerpentCompiler {
|
||||
|
||||
String lexa = lexaList.get(i);
|
||||
|
||||
{ // skiping the [asm asm] block
|
||||
if (lexa.equals("asm]")) {
|
||||
skiping = false;
|
||||
lexaList.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
if (lexa.equals("[asm")) {
|
||||
skiping = true;
|
||||
lexaList.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
if (skiping)
|
||||
continue;
|
||||
}
|
||||
{ // skiping the [asm asm] block
|
||||
if (lexa.equals("asm]")) {
|
||||
skiping = false;
|
||||
lexaList.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
if (lexa.equals("[asm")) {
|
||||
skiping = true;
|
||||
lexaList.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
if (skiping)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (OpCode.contains(lexa) ||
|
||||
lexa.contains("REF_") ||
|
||||
@ -124,7 +124,7 @@ public class SerpentCompiler {
|
||||
|
||||
// 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);
|
||||
|
@ -126,7 +126,7 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
||||
// check if there is 'else'
|
||||
if (ctx.block(i) != null) {
|
||||
|
||||
// body
|
||||
// body
|
||||
String elseBlockCode = visitBlock(ctx.block(i));
|
||||
|
||||
// append to general retCode
|
||||
@ -194,7 +194,7 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
||||
// msg assigned has two arrays to calc
|
||||
if (ctx.msg_func() != null) {
|
||||
|
||||
String msgCode = visitMsg_func(ctx.msg_func(), varName);
|
||||
String msgCode = visitMsg_func(ctx.msg_func(), varName);
|
||||
return msgCode;
|
||||
} else if (ctx.arr_def() != null) {
|
||||
// if it's an array the all management is different
|
||||
@ -701,7 +701,7 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
||||
|
||||
private Integer getMsgOutputArraySize(String code) {
|
||||
|
||||
String result = "0";
|
||||
String result = "0";
|
||||
Pattern pattern = Pattern.compile("<out_size ([0-9])* out_size>");
|
||||
Matcher matcher = pattern.matcher(code.trim());
|
||||
if (matcher.find()) {
|
||||
|
@ -15,105 +15,105 @@ import org.iq80.leveldb.WriteBatch;
|
||||
* Created on: 20/05/2014 10:44
|
||||
*/
|
||||
public class Cache {
|
||||
|
||||
private Map<ByteArrayWrapper, Node> nodes = new ConcurrentHashMap<>();
|
||||
private DB db;
|
||||
private boolean isDirty;
|
||||
|
||||
private Map<ByteArrayWrapper, Node> nodes = new ConcurrentHashMap<>();
|
||||
private DB db;
|
||||
private boolean isDirty;
|
||||
|
||||
public Cache(DB db) {
|
||||
this.db = db;
|
||||
}
|
||||
public Cache(DB db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the node in the cache if RLP encoded value is longer than 32 bytes
|
||||
*
|
||||
* @param o the Node which could be a pair-, multi-item Node or single Value
|
||||
* @return sha3 hash of RLP encoded node if length > 32 otherwise return node itself
|
||||
*/
|
||||
public Object put(Object o) {
|
||||
Value value = new Value(o);
|
||||
byte[] enc = value.encode();
|
||||
if (enc.length >= 32) {
|
||||
byte[] sha = HashUtil.sha3(enc);
|
||||
this.nodes.put(new ByteArrayWrapper(sha), new Node(value, true));
|
||||
this.isDirty = true;
|
||||
return sha;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Put the node in the cache if RLP encoded value is longer than 32 bytes
|
||||
*
|
||||
* @param o the Node which could be a pair-, multi-item Node or single Value
|
||||
* @return sha3 hash of RLP encoded node if length > 32 otherwise return node itself
|
||||
*/
|
||||
public Object put(Object o) {
|
||||
Value value = new Value(o);
|
||||
byte[] enc = value.encode();
|
||||
if (enc.length >= 32) {
|
||||
byte[] sha = HashUtil.sha3(enc);
|
||||
this.nodes.put(new ByteArrayWrapper(sha), new Node(value, true));
|
||||
this.isDirty = true;
|
||||
return sha;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public Value get(byte[] key) {
|
||||
ByteArrayWrapper keyObj = new ByteArrayWrapper(key);
|
||||
// First check if the key is the cache
|
||||
if (this.nodes.get(keyObj) != null) {
|
||||
return this.nodes.get(keyObj).getValue();
|
||||
}
|
||||
public Value get(byte[] key) {
|
||||
ByteArrayWrapper keyObj = new ByteArrayWrapper(key);
|
||||
// First check if the key is the cache
|
||||
if (this.nodes.get(keyObj) != null) {
|
||||
return this.nodes.get(keyObj).getValue();
|
||||
}
|
||||
|
||||
// Get the key of the database instead and cache it
|
||||
byte[] data = this.db.get(key);
|
||||
Value value = Value.fromRlpEncoded(data);
|
||||
// Create caching node
|
||||
this.nodes.put(keyObj, new Node(value, false));
|
||||
// Get the key of the database instead and cache it
|
||||
byte[] data = this.db.get(key);
|
||||
Value value = Value.fromRlpEncoded(data);
|
||||
// Create caching node
|
||||
this.nodes.put(keyObj, new Node(value, false));
|
||||
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public void delete(byte[] key) {
|
||||
ByteArrayWrapper keyObj = new ByteArrayWrapper(key);
|
||||
this.nodes.remove(keyObj);
|
||||
public void delete(byte[] key) {
|
||||
ByteArrayWrapper keyObj = new ByteArrayWrapper(key);
|
||||
this.nodes.remove(keyObj);
|
||||
|
||||
if (db == null) return;
|
||||
this.db.delete(key);
|
||||
}
|
||||
this.db.delete(key);
|
||||
}
|
||||
|
||||
public void commit() {
|
||||
public void commit() {
|
||||
|
||||
if (db == null) return;
|
||||
|
||||
// Don't try to commit if it isn't dirty
|
||||
if (!this.isDirty) {
|
||||
return;
|
||||
}
|
||||
// Don't try to commit if it isn't dirty
|
||||
if (!this.isDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
WriteBatch batch = db.createWriteBatch();
|
||||
|
||||
for (ByteArrayWrapper key : this.nodes.keySet()) {
|
||||
Node node = this.nodes.get(key);
|
||||
if (node.isDirty()) {
|
||||
for (ByteArrayWrapper key : this.nodes.keySet()) {
|
||||
Node node = this.nodes.get(key);
|
||||
if (node.isDirty()) {
|
||||
batch.put(key.getData(), node.getValue().encode());
|
||||
node.setDirty(false);
|
||||
}
|
||||
}
|
||||
node.setDirty(false);
|
||||
}
|
||||
}
|
||||
|
||||
db.write(batch);
|
||||
this.isDirty = false;
|
||||
}
|
||||
this.isDirty = false;
|
||||
}
|
||||
|
||||
public void undo() {
|
||||
Iterator<Map.Entry<ByteArrayWrapper, Node>> iter = this.nodes.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
if(iter.next().getValue().isDirty()) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
this.isDirty = false;
|
||||
}
|
||||
public void undo() {
|
||||
Iterator<Map.Entry<ByteArrayWrapper, Node>> iter = this.nodes.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
if(iter.next().getValue().isDirty()) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
this.isDirty = false;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return isDirty;
|
||||
}
|
||||
public boolean isDirty() {
|
||||
return isDirty;
|
||||
}
|
||||
|
||||
public void setDirty(boolean isDirty) {
|
||||
this.isDirty = isDirty;
|
||||
}
|
||||
public void setDirty(boolean isDirty) {
|
||||
this.isDirty = isDirty;
|
||||
}
|
||||
|
||||
public Map<ByteArrayWrapper, Node> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
public Map<ByteArrayWrapper, Node> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public DB getDb() {
|
||||
return db;
|
||||
}
|
||||
public DB getDb() {
|
||||
return db;
|
||||
}
|
||||
|
||||
public String cacheDump(){
|
||||
|
||||
|
@ -6,9 +6,9 @@ import org.ethereum.util.Value;
|
||||
/**
|
||||
* A Node in a Merkle Patricia Tree is one of the following:
|
||||
*
|
||||
* - NULL (represented as the empty string)
|
||||
* - A two-item array [ key, value ] (1 key for 2-item array)
|
||||
* - A 17-item array [ v0 ... v15, vt ] (16 keys for 17-item array)
|
||||
* - NULL (represented as the empty string)
|
||||
* - A two-item array [ key, value ] (1 key for 2-item array)
|
||||
* - A 17-item array [ v0 ... v15, vt ] (16 keys for 17-item array)
|
||||
*
|
||||
* The idea is that in the event that there is a long path of nodes
|
||||
* each with only one element, we shortcut the descent by setting up
|
||||
@ -16,12 +16,12 @@ import org.ethereum.util.Value;
|
||||
* to descend, in the compact encoding described above, and the value
|
||||
* is just the hash of the node like in the standard radix tree.
|
||||
*
|
||||
* R
|
||||
* / \
|
||||
* / \
|
||||
* N N
|
||||
* / \ / \
|
||||
* L L L L
|
||||
* R
|
||||
* / \
|
||||
* / \
|
||||
* N N
|
||||
* / \ / \
|
||||
* L L L L
|
||||
* *
|
||||
* Also, we add another conceptual change: internal nodes can no longer
|
||||
* have values, only leaves with no children of their own can; however,
|
||||
@ -32,7 +32,7 @@ import org.ethereum.util.Value;
|
||||
*
|
||||
* Where a node is referenced inside a node, what is included is:
|
||||
*
|
||||
* H(rlp.encode(x)) where H(x) = sha3(x) if len(x) >= 32 else x
|
||||
* H(rlp.encode(x)) where H(x) = sha3(x) if len(x) >= 32 else x
|
||||
*
|
||||
* Note that when updating a trie, you will need to store the key/value pair (sha3(x), x)
|
||||
* in a persistent lookup table when you create a node with length >= 32,
|
||||
@ -45,32 +45,32 @@ import org.ethereum.util.Value;
|
||||
*/
|
||||
public class Node {
|
||||
|
||||
/* RLP encoded value of the Trie-node */
|
||||
private Value value;
|
||||
private boolean dirty;
|
||||
/* RLP encoded value of the Trie-node */
|
||||
private Value value;
|
||||
private boolean dirty;
|
||||
|
||||
public Node(Value val) {
|
||||
this(val, false);
|
||||
}
|
||||
|
||||
public Node(Value val, boolean dirty) {
|
||||
this.value = val;
|
||||
this.dirty = dirty;
|
||||
}
|
||||
public Node(Value val) {
|
||||
this(val, false);
|
||||
}
|
||||
|
||||
public Node(Value val, boolean dirty) {
|
||||
this.value = val;
|
||||
this.dirty = dirty;
|
||||
}
|
||||
|
||||
public Node copy() {
|
||||
return new Node(this.value, this.dirty);
|
||||
}
|
||||
public Node copy() {
|
||||
return new Node(this.value, this.dirty);
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
public void setDirty(boolean ditry) {
|
||||
this.dirty = ditry;
|
||||
}
|
||||
|
||||
public Value getValue() {
|
||||
return value;
|
||||
}
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
public void setDirty(boolean ditry) {
|
||||
this.dirty = ditry;
|
||||
}
|
||||
|
||||
public Value getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,12 @@ public interface Trie {
|
||||
*/
|
||||
public byte[] get(byte[] key);
|
||||
|
||||
/**
|
||||
* Insert or update a value in the trie for a specified key
|
||||
*
|
||||
* @param key - any length byte array
|
||||
* @param value rlp encoded byte array of the object to store
|
||||
*/
|
||||
/**
|
||||
* Insert or update a value in the trie for a specified key
|
||||
*
|
||||
* @param key - any length byte array
|
||||
* @param value rlp encoded byte array of the object to store
|
||||
*/
|
||||
public void update(byte[] key, byte[] value);
|
||||
|
||||
/**
|
||||
|
@ -82,7 +82,7 @@ public class TrieImpl implements Trie {
|
||||
|
||||
@Override
|
||||
public void setRoot(byte[] root) {
|
||||
this.root = root;
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
@ -102,7 +102,7 @@ public class TrieImpl implements Trie {
|
||||
@Override
|
||||
public byte[] get(byte[] key) {
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Retrieving key {}", Hex.toHexString(key));
|
||||
logger.debug("Retrieving key {}", Hex.toHexString(key));
|
||||
byte[] k = binToNibbles(key);
|
||||
Value c = new Value(this.get(this.root, k));
|
||||
|
||||
@ -166,7 +166,7 @@ public class TrieImpl implements Trie {
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Private functions *
|
||||
* Private functions *
|
||||
****************************************/
|
||||
|
||||
private Object get(Object node, byte[] key) {
|
||||
@ -389,10 +389,10 @@ public class TrieImpl implements Trie {
|
||||
// Simple compare function which compares two tries based on their stateRoot
|
||||
@Override
|
||||
public boolean equals(Object trie) {
|
||||
if (this == trie) return true;
|
||||
if (trie instanceof Trie)
|
||||
return Arrays.equals(this.getRootHash(), ((Trie) trie).getRootHash());
|
||||
return false;
|
||||
if (this == trie) return true;
|
||||
if (trie instanceof Trie)
|
||||
return Arrays.equals(this.getRootHash(), ((Trie) trie).getRootHash());
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -418,7 +418,7 @@ public class TrieImpl implements Trie {
|
||||
}
|
||||
|
||||
/********************************
|
||||
* Utility functions *
|
||||
* Utility functions *
|
||||
*******************************/
|
||||
|
||||
// Created an array of empty elements of required length
|
||||
|
@ -11,80 +11,80 @@ import static org.ethereum.util.CompactEncoder.unpackToNibbles;
|
||||
* Created on: 20/05/2014 10:44
|
||||
*/
|
||||
public class TrieIterator {
|
||||
|
||||
private TrieImpl trie;
|
||||
private String key;
|
||||
private String value;
|
||||
|
||||
private TrieImpl trie;
|
||||
private String key;
|
||||
private String value;
|
||||
|
||||
private List<byte[]> shas;
|
||||
private List<String> values;
|
||||
private List<byte[]> shas;
|
||||
private List<String> values;
|
||||
|
||||
public TrieIterator(TrieImpl t) {
|
||||
this.trie = t;
|
||||
}
|
||||
public TrieIterator(TrieImpl t) {
|
||||
this.trie = t;
|
||||
}
|
||||
|
||||
// Some time in the near future this will need refactoring :-)
|
||||
// XXX Note to self, IsSlice == inline node. Str == sha3 to node
|
||||
private void workNode(Value currentNode) {
|
||||
if (currentNode.length() == 2) {
|
||||
byte[] k = unpackToNibbles(currentNode.get(0).asBytes());
|
||||
// Some time in the near future this will need refactoring :-)
|
||||
// XXX Note to self, IsSlice == inline node. Str == sha3 to node
|
||||
private void workNode(Value currentNode) {
|
||||
if (currentNode.length() == 2) {
|
||||
byte[] k = unpackToNibbles(currentNode.get(0).asBytes());
|
||||
|
||||
if (currentNode.get(1).asString() == "") {
|
||||
this.workNode(currentNode.get(1));
|
||||
} else {
|
||||
if (k[k.length-1] == 16) {
|
||||
this.values.add(currentNode.get(1).asString());
|
||||
} else {
|
||||
this.shas.add(currentNode.get(1).asBytes());
|
||||
this.getNode(currentNode.get(1).asBytes());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < currentNode.length(); i++) {
|
||||
if (i == 16 && currentNode.get(i).length() != 0) {
|
||||
this.values.add(currentNode.get(i).asString());
|
||||
} else {
|
||||
if (currentNode.get(i).asString() == "") {
|
||||
this.workNode(currentNode.get(i));
|
||||
} else {
|
||||
String val = currentNode.get(i).asString();
|
||||
if (val != "") {
|
||||
this.shas.add(currentNode.get(1).asBytes());
|
||||
this.getNode(val.getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentNode.get(1).asString() == "") {
|
||||
this.workNode(currentNode.get(1));
|
||||
} else {
|
||||
if (k[k.length-1] == 16) {
|
||||
this.values.add(currentNode.get(1).asString());
|
||||
} else {
|
||||
this.shas.add(currentNode.get(1).asBytes());
|
||||
this.getNode(currentNode.get(1).asBytes());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < currentNode.length(); i++) {
|
||||
if (i == 16 && currentNode.get(i).length() != 0) {
|
||||
this.values.add(currentNode.get(i).asString());
|
||||
} else {
|
||||
if (currentNode.get(i).asString() == "") {
|
||||
this.workNode(currentNode.get(i));
|
||||
} else {
|
||||
String val = currentNode.get(i).asString();
|
||||
if (val != "") {
|
||||
this.shas.add(currentNode.get(1).asBytes());
|
||||
this.getNode(val.getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void getNode(byte[] node) {
|
||||
Value currentNode = this.trie.getCache().get(node);
|
||||
this.workNode(currentNode);
|
||||
}
|
||||
private void getNode(byte[] node) {
|
||||
Value currentNode = this.trie.getCache().get(node);
|
||||
this.workNode(currentNode);
|
||||
}
|
||||
|
||||
private List<byte[]> collect() {
|
||||
if (this.trie.getRoot() == "") {
|
||||
return null;
|
||||
}
|
||||
this.getNode(new Value(this.trie.getRoot()).asBytes());
|
||||
return this.shas;
|
||||
}
|
||||
private List<byte[]> collect() {
|
||||
if (this.trie.getRoot() == "") {
|
||||
return null;
|
||||
}
|
||||
this.getNode(new Value(this.trie.getRoot()).asBytes());
|
||||
return this.shas;
|
||||
}
|
||||
|
||||
public int purge() {
|
||||
List<byte[]> shas = this.collect();
|
||||
|
||||
for (byte[] sha : shas) {
|
||||
this.trie.getCache().delete(sha);
|
||||
}
|
||||
return this.values.size();
|
||||
}
|
||||
public int purge() {
|
||||
List<byte[]> shas = this.collect();
|
||||
|
||||
for (byte[] sha : shas) {
|
||||
this.trie.getCache().delete(sha);
|
||||
}
|
||||
return this.values.size();
|
||||
}
|
||||
|
||||
private String getKey() {
|
||||
return "";
|
||||
}
|
||||
private String getKey() {
|
||||
return "";
|
||||
}
|
||||
|
||||
private String getValue() {
|
||||
return "";
|
||||
}
|
||||
private String getValue() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ public class ByteUtil {
|
||||
* @return numBytes byte long array.
|
||||
*/
|
||||
public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) {
|
||||
if (b == null)
|
||||
return null;
|
||||
if (b == null)
|
||||
return null;
|
||||
byte[] bytes = new byte[numBytes];
|
||||
byte[] biBytes = b.toByteArray();
|
||||
int start = (biBytes.length == numBytes + 1) ? 1 : 0;
|
||||
@ -50,7 +50,7 @@ public class ByteUtil {
|
||||
*
|
||||
* @param value - any big integer number. A <code>null</code>-value will return <code>null</code>
|
||||
* @return A byte array without a leading zero byte if present in the signed encoding.
|
||||
* BigInteger.ZERO will return an array with length 1 and byte-value 0.
|
||||
* BigInteger.ZERO will return an array with length 1 and byte-value 0.
|
||||
*/
|
||||
public static byte[] bigIntegerToBytes(BigInteger value) {
|
||||
if (value == null)
|
||||
@ -68,7 +68,7 @@ public class ByteUtil {
|
||||
|
||||
/**
|
||||
* Returns the amount of nibbles that match each other from 0 ...
|
||||
* amount will never be larger than smallest input
|
||||
* amount will never be larger than smallest input
|
||||
*
|
||||
* @param a - first input
|
||||
* @param b - second input
|
||||
@ -78,8 +78,8 @@ public class ByteUtil {
|
||||
int i = 0;
|
||||
int length = a.length < b.length ? a.length : b.length;
|
||||
while (i < length) {
|
||||
if (a[i] != b[i])
|
||||
break;
|
||||
if (a[i] != b[i])
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
@ -92,7 +92,7 @@ public class ByteUtil {
|
||||
* @return <code>byte[]</code> of length 8, representing the long value
|
||||
*/
|
||||
public static byte[] longToBytes(long val) {
|
||||
return ByteBuffer.allocate(8).putLong(val).array();
|
||||
return ByteBuffer.allocate(8).putLong(val).array();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,7 +102,7 @@ public class ByteUtil {
|
||||
*
|
||||
* @param data - byte-array to convert to a hex-string
|
||||
* @return hex representation of the data.<br>
|
||||
* Returns an empty String if the input is <code>null</code>
|
||||
* Returns an empty String if the input is <code>null</code>
|
||||
*
|
||||
* @see Hex#toHexString
|
||||
*/
|
||||
@ -125,19 +125,19 @@ public class ByteUtil {
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast hex encoded value from byte[] to int
|
||||
*
|
||||
* Limited to Integer.MAX_VALUE: 2^32-1 (4 bytes)
|
||||
*
|
||||
* @param b array contains the values
|
||||
* @return unsigned positive int value.
|
||||
*/
|
||||
public static int byteArrayToInt(byte[] b) {
|
||||
if (b == null || b.length == 0)
|
||||
return 0;
|
||||
return new BigInteger(1, b).intValue();
|
||||
}
|
||||
/**
|
||||
* Cast hex encoded value from byte[] to int
|
||||
*
|
||||
* Limited to Integer.MAX_VALUE: 2^32-1 (4 bytes)
|
||||
*
|
||||
* @param b array contains the values
|
||||
* @return unsigned positive int value.
|
||||
*/
|
||||
public static int byteArrayToInt(byte[] b) {
|
||||
if (b == null || b.length == 0)
|
||||
return 0;
|
||||
return new BigInteger(1, b).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast hex encoded value from byte[] to int
|
||||
@ -153,11 +153,11 @@ public class ByteUtil {
|
||||
return new BigInteger(1, b).longValue();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Turn nibbles to a pretty looking output string
|
||||
*
|
||||
* Example. [ 1, 2, 3, 4, 5 ] becomes '\x11\x23\x45'
|
||||
*
|
||||
* Example. [ 1, 2, 3, 4, 5 ] becomes '\x11\x23\x45'
|
||||
*
|
||||
* @param nibbles - getting byte of data [ 04 ] and turning
|
||||
* it to a '\x04' representation
|
||||
@ -202,50 +202,50 @@ public class ByteUtil {
|
||||
* @param arg - not more that 32 bits
|
||||
* @return - bytes of the value pad with complete to 32 zeroes
|
||||
*/
|
||||
public static byte[] encodeValFor32Bits(Object arg) {
|
||||
public static byte[] encodeValFor32Bits(Object arg) {
|
||||
|
||||
byte[] data;
|
||||
byte[] data;
|
||||
|
||||
// check if the string is numeric
|
||||
if (arg.toString().trim().matches("-?\\d+(\\.\\d+)?"))
|
||||
data = new BigInteger(arg.toString().trim()).toByteArray();
|
||||
// check if it's hex number
|
||||
else if (arg.toString().trim().matches("0[xX][0-9a-fA-F]+"))
|
||||
// check if the string is numeric
|
||||
if (arg.toString().trim().matches("-?\\d+(\\.\\d+)?"))
|
||||
data = new BigInteger(arg.toString().trim()).toByteArray();
|
||||
// check if it's hex number
|
||||
else if (arg.toString().trim().matches("0[xX][0-9a-fA-F]+"))
|
||||
data = new BigInteger(arg.toString().trim().substring(2), 16).toByteArray();
|
||||
else
|
||||
data = arg.toString().trim().getBytes();
|
||||
data = arg.toString().trim().getBytes();
|
||||
|
||||
|
||||
if (data.length > 32)
|
||||
throw new RuntimeException("values can't be more than 32 byte");
|
||||
|
||||
if (data.length > 32)
|
||||
throw new RuntimeException("values can't be more than 32 byte");
|
||||
|
||||
byte[] val = new byte[32];
|
||||
byte[] val = new byte[32];
|
||||
|
||||
int j = 0;
|
||||
for (int i = data.length; i > 0; --i) {
|
||||
val[31 - j] = data[i - 1];
|
||||
++j;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
int j = 0;
|
||||
for (int i = data.length; i > 0; --i) {
|
||||
val[31 - j] = data[i - 1];
|
||||
++j;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* encode the values and concatenate together
|
||||
/**
|
||||
* encode the values and concatenate together
|
||||
* @param args Object
|
||||
* @return byte[]
|
||||
*/
|
||||
public static byte[] encodeDataList(Object... args) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (Object arg : args) {
|
||||
byte[] val = encodeValFor32Bits(arg);
|
||||
try {
|
||||
baos.write(val);
|
||||
} catch (IOException e) {
|
||||
throw new Error("Happen something that should never happen ", e);
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
*/
|
||||
public static byte[] encodeDataList(Object... args) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (Object arg : args) {
|
||||
byte[] val = encodeValFor32Bits(arg);
|
||||
try {
|
||||
baos.write(val);
|
||||
} catch (IOException e) {
|
||||
throw new Error("Happen something that should never happen ", e);
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public static int firstNonZeroByte(byte[] data){
|
||||
int firstNonZero = -1;
|
||||
@ -259,29 +259,29 @@ public class ByteUtil {
|
||||
return firstNonZero;
|
||||
}
|
||||
|
||||
public static byte[] stripLeadingZeroes(byte[] data) {
|
||||
public static byte[] stripLeadingZeroes(byte[] data) {
|
||||
|
||||
if (data == null)
|
||||
return null;
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
int firstNonZero = firstNonZeroByte(data);
|
||||
int i = 0;
|
||||
for (; i < data.length; ++i) {
|
||||
if (data[i] != 0) {
|
||||
firstNonZero = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == data.length)
|
||||
return new byte[1];
|
||||
if (firstNonZero == 0)
|
||||
return data;
|
||||
int firstNonZero = firstNonZeroByte(data);
|
||||
int i = 0;
|
||||
for (; i < data.length; ++i) {
|
||||
if (data[i] != 0) {
|
||||
firstNonZero = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == data.length)
|
||||
return new byte[1];
|
||||
if (firstNonZero == 0)
|
||||
return data;
|
||||
|
||||
byte[] result = new byte[data.length - firstNonZero];
|
||||
System.arraycopy(data, firstNonZero, result, 0, data.length - firstNonZero);
|
||||
byte[] result = new byte[data.length - firstNonZero];
|
||||
System.arraycopy(data, firstNonZero, result, 0, data.length - firstNonZero);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* increment byte array as a number until max is reached
|
||||
@ -311,10 +311,10 @@ public class ByteUtil {
|
||||
* @return Byte array of given size with a copy of the <code>src</code>
|
||||
*/
|
||||
public static byte[] copyToArray(BigInteger value) {
|
||||
byte[] src = ByteUtil.bigIntegerToBytes(value);
|
||||
byte[] dest = ByteBuffer.allocate(32).array();
|
||||
System.arraycopy(src, 0, dest, dest.length - src.length, src.length);
|
||||
return dest;
|
||||
byte[] src = ByteUtil.bigIntegerToBytes(value);
|
||||
byte[] dest = ByteBuffer.allocate(32).array();
|
||||
System.arraycopy(src, 0, dest, dest.length - src.length, src.length);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,7 +48,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class CompactEncoder {
|
||||
|
||||
private final static byte TERMINATOR = 16;
|
||||
private final static byte TERMINATOR = 16;
|
||||
private final static Map<Character, Byte> hexMap = new HashMap<>();
|
||||
static {
|
||||
hexMap.put('0', (byte)0x0);
|
||||
@ -69,70 +69,70 @@ public class CompactEncoder {
|
||||
hexMap.put('f', (byte)0xf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack nibbles to binary
|
||||
*
|
||||
* @param nibbles sequence. may have a terminator
|
||||
* @return hex-encoded byte array
|
||||
*/
|
||||
public static byte[] packNibbles(byte[] nibbles) {
|
||||
int terminator = 0;
|
||||
|
||||
if (nibbles[nibbles.length-1] == TERMINATOR) {
|
||||
terminator = 1;
|
||||
nibbles = copyOf(nibbles, nibbles.length-1);
|
||||
}
|
||||
int oddlen = nibbles.length % 2;
|
||||
int flag = 2*terminator + oddlen;
|
||||
if (oddlen != 0) {
|
||||
byte[] flags = new byte[] { (byte) flag};
|
||||
nibbles = concatenate(flags, nibbles);
|
||||
} else {
|
||||
byte[] flags = new byte[] { (byte) flag, 0};
|
||||
nibbles = concatenate(flags, nibbles);
|
||||
}
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < nibbles.length; i += 2) {
|
||||
buffer.write(16*nibbles[i] + nibbles[i+1]);
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
/**
|
||||
* Pack nibbles to binary
|
||||
*
|
||||
* @param nibbles sequence. may have a terminator
|
||||
* @return hex-encoded byte array
|
||||
*/
|
||||
public static byte[] packNibbles(byte[] nibbles) {
|
||||
int terminator = 0;
|
||||
|
||||
if (nibbles[nibbles.length-1] == TERMINATOR) {
|
||||
terminator = 1;
|
||||
nibbles = copyOf(nibbles, nibbles.length-1);
|
||||
}
|
||||
int oddlen = nibbles.length % 2;
|
||||
int flag = 2*terminator + oddlen;
|
||||
if (oddlen != 0) {
|
||||
byte[] flags = new byte[] { (byte) flag};
|
||||
nibbles = concatenate(flags, nibbles);
|
||||
} else {
|
||||
byte[] flags = new byte[] { (byte) flag, 0};
|
||||
nibbles = concatenate(flags, nibbles);
|
||||
}
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < nibbles.length; i += 2) {
|
||||
buffer.write(16*nibbles[i] + nibbles[i+1]);
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack a binary string to its nibbles equivalent
|
||||
*
|
||||
* @param str of binary data
|
||||
* @return array of nibbles in byte-format
|
||||
*/
|
||||
public static byte[] unpackToNibbles(byte[] str) {
|
||||
byte[] base = binToNibbles(str);
|
||||
base = copyOf(base, base.length - 1);
|
||||
if (base[0] >= 2) {
|
||||
base = appendByte(base, TERMINATOR);
|
||||
}
|
||||
if (base[0] % 2 == 1) {
|
||||
base = copyOfRange(base, 1, base.length);
|
||||
} else {
|
||||
base = copyOfRange(base, 2, base.length);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
/**
|
||||
* Unpack a binary string to its nibbles equivalent
|
||||
*
|
||||
* @param str of binary data
|
||||
* @return array of nibbles in byte-format
|
||||
*/
|
||||
public static byte[] unpackToNibbles(byte[] str) {
|
||||
byte[] base = binToNibbles(str);
|
||||
base = copyOf(base, base.length - 1);
|
||||
if (base[0] >= 2) {
|
||||
base = appendByte(base, TERMINATOR);
|
||||
}
|
||||
if (base[0] % 2 == 1) {
|
||||
base = copyOfRange(base, 1, base.length);
|
||||
} else {
|
||||
base = copyOfRange(base, 2, base.length);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a binary array to hexadecimal format + terminator
|
||||
*
|
||||
/**
|
||||
* Transforms a binary array to hexadecimal format + terminator
|
||||
*
|
||||
* @param str byte[]
|
||||
* @return array with each individual nibble adding a terminator at the end
|
||||
*/
|
||||
public static byte[] binToNibbles(byte[] str) {
|
||||
byte[] hexEncoded = encode(str);
|
||||
ByteBuffer slice = ByteBuffer.allocate(hexEncoded.length + 1);
|
||||
for (byte b : hexEncoded) {
|
||||
slice.put(hexMap.get((char)b));
|
||||
}
|
||||
slice.put(TERMINATOR);
|
||||
return slice.array();
|
||||
}
|
||||
* @return array with each individual nibble adding a terminator at the end
|
||||
*/
|
||||
public static byte[] binToNibbles(byte[] str) {
|
||||
byte[] hexEncoded = encode(str);
|
||||
ByteBuffer slice = ByteBuffer.allocate(hexEncoded.length + 1);
|
||||
for (byte b : hexEncoded) {
|
||||
slice.put(hexMap.get((char)b));
|
||||
}
|
||||
slice.put(TERMINATOR);
|
||||
return slice.array();
|
||||
}
|
||||
|
||||
public static byte[] binToNibblesNoTerminator(byte[] str) {
|
||||
byte[] hexEncoded = encode(str);
|
||||
|
@ -7,37 +7,37 @@ import org.spongycastle.util.encoders.Hex;
|
||||
@SuppressWarnings("serial")
|
||||
public class DecodeResult implements Serializable {
|
||||
|
||||
private int pos;
|
||||
private Object decoded;
|
||||
|
||||
public DecodeResult(int pos, Object decoded) {
|
||||
this.pos = pos;
|
||||
this.decoded = decoded;
|
||||
}
|
||||
|
||||
public int getPos() {
|
||||
return pos;
|
||||
}
|
||||
public Object getDecoded() {
|
||||
return decoded;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return asString(this.decoded);
|
||||
}
|
||||
|
||||
private String asString(Object decoded) {
|
||||
if(decoded instanceof String) {
|
||||
return (String) decoded;
|
||||
} else if (decoded instanceof byte[]) {
|
||||
return Hex.toHexString((byte[]) decoded);
|
||||
} else if (decoded instanceof Object[]) {
|
||||
String result = "";
|
||||
for (Object item : (Object[]) decoded) {
|
||||
result += asString(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
throw new RuntimeException("Not a valid type. Should not occur");
|
||||
}
|
||||
private int pos;
|
||||
private Object decoded;
|
||||
|
||||
public DecodeResult(int pos, Object decoded) {
|
||||
this.pos = pos;
|
||||
this.decoded = decoded;
|
||||
}
|
||||
|
||||
public int getPos() {
|
||||
return pos;
|
||||
}
|
||||
public Object getDecoded() {
|
||||
return decoded;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return asString(this.decoded);
|
||||
}
|
||||
|
||||
private String asString(Object decoded) {
|
||||
if(decoded instanceof String) {
|
||||
return (String) decoded;
|
||||
} else if (decoded instanceof byte[]) {
|
||||
return Hex.toHexString((byte[]) decoded);
|
||||
} else if (decoded instanceof Object[]) {
|
||||
String result = "";
|
||||
for (Object item : (Object[]) decoded) {
|
||||
result += asString(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
throw new RuntimeException("Not a valid type. Should not occur");
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class LRUMap<K,V> extends ConcurrentHashMap<K,V> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final int maxEntries;
|
||||
protected final int maxEntries;
|
||||
|
||||
public LRUMap(int initialEntries, int maxEntries) {
|
||||
super(initialEntries, 0.8f, 3);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,5 +12,5 @@ import java.io.Serializable;
|
||||
*/
|
||||
public interface RLPElement extends Serializable {
|
||||
|
||||
public byte[] getRLPData();
|
||||
public byte[] getRLPData();
|
||||
}
|
||||
|
@ -8,15 +8,15 @@ package org.ethereum.util;
|
||||
*/
|
||||
public class RLPItem implements RLPElement {
|
||||
|
||||
byte[] rlpData;
|
||||
|
||||
public RLPItem(byte[] rlpData) {
|
||||
this.rlpData = rlpData;
|
||||
}
|
||||
|
||||
public byte[] getRLPData() {
|
||||
if (rlpData.length == 0)
|
||||
return null;
|
||||
return rlpData;
|
||||
}
|
||||
byte[] rlpData;
|
||||
|
||||
public RLPItem(byte[] rlpData) {
|
||||
this.rlpData = rlpData;
|
||||
}
|
||||
|
||||
public byte[] getRLPData() {
|
||||
if (rlpData.length == 0)
|
||||
return null;
|
||||
return rlpData;
|
||||
}
|
||||
}
|
||||
|
@ -19,21 +19,21 @@ public class RLPList extends ArrayList<RLPElement> implements RLPElement {
|
||||
return rlpData;
|
||||
}
|
||||
|
||||
public static void recursivePrint(RLPElement element) {
|
||||
public static void recursivePrint(RLPElement element) {
|
||||
|
||||
if (element == null)
|
||||
throw new RuntimeException("RLPElement object can't be null");
|
||||
if (element instanceof RLPList) {
|
||||
if (element == null)
|
||||
throw new RuntimeException("RLPElement object can't be null");
|
||||
if (element instanceof RLPList) {
|
||||
|
||||
RLPList rlpList = (RLPList) element;
|
||||
System.out.print("[");
|
||||
for (RLPElement singleElement : rlpList) {
|
||||
recursivePrint(singleElement);
|
||||
}
|
||||
System.out.print("]");
|
||||
} else {
|
||||
String hex = ByteUtil.toHexString(((RLPItem) element).getRLPData());
|
||||
System.out.print(hex + ", ");
|
||||
}
|
||||
}
|
||||
RLPList rlpList = (RLPList) element;
|
||||
System.out.print("[");
|
||||
for (RLPElement singleElement : rlpList) {
|
||||
recursivePrint(singleElement);
|
||||
}
|
||||
System.out.print("]");
|
||||
} else {
|
||||
String hex = ByteUtil.toHexString(((RLPItem) element).getRLPData());
|
||||
System.out.print(hex + ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ public class Utils {
|
||||
* @return String formatted as - yyyy.MM.dd HH:mm:ss
|
||||
*/
|
||||
public static String longToDateTime(long timestamp) {
|
||||
Date date = new Date(timestamp * 1000);
|
||||
DateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
|
||||
return formatter.format(date);
|
||||
Date date = new Date(timestamp * 1000);
|
||||
DateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
|
||||
return formatter.format(date);
|
||||
}
|
||||
|
||||
public static ImageIcon getImageIcon(String resource) {
|
||||
@ -67,17 +67,17 @@ public class Utils {
|
||||
* @return - decode and validated address byte[]
|
||||
*/
|
||||
public static byte[] addressStringToBytes(String hex) {
|
||||
byte[] addr = null;
|
||||
try { addr = Hex.decode(hex); }
|
||||
catch(DecoderException addressIsNotValid) { return null; }
|
||||
|
||||
if(isValidAddress(addr))
|
||||
return addr;
|
||||
return null;
|
||||
byte[] addr = null;
|
||||
try { addr = Hex.decode(hex); }
|
||||
catch(DecoderException addressIsNotValid) { return null; }
|
||||
|
||||
if(isValidAddress(addr))
|
||||
return addr;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isValidAddress(byte[] addr) {
|
||||
return addr != null && addr.length == 20;
|
||||
return addr != null && addr.length == 20;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,15 +115,15 @@ public class Utils {
|
||||
return Double.parseDouble (version.substring (0, pos - 1));
|
||||
}
|
||||
|
||||
public static StringBuffer getHashlistShort(List<byte[]> blockHashes) {
|
||||
public static StringBuffer getHashlistShort(List<byte[]> blockHashes) {
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
if (blockHashes.isEmpty()) return sb.append("[]");
|
||||
|
||||
String firstHash = Hex.toHexString(blockHashes.get(0));
|
||||
String lastHash = Hex.toHexString(blockHashes.get(blockHashes.size()-1));
|
||||
return sb.append(" ").append(firstHash).append("...").append(lastHash);
|
||||
}
|
||||
String lastHash = Hex.toHexString(blockHashes.get(blockHashes.size()-1));
|
||||
return sb.append(" ").append(firstHash).append("...").append(lastHash);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,10 +30,10 @@ public class Value {
|
||||
this.value = obj;
|
||||
}
|
||||
}
|
||||
|
||||
/* *****************
|
||||
* Convert
|
||||
* *****************/
|
||||
|
||||
/* *****************
|
||||
* Convert
|
||||
* *****************/
|
||||
|
||||
public Object asObj() {
|
||||
return value;
|
||||
@ -102,10 +102,10 @@ public class Value {
|
||||
// If this wasn't a slice you probably shouldn't be using this function
|
||||
return new Value(null);
|
||||
}
|
||||
|
||||
/* *****************
|
||||
* Utility
|
||||
* *****************/
|
||||
|
||||
/* *****************
|
||||
* Utility
|
||||
* *****************/
|
||||
|
||||
public byte[] encode() {
|
||||
return RLP.encode(value);
|
||||
@ -114,10 +114,10 @@ public class Value {
|
||||
public boolean cmp(Value o) {
|
||||
return DeepEquals.deepEquals(this, o);
|
||||
}
|
||||
|
||||
/* *****************
|
||||
* Checks
|
||||
* *****************/
|
||||
|
||||
/* *****************
|
||||
* Checks
|
||||
* *****************/
|
||||
|
||||
public boolean isList() {
|
||||
return value != null && value.getClass().isArray() && !value.getClass().getComponentType().isPrimitive();
|
||||
@ -169,12 +169,12 @@ public class Value {
|
||||
int hexChars = 0;
|
||||
byte[] data = (byte[])value;
|
||||
|
||||
for (int i = 0; i < data.length; ++i) {
|
||||
for (int i = 0; i < data.length; ++i) {
|
||||
|
||||
if ((data[i] >= 48 && data[i] <= 57)
|
||||
|| (data[i] >= 97 && data[i] <= 102))
|
||||
++hexChars;
|
||||
}
|
||||
if ((data[i] >= 48 && data[i] <= 57)
|
||||
|| (data[i] >= 97 && data[i] <= 102))
|
||||
++hexChars;
|
||||
}
|
||||
|
||||
if ((double) hexChars / (double) data.length > 0.9)
|
||||
return true;
|
||||
@ -242,7 +242,7 @@ public class Value {
|
||||
for (int i = 0; i < list.length; ++i){
|
||||
Value val = new Value(list[i]);
|
||||
if (val.isString() || val.isEmpty()){
|
||||
buffer.append("'").append(val.toString()).append("'");
|
||||
buffer.append("'").append(val.toString()).append("'");
|
||||
} else {
|
||||
buffer.append(val.toString());
|
||||
}
|
||||
|
@ -19,23 +19,23 @@ import java.nio.ByteBuffer;
|
||||
*/
|
||||
public class DataWord implements Comparable<DataWord> {
|
||||
|
||||
/* Maximum value of the DataWord */
|
||||
public static final BigInteger _2_256 = BigInteger.valueOf(2).pow(256);
|
||||
public static final BigInteger MAX_VALUE = _2_256.subtract(BigInteger.ONE);
|
||||
public static final DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack
|
||||
public static final DataWord ZERO_EMPTY_ARRAY = new DataWord(new byte[0]); // don't push it in to the stack
|
||||
/* Maximum value of the DataWord */
|
||||
public static final BigInteger _2_256 = BigInteger.valueOf(2).pow(256);
|
||||
public static final BigInteger MAX_VALUE = _2_256.subtract(BigInteger.ONE);
|
||||
public static final DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack
|
||||
public static final DataWord ZERO_EMPTY_ARRAY = new DataWord(new byte[0]); // don't push it in to the stack
|
||||
|
||||
private byte[] data = new byte[32];
|
||||
|
||||
public DataWord() {
|
||||
}
|
||||
public DataWord() {
|
||||
}
|
||||
|
||||
public DataWord(int num) {
|
||||
ByteBuffer bInt = ByteBuffer.allocate(4).putInt(num);
|
||||
ByteBuffer data = ByteBuffer.allocate(32);
|
||||
System.arraycopy(bInt.array(), 0, data.array(), 28, 4);
|
||||
this.data = data.array();
|
||||
}
|
||||
public DataWord(int num) {
|
||||
ByteBuffer bInt = ByteBuffer.allocate(4).putInt(num);
|
||||
ByteBuffer data = ByteBuffer.allocate(32);
|
||||
System.arraycopy(bInt.array(), 0, data.array(), 28, 4);
|
||||
this.data = data.array();
|
||||
}
|
||||
|
||||
public DataWord(long num) {
|
||||
ByteBuffer bLong = ByteBuffer.allocate(8).putLong(num);
|
||||
@ -44,14 +44,14 @@ public class DataWord implements Comparable<DataWord> {
|
||||
this.data = data.array();
|
||||
}
|
||||
|
||||
public DataWord(byte[] data) {
|
||||
if (data == null)
|
||||
this.data = ByteUtil.EMPTY_BYTE_ARRAY;
|
||||
else if (data.length <= 32)
|
||||
System.arraycopy(data, 0, this.data, 32 - data.length, data.length);
|
||||
else
|
||||
throw new RuntimeException("Data word can't exit 32 bytes: " + data);
|
||||
}
|
||||
public DataWord(byte[] data) {
|
||||
if (data == null)
|
||||
this.data = ByteUtil.EMPTY_BYTE_ARRAY;
|
||||
else if (data.length <= 32)
|
||||
System.arraycopy(data, 0, this.data, 32 - data.length, data.length);
|
||||
else
|
||||
throw new RuntimeException("Data word can't exit 32 bytes: " + data);
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
@ -61,7 +61,7 @@ public class DataWord implements Comparable<DataWord> {
|
||||
return ByteUtil.stripLeadingZeroes(data);
|
||||
}
|
||||
public byte[] getLast20Bytes() {
|
||||
return Arrays.copyOfRange(data, 12, data.length);
|
||||
return Arrays.copyOfRange(data, 12, data.length);
|
||||
}
|
||||
|
||||
public BigInteger value() {
|
||||
@ -77,10 +77,10 @@ public class DataWord implements Comparable<DataWord> {
|
||||
* @throws ArithmeticException - if this will not fit in an int.
|
||||
*/
|
||||
public int intValue() {
|
||||
BigDecimal tmpValue = new BigDecimal(this.value());
|
||||
if(this.bytesOccupied() > 4)
|
||||
return Integer.MAX_VALUE;
|
||||
return tmpValue.intValueExact();
|
||||
BigDecimal tmpValue = new BigDecimal(this.value());
|
||||
if(this.bytesOccupied() > 4)
|
||||
return Integer.MAX_VALUE;
|
||||
return tmpValue.intValueExact();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,7 +92,7 @@ public class DataWord implements Comparable<DataWord> {
|
||||
* @throws ArithmeticException - if this will not fit in a long.
|
||||
*/
|
||||
public long longValue() {
|
||||
BigDecimal tmpValue = new BigDecimal(this.value());
|
||||
BigDecimal tmpValue = new BigDecimal(this.value());
|
||||
return tmpValue.longValueExact();
|
||||
}
|
||||
|
||||
@ -159,29 +159,29 @@ public class DataWord implements Comparable<DataWord> {
|
||||
this.data = ByteUtil.copyToArray(MAX_VALUE.subtract(this.value()));
|
||||
}
|
||||
|
||||
// By : Holger
|
||||
// From : http://stackoverflow.com/a/24023466/459349
|
||||
// By : Holger
|
||||
// From : http://stackoverflow.com/a/24023466/459349
|
||||
public void add(DataWord word) {
|
||||
byte[] result = new byte[32];
|
||||
for (int i = 31, overflow = 0; i >= 0; i--) {
|
||||
int v = (this.data[i] & 0xff) + (word.data[i] & 0xff) + overflow;
|
||||
result[i] = (byte) v;
|
||||
overflow = v >>> 8;
|
||||
}
|
||||
this.data = result;
|
||||
byte[] result = new byte[32];
|
||||
for (int i = 31, overflow = 0; i >= 0; i--) {
|
||||
int v = (this.data[i] & 0xff) + (word.data[i] & 0xff) + overflow;
|
||||
result[i] = (byte) v;
|
||||
overflow = v >>> 8;
|
||||
}
|
||||
this.data = result;
|
||||
}
|
||||
|
||||
// old add-method with BigInteger quick hack
|
||||
public void add2(DataWord word) {
|
||||
BigInteger result = value().add(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
BigInteger result = value().add(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
// TODO: mul can be done in more efficient way
|
||||
// TODO: with shift left shift right trick
|
||||
// TODO without BigInteger quick hack
|
||||
public void mul(DataWord word) {
|
||||
BigInteger result = value().multiply(word.value());
|
||||
BigInteger result = value().multiply(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
@ -193,8 +193,8 @@ public class DataWord implements Comparable<DataWord> {
|
||||
return;
|
||||
}
|
||||
|
||||
BigInteger result = value().divide(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
BigInteger result = value().divide(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
@ -205,21 +205,21 @@ public class DataWord implements Comparable<DataWord> {
|
||||
return;
|
||||
}
|
||||
|
||||
BigInteger result = sValue().divide(word.sValue());
|
||||
BigInteger result = sValue().divide(word.sValue());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
public void sub(DataWord word) {
|
||||
BigInteger result = value().subtract(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
BigInteger result = value().subtract(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
public void exp(DataWord word) {
|
||||
BigInteger result = value().modPow(word.value(), _2_256);
|
||||
this.data = ByteUtil.copyToArray(result);
|
||||
BigInteger result = value().modPow(word.value(), _2_256);
|
||||
this.data = ByteUtil.copyToArray(result);
|
||||
}
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
@ -246,13 +246,13 @@ public class DataWord implements Comparable<DataWord> {
|
||||
}
|
||||
|
||||
public void addmod(DataWord word1, DataWord word2) {
|
||||
this.add(word1);
|
||||
BigInteger result = this.value().mod(word2.value());
|
||||
this.add(word1);
|
||||
BigInteger result = this.value().mod(word2.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
public void mulmod(DataWord word1, DataWord word2) {
|
||||
BigInteger result = value().multiply(word1.value()).mod(word2.value());
|
||||
BigInteger result = value().multiply(word1.value()).mod(word2.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
@ -261,8 +261,8 @@ public class DataWord implements Comparable<DataWord> {
|
||||
}
|
||||
|
||||
public String shortHex() {
|
||||
String hexValue = Hex.toHexString(getNoLeadZeroesData()).toUpperCase();
|
||||
return "0x" + hexValue.replaceFirst("^0+(?!$)", "");
|
||||
String hexValue = Hex.toHexString(getNoLeadZeroesData()).toUpperCase();
|
||||
return "0x" + hexValue.replaceFirst("^0+(?!$)", "");
|
||||
}
|
||||
|
||||
public DataWord clone() {
|
||||
@ -296,14 +296,14 @@ public class DataWord implements Comparable<DataWord> {
|
||||
return (int) Math.signum(result);
|
||||
}
|
||||
|
||||
public void signExtend(byte k) {
|
||||
if (0 > k || k > 31)
|
||||
throw new IndexOutOfBoundsException();
|
||||
byte mask = this.sValue().testBit((k * 8) + 7) ? (byte) 0xff : 0;
|
||||
for (int i = 31; i > k; i--) {
|
||||
this.data[31 - i] = mask;
|
||||
}
|
||||
}
|
||||
public void signExtend(byte k) {
|
||||
if (0 > k || k > 31)
|
||||
throw new IndexOutOfBoundsException();
|
||||
byte mask = this.sValue().testBit((k * 8) + 7) ? (byte) 0xff : 0;
|
||||
for (int i = 31; i > k; i--) {
|
||||
this.data[31 - i] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
public int bytesOccupied(){
|
||||
int firstNonZero = ByteUtil.firstNonZeroByte(data);
|
||||
|
@ -8,8 +8,8 @@ package org.ethereum.vm;
|
||||
*/
|
||||
public class GasCost {
|
||||
|
||||
/** Cost 1 gas */
|
||||
public static int STEP = 1;
|
||||
/** Cost 1 gas */
|
||||
public static int STEP = 1;
|
||||
/** Cost 20 gas */
|
||||
public static int BALANCE = 20;
|
||||
/** Cost 10 gas */
|
||||
@ -18,30 +18,30 @@ public class GasCost {
|
||||
public static int SHA3_WORD = 10;
|
||||
/** Cost 20 gas */
|
||||
public static int SLOAD = 20;
|
||||
/** Cost 0 gas */
|
||||
public static int STOP = 0;
|
||||
/** Cost 0 gas */
|
||||
public static int SUICIDE = 0;
|
||||
/** Cost 300 gas */
|
||||
public static int SSTORE = 300;
|
||||
/** Cost 0 gas */
|
||||
public static int STOP = 0;
|
||||
/** Cost 0 gas */
|
||||
public static int SUICIDE = 0;
|
||||
/** Cost 300 gas */
|
||||
public static int SSTORE = 300;
|
||||
/** Cost 100 gas */
|
||||
public static int RESET_SSTORE = 100;
|
||||
/** Cost 100 gas */
|
||||
public static int REFUND_SSTORE = 100;
|
||||
/** Cost 100 gas */
|
||||
public static int CREATE = 100;
|
||||
/** Cost 100 gas */
|
||||
public static int CREATE = 100;
|
||||
/** Cost 1 gas */
|
||||
public static int CREATE_DATA_BYTE = 5;
|
||||
/** Cost 20 gas */
|
||||
public static int CALL = 20;
|
||||
/** Cost 1 gas */
|
||||
public static int MEMORY = 1;
|
||||
/** Cost 5 gas */
|
||||
public static int TX_NO_ZERO_DATA = 5;
|
||||
public static int CALL = 20;
|
||||
/** Cost 1 gas */
|
||||
public static int MEMORY = 1;
|
||||
/** Cost 5 gas */
|
||||
public static int TX_NO_ZERO_DATA = 5;
|
||||
/** Cost 1 gas */
|
||||
public static int TX_ZERO_DATA = 1;
|
||||
/** Cost 500 gas */
|
||||
public static int TRANSACTION = 500;
|
||||
/** Cost 500 gas */
|
||||
public static int TRANSACTION = 500;
|
||||
/** Cost 32 gas */
|
||||
public static int LOG_GAS = 32;
|
||||
/** Cost 1 gas */
|
||||
|
@ -5,78 +5,78 @@ package org.ethereum.vm;
|
||||
* This can either be a normal CALL, STATELESS call or POST call.
|
||||
*/
|
||||
public class MessageCall {
|
||||
|
||||
public enum MsgType {
|
||||
CALL,
|
||||
STATELESS,
|
||||
POST;
|
||||
}
|
||||
|
||||
/** Type of internal call. Either CALL, STATELESS or POST */
|
||||
private MsgType type;
|
||||
|
||||
public enum MsgType {
|
||||
CALL,
|
||||
STATELESS,
|
||||
POST;
|
||||
}
|
||||
|
||||
/** Type of internal call. Either CALL, STATELESS or POST */
|
||||
private MsgType type;
|
||||
|
||||
/** gas to pay for the call, remaining gas will be refunded to the caller */
|
||||
private DataWord gas;
|
||||
private DataWord gas;
|
||||
/** address of account which code to call */
|
||||
private DataWord codeAddress;
|
||||
private DataWord codeAddress;
|
||||
/** the value that can be transfer along with the code execution */
|
||||
private DataWord endowment;
|
||||
private DataWord endowment;
|
||||
/** start of memory to be input data to the call */
|
||||
private DataWord inDataOffs;
|
||||
private DataWord inDataOffs;
|
||||
/** size of memory to be input data to the call */
|
||||
private DataWord inDataSize;
|
||||
private DataWord inDataSize;
|
||||
/** start of memory to be output of the call */
|
||||
private DataWord outDataOffs;
|
||||
private DataWord outDataOffs;
|
||||
/** size of memory to be output data to the call */
|
||||
private DataWord outDataSize;
|
||||
private DataWord outDataSize;
|
||||
|
||||
public MessageCall(MsgType type, DataWord gas, DataWord codeAddress,
|
||||
DataWord endowment, DataWord inDataOffs, DataWord inDataSize) {
|
||||
this.type = type;
|
||||
this.gas = gas;
|
||||
this.codeAddress = codeAddress;
|
||||
this.endowment = endowment;
|
||||
this.inDataOffs = inDataOffs;
|
||||
this.inDataSize = inDataSize;
|
||||
}
|
||||
|
||||
public MessageCall(MsgType type, DataWord gas, DataWord codeAddress,
|
||||
DataWord endowment, DataWord inDataOffs, DataWord inDataSize,
|
||||
DataWord outDataOffs, DataWord outDataSize) {
|
||||
this(type, gas, codeAddress, endowment, inDataOffs, inDataSize);
|
||||
this.outDataOffs = outDataOffs;
|
||||
this.outDataSize = outDataSize;
|
||||
}
|
||||
public MessageCall(MsgType type, DataWord gas, DataWord codeAddress,
|
||||
DataWord endowment, DataWord inDataOffs, DataWord inDataSize) {
|
||||
this.type = type;
|
||||
this.gas = gas;
|
||||
this.codeAddress = codeAddress;
|
||||
this.endowment = endowment;
|
||||
this.inDataOffs = inDataOffs;
|
||||
this.inDataSize = inDataSize;
|
||||
}
|
||||
|
||||
public MessageCall(MsgType type, DataWord gas, DataWord codeAddress,
|
||||
DataWord endowment, DataWord inDataOffs, DataWord inDataSize,
|
||||
DataWord outDataOffs, DataWord outDataSize) {
|
||||
this(type, gas, codeAddress, endowment, inDataOffs, inDataSize);
|
||||
this.outDataOffs = outDataOffs;
|
||||
this.outDataSize = outDataSize;
|
||||
}
|
||||
|
||||
public MsgType getType() {
|
||||
return type;
|
||||
}
|
||||
public MsgType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public DataWord getGas() {
|
||||
return gas;
|
||||
}
|
||||
public DataWord getGas() {
|
||||
return gas;
|
||||
}
|
||||
|
||||
public DataWord getCodeAddress() {
|
||||
return codeAddress;
|
||||
}
|
||||
public DataWord getCodeAddress() {
|
||||
return codeAddress;
|
||||
}
|
||||
|
||||
public DataWord getEndowment() {
|
||||
return endowment;
|
||||
}
|
||||
public DataWord getEndowment() {
|
||||
return endowment;
|
||||
}
|
||||
|
||||
public DataWord getInDataOffs() {
|
||||
return inDataOffs;
|
||||
}
|
||||
public DataWord getInDataOffs() {
|
||||
return inDataOffs;
|
||||
}
|
||||
|
||||
public DataWord getInDataSize() {
|
||||
return inDataSize;
|
||||
}
|
||||
public DataWord getInDataSize() {
|
||||
return inDataSize;
|
||||
}
|
||||
|
||||
public DataWord getOutDataOffs() {
|
||||
return outDataOffs;
|
||||
}
|
||||
public DataWord getOutDataOffs() {
|
||||
return outDataOffs;
|
||||
}
|
||||
|
||||
public DataWord getOutDataSize() {
|
||||
return outDataSize;
|
||||
}
|
||||
public DataWord getOutDataSize() {
|
||||
return outDataSize;
|
||||
}
|
||||
}
|
||||
|
@ -10,287 +10,287 @@ import java.util.Map;
|
||||
*/
|
||||
public enum OpCode {
|
||||
|
||||
/** Halts execution (0x00) */
|
||||
STOP(0x00, 0),
|
||||
/** Halts execution (0x00) */
|
||||
STOP(0x00, 0),
|
||||
|
||||
/* Arithmetic Operations */
|
||||
/* Arithmetic Operations */
|
||||
|
||||
/** (0x01) Addition operation */
|
||||
ADD(0x01, 2),
|
||||
/** (0x02) Multiplication operation */
|
||||
MUL(0x02, 2),
|
||||
/** (0x03) Subtraction operations */
|
||||
SUB(0x03, 2),
|
||||
/** (0x04) Integer division operation */
|
||||
DIV(0x04, 2),
|
||||
/** (0x05) Signed integer division operation*/
|
||||
SDIV(0x05, 2),
|
||||
/** (0x06) Modulo remainder operation */
|
||||
MOD(0x06, 2),
|
||||
/** (0x07) Signed modulo remainder operation*/
|
||||
SMOD(0x07, 2),
|
||||
/** (0x08) Addition combined with modulo
|
||||
* remainder operation */
|
||||
ADDMOD(0x08, 3),
|
||||
/** (0x09) Multiplication combined with modulo
|
||||
* remainder operation */
|
||||
MULMOD(0x09, 3),
|
||||
/** (0x0a) Exponential operation */
|
||||
EXP(0x0a, 2),
|
||||
/** (0x0b) Extend length of signed integer */
|
||||
SIGNEXTEND(0x0b, 2),
|
||||
/** (0x01) Addition operation */
|
||||
ADD(0x01, 2),
|
||||
/** (0x02) Multiplication operation */
|
||||
MUL(0x02, 2),
|
||||
/** (0x03) Subtraction operations */
|
||||
SUB(0x03, 2),
|
||||
/** (0x04) Integer division operation */
|
||||
DIV(0x04, 2),
|
||||
/** (0x05) Signed integer division operation*/
|
||||
SDIV(0x05, 2),
|
||||
/** (0x06) Modulo remainder operation */
|
||||
MOD(0x06, 2),
|
||||
/** (0x07) Signed modulo remainder operation*/
|
||||
SMOD(0x07, 2),
|
||||
/** (0x08) Addition combined with modulo
|
||||
* remainder operation */
|
||||
ADDMOD(0x08, 3),
|
||||
/** (0x09) Multiplication combined with modulo
|
||||
* remainder operation */
|
||||
MULMOD(0x09, 3),
|
||||
/** (0x0a) Exponential operation */
|
||||
EXP(0x0a, 2),
|
||||
/** (0x0b) Extend length of signed integer */
|
||||
SIGNEXTEND(0x0b, 2),
|
||||
|
||||
/* Bitwise Logic & Comparison Operations */
|
||||
/* Bitwise Logic & Comparison Operations */
|
||||
|
||||
/** (0x10) Less-than comparison */
|
||||
LT(0X10, 2),
|
||||
/** (0x11) Greater-than comparison */
|
||||
/** (0x10) Less-than comparison */
|
||||
LT(0X10, 2),
|
||||
/** (0x11) Greater-than comparison */
|
||||
GT(0X11, 2),
|
||||
/** (0x12) Signed less-than comparison */
|
||||
/** (0x12) Signed less-than comparison */
|
||||
SLT(0X12, 2),
|
||||
/** (0x13) Signed greater-than comparison */
|
||||
/** (0x13) Signed greater-than comparison */
|
||||
SGT(0X13, 2),
|
||||
/** (0x14) Equality comparison */
|
||||
EQ(0X14, 2),
|
||||
/** (0x15) Negation operation */
|
||||
ISZERO(0x15, 1),
|
||||
/** (0x16) Bitwise AND operation */
|
||||
AND(0x16, 2),
|
||||
/** (0x17) Bitwise OR operation */
|
||||
OR(0x17, 2),
|
||||
/** (0x18) Bitwise XOR operation */
|
||||
XOR(0x18, 2),
|
||||
/** (0x19) Bitwise NOT operationr */
|
||||
NOT(0x19, 1),
|
||||
/** (0x1a) Retrieve single byte from word */
|
||||
/** (0x14) Equality comparison */
|
||||
EQ(0X14, 2),
|
||||
/** (0x15) Negation operation */
|
||||
ISZERO(0x15, 1),
|
||||
/** (0x16) Bitwise AND operation */
|
||||
AND(0x16, 2),
|
||||
/** (0x17) Bitwise OR operation */
|
||||
OR(0x17, 2),
|
||||
/** (0x18) Bitwise XOR operation */
|
||||
XOR(0x18, 2),
|
||||
/** (0x19) Bitwise NOT operationr */
|
||||
NOT(0x19, 1),
|
||||
/** (0x1a) Retrieve single byte from word */
|
||||
BYTE(0x1a, 2),
|
||||
|
||||
/* Cryptographic Operations */
|
||||
/* Cryptographic Operations */
|
||||
|
||||
/** (0x20) Compute SHA3-256 hash */
|
||||
SHA3(0x20, 2),
|
||||
/** (0x20) Compute SHA3-256 hash */
|
||||
SHA3(0x20, 2),
|
||||
|
||||
/* Environmental Information */
|
||||
/* Environmental Information */
|
||||
|
||||
/** (0x30) Get address of currently
|
||||
* executing account */
|
||||
ADDRESS(0x30, 0),
|
||||
/** (0x31) Get balance of the given account */
|
||||
BALANCE(0x31, 1),
|
||||
/** (0x32) Get execution origination address*/
|
||||
ORIGIN(0x32, 0),
|
||||
/** (0x33) Get caller address */
|
||||
CALLER(0x33, 0),
|
||||
/** (0x34) Get deposited value by the
|
||||
* instruction/transaction responsible
|
||||
* for this execution */
|
||||
CALLVALUE(0x34, 0),
|
||||
/** (0x35) Get input data of current
|
||||
* environment */
|
||||
CALLDATALOAD(0x35, 1),
|
||||
/** (0x36) Get size of input data in current
|
||||
* environment */
|
||||
CALLDATASIZE(0x36, 0),
|
||||
/** (0x37) Copy input data in current
|
||||
* environment to memory */
|
||||
CALLDATACOPY(0x37, 3),
|
||||
/** (0x38) Get size of code running in
|
||||
* current environment */
|
||||
CODESIZE(0x38, 0),
|
||||
/** (0x39) Copy code running in current
|
||||
* environment to memory */
|
||||
CODECOPY(0x39, 3), // [len code_start mem_start CODECOPY]
|
||||
/** (0x3a) Get price of gas in current
|
||||
* environment */
|
||||
GASPRICE(0x3a, 0),
|
||||
/** (0x3b) Get size of code running in
|
||||
* current environment with given offset */
|
||||
EXTCODESIZE(0x3b, 1),
|
||||
/** (0x3c) Copy code running in current
|
||||
* environment to memory with given offset */
|
||||
EXTCODECOPY(0x3c, 4),
|
||||
/** (0x30) Get address of currently
|
||||
* executing account */
|
||||
ADDRESS(0x30, 0),
|
||||
/** (0x31) Get balance of the given account */
|
||||
BALANCE(0x31, 1),
|
||||
/** (0x32) Get execution origination address*/
|
||||
ORIGIN(0x32, 0),
|
||||
/** (0x33) Get caller address */
|
||||
CALLER(0x33, 0),
|
||||
/** (0x34) Get deposited value by the
|
||||
* instruction/transaction responsible
|
||||
* for this execution */
|
||||
CALLVALUE(0x34, 0),
|
||||
/** (0x35) Get input data of current
|
||||
* environment */
|
||||
CALLDATALOAD(0x35, 1),
|
||||
/** (0x36) Get size of input data in current
|
||||
* environment */
|
||||
CALLDATASIZE(0x36, 0),
|
||||
/** (0x37) Copy input data in current
|
||||
* environment to memory */
|
||||
CALLDATACOPY(0x37, 3),
|
||||
/** (0x38) Get size of code running in
|
||||
* current environment */
|
||||
CODESIZE(0x38, 0),
|
||||
/** (0x39) Copy code running in current
|
||||
* environment to memory */
|
||||
CODECOPY(0x39, 3), // [len code_start mem_start CODECOPY]
|
||||
/** (0x3a) Get price of gas in current
|
||||
* environment */
|
||||
GASPRICE(0x3a, 0),
|
||||
/** (0x3b) Get size of code running in
|
||||
* current environment with given offset */
|
||||
EXTCODESIZE(0x3b, 1),
|
||||
/** (0x3c) Copy code running in current
|
||||
* environment to memory with given offset */
|
||||
EXTCODECOPY(0x3c, 4),
|
||||
|
||||
/* Block Information */
|
||||
/* Block Information */
|
||||
|
||||
/** (0x40) Get hash of most recent
|
||||
* complete block */
|
||||
PREVHASH(0x40, 0),
|
||||
/** (0x41) Get the block’s coinbase address */
|
||||
COINBASE(0x41, 0),
|
||||
/** (x042) Get the block’s timestamp */
|
||||
TIMESTAMP(0x42, 0),
|
||||
/** (0x43) Get the block’s number */
|
||||
NUMBER(0x43, 0),
|
||||
/** (0x44) Get the block’s difficulty */
|
||||
DIFFICULTY(0x44, 0),
|
||||
/** (0x45) Get the block’s gas limit */
|
||||
GASLIMIT(0x45, 0),
|
||||
/** (0x40) Get hash of most recent
|
||||
* complete block */
|
||||
PREVHASH(0x40, 0),
|
||||
/** (0x41) Get the block’s coinbase address */
|
||||
COINBASE(0x41, 0),
|
||||
/** (x042) Get the block’s timestamp */
|
||||
TIMESTAMP(0x42, 0),
|
||||
/** (0x43) Get the block’s number */
|
||||
NUMBER(0x43, 0),
|
||||
/** (0x44) Get the block’s difficulty */
|
||||
DIFFICULTY(0x44, 0),
|
||||
/** (0x45) Get the block’s gas limit */
|
||||
GASLIMIT(0x45, 0),
|
||||
|
||||
/* Memory, Storage and Flow Operations */
|
||||
/* Memory, Storage and Flow Operations */
|
||||
|
||||
/** (0x50) Remove item from stack */
|
||||
POP(0x50, 1),
|
||||
/** (0x51) Load word from memory */
|
||||
MLOAD(0x51, 1),
|
||||
/** (0x52) Save word to memory */
|
||||
MSTORE(0x52, 2),
|
||||
/** (0x53) Save byte to memory */
|
||||
MSTORE8(0x53, 2),
|
||||
/** (0x54) Load word from storage */
|
||||
SLOAD(0x54, 1),
|
||||
/** (0x55) Save word to storage */
|
||||
SSTORE(0x55, 2),
|
||||
/** (0x56) Alter the program counter */
|
||||
JUMP(0x56, 1),
|
||||
/** (0x57) Conditionally alter the program
|
||||
* counter */
|
||||
JUMPI(0x57, 2),
|
||||
/** (0x58) Get the program counter */
|
||||
PC(0x58, 0),
|
||||
/** (0x59) Get the size of active memory */
|
||||
MSIZE(0x59, 0),
|
||||
/** (0x5a) Get the amount of available gas */
|
||||
GAS(0x5a, 0),
|
||||
/** (0x5b) */
|
||||
JUMPDEST(0x5b, 0),
|
||||
/** (0x50) Remove item from stack */
|
||||
POP(0x50, 1),
|
||||
/** (0x51) Load word from memory */
|
||||
MLOAD(0x51, 1),
|
||||
/** (0x52) Save word to memory */
|
||||
MSTORE(0x52, 2),
|
||||
/** (0x53) Save byte to memory */
|
||||
MSTORE8(0x53, 2),
|
||||
/** (0x54) Load word from storage */
|
||||
SLOAD(0x54, 1),
|
||||
/** (0x55) Save word to storage */
|
||||
SSTORE(0x55, 2),
|
||||
/** (0x56) Alter the program counter */
|
||||
JUMP(0x56, 1),
|
||||
/** (0x57) Conditionally alter the program
|
||||
* counter */
|
||||
JUMPI(0x57, 2),
|
||||
/** (0x58) Get the program counter */
|
||||
PC(0x58, 0),
|
||||
/** (0x59) Get the size of active memory */
|
||||
MSIZE(0x59, 0),
|
||||
/** (0x5a) Get the amount of available gas */
|
||||
GAS(0x5a, 0),
|
||||
/** (0x5b) */
|
||||
JUMPDEST(0x5b, 0),
|
||||
|
||||
/* Push Operations */
|
||||
/* Push Operations */
|
||||
|
||||
/** (0x60) Place 1-byte item on stack */
|
||||
PUSH1(0x60, 0),
|
||||
/** (0x61) Place 2-byte item on stack */
|
||||
PUSH2(0x61, 0),
|
||||
/** (0x62) Place 3-byte item on stack */
|
||||
PUSH3(0x62, 0),
|
||||
/** (0x63) Place 4-byte item on stack */
|
||||
PUSH4(0x63, 0),
|
||||
/** (0x64) Place 5-byte item on stack */
|
||||
PUSH5(0x64, 0),
|
||||
/** (0x65) Place 6-byte item on stack */
|
||||
PUSH6(0x65, 0),
|
||||
/** (0x66) Place 7-byte item on stack */
|
||||
PUSH7(0x66, 0),
|
||||
/** (0x67) Place 8-byte item on stack */
|
||||
PUSH8(0x67, 0),
|
||||
/** (0x68) Place 9-byte item on stack */
|
||||
PUSH9(0x68, 0),
|
||||
/** (0x69) Place 10-byte item on stack */
|
||||
PUSH10(0x69, 0),
|
||||
/** (0x6a) Place 11-byte item on stack */
|
||||
PUSH11(0x6a, 0),
|
||||
/** (0x6b) Place 12-byte item on stack */
|
||||
PUSH12(0x6b, 0),
|
||||
/** (0x6c) Place 13-byte item on stack */
|
||||
PUSH13(0x6c, 0),
|
||||
/** (0x6d) Place 14-byte item on stack */
|
||||
PUSH14(0x6d, 0),
|
||||
/** (0x6e) Place 15-byte item on stack */
|
||||
PUSH15(0x6e, 0),
|
||||
/** (0x6f) Place 16-byte item on stack */
|
||||
PUSH16(0x6f, 0),
|
||||
/** (0x70) Place 17-byte item on stack */
|
||||
PUSH17(0x70, 0),
|
||||
/** (0x71) Place 18-byte item on stack */
|
||||
PUSH18(0x71, 0),
|
||||
/** (0x72) Place 19-byte item on stack */
|
||||
PUSH19(0x72, 0),
|
||||
/** (0x73) Place 20-byte item on stack */
|
||||
PUSH20(0x73, 0),
|
||||
/** (0x74) Place 21-byte item on stack */
|
||||
PUSH21(0x74, 0),
|
||||
/** (0x75) Place 22-byte item on stack */
|
||||
PUSH22(0x75, 0),
|
||||
/** (0x76) Place 23-byte item on stack */
|
||||
PUSH23(0x76, 0),
|
||||
/** (0x77) Place 24-byte item on stack */
|
||||
PUSH24(0x77, 0),
|
||||
/** (0x78) Place 25-byte item on stack */
|
||||
PUSH25(0x78, 0),
|
||||
/** (0x79) Place 26-byte item on stack */
|
||||
PUSH26(0x79, 0),
|
||||
/** (0x7a) Place 27-byte item on stack */
|
||||
PUSH27(0x7a, 0),
|
||||
/** (0x7b) Place 28-byte item on stack */
|
||||
PUSH28(0x7b, 0),
|
||||
/** (0x7c) Place 29-byte item on stack */
|
||||
PUSH29(0x7c, 0),
|
||||
/** (0x7d) Place 30-byte item on stack */
|
||||
PUSH30(0x7d, 0),
|
||||
/** (0x7e) Place 31-byte item on stack */
|
||||
PUSH31(0x7e, 0),
|
||||
/** (0x7f) Place 32-byte (full word)
|
||||
* item on stack */
|
||||
PUSH32(0x7f, 0),
|
||||
/** (0x60) Place 1-byte item on stack */
|
||||
PUSH1(0x60, 0),
|
||||
/** (0x61) Place 2-byte item on stack */
|
||||
PUSH2(0x61, 0),
|
||||
/** (0x62) Place 3-byte item on stack */
|
||||
PUSH3(0x62, 0),
|
||||
/** (0x63) Place 4-byte item on stack */
|
||||
PUSH4(0x63, 0),
|
||||
/** (0x64) Place 5-byte item on stack */
|
||||
PUSH5(0x64, 0),
|
||||
/** (0x65) Place 6-byte item on stack */
|
||||
PUSH6(0x65, 0),
|
||||
/** (0x66) Place 7-byte item on stack */
|
||||
PUSH7(0x66, 0),
|
||||
/** (0x67) Place 8-byte item on stack */
|
||||
PUSH8(0x67, 0),
|
||||
/** (0x68) Place 9-byte item on stack */
|
||||
PUSH9(0x68, 0),
|
||||
/** (0x69) Place 10-byte item on stack */
|
||||
PUSH10(0x69, 0),
|
||||
/** (0x6a) Place 11-byte item on stack */
|
||||
PUSH11(0x6a, 0),
|
||||
/** (0x6b) Place 12-byte item on stack */
|
||||
PUSH12(0x6b, 0),
|
||||
/** (0x6c) Place 13-byte item on stack */
|
||||
PUSH13(0x6c, 0),
|
||||
/** (0x6d) Place 14-byte item on stack */
|
||||
PUSH14(0x6d, 0),
|
||||
/** (0x6e) Place 15-byte item on stack */
|
||||
PUSH15(0x6e, 0),
|
||||
/** (0x6f) Place 16-byte item on stack */
|
||||
PUSH16(0x6f, 0),
|
||||
/** (0x70) Place 17-byte item on stack */
|
||||
PUSH17(0x70, 0),
|
||||
/** (0x71) Place 18-byte item on stack */
|
||||
PUSH18(0x71, 0),
|
||||
/** (0x72) Place 19-byte item on stack */
|
||||
PUSH19(0x72, 0),
|
||||
/** (0x73) Place 20-byte item on stack */
|
||||
PUSH20(0x73, 0),
|
||||
/** (0x74) Place 21-byte item on stack */
|
||||
PUSH21(0x74, 0),
|
||||
/** (0x75) Place 22-byte item on stack */
|
||||
PUSH22(0x75, 0),
|
||||
/** (0x76) Place 23-byte item on stack */
|
||||
PUSH23(0x76, 0),
|
||||
/** (0x77) Place 24-byte item on stack */
|
||||
PUSH24(0x77, 0),
|
||||
/** (0x78) Place 25-byte item on stack */
|
||||
PUSH25(0x78, 0),
|
||||
/** (0x79) Place 26-byte item on stack */
|
||||
PUSH26(0x79, 0),
|
||||
/** (0x7a) Place 27-byte item on stack */
|
||||
PUSH27(0x7a, 0),
|
||||
/** (0x7b) Place 28-byte item on stack */
|
||||
PUSH28(0x7b, 0),
|
||||
/** (0x7c) Place 29-byte item on stack */
|
||||
PUSH29(0x7c, 0),
|
||||
/** (0x7d) Place 30-byte item on stack */
|
||||
PUSH30(0x7d, 0),
|
||||
/** (0x7e) Place 31-byte item on stack */
|
||||
PUSH31(0x7e, 0),
|
||||
/** (0x7f) Place 32-byte (full word)
|
||||
* item on stack */
|
||||
PUSH32(0x7f, 0),
|
||||
|
||||
/* Duplicate Nth item from the stack */
|
||||
/* Duplicate Nth item from the stack */
|
||||
|
||||
/** (0x80) Duplicate 1st item on stack */
|
||||
DUP1(0x80, 1),
|
||||
/** (0x81) Duplicate 2nd item on stack */
|
||||
DUP2(0x81, 2),
|
||||
/** (0x82) Duplicate 3rd item on stack */
|
||||
DUP3(0x82, 3),
|
||||
/** (0x83) Duplicate 4th item on stack */
|
||||
DUP4(0x83, 4),
|
||||
/** (0x84) Duplicate 5th item on stack */
|
||||
DUP5(0x84, 5),
|
||||
/** (0x85) Duplicate 6th item on stack */
|
||||
DUP6(0x85, 6),
|
||||
/** (0x86) Duplicate 7th item on stack */
|
||||
DUP7(0x86, 7),
|
||||
/** (0x87) Duplicate 8th item on stack */
|
||||
DUP8(0x87, 8),
|
||||
/** (0x88) Duplicate 9th item on stack */
|
||||
DUP9(0x88, 9),
|
||||
/** (0x89) Duplicate 10th item on stack */
|
||||
DUP10(0x89, 10),
|
||||
/** (0x8a) Duplicate 11th item on stack */
|
||||
DUP11(0x8a, 11),
|
||||
/** (0x8b) Duplicate 12th item on stack */
|
||||
DUP12(0x8b, 12),
|
||||
/** (0x8c) Duplicate 13th item on stack */
|
||||
DUP13(0x8c, 13),
|
||||
/** (0x8d) Duplicate 14th item on stack */
|
||||
DUP14(0x8d, 14),
|
||||
/** (0x8e) Duplicate 15th item on stack */
|
||||
DUP15(0x8e, 15),
|
||||
/** (0x8f) Duplicate 16th item on stack */
|
||||
DUP16(0x8f, 16),
|
||||
/** (0x80) Duplicate 1st item on stack */
|
||||
DUP1(0x80, 1),
|
||||
/** (0x81) Duplicate 2nd item on stack */
|
||||
DUP2(0x81, 2),
|
||||
/** (0x82) Duplicate 3rd item on stack */
|
||||
DUP3(0x82, 3),
|
||||
/** (0x83) Duplicate 4th item on stack */
|
||||
DUP4(0x83, 4),
|
||||
/** (0x84) Duplicate 5th item on stack */
|
||||
DUP5(0x84, 5),
|
||||
/** (0x85) Duplicate 6th item on stack */
|
||||
DUP6(0x85, 6),
|
||||
/** (0x86) Duplicate 7th item on stack */
|
||||
DUP7(0x86, 7),
|
||||
/** (0x87) Duplicate 8th item on stack */
|
||||
DUP8(0x87, 8),
|
||||
/** (0x88) Duplicate 9th item on stack */
|
||||
DUP9(0x88, 9),
|
||||
/** (0x89) Duplicate 10th item on stack */
|
||||
DUP10(0x89, 10),
|
||||
/** (0x8a) Duplicate 11th item on stack */
|
||||
DUP11(0x8a, 11),
|
||||
/** (0x8b) Duplicate 12th item on stack */
|
||||
DUP12(0x8b, 12),
|
||||
/** (0x8c) Duplicate 13th item on stack */
|
||||
DUP13(0x8c, 13),
|
||||
/** (0x8d) Duplicate 14th item on stack */
|
||||
DUP14(0x8d, 14),
|
||||
/** (0x8e) Duplicate 15th item on stack */
|
||||
DUP15(0x8e, 15),
|
||||
/** (0x8f) Duplicate 16th item on stack */
|
||||
DUP16(0x8f, 16),
|
||||
|
||||
/* Swap the Nth item from the stack with the top */
|
||||
/* Swap the Nth item from the stack with the top */
|
||||
|
||||
/** (0x90) Exchange 2nd item from stack with the top */
|
||||
SWAP1(0x90, 2),
|
||||
/** (0x91) Exchange 3rd item from stack with the top */
|
||||
SWAP2(0x91, 3),
|
||||
/** (0x92) Exchange 4th item from stack with the top */
|
||||
SWAP3(0x92, 4),
|
||||
/** (0x93) Exchange 5th item from stack with the top */
|
||||
SWAP4(0x93, 5),
|
||||
/** (0x94) Exchange 6th item from stack with the top */
|
||||
SWAP5(0x94, 6),
|
||||
/** (0x95) Exchange 7th item from stack with the top */
|
||||
SWAP6(0x95, 7),
|
||||
/** (0x96) Exchange 8th item from stack with the top */
|
||||
SWAP7(0x96, 8),
|
||||
/** (0x97) Exchange 9th item from stack with the top */
|
||||
SWAP8(0x97, 9),
|
||||
/** (0x98) Exchange 10th item from stack with the top */
|
||||
SWAP9(0x98, 10),
|
||||
/** (0x99) Exchange 11th item from stack with the top */
|
||||
SWAP10(0x99, 11),
|
||||
/** (0x9a) Exchange 12th item from stack with the top */
|
||||
SWAP11(0x9a, 12),
|
||||
/** (0x9b) Exchange 13th item from stack with the top */
|
||||
SWAP12(0x9b, 13),
|
||||
/** (0x9c) Exchange 14th item from stack with the top */
|
||||
SWAP13(0x9c, 14),
|
||||
/** (0x9d) Exchange 15th item from stack with the top */
|
||||
SWAP14(0x9d, 15),
|
||||
/** (0x9e) Exchange 16th item from stack with the top */
|
||||
SWAP15(0x9e, 16),
|
||||
/** (0x9f) Exchange 17th item from stack with the top */
|
||||
SWAP16(0x9f, 17),
|
||||
/** (0x90) Exchange 2nd item from stack with the top */
|
||||
SWAP1(0x90, 2),
|
||||
/** (0x91) Exchange 3rd item from stack with the top */
|
||||
SWAP2(0x91, 3),
|
||||
/** (0x92) Exchange 4th item from stack with the top */
|
||||
SWAP3(0x92, 4),
|
||||
/** (0x93) Exchange 5th item from stack with the top */
|
||||
SWAP4(0x93, 5),
|
||||
/** (0x94) Exchange 6th item from stack with the top */
|
||||
SWAP5(0x94, 6),
|
||||
/** (0x95) Exchange 7th item from stack with the top */
|
||||
SWAP6(0x95, 7),
|
||||
/** (0x96) Exchange 8th item from stack with the top */
|
||||
SWAP7(0x96, 8),
|
||||
/** (0x97) Exchange 9th item from stack with the top */
|
||||
SWAP8(0x97, 9),
|
||||
/** (0x98) Exchange 10th item from stack with the top */
|
||||
SWAP9(0x98, 10),
|
||||
/** (0x99) Exchange 11th item from stack with the top */
|
||||
SWAP10(0x99, 11),
|
||||
/** (0x9a) Exchange 12th item from stack with the top */
|
||||
SWAP11(0x9a, 12),
|
||||
/** (0x9b) Exchange 13th item from stack with the top */
|
||||
SWAP12(0x9b, 13),
|
||||
/** (0x9c) Exchange 14th item from stack with the top */
|
||||
SWAP13(0x9c, 14),
|
||||
/** (0x9d) Exchange 15th item from stack with the top */
|
||||
SWAP14(0x9d, 15),
|
||||
/** (0x9e) Exchange 16th item from stack with the top */
|
||||
SWAP15(0x9e, 16),
|
||||
/** (0x9f) Exchange 17th item from stack with the top */
|
||||
SWAP16(0x9f, 17),
|
||||
|
||||
/** (0xa[n]) log some data for some addres with 0..n tags [addr [tag0..tagn] data] */
|
||||
LOG0(0xa0, 2),
|
||||
@ -299,23 +299,23 @@ public enum OpCode {
|
||||
LOG3(0xa3, 5),
|
||||
LOG4(0xa4, 6),
|
||||
|
||||
/* System operations */
|
||||
/* System operations */
|
||||
|
||||
/** (0xf0) Create a new account with associated code */
|
||||
CREATE(0xf0, 3), // [in_size] [in_offs] [gas_val] CREATE
|
||||
/** (cxf1) Message-call into an account */
|
||||
CALL(0xf1, 7), // [out_data_size] [out_data_start] [in_data_size] [in_data_start] [value] [to_addr] [gas] CALL
|
||||
/** (0xf2) Calls self, but grabbing the code from the
|
||||
* TO argument instead of from one's own address */
|
||||
CALLCODE(0xf2, 7),
|
||||
/** (0xf3) Halt execution returning output data */
|
||||
/** (0xf0) Create a new account with associated code */
|
||||
CREATE(0xf0, 3), // [in_size] [in_offs] [gas_val] CREATE
|
||||
/** (cxf1) Message-call into an account */
|
||||
CALL(0xf1, 7), // [out_data_size] [out_data_start] [in_data_size] [in_data_start] [value] [to_addr] [gas] CALL
|
||||
/** (0xf2) Calls self, but grabbing the code from the
|
||||
* TO argument instead of from one's own address */
|
||||
CALLCODE(0xf2, 7),
|
||||
/** (0xf3) Halt execution returning output data */
|
||||
RETURN(0xf3, 2),
|
||||
/** (0xff) Halt execution and register account for
|
||||
* later deletion */
|
||||
SUICIDE(0xff, 1);
|
||||
/** (0xff) Halt execution and register account for
|
||||
* later deletion */
|
||||
SUICIDE(0xff, 1);
|
||||
|
||||
private byte opcode;
|
||||
private int require;
|
||||
private byte opcode;
|
||||
private int require;
|
||||
|
||||
private static final Map<Byte, OpCode> intToTypeMap = new HashMap<>();
|
||||
private static final Map<String, Byte> stringToByteMap = new HashMap<>();
|
||||
@ -342,11 +342,11 @@ public enum OpCode {
|
||||
* @return minimum amount of expected items on the stack
|
||||
*/
|
||||
public int require() {
|
||||
return require;
|
||||
return require;
|
||||
}
|
||||
|
||||
public int asInt() {
|
||||
return opcode;
|
||||
return opcode;
|
||||
}
|
||||
|
||||
public static boolean contains(String code) {
|
||||
@ -358,6 +358,6 @@ public enum OpCode {
|
||||
}
|
||||
|
||||
public static OpCode code(byte code) {
|
||||
return intToTypeMap.get(code);
|
||||
return intToTypeMap.get(code);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
|
||||
* Created on: 01/06/2014 10:45
|
||||
*/
|
||||
public class Program {
|
||||
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("VM");
|
||||
private static final Logger gasLogger = LoggerFactory.getLogger("gas");
|
||||
|
||||
@ -51,33 +51,33 @@ public class Program {
|
||||
byte[] ops;
|
||||
int pc = 0;
|
||||
byte lastOp = 0;
|
||||
byte previouslyExecutedOp = 0;
|
||||
byte previouslyExecutedOp = 0;
|
||||
boolean stopped = false;
|
||||
|
||||
ProgramInvoke invokeData;
|
||||
|
||||
public Program(byte[] ops, ProgramInvoke invokeData) {
|
||||
|
||||
if (ops == null) ops = EMPTY_BYTE_ARRAY;
|
||||
this.ops = ops;
|
||||
|
||||
if (invokeData != null) {
|
||||
this.invokeData = invokeData;
|
||||
this.programAddress = invokeData.getOwnerAddress();
|
||||
this.invokeHash = invokeData.hashCode();
|
||||
this.result.setRepository(invokeData.getRepository());
|
||||
}
|
||||
}
|
||||
public Program(byte[] ops, ProgramInvoke invokeData) {
|
||||
|
||||
if (ops == null) ops = EMPTY_BYTE_ARRAY;
|
||||
this.ops = ops;
|
||||
|
||||
if (invokeData != null) {
|
||||
this.invokeData = invokeData;
|
||||
this.programAddress = invokeData.getOwnerAddress();
|
||||
this.invokeHash = invokeData.hashCode();
|
||||
this.result.setRepository(invokeData.getRepository());
|
||||
}
|
||||
}
|
||||
|
||||
public byte getOp(int pc) {
|
||||
if (ops.length <= pc)
|
||||
return 0;
|
||||
return ops[pc];
|
||||
}
|
||||
public byte getOp(int pc) {
|
||||
if (ops.length <= pc)
|
||||
return 0;
|
||||
return ops[pc];
|
||||
}
|
||||
|
||||
public byte getCurrentOp() {
|
||||
if(ops.length == 0)
|
||||
return 0;
|
||||
if(ops.length == 0)
|
||||
return 0;
|
||||
return ops[pc];
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ public class Program {
|
||||
* @param op
|
||||
*/
|
||||
public void setPreviouslyExecutedOp(byte op) {
|
||||
this.previouslyExecutedOp = op;
|
||||
this.previouslyExecutedOp = op;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,7 +102,7 @@ public class Program {
|
||||
* @return
|
||||
*/
|
||||
public byte getPreviouslyExecutedOp() {
|
||||
return this.previouslyExecutedOp;
|
||||
return this.previouslyExecutedOp;
|
||||
}
|
||||
|
||||
public void stackPush(byte[] data) {
|
||||
@ -125,7 +125,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public Stack<DataWord> getStack() {
|
||||
return this.stack;
|
||||
return this.stack;
|
||||
}
|
||||
|
||||
public int getPC() {
|
||||
@ -180,13 +180,13 @@ public class Program {
|
||||
* Verifies that the stack is at least <code>stackSize</code>
|
||||
* @param stackSize int
|
||||
* @throws StackTooSmallException If the stack is
|
||||
* smaller than <code>stackSize</code>
|
||||
* smaller than <code>stackSize</code>
|
||||
*/
|
||||
public void stackRequire(int stackSize) {
|
||||
if (stack.size() < stackSize) {
|
||||
throw new StackTooSmallException("Expected: " + stackSize
|
||||
+ ", found: " + stack.size());
|
||||
}
|
||||
if (stack.size() < stackSize) {
|
||||
throw new StackTooSmallException("Expected: " + stackSize
|
||||
+ ", found: " + stack.size());
|
||||
}
|
||||
}
|
||||
|
||||
public int getMemSize() {
|
||||
@ -198,7 +198,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public void memorySave(int addr, byte[] value) {
|
||||
memorySave(addr, value.length, value);
|
||||
memorySave(addr, value.length, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -215,7 +215,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public DataWord memoryLoad(DataWord addr) {
|
||||
return memoryLoad(addr.intValue());
|
||||
return memoryLoad(addr.intValue());
|
||||
}
|
||||
|
||||
public DataWord memoryLoad(int address) {
|
||||
@ -229,7 +229,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public ByteBuffer memoryChunk(DataWord offsetData, DataWord sizeData) {
|
||||
return memoryChunk(offsetData.intValue(), sizeData.intValue());
|
||||
return memoryChunk(offsetData.intValue(), sizeData.intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,9 +246,9 @@ public class Program {
|
||||
allocateMemory(offset, size);
|
||||
byte[] chunk;
|
||||
if (memory != null && size != 0)
|
||||
chunk = Arrays.copyOfRange(memory.array(), offset, offset+size);
|
||||
chunk = Arrays.copyOfRange(memory.array(), offset, offset+size);
|
||||
else
|
||||
chunk = new byte[size];
|
||||
chunk = new byte[size];
|
||||
return ByteBuffer.wrap(chunk);
|
||||
}
|
||||
|
||||
@ -262,11 +262,11 @@ public class Program {
|
||||
public void allocateMemory(int offset, int size) {
|
||||
|
||||
int memSize = memory != null ? memory.limit() : 0;
|
||||
double newMemSize = Math.max(memSize, size != 0 ?
|
||||
Math.ceil((double) (offset + size) / 32) * 32 : 0);
|
||||
double newMemSize = Math.max(memSize, size != 0 ?
|
||||
Math.ceil((double) (offset + size) / 32) * 32 : 0);
|
||||
ByteBuffer tmpMem = ByteBuffer.allocate((int)newMemSize);
|
||||
if (memory != null)
|
||||
tmpMem.put(memory.array(), 0, memory.limit());
|
||||
tmpMem.put(memory.array(), 0, memory.limit());
|
||||
memory = tmpMem;
|
||||
}
|
||||
|
||||
@ -276,9 +276,9 @@ public class Program {
|
||||
DataWord balance = getBalance(this.getOwnerAddress());
|
||||
// 1) pass full endowment to the obtainer
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("Transfer to: [{}] heritage: [{}]",
|
||||
Hex.toHexString(obtainer.getLast20Bytes()),
|
||||
balance.longValue());
|
||||
logger.info("Transfer to: [{}] heritage: [{}]",
|
||||
Hex.toHexString(obtainer.getLast20Bytes()),
|
||||
balance.longValue());
|
||||
|
||||
this.result.getRepository().addBalance(obtainer.getLast20Bytes(), balance.value());
|
||||
this.result.getRepository().addBalance(this.getOwnerAddress().getLast20Bytes(), balance.value().negate());
|
||||
@ -305,12 +305,12 @@ public class Program {
|
||||
byte[] newAddress = HashUtil.calcNewAddr(this.getOwnerAddress().getLast20Bytes(), nonce);
|
||||
result.getRepository().createAccount(newAddress);
|
||||
|
||||
if (invokeData.byTestingSuite()) {
|
||||
// This keeps track of the contracts created for a test
|
||||
this.getResult().addCallCreate(programCode, newAddress,
|
||||
gasLimit.getNoLeadZeroesData(),
|
||||
value.getNoLeadZeroesData());
|
||||
}
|
||||
if (invokeData.byTestingSuite()) {
|
||||
// This keeps track of the contracts created for a test
|
||||
this.getResult().addCallCreate(programCode, newAddress,
|
||||
gasLimit.getNoLeadZeroesData(),
|
||||
value.getNoLeadZeroesData());
|
||||
}
|
||||
|
||||
// [4] TRANSFER THE BALANCE
|
||||
BigInteger endowment = value.value();
|
||||
@ -329,10 +329,10 @@ public class Program {
|
||||
Repository track = result.getRepository().startTracking();
|
||||
|
||||
// [5] COOK THE INVOKE AND EXECUTE
|
||||
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(
|
||||
this, new DataWord(newAddress), DataWord.ZERO, gasLimit,
|
||||
newBalance, null, track);
|
||||
|
||||
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(
|
||||
this, new DataWord(newAddress), DataWord.ZERO, gasLimit,
|
||||
newBalance, null, track);
|
||||
|
||||
ProgramResult result = null;
|
||||
|
||||
if (programCode != null && programCode.length != 0) {
|
||||
@ -345,7 +345,7 @@ public class Program {
|
||||
}
|
||||
|
||||
if (result != null &&
|
||||
result.getException() != null &&
|
||||
result.getException() != null &&
|
||||
result.getException() instanceof Program.OutOfGasException) {
|
||||
logger.debug("contract run halted by Exception: contract: [{}], exception: [{}]",
|
||||
Hex.toHexString(newAddress),
|
||||
@ -397,7 +397,7 @@ public class Program {
|
||||
* @param msg is the message call object
|
||||
*/
|
||||
public void callToAddress(MessageCall msg) {
|
||||
|
||||
|
||||
byte[] data = memoryChunk(msg.getInDataOffs(), msg.getInDataSize()).array();
|
||||
|
||||
// FETCH THE SAVED STORAGE
|
||||
@ -432,7 +432,7 @@ public class Program {
|
||||
|
||||
if (invokeData.byTestingSuite()) {
|
||||
// This keeps track of the calls created for a test
|
||||
this.getResult().addCallCreate(data, contextAddress,
|
||||
this.getResult().addCallCreate(data, contextAddress,
|
||||
msg.getGas().getNoLeadZeroesData(),
|
||||
msg.getEndowment().getNoLeadZeroesData());
|
||||
}
|
||||
@ -441,10 +441,10 @@ public class Program {
|
||||
this.spendGas(msg.getGas().longValue(), "internal call");
|
||||
|
||||
Repository trackRepository = result.getRepository().startTracking();
|
||||
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(
|
||||
this, new DataWord(contextAddress), msg.getEndowment(),
|
||||
msg.getGas(), contextBalance, data, trackRepository);
|
||||
|
||||
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(
|
||||
this, new DataWord(contextAddress), msg.getEndowment(),
|
||||
msg.getGas(), contextBalance, data, trackRepository);
|
||||
|
||||
ProgramResult result = null;
|
||||
|
||||
if (programCode != null && programCode.length != 0) {
|
||||
@ -458,8 +458,8 @@ public class Program {
|
||||
}
|
||||
|
||||
if (result != null &&
|
||||
result.getException() != null &&
|
||||
result.getException() instanceof Program.OutOfGasException) {
|
||||
result.getException() != null &&
|
||||
result.getException() instanceof Program.OutOfGasException) {
|
||||
gasLogger.debug("contract run halted by Exception: contract: [{}], exception: [{}]",
|
||||
Hex.toHexString(contextAddress),
|
||||
result.getException());
|
||||
@ -494,9 +494,9 @@ public class Program {
|
||||
if (refundGas.signum() == 1) {
|
||||
this.refundGas(refundGas.longValue(), "remaining gas from the internal call");
|
||||
if(gasLogger.isInfoEnabled())
|
||||
gasLogger.info("The remaining gas refunded, account: [{}], gas: [{}] ",
|
||||
Hex.toHexString(senderAddress),
|
||||
refundGas.toString());
|
||||
gasLogger.info("The remaining gas refunded, account: [{}], gas: [{}] ",
|
||||
Hex.toHexString(senderAddress),
|
||||
refundGas.toString());
|
||||
}
|
||||
} else {
|
||||
this.refundGas(msg.getGas().longValue(), "remaining gas from the internal call");
|
||||
@ -513,7 +513,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public void spendAllGas() {
|
||||
spendGas(invokeData.getGas().longValue() - result.getGasUsed(), "Spending all remaining");
|
||||
spendGas(invokeData.getGas().longValue() - result.getGasUsed(), "Spending all remaining");
|
||||
}
|
||||
|
||||
public void refundGas(long gasValue, String cause) {
|
||||
@ -536,7 +536,7 @@ public class Program {
|
||||
}
|
||||
|
||||
public byte[] getCode() {
|
||||
return ops;
|
||||
return ops;
|
||||
}
|
||||
|
||||
public byte[] getCodeAt(DataWord address) {
|
||||
@ -544,7 +544,7 @@ public class Program {
|
||||
byte[] code = invokeData.getRepository().getCode(address.getLast20Bytes());
|
||||
if (code == null) code = ByteUtil.EMPTY_BYTE_ARRAY;
|
||||
|
||||
return code;
|
||||
return code;
|
||||
}
|
||||
|
||||
public DataWord getOwnerAddress() {
|
||||
@ -646,7 +646,7 @@ public class Program {
|
||||
|
||||
byte value = memory.get(i);
|
||||
// Check if value is ASCII
|
||||
String character = ((byte) 0x20 <= value && value <= (byte) 0x7e) ? new String(new byte[] { value }) : "?";
|
||||
String character = ((byte) 0x20 <= value && value <= (byte) 0x7e) ? new String(new byte[] { value }) : "?";
|
||||
firstLine.append(character).append("");
|
||||
secondLine.append(ByteUtil.oneByteToHexString(value)).append(" ");
|
||||
|
||||
@ -679,7 +679,7 @@ public class Program {
|
||||
StringBuilder storageData = new StringBuilder();
|
||||
if(contractDetails != null) {
|
||||
List<DataWord> storageKeys = new ArrayList<>(contractDetails.getStorage().keySet());
|
||||
Collections.sort((List<DataWord>) storageKeys);
|
||||
Collections.sort((List<DataWord>) storageKeys);
|
||||
for (DataWord key : storageKeys) {
|
||||
storageData.append(" ").append(key).append(" -> ").
|
||||
append(contractDetails.getStorage().get(key)).append("\n");
|
||||
@ -741,18 +741,18 @@ public class Program {
|
||||
globalOutput.append(" -- STORAGE -- ").append(storageData).append("\n");
|
||||
|
||||
if (result.getHReturn() != null)
|
||||
globalOutput.append("\n HReturn: ").append(
|
||||
Hex.toHexString(result.getHReturn().array()));
|
||||
globalOutput.append("\n HReturn: ").append(
|
||||
Hex.toHexString(result.getHReturn().array()));
|
||||
|
||||
// sophisticated assumption that msg.data != codedata
|
||||
// means we are calling the contract not creating it
|
||||
byte[] txData = invokeData.getDataCopy(DataWord.ZERO, getDataSize());
|
||||
if (!Arrays.equals(txData, ops))
|
||||
globalOutput.append("\n msg.data: ").append(Hex.toHexString(txData));
|
||||
globalOutput.append("\n msg.data: ").append(Hex.toHexString(txData));
|
||||
globalOutput.append("\n\n Spent Gas: ").append(result.getGasUsed());
|
||||
|
||||
if (listener != null)
|
||||
listener.output(globalOutput.toString());
|
||||
if (listener != null)
|
||||
listener.output(globalOutput.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -818,57 +818,57 @@ public class Program {
|
||||
}
|
||||
|
||||
public static String stringify(byte[] code, int index, String result) {
|
||||
if(code == null || code.length == 0)
|
||||
return result;
|
||||
|
||||
OpCode op = OpCode.code(code[index]);
|
||||
byte[] continuedCode = null;
|
||||
|
||||
switch(op) {
|
||||
case PUSH1: case PUSH2: case PUSH3: case PUSH4: case PUSH5: case PUSH6: case PUSH7: case PUSH8:
|
||||
case PUSH9: case PUSH10: case PUSH11: case PUSH12: case PUSH13: case PUSH14: case PUSH15: case PUSH16:
|
||||
case PUSH17: case PUSH18: case PUSH19: case PUSH20: case PUSH21: case PUSH22: case PUSH23: case PUSH24:
|
||||
case PUSH25: case PUSH26: case PUSH27: case PUSH28: case PUSH29: case PUSH30: case PUSH31: case PUSH32:
|
||||
result += ' ' + op.name() + ' ';
|
||||
|
||||
int nPush = op.val() - OpCode.PUSH1.val() + 1;
|
||||
byte[] data = Arrays.copyOfRange(code, index+1, index + nPush + 1);
|
||||
result += new BigInteger(1, data).toString() + ' ';
|
||||
|
||||
continuedCode = Arrays.copyOfRange(code, index + nPush + 1, code.length);
|
||||
break;
|
||||
|
||||
default:
|
||||
result += ' ' + op.name();
|
||||
continuedCode = Arrays.copyOfRange(code, index + 1, code.length);
|
||||
break;
|
||||
}
|
||||
return stringify(continuedCode, 0, result);
|
||||
if(code == null || code.length == 0)
|
||||
return result;
|
||||
|
||||
OpCode op = OpCode.code(code[index]);
|
||||
byte[] continuedCode = null;
|
||||
|
||||
switch(op) {
|
||||
case PUSH1: case PUSH2: case PUSH3: case PUSH4: case PUSH5: case PUSH6: case PUSH7: case PUSH8:
|
||||
case PUSH9: case PUSH10: case PUSH11: case PUSH12: case PUSH13: case PUSH14: case PUSH15: case PUSH16:
|
||||
case PUSH17: case PUSH18: case PUSH19: case PUSH20: case PUSH21: case PUSH22: case PUSH23: case PUSH24:
|
||||
case PUSH25: case PUSH26: case PUSH27: case PUSH28: case PUSH29: case PUSH30: case PUSH31: case PUSH32:
|
||||
result += ' ' + op.name() + ' ';
|
||||
|
||||
int nPush = op.val() - OpCode.PUSH1.val() + 1;
|
||||
byte[] data = Arrays.copyOfRange(code, index+1, index + nPush + 1);
|
||||
result += new BigInteger(1, data).toString() + ' ';
|
||||
|
||||
continuedCode = Arrays.copyOfRange(code, index + nPush + 1, code.length);
|
||||
break;
|
||||
|
||||
default:
|
||||
result += ' ' + op.name();
|
||||
continuedCode = Arrays.copyOfRange(code, index + 1, code.length);
|
||||
break;
|
||||
}
|
||||
return stringify(continuedCode, 0, result);
|
||||
}
|
||||
|
||||
public void addListener(ProgramListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
public void addListener(ProgramListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public interface ProgramListener {
|
||||
public void output(String out);
|
||||
}
|
||||
public interface ProgramListener {
|
||||
public void output(String out);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class OutOfGasException extends RuntimeException {}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class OutOfGasException extends RuntimeException {}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class IllegalOperationException extends RuntimeException {}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class BadJumpDestinationException extends RuntimeException {}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class StackTooSmallException extends RuntimeException {
|
||||
public StackTooSmallException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class StackTooSmallException extends RuntimeException {
|
||||
public StackTooSmallException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* used mostly for testing reasons
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user