stringCandidateMethodEntry : candidateMethods.entrySet()) {
- final CandidateMethod candidate = stringCandidateMethodEntry.getValue();
- if (candidate.getCurrentState() == CandidateMethod.State.DISALLOWED) {
- out.add(stringCandidateMethodEntry.getKey());
- }
- }
-
- return out;
- }
-
- @Override
- public String toString() {
- return "CandidacyStatus{" + "candidateMethods=" + candidateMethods + ", backlog=" + backlog + ", contextLoader=" + contextLoader + ", loadable=" + loadable + ", reason=" + reason + ", recursiveDepth=" + recursiveDepth + '}';
- }
-
- @Override
- public int hashCode() {
- int hash = 5;
- hash = 53 * hash + Objects.hashCode(this.candidateMethods);
- hash = 53 * hash + Objects.hashCode(this.backlog);
- hash = 53 * hash + Objects.hashCode(this.contextLoader);
- hash = 53 * hash + (this.loadable ? 1 : 0);
- hash = 53 * hash + Objects.hashCode(this.reason);
- hash = 53 * hash + this.recursiveDepth;
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- final CandidacyStatus other = (CandidacyStatus) obj;
- if (!Objects.equals(this.candidateMethods, other.candidateMethods))
- return false;
- if (!Objects.equals(this.backlog, other.backlog))
- return false;
- if (!Objects.equals(this.contextLoader, other.contextLoader))
- return false;
- if (this.loadable != other.loadable)
- return false;
- if (!Objects.equals(this.reason, other.reason))
- return false;
- return this.recursiveDepth == other.recursiveDepth;
- }
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/CandidateMethod.java b/experimental/sandbox/src/main/java/net/corda/sandbox/CandidateMethod.java
deleted file mode 100644
index bc7a1cd7a1..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/CandidateMethod.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox;
-
-import java.lang.invoke.MethodType;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A candidate method that is under evaluation. Candidate methods have one of the following states:
- *
- *
- * - {@link CandidateMethod.State#DETERMINISTIC} - It's deterministic and therefore is allowed to be loaded.
- * - {@link CandidateMethod.State#DISALLOWED} - It's not deterministic and won't be allowed to be loaded.
- * - {@link CandidateMethod.State#SCANNED} - We're not sure if it's deterministic or not.
- *
- *
- * CandidateMethods themselves reference other CandidateMethods which are be checked for their deterministic state
- */
-public final class CandidateMethod {
-
- // The state model must reflect the difference between "mentioned in an API" and
- // "scanned by classloader"
- public enum State {
- DETERMINISTIC,
- MENTIONED,
- SCANNED,
- DISALLOWED
- }
-
- private State currentState = State.MENTIONED;
-
- private String reason;
-
- private CandidateMethod(String methodSignature) {
- internalMethodName = methodSignature;
- }
-
- // TODO We'll likely use the formal MethodType for deeper analysis
- private MethodType methodType;
-
- // Internal method name as it appears in the constant pool
- private final String internalMethodName;
-
- private final Set referencedCandidateMethods = new HashSet<>();
-
-
- public State getCurrentState() {
- return currentState;
- }
-
- public void setCurrentState(final State currentState) {
- this.currentState = currentState;
- }
-
- public void disallowed(final String because) {
- reason = because;
- currentState = State.DISALLOWED;
- }
-
- public void deterministic() {
- if (currentState == State.DISALLOWED) {
- throw new IllegalArgumentException("Method " + internalMethodName + " attempted to transition from DISALLOWED to DETERMINISTIC");
- }
- currentState = State.DETERMINISTIC;
- }
-
- public void scanned() {
- currentState = State.SCANNED;
- }
-
- public String getReason() {
- return reason;
- }
-
- public void setReason(String reason) {
- this.reason = reason;
- }
-
- public String getInternalMethodName() {
- return internalMethodName;
- }
-
- public void addReferencedCandidateMethod(final CandidateMethod referenceCandidateMethod) {
- referencedCandidateMethods.add(referenceCandidateMethod);
- }
-
- public Set getReferencedCandidateMethods() {
- return referencedCandidateMethods;
- }
-
- public static CandidateMethod of(String methodSignature) {
- return new CandidateMethod(methodSignature);
- }
-
- /**
- * This factory constructor is only called for methods that are known to be deterministic in advance
- *
- * @param methodSignature
- * @return
- */
- public static CandidateMethod proven(String methodSignature) {
- final CandidateMethod provenCandidateMethod = new CandidateMethod(methodSignature);
- provenCandidateMethod.deterministic();
- return provenCandidateMethod;
- }
-
- @Override
- public String toString() {
- return "CandidateMethod{" + "currentState=" + currentState + ", reason=" + reason + ", methodType=" + methodType + ", internalMethodName=" + internalMethodName + ", referencedCandidateMethods=" + referencedCandidateMethods + '}';
- }
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/SandboxAwareClassWriter.java b/experimental/sandbox/src/main/java/net/corda/sandbox/SandboxAwareClassWriter.java
deleted file mode 100644
index 9df01b5919..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/SandboxAwareClassWriter.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox;
-
-import static net.corda.sandbox.Utils.*;
-
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassWriter;
-
-/**
- * @author ben
- */
-public final class SandboxAwareClassWriter extends ClassWriter {
-
- private final ClassLoader loader;
-
- public SandboxAwareClassWriter(final ClassLoader save, final ClassReader classReader, final int flags) {
- super(classReader, flags);
- loader = save;
- }
-
- /**
- * Returns the common super type of the two given types. The default
- * implementation of this method loads the two given classes and uses
- * the java.lang.Class methods to find the common super class. It can be
- * overridden to compute this common super type in other ways, in particular
- * without actually loading any class, or to take into account the class
- * that is currently being generated by this ClassWriter, which can of
- * course not be loaded since it is under construction.
- *
- * @param type1 the internal name of a class.
- * @param type2 the internal name of another class.
- * @return the internal name of the common super class of the two given
- * classes.
- */
- @Override
- public String getCommonSuperClass(final String type1, final String type2) {
- if (OBJECT.equals(type1) || OBJECT.equals(type2)
- || OBJECT.equals(unsandboxNameIfNeedBe(type1)) || OBJECT.equals(unsandboxNameIfNeedBe(type2))) {
- return OBJECT;
- }
-// System.out.println(type1 + " ; " + type2);
- String out = super.getCommonSuperClass(unsandboxNameIfNeedBe(type1), unsandboxNameIfNeedBe(type2));
-// try {
-// out = getCommonSuperClassBorrowed(type1, type2);
-// } catch (final ClassNotFoundException cnfe) {
-// throw new RuntimeException(cnfe);
-// }
- if (SANDBOX_PATTERN_INTERNAL.asPredicate().test(type1) || SANDBOX_PATTERN_INTERNAL.asPredicate().test(type2)) {
- return SANDBOX_PREFIX_INTERNAL + out;
- }
- return out;
- }
-
- public String getCommonSuperClassBorrowed(final String type1, final String type2) throws ClassNotFoundException {
- Class> c;
- Class> d;
- try {
- c = Class.forName(type1.replace('/', '.'), false, loader);
- d = Class.forName(type2.replace('/', '.'), false, loader);
- } catch (Exception e) {
-
- c = Class.forName(unsandboxNameIfNeedBe(type1).replace('/', '.'), false, loader);
- d = Class.forName(unsandboxNameIfNeedBe(type2).replace('/', '.'), false, loader);
-
-// throw new RuntimeException(e.toString());
- }
- if (c.isAssignableFrom(d)) {
- return type1;
- }
- if (d.isAssignableFrom(c)) {
- return type2;
- }
- if (c.isInterface() || d.isInterface()) {
- return "java/lang/Object";
- } else {
- do {
- c = c.getSuperclass();
- } while (!c.isAssignableFrom(d));
- return c.getName().replace('.', '/');
- }
- }
-
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/SandboxRemapper.java b/experimental/sandbox/src/main/java/net/corda/sandbox/SandboxRemapper.java
deleted file mode 100644
index ff4eb919b8..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/SandboxRemapper.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox;
-
-import org.objectweb.asm.commons.Remapper;
-
-/**
- * @author ben
- */
-public final class SandboxRemapper extends Remapper {
-
- @Override
- public String mapDesc(final String desc) {
- return super.mapDesc(Utils.rewriteDescInternal(desc));
- }
-
- @Override
- public String map(final String typename) {
- return super.map(Utils.sandboxInternalTypeName(typename));
- }
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/Utils.java b/experimental/sandbox/src/main/java/net/corda/sandbox/Utils.java
deleted file mode 100644
index d5be161248..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/Utils.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @author ben
- */
-public final class Utils {
-
- public static final String SANDBOX_PREFIX_INTERNAL = "sandbox/";
-
- public static final String CLASSFILE_NAME_SUFFIX = "^(.*)\\.class$";
-
- public static final Pattern JAVA_LANG_PATTERN_INTERNAL = Pattern.compile("^java/lang/(.*)");
-
- public static final Pattern SANDBOX_PATTERN_INTERNAL = Pattern.compile("^" + SANDBOX_PREFIX_INTERNAL + "(.*)");
-
- public static final Pattern SIGNATURE_PATTERN_INTERNAL = Pattern.compile("\\((.*)\\)(.+)");
-
- public static final Pattern REFTYPE_PATTERN_INTERNAL = Pattern.compile("(L[^;]+;)");
-
- public static final Pattern ARRAY_REFTYPE_PATTERN_INTERNAL = Pattern.compile("((\\[+)L[^;]+;)");
-
- public static final Pattern JAVA_PATTERN_QUALIFIED = Pattern.compile("^java\\.(.+)");
-
- public static final Pattern CLASSNAME_PATTERN_QUALIFIED = Pattern.compile("([^\\.]+)\\.");
-
- public static final String OBJECT = "java/lang/Object";
-
- public static final String THROWABLE = "java/lang/Throwable";
-
- public static final String ERROR = "java/lang/Error";
-
- public static final String THREAD_DEATH = "java/lang/ThreadDeath";
-
- // Hide constructor
- private Utils() {
- }
-
- /**
- * Helper method that converts from the internal class name format (as used in the
- * Constant Pool) to a fully-qualified class name. No obvious library method to do this
- * appears to exist, hence this code. If one exists, rip this out.
- *
- * @param classInternalName
- * @return
- */
- public static String convertInternalFormToQualifiedClassName(final String classInternalName) {
- String out = classInternalName.replaceAll("/", "\\.");
- return out;
- }
-
- /**
- * This method takes in an internal method name but needs to return a qualified
- * classname (suitable for loading)
- *
- * @param internalMethodName
- * @return
- */
- public static String convertInternalMethodNameToQualifiedClassName(final String internalMethodName) {
- final Matcher classMatch = CLASSNAME_PATTERN_QUALIFIED.matcher(internalMethodName);
- if (classMatch.find()) {
- return convertInternalFormToQualifiedClassName(classMatch.group(1));
- } else {
- throw new IllegalArgumentException(internalMethodName + " is not a legal method name");
- }
- }
-
- /**
- * Helper method that converts from a fully-qualified class name to the internal class
- * name format (as used in the Constant Pool). No obvious library method to do this
- * appears to exist, hence this code. If one exists, rip this out.
- *
- * @param qualifiedClassName
- * @return
- */
- public static String convertQualifiedClassNameToInternalForm(final String qualifiedClassName) {
- String out = qualifiedClassName.replaceAll("\\.", "/");
- return out;
- }
-
- /**
- * This method potentially rewrites the classname.
- *
- * @param internalClassname - specified in internal form
- * @return
- */
- public static String sandboxInternalTypeName(final String internalClassname) {
- if (classShouldBeSandboxedInternal(internalClassname)) {
- final Matcher arrayMatch = ARRAY_REFTYPE_PATTERN_INTERNAL.matcher(internalClassname);
- if (arrayMatch.find()) {
- final String indirection = arrayMatch.group(2);
- return indirection + SANDBOX_PREFIX_INTERNAL + internalClassname.substring(indirection.length());
- } else {
- // Regular, non-array reftype
- return SANDBOX_PREFIX_INTERNAL + internalClassname;
- }
- }
-
- return internalClassname;
- }
-
- /**
- * @param qualifiedTypeName
- * @return
- */
- public static String sandboxQualifiedTypeName(final String qualifiedTypeName) {
- final String internal = convertQualifiedClassNameToInternalForm(qualifiedTypeName);
- final String sandboxedInternal = sandboxInternalTypeName(internal);
- if (internal.equals(sandboxedInternal)) {
- return qualifiedTypeName;
- }
- return convertInternalFormToQualifiedClassName(sandboxedInternal);
- }
-
- /**
- * This method removes the sandboxing prefix from a method or type name, if it has
- * one, otherwise it returns the input string.
- *
- * @param internalClassname
- * @return the internal classname, unsandboxed if that was required
- */
- public static String unsandboxNameIfNeedBe(final String internalClassname) {
- final Matcher m = SANDBOX_PATTERN_INTERNAL.matcher(internalClassname);
- if (m.find()) {
- return m.group(1);
- }
- return internalClassname;
- }
-
- /**
- * @param desc - internal
- * @return the rewritten desc string
- */
- public static String rewriteDescInternal(final String desc) {
- String remaining = desc;
- final Matcher formatCheck = SIGNATURE_PATTERN_INTERNAL.matcher(desc);
- // Check it's a valid signature string
- if (!formatCheck.find())
- return remaining;
-
- final StringBuilder out = new StringBuilder();
- while (!remaining.isEmpty()) {
- final Matcher refTypeFound = REFTYPE_PATTERN_INTERNAL.matcher(remaining);
- if (refTypeFound.find()) {
- final int startOfType = refTypeFound.start();
- final int endOfType = refTypeFound.end();
- final String before = remaining.substring(0, startOfType);
-
- final String found = refTypeFound.group(1);
- final String rewritten = "L" + sandboxInternalTypeName(found.substring(1));
- out.append(before);
- out.append(rewritten);
- remaining = remaining.substring(endOfType);
- } else {
- out.append(remaining);
- remaining = "";
- }
- }
-
- return out.toString();
- }
-
- /**
- * Determines whether a classname in qualified form is a candidate for transitive
- * loading. This should not attempt to load a classname that starts with java. as
- * the only permissable classes have already been transformed into sandboxed
- * methods
- *
- * @param qualifiedClassName
- * @return
- */
- public static boolean shouldAttemptToTransitivelyLoad(final String qualifiedClassName) {
- return !JAVA_PATTERN_QUALIFIED.asPredicate().test(qualifiedClassName);
- }
-
- /**
- * Helper method that determines whether this class requires sandboxing
- *
- * @param clazzName - specified in internal form
- * @return true if the class should be sandboxed
- */
- public static boolean classShouldBeSandboxedInternal(final String clazzName) {
- if (ARRAY_REFTYPE_PATTERN_INTERNAL.asPredicate().test(clazzName)) {
- return classShouldBeSandboxedInternal(clazzName.substring(2, clazzName.length() - 1));
- }
-
- if (JAVA_LANG_PATTERN_INTERNAL.asPredicate().test(clazzName)) {
- return false;
- }
-
- return !SANDBOX_PATTERN_INTERNAL.asPredicate().test(clazzName);
- }
-
-
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/WhitelistClassLoader.java b/experimental/sandbox/src/main/java/net/corda/sandbox/WhitelistClassLoader.java
deleted file mode 100644
index fa34c1cab5..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/WhitelistClassLoader.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox;
-
-import net.corda.sandbox.visitors.CostInstrumentingMethodVisitor;
-import net.corda.sandbox.visitors.WhitelistCheckingClassVisitor;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.*;
-import java.util.*;
-
-import org.objectweb.asm.*;
-import org.objectweb.asm.commons.ClassRemapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @author ben
- */
-public final class WhitelistClassLoader extends ClassLoader {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(WhitelistClassLoader.class);
-
- private final Map> loadedClasses;
-
- private final Map transformedClasses;
-
- private final List primaryClasspathSearchPath = new ArrayList<>();
-
- private final List fileSystemSearchPath = new ArrayList<>();
-
- private final CandidacyStatus candidacyStatus;
-
- private final boolean removeNonDeterministicMethods;
-
- private Path classDir;
-
- private String classInternalName;
-
- private Path outputJarPath;
-
- private WhitelistClassLoader(final boolean stripNonDeterministicMethods) {
- candidacyStatus = CandidacyStatus.of();
- loadedClasses = new HashMap<>();
- transformedClasses = new HashMap<>();
- removeNonDeterministicMethods = stripNonDeterministicMethods;
- }
-
- /*
- * Copy constructor for use in recursive calls
- * @param other
- */
- private WhitelistClassLoader(WhitelistClassLoader other) {
- candidacyStatus = other.candidacyStatus;
- loadedClasses = other.loadedClasses;
- transformedClasses = other.transformedClasses;
- fileSystemSearchPath.addAll(other.fileSystemSearchPath);
- primaryClasspathSearchPath.addAll(other.primaryClasspathSearchPath);
- removeNonDeterministicMethods = other.removeNonDeterministicMethods;
- }
-
- /**
- * Static factory method. Throws URISyntaxException currently, as this method is
- * called with user data, so a checked exception is not unreasonable. Could use a
- * runtime exception instead.
- *
- * @param auxiliaryClassPath
- * @param stripNonDeterministic if set to true, then rather than requiring all
- * methods to be deterministic, instead the classloader
- * will remove all non-deterministic methods.
- * @return a suitably constructed whitelisting classloader
- * @throws URISyntaxException
- */
- public static WhitelistClassLoader of(final String auxiliaryClassPath, final boolean stripNonDeterministic) throws URISyntaxException {
- final WhitelistClassLoader out = new WhitelistClassLoader(stripNonDeterministic);
- out.candidacyStatus.setContextLoader(out);
- out.setupClasspath(auxiliaryClassPath);
- return out;
- }
-
- public static WhitelistClassLoader of(final String auxiliaryClassPath) throws URISyntaxException {
- return of(auxiliaryClassPath, false);
- }
-
- public static WhitelistClassLoader of(final Path auxiliaryJar, final boolean stripNonDeterministic) {
- final WhitelistClassLoader out = new WhitelistClassLoader(stripNonDeterministic);
- out.candidacyStatus.setContextLoader(out);
- out.fileSystemSearchPath.add(auxiliaryJar);
- return out;
- }
-
- public static WhitelistClassLoader of(final Path auxiliaryJar) throws URISyntaxException {
- return of(auxiliaryJar, false);
- }
-
- /**
- * Static factory method. Used for recursive classloading
- *
- * @param other
- * @return a suitably constructed whitelisting classloader based on the state
- * of the passed classloader
- */
- public static WhitelistClassLoader of(final WhitelistClassLoader other) {
- final WhitelistClassLoader out = new WhitelistClassLoader(other);
-// out.candidacyStatus.setContextLoader(out);
- return out;
- }
-
- /**
- * Helper method that adds a jar to the path to be searched
- *
- * @param knownGoodJar
- */
- void addJarToSandbox(final Path knownGoodJar) {
- fileSystemSearchPath.add(knownGoodJar);
- }
-
- /**
- * Setup the auxiliary classpath so that classes that are not on the original
- * classpath can be scanned for.
- * Note that this this method hardcodes Unix conventions, so won't work on e.g. Windows
- *
- * @param auxiliaryClassPath
- * @throws URISyntaxException
- */
- void setupClasspath(final String auxiliaryClassPath) throws URISyntaxException {
- for (String entry : auxiliaryClassPath.split(":")) {
- if (entry.startsWith("/")) {
- fileSystemSearchPath.add(Paths.get(entry));
- } else {
- final URL u = getClass().getClassLoader().getResource(entry);
- primaryClasspathSearchPath.add(Paths.get(u.toURI()));
- }
- }
- }
-
- /**
- * @param qualifiedClassName
- * @return a class object that has been whitelist checked and is known to be
- * deterministic
- * @throws ClassNotFoundException
- */
- @Override
- public Class> findClass(final String qualifiedClassName) throws ClassNotFoundException {
- // One problem is that the requested class may refer to untransformed (but
- // deterministic) classes that will resolve & be loadable by the WLCL, but
- // in doing so, the name of the referenced class is rewritten and the name
- // by which it is now known does not have a mapping to a loaded class.
- // To solve this, we use the loadedClasses cache - on both possible keys
- // for the class (either of which will point to a transformed class object)
- Class> cls = loadedClasses.get(qualifiedClassName);
- if (cls != null) {
- return cls;
- }
- final String sandboxed = Utils.sandboxQualifiedTypeName(qualifiedClassName);
- cls = loadedClasses.get(sandboxed);
- if (cls != null) {
- return cls;
- }
- // Cache miss - so now try the superclass implementation
- try {
- cls = super.findClass(qualifiedClassName);
- } catch (ClassNotFoundException ignored) {
- // We actually need to load this ourselves, so find the path
- // corresponding to the directory where the classfile lives.
- // Note that for jar files this might be a "virtual" Path object
- classInternalName = Utils.convertQualifiedClassNameToInternalForm(qualifiedClassName);
- classDir = locateClassfileDir(classInternalName);
- try {
- final boolean isDeterministic = scan();
- if (isDeterministic || removeNonDeterministicMethods) {
- final Path fullPathToClass = classDir.resolve(classInternalName + ".class");
- Set methodsToRemove = new HashSet<>();
- if (removeNonDeterministicMethods && !isDeterministic) {
- methodsToRemove = candidacyStatus.getDisallowedMethods();
- }
-
- final byte[] classContents = Files.readAllBytes(fullPathToClass);
- final byte[] instrumentedBytes = instrumentWithCosts(classContents, methodsToRemove);
- if (!removeNonDeterministicMethods) {
- // If we're in stripping mode, then trying to define the class
- // will cause a transitive loading failure
- cls = defineClass(null, instrumentedBytes, 0, instrumentedBytes.length);
- }
- transformedClasses.put(sandboxed, instrumentedBytes);
- } else {
- throw new ClassNotFoundException("Class " + qualifiedClassName + " could not be loaded.", reason());
- }
- } catch (final IOException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("Saving class " + cls + " as " + qualifiedClassName);
-
- loadedClasses.put(qualifiedClassName, cls);
-
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("Saving class " + cls + " as " + sandboxed);
-
- loadedClasses.put(sandboxed, cls);
-
- return cls;
- }
-
- /**
- * Using the ASM library read in the currentClass's byte code and visit the call
- * sites within it. Whilst visiting, check to see if the classes/methods visited
- * are deterministic and therefore safe to load.
- *
- * @return true if the current class is safe to be loaded
- * @throws java.io.IOException
- */
- public boolean scan() throws IOException {
- try (final InputStream in = Files.newInputStream(classDir.resolve(classInternalName + ".class"))) {
- try {
- final ClassReader classReader = new ClassReader(in);
-
- // Useful for debug, you can pass in the traceClassVisitor as an extra parameter if needed
- // PrintWriter printWriter = new PrintWriter(System.out);
- // TraceClassVisitor traceClassVisitor = new TraceClassVisitor(printWriter);
- final ClassVisitor whitelistCheckingClassVisitor
- = new WhitelistCheckingClassVisitor(classInternalName, candidacyStatus);
-
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("About to read class: " + classInternalName);
-
- // If there's debug info in the class, don't look at that whilst visiting
- classReader.accept(whitelistCheckingClassVisitor, ClassReader.SKIP_DEBUG);
- } catch (Exception ex) {
- LOGGER.error("Exception whilst reading class: " + classInternalName, ex);
- }
- }
-
- return candidacyStatus.isLoadable();
- }
-
- /**
- * Helper method that takes a class name (in internal format) and returns a Path
- * corresponding to the dir where the classfile was found. We are essentially working
- * around a limitation of the ASM library that does not integrate cleanly with Java 7
- * NIO.2 Path APIs. This method also performs a couple of basic sanity check on the
- * class file (e.g. that it exists, is a regular file and is readable).
- *
- * @param internalClassName
- * @return a path object that corresponds to a class that has been found
- * @throws ClassNotFoundException
- */
- Path locateClassfileDir(final String internalClassName) throws ClassNotFoundException {
- // Check the primaryClasspathSearchPath
- for (final Path p : primaryClasspathSearchPath) {
- final Path check = Paths.get(p.toString(), internalClassName + ".class");
-
- if (Files.isRegularFile(check)) {
- if (!Files.isReadable(check)) {
- throw new IllegalArgumentException("File " + check + " found but is not readable");
- }
- return p;
- }
- }
- for (final Path p : fileSystemSearchPath) {
- final Path check = p.resolve(internalClassName + ".class");
- if (Files.isRegularFile(check)) {
- if (!Files.isReadable(check)) {
- throw new IllegalArgumentException("File " + check + " found but is not readable");
- }
- return p;
- }
- }
-
- throw new ClassNotFoundException("Requested class "
- + Utils.convertInternalFormToQualifiedClassName(internalClassName) + " could not be found");
- }
-
- /**
- * Instruments a class with runtime cost accounting
- *
- * @param originalClassContents
- * @param methodsToRemove
- * @return the byte array that represents the transformed class
- */
- public byte[] instrumentWithCosts(final byte[] originalClassContents, final Set methodsToRemove) {
- final ClassReader reader = new ClassReader(originalClassContents);
- final ClassWriter writer = new SandboxAwareClassWriter(this, reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
- final ClassVisitor remapper = new ClassRemapper(writer, new SandboxRemapper());
- final ClassVisitor coster = new ClassVisitor(Opcodes.ASM5, remapper) {
- @Override
- public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
- final MethodVisitor baseMethodVisitor = super.visitMethod(access, name, desc, signature, exceptions);
- return new CostInstrumentingMethodVisitor(baseMethodVisitor, access, name, desc);
- }
- };
- reader.accept(coster, ClassReader.EXPAND_FRAMES);
- return writer.toByteArray();
- }
-
- /**
- * Creates a jar archive of all the transformed classes that this classloader
- * has loaded.
- *
- * @return true on success, false on failure
- * @throws java.io.IOException
- * @throws java.net.URISyntaxException
- */
- public void createJar() throws IOException, URISyntaxException {
- final Map env = new HashMap<>();
- env.put("create", String.valueOf(!outputJarPath.toFile().exists()));
-
- final URI fileUri = outputJarPath.toUri();
- final URI zipUri = new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null);
-
- try (final FileSystem zfs = FileSystems.newFileSystem(zipUri, env)) {
- final Path jarRoot = zfs.getRootDirectories().iterator().next();
-
- for (final Map.Entry stringEntry : transformedClasses.entrySet()) {
- final byte[] newClassDef = stringEntry.getValue();
- final String relativePathName = Utils.convertQualifiedClassNameToInternalForm(stringEntry.getKey()) + ".class";
- final Path outPath = jarRoot.resolve(relativePathName);
-
- Files.createDirectories(outPath.getParent());
- Files.write(outPath, newClassDef);
- }
- }
- }
-
- /**
- * Getter method for the reason for failure
- *
- * @return
- */
- public WhitelistClassloadingException reason() {
- return candidacyStatus.getReason();
- }
-
- /**
- * Getter method for the method candidacy status
- *
- * @return
- */
- public CandidacyStatus getCandidacyStatus() {
- return candidacyStatus;
- }
-
- public Path getOutpurJarPath() {
- return outputJarPath;
- }
-
- public void setOutpurJarPath(Path outpurJarPath) {
- this.outputJarPath = outpurJarPath;
- }
-
- public Set cachedClasses() {
- return loadedClasses.keySet();
- }
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/WhitelistClassloadingException.java b/experimental/sandbox/src/main/java/net/corda/sandbox/WhitelistClassloadingException.java
deleted file mode 100644
index b2fd28250c..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/WhitelistClassloadingException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox;
-
-/**
- *
- */
-public class WhitelistClassloadingException extends Exception {
-
- public WhitelistClassloadingException() {
- super();
- }
-
- public WhitelistClassloadingException(String message) {
- super(message);
- }
-
- public WhitelistClassloadingException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public WhitelistClassloadingException(Throwable cause) {
- super(cause);
- }
-
- protected WhitelistClassloadingException(String message, Throwable cause,
- boolean enableSuppression,
- boolean writableStackTrace) {
- super(message, cause, enableSuppression, writableStackTrace);
- }
-
-
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/costing/Contract.java b/experimental/sandbox/src/main/java/net/corda/sandbox/costing/Contract.java
deleted file mode 100644
index 3826f4d4b6..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/costing/Contract.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox.costing;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This class is the runtime representation of a running contract.
- *
- * @author ben
- */
-public class Contract {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(Contract.class);
-
- private final RuntimeCostAccounter accountant = new RuntimeCostAccounter();
- private final Thread contractThread;
- private final Class> vettedCode;
- private final ContractExecutor executionStrategy;
-
- public Contract(final Class> newCode, final ContractExecutor strategy) {
- vettedCode = newCode;
- executionStrategy = strategy;
- contractThread = new Thread(() -> executionStrategy.execute(this));
- contractThread.setName("ContractThread-" + System.currentTimeMillis());
- contractThread.setDaemon(true);
- }
-
- public boolean isViable() {
- return executionStrategy.isSuitable(this);
- }
-
- public Thread getThread() {
- return contractThread;
- }
-
- public Class> getCode() {
- return vettedCode;
- }
-
- public void start() {
- contractThread.start();
- }
-
- void suicide() {
- LOGGER.info("Terminating contract " + this);
- throw new ThreadDeath();
- }
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/costing/ContractExecutor.java b/experimental/sandbox/src/main/java/net/corda/sandbox/costing/ContractExecutor.java
deleted file mode 100644
index c2d3e443f9..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/costing/ContractExecutor.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox.costing;
-
-/**
- * This interface is to decouple the actual executable code from the entry point and
- * how vetted deterministic code will be used inside the sandbox
- *
- * @author ben
- */
-public interface ContractExecutor {
- /**
- * Executes a smart contract
- *
- * @param contract the contract to be executed
- */
- void execute(Contract contract);
-
- /**
- * Checks to see if the supplied Contract is suitable
- *
- * @param contract
- * @return true if the contract is suitable for execution
- */
- boolean isSuitable(Contract contract);
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/costing/RuntimeCostAccounter.java b/experimental/sandbox/src/main/java/net/corda/sandbox/costing/RuntimeCostAccounter.java
deleted file mode 100644
index 06487859db..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/costing/RuntimeCostAccounter.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox.costing;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @author ben
- */
-public class RuntimeCostAccounter {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeCostAccounter.class);
-
- private static Thread primaryThread;
-
- private static final ThreadLocal allocationCost = ThreadLocal.withInitial(() -> 0L);
-
- private static final ThreadLocal jumpCost = ThreadLocal.withInitial(() -> 0L);
-
- private static final ThreadLocal invokeCost = ThreadLocal.withInitial(() -> 0L);
-
- private static final ThreadLocal throwCost = ThreadLocal.withInitial(() -> 0L);
-
- private static final long BASELINE_ALLOC_KILL_THRESHOLD = 1024 * 1024;
-
- private static final long BASELINE_JUMP_KILL_THRESHOLD = 100;
-
- private static final long BASELINE_INVOKE_KILL_THRESHOLD = 100;
-
- private static final long BASELINE_THROW_KILL_THRESHOLD = 50;
-
- public static void recordJump() {
- final Thread current = Thread.currentThread();
- if (current == primaryThread)
- return;
-
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("In recordJump() at " + System.currentTimeMillis() + " on " + current.getName());
- checkJumpCost(1);
- }
-
- public static void recordAllocation(final String typeName) {
- final Thread current = Thread.currentThread();
- if (current == primaryThread)
- return;
-
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("In recordAllocation() at " + System.currentTimeMillis()
- + ", got object type: " + typeName + " on " + current.getName());
-
- // More sophistication is clearly possible, e.g. caching approximate sizes for types that we encounter
- checkAllocationCost(1);
- }
-
- public static void recordArrayAllocation(final int length, final int multiplier) {
- final Thread current = Thread.currentThread();
- if (current == primaryThread)
- return;
-
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("In recordArrayAllocation() at " + System.currentTimeMillis()
- + ", got array element size: " + multiplier + " and size: " + length + " on " + current.getName());
-
- checkAllocationCost(length * multiplier);
- }
-
- public static void recordMethodCall() {
- final Thread current = Thread.currentThread();
- if (current == primaryThread)
- return;
-
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("In recordMethodCall() at " + System.currentTimeMillis() + " on " + current.getName());
-
- checkInvokeCost(1);
- }
-
- public static void recordThrow() {
- final Thread current = Thread.currentThread();
- if (current == primaryThread)
- return;
-
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("In recordThrow() at " + System.currentTimeMillis() + " on " + current.getName());
- checkThrowCost(1);
- }
-
- public static void setPrimaryThread(final Thread toBeIgnored) {
- primaryThread = toBeIgnored;
- }
-
- private static void checkAllocationCost(final long additional) {
- final long newValue = additional + allocationCost.get();
- allocationCost.set(newValue);
- if (newValue > BASELINE_ALLOC_KILL_THRESHOLD) {
- final Thread current = Thread.currentThread();
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("Contract " + current + " terminated for overallocation");
- throw new ThreadDeath();
- }
- }
-
- private static void checkJumpCost(final long additional) {
- final long newValue = additional + jumpCost.get();
- jumpCost.set(newValue);
- if (newValue > BASELINE_JUMP_KILL_THRESHOLD) {
- final Thread current = Thread.currentThread();
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("Contract " + current + " terminated for excessive use of looping");
- throw new ThreadDeath();
- }
- }
-
- private static void checkInvokeCost(final long additional) {
- final long newValue = additional + invokeCost.get();
- invokeCost.set(newValue);
- if (newValue > BASELINE_INVOKE_KILL_THRESHOLD) {
- final Thread current = Thread.currentThread();
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("Contract " + current + " terminated for excessive method calling");
- throw new ThreadDeath();
- }
- }
-
- private static void checkThrowCost(final long additional) {
- final long newValue = additional + throwCost.get();
- throwCost.set(newValue);
- if (newValue > BASELINE_THROW_KILL_THRESHOLD) {
- final Thread current = Thread.currentThread();
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("Contract " + current + " terminated for excessive exception throwing");
- throw new ThreadDeath();
- }
- }
-
- public static long getAllocationCost() {
- return allocationCost.get();
- }
-
- public static long getJumpCost() {
- return jumpCost.get();
- }
-
- public static long getInvokeCost() {
- return invokeCost.get();
- }
-
- public static long getThrowCost() {
- return throwCost.get();
- }
-
- public static void resetCounters() {
- allocationCost.set(0L);
- jumpCost.set(0L);
- invokeCost.set(0L);
- throwCost.set(0L);
- }
-}
diff --git a/experimental/sandbox/src/main/java/net/corda/sandbox/tools/SandboxCreator.java b/experimental/sandbox/src/main/java/net/corda/sandbox/tools/SandboxCreator.java
deleted file mode 100644
index 44d0232046..0000000000
--- a/experimental/sandbox/src/main/java/net/corda/sandbox/tools/SandboxCreator.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * R3 Proprietary and Confidential
- *
- * Copyright (c) 2018 R3 Limited. All rights reserved.
- *
- * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
- *
- * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
- */
-
-package net.corda.sandbox.tools;
-
-import net.corda.sandbox.WhitelistClassLoader;
-import net.corda.sandbox.visitors.SandboxPathVisitor;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.file.*;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import joptsimple.OptionParser;
-import joptsimple.OptionSet;
-
-/**
- * This class takes in an exploded set of JRE classes, and a whitelist, and rewrites all
- * classes (note: not methods) that have at least one whitelisted method to create a
- * sandboxed version of the class.
- */
-// java8.scan.java.lang_and_util java8.interfaces_for_compat java8 sandbox
-public final class SandboxCreator {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(SandboxCreator.class);
- private static final String USAGE_STRING = "Usage: SandboxCreator