Browse Source

More tests (now in org.ciyam.at), better exception messages, tidying, tightened visibilty.

Added unit test to cover branching to beyond end of code segment.
Added unit test to cover branching to before start of code segment.

Added very naive fuzzy disassembly test to see how it handles random, invalid code.

Refactored data address checking in FunctionCode.postCheckExecute() methods to
single FunctionCode.checkDataAddress method. New method includes FunctionCode's name
when throwing due to out-of-bounds address.

Tidied narrowing conversions by replacing literal 0x7fffffffL with Integer.MAX_VALUE.

Tightened OpCode methods visiblity from public to protected.
Added branch target checking to OpCode.executeBranchConditional but maybe this is
already covered by call to Utils.getCodeOffset() when assembling params in Opcode.execute().
Improved message in Utils.getCodeOffset() anyway.

Moved unit tests to org.ciyam.at package.
Moved unit test support classes from 'common' to org.ciyam.at.test.
master
catbref 5 years ago
parent
commit
6e9198b226
  1. 39
      Java/src/main/java/org/ciyam/at/FunctionCode.java
  2. 107
      Java/src/main/java/org/ciyam/at/OpCode.java
  3. 8
      Java/src/main/java/org/ciyam/at/Utils.java
  4. 35
      Java/src/test/java/org/ciyam/at/BlockchainFunctionCodeTests.java
  5. 35
      Java/src/test/java/org/ciyam/at/BranchingOpCodeTests.java
  6. 5
      Java/src/test/java/org/ciyam/at/CallStackOpCodeTests.java
  7. 5
      Java/src/test/java/org/ciyam/at/DataOpCodeTests.java
  8. 35
      Java/src/test/java/org/ciyam/at/DisassemblyTests.java
  9. 5
      Java/src/test/java/org/ciyam/at/FunctionCodeTests.java
  10. 7
      Java/src/test/java/org/ciyam/at/HashingFunctionCodeTests.java
  11. 9
      Java/src/test/java/org/ciyam/at/MiscTests.java
  12. 7
      Java/src/test/java/org/ciyam/at/OpCodeTests.java
  13. 9
      Java/src/test/java/org/ciyam/at/SerializationTests.java
  14. 4
      Java/src/test/java/org/ciyam/at/ToolchainTests.java
  15. 5
      Java/src/test/java/org/ciyam/at/UserStackOpCodeTests.java
  16. 2
      Java/src/test/java/org/ciyam/at/test/ExecutableTest.java
  17. 2
      Java/src/test/java/org/ciyam/at/test/TestAPI.java
  18. 2
      Java/src/test/java/org/ciyam/at/test/TestLogger.java
  19. 2
      Java/src/test/java/org/ciyam/at/test/TestUtils.java

39
Java/src/main/java/org/ciyam/at/FunctionCode.java

