Skip to content
This repository has been archived by the owner on Apr 11, 2023. It is now read-only.

Commit

Permalink
feat: Create TRIGGER instruction and support to Time type (#48, #50)
Browse files Browse the repository at this point in the history
  • Loading branch information
federicozanardo committed Jan 28, 2023
1 parent a90b7d8 commit 86b7d84
Showing 1 changed file with 83 additions and 6 deletions.
89 changes: 83 additions & 6 deletions src/main/java/vm/SmartContractVirtualMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import lib.datastructures.Stack;
import models.address.Address;
import models.contract.SingleUseSeal;
import models.dto.requests.event.EventTriggerRequest;
import vm.trap.Trap;
import vm.trap.TrapErrorCodes;
import vm.types.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
Expand All @@ -26,6 +28,7 @@ public class SmartContractVirtualMachine {
private final HashMap<String, Type> argumentsSpace = new HashMap<String, Type>();
private final HashMap<String, TraceChange> globalSpace;
private final HashMap<String, SingleUseSeal> singleUseSealsToCreate = new HashMap<String, SingleUseSeal>();
private final ArrayList<EventTriggerRequest> eventTriggersToRequest = new ArrayList<EventTriggerRequest>();
private final Trap trap;
// private String stuffToStore; // TODO: data to save in a blockchain transaction

Expand All @@ -51,6 +54,10 @@ public HashMap<String, SingleUseSeal> getSingleUseSealsToCreate() {
return singleUseSealsToCreate;
}

public ArrayList<EventTriggerRequest> getEventTriggersToRequest() {
return eventTriggersToRequest;
}

public boolean execute() {
while (isRunning) {
if (trap.isEmptyStack()) {
Expand Down Expand Up @@ -140,13 +147,11 @@ public boolean execute() {
case "RAISE":
this.raiseOperation(instruction);
break;
case "TRIGGER":
this.triggerOperation(instruction);
break;
case "HALT":
if ((instruction.length - 1) > 0) {
trap.raiseError(TrapErrorCodes.TOO_MANY_ARGUMENTS, executionPointer, Arrays.toString(instruction));
break;
}
// Terminate the execution
this.haltProgramExecution();
this.haltOperation(instruction);
break;
default:
trap.raiseError(TrapErrorCodes.INSTRUCTION_DOES_NOT_EXISTS, executionPointer, Arrays.toString(instruction));
Expand Down Expand Up @@ -233,6 +238,16 @@ private void haltProgramExecution() {

// Instructions

private void haltOperation(String[] instruction) {
if ((instruction.length - 1) > 0) {
trap.raiseError(TrapErrorCodes.TOO_MANY_ARGUMENTS, executionPointer, Arrays.toString(instruction));
return;
}

// Terminate the execution
this.haltProgramExecution();
}

private void pushOperation(String[] instruction) throws StackOverflowException, NoSuchAlgorithmException {
if ((instruction.length - 1) < 2) {
trap.raiseError(TrapErrorCodes.NOT_ENOUGH_ARGUMENTS, executionPointer, Arrays.toString(instruction));
Expand Down Expand Up @@ -287,6 +302,14 @@ private void pushOperation(String[] instruction) throws StackOverflowException,
case "asset":
stack.push(new AssetType(assetId, new FloatType(Integer.parseInt(value), Integer.parseInt(decimals))));
break;
case "time":
if (value.equals("now")) {
long timestamp = System.currentTimeMillis() / 1000;
stack.push(new TimeType((int) timestamp));
} else {
stack.push(new TimeType(Integer.parseInt(value)));
}
break;
default:
trap.raiseError(TrapErrorCodes.TYPE_DOES_NOT_EXIST, executionPointer, Arrays.toString(instruction));
}
Expand Down Expand Up @@ -354,6 +377,10 @@ private void addOperation(String[] instruction) throws StackOverflowException, S
firstVal.getInteger() + secondVal.getValue().getInteger(),
firstVal.getDecimals()
);
} else if (first.getType().equals("time") && second.getType().equals("time")) {
TimeType firstVal = (TimeType) first;
TimeType secondVal = (TimeType) second;
result = new TimeType(firstVal.getValue() + secondVal.getValue());
} else {
trap.raiseError(TrapErrorCodes.INCORRECT_TYPE, executionPointer, Arrays.toString(instruction));
return;
Expand Down Expand Up @@ -674,6 +701,9 @@ private void instOperation(String[] instruction) {
case "float":
dataSpace.put(variableName, new FloatType(0, Integer.parseInt(decimals)));
break;
case "time":
dataSpace.put(variableName, new TimeType());
break;
default:
trap.raiseError(TrapErrorCodes.TYPE_DOES_NOT_EXIST, executionPointer, Arrays.toString(instruction));
}
Expand Down Expand Up @@ -921,6 +951,11 @@ private void iseqOperation(String[] instruction) throws StackOverflowException,

stack.push(new BoolType(result));
break;
case "time":
TimeType firstTime = new TimeType((Integer) first.getValue());
TimeType secondTime = new TimeType((Integer) second.getValue());
stack.push(new BoolType(firstTime.getValue() == secondTime.getValue()));
break;
default:
trap.raiseError(TrapErrorCodes.INCORRECT_TYPE, executionPointer, Arrays.toString(instruction));
}
Expand Down Expand Up @@ -1095,6 +1130,9 @@ private void ainstOperation(String[] instruction) {
AssetType value = new AssetType(assetId, new FloatType(0, Integer.parseInt(decimals)));
argumentsSpace.put(variableName, value);
break;
case "time":
argumentsSpace.put(variableName, new TimeType());
break;
default:
trap.raiseError(TrapErrorCodes.TYPE_DOES_NOT_EXIST, executionPointer, Arrays.toString(instruction));
}
Expand Down Expand Up @@ -1246,6 +1284,9 @@ private void ginstOperation(String[] instruction) {
AssetType value = new AssetType(assetId, new FloatType(0, Integer.parseInt(decimals)));
globalSpace.put(variableName, new TraceChange(value, true));
break;
case "time":
globalSpace.put(variableName, new TraceChange(new TimeType(), true));
break;
default:
trap.raiseError(TrapErrorCodes.TYPE_DOES_NOT_EXIST, executionPointer, Arrays.toString(instruction));
}
Expand Down Expand Up @@ -1447,4 +1488,40 @@ private void raiseOperation(String[] instruction) {
trap.raiseError(TrapErrorCodes.ERROR_CODE_DOES_NOT_EXISTS, executionPointer, Arrays.toString(instruction));
}
}

private void triggerOperation(String[] instruction) throws StackUnderflowException {
if ((instruction.length - 1) < 1) {
trap.raiseError(TrapErrorCodes.NOT_ENOUGH_ARGUMENTS, executionPointer, Arrays.toString(instruction));
return;
}

if ((instruction.length - 1) > 1) {
trap.raiseError(TrapErrorCodes.TOO_MANY_ARGUMENTS, executionPointer, Arrays.toString(instruction));
return;
}

String obligationFunctionName = instruction[1];

Type value = stack.pop(); // Time

if (!value.getType().equals("time")) {
trap.raiseError(TrapErrorCodes.INCORRECT_TYPE, executionPointer, Arrays.toString(instruction));
return;
}

TimeType timeVal = (TimeType) value;

// Check that the value is not negative
if (timeVal.getValue() <= 0) {
trap.raiseError(TrapErrorCodes.LESS_THAN_ZERO, executionPointer, Arrays.toString(instruction));
return;
}

EventTriggerRequest eventTriggerRequest = new EventTriggerRequest(obligationFunctionName, timeVal.getValue());
eventTriggersToRequest.add(eventTriggerRequest);

System.out.println("triggerOperation: eventTriggersToRequest => " + eventTriggersToRequest);
System.out.println("triggerOperation: current timestamp => " + System.currentTimeMillis() / 1000);
System.out.println("triggerOperation: expire => " + eventTriggerRequest.getTime());
}
}

0 comments on commit 86b7d84

Please sign in to comment.