Skip to content

Commit

Permalink
Merge pull request #13 from ketola/admission_control_layer
Browse files Browse the repository at this point in the history
Admission control layer
  • Loading branch information
ice09 authored Jul 13, 2019
2 parents 52e5a78 + 10b1dbd commit fb56637
Show file tree
Hide file tree
Showing 16 changed files with 433 additions and 119 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/dev/jlibra/KeyUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@

public class KeyUtils {

public static String toLibraAddress(byte[] publicKeyBytes) {
public static String toHexStringLibraAddress(byte[] publicKeyBytes) {
return new String(Hex.encode(toByteArrayLibraAddress(publicKeyBytes)));
}

public static byte[] toByteArrayLibraAddress(byte[] publicKeyBytes) {
SHA3.DigestSHA3 digestSHA3 = new SHA3.Digest256();
return new String(Hex.encode(digestSHA3.digest(stripPublicKeyPrefix(publicKeyBytes))));
return digestSHA3.digest(stripPublicKeyPrefix(publicKeyBytes));
}

public static byte[] stripPublicKeyPrefix(byte[] pubKeyBytes) {
Expand Down
149 changes: 149 additions & 0 deletions src/main/java/dev/jlibra/admissioncontrol/AdmissionControl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package dev.jlibra.admissioncontrol;

import static java.util.stream.Collectors.toList;

import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.protobuf.ByteString;

import admission_control.AdmissionControlGrpc;
import admission_control.AdmissionControlGrpc.AdmissionControlBlockingStub;
import admission_control.AdmissionControlOuterClass.SubmitTransactionRequest;
import admission_control.AdmissionControlOuterClass.SubmitTransactionResponse;
import dev.jlibra.AccountState;
import dev.jlibra.KeyUtils;
import dev.jlibra.LibraHelper;
import dev.jlibra.admissioncontrol.query.GetAccountState;
import dev.jlibra.admissioncontrol.query.UpdateToLatestLedgerResult;
import dev.jlibra.admissioncontrol.transaction.SubmitTransactionResult;
import dev.jlibra.admissioncontrol.transaction.Transaction;
import dev.jlibra.admissioncontrol.transaction.TransactionArgument.Type;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import types.GetWithProof.GetAccountStateRequest;
import types.GetWithProof.RequestItem;
import types.GetWithProof.UpdateToLatestLedgerRequest;
import types.GetWithProof.UpdateToLatestLedgerResponse;
import types.Transaction.Program;
import types.Transaction.RawTransaction;
import types.Transaction.SignedTransaction;
import types.Transaction.TransactionArgument;
import types.Transaction.TransactionArgument.ArgType;

public class AdmissionControl {

private String host;

private int port;

public AdmissionControl(String host, int port) {
this.host = host;
this.port = port;
}

private static Map<Type, ArgType> jlibraArgumentTypeToGrpcArgumentType;

static {
jlibraArgumentTypeToGrpcArgumentType = new HashMap<>();
jlibraArgumentTypeToGrpcArgumentType.put(Type.ADDRESS, ArgType.ADDRESS);
jlibraArgumentTypeToGrpcArgumentType.put(Type.U64, ArgType.U64);
}

public SubmitTransactionResult submitTransaction(PublicKey publicKey, PrivateKey privateKey,
Transaction transaction) {

ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.build();

AdmissionControlBlockingStub stub = AdmissionControlGrpc.newBlockingStub(channel);

List<TransactionArgument> transactionArguments = transaction.getProgram().getArguments().stream()
.map(txArgument -> TransactionArgument.newBuilder()
.setType(jlibraArgumentTypeToGrpcArgumentType.get(txArgument.type()))
.setData(ByteString.copyFrom(txArgument.toByteArray()))
.build())
.collect(toList());

Program program = Program.newBuilder()
.addAllArguments(transactionArguments)
.setCode(readCodeFromStream(transaction))
.addAllModules(new ArrayList<ByteString>())
.build();

RawTransaction rawTransaction = RawTransaction.newBuilder()
.setProgram(program)
.setExpirationTime(transaction.getExpirationTime())
.setGasUnitPrice(transaction.getGasUnitPrice())
.setMaxGasAmount(transaction.getMaxGasAmount())
.setSenderAccount(ByteString.copyFrom(KeyUtils.toByteArrayLibraAddress(publicKey.getEncoded())))
.setSequenceNumber(transaction.getSequenceNumber())
.build();

SignedTransaction signedTransaction = SignedTransaction.newBuilder()
.setRawTxnBytes(rawTransaction.toByteString())
.setSenderPublicKey(ByteString.copyFrom(KeyUtils.stripPublicKeyPrefix(publicKey.getEncoded())))
.setSenderSignature(ByteString.copyFrom(LibraHelper.signTransaction(rawTransaction, privateKey)))
.build();

SubmitTransactionRequest submitTransactionRequest = SubmitTransactionRequest.newBuilder()
.setSignedTxn(signedTransaction)
.build();

SubmitTransactionResponse response = stub.submitTransaction(submitTransactionRequest);

channel.shutdown();

return new SubmitTransactionResult(response.getAcStatus(), response.getMempoolStatus(), response.getVmStatus());
}

private ByteString readCodeFromStream(Transaction transaction) {
try {
return ByteString.readFrom(transaction.getProgram().getCode());
} catch (IOException e) {
throw new RuntimeException("Could not read move code from input stream", e);
}
}

public UpdateToLatestLedgerResult updateToLatestLedger(List<GetAccountState> arguments) {
ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.build();

AdmissionControlBlockingStub stub = AdmissionControlGrpc.newBlockingStub(channel);

List<RequestItem> requestItems = arguments.stream().map(argument -> {
GetAccountStateRequest getAccountStateRequest = GetAccountStateRequest.newBuilder()
.setAddress(ByteString.copyFrom(argument.getAddress()))
.build();

RequestItem requestItem = RequestItem.newBuilder()
.setGetAccountStateRequest(getAccountStateRequest)
.build();
return requestItem;
}).collect(toList());

UpdateToLatestLedgerResponse response = stub.updateToLatestLedger(UpdateToLatestLedgerRequest.newBuilder()
.addAllRequestedItems(requestItems)
.build());

List<AccountState> accountStates = new ArrayList<>();

response.getResponseItemsList().forEach(responseItem -> {
accountStates.addAll(LibraHelper.readAccountStates(responseItem.getGetAccountStateResponse()
.getAccountStateWithProof()));
});

UpdateToLatestLedgerResult result = UpdateToLatestLedgerResult.create()
.withAccountStates(accountStates);

return result;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dev.jlibra.admissioncontrol.query;

public class GetAccountState {
private byte[] address;

public GetAccountState(byte[] address) {
this.address = address;
}

public byte[] getAddress() {
return address;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.jlibra.admissioncontrol.query;

import java.util.List;

import dev.jlibra.AccountState;

public class UpdateToLatestLedgerResult {

private List<AccountState> accountStates;

private UpdateToLatestLedgerResult() {
}

public static UpdateToLatestLedgerResult create() {
return new UpdateToLatestLedgerResult();
}

public UpdateToLatestLedgerResult withAccountStates(List<AccountState> accountStates) {
this.accountStates = accountStates;
return this;
}

public List<AccountState> getAccountStates() {
return accountStates;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package dev.jlibra.admissioncontrol.transaction;

public class AddressArgument implements TransactionArgument {

private byte[] address;

public AddressArgument(byte[] address) {
this.address = address;
}

@Override
public byte[] toByteArray() {
return address;
}

@Override
public Type type() {
return Type.ADDRESS;
}

}
25 changes: 25 additions & 0 deletions src/main/java/dev/jlibra/admissioncontrol/transaction/Program.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.jlibra.admissioncontrol.transaction;

import java.io.InputStream;
import java.util.List;

public class Program {

private InputStream code;

private List<TransactionArgument> arguments;

public Program(InputStream code, List<TransactionArgument> arguments) {
this.code = code;
this.arguments = arguments;
}

public InputStream getCode() {
return code;
}

public List<TransactionArgument> getArguments() {
return arguments;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.jlibra.admissioncontrol.transaction;

import admission_control.AdmissionControlOuterClass.AdmissionControlStatus;
import mempool.MempoolStatus;
import types.VmErrors.VMStatus;

public class SubmitTransactionResult {

// TODO: Create own enum types instead of putting grpc enums directly here
// Could also add the description texts for clearer errors

private AdmissionControlStatus admissionControlStatus;

private MempoolStatus.MempoolAddTransactionStatus mempoolStatus;

private VMStatus vmStatus;

public SubmitTransactionResult(AdmissionControlStatus admissionControlStatus,
MempoolStatus.MempoolAddTransactionStatus mempoolStatus,
VMStatus vmStatus) {
this.admissionControlStatus = admissionControlStatus;
this.mempoolStatus = mempoolStatus;
this.vmStatus = vmStatus;
}

public AdmissionControlStatus getAdmissionControlStatus() {
return admissionControlStatus;
}

public MempoolStatus.MempoolAddTransactionStatus getMempoolStatus() {
return mempoolStatus;
}

public VMStatus getVmStatus() {
return vmStatus;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package dev.jlibra.admissioncontrol.transaction;

public class Transaction {

private long sequenceNumber;

private Program program;

private long expirationTime;

private long gasUnitPrice;

private long maxGasAmount;

private Transaction() {
}

public static Transaction create() {
return new Transaction();
}

public Transaction withProgram(Program program) {
this.program = program;
return this;
}

public Transaction withSequenceNumber(long sequenceNumber) {
this.sequenceNumber = sequenceNumber;
return this;
}

public Transaction withExpirationTime(long expirationTime) {
this.expirationTime = expirationTime;
return this;
}

public Transaction withGasUnitPrice(long gasUnitPrice) {
this.gasUnitPrice = gasUnitPrice;
return this;
}

public Transaction withMaxGasAmount(long maxGasAmount) {
this.maxGasAmount = maxGasAmount;
return this;
}

public long getSequenceNumber() {
return sequenceNumber;
}

public Program getProgram() {
return program;
}

public long getExpirationTime() {
return expirationTime;
}

public long getGasUnitPrice() {
return gasUnitPrice;
}

public long getMaxGasAmount() {
return maxGasAmount;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dev.jlibra.admissioncontrol.transaction;

public interface TransactionArgument {

public enum Type {
U64, ADDRESS
}

byte[] toByteArray();

Type type();

}
Loading

0 comments on commit fb56637

Please sign in to comment.