@ -121,10 +121,9 @@ public enum FunctionCode {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
// Validate data offset in arg1
if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages - 3)
throw new ExecutionException(this.name() + " data start address out of bounds");
checkDataAddress(state, functionData.value1, 4);
int dataIndex = (int) (functionData.value1 & 0x7fffffffL);
int dataIndex = (int) (functionData.value1 & Integer.MAX_VALUE);
state.dataByteBuffer.putLong(dataIndex++ * MachineState.VALUE_SIZE, state.a1);
state.dataByteBuffer.putLong(dataIndex++ * MachineState.VALUE_SIZE, state.a2);
@ -140,10 +139,9 @@ public enum FunctionCode {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
// Validate data offset in arg1
if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages - 3)
throw new ExecutionException(this.name() + " data start address out of bounds");
checkDataAddress(state, functionData.value1, 4);
int dataIndex = (int) (functionData.value1 & 0x7fffffffL);
int dataIndex = (int) (functionData.value1 & Integer.MAX_VALUE);
state.dataByteBuffer.putLong(dataIndex++ * MachineState.VALUE_SIZE, state.b1);
state.dataByteBuffer.putLong(dataIndex++ * MachineState.VALUE_SIZE, state.b2);
@ -283,10 +281,9 @@ public enum FunctionCode {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
// Validate data offset in arg1
if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages - 3)
throw new ExecutionException(this.name() + " data start address out of bounds");
checkDataAddress(state, functionData.value1, 4);
int dataIndex = (int) (functionData.value1 & 0x7fffffffL);
int dataIndex = (int) (functionData.value1 & Integer.MAX_VALUE);
state.a1 = state.dataByteBuffer.getLong(dataIndex++ * MachineState.VALUE_SIZE);
state.a2 = state.dataByteBuffer.getLong(dataIndex++ * MachineState.VALUE_SIZE);
@ -302,10 +299,9 @@ public enum FunctionCode {
@Override
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
// Validate data offset in arg1
if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages - 3)
throw new ExecutionException(this.name() + " data start address out of bounds");
checkDataAddress(state, functionData.value1, 4);
int dataIndex = (int) (functionData.value1 & 0x7fffffffL);
int dataIndex = (int) (functionData.value1 & Integer.MAX_VALUE);
state.b1 = state.dataByteBuffer.getLong(dataIndex++ * MachineState.VALUE_SIZE);
state.b2 = state.dataByteBuffer.getLong(dataIndex++ * MachineState.VALUE_SIZE);
@ -1081,15 +1077,14 @@ public enum FunctionCode {
protected byte[] getHashData(FunctionData functionData, MachineState state) throws ExecutionException {
// Validate data offset in arg1
if (functionData.value1 < 0L || functionData.value1 > Integer.MAX_VALUE || functionData.value1 >= state.numDataPages)
throw new ExecutionException(this.name() + " data start address out of bounds");
checkDataAddress(state, functionData.value1, 1);
// Validate data length in arg2
if (functionData.value2 < 0L || functionData.value2 > Integer.MAX_VALUE || functionData.value1 + byteLengthToDataLength(functionData.value2) > state.numDataPages)
if (functionData.value2 < 0L || functionData.value2 > state.numDataPages || functionData.value1 + byteLengthToDataLength(functionData.value2) > state.numDataPages)
throw new ExecutionException(this.name() + " data length invalid");
final int dataStart = (int) (functionData.value1 & 0x7fffffffL);
final int dataLength = (int) (functionData.value2 & 0x7fffffffL);
final int dataStart = (int) (functionData.value1 & Integer.MAX_VALUE);
final int dataLength = (int) (functionData.value2 & Integer.MAX_VALUE);
byte[] message = new byte[dataLength];
@ -1104,7 +1099,15 @@ public enum FunctionCode {
/** Returns the number of data-page values to contain specific length of bytes. */
protected int byteLengthToDataLength(long byteLength) {
return (MachineState.VALUE_SIZE - 1 + (int) (byteLength & 0x7fffffffL)) / MachineState.VALUE_SIZE;
return (MachineState.VALUE_SIZE - 1 + (int) (byteLength & Integer.MAX_VALUE)) / MachineState.VALUE_SIZE;
}
/** Check that data segment address (+ subsequent locations) are within data segment bounds. */
protected void checkDataAddress(MachineState state, long address, int count) throws ExecutionException {
final int maxAddress = state.numDataPages - count;
if (address < 0L || address > maxAddress)
throw new ExecutionException(String.format("%s data address %d out of bounds: 0 to %d", this.name(), address, maxAddress));
}
}

107
Java/src/main/java/org/ciyam/at/OpCode.java

@ -39,7 +39,7 @@ public enum OpCode {
*/
NOP(0x7f) {
@Override
public void executeWithParams(MachineState state, Object... args) {
protected void executeWithParams(MachineState state, Object... args) {
// Do nothing
}
},
@ -50,7 +50,7 @@ public enum OpCode {
*/
SET_VAL(0x01, OpCodeParam.DEST_ADDR, OpCodeParam.VALUE) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
long value = (long) args[1];
@ -64,7 +64,7 @@ public enum OpCode {
*/
SET_DAT(0x02, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address1 = (int) args[0];
int address2 = (int) args[1];
@ -79,7 +79,7 @@ public enum OpCode {
*/
CLR_DAT(0x03, OpCodeParam.DEST_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
state.dataByteBuffer.putLong(address, 0L);
@ -92,7 +92,7 @@ public enum OpCode {
*/
INC_DAT(0x04, OpCodeParam.DEST_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
long value = state.dataByteBuffer.getLong(address);
@ -106,7 +106,7 @@ public enum OpCode {
*/
DEC_DAT(0x05, OpCodeParam.DEST_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
long value = state.dataByteBuffer.getLong(address);
@ -120,7 +120,7 @@ public enum OpCode {
*/
ADD_DAT(0x06, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeDataOperation(state, (a, b) -> a + b, args);
}
},
@ -131,7 +131,7 @@ public enum OpCode {
*/
SUB_DAT(0x07, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeDataOperation(state, (a, b) -> a - b, args);
}
},
@ -142,7 +142,7 @@ public enum OpCode {
*/
MUL_DAT(0x08, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeDataOperation(state, (a, b) -> a * b, args);
}
},
@ -154,7 +154,7 @@ public enum OpCode {
*/
DIV_DAT(0x09, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
try {
executeDataOperation(state, (a, b) -> a / b, args);
} catch (ArithmeticException e) {
@ -169,7 +169,7 @@ public enum OpCode {
*/
BOR_DAT(0x0a, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeDataOperation(state, (a, b) -> a | b, args);
}
},
@ -180,7 +180,7 @@ public enum OpCode {
*/
AND_DAT(0x0b, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeDataOperation(state, (a, b) -> a & b, args);
}
},
@ -191,7 +191,7 @@ public enum OpCode {
*/
XOR_DAT(0x0c, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeDataOperation(state, (a, b) -> a ^ b, args);
}
},
@ -202,7 +202,7 @@ public enum OpCode {
*/
NOT_DAT(0x0d, OpCodeParam.DEST_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
long value = state.dataByteBuffer.getLong(address);
@ -216,7 +216,7 @@ public enum OpCode {
*/
SET_IND(0x0e, OpCodeParam.DEST_ADDR, OpCodeParam.INDIRECT_SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address1 = (int) args[0];
int address2 = (int) args[1];
@ -236,7 +236,7 @@ public enum OpCode {
*/
SET_IDX(0x0f, OpCodeParam.DEST_ADDR, OpCodeParam.INDIRECT_SRC_ADDR_WITH_INDEX, OpCodeParam.INDEX) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address1 = (int) args[0];
int address2 = (int) args[1];
int address3 = (int) args[2];
@ -261,7 +261,7 @@ public enum OpCode {
*/
PSH_DAT(0x10, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
long value = state.dataByteBuffer.getLong(address);
@ -284,7 +284,7 @@ public enum OpCode {
*/
POP_DAT(0x11, OpCodeParam.DEST_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
try {
@ -308,7 +308,7 @@ public enum OpCode {
*/
JMP_SUB(0x12, OpCodeParam.CODE_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
try {
@ -331,7 +331,7 @@ public enum OpCode {
*/
RET_SUB(0x13) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
try {
int returnAddress = state.callStackByteBuffer.getInt();
@ -351,7 +351,7 @@ public enum OpCode {
*/
IND_DAT(0x14, OpCodeParam.INDIRECT_DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address1 = (int) args[0];
int address2 = (int) args[1];
@ -371,7 +371,7 @@ public enum OpCode {
*/
IDX_DAT(0x15, OpCodeParam.INDIRECT_DEST_ADDR_WITH_INDEX, OpCodeParam.INDEX, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address1 = (int) args[0];
int address2 = (int) args[1];
int address3 = (int) args[2];
@ -395,7 +395,7 @@ public enum OpCode {
*/
MOD_DAT(0x16, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
try {
executeDataOperation(state, (a, b) -> a % b, args);
} catch (ArithmeticException e) {
@ -412,7 +412,7 @@ public enum OpCode {
private static final long MAX_SHIFT = MachineState.VALUE_SIZE * 8L;
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
// If 2nd arg is more than value size (in bits) then return 0 to simulate all bits being shifted out of existence
executeDataOperation(state, (a, b) -> b >= MAX_SHIFT ? 0 : a << b, args);
}
@ -427,7 +427,7 @@ public enum OpCode {
private static final long MAX_SHIFT = MachineState.VALUE_SIZE * 8L;
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
// If 2nd arg is more than value size (in bits) then return 0 to simulate all bits being shifted out of existence
executeDataOperation(state, (a, b) -> b >= MAX_SHIFT ? 0 : a >>> b, args);
}
@ -439,7 +439,7 @@ public enum OpCode {
*/
JMP_ADR(0x1a, OpCodeParam.CODE_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
state.codeByteBuffer.position(address);
@ -453,7 +453,7 @@ public enum OpCode {
*/
BZR_DAT(0x1b, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
byte offset = (byte) args[1];
@ -476,7 +476,7 @@ public enum OpCode {
*/
BNZ_DAT(0x1e, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
byte offset = (byte) args[1];
@ -499,7 +499,7 @@ public enum OpCode {
*/
BGT_DAT(0x1f, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeBranchConditional(state, (a, b) -> a > b, args);
}
},
@ -511,7 +511,7 @@ public enum OpCode {
*/
BLT_DAT(0x20, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeBranchConditional(state, (a, b) -> a < b, args);
}
},
@ -523,7 +523,7 @@ public enum OpCode {
*/
BGE_DAT(0x21, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeBranchConditional(state, (a, b) -> a >= b, args);
}
},
@ -535,7 +535,7 @@ public enum OpCode {
*/
BLE_DAT(0x22, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeBranchConditional(state, (a, b) -> a <= b, args);
}
},
@ -547,7 +547,7 @@ public enum OpCode {
*/
BEQ_DAT(0x23, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeBranchConditional(state, (a, b) -> a == b, args);
}
},
@ -559,7 +559,7 @@ public enum OpCode {
*/
BNE_DAT(0x24, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.OFFSET) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
executeBranchConditional(state, (a, b) -> a != b, args);
}
},
@ -571,7 +571,7 @@ public enum OpCode {
*/
SLP_DAT(0x25, OpCodeParam.BLOCK_HEIGHT) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
long value = state.codeByteBuffer.getLong(address);
@ -587,7 +587,7 @@ public enum OpCode {
*/
FIZ_DAT(0x26, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
long value = state.dataByteBuffer.getLong(address);
@ -603,7 +603,7 @@ public enum OpCode {
*/
STZ_DAT(0x27, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
long value = state.dataByteBuffer.getLong(address);
@ -621,7 +621,7 @@ public enum OpCode {
*/
FIN_IMD(0x28) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
state.setIsFinished(true);
}
},
@ -632,7 +632,7 @@ public enum OpCode {
*/
STP_IMD(0x29) {
@Override
public void executeWithParams(MachineState state, Object... args) {
protected void executeWithParams(MachineState state, Object... args) {
state.setIsStopped(true);
}
},
@ -643,7 +643,7 @@ public enum OpCode {
*/
SLP_IMD(0x2a) {
@Override
public void executeWithParams(MachineState state, Object... args) {
protected void executeWithParams(MachineState state, Object... args) {
state.setSleepUntilHeight(state.getCurrentBlockHeight() + 1);
state.setIsSleeping(true);
}
@ -655,7 +655,7 @@ public enum OpCode {
*/
ERR_ADR(0x2b, OpCodeParam.CODE_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
int address = (int) args[0];
state.setOnErrorAddress(address);
@ -669,7 +669,7 @@ public enum OpCode {
*/
SET_PCS(0x30) {
@Override
public void executeWithParams(MachineState state, Object... args) {
protected void executeWithParams(MachineState state, Object... args) {
state.setOnStopAddress(state.codeByteBuffer.position());
}
},
@ -680,7 +680,7 @@ public enum OpCode {
*/
EXT_FUN(0x32, OpCodeParam.FUNC) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
short rawFunctionCode = (short) args[0];
FunctionCode functionCode = FunctionCode.valueOf(rawFunctionCode);
@ -702,7 +702,7 @@ public enum OpCode {
*/
EXT_FUN_DAT(0x33, OpCodeParam.FUNC, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
short rawFunctionCode = (short) args[0];
int address = (int) args[1];
@ -727,7 +727,7 @@ public enum OpCode {
*/
EXT_FUN_DAT_2(0x34, OpCodeParam.FUNC, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
short rawFunctionCode = (short) args[0];
int address1 = (int) args[1];
int address2 = (int) args[2];
@ -754,7 +754,7 @@ public enum OpCode {
*/
EXT_FUN_RET(0x35, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
short rawFunctionCode = (short) args[0];
int address = (int) args[1];
@ -782,7 +782,7 @@ public enum OpCode {
*/
EXT_FUN_RET_DAT(0x36, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
short rawFunctionCode = (short) args[0];
int address1 = (int) args[1];
int address2 = (int) args[2];
@ -813,7 +813,7 @@ public enum OpCode {
*/
EXT_FUN_RET_DAT_2(0x37, OpCodeParam.FUNC, OpCodeParam.DEST_ADDR, OpCodeParam.SRC_ADDR, OpCodeParam.SRC_ADDR) {
@Override
public void executeWithParams(MachineState state, Object... args) throws ExecutionException {
protected void executeWithParams(MachineState state, Object... args) throws ExecutionException {
short rawFunctionCode = (short) args[0];
int address1 = (int) args[1];
int address2 = (int) args[2];
@ -842,7 +842,7 @@ public enum OpCode {
};
public final byte value;
public final OpCodeParam[] params;
private final OpCodeParam[] params;
// Create a map of opcode values to OpCode
private static final Map<Byte, OpCode> map = Arrays.stream(OpCode.values()).collect(Collectors.toMap(opcode -> opcode.value, opcode -> opcode));
@ -873,7 +873,7 @@ public enum OpCode {
*
* @throws ExecutionException
*/
public abstract void executeWithParams(MachineState state, Object... args) throws ExecutionException;
protected abstract void executeWithParams(MachineState state, Object... args) throws ExecutionException;
public void execute(MachineState state) throws ExecutionException {
List<Object> args = new ArrayList<>();
@ -914,7 +914,7 @@ public enum OpCode {
* - typically a lambda operating on two <tt>long</tt> params, e.g. <tt>(a, b) -> a + b</tt>
* @throws ExecutionException
*/
private static void executeDataOperation(MachineState state, TwoValueOperator operator, Object... args) throws ExecutionException {
protected void executeDataOperation(MachineState state, TwoValueOperator operator, Object... args) throws ExecutionException {
int address1 = (int) args[0];
int address2 = (int) args[1];
@ -936,13 +936,16 @@ public enum OpCode {
* - typically a lambda comparing two <tt>long</tt> params, e.g. <tt>(a, b) -> a == b</tt>
* @throws ExecutionException
*/
private static void executeBranchConditional(MachineState state, TwoValueComparator comparator, Object... args) throws ExecutionException {
protected void executeBranchConditional(MachineState state, TwoValueComparator comparator, Object... args) throws ExecutionException {
int address1 = (int) args[0];
int address2 = (int) args[1];
byte offset = (byte) args[2];
int branchTarget = state.getProgramCounter() + offset;
if (branchTarget < 0 || branchTarget >= state.codeByteBuffer.limit())
throw new InvalidAddressException("branch target out of bounds");
long value1 = state.dataByteBuffer.getLong(address1);
long value2 = state.dataByteBuffer.getLong(address2);

8
Java/src/main/java/org/ciyam/at/Utils.java

@ -94,10 +94,12 @@ public class Utils {
*/
public static byte getCodeOffset(ByteBuffer codeByteBuffer) throws CodeSegmentException, InvalidAddressException {
try {
byte offset = codeByteBuffer.get();
final byte offset = codeByteBuffer.get();
final int target = codeByteBuffer.position() + offset;
if (codeByteBuffer.position() + offset < 0 || codeByteBuffer.position() + offset >= codeByteBuffer.limit())
throw new InvalidAddressException("Code offset out of bounds");
if (target < 0 || target >= codeByteBuffer.limit() - 1)
throw new InvalidAddressException(String.format("Code target PC+%02x=[%04x] out of bounds: 0x0000 to 0x%04x",
codeByteBuffer.position() - 1, offset, target, codeByteBuffer.limit() - 1 -1));
return offset;
} catch (BufferUnderflowException e) {

35
Java/src/test/java/BlockchainFunctionCodeTests.java → Java/src/test/java/org/ciyam/at/BlockchainFunctionCodeTests.java

@ -1,3 +1,5 @@
package org.ciyam.at;
import static org.junit.Assert.*;
import java.util.Arrays;
@ -9,38 +11,15 @@ import org.ciyam.at.FunctionCode;
import org.ciyam.at.MachineState;
import org.ciyam.at.OpCode;
import org.ciyam.at.Timestamp;
import org.ciyam.at.test.ExecutableTest;
import org.ciyam.at.test.TestAPI;
import org.ciyam.at.test.TestAPI.TestAccount;
import org.ciyam.at.test.TestAPI.TestBlock;
import org.ciyam.at.test.TestAPI.TestTransaction;
import org.junit.Test;
import common.ExecutableTest;
import common.TestAPI;
import common.TestAPI.TestAccount;
import common.TestAPI.TestBlock;
import common.TestAPI.TestTransaction;
public class BlockchainFunctionCodeTests extends ExecutableTest {
/**
* GET_BLOCK_TIMESTAMP
* GET_CREATION_TIMESTAMP
* GET_PREVIOUS_BLOCK_TIMESTAMP
* PUT_PREVIOUS_BLOCK_HASH_INTO_A
* PUT_TX_AFTER_TIMESTAMP_INTO_A
* GET_TYPE_FROM_TX_IN_A
* GET_AMOUNT_FROM_TX_IN_A
* GET_TIMESTAMP_FROM_TX_IN_A
* GENERATE_RANDOM_USING_TX_IN_A
* PUT_MESSAGE_FROM_TX_IN_A_INTO_B
* PUT_ADDRESS_FROM_TX_IN_A_INTO_B
* PUT_CREATOR_INTO_B
* GET_CURRENT_BALANCE
* GET_PREVIOUS_BALANCE
* PAY_TO_ADDRESS_IN_B
* PAY_ALL_TO_ADDRESS_IN_B
* PAY_PREVIOUS_TO_ADDRESS_IN_B
* MESSAGE_A_TO_ADDRESS_IN_B
* ADD_MINUTES_TO_TIMESTAMP
*/
@Test
public void testGetBlockTimestamp() throws ExecutionException {
// Grab block 'timestamp' and save into address 0

35
Java/src/test/java/BranchingOpCodeTests.java → Java/src/test/java/org/ciyam/at/BranchingOpCodeTests.java

@ -1,11 +1,12 @@
package org.ciyam.at;
import static org.junit.Assert.*;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.junit.Test;
import common.ExecutableTest;
public class BranchingOpCodeTests extends ExecutableTest {
@Test
@ -35,6 +36,36 @@ public class BranchingOpCodeTests extends ExecutableTest {
assertEquals("Data does not match", 2L, getData(1));
}
@Test
public void testOutOfBoundsForwardsBranch() throws ExecutionException {
int forwardAddr = codeByteBuffer.limit() - 60; // enough room for post-jump code
codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(forwardAddr);
codeByteBuffer.position(forwardAddr);
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(0L);
codeByteBuffer.put(OpCode.BZR_DAT.value).putInt(0).put((byte) 80); // way after end
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(1).putLong(1L);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getHadFatalError());
}
@Test
public void testOutOfBoundsBackwardsBranch() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(0L);
codeByteBuffer.put(OpCode.BZR_DAT.value).putInt(0).put((byte) -80); // way before start
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(1).putLong(1L);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getHadFatalError());
}
@Test
public void testBZR_DATtrue() throws ExecutionException {
int targetAddr = 0x21;

5
Java/src/test/java/CallStackOpCodeTests.java → Java/src/test/java/org/ciyam/at/CallStackOpCodeTests.java

@ -1,12 +1,13 @@
package org.ciyam.at;
import static org.junit.Assert.*;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.MachineState;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.junit.Test;
import common.ExecutableTest;
public class CallStackOpCodeTests extends ExecutableTest {
@Test

5
Java/src/test/java/DataOpCodeTests.java → Java/src/test/java/org/ciyam/at/DataOpCodeTests.java

@ -1,11 +1,12 @@
package org.ciyam.at;
import static org.junit.Assert.*;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.junit.Test;
import common.ExecutableTest;
public class DataOpCodeTests extends ExecutableTest {
@Test

35
Java/src/test/java/DisassemblyTests.java → Java/src/test/java/org/ciyam/at/DisassemblyTests.java

@ -1,16 +1,19 @@
import static common.TestUtils.hexToBytes;
package org.ciyam.at;
import static org.ciyam.at.test.TestUtils.hexToBytes;
import static org.junit.Assert.fail;
import java.nio.charset.StandardCharsets;
import java.util.Random;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.FunctionCode;
import org.ciyam.at.MachineState;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.ciyam.at.test.TestUtils;
import org.junit.Test;
import common.ExecutableTest;
import common.TestUtils;
public class DisassemblyTests extends ExecutableTest {
private static final String message = "The quick, brown fox jumped over the lazy dog.";
@ -55,4 +58,28 @@ public class DisassemblyTests extends ExecutableTest {
System.out.println(state.disassemble());
}
@Test
public void testFuzzyDisassembly() {
Random random = new Random();
byte[] randomCode = new byte[200];
random.nextBytes(randomCode);
codeByteBuffer.put(randomCode);
byte[] headerBytes = TestUtils.HEADER_BYTES;
byte[] codeBytes = codeByteBuffer.array();
byte[] dataBytes = dataByteBuffer.array();
state = new MachineState(api, logger, headerBytes, codeBytes, dataBytes);
try {
System.out.println(state.disassemble());
} catch (ExecutionException e) {
// we expect this to fail
return;
}
fail("Random code should cause disassembly failure");
}
}

5
Java/src/test/java/FunctionCodeTests.java → Java/src/test/java/org/ciyam/at/FunctionCodeTests.java

@ -1,3 +1,5 @@
package org.ciyam.at;
import static org.junit.Assert.*;
import java.util.Arrays;
@ -7,10 +9,9 @@ import org.ciyam.at.FunctionCode;
import org.ciyam.at.MachineState;
import org.ciyam.at.OpCode;
import org.ciyam.at.Timestamp;
import org.ciyam.at.test.ExecutableTest;
import org.junit.Test;
import common.ExecutableTest;
public class FunctionCodeTests extends ExecutableTest {
private static final byte[] TEST_BYTES = "This string is exactly 32 bytes!".getBytes();

7
Java/src/test/java/HashingFunctionCodeTests.java → Java/src/test/java/org/ciyam/at/HashingFunctionCodeTests.java

@ -1,4 +1,6 @@
import static common.TestUtils.hexToBytes;
package org.ciyam.at;
import static org.ciyam.at.test.TestUtils.hexToBytes;
import static org.junit.Assert.*;
import java.nio.charset.StandardCharsets;
@ -6,10 +8,9 @@ import java.nio.charset.StandardCharsets;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.FunctionCode;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.junit.Test;
import common.ExecutableTest;
public class HashingFunctionCodeTests extends ExecutableTest {
private static final String message = "The quick, brown fox jumped over the lazy dog.";

9
Java/src/test/java/MiscTests.java → Java/src/test/java/org/ciyam/at/MiscTests.java

@ -1,15 +1,16 @@
package org.ciyam.at;
import static org.junit.Assert.*;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.FunctionCode;
import org.ciyam.at.MachineState;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.ciyam.at.test.TestAPI;
import org.ciyam.at.test.TestUtils;
import org.junit.Test;
import common.ExecutableTest;
import common.TestAPI;
import common.TestUtils;
public class MiscTests extends ExecutableTest {
@Test

7
Java/src/test/java/OpCodeTests.java → Java/src/test/java/org/ciyam/at/OpCodeTests.java

@ -1,12 +1,13 @@
import static common.TestUtils.hexToBytes;
package org.ciyam.at;
import static org.ciyam.at.test.TestUtils.hexToBytes;
import static org.junit.Assert.*;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.junit.Test;
import common.ExecutableTest;
public class OpCodeTests extends ExecutableTest {
@Test

9
Java/src/test/java/SerializationTests.java → Java/src/test/java/org/ciyam/at/SerializationTests.java

@ -1,4 +1,6 @@
import static common.TestUtils.hexToBytes;
package org.ciyam.at;
import static org.ciyam.at.test.TestUtils.hexToBytes;
import static org.junit.Assert.*;
import java.util.Arrays;
@ -7,11 +9,10 @@ import org.ciyam.at.ExecutionException;
import org.ciyam.at.FunctionCode;
import org.ciyam.at.MachineState;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.ciyam.at.test.TestUtils;
import org.junit.Test;
import common.ExecutableTest;
import common.TestUtils;
public class SerializationTests extends ExecutableTest {
private byte[] simulate() {

4
Java/src/test/java/ToolchainTests.java → Java/src/test/java/org/ciyam/at/ToolchainTests.java

@ -1,4 +1,6 @@
import static common.TestUtils.hexToBytes;
package org.ciyam.at;
import static org.ciyam.at.test.TestUtils.hexToBytes;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;

5
Java/src/test/java/UserStackOpCodeTests.java → Java/src/test/java/org/ciyam/at/UserStackOpCodeTests.java

@ -1,12 +1,13 @@
package org.ciyam.at;
import static org.junit.Assert.*;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.MachineState;
import org.ciyam.at.OpCode;
import org.ciyam.at.test.ExecutableTest;
import org.junit.Test;
import common.ExecutableTest;
public class UserStackOpCodeTests extends ExecutableTest {
@Test

2
Java/src/test/java/common/ExecutableTest.java → Java/src/test/java/org/ciyam/at/test/ExecutableTest.java

@ -1,4 +1,4 @@
package common;
package org.ciyam.at.test;
import java.nio.ByteBuffer;
import java.security.Security;

2
Java/src/test/java/common/TestAPI.java → Java/src/test/java/org/ciyam/at/test/TestAPI.java

@ -1,4 +1,4 @@
package common;
package org.ciyam.at.test;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;

2
Java/src/test/java/common/TestLogger.java → Java/src/test/java/org/ciyam/at/test/TestLogger.java

@ -1,4 +1,4 @@
package common;
package org.ciyam.at.test;
import org.ciyam.at.LoggerInterface;

2
Java/src/test/java/common/TestUtils.java → Java/src/test/java/org/ciyam/at/test/TestUtils.java

@ -1,4 +1,4 @@
package common;
package org.ciyam.at.test;
import java.math.BigInteger;
import java.nio.ByteBuffer;
Loading…
Cancel
Save