Skip to content

Commit

Permalink
Merge pull request #90 from orogvany/testnet_rc
Browse files Browse the repository at this point in the history
RC: 1.5.0 Testnet - VM + HD Wallets
  • Loading branch information
orogvany committed Nov 17, 2018
2 parents 40a00cc + f1982a7 commit 021d510
Show file tree
Hide file tree
Showing 64 changed files with 4,526 additions and 258 deletions.
10 changes: 10 additions & 0 deletions config/semux.properties
Expand Up @@ -75,3 +75,13 @@ api.password = YOUR_API_PASSWORD
# ui.unit must be one of SEM, mSEM, μSEM
ui.unit = SEM
ui.fractionDigits = 9

#================
# VM
#================

# Set the maximum gas this client can process in one block proposal
vm.blockGasLimit = 2000000

# The minimum price this client will accept for gas
vm.minGasPrice = 1
1 change: 1 addition & 0 deletions evm
Submodule evm added at f0cd32
27 changes: 23 additions & 4 deletions pom.xml
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.semux</groupId>
<artifactId>semux</artifactId>
<version>1.4.0</version>
<version>1.5.0</version>
<packaging>jar</packaging>
<description>Semux is an experimental high-performance blockchain platform that powers decentralized application.</description>

Expand All @@ -14,6 +14,7 @@
<dist.windowsExecutableVersion>${project.version}.0</dist.windowsExecutableVersion>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<skip.git.info>false</skip.git.info>
</properties>

<organization>
Expand Down Expand Up @@ -107,7 +108,7 @@
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/org/semux/api/swagger/v2.1.0.json</inputSpec>
<inputSpec>${project.basedir}/src/main/resources/org/semux/api/swagger/v2.2.0.json</inputSpec>
<language>jaxrs-cxf</language>
<configOptions>
<useGenericResponse>true</useGenericResponse>
Expand Down Expand Up @@ -137,7 +138,7 @@
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/org/semux/api/swagger/v2.1.0.json</inputSpec>
<inputSpec>${project.basedir}/src/main/resources/org/semux/api/swagger/v2.2.0.json</inputSpec>
<language>jaxrs-cxf-client</language>
<configOptions>
<useBeanValidation>false</useBeanValidation>
Expand Down Expand Up @@ -244,6 +245,7 @@
</execution>
</executions>
<configuration>
<skip>${skip.git.info}</skip>
<abbrevLength>7</abbrevLength>
<verbose>false</verbose>
<skipPoms>false</skipPoms>
Expand Down Expand Up @@ -676,7 +678,7 @@
<dependency>
<groupId>com.github.semuxproject</groupId>
<artifactId>evm</artifactId>
<version>-SNAPSHOT</version>
<version>f0cd3256aad61634e0efb320478e8075beec076f</version>
</dependency>

<!-- Swagger & JAX-RS API -->
Expand Down Expand Up @@ -1017,9 +1019,26 @@
<version>2.9.7</version>
<scope>test</scope>
</dependency>

<!-- HD wallets -->
<dependency>
<groupId>com.github.orogvany</groupId>
<artifactId>BIP32-Ed25519-java</artifactId>
<version>a5865ea2916197e2da83c38a3b50972f01a8c93c</version>
</dependency>
</dependencies>

<profiles>
<profile>
<id>src-build</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<skip.git.info>true</skip.git.info>
<git.commit.id.abbrev>local</git.commit.id.abbrev>
</properties>
</profile>
<profile>
<id>windows</id>
<activation>
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/semux/api/ApiHandlerImpl.java
Expand Up @@ -59,6 +59,7 @@ public ApiHandlerImpl(Kernel kernel) {

this.routes.put(ApiVersion.v2_0_0, routesV2);
this.routes.put(ApiVersion.v2_1_0, routesV2);
this.routes.put(ApiVersion.v2_2_0, routesV2);
}

