diff --git a/bindings/java/.gitignore b/bindings/java/.gitignore index 69c31f776..ec196c5b2 100644 --- a/bindings/java/.gitignore +++ b/bindings/java/.gitignore @@ -7,4 +7,12 @@ c/build/* *.dylib .DS_Store .gradle -build \ No newline at end of file +build +.classpath +.project +.settings/ +java/.classpath +java/.project +java/.settings/ +java/bin/ +java/hs_err_pid* \ No newline at end of file diff --git a/bindings/java/c/evmc-vm.c b/bindings/java/c/evmc-vm.c index fbae0cfa4..e8693c218 100644 --- a/bindings/java/c/evmc-vm.c +++ b/bindings/java/c/evmc-vm.c @@ -7,43 +7,6 @@ #include "evmc-vm.h" #include "host.h" - -JNIEXPORT jint JNICALL Java_org_ethereum_evmc_EvmcVm_test(JNIEnv* jenv, jclass jcls, jobject jbuffer){ - struct test_struct{ - int one; - long two; - int int1; - int int2; - char three; - long four; - char five[11]; - }; - - struct test_struct *test = (struct test_struct *) (*jenv)->GetDirectBufferAddress(jenv, jbuffer); - - struct test_struct *dummy =malloc (sizeof (struct test_struct)); - printf("struct: dummy=%p, test=%p\n",dummy,test); - printf("one: dummy=%p, test=%p\n",&dummy->one,&test->one); - printf("two: dummy=%p, test=%p\n",&dummy->two,&test->two); - printf("int1: dummy=%p, test=%p\n",&dummy->int1,&test->int1); - printf("int2: dummy=%p, test=%p\n",&dummy->int2,&test->int2); - printf("three: dummy=%p, test=%p\n",&dummy->three,&test->three); - printf("four: dummy=%p, test=%p\n",&dummy->four, &test->four); - printf("five: dummy=%p, test=%p\n\n",&dummy->five,&test->five); - - printf("one=%d\n",test->one); - printf("two=%ld\n",test->two); - printf("int1=%d\n",test->int1); - printf("int2=%d\n",test->int2); - printf("three=%c\n",test->three); - printf("four=%ld\n",test->four); - printf("five=%s\n",test->five); - - return 0; - - -} - JNIEXPORT jint JNICALL Java_org_ethereum_evmc_EvmcVm_init(JNIEnv* jenv, jclass jcls, jstring jfilename) { jint rs = (*jenv)->GetJavaVM(jenv, &jvm); @@ -55,15 +18,14 @@ JNIEXPORT jint JNICALL Java_org_ethereum_evmc_EvmcVm_init(JNIEnv* jenv, jclass j evm_handle = evmc_load_and_create(filename, &loader_error); if (evm_handle == NULL || loader_error != EVMC_LOADER_SUCCESS) { const char *error_msg = evmc_last_error_msg(); - printf("EVMC loading error: %s\n", error_msg); - exit(EXIT_FAILURE); + (*jenv)->ThrowNew(jenv, jcls, error_msg); } (*jenv)->ReleaseStringUTFChars(jenv, jfilename, filename); // instantiate the EVMC host interface host = malloc (sizeof (struct evmc_host_interface)); if (host == NULL) { - exit(EXIT_FAILURE); + (*jenv)->ThrowNew(jenv, jcls, "JNI error: Couldn't instantiate EVMC host interface"); } host->account_exists = account_exists_fn; diff --git a/bindings/java/c/evmc-vm.h b/bindings/java/c/evmc-vm.h index 8143486cb..1e3ec31c4 100644 --- a/bindings/java/c/evmc-vm.h +++ b/bindings/java/c/evmc-vm.h @@ -1,4 +1,3 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class org_ethereum_evmc_EvmcVm */ @@ -8,8 +7,6 @@ extern "C" { #endif -JNIEXPORT jint JNICALL Java_org_ethereum_evmc_EvmcVm_test - (JNIEnv *, jclass, jobject); /* * Class: org_ethereum_evmc_EvmcVm * Method: init diff --git a/bindings/java/c/host.c b/bindings/java/c/host.c index 78fa21e70..28c652edd 100644 --- a/bindings/java/c/host.c +++ b/bindings/java/c/host.c @@ -8,12 +8,11 @@ static const int BYTES32_SIZE = 32; bool account_exists_fn(struct evmc_host_context* context, const evmc_address* address){ printf("********************account_exists_fn*******************\n"); - JNIEnv *jenv; + bool result = false; const char java_method_name[] = "account_exists"; const char java_method_signature[] = "(I[B)I"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -23,6 +22,7 @@ bool account_exists_fn(struct evmc_host_context* context, const evmc_address* ad //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -45,6 +45,7 @@ bool account_exists_fn(struct evmc_host_context* context, const evmc_address* ad (*jenv)->SetByteArrayRegion(jenv, jaddress, 0, ADDRESS_SIZE, (jbyte *)address); if(!jcontext_index || !jaddress){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -57,12 +58,11 @@ bool account_exists_fn(struct evmc_host_context* context, const evmc_address* ad evmc_bytes32 get_storage_fn(struct evmc_host_context* context, const evmc_address* address, const evmc_bytes32* key){ printf("********************get_storage_fn*******************\n"); - JNIEnv *jenv; + evmc_bytes32 result; const char java_method_name[] = "get_storage"; const char java_method_signature[] = "(I[B[B)Ljava/nio/ByteBuffer;"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -72,6 +72,7 @@ evmc_bytes32 get_storage_fn(struct evmc_host_context* context, const evmc_addres //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -97,6 +98,7 @@ evmc_bytes32 get_storage_fn(struct evmc_host_context* context, const evmc_addres (*jenv)->SetByteArrayRegion(jenv, jkey, 0, BYTES32_SIZE, (jbyte *)key); if(!jcontext_index || !jaddress || !jkey){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -116,12 +118,11 @@ evmc_bytes32 get_storage_fn(struct evmc_host_context* context, const evmc_addres enum evmc_storage_status set_storage_fn(struct evmc_host_context* context, const evmc_address* address, const evmc_bytes32* key, const evmc_bytes32* value){ printf("********************set_storage_fn*******************\n"); - JNIEnv *jenv; + enum evmc_storage_status result; const char java_method_name[] = "set_storage"; const char java_method_signature[] = "(I[B[B[B)I"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -132,6 +133,7 @@ enum evmc_storage_status set_storage_fn(struct evmc_host_context* context, const //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -159,6 +161,7 @@ enum evmc_storage_status set_storage_fn(struct evmc_host_context* context, const (*jenv)->SetByteArrayRegion(jenv, jvalue, 0, BYTES32_SIZE, (jbyte *)value); if(!jcontext_index || !jaddress || !jkey || !jvalue){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } //call java method @@ -170,12 +173,11 @@ enum evmc_storage_status set_storage_fn(struct evmc_host_context* context, const evmc_uint256be get_balance_fn(struct evmc_host_context* context, const evmc_address* address){ printf("********************get_balance_fn*******************\n"); - JNIEnv *jenv; + evmc_uint256be result; char java_method_name[] = "get_balance"; char java_method_signature[] = "(I[B)Ljava/nio/ByteBuffer;"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -185,6 +187,7 @@ evmc_uint256be get_balance_fn(struct evmc_host_context* context, const evmc_addr //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -207,6 +210,7 @@ evmc_uint256be get_balance_fn(struct evmc_host_context* context, const evmc_addr (*jenv)->SetByteArrayRegion(jenv, jaddress, 0, ADDRESS_SIZE, (jbyte *)address); if(!jcontext_index || !jaddress){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -228,12 +232,11 @@ evmc_uint256be get_balance_fn(struct evmc_host_context* context, const evmc_addr size_t get_code_size_fn(struct evmc_host_context* context,const evmc_address* address){ printf("********************get_code_size_fn*******************\n"); - JNIEnv *jenv; + size_t result = 0; char java_method_name[] = "get_code_size"; char java_method_signature[] = "(I[B)I"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -243,6 +246,7 @@ size_t get_code_size_fn(struct evmc_host_context* context,const evmc_address* ad //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -265,6 +269,7 @@ size_t get_code_size_fn(struct evmc_host_context* context,const evmc_address* ad (*jenv)->SetByteArrayRegion(jenv, jaddress, 0, ADDRESS_SIZE, (jbyte *)address); if(!jcontext_index || !jaddress){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -277,12 +282,11 @@ size_t get_code_size_fn(struct evmc_host_context* context,const evmc_address* ad evmc_bytes32 get_code_hash_fn(struct evmc_host_context* context, const evmc_address* address){ printf("********************get_code_hash_fn*******************\n"); - JNIEnv *jenv; + evmc_bytes32 result; char java_method_name[] = "get_code_hash"; char java_method_signature[] = "(I[B)Ljava/nio/ByteBuffer;"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -292,6 +296,7 @@ evmc_bytes32 get_code_hash_fn(struct evmc_host_context* context, const evmc_addr //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -314,6 +319,7 @@ evmc_bytes32 get_code_hash_fn(struct evmc_host_context* context, const evmc_addr (*jenv)->SetByteArrayRegion(jenv, jaddress, 0, ADDRESS_SIZE, (jbyte *)address); if(!jcontext_index || !jaddress ){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -335,12 +341,11 @@ evmc_bytes32 get_code_hash_fn(struct evmc_host_context* context, const evmc_addr size_t copy_code_fn(struct evmc_host_context* context, const evmc_address* address, size_t code_offset, uint8_t* buffer_data, size_t buffer_size){ printf("********************copy_code_fn*******************\n"); - JNIEnv *jenv; + size_t result; const char java_method_name[] = "copy_code"; const char java_method_signature[] = "(I[BI)Ljava/nio/ByteBuffer;"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -351,6 +356,7 @@ size_t copy_code_fn(struct evmc_host_context* context, const evmc_address* addre //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -375,6 +381,7 @@ size_t copy_code_fn(struct evmc_host_context* context, const evmc_address* addre jcode_offset = code_offset; if(!jcontext_index || !jaddress || !jcode_offset){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -400,11 +407,10 @@ size_t copy_code_fn(struct evmc_host_context* context, const evmc_address* addre void selfdestruct_fn(struct evmc_host_context* context, const evmc_address* address, const evmc_address* beneficiary){ printf("********************selfdestruct_fn*******************\n"); - JNIEnv *jenv; + const char java_method_name[] = "selfdestruct"; const char java_method_signature[] = "(I[B[B)V"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -415,6 +421,7 @@ void selfdestruct_fn(struct evmc_host_context* context, const evmc_address* addr //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -440,6 +447,7 @@ void selfdestruct_fn(struct evmc_host_context* context, const evmc_address* addr (*jenv)->SetByteArrayRegion(jenv, jbeneficiary, 0, ADDRESS_SIZE, (jbyte *)beneficiary); if(!jcontext_index || !jaddress){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -451,12 +459,11 @@ void selfdestruct_fn(struct evmc_host_context* context, const evmc_address* addr struct evmc_result call_fn(struct evmc_host_context* context, const struct evmc_message* msg){ printf("********************call_fn*******************\n"); - JNIEnv *jenv; + struct evmc_result result; const char java_method_name[] = "call"; const char java_method_signature[] = "(ILjava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -466,6 +473,7 @@ struct evmc_result call_fn(struct evmc_host_context* context, const struct evmc_ //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -488,6 +496,7 @@ struct evmc_result call_fn(struct evmc_host_context* context, const struct evmc_ jmsg = (*jenv)->NewDirectByteBuffer(jenv, (void*) msg, sizeof(struct evmc_message)); if(!jcontext_index || !jmsg){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -507,12 +516,11 @@ struct evmc_result call_fn(struct evmc_host_context* context, const struct evmc_ struct evmc_tx_context get_tx_context_fn(struct evmc_host_context* context){ printf("********************get_tx_context_fn*******************\n"); - JNIEnv *jenv; + struct evmc_tx_context result; const char java_method_name[] = "get_tx_context"; const char java_method_signature[] = "(I)Ljava/nio/ByteBuffer;"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -520,6 +528,7 @@ struct evmc_tx_context get_tx_context_fn(struct evmc_host_context* context){ //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -540,6 +549,7 @@ struct evmc_tx_context get_tx_context_fn(struct evmc_host_context* context){ jcontext_index = context->index; if(!jcontext_index){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -560,12 +570,11 @@ struct evmc_tx_context get_tx_context_fn(struct evmc_host_context* context){ evmc_bytes32 get_block_hash_fn(struct evmc_host_context* context, int64_t number){ printf("********************get_block_hash_fn*******************\n"); - JNIEnv *jenv; + evmc_bytes32 result; char java_method_name[] = "get_code_hash"; char java_method_signature[] = "(IJ)Ljava/nio/ByteBuffer;"; - jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); - assert (rs == JNI_OK); + JNIEnv *jenv = attach(); if(jenv != NULL) { jclass host_class; jmethodID method; @@ -575,6 +584,7 @@ evmc_bytes32 get_block_hash_fn(struct evmc_host_context* context, int64_t number //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -599,6 +609,7 @@ evmc_bytes32 get_block_hash_fn(struct evmc_host_context* context, int64_t number jnumber = (jlong)number; if(!jcontext_index || !jnumber ){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -618,10 +629,11 @@ evmc_bytes32 get_block_hash_fn(struct evmc_host_context* context, int64_t number void emit_log_fn(struct evmc_host_context* context, const evmc_address* address, const uint8_t* data, size_t data_size, const evmc_bytes32 topics[], size_t topics_count){ printf("********************emit_log_fn*******************\n"); - JNIEnv *jenv; + const char java_method_name[] = "emit_log"; const char java_method_signature[] = "(I[B[BI[[BI)V"; - if(jenv != NULL) { + JNIEnv *jenv = attach(); + if(jenv != NULL) { jclass host_class; jmethodID method; jint jcontext_index; @@ -632,6 +644,7 @@ void emit_log_fn(struct evmc_host_context* context, const evmc_address* address, //get java class host_class = (*jenv)->FindClass(jenv, "org/ethereum/evmc/Host"); if(!host_class){ + printf("JNI Error: FindClass was unable to load the Host class\n"); detach(jenv); } @@ -669,6 +682,7 @@ void emit_log_fn(struct evmc_host_context* context, const evmc_address* address, } if(!jcontext_index || !jaddress || !jdata || !jtopics){ + printf("JNI Error: method params could not be initialized for method: %s\n",java_method_name); detach(jenv); } @@ -678,6 +692,13 @@ void emit_log_fn(struct evmc_host_context* context, const evmc_address* address, return; } +JNIEnv* attach() { + JNIEnv *jenv; + jint rs = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL); + assert (rs == JNI_OK); + return jenv; +} + void detach(JNIEnv* jenv){ if((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); diff --git a/bindings/java/c/host.h b/bindings/java/c/host.h index 30f607914..3f8f733f7 100644 --- a/bindings/java/c/host.h +++ b/bindings/java/c/host.h @@ -8,8 +8,8 @@ extern "C" { #endif JavaVM *jvm; -static struct evmc_vm *evm_handle; -static struct evmc_host_interface *host; +struct evmc_vm *evm_handle; +struct evmc_host_interface *host; struct evmc_result result; struct evmc_host_context{ int index; @@ -39,6 +39,8 @@ evmc_bytes32 get_block_hash_fn(struct evmc_host_context*, int64_t); void emit_log_fn(struct evmc_host_context*, const evmc_address*, const uint8_t*, size_t, const evmc_bytes32[], size_t); +JNIEnv* attach(); + void detach(JNIEnv*); #ifdef __cplusplus diff --git a/bindings/java/java/src/main/java/org/ethereum/evmc/EvmcVm.java b/bindings/java/java/src/main/java/org/ethereum/evmc/EvmcVm.java index 3167e09f5..272d5c7c7 100644 --- a/bindings/java/java/src/main/java/org/ethereum/evmc/EvmcVm.java +++ b/bindings/java/java/src/main/java/org/ethereum/evmc/EvmcVm.java @@ -1,9 +1,9 @@ package org.ethereum.evmc; +import static org.ethereum.evmc.Host.addContext; +import static org.ethereum.evmc.Host.removeContext; + import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; /** * The Java interface to the evm instance. @@ -12,17 +12,29 @@ */ public final class EvmcVm { - static { + /** + * This method loads the specified evm shared library and loads/initializes the jni bindings. + * + * @param filename /path/filename of the evm shared object + */ + public static void create(String filename) { try { + // load so containing the jni bindings to evmc System.load(System.getProperty("user.dir") + "/../c/build/evmc.so"); + // initialize jni and load EVM shared library + init(filename); } catch (UnsatisfiedLinkError e) { System.err.println("Native code library failed to load.\n" + e); System.exit(1); } } - public static native int test(ByteBuffer buff); - + /** + * This method loads the specified evm implementation and initializes jni + * + * @param filename path + filename of the evm shared object to load + * @return + */ public static native int init(String filename); /** @@ -61,7 +73,7 @@ public final class EvmcVm { * *

This is a mandatory method and MUST NOT be set to NULL. */ - public static native ByteBuffer execute( + static native ByteBuffer execute( int context_index, int rev, ByteBuffer msg, ByteBuffer code, int size); /** * Function is a wrapper around native execute. @@ -94,20 +106,4 @@ public static synchronized ByteBuffer execute( *

If the VM does not support this feature the pointer can be NULL. */ public static native int set_option(String name, String value); - - private static List contextList = - Collections.synchronizedList(new ArrayList()); - - public static HostContext getContext(int index) { - return contextList.get(index); - } - - public static int addContext(HostContext context) { - contextList.add(context); - return contextList.size() - 1; - } - - public static void removeContext(int index) { - contextList.remove(index); - } } diff --git a/bindings/java/java/src/main/java/org/ethereum/evmc/Host.java b/bindings/java/java/src/main/java/org/ethereum/evmc/Host.java index 681829b31..fe7c16e27 100644 --- a/bindings/java/java/src/main/java/org/ethereum/evmc/Host.java +++ b/bindings/java/java/src/main/java/org/ethereum/evmc/Host.java @@ -1,54 +1,78 @@ package org.ethereum.evmc; -import static org.ethereum.evmc.EvmcVm.getContext; +import static java.util.Objects.requireNonNull; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * The Host interface. * *

The set of all callback functions expected by VM instances. */ -public final class Host { +final class Host { /** Check account existence callback function. */ - public static int account_exists(int context_index, byte[] address) { - HostContext context = getContext(context_index); + static int account_exists(int context_index, byte[] address) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.accountExists(address) ? 1 : 0; } /** Get storage callback function. */ - public static ByteBuffer get_storage(int context_index, byte[] address, byte[] key) { - HostContext context = getContext(context_index); + static ByteBuffer get_storage(int context_index, byte[] address, byte[] key) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.getStorage(address, key); } /** Set storage callback function. */ - public static int set_storage(int context_index, byte[] address, byte[] key, byte[] value) { - HostContext context = getContext(context_index); + static int set_storage(int context_index, byte[] address, byte[] key, byte[] value) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.setStorage(address, key, value); } /** Get balance callback function. */ - public static ByteBuffer get_balance(int context_index, byte[] address) { - HostContext context = getContext(context_index); + static ByteBuffer get_balance(int context_index, byte[] address) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.getBalance(address); } /** Get code size callback function. */ - public static int get_code_size(int context_index, byte[] address) { - HostContext context = getContext(context_index); + static int get_code_size(int context_index, byte[] address) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.getCodeSize(address); } /** Get code hash callback function. */ - public static ByteBuffer get_code_hash(int context_index, byte[] address) { - HostContext context = getContext(context_index); + static ByteBuffer get_code_hash(int context_index, byte[] address) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.getCodeHash(address); } /** Copy code callback function. */ - public static ByteBuffer copy_code(int context_index, byte[] address, int code_offset) { - HostContext context = getContext(context_index); + static ByteBuffer copy_code(int context_index, byte[] address, int code_offset) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); byte[] code = context.getCode(address).array(); if (code != null && code_offset > 0 && code_offset < code.length) { @@ -60,38 +84,68 @@ public static ByteBuffer copy_code(int context_index, byte[] address, int code_o } /** Selfdestruct callback function. */ - public static void selfdestruct(int context_index, byte[] address, byte[] beneficiary) { - HostContext context = getContext(context_index); + static void selfdestruct(int context_index, byte[] address, byte[] beneficiary) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); context.selfdestruct(address, beneficiary); } /** Call callback function. */ - public static ByteBuffer call(int context_index, ByteBuffer msg) { - HostContext context = getContext(context_index); + static ByteBuffer call(int context_index, ByteBuffer msg) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.call(msg); } /** Get transaction context callback function. */ - public static ByteBuffer get_tx_context(int context_index) { - HostContext context = getContext(context_index); + static ByteBuffer get_tx_context(int context_index) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.getTxContext(); } /** Get block hash callback function. */ - public static ByteBuffer get_block_hash_fn(int context_index, long number) { - HostContext context = getContext(context_index); + static ByteBuffer get_block_hash_fn(int context_index, long number) { + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); return context.getBlockHash(number); } /** Emit log callback function. */ - public static void emit_log( + static void emit_log( int context_index, byte[] address, byte[] data, int data_size, byte[][] topics, int topic_count) { - HostContext context = getContext(context_index); + HostContext context = + requireNonNull( + getContext(context_index), + "HostContext does not exist for context_index: " + context_index); context.emitLog(address, data, data_size, topics, topic_count); } + + static HostContext getContext(int index) { + return contextList.get(index); + } + + static synchronized int addContext(HostContext context) { + contextList.add(context); + return contextList.size() - 1; + } + + static void removeContext(int index) { + contextList.remove(index); + } + + private static List contextList = Collections.synchronizedList(new ArrayList<>()); } diff --git a/bindings/java/java/src/main/java/org/ethereum/evmc/HostContext.java b/bindings/java/java/src/main/java/org/ethereum/evmc/HostContext.java index 428caa869..b3ddf1a6c 100644 --- a/bindings/java/java/src/main/java/org/ethereum/evmc/HostContext.java +++ b/bindings/java/java/src/main/java/org/ethereum/evmc/HostContext.java @@ -2,6 +2,10 @@ import java.nio.ByteBuffer; +/** + * This interface represents the callback functions must be implemented in order to interface with + * the EVM. + */ public interface HostContext { /** diff --git a/bindings/java/java/src/test/java/org/ethereum/evmc/EvmcTest.java b/bindings/java/java/src/test/java/org/ethereum/evmc/EvmcTest.java index 816b0671e..2144e80a7 100644 --- a/bindings/java/java/src/test/java/org/ethereum/evmc/EvmcTest.java +++ b/bindings/java/java/src/test/java/org/ethereum/evmc/EvmcTest.java @@ -2,21 +2,19 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.CharBuffer; -import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; final class EvmcTest { @Test void testInit() { - int result = EvmcVm.init(System.getProperty("user.dir") + "/../c/build/example_vm.so"); - assert (result == 0); + Assertions.assertDoesNotThrow( + () -> EvmcVm.create(System.getProperty("user.dir") + "/../c/build/example_vm.so")); } @Test void test_return_address() { - EvmcVm.init(System.getProperty("user.dir") + "/../c/build/example_vm.so"); + EvmcVm.create(System.getProperty("user.dir") + "/../c/build/example_vm.so"); HostContext context = new TestHostContext(); int BYZANTIUM = 4; int EVMC_CALL = 0; @@ -45,7 +43,7 @@ void test_return_address() { /** Tests callbacks: get_storage_fn & set_storage_fn */ @Test void test_counter() { - EvmcVm.init(System.getProperty("user.dir") + "/../c/build/example_vm.so"); + EvmcVm.create(System.getProperty("user.dir") + "/../c/build/example_vm.so"); HostContext context = new TestHostContext(); int BYZANTIUM = 4; int EVMC_CALL = 0; @@ -74,7 +72,7 @@ void test_counter() { /** Tests callbacks: get_tx_context_fn */ @Test void test_return_block_number() { - EvmcVm.init(System.getProperty("user.dir") + "/../c/build/example_vm.so"); + EvmcVm.create(System.getProperty("user.dir") + "/../c/build/example_vm.so"); HostContext context = new TestHostContext(); int BYZANTIUM = 4; int EVMC_CALL = 0; @@ -103,7 +101,7 @@ void test_return_block_number() { /** Tests callbacks: get_tx_context_fn & set_storage_fn */ @Test void test_save_return_block_number() { - EvmcVm.init(System.getProperty("user.dir") + "/../c/build/example_vm.so"); + EvmcVm.create(System.getProperty("user.dir") + "/../c/build/example_vm.so"); HostContext context = new TestHostContext(); int BYZANTIUM = 4; int EVMC_CALL = 0; @@ -134,7 +132,7 @@ void test_save_return_block_number() { /** Tests callbacks: call_fn */ @Test void test_make_a_call() { - EvmcVm.init(System.getProperty("user.dir") + "/../c/build/example_vm.so"); + EvmcVm.create(System.getProperty("user.dir") + "/../c/build/example_vm.so"); HostContext context = new TestHostContext(); int BYZANTIUM = 4; int EVMC_CALL = 0; @@ -166,12 +164,12 @@ void test_make_a_call() { result.getInt(); // padding long gasLeft = result.getLong(); assert (statusCode == 0); - assert (gasLeft == 0); + assert (gasLeft == 0); // gas - gas / 64); } @Test void test_EVMC_CREATE() { - EvmcVm.init(System.getProperty("user.dir") + "/../c/build/example_vm.so"); + EvmcVm.create(System.getProperty("user.dir") + "/../c/build/example_vm.so"); HostContext context = new TestHostContext(); int BYZANTIUM = 4; int EVMC_CREATE = 3; @@ -195,33 +193,4 @@ void test_EVMC_CREATE() { assert (statusCode == 0); assert (gasLeft == gas / 10); } - - @Disabled - @Test - void testDirectByteBuffer() { - int one = 1; // 4 bytes - long two = 2; // 8 bytes - int int1 = 1; // 4 bytes - int int2 = 2; // 4 bytes - char three = '3'; // 2 bytes (one for the null terminator) - long four = 4; // 8 bytes - char[] five = "Hello World".toCharArray(); // 12 bytes - System.out.println( - "LENGTH = " + StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(five)).array().length); - ByteBuffer bb = - ByteBuffer.allocateDirect(56) - .order(ByteOrder.nativeOrder()) - .putInt(one) - .put(new byte[4]) - .putLong(two) - .putInt(int1) - .putInt(int2) - .putChar(three) - .put(new byte[6]) - .putLong(four) - .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(five))); - - int result = EvmcVm.test(bb); - assert (result == 0); - } } diff --git a/bindings/java/java/src/test/java/org/ethereum/evmc/TestHostContext.java b/bindings/java/java/src/test/java/org/ethereum/evmc/TestHostContext.java index a985826d5..1a387d2fc 100644 --- a/bindings/java/java/src/test/java/org/ethereum/evmc/TestHostContext.java +++ b/bindings/java/java/src/test/java/org/ethereum/evmc/TestHostContext.java @@ -44,6 +44,15 @@ public void selfdestruct(byte[] address, byte[] beneficiary) {} @Override public ByteBuffer call(ByteBuffer msg) { + + /*TestMessage message = new TestMessage(msg); + return ByteBuffer.allocateDirect(64) + .order(ByteOrder.nativeOrder()) + .putInt(0) // success + .putInt(0) // padding + .putLong(message.gas) + .put(new byte[40]);*/ + return ByteBuffer.allocateDirect(64).put(new byte[64]); } diff --git a/bindings/java/java/src/test/java/org/ethereum/evmc/TestMessage.java b/bindings/java/java/src/test/java/org/ethereum/evmc/TestMessage.java index 137063d6e..77b8ca2bb 100644 --- a/bindings/java/java/src/test/java/org/ethereum/evmc/TestMessage.java +++ b/bindings/java/java/src/test/java/org/ethereum/evmc/TestMessage.java @@ -50,23 +50,38 @@ public TestMessage( this.createSalt = new byte[32]; } + public TestMessage(ByteBuffer msg) { + this.kind = msg.getInt(); + this.flags = msg.getInt(); + this.depth = msg.getInt(); + msg.getInt(); // padding + this.gas = msg.getLong(); + ByteBuffer tmpbuf = msg.get(new byte[20]); + this.destination = StandardCharsets.ISO_8859_1.decode(tmpbuf).array(); + tmpbuf = msg.get(new byte[20]); + this.sender = StandardCharsets.ISO_8859_1.decode(tmpbuf).array(); + tmpbuf = msg.get(new byte[8]); + this.inputData = StandardCharsets.ISO_8859_1.decode(tmpbuf).array(); + this.inputSize = msg.getLong(); + tmpbuf = msg.get(new byte[32]); + this.value = StandardCharsets.ISO_8859_1.decode(tmpbuf).array(); + this.createSalt = msg.get(new byte[32]).array(); + } + public ByteBuffer toByteBuffer() { - ByteBuffer bb = - ByteBuffer.allocateDirect(152) - .order(ByteOrder.nativeOrder()) - .putInt(kind) // 4 - .putInt(flags) // 4 - .putInt(depth) // 4 - .put(new byte[4]) // 4 (padding) - .putLong(gas) // 8 - .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(destination))) // 20 - .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(sender))) // 20 - .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(inputData))) // 8 - .putLong(inputSize) // 8 - .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(value))) // 32 - .put(createSalt); // 32 - System.out.println(bb); - return bb; + return ByteBuffer.allocateDirect(152) + .order(ByteOrder.nativeOrder()) + .putInt(kind) // 4 + .putInt(flags) // 4 + .putInt(depth) // 4 + .put(new byte[4]) // 4 (padding) + .putLong(gas) // 8 + .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(destination))) // 20 + .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(sender))) // 20 + .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(inputData))) // 8 + .putLong(inputSize) // 8 + .put(StandardCharsets.ISO_8859_1.encode(CharBuffer.wrap(value))) // 32 + .put(createSalt); // 32 } } diff --git a/circle.yml b/circle.yml index 8bf839591..8197352a3 100644 --- a/circle.yml +++ b/circle.yml @@ -193,7 +193,7 @@ jobs: - run: name: "Java Test" command: | - cd bindings/java && make test + cd bindings/java && make test bindings-rust: docker: