Skip to content

Commit

Permalink
Ensure consistency by making the object class mapping always load at …
Browse files Browse the repository at this point in the history
…the beginnings of transactions.

Not particularly efficient, but it does the job.
  • Loading branch information
mcoblenz committed Apr 10, 2020
1 parent c7f5cc4 commit 664d65b
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@


public abstract class HyperledgerChaincodeBase extends ChaincodeBase implements ObsidianSerialized {
SerializationState serializationState;
public SerializationState serializationState;

public HyperledgerChaincodeBase() {
serializationState = new SerializationState();
Expand Down Expand Up @@ -81,6 +81,10 @@ public Response init(ChaincodeStub stub) {
public Response invoke(ChaincodeStub stub) {
serializationState.setStub(stub);

// We load the object classes to make sure that all the peers see the same object class state,
// regardless of whether they were the instantiating peer or not.
serializationState.loadObjectClasses(stub);

final String function = stub.getFunction();
List<byte[]> allArgs = stub.getArgs();
List<byte[]> params = allArgs.subList(1, allArgs.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
import java.util.HashSet;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.*;

public class SerializationState {
private Logger logger;
private Map<String, ObsidianSerialized> guidMap;

/* When we return an object to the client, we have to be able to look up that object later by its GUID.
Expand Down Expand Up @@ -51,6 +53,7 @@ public SerializationState() {
guidMap = new HashMap<String, ObsidianSerialized>();
stateLockedObjects = new HashSet<Object>();
allObjectClasses = new HashMap<String, Class>();
logger = Logger.getLogger("SerializationStateLogger");
}

public void setStub(ChaincodeStub newStub) {
Expand All @@ -67,6 +70,9 @@ public ObsidianSerialized getEntry(String guid) {
}

public void putEntry(String guid, ObsidianSerialized obj) {
Exception e = new Exception();
System.out.println("putEntry stack trace: ");
e.printStackTrace();
guidMap.put(guid, obj);
allObjectClasses.put(guid, obj.getClass());
}
Expand All @@ -82,6 +88,7 @@ public void flushEntries() {
}

returnedObjectClassMap = null;
allObjectClasses = null;
}

// TODO: move this to another class, since it pertains to clients too (and does not pertain to serialization).
Expand Down Expand Up @@ -126,7 +133,6 @@ public ReturnedReferenceState getReturnedReferenceState(ChaincodeStub stub, Stri
}

public Class getClassOfObject(ChaincodeStub stub, String guid) {
loadObjectClasses(stub);
return allObjectClasses.get(guid);
}

Expand Down Expand Up @@ -209,48 +215,42 @@ public void archiveObjectClasses(ChaincodeStub stub) {
String classNameKey = "ObjectClass" + Integer.toString(i);
stub.putStringState(classNameKey, entry.getValue().getCanonicalName());

// System.out.println("archived: obj " + objGuid + " has class " + entry.getValue().getCanonicalName());

i++;
}
}
}


private void loadObjectClasses (ChaincodeStub stub) {
if (allObjectClasses == null) {
allObjectClasses = new HashMap<String, Class>();

try {
String numAsString = stub.getStringState("NumObjectClasses");
int numObjects = 0;
public void loadObjectClasses (ChaincodeStub stub) {
// Load unconditionally so all peers load the same.
allObjectClasses = new HashMap<String, Class>();

if (numAsString != null && numAsString.length() > 0) {
numObjects = Integer.parseInt(numAsString);
}
try {
String numAsString = stub.getStringState("NumObjectClasses");
int numObjects = 0;

for (int i = 0; i < numObjects; i++) {
String indexAsString = Integer.toString(i);
if (numAsString != null && numAsString.length() > 0) {
numObjects = Integer.parseInt(numAsString);
}

String guidKey = "ObjectClassGUID" + indexAsString;
String classNameKey = "ObjectClass" + indexAsString;
for (int i = 0; i < numObjects; i++) {
String indexAsString = Integer.toString(i);

String guid = stub.getStringState(guidKey);
String objectClass = stub.getStringState(classNameKey);
Class c = Class.forName(objectClass);
String guidKey = "ObjectClassGUID" + indexAsString;
String classNameKey = "ObjectClass" + indexAsString;

allObjectClasses.put(guid, c);
String guid = stub.getStringState(guidKey);
String objectClass = stub.getStringState(classNameKey);
Class c = Class.forName(objectClass);

// System.out.println("loaded: obj " + guid + " has class " + c.getCanonicalName());
}
}
catch (NumberFormatException e) {
System.err.println("Failed to parse the number of returned objects: " + e);
}
catch (ClassNotFoundException e) {
System.err.println("Failed to find a Class object for class name: " + e);
allObjectClasses.put(guid, c);
}

}
catch (NumberFormatException e) {
System.err.println("Failed to parse the number of returned objects: " + e);
}
catch (ClassNotFoundException e) {
System.err.println("Failed to find a Class object for class name: " + e);
}
}

Expand Down
Binary file modified docs/repository/edu/cmu/cs/obsidian/runtime/0.1/runtime-0.1.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6f200788a29cac50199ef703ed34a7d1
96d5bcb30d9039bfda6c75da8d1509b4
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b2da9450c2f3c98a73bc5ecc56dc368e24b5cc09
dbec030ce2a41dad045b948ab62d4cda0b5a0e2f
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
<versions>
<version>0.1</version>
</versions>
<lastUpdated>20200409212128</lastUpdated>
<lastUpdated>20200410214536</lastUpdated>
</versioning>
</metadata>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
63d6ee3adb9d25f83bfad18d62bfb61b
2913d8187813798e0542c2a27bd9d833
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8c10c630b969ad2ceba7e7735955c36abaaffce2
93b9f5334186d39712ae4bfc41d9433d30a3c65a
7 changes: 7 additions & 0 deletions src/main/scala/edu/cmu/cs/obsidian/codegen/CodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,7 @@ class CodeGen (val target: Target, table: SymbolTable) {

val guidConstructor = newClass.constructor(JMod.PUBLIC)
guidConstructor.param(model.ref("String"), "__guid_")

guidConstructor.body().assign(JExpr.ref(modifiedFieldName), JExpr.lit(false))
guidConstructor.body().assign(JExpr.ref(loadedFieldName), JExpr.lit(false))
guidConstructor.body().assign(JExpr.ref(guidFieldName), JExpr.ref("__guid_"))
Expand Down Expand Up @@ -1854,6 +1855,11 @@ class CodeGen (val target: Target, table: SymbolTable) {
constructorInvocation.arg(newClass.name()) // The name of the class suffices as a GUID for the top level contract.
val instance = body.decl(newClass, "instance", constructorInvocation)

val putEntryInvocation = instance.ref("serializationState").invoke("putEntry")
putEntryInvocation.arg(instance.ref(newClass.fields get guidFieldName))
putEntryInvocation.arg(instance)
body.add(putEntryInvocation)

val invocation = JExpr.invoke(instance, "delegatedMain").arg(args)
body.add(invocation)
}
Expand Down Expand Up @@ -2907,6 +2913,7 @@ class CodeGen (val target: Target, table: SymbolTable) {
}

addArgs(JExpr._new(resolvedType), args, contractParams, contractType.typeArgs, translationContext, localContext, isFFIInvocation)

case Parent() => assert(false, "Parents should not exist in code generation"); JExpr._null()
case Disown(e) => recurse(e)
case StateInitializer(stateName, fieldName) => JExpr.ref(stateInitializationVariableName(stateName._1, fieldName._1))
Expand Down

0 comments on commit 664d65b

Please sign in to comment.