@Override
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/org/semux/api/ApiVersion.java
Expand Up @@ -28,9 +28,11 @@ public enum ApiVersion {

v2_0_0("v2.0.0"),

v2_1_0("v2.1.0");
v2_1_0("v2.1.0"),

public final static ApiVersion DEFAULT = v2_1_0;
v2_2_0("v2.2.0");

public final static ApiVersion DEFAULT = v2_2_0;

public final String prefix;

Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/semux/api/SemuxApiService.java
Expand Up @@ -9,9 +9,12 @@
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import io.netty.channel.ChannelOption;
import io.netty.channel.FixedRecvByteBufAllocator;
import org.semux.Kernel;
import org.semux.api.http.HttpChannelInitializer;
import org.semux.api.http.HttpHandler;
import org.semux.net.Frame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -97,6 +100,13 @@ public HttpHandler initHandler() {

logger.info("Starting API server: address = {}:{}", ip, port);
channel = b.bind(ip, port).sync().channel();

// allow larger messages for local contract calls.
// contract/call data is 64 * 1024, plus another 1024 for rest of call
int bufferSize = 65 * 1024;
channel.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(bufferSize));
channel.config().setOption(ChannelOption.SO_RCVBUF, bufferSize);

logger.info("API server started. Base URL: {}, Explorer: {}", getApiBaseUrl(), getApiExplorerUrl());
} catch (Exception e) {
logger.error("Failed to start API server", e);
Expand Down
42 changes: 41 additions & 1 deletion src/main/java/org/semux/api/util/TransactionBuilder.java
Expand Up @@ -72,6 +72,9 @@ public class TransactionBuilder {
*/
private byte[] data;

private long gasPrice = 0;
private long gas = 0;

public TransactionBuilder(Kernel kernel) {
this.kernel = kernel;
}
Expand Down Expand Up @@ -129,6 +132,12 @@ public TransactionBuilder withTo(String to) {
}
return this; // ignore the provided parameter
}
if (type == TransactionType.CREATE) {
if (to != null && !to.isEmpty()) {
throw new IllegalArgumentException("Parameter `to` is not needed for CREATE transaction");
}
return this; // ignore the provided parameter
}

if (to == null) {
throw new IllegalArgumentException("Parameter `to` is required");
Expand Down Expand Up @@ -211,12 +220,43 @@ public TransactionBuilder withData(String data) {
return this;
}

public TransactionBuilder withGasPrice(String gasPrice) {
if (gasPrice == null) {
throw new IllegalArgumentException("Parameter `gasPrice` is required");
}

try {
this.gasPrice = Long.parseLong(gasPrice);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Parameter `gasPrice` is not a valid number");
}

return this;
}

public TransactionBuilder withGas(String gasLimit) {
if (gasLimit == null) {
throw new IllegalArgumentException("Parameter `gas` is required");
}

try {
this.gas = Long.parseLong(gasLimit);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Parameter `gas` is not a valid number");
}

return this;
}

public Transaction buildUnsigned() {
// DELEGATE transaction has fixed receiver and value
if (type == TransactionType.DELEGATE) {
to = Bytes.EMPTY_ADDRESS;
value = kernel.getConfig().minDelegateBurnAmount();
}
if (type == TransactionType.CREATE) {
to = Bytes.EMPTY_ADDRESS;
}

return new Transaction(
network != null ? network : kernel.getConfig().network(),
Expand All @@ -226,7 +266,7 @@ public Transaction buildUnsigned() {
fee,
nonce != null ? nonce : kernel.getPendingManager().getNonce(account.toAddress()),
timestamp != null ? timestamp : TimeUtil.currentTimeMillis(),
data);
data, gas, gasPrice);
}

public Transaction buildSigned() {
Expand Down
111 changes: 88 additions & 23 deletions src/main/java/org/semux/api/v2/SemuxApiImpl.java
Expand Up @@ -25,6 +25,12 @@

import org.apache.commons.validator.routines.DomainValidator;
import org.apache.commons.validator.routines.InetAddressValidator;
import org.ethereum.vm.chainspec.Spec;
import org.ethereum.vm.client.BlockStore;
import org.ethereum.vm.client.Repository;
import org.ethereum.vm.client.TransactionReceipt;
import org.ethereum.vm.program.invoke.ProgramInvokeFactory;
import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl;
import org.semux.Kernel;
import org.semux.api.util.TransactionBuilder;
import org.semux.api.v2.model.AddNodeResponse;
Expand Down Expand Up @@ -75,6 +81,10 @@
import org.semux.net.filter.SemuxIpFilter;

import net.i2p.crypto.eddsa.EdDSAPublicKey;
import org.semux.vm.client.SemuxBlock;
import org.semux.vm.client.SemuxBlockStore;
import org.semux.vm.client.SemuxRepository;
import org.semux.vm.client.SemuxTransaction;

public final class SemuxApiImpl implements SemuxApi {

Expand Down Expand Up @@ -730,6 +740,45 @@ public Response transfer(String from, String to, String value, String fee, Strin
return doTransaction(TransactionType.TRANSFER, from, to, value, fee, nonce, validateNonce, data);
}

@Override
public Response create(String from, String value, String data, String gasPrice, String gas, String fee,
String nonce, Boolean validateNonce) {
return doTransaction(TransactionType.CREATE, from, null, value, fee, nonce, validateNonce, data, gasPrice,
gas);
}

@Override
public Response call(String from, String to, String value, String gasPrice, String gas, String fee,
String nonce, Boolean validateNonce, String data, Boolean local) {
if (local) {
Transaction tx = getTransaction(TransactionType.CALL, from, to, value, fee, nonce, validateNonce, data,
gasPrice, gas);

SemuxTransaction transaction = new SemuxTransaction(tx);
SemuxBlock block = new SemuxBlock(kernel.getBlockchain().getLatestBlock().getHeader(), 0);
Repository repository = new SemuxRepository(kernel.getBlockchain().getAccountState());
ProgramInvokeFactory invokeFactory = new ProgramInvokeFactoryImpl();
BlockStore blockStore = new SemuxBlockStore(kernel.getBlockchain());
long gasUsedInBlock = 0l;

org.ethereum.vm.client.TransactionExecutor executor = new org.ethereum.vm.client.TransactionExecutor(
transaction, block, repository, blockStore,
Spec.DEFAULT, invokeFactory, gasUsedInBlock, true);
TransactionReceipt results = executor.run();

DoTransactionResponse resp = new DoTransactionResponse();
resp.setResult(Hex.encode0x(results.getReturnData()));
if (!results.isSuccess()) {
return badRequest(resp, "Error calling method");
} else {
return success(resp);
}
} else {
return doTransaction(TransactionType.CALL, from, to, value, fee, nonce, validateNonce, data, gasPrice,
gas);
}
}

@Override
public Response unvote(String from, String to, String value, String fee, String nonce, Boolean validateNonce) {
return doTransaction(TransactionType.UNVOTE, from, to, value, fee, nonce, validateNonce, null);
Expand Down Expand Up @@ -857,6 +906,43 @@ private NodeManager.Node validateAddNodeParameter(String node) {
return new NodeManager.Node(host, port);
}

private Response doTransaction(TransactionType type, String from, String to, String value, String fee, String nonce,
Boolean validateNonce, String data) {
return doTransaction(type, from, to, value, fee, nonce, validateNonce, data, null, null);
}

private Transaction getTransaction(TransactionType type, String from, String to, String value, String fee,
String nonce,
Boolean validateNonce, String data, String gasPrice, String gas) {
TransactionBuilder transactionBuilder = new TransactionBuilder(kernel)
.withType(type)
.withFrom(from)
.withTo(to)
.withValue(value)
.withFee(fee, true)
.withData(data);
if (type == TransactionType.CREATE || type == TransactionType.CALL) {
transactionBuilder.withGasPrice(gasPrice).withGas(gas);
}

if (nonce != null) {
transactionBuilder.withNonce(nonce);
} else {
// TODO: fix race condition of auto-assigned nonce
}

Transaction tx = transactionBuilder.buildSigned();

// tx nonce is validated in advance to avoid silently pushing the tx into
// delayed queue of pending manager
if ((validateNonce != null && validateNonce)
&& tx.getNonce() != kernel.getPendingManager().getNonce(tx.getFrom())) {
throw new IllegalArgumentException("Invalid transaction nonce.");
}
return tx;

}

/**
* Constructs a transaction and adds it to pending manager.
*
Expand All @@ -871,31 +957,10 @@ private NodeManager.Node validateAddNodeParameter(String node) {
* @return
*/
private Response doTransaction(TransactionType type, String from, String to, String value, String fee, String nonce,
Boolean validateNonce, String data) {
Boolean validateNonce, String data, String gasPrice, String gas) {
DoTransactionResponse resp = new DoTransactionResponse();
try {
TransactionBuilder transactionBuilder = new TransactionBuilder(kernel)
.withType(type)
.withFrom(from)
.withTo(to)
.withValue(value)
.withFee(fee, true)
.withData(data);

if (nonce != null) {
transactionBuilder.withNonce(nonce);
} else {
// TODO: fix race condition of auto-assigned nonce
}

Transaction tx = transactionBuilder.buildSigned();

// tx nonce is validated in advance to avoid silently pushing the tx into
// delayed queue of pending manager
if ((validateNonce != null && validateNonce)
&& tx.getNonce() != kernel.getPendingManager().getNonce(tx.getFrom())) {
return badRequest(resp, "Invalid transaction nonce.");
}
Transaction tx = getTransaction(type, from, to, value, fee, nonce, validateNonce, data, gasPrice, gas);

PendingManager.ProcessingResult result = kernel.getPendingManager().addTransactionSync(tx);
if (result.error != null) {
Expand Down

0 comments on commit 021d510

Please sign in to comment.