diff --git a/beakerlib/index.js b/beakerlib/index.js index e878b30..a68f171 100644 --- a/beakerlib/index.js +++ b/beakerlib/index.js @@ -1,8 +1,5 @@ const CAP_TYPE = { - NULL : 0, - PROC_CAP_PUSH : 1, - PROC_CAP_DELETE : 2, PROC_CALL : 3, PROC_REGISTER : 4, PROC_DELETE : 5, @@ -14,6 +11,25 @@ const CAP_TYPE = { exports.CAP_TYPE = CAP_TYPE; +function capTypeToSize(capType) { + if (capType == PROC_CALL) { + return 1; + } else if (capType == STORE_WRITE) { + return 2; + } else if (capType == LOG) { + return 5; + } else if (capType == PROC_REGISTER) { + return 1; + } else if (capType == PROC_DELETE) { + return 1; + } else if (capType == PROC_ENTRY) { + return 0; + } else if (capType == ACC_CALL) { + return 1; + } else { + throw new Error("invalid capability type"); + } +} class ProcedureTable { constructor(procTable) { @@ -24,28 +40,65 @@ class ProcedureTable { // } static parse(val) { const procTable = {}; - for (let i = 0; i < val.length;) { + const nVals = val[0]; + for (let i = 1; i < nVals;) { const proc = {}; // Key proc.key = web3.toHex(val[i]); i++; - if (proc.key == "0x0") break; - // KeyIndex - proc.keyIndex = web3.toHex(val[i]); i++; // Location proc.location = web3.toHex(val[i]); i++; + // KeyIndex + proc.keyIndex = web3.toHex(val[i]); i++; // Capabilities - proc.caps = []; + proc.rawcaps = []; const nCaps = val[i].toNumber(); i++; + // Here, j represents the cap index for (let j = 0; j < nCaps; j++) { const cap = {}; - const length = web3.toHex(val[i]); i++; - cap.type = web3.toHex(val[i]); i++; - // (length - 1) as the first value is the length + const capSize = val[i].toNumber(); i++; + const capType = val[i].toNumber(); i++; + cap.type = capType; cap.values = []; - for (let k = 0; k < (length - 1); k++) { + for (let k = 0; k < (capSize-2); k++) { cap.values.push(web3.toHex(val[i])); i++; } - proc.caps.push(cap); + proc.rawcaps.push(cap); + } + proc.caps = []; + proc.caps[CAP_TYPE.PROC_CALL] = []; + proc.caps[CAP_TYPE.PROC_REGISTER] = []; + proc.caps[CAP_TYPE.PROC_DELETE] = []; + proc.caps[CAP_TYPE.PROC_ENTRY] = []; + proc.caps[CAP_TYPE.STORE_WRITE] = []; + proc.caps[CAP_TYPE.LOG] = []; + proc.caps[CAP_TYPE.ACC_CALL] = []; + for (const rawcap of proc.rawcaps) { + switch (rawcap.type) { + case CAP_TYPE.PROC_CALL: + proc.caps[rawcap.type].push(CallCap.fromKeyValues(rawcap.values)); + break; + case CAP_TYPE.PROC_REGISTER: + proc.caps[rawcap.type].push(RegisterCap.fromKeyValues(rawcap.values)); + break; + case CAP_TYPE.PROC_DELETE: + proc.caps[rawcap.type].push(DeleteCap.fromKeyValues(rawcap.values)); + break; + case CAP_TYPE.PROC_ENTRY: + proc.caps[rawcap.type].push(SetEntryCap.fromKeyValues(rawcap.values)); + break; + case CAP_TYPE.STORE_WRITE: + proc.caps[rawcap.type].push(WriteCap.fromKeyValues(rawcap.values)); + break; + case CAP_TYPE.LOG: + proc.caps[rawcap.type].push(LogCap.fromKeyValues(rawcap.values)); + break; + case CAP_TYPE.ACC_CALL: + proc.caps[rawcap.type].push(AccCallCap.fromKeyValues(rawcap.values)); + break; + default: + console.log(rawcap) + throw new Error(`unknown captype ${rawcap.type}: ${rawcap}`); + } } procTable[proc.key] = proc; } @@ -76,17 +129,33 @@ class ProcedureTable { } exports.ProcedureTable = ProcedureTable; - class Cap { - constructor(type) { + constructor(type, capIndex) { this.type = type; + // capIndex defaults to 0 + this.capIndex = capIndex ? capIndex : 0; } toIntegerArray() { const keyValArray = this.keyValues(); // The plus one is to account for the type value - const headerArray = Array.from([keyValArray.length + 1, this.type]); + const headerArray = Array.from([keyValArray.length + 3, this.type, this.capIndex]); return headerArray.concat(keyValArray); } + // Convert clists based on types. + static toCLists(caps) { + const cLists = []; + cLists[CAP_TYPE.PROC_CALL] = []; + cLists[CAP_TYPE.PROC_REGISTER] = []; + cLists[CAP_TYPE.PROC_DELETE] = []; + cLists[CAP_TYPE.PROC_ENTRY] = []; + cLists[CAP_TYPE.STORE_WRITE] = []; + cLists[CAP_TYPE.LOG] = []; + cLists[CAP_TYPE.ACC_CALL] = []; + for (const cap of caps) { + cLists[cap.type].push(cap); + } + return cLists; + } static toInput(caps) { let input = new Array(); for (const cap of caps) { @@ -98,40 +167,135 @@ class Cap { exports.Cap = Cap; class WriteCap extends Cap { - constructor(address, size) { - super(CAP_TYPE.STORE_WRITE); - this.address = address; - this.size = size; + constructor(address, size, capIndex) { + super(CAP_TYPE.STORE_WRITE, capIndex); + if ((typeof address === "string") || (typeof address === "number")) { + this.address = web3.toBigNumber(address); + } else { + this.address = address; + } + if ((typeof size === "string") || (typeof size === "number")) { + this.size = web3.toBigNumber(size); + } else { + this.size = size; + } + + // try { + // if (this.address > web3.toBigNumber("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) { + // console.log(this.address) + // console.log(web3.toHex(this.address)) + // console.log(this.address.toNumber()) + // console.log( web3.toBigNumber("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) + // console.log(web3.toHex(web3.toBigNumber("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))) + // throw new Error("baseAddress too big"); + // } + // } catch (e) { + // throw new Error(e); + // } + // try { + // if (this.size > web3.toBigNumber("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) { + // throw new Error("size too big"); + // } + // } catch (e) { + // throw new Error(e); + // } } // Format the capability values into the values that will be stored in the // kernel. Must be defined for all subclasses keyValues() { return Array.from([this.address, this.size]); } + static fromKeyValues(values) { + if (values.length != 2) { + throw new Error("Incorrect number of values for WRITE cap"); + } + const baseAddress = values[0]; + const additionalKeys = values[1]; + let baseAddressBN; + baseAddressBN = web3.toBigNumber(baseAddress); + // try { + // baseAddressBN = web3.toBigNumber(baseAddress); + // if (baseAddressBN > web3.toBigNumber("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) { + // throw new Error("baseAddress too big"); + // } + // } catch (e) { + // throw new Error(e); + // } + let additionalKeysBN; + additionalKeysBN = web3.toBigNumber(additionalKeys); + // try { + // additionalKeysBN = web3.toBigNumber(additionalKeys); + // if (additionalKeysBN > web3.toBigNumber("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) { + // throw new Error("size too big"); + // } + // } catch (e) { + // throw new Error(e); + // } + return new WriteCap(baseAddressBN, additionalKeysBN); + } } exports.WriteCap = WriteCap; class LogCap extends Cap { - constructor(topics) { - super(CAP_TYPE.LOG); - this.topics = topics; + constructor(topics, capIndex) { + super(CAP_TYPE.LOG, capIndex); + if (topics.length > 4) { + throw new Error("too many topics"); + } + // Input topics must be hex strings or bignums. If it is a string it is + // interpreted as bytes, that is, left-aligned in 32-bytes. If it is + // longer than 32 bytes throw an error. + this.topics = []; + for (const topic of topics) { + if (typeof topic === "string") { + if (!topic.startsWith("0x")) { + throw new Error("Topic must be prefixed with \"0x\""); + } + if (topic.length > 66) { + throw new Error("Topic must be 32 bytes or less"); + } + this.topics.push(web3.toBigNumber("0x"+topic.slice(2).padStart(64,0))); + } else if (typeof topic === "object") { + this.topics.push(topic); + } else { + throw new Error("Topic must be a hex-string or bignum"); + } + } } // Format the capability values into the values that will be stored in the // kernel. Must be defined for all subclasses keyValues() { - return Array.from(this.topics); + const topic1 = (this.topics.length >= 1) ? this.topics[0] : 0; + const topic2 = (this.topics.length >= 2) ? this.topics[1] : 0; + const topic3 = (this.topics.length >= 3) ? this.topics[2] : 0; + const topic4 = (this.topics.length >= 4) ? this.topics[3] : 0; + return Array.from([this.topics.length, topic1, topic2, topic3, topic4]); + } + static fromKeyValues(values) { + if (values.length != 5) { + throw new Error("Incorrect number of values for LOG cap"); + } + const nTopics = values[0]; + if (nTopics > 4 || nTopics < 0) { + throw new Error("Invalid number of topics"); + } + const topics = []; + for (let i = 0; i < nTopics; i++) { + topics.push(values[i+1]); + } + return new LogCap(topics); } } exports.LogCap = LogCap; class CallCap extends Cap { // keys should be a list of strings - constructor(prefixLength, baseKey) { - super(CAP_TYPE.PROC_CALL); + constructor(prefixLength, baseKey, capIndex) { + super(CAP_TYPE.PROC_CALL, capIndex); if (baseKey.length > 24) { - throw new Error("key too long"); + throw new Error(`key too long ${baseKey}`); } - this.baseKey = baseKey; + this.baseKey = baseKey.padEnd(24,'\0'); this.prefixLength = prefixLength; } // Format the capability values into the values that will be stored in the @@ -154,46 +318,108 @@ class CallCap extends Cap { const val = Array.from([key]); return val; } + static fromKeyValues(values) { + if (values.length != 1) { + throw new Error("Incorrect number of values for CALL cap"); + } + const val = "0x"+values[0].slice(2).padStart(64,0); + const prefixHex = val.slice(0,4); + const baseKeyHex = "0x"+val.slice(18); + return new CallCap(web3.toBigNumber(prefixHex).toNumber(), web3.toAscii(baseKeyHex)); + } } exports.CallCap = CallCap; class RegisterCap extends Cap { // A RegisterCap is just a boolean value, a procedure can or cannot // register new procedures - constructor() { - super(CAP_TYPE.PROC_REGISTER); - this.keys = []; + constructor(prefixLength, baseKey, capIndex) { + super(CAP_TYPE.PROC_REGISTER, capIndex); + if (baseKey.length > 24) { + throw new Error("key too long"); + } + this.baseKey = baseKey.padEnd(24,'\0'); + this.prefixLength = prefixLength; } // Format the capability values into the values that will be stored in the // kernel. Must be defined for all subclasses keyValues() { - const val = Array.from(this.keys.map(x => web3.fromAscii(x.padEnd(32, '\0')))); + // The baseKey will take up the last 24 bytes + // baseKey24 is the given key correctly padded to 24 bytes, left aligned + const baseKey24 = web3.fromAscii(this.baseKey.padEnd(24, '\0')) + // baseKeyHex is baseKey24, hex-encoded, and is therefore 48 chars. The + // "0x" is removed from the start of the string. + const baseKeyHex = web3.toHex(baseKey24).slice(2); + // prefixHex is the prefix length hex-encoded and padded to two chars (a + // single byte). The "0x" is removed here also. + const prefixHex = web3.toHex(this.prefixLength).slice(2).padStart(2,'0'); + // There are 7 bytes between the prefix length and the start of the base + // key. + const undefinedFill = web3.toHex("".padEnd(7,'\0')).slice(2); + // We string these together in the correct order. + const key = "0x" + prefixHex + undefinedFill + baseKeyHex; + const val = Array.from([key]); return val; } + static fromKeyValues(values) { + if (values.length != 1) { + throw new Error("Incorrect number of values for REGISTER cap"); + } + const val = "0x"+values[0].slice(2).padStart(64,0); + const prefixHex = val.slice(0,4); + const baseKeyHex = "0x"+val.slice(18); + return new RegisterCap(web3.toBigNumber(prefixHex).toNumber(), web3.toAscii(baseKeyHex)); + } } exports.RegisterCap = RegisterCap; class DeleteCap extends Cap { - // A DeleteCap is just a boolean value, a procedure can or cannot - // register new procedures - constructor(keys = []) { - super(CAP_TYPE.PROC_DELETE); - this.keys = keys; + // keys should be a list of strings + constructor(prefixLength, baseKey, capIndex) { + super(CAP_TYPE.PROC_DELETE, capIndex); + if (baseKey.length > 24) { + throw new Error("key too long"); + } + this.baseKey = baseKey.padEnd(24,'\0'); + this.prefixLength = prefixLength; } // Format the capability values into the values that will be stored in the // kernel. Must be defined for all subclasses keyValues() { - const val = Array.from(this.keys.map(x => web3.fromAscii(x.padEnd(32, '\0')))); + // The baseKey will take up the last 24 bytes + // baseKey24 is the given key correctly padded to 24 bytes, left aligned + const baseKey24 = web3.fromAscii(this.baseKey.padEnd(24, '\0')) + // baseKeyHex is baseKey24, hex-encoded, and is therefore 48 chars. The + // "0x" is removed from the start of the string. + const baseKeyHex = web3.toHex(baseKey24).slice(2); + // prefixHex is the prefix length hex-encoded and padded to two chars (a + // single byte). The "0x" is removed here also. + const prefixHex = web3.toHex(this.prefixLength).slice(2).padStart(2,'0'); + // There are 7 bytes between the prefix length and the start of the base + // key. + const undefinedFill = web3.toHex("".padEnd(7,'\0')).slice(2); + // We string these together in the correct order. + const key = "0x" + prefixHex + undefinedFill + baseKeyHex; + const val = Array.from([key]); return val; } + static fromKeyValues(values) { + if (values.length != 1) { + throw new Error("Incorrect number of values for DELETE cap"); + } + const val = "0x"+values[0].slice(2).padStart(64,0); + const prefixHex = val.slice(0,4); + const baseKeyHex = "0x"+val.slice(18); + return new DeleteCap(web3.toBigNumber(prefixHex).toNumber(), web3.toAscii(baseKeyHex)); + } } exports.DeleteCap = DeleteCap; class SetEntryCap extends Cap { // A DeleteCap is just a boolean value, a procedure can or cannot // register new procedures - constructor() { - super(CAP_TYPE.PROC_ENTRY); + constructor(capIndex) { + super(CAP_TYPE.PROC_ENTRY, capIndex); this.keys = []; } // Format the capability values into the values that will be stored in the @@ -202,25 +428,47 @@ class SetEntryCap extends Cap { const val = Array.from(this.keys.map(x => web3.fromAscii(x.padEnd(32, '\0')))); return val; } + static fromKeyValues(values) { + return new SetEntryCap(); + } } exports.SetEntryCap = SetEntryCap; class AccCallCap extends Cap { - constructor(callAny, sendValue, ethAddress) { - super(CAP_TYPE.ACC_CALL); + constructor(callAny, sendValue, ethAddress, capIndex) { + super(CAP_TYPE.ACC_CALL, capIndex); this.callAny = callAny; this.sendValue = sendValue; this.ethAddress = ethAddress; } + // Format the capability values into the values that will be stored in the // kernel. Must be defined for all subclasses keyValues() { - const callAny = this.callAny ? 1 : 0; - const sendValue = this.sendValue ? 1 : 0; - - const val = Array.from([callAny, sendValue, this.ethAddress]); + const value = new Uint8Array(32); + const callAny = this.callAny ? 0b10000000 : 0; + const sendValue = this.sendValue ? 0b01000000 : 0; + value[0] = callAny | sendValue; + if (!this.ethAddress) { + value.fill(0,12,32); + } else { + const byteArray = hexToByteArray(this.ethAddress); + value.set(byteArray, 32 - byteArray.length); + } + const val = Array.from(["0x"+bufferToHex(value)]); return val; } + static fromKeyValues(values) { + if (values.length != 1) { + throw new Error("Incorrect number of values for DELETE cap"); + } + const val = "0x"+values[0].slice(2).padStart(64,0); + const flagByte = parseInt(val.slice(0,4)); + const callAny = 0b10000000 & flagByte ? true : false; + const sendValue = 0b01000000 & flagByte ? true : false; + const ethAddress = "0x"+val.slice(26); + return new AccCallCap(callAny, sendValue, ethAddress); + } } exports.AccCallCap = AccCallCap; @@ -231,3 +479,25 @@ exports.SysCallResponse = { LOGFAILURE: 33, CALLFAILURE: 44, } + +// Convert a Uint8Array to a hex string (non-prepended) +function bufferToHex(buffer) { + return Array + .from (new Uint8Array (buffer)) + .map (b => b.toString (16).padStart (2, "0")) + .join (""); +} + + +function hexToByteArray(string) { + const sa = string.startsWith("0x") ? string.slice(2) : string; + const s = ((sa.length % 2) == 0) ? sa : "0"+sa; + const r = []; + let i = 0; + while ((i+1) < s.length) { + const ins = "0x"+s[i]+s[i+1]; + r.push(parseInt(ins)) + i += 2; + } + return r; +} diff --git a/contracts/BasicEntryProcedure.sol b/contracts/BasicEntryProcedure.sol index 549d4c5..3dd3b44 100644 --- a/contracts/BasicEntryProcedure.sol +++ b/contracts/BasicEntryProcedure.sol @@ -38,8 +38,8 @@ contract BasicEntryProcedure { // First set up the input data (at memory location 0x0) // The call call is 0x-03 mstore(add(ins,0x0),0x03) - // The capability index is 0x-02 - mstore(add(ins,0x20),0x02) + // The capability index is 0x-00 (the 0th proc call cap) + mstore(add(ins,0x20),0x00) // The key of the procedure // mstore(add(ins,0x40),0) // clear mstore(add(ins,0x40),div(procedureKey,0x10000000000000000)) diff --git a/contracts/BeakerContract.sol b/contracts/BeakerContract.sol index f7c6a65..4eae025 100644 --- a/contracts/BeakerContract.sol +++ b/contracts/BeakerContract.sol @@ -2,11 +2,12 @@ pragma solidity ^0.4.17; import "./Kernel.sol"; import "./ProcedureTable.sol"; +import "./KernelStorage.sol"; contract BeakerContract is IKernel { - function this_proc() internal view returns (ProcedureTable.Procedure memory) { - return ProcedureTable._getProcedureByKey(uint192(currentProcedure)); + function this_proc() internal view returns (Procedure memory) { + return _getProcedureByKey(_getCurrentProcedure()); } // TODO: this doesn't actually use caps, just reads raw @@ -260,6 +261,15 @@ contract BeakerContract is IKernel { uint256 retSize = retInput.length; assembly { + function malloc(size) -> result { + // align to 32-byte words + let rsize := add(size,sub(32,mod(size,32))) + // get the current free mem location + result := mload(0x40) + // Bump the value of 0x40 so that it holds the next + // available memory location. + mstore(0x40,add(result,rsize)) + } let ins := add(input, 0x20) // First set up the input data (at memory location 0x0) // The register syscall is 4 @@ -278,16 +288,15 @@ contract BeakerContract is IKernel { // "in_offset" is at 31, because we only want the last byte of type // "in_size" is 97 because it is 1+32+32+32 // we will store the result at 0x80 and it will be 32 bytes - let retLoc := add(retInput, 0x20) err := 0 - if iszero(delegatecall(gas, caller, add(ins,31), inSize, retLoc, retSize)) { - err := add(2200, mload(retLoc)) - if nCapKeys { - err := add(77,mul(100,mload(retLoc))) - } - mstore(0xd, err) - revert(0xd,retSize) + let status := delegatecall(gas, caller, add(ins,31), inSize, 0, 0) + let retLoc := malloc(returndatasize) + returndatacopy(retLoc,0,returndatasize) + if iszero(status) { + revert(retLoc,returndatasize) } + // Here we will just take the first 32 bytes of the return data. + err := mload(retLoc) } return err; } @@ -351,7 +360,7 @@ contract BeakerContract is IKernel { } return err; } - function proc_log1(uint8 capIndex, uint32 t1, uint32 value) internal returns (uint32 err) { + function proc_log1(uint8 capIndex, bytes32 t1, bytes32 value) internal returns (uint32 err) { bytes memory input = new bytes(5 * 0x20); bytes memory ret = new bytes(0x20); diff --git a/contracts/CapabilityManager.sol b/contracts/CapabilityManager.sol new file mode 100644 index 0000000..156ae0b --- /dev/null +++ b/contracts/CapabilityManager.sol @@ -0,0 +1,277 @@ +pragma solidity ^0.4.17; + +import "./Factory.sol"; +import "./ProcedureTable.sol"; + +contract CapabilityManager is ProcedureTable { + + // CAPABILITY_TYPES + uint8 constant CAP_PROC_CALL = 3; + uint8 constant CAP_PROC_REGISTER = 4; + uint8 constant CAP_PROC_DELETE = 5; + uint8 constant CAP_PROC_ENTRY = 6; + uint8 constant CAP_STORE_WRITE = 7; + uint8 constant CAP_LOG = 8; + uint8 constant CAP_ACC_CALL = 9; + + function checkRegisterCapability(uint192 currentProcedure, bytes24 procedureKey, uint256 reqCapIndex) internal view returns (bool) { + + uint256 capType = CAP_PROC_REGISTER; + // Storage key of the current procedure on the procedure heap + uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure); + // How many Procedure Call capabilities does the current procedure have? + uint256 nCaps = _get(currentProcPointer | (capType*0x10000)); + // If the requested cap is out of the bounds of the cap list, we + // clearly don't have the capability; + if (reqCapIndex+1 > nCaps) { + return false; + } + // A procedure call capabilities stores a single 32-byte value at 0x00. + uint256 value = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00); + // This value has to be destructured to get 2 values, a prefix length + // and a base address. + uint8 prefix; + bytes24 baseKey; + bytes24 clearedBaseKey; + bytes24 clearedReqKey; + assembly { + // Shift the 32-byte value to the right to obtain the first byte only + prefix := div(value,0x100000000000000000000000000000000000000000000000000000000000000) + // Shift the value to get the procedure key left align (as it should + // be for compatibility with bytes24). + baseKey := mul(value,0x10000000000000000) + let q := signextend(1,2) + // h is a large number we will use for arithmetic + let h := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + // y is a number with $prefix 1s at the start + let y := mul(h,exp(2,sub(256,prefix))) + clearedBaseKey := and(y,baseKey) + clearedReqKey := and(y,procedureKey) + } + return clearedBaseKey == clearedReqKey; + } + + function checkDeleteCapability(uint192 currentProcedure, bytes24 procedureKey, uint256 reqCapIndex) internal view returns (bool) { + + uint256 capType = CAP_PROC_DELETE; + // Storage key of the current procedure on the procedure heap + uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure); + // How many Procedure Call capabilities does the current procedure have? + uint256 nCaps = _get(currentProcPointer | (capType*0x10000)); + // If the requested cap is out of the bounds of the cap list, we + // clearly don't have the capability; + if (reqCapIndex+1 > nCaps) { + return false; + } + // A procedure delete capability stores a single 32-byte value at 0x00. + uint256 value = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00); + // This value has to be destructured to get 2 values, a prefix length + // and a base address. + uint8 prefix; + bytes24 baseKey; + bytes24 clearedBaseKey; + bytes24 clearedReqKey; + assembly { + // Shift the 32-byte value to the right to obtain the first byte only + prefix := div(value,0x100000000000000000000000000000000000000000000000000000000000000) + // Shift the value to get the procedure key left align (as it should + // be for compatibility with bytes24). + baseKey := mul(value,0x10000000000000000) + let q := signextend(1,2) + // h is a large number we will use for arithmetic + let h := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + // y is a number with $prefix 1s at the start + let y := mul(h,exp(2,sub(256,prefix))) + clearedBaseKey := and(y,baseKey) + clearedReqKey := and(y,procedureKey) + } + return clearedBaseKey == clearedReqKey; + } + + function checkSetEntryCapability(uint192 currentProcedure, uint256 reqCapIndex) internal view returns (bool) { + uint256 capType = CAP_PROC_ENTRY; + // Storage key of the current procedure on the procedure heap + uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure); + // How many Write capabilities does the current procedure have? + uint256 nCaps = _get(currentProcPointer | (capType*0x10000)); + // If the requested cap is out of the bounds of the cap list, we + // clearly don't have the capability. + // NB: Even though all set entry caps are identical, if you ask for an + // index that doesn't exist, we will still return false. This implies + // that you should always ask for the cap at index zero to be on the + // safe side. + if (reqCapIndex+1 > nCaps) { + return false; + } else { + return true; + } + // A set entry capability has no values + } + + function checkCallCapability(uint192 currentProcedure, bytes24 procedureKey, uint256 reqCapIndex) internal view returns (bool) { + + uint256 capType = CAP_PROC_CALL; + // Storage key of the current procedure on the procedure heap + uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure); + // How many Procedure Call capabilities does the current procedure have? + uint256 nCaps = _get(currentProcPointer | (capType*0x10000)); + // If the requested cap is out of the bounds of the cap list, we + // clearly don't have the capability; + if (reqCapIndex+1 > nCaps) { + return false; + } + // A procedure call capabilities stores a single 32-byte value at 0x00. + uint256 value = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00); + // This value has to be destructured to get 2 values, a prefix length + // and a base address. + uint8 prefix; + bytes24 baseKey; + bytes24 clearedBaseKey; + bytes24 clearedReqKey; + assembly { + // Shift the 32-byte value to the right to obtain the first byte only + prefix := div(value,0x100000000000000000000000000000000000000000000000000000000000000) + // Shift the value to get the procedure key left align (as it should + // be for compatibility with bytes24). + baseKey := mul(value,0x10000000000000000) + let q := signextend(1,2) + // h is a large number we will use for arithmetic + let h := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + // y is a number with $prefix 1s at the start + let y := mul(h,exp(2,sub(256,prefix))) + clearedBaseKey := and(y,baseKey) + clearedReqKey := and(y,procedureKey) + } + return clearedBaseKey == clearedReqKey; + } + + function checkAccCallCapability(uint192 currentProcedure, address account, uint256 amount, uint256 reqCapIndex) internal view returns (bool) { + uint256 capType = CAP_ACC_CALL; + // Storage key of the current procedure on the procedure heap + uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure); + // How many Write capabilities does the current procedure have? + uint256 nCaps = _get(currentProcPointer | (capType*0x10000)); + // If the requested cap is out of the bounds of the cap list, we + // clearly don't have the capability; + if (reqCapIndex+1 > nCaps) { + return false; + } + // A write capability has 2-3 values, callAny: Boolean, sendValue: Boolean, + // and ethAddress: EthereumAddress. ethAddress is only defined if + // callAny is false. These values are packed into a single 32-byte value. + uint256 value = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00); + // This value has to be destructured to get 2 values, a prefix length + // and a base address. + // The two flags, callAny and sendValue are stored in the first byte + // (which we will call the flagByte). + uint8 flagByte; + assembly { + flagByte := byte(0,value) + } + + // Select the first bit + // Solidity does not allow conversion of ints to bools, so we do it + // explicitly. + bool callAny; + if ((flagByte & 0x80) > 0) { // 0x80 == 0b100000000; + callAny = true; + } + // Select the second bit + // Solidity does not allow conversion of ints to bools, so we do it + // explicitly. + bool sendValue; + if ((flagByte & 0x40) > 0) { // 0x40 == 0b010000000; + sendValue = true; + } + + // We probably don't need to clear these bits, but it is defensive coding. + address ethAddress = address(value & 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff); // clear all but last 20-bytes + + // If callAny is false (0) and ethAddress does not match the requested + // account, return false + if (!callAny && (ethAddress != account)) { + return false; + } + + // If sendValue is false (0) and amount is non-zero, return false + if (!sendValue && (amount != 0)) { + return false; + } + + // Otherwise return true + return true; + } + + function checkWriteCapability(uint192 currentProcedure, uint256 toStoreAddress, uint256 reqCapIndex) internal view returns (bool) { + uint256 capType = CAP_STORE_WRITE; + // Storage key of the current procedure on the procedure heap + uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure); + // How many Write capabilities does the current procedure have? + uint256 nCaps = _get(currentProcPointer | (capType*0x10000)); + // If the requested cap is out of the bounds of the cap list, we + // clearly don't have the capability; + if (reqCapIndex+1 > nCaps) { + return false; + } + // A write capability has two values, address and size. Address is at + // 0x00 and size is at 0x01. + uint256 addr = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00); + uint256 size = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x01); + + // If the store addess is within the range return true, else false + return (toStoreAddress >= addr && toStoreAddress <= (addr + size)); + } + + function checkLogCapability(uint192 currentProcedure, bytes32[] reqTopics, uint256 reqCapIndex) internal view returns (bool) { + uint256 capType = CAP_LOG; + // Storage key of the current procedure on the procedure heap + uint256 currentProcPointer = _getPointerProcHeapByName(currentProcedure); + // How many Write capabilities does the current procedure have? + uint256 nCaps = _get(currentProcPointer | (capType*0x10000)); + // If the requested cap is out of the bounds of the cap list, we + // clearly don't have the capability; + if (reqCapIndex+1 > nCaps) { + return false; + } + // A log capability has 5 values. The first is the number of topics + // specified and must be in the range [0,4]. The next 4 values are the + // values that those log topics are required to be. + + uint256 nTopics = _get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x00); + bytes32 topic1 = bytes32(_get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x01)); + bytes32 topic2 = bytes32(_get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x02)); + bytes32 topic3 = bytes32(_get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x03)); + bytes32 topic4 = bytes32(_get(currentProcPointer | (capType*0x10000) | (reqCapIndex + 1)*0x100 | 0x04)); + + // Check that all of the topics required by the cap are satisfied. That + // is, for every topic in the capability, the corresponding exists in + // the system call and is set to that exact value. First we check that + // there are enough topics in the request. + if (reqTopics.length < nTopics) { + // The system call specifies an insufficient number of topics + return false; + } + + if (nTopics >= 1) { + if (reqTopics[0] != topic1) { + return false; + } + } + if (nTopics >= 2) { + if (reqTopics[1] != topic2) { + return false; + } + } + if (nTopics >= 3) { + if (reqTopics[2] != topic3) { + return false; + } + } + if (nTopics >= 4) { + if (reqTopics[3] != topic4) { + return false; + } + } + return true; + } +} diff --git a/contracts/Factory.sol b/contracts/Factory.sol index 8178c27..d19e136 100644 --- a/contracts/Factory.sol +++ b/contracts/Factory.sol @@ -39,7 +39,7 @@ contract Factory { if((ins == 0x20)){continue;} // SHA3 if((ins >= 0x30 && ins <= 0x3e)){continue;} // Environmental Informatio if((ins >= 0x40 && ins <= 0x45)){continue;} // Block Information - if((ins >= 0x50 && ins <= 0x53)){continue;} // Stack, Memory, Storage and Flow Operation + if((ins >= 0x50 && ins <= 0x53)){continue;} // Stack, Memory, Storage and Flow Operation if((ins >= 0x56 && ins <= 0x5b)){continue;} // Stack, Memory, Storage and Flow Operation if((ins >= 0x80 && ins <= 0x8f)){continue;} // Duplication Operations if((ins >= 0x90 && ins <= 0x9f)){continue;} // Exchange Operations @@ -74,10 +74,10 @@ contract Factory { if (ins == 0xf5) {return 12;} // CREATE2 if (ins == 0xff) {return 13;} // SELFDESTRUCT - + return 100; // UNKNOWN OPCODE - + } return 0; } diff --git a/contracts/Kernel.sol b/contracts/Kernel.sol index f88d1c4..ad61373 100644 --- a/contracts/Kernel.sol +++ b/contracts/Kernel.sol @@ -2,6 +2,7 @@ pragma solidity ^0.4.17; import "./Factory.sol"; import "./ProcedureTable.sol"; +import "./CapabilityManager.sol"; library WhatIsMyAddress { function get() public view returns (address) { @@ -10,32 +11,9 @@ library WhatIsMyAddress { } // Public Kernel Interface -contract IKernel { - event KernelLog(string message); - - using ProcedureTable for ProcedureTable.Self; - ProcedureTable.Self procedures; - - // Current Entry Procedure - bytes24 public entryProcedure; - // Current Instance Address - address kernelAddress; - // Current Running Procedure - bytes24 currentProcedure; - - // SYSCALL_RESPONSE_TYPES - uint8 constant SyscallSuccess = 0; - uint8 constant SyscallReadError = 11; - uint8 constant SyscallWriteError = 22; - uint8 constant SyscallLogError = 33; - uint8 constant SyscallCallError = 44; - - uint8 constant NoSuchSyscallError = 111; +contract IKernel is KernelStorage, ProcedureTable { // CAPABILITY_TYPES - uint8 constant CAP_NULL = 0; - uint8 constant CAP_PROC_CAP_PUSH = 1; - uint8 constant CAP_PROC_CAP_DELETE = 2; uint8 constant CAP_PROC_CALL = 3; uint8 constant CAP_PROC_REGISTER = 4; uint8 constant CAP_PROC_DELETE = 5; @@ -44,32 +22,174 @@ contract IKernel { uint8 constant CAP_LOG = 8; uint8 constant CAP_ACC_CALL = 9; - function getEntryProcedure() public view returns (bytes24 key) { - return entryProcedure; + function getCurrentProcedure() public view returns (bytes24) { + return bytes24(_getCurrentProcedure()); } - function listProcedures() public view returns (bytes24[] memory) { - return procedures.getKeys(); + function getEntryProcedure() public view returns (bytes24) { + return bytes24(_getEntryProcedure()); } - function returnRawProcedureTable() public view returns (uint256[]) { - return procedures.returnRawProcedureTable(); + function listProcedures() public view returns (bytes24[] memory keys) { + uint256 lenP = _getPointerProcedureTableLength(); + uint256 len = _get(lenP); + keys = new bytes24[](len); + for (uint256 i = 0; i < len; i++) { + // We use +1 here because the length of the procedure list is + // stored in the first position + keys[i] = bytes24(_get(lenP + ((i+1) << 24))); + } } - function returnProcedureTable() public view returns (uint256[]) { - return procedures.returnProcedureTable(); + function getProcedureAddress(bytes24 name) public view returns (address) { + return address(_get(_getPointerProcHeapByName(uint192(name)) + 0)); + } + + struct Procedure { + // Equal to the index of the key of this item in keys, plus 1. + uint8 keyIndex; + address location; + Capability[] caps; } - function getProcedure(bytes24 name) public view returns (address) { - return procedures.get(name); + struct Capability { + uint8 capType; + uint256[] values; + } + + function _getProcedureByKey(uint192 key) internal view returns (Procedure memory p) { + // pPointer is a storage key which points to the start of the procedure + // data on the procedure heap + uint256 pPointer = _getPointerProcHeapByName(key); + // The first storage location (0) is used to store the keyIndex. + p.keyIndex = uint8(_get(pPointer)); + // The second storage location (1) is used to store the address of the + // contract. + p.location = address(_get(pPointer + 1)); + // For now let's just get the number of Procedure Call caps + uint256 nCallCaps = _get(pPointer | 0x030000); + + // The third storage location (2) is used to store the number of caps + // uint256 nCaps = _get(pPointer + 2); + p.caps = new Capability[](nCallCaps); + // n is the cap index + uint256 n = 0; + // The rest of the 256 keys are (or can be) used for the caps + for (uint256 i = 0; i < (256-3); i++) { + if (n >= nCallCaps) { + break; + } + p.caps[n].capType = uint8(0x03); + // A call cap will always have length 1 + uint256 nValues = 1; + p.caps[n].values = new uint256[](nValues); + for (uint256 k = 0; k < nValues; k++) { + p.caps[n].values[k] = uint256(_get((pPointer | 0x030000) + i*(0x100) + k)); + } + // uint256 thisCurrentCapLength = _get(pPointer+3+i); + // p.caps[n].capType = uint8(_get(pPointer+3+i+1)); + // // subtract 1 from cap length because it includes the type + // uint256 nValues = thisCurrentCapLength - 1; + // // uint256 nValues = 2; + // p.caps[n].values = new uint256[](nValues); + // for (uint256 k = 0; k < nValues; k++) { + // p.caps[n].values[k] = uint256(_get(pPointer+3+i+2+k)); + // } + // i = i + uint256(thisCurrentCapLength); + // n++; + } + } + + function _parseCaps(Procedure memory p, uint256[] caps) internal pure { + // count caps + uint256 nCaps = 0; + for (uint256 i = 0; i < caps.length; i++) { + uint256 capLength = caps[i]; + i = i + capLength; + nCaps++; + } + p.caps = new Capability[](nCaps); + uint256 n = 0; + for (i = 0; i < caps.length; ) { + capLength = caps[i]; i++; + uint256 nValues = capLength - 1; + p.caps[n].values = new uint256[](nValues); + p.caps[n].capType = uint8(caps[i]); i++; + for (uint256 j = 0; j < nValues; j++) { + p.caps[n].values[j] = caps[i];i++; + } + n++; + } + } + + + // Just returns an array of all the procedure data (257 32-byte values) concatenated. + function returnRawProcedureTable() public view returns (uint256[]) { + bytes24[] memory keys = getKeys(); + uint256 len = keys.length; + // max is 256 keys times the number of procedures + uint256[] memory r = new uint256[](len*257); + // The rest are the elements + uint256 n = 0; + for (uint256 i = 0; i < len ; i++) { + uint192 key = uint192(keys[i]); + uint256 pPointer = _getPointerProcHeapByName(key); + r[n] = uint256(key); n++; + for (uint256 j = 0; j < 256; j++) { + r[n] = _get(pPointer+j); n++; + } + } + return r; + } + + function returnProcedureTable() public view returns (uint256[]) { + bytes24[] memory keys = getKeys(); + uint256 len = keys.length; + // max is 256 keys times the number of procedures + uint256[] memory r = new uint256[](len*256); + // The rest are the elements + uint256 n = 1; + for (uint256 i = 0; i < len ; i++) { + // uint192 key = uint192(keys[i]); + uint256 pPointer = _getPointerProcHeapByName(uint192(keys[i])); + r[n] = uint192(keys[i]); n++; + // Store the keyIndex at this location + r[n] = _get(pPointer); n++; + r[n] = _get(pPointer + 1); n++; + // Save this spot to record the the total number of caps + uint256 nCapTypesLocation = n; n++; + uint256 totalCaps = 0; + // Cycle through all cap types [0,255], even though most don't exist + for (uint256 j = 1; j <= 10; j++) { + // How many caps are there of this type + uint256 nCaps = _get(pPointer | (j*0x10000) | 0x00 | 0x00); + // Only record the caps if they're at least 1W + if (nCaps > 0) { + uint256 capSize = capTypeToSize(j); + // Cycle through them and add them to the array. Here we need to + // know the size. + for (uint256 k = 1; k <= nCaps; k++) { + // record the size + r[n] = (capSize+2); n++; + // record the type + r[n] = j; n++; + totalCaps++; + for (uint256 l = 0; l < capSize; l++) { + r[n] = _get(pPointer | (j*0x10000) | (k*0x100) | (l*0x1)); n++; + } + } + } + } + r[nCapTypesLocation] = totalCaps; + } + r[0] = n; + return r; } } // Internal Kernel Interface -contract Kernel is Factory, IKernel { - - constructor() public {} +contract Kernel is Factory, ProcedureTable, CapabilityManager, IKernel { function parse32ByteValue(uint256 startOffset) pure internal returns (uint256) { uint256 value = 0; @@ -114,7 +234,7 @@ contract Kernel is Factory, IKernel { // TODO: we will need to reserve a value for "not executing anything" // If the transaction is from this procedure... - return (currentProcedure == 0); + return (_getCurrentProcedure() == 0); } @@ -123,12 +243,12 @@ contract Kernel is Factory, IKernel { // TODO: we need to pass through the sender somehow // _executeProcedure will call RETURN or REVERT, ending the transaction, // so control should never return here - _executeProcedure(entryProcedure, "", msg.data); + _executeProcedure(bytes24(_getEntryProcedure()), "", msg.data); } // This is the fallback function which is used to handle system calls. This // is only called if the other functions fail. - function() public payable { + function () public payable { // This is the entry point for the kernel // If it is an external account, we forward it straight to the init @@ -191,15 +311,15 @@ contract Kernel is Factory, IKernel { } else { dataLength = 0; } - bool cap = procedures.checkCallCapability(uint192(currentProcedure), procedureKey, capIndex); - address procedureAddress = procedures.get(procedureKey); + bool cap = checkCallCapability(_getCurrentProcedure(), procedureKey, capIndex); + address procedureAddress = get(procedureKey); // Note the procedure we are currently running, we will put this // back into the "currentProcedure" after we have finished the call. - bytes24 previousProcedure = currentProcedure; + bytes24 previousProcedure = bytes24(_getCurrentProcedure()); // We set the value for the current procedure in the kernel so that // it knows which procedure it is executing (this is important for // looking up capabilities). - currentProcedure = procedureKey; + _setCurrentProcedure(uint192(procedureKey)); if (cap) { assembly { function malloc(size) -> result { @@ -276,7 +396,8 @@ contract Kernel is Factory, IKernel { 0) // We need to restore the previous procedure as the current // procedure, this can simply be on the stack - sstore(currentProcedure_slot,div(previousProcedure,exp(0x100,8))) + // TODO: remove direct reference to storage key here + sstore(0xffffffff03000000000000000000000000000000000000000000000000000000,div(previousProcedure,exp(0x100,8))) if status { let returnLength := returndatasize @@ -311,8 +432,8 @@ contract Kernel is Factory, IKernel { bytes32 regNameB = bytes32(parse32ByteValue(1+32)); bytes24 regName = bytes24(regNameB); address regProcAddress = address(parse32ByteValue(1+32+32)); - // the general format of a capability is length,type,values, where - // length includes the type + // the general format of a capability is length,type,capIndex,values, where + // length includes the type and the length itself uint256 capsStartOffset = /* sysCallCapType */ 1 /* capIndex */ + 32 @@ -328,7 +449,7 @@ contract Kernel is Factory, IKernel { for (uint256 q = 0; q < capsLengthKeys; q++) { regCaps[q] = parse32ByteValue(capsStartOffset+q*32); } - bool cap = procedures.checkRegisterCapability(uint192(currentProcedure), capIndex); + bool cap = checkRegisterCapability(uint192(_getCurrentProcedure()), regName, capIndex); if (cap) { (uint8 err, /* address addr */) = _registerProcedure(regName, regProcAddress, regCaps); @@ -376,9 +497,9 @@ contract Kernel is Factory, IKernel { bytes24 regName = bytes24(regNameB); // Check that target is not the Entry Procedure - bool not_entry = entryProcedure != regName; + bool not_entry = bytes24(_getEntryProcedure()) != regName; // Check if Valid Capability - bool cap = procedures.checkDeleteCapability(uint192(currentProcedure), regName, capIndex); + bool cap = checkDeleteCapability(uint192(_getCurrentProcedure()), regName, capIndex); if (cap && not_entry) { (uint8 err, /* address addr */) = _deleteProcedure(regName); uint256 bigErr = uint256(err); @@ -402,6 +523,10 @@ contract Kernel is Factory, IKernel { } let retSize := 32 let retLoc := mallocZero(retSize) + if iszero(bigErr) { + // return nothing if everything went smoothly + return(0,0) + } mstore(retLoc,bigErr) return(retLoc,retSize) } @@ -423,7 +548,7 @@ contract Kernel is Factory, IKernel { // TODO: fix this double name variable work-around bytes32 regNameB = bytes32(parse32ByteValue(1+32)); bytes24 regName = bytes24(regNameB); - bool cap = procedures.checkSetEntryCapability(uint192(currentProcedure), capIndex); + bool cap = checkSetEntryCapability(uint192(_getCurrentProcedure()), capIndex); if (cap) { (uint8 err) = _setEntryProcedure(regName); uint256 bigErr = uint256(err); @@ -466,7 +591,7 @@ contract Kernel is Factory, IKernel { uint256 capIndex = parse32ByteValue(1); uint256 writeAddress = parse32ByteValue(1+32*1); uint256 writeValue = parse32ByteValue(1+32*2); - bool cap = procedures.checkWriteCapability(uint192(currentProcedure), writeAddress, capIndex); + bool cap = checkWriteCapability(uint192(_getCurrentProcedure()), writeAddress, capIndex); if (cap) { assembly { sstore(writeAddress, writeValue) @@ -495,7 +620,7 @@ contract Kernel is Factory, IKernel { topicVals[i] = bytes32(parse32ByteValue(1+32*(2+i))); } bytes32 logValue = bytes32(parse32ByteValue(1+32*(2+nTopics))); - bool cap = procedures.checkLogCapability(uint192(currentProcedure), topicVals, capIndex); + bool cap = checkLogCapability(uint192(_getCurrentProcedure()), topicVals, capIndex); if (cap) { if (nTopics == 0) { log0(logValue); @@ -558,7 +683,7 @@ contract Kernel is Factory, IKernel { } else { dataLength = 0; } - bool cap = procedures.checkAccCallCapability(uint192(currentProcedure), account, amount, capIndex); + bool cap = checkAccCallCapability(uint192(_getCurrentProcedure()), account, amount, capIndex); if (cap) { assembly { function malloc(size) -> result { @@ -675,22 +800,18 @@ contract Kernel is Factory, IKernel { return; } - // Check whether the address exists - bool exist = procedures.contains(name); - if (exist) { - err = 3; - return; - } - - procedures.insert(name, procedureAddress, caps); + bool inserted = insert(name, procedureAddress, caps); retAddress = procedureAddress; err = 0; - return (0, procedureAddress); + if (!inserted) { + err = 4; + } + return (err, procedureAddress); } function _setEntryProcedure(bytes24 name) internal returns (uint8 err) { - if (procedures.contains(name)) { - entryProcedure = name; + if (contains(name)) { + _setEntryProcedureRaw(uint192(name)); err = 0; } else { err = 1; @@ -704,11 +825,13 @@ contract Kernel is Factory, IKernel { return; } - procedureAddress = procedures.get(name); - bool success = procedures.remove(name); + procedureAddress = get(name); + bool success = remove(name); // Check whether the address exists - if (!success) {err = 2;} + if (!success) { + err = 2; + } } @@ -721,7 +844,7 @@ contract Kernel is Factory, IKernel { } } // Check whether the address exists - bool exist = procedures.contains(name); + bool exist = contains(name); if (!exist) { assembly { mstore8(0,3) @@ -733,8 +856,8 @@ contract Kernel is Factory, IKernel { // assembly { // sstore(currentProcedure_slot,div(name,exp(0x100,8))) // } - currentProcedure = name; - address procedureAddress = procedures.get(name); + _setCurrentProcedure(uint192(name)); + address procedureAddress = get(name); bool status = false; assembly { function malloc(size) -> result { @@ -828,7 +951,8 @@ contract Kernel is Factory, IKernel { status := callcode(gas,procedureAddress,0,ins,inl,0,0) // Zero-out the currentProcedure - sstore(currentProcedure_slot,0) + // TODO: needs to use the KernelStorage abstraction + sstore(0xffffffff03000000000000000000000000000000000000000000000000000000,0) // copy the return data to memory based on its size if iszero(status) { let retSize := add(0x1,returndatasize) diff --git a/contracts/KernelInstance.sol b/contracts/KernelInstance.sol new file mode 100644 index 0000000..5a12aa2 --- /dev/null +++ b/contracts/KernelInstance.sol @@ -0,0 +1,44 @@ +pragma solidity ^0.4.17; + +import "./Kernel.sol"; + +contract KernelInstance is Kernel { + constructor(address initProcAddress) public { + // Set the kernel address to the current address. + _setKernelAddress(this); + + uint256[] memory caps = new uint256[](21); + // CAP_PROC_CALL = 3; + caps[0] = 3; // capSize + caps[1] = 3; // capType + caps[2] = 0; // capIndex + // CAP_PROC_REGISTER = 4; + caps[3] = 3; // capSize + caps[4] = 4; // capType + caps[5] = 0; // capIndex + // CAP_PROC_DELETE = 5; + caps[6] = 3; // capSize + caps[7] = 5; // capType + caps[8] = 0; // capIndex + // CAP_PROC_ENTRY = 6; + caps[9] = 3; // capSize + caps[10] = 6; // capType + caps[11] = 0; // capIndex + // CAP_STORE_WRITE = 7; + caps[12] = 3; // capSize + caps[13] = 7; // capType + caps[14] = 0; // capIndex + // CAP_LOG = 8; + caps[15] = 3; // capSize + caps[16] = 8; // capType + caps[17] = 0; // capIndex + // CAP_ACC_CALL = 9; + caps[18] = 3; // capSize + caps[19] = 9; // capType + caps[20] = 0; // capIndex + bytes24 procName = bytes24("init"); + // TODO: Using insert directly skips validation, we shouldn't do that + insert(procName, initProcAddress, caps); + _setEntryProcedureRaw(uint192(procName)); + } +} diff --git a/contracts/KernelStorage.sol b/contracts/KernelStorage.sol new file mode 100644 index 0000000..1474b9d --- /dev/null +++ b/contracts/KernelStorage.sol @@ -0,0 +1,144 @@ +pragma solidity ^0.4.17; + +contract KernelStorage { + event KernelLog(string message); + + // ** KERNEL STORAGE API ** + // These functions operate on the kernel storage. These functions can be + // considered the kernel storage API, all storage reads and writes should + // come through this API. Each storage item/location has 3 functions, _set*, + // _get*, and _getPointer*. The _get and _set functions work directly on + // the value, while _getPointer returns the storage location. _get and _set + // rely on _getPointer in such a way that storage locations are defined via + // the _getPointer functions. + + // _getPointer* functions. These are all defined together first. + + // Returns the storage key that holds the entry procedure name. + function _getPointerEntryProcedure() pure internal returns (uint256) { + return 0xffffffff04000000000000000000000000000000000000000000000000000000; + } + + // Returns the storage key that holds the current procedure name. + function _getPointerCurrentProcedure() pure internal returns (uint256) { + return 0xffffffff03000000000000000000000000000000000000000000000000000000; + } + + // Returns the storage key that holds the kernel address. + function _getPointerKernelAddress() pure internal returns (uint256) { + return 0xffffffff02000000000000000000000000000000000000000000000000000000; + } + + // Return the storage key that holds the number of procedures in the list. + function _getPointerProcedureTableLength() internal pure returns (uint256) { + bytes5 directory = bytes5(0xffffffff01); + return uint256(bytes32(directory)); + } + + // Returns the storage key that holds the procedure data of procedure #idx + // in the procedure list. idx starts at 1. + function _getPointerProcHeapByIndex(uint192 idx) internal pure returns (uint256) { + // TODO: annoying error condition, can we avoid it? + if (idx == 0) { + revert("0 is not a valid key index"); + } + bytes5 directory = bytes5(0xffffffff01); + return uint256(bytes32(directory)) | (uint256(idx) << 24); + } + + // Returns the storage key that holds the procedure data with the given + // procedure name. + function _getPointerProcHeapByName(uint192 name) internal pure returns (uint256) { + bytes5 directory = bytes5(0xffffffff00); + return uint256(bytes32(directory)) | (uint256(name) << 24); + } + // The storage key that holds the Procedure Index of a procedure with the + // given procedure name. + function _getPointerProcedureIndexOnHeap(uint192 name) internal pure returns (uint256) { + uint256 pPointer = _getPointerProcHeapByName(name); + // The procedure index is stored at position 1 + return (pPointer+1); + } + + // The storage key that holds the Ethereum Address of the code of a + // procedure with the given procedure name. + function _getPointerProcedureAddress(uint192 name) internal pure returns (uint256) { + uint256 pPointer = _getPointerProcHeapByName(name); + // The procedure index is stored at position 1 + return (pPointer+1); + } + + + // The storage get and set functions + + function _get(uint256 pointer) internal view returns (uint256 val) { + assembly { + // Load Value + val := sload(pointer) + } + } + + function _set(uint256 pointer, uint256 value) internal { + assembly { + sstore(pointer, value) + } + } + + + // _get and _set functions + + function _getEntryProcedure() view internal returns (uint192 val) { + uint256 storageKey = _getPointerEntryProcedure(); + assembly { + val := sload(storageKey) + } + return val; + } + + function _setEntryProcedureRaw(uint192 procedureKey) internal { + uint256 storageKey = _getPointerEntryProcedure(); + assembly { + sstore(storageKey,procedureKey) + } + } + + function _getCurrentProcedure() view internal returns (uint192 val) { + uint256 storageKey = _getPointerCurrentProcedure(); + assembly { + val := sload(storageKey) + } + return val; + } + + function _setCurrentProcedure(uint192 procedureKey) internal { + uint256 storageKey = _getPointerCurrentProcedure(); + assembly { + sstore(storageKey,procedureKey) + } + } + + function _getKernelAddress() view internal returns (address val) { + uint256 storageKey = _getPointerKernelAddress(); + assembly { + val := sload(storageKey) + } + return val; + } + + function _setKernelAddress(address theAddress) internal { + uint256 storageKey = _getPointerKernelAddress(); + assembly { + sstore(storageKey, theAddress) + } + } + + // _get and _set functions which use the _getPointer functions above. + + // Given a Procedure Name, return it's index in the Procedure List (i.e. its + // Procedure Index). If the procedure is not in the list it will return a + // Procedure Index of zero. Zero is not a valid Procedure Index. + function _getProcedureIndex(uint192 name) internal view returns (uint192) { + uint256 procedureIndexPointer = _getPointerProcedureIndexOnHeap(name); + return uint192(_get(procedureIndexPointer)); + } +} diff --git a/contracts/ProcedureTable.sol b/contracts/ProcedureTable.sol index b668b97..a42984a 100644 --- a/contracts/ProcedureTable.sol +++ b/contracts/ProcedureTable.sol @@ -1,26 +1,10 @@ pragma solidity ^0.4.17; -library ProcedureTable { - using ProcedureTable for ProcedureTable.Self; - - struct Procedure { - // Equal to the index of the key of this item in keys, plus 1. - uint8 keyIndex; - address location; - Capability[] caps; - } - - struct Capability { - uint8 capType; - uint256[] values; - } +import "./KernelStorage.sol"; - struct Self {} +contract ProcedureTable is KernelStorage { // CAPABILITY_TYPES - uint8 constant CAP_NULL = 0; - uint8 constant CAP_PROC_CAP_PUSH = 1; - uint8 constant CAP_PROC_CAP_DELETE = 2; uint8 constant CAP_PROC_CALL = 3; uint8 constant CAP_PROC_REGISTER = 4; uint8 constant CAP_PROC_DELETE = 5; @@ -29,508 +13,437 @@ library ProcedureTable { uint8 constant CAP_LOG = 8; uint8 constant CAP_ACC_CALL = 9; - // Convert Pointer To File Pointer - // Takes a single byte and a full 256 bit storage location - function _filePointer(uint8 fileId, uint248 pointer) internal pure returns (uint256) { - // Mask to Uint256 - // Overwrite the most significant byte of pointer with fileId - return uint256(pointer) | (uint256(fileId) << 248); - } - - function _get(uint8 fileId, uint248 _pointer) internal view returns (uint256 val) { - uint256 pointer = _filePointer(fileId, _pointer); - assembly { - // Load Value - val := sload(pointer) - } - } - - function _set(uint8 fileId, uint248 _pointer, uint256 value) internal { - // Convert Mask to Uint256 - uint256 pointer = _filePointer(fileId, _pointer); - assembly { - sstore(pointer, value) - } - } - - function _getLengthPointer() internal pure returns (uint248) { - bytes8 directory = bytes8(keccak256("keyPointer")); - return uint248(directory) << 240; - } - function _getKeyPointerByIndex(uint8 idx) internal pure returns (uint248) { - bytes8 directory = bytes8(keccak256("keyPointer")); - return (uint248(directory) << 240) + 1 + uint248(idx); - } - - function _getProcedurePointerByKey(uint192 key) internal pure returns (uint248) { - // Procedure data is stored under the procedurePointer "directory". The - // location of the procedure data is followed by the name/key of the - // procedure. - // keccak256("procedurePointer") is 0x85a94e7072614513158f210a7e69624a1aadd1603708f4f46564d8dd4195f87d - bytes32 directory = keccak256("procedurePointer"); - // The case to uint240 drops the most significant bytes converting the value to - // 0xd8dd4195f87d0000000000000000000000000000000000000000000000000000 - // then left shift the value 240 bits, losing all but the least signficant byte, the result is - // proc-prefix procedure key - // 0xd8dd4195f87d--000000000000000000000000000000000000000000000000 - // We than OR that with the key, which is 192 bits or 24 bytes. This is - // the key provided on creation. If the key was 0x555555555555555555555555555555555555555555555555 - // then the resulting uint248 would be - // 0xd8dd4195f87d5555555555555555555555555555555555555555555555555 - // TODO: it seems like this might not be what was intended - return uint248(uint240(uint240(directory) << 192) | uint240(key)) << 8; + function _storeProcedure(uint192 key, uint192 keyIndex, address location, uint256[] caps) internal { + // Procedure List + // Store the the procedure key in the procedure list + uint256 keyPointer = _getPointerProcHeapByIndex(keyIndex); + _set(keyPointer, key); + // Procedure Heap + // Get the storage address of the procedure data. This is the storage + // key which contains all of the procedure data. + uint256 pPointer = _getPointerProcHeapByName(key); + _serialiseProcedure(pPointer, keyIndex, location, caps); } - function _getProcedureByKey(uint192 key) internal view returns (Procedure memory p) { - // pPointer is a uint248, which is all but one byte of a storage - // address. This means that there are 256 storage keys "under" - // this pPointer (at 32 bytes each this means 8,192 bytes of storage). - uint248 pPointer = _getProcedurePointerByKey(key); - // The first storage location (0) is used to store the keyIndex. - p.keyIndex = uint8(_get(0, pPointer)); - // The second storage location (1) is used to store the address of the - // contract. - p.location = address(_get(0, pPointer + 1)); - // The thirs storage location (2) is used to store the number of caps - uint256 nCaps = _get(0, pPointer + 2); - p.caps = new Capability[](nCaps); - // n is the cap index - uint256 n = 0; - // The rest of the 256 keys are (or can be) used for the caps - for (uint248 i = 0; i < (256-3); i++) { - if (n >= nCaps) { - break; - } - uint256 thisCurrentCapLength = _get(0, pPointer+3+i); - p.caps[n].capType = uint8(_get(0, pPointer+3+i+1)); - // subtract 1 from cap length because it includes the type - uint256 nValues = thisCurrentCapLength - 1; - // uint256 nValues = 2; - p.caps[n].values = new uint256[](nValues); - for (uint248 k = 0; k < nValues; k++) { - p.caps[n].values[k] = uint256(_get(0, pPointer+3+i+2+k)); - } - i = i + uint248(thisCurrentCapLength); - n++; - } - } - - function checkRegisterCapability(Self storage /* self */, uint192 key, uint256 reqCapIndex) internal view returns (bool) { - Procedure memory p = _getProcedureByKey(uint192(key)); - - // If the requested cap is out of the bounds of the cap table, we - // clearly don't have the capability; - if ((p.caps.length == 0) || (reqCapIndex > (p.caps.length - 1))) { - return false; - } - Capability memory cap = p.caps[reqCapIndex]; - // If the capability type is not REGISTER (11) it is the wrong type of - // capability and we should reject - if (cap.capType != CAP_PROC_REGISTER) { - return false; - } - // If the cap is empty it implies all procedures are ok - if (cap.values.length == 0) { - return true; - } else { - // the register cap should always be empty, otherwise it is invalid - return false; - } + function _serialiseProcedure(uint256 pPointer, uint192 keyIndex, address location, uint256[] caps) internal { + // Store the address of the code contract + _set(pPointer + 0, uint256(location)); + // Store the keyIndex + _set(pPointer + 1, uint256(keyIndex)); + // Clear any previously defined caps by setting the clists to 0-length + _clearCaps(pPointer); + _serialiseCapArray(pPointer, caps); } - function checkDeleteCapability(Self storage /* self */, uint192 key, bytes24 procedureKey, uint256 reqCapIndex) internal view returns (bool) { - Procedure memory p = _getProcedureByKey(uint192(key)); - - // If the requested cap is out of the bounds of the cap table, we - // clearly don't have the capability; - if ((p.caps.length == 0) || (reqCapIndex > (p.caps.length - 1))) { - return false; - } - Capability memory cap = p.caps[reqCapIndex]; - // If the capability type is not DELETE it is the wrong type of - // capability and we should reject - if (cap.capType != CAP_PROC_DELETE) { - return false; - } - // If the cap is empty it implies all procedures are ok - if (cap.values.length == 0) { - return true; - } else { - // otherwise we cycle through the permitted procedure keys and see - // if we can find the requested on - for (uint256 i = 0; i < cap.values.length; i++) { - if (bytes24(cap.values[i]/0x10000000000000000) == procedureKey) { - return true; + function _serialiseCapArray(uint256 pPointer, uint256[] caps) internal { + uint192 currentProcedure = _getCurrentProcedure(); + // If there is no current procedure, we can do anything. + // TODO: this is something for consideration, we often ask the kernel to + // register things directly. + + // Variables for later use + uint256 currentLength; + uint256 val; + uint256 j; + uint256 thisTypeLength; + // i is the index into the caps array, which is a series of 32-byte values + for (uint256 i = 0; (i+2) < caps.length; ) { + uint256 capSize = caps[i+0]; + uint256 capType = caps[i+1]; + // TODO: check for overflows + uint8 capIndex = uint8(caps[i+2]); + + if (capSize == 3) { + // If the capSize is 3, we don't need to create a subset, we just + // copy whatever is at capIndex + + // We can't deal with this properly yet, but for the pursposes of setEntry, we will just set an empty value + currentLength = _get(pPointer | (capType*0x10000)); + // Increment length + _set(pPointer | (capType*0x10000), currentLength + 1); + + if (currentProcedure == 0) { + // If there is no currentProcedure we are under direct control + // of the kernel, and any capability is the max cap of that type + // serialise Procedure Call cap + + currentLength = _get(pPointer | (capType*0x10000)); + // We branch here as we need to insert the maximum capability, which varies for each type + if (capType == CAP_PROC_CALL) { + // Insert a 0 value (which means the prefix will be zero, i.e. the maximum capability) + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x00, val); + } else if (capType == CAP_STORE_WRITE) { + // Insert a base address of zero + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x00, val); + // Insert "number of additional keys as MAX-1 + val = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x01, val); + } else if (capType == CAP_LOG) { + // Number of requred caps is zero + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x00, val); + // set topic 1 to zero (TODO: not required but defensive) + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x01, val); + // set topic 2 to zero (TODO: not required but defensive) + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x02, val); + // set topic 3 to zero (TODO: not required but defensive) + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x03, val); + // set topic 4 to zero (TODO: not required but defensive) + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x04, val); + } else if (capType == CAP_PROC_REGISTER) { + // Insert a 0 value (which means the prefix will be zero, i.e. the maximum capability) + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x00, val); + } else if (capType == CAP_PROC_DELETE) { + // Insert a 0 value (which means the prefix will be zero, i.e. the maximum capability) + val = 0; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x00, val); + } else if (capType == CAP_PROC_ENTRY) { + // This cap does not require any values to be set + } else if (capType == CAP_ACC_CALL) { + // Insert the max value, which is the first 2 bits set on, and the remainder zero + val = 0xc000000000000000000000000000000000000000000000000000000000000000; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x00, val); + } else { + revert("unknown capability"); + } + // Increment length + _set(pPointer | (capType*0x10000), currentLength + 1); + } else { + // Otherwise we need to copy the capability from the current + // procedure. + + // First check that capIndex (from which we derive our cap) + // actually exists. This just checks that the list of that + // type is long enough. + thisTypeLength = _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | (0)*0x100); + if (capIndex >= thisTypeLength) { + // The c-list of this type is not long enough. + // revert("bad cap index"); + assembly { + mstore(0,0x88) + revert(0,32) + } + } + + // Serialise the cap. + currentLength = _get(pPointer | (capType*0x10000)); + for (j = 0; (j+3) < capSize; j++) { + val = caps[i+3+j]; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | j, val); + } + // Increment length + _set(pPointer | (capType*0x10000), currentLength + 1); + + + val = _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | (capIndex + 1)*0x100); + // Store that in the procedure we are registering + // Get the current number of caps of this type for this + // proc. + currentLength = _get(pPointer | (capType*0x10000)); + // A Procedure Call cap has one 32-byte value. Set it here at + // position 0 + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | 0x00, val); + // Increment length + _set(pPointer | (capType*0x10000), currentLength + 1); + } + } else { + // If the capSize is not three, we want to create a subset. + // For testing purposes at this stage we will ignore subsets + // and simply allow whatever is dictated by the request. + if (currentProcedure == 0) { + // Get the current number of caps of this type for this + // proc. + currentLength = _get(pPointer | (capType*0x10000)); + for (j = 0; (j+3) < capSize; j++) { + val = caps[i+3+j]; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | j, val); + } + // Increment length + _set(pPointer | (capType*0x10000), currentLength + 1); + } else { + // First check that capIndex (from which we derive our cap) + // actually exists. This just checks that the list of that + // type is long enough. + thisTypeLength = _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | (0)*0x100); + if (capIndex >= thisTypeLength) { + // The c-list of this type is not long enough. + // revert("bad cap index"); + assembly { + mstore(0,0x88) + revert(0,32) + } + } + + bool subset = isSubset(currentProcedure, capType, capIndex, caps, i); + if (!subset) { + revert("cap not valid subset"); + } + + // Serialise the cap. + currentLength = _get(pPointer | (capType*0x10000)); + for (j = 0; (j+3) < capSize; j++) { + val = caps[i+3+j]; + _set(pPointer | (capType*0x10000) | ((currentLength+1)*0x100) | j, val); + } + // Increment length + _set(pPointer | (capType*0x10000), currentLength + 1); } } + i += capSize; } - return false; } - function checkSetEntryCapability(Self storage /* self */, uint192 key, uint256 reqCapIndex) internal view returns (bool) { - Procedure memory p = _getProcedureByKey(uint192(key)); - - // If the requested cap is out of the bounds of the cap table, we - // clearly don't have the capability; - if ((p.caps.length == 0) || (reqCapIndex > (p.caps.length - 1))) { - return false; - } - Capability memory cap = p.caps[reqCapIndex]; - // If the capability type is not ENTRY it is the wrong type of - // capability and we should reject - if (cap.capType != CAP_PROC_ENTRY) { - return false; - } - // If the cap is empty it implies all procedures are ok - if (cap.values.length == 0) { - return true; - } else { - // the register cap should always be empty, otherwise it is invalid - return false; - } - } - - function checkCallCapability(Self storage /* self */, uint192 key, bytes24 procedureKey, uint256 reqCapIndex) internal view returns (bool) { - Procedure memory p = _getProcedureByKey(uint192(key)); - - // If the requested cap is out of the bounds of the cap table, we - // clearly don't have the capability; - if ((p.caps.length == 0) || (reqCapIndex > (p.caps.length - 1))) { - return false; - } - Capability memory cap = p.caps[reqCapIndex]; - // If the capability type is not CALL (0x3) it is the wrong type of - // capability and we should reject - if (cap.capType != CAP_PROC_CALL) { - return false; - } - // The cap should contain a single 32-byte value. - if (cap.values.length != 1) { - return false; - } - // Put that value in a local variable. - uint256 value = cap.values[0]; - uint8 prefix = 0xff; - bytes24 baseKey = 0; - bytes24 clearedBaseKey; - bytes24 clearedReqKey; - assembly { - // Shift that 32 bytes to the right to obtain the first byte only - prefix := div(value,0x100000000000000000000000000000000000000000000000000000000000000) - // Shift the value to get the procedure key left align (as it should - // be for compatibility with bytes24). - baseKey := mul(value,0x10000000000000000) - let q := signextend(1,2) - // h is a large number we will use for arithmetic - let h := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - // y is a number with $prefix 1s at the start - let y := mul(h,exp(2,sub(256,prefix))) - clearedBaseKey := and(y,baseKey) - clearedReqKey := and(y,procedureKey) - } - return clearedBaseKey == clearedReqKey; + // Clear the capabilities of a procedure of the given name. + function _clearCaps(uint256 pPointer) internal { + _set(pPointer | (CAP_PROC_CALL*0x10000), 0); + _set(pPointer | (CAP_PROC_REGISTER*0x10000), 0); + _set(pPointer | (CAP_PROC_DELETE*0x10000), 0); + _set(pPointer | (CAP_PROC_ENTRY*0x10000), 0); + _set(pPointer | (CAP_STORE_WRITE*0x10000), 0); + _set(pPointer | (CAP_LOG*0x10000), 0); + _set(pPointer | (CAP_ACC_CALL*0x10000), 0); } - function checkAccCallCapability(Self storage /* self */, uint192 key, address account, uint256 amount, uint256 reqCapIndex) internal view returns (bool) { - Procedure memory p = _getProcedureByKey(uint192(key)); + function isSubset(uint192 currentProcedure, uint256 capType, uint256 capIndex, uint256[] caps, uint256 i) internal view returns (bool) { + uint256 currentVal; + uint256 requestedVal; + uint256 b; + uint256 current; + uint256 req; + // Check if our cap is a subset. If not revert. + // The subset logic of these three caps are the same + if (capType == CAP_PROC_CALL || capType == CAP_PROC_REGISTER || capType == CAP_PROC_DELETE) { + currentVal = _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | ((capIndex + 1)*0x100) | 0x00); + requestedVal = caps[i+3+0]; + + // Check that the prefix of B is >= than the prefix of A. + current = currentVal & 0xff00000000000000000000000000000000000000000000000000000000000000; + req = requestedVal & 0xff00000000000000000000000000000000000000000000000000000000000000; + if (current > req) { + return false; + } - // If the requested cap is out of the bounds of the cap table, we - // clearly don't have the capability; - if ((p.caps.length == 0) || (reqCapIndex > (p.caps.length - 1))) { - return false; - } - Capability memory cap = p.caps[reqCapIndex]; - // If the capability type is the wrong type of capability and we - // should reject - if (cap.capType != CAP_ACC_CALL) { - return false; - } - // The first value is CallAny. - bool callAny = cap.values[0] != 0; - // The second value is SendValue - bool sendValue = cap.values[1] != 0; - // If CallAny is true, all addresses are ok. If it is false we must - // check that the account requested equals the one permitted in the - // capability. - if (!callAny) { - if (address(cap.values[2]) != account) { - // The account requested is not the one specified, return false. + // b is "currentMask" + b = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff << ((192 - (current >> 248))); + current = b & currentVal & 0x0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff; + req = b & requestedVal & 0x0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff; + // Insert a 0 value (which means the prefix will be zero, i.e. the maximum capability) + // Check that the first $prefix bits of the two keys are the same + if (current != req) { return false; } - } - // If SendValue is false, the amount sent must be zero. - if (!sendValue) { - if (amount != 0) { - // SendValue is false, but a non-zero amount was requested to be - // transferred. + return true; + } else if (capType == CAP_STORE_WRITE) { + // Base storage address + currentVal = _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | ((capIndex+1)*0x100) | 0x00); + requestedVal = caps[i+3+0]; + if (requestedVal < currentVal) { return false; } - } - return true; - } - function checkWriteCapability(Self storage /* self */, uint192 key, uint256 toStoreAddress, uint256 reqCapIndex) internal view returns (bool) { - Procedure memory p = _getProcedureByKey(uint192(key)); - - // If the requested cap is out of the bounds of the cap table, we - // clearly don't have the capability; - if ((p.caps.length == 0) || (reqCapIndex > (p.caps.length - 1))) { - return false; - } - Capability memory cap = p.caps[reqCapIndex]; - uint256 capabilityType = cap.capType; - // If the capability type is not WRITE (0x7) it is the wrong type of - // capability and we should reject - if (capabilityType != CAP_STORE_WRITE) { - return false; - } - // We need two values for a valid write cap - if (cap.values.length < 2) { - return false; - } - uint256 capabilityKey = cap.values[0]; - uint256 capabilitySize = cap.values[1]; - - if (capabilityType == CAP_STORE_WRITE - && toStoreAddress >= capabilityKey - && toStoreAddress <= (capabilityKey + capabilitySize)) { + // Number of additional storage keys + currentVal += _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | ((capIndex+1)*0x100) | 0x01); + requestedVal += caps[i+3+1]; + if (requestedVal > currentVal) { + return false; + } + // Even though there exists invalid capabilities, we don't check for + // them here as it wouldn't cover all circumstances. If we wan to + // check for it we should do it more generally. + // if (requestedVal == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) { + // return false; + // } return true; - } - } - - function checkLogCapability(Self storage /* self */, uint192 key, bytes32[] reqTopics, uint256 reqCapIndex) internal view returns (bool) { - Procedure memory p = _getProcedureByKey(uint192(key)); - - // If the requested cap is out of the bounds of the cap table, we - // clearly don't have the capability; - if ((p.caps.length == 0) || (reqCapIndex > (p.caps.length - 1))) { - return false; - } - Capability memory cap = p.caps[reqCapIndex]; - uint256 capabilityType = cap.capType; - // If the capability type is not LOG (0x9) it is the wrong type of - // capability and we should reject - if (capabilityType != CAP_LOG) { - return false; - } - // The number of topics is simply the number of keys of the cap (i.e. - // not including the type) - uint256 nTopics = cap.values.length; - // Then we retrieve the topics - bytes32[] memory capTopics = new bytes32[](nTopics); - for (uint256 i = 0; i < nTopics; i++) { - capTopics[i] = bytes32(cap.values[i]); - } - - // Check that all of the topics required by the cap are satisfied. That - // is, for every topic in the capability, the corresponding exists in - // the system call and is set to that exact value. First we check that - // there are enough topics in the request. - if (reqTopics.length < capTopics.length) { - // The system call specifies an insufficient number of topics - return false; - } - for (uint256 j = 0; j < capTopics.length; j++) { - if (reqTopics[j] != capTopics[j]) { + } else if (capType == CAP_LOG) { + // First we check the number of required topics. The number of + // required topics of the requested cap must be equal to or greater + // than the number of required topics for the current cap. + currentVal = _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | ((capIndex+1)*0x100) | 0x00); + requestedVal = caps[i+3+0]; + if (requestedVal < currentVal) { return false; } - } - return true; - } - function _storeProcedure(Procedure memory p, uint192 key) internal { - // Get the storage address of the name/key of the procedure. In this - // scope "key" is the 24 byte name which is provided by the user. The - // procedure "p" has already been given an index (p.keyIndex) which is - // the offset where the name/key is stored. - uint248 keyPointer = _getKeyPointerByIndex(p.keyIndex); - // Store the name/key at this location. - _set(0, keyPointer, key); - - // Get the storage address of the procedure data. This is the storage - // key which contains all of the procedure data. - uint248 pPointer = _getProcedurePointerByKey(key); - _serialiseProcedure(p, 0, pPointer); - } - - function _serialiseProcedure(Procedure memory p, uint8 storagePage, uint248 pPointer) internal { - // Store the keyIndex at this location - _set(storagePage, pPointer, p.keyIndex); - // Store the address at the loction after this (making this data 2 - // uint256 wide). - _set(storagePage, pPointer + 1, uint256(p.location)); - - // The first value of the array is the number of capabilities - _set(storagePage, pPointer + 2, p.caps.length); - _serialiseCapArray(p, storagePage, pPointer); - } - - function _serialiseCapArray(Procedure memory p, uint8 storagePage, uint248 pPointer) internal { - // n is the storage key index - uint248 n = 0; - // i is the index of the cap - for (uint248 i = 0; i < p.caps.length; i++) { - uint256 nValues = p.caps[i].values.length; - uint256 capSize = nValues + 1; - _set(storagePage, pPointer + 3 + n, capSize); n++; - _set(storagePage, pPointer + 3 + n, p.caps[i].capType); n++; - for (uint248 j = 0; j < nValues; j++) { - _set(storagePage, pPointer + 3 + n, p.caps[i].values[j]); n++; + // Next we check that the topics required by the current cap are + // also required by the requested cap. + for (b = 1; b <= currentVal; b++) { + if (caps[i+3+b] != _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | ((capIndex+1)*0x100) | b)) { + return false; + } } - } - } - - function _freeProcedure(uint248 pPointer) internal { - _set(0, pPointer, 0); - _set(0, pPointer + 1, 0); - } - - // Just returns an array of all the procedure data (257 32-byte values) concatenated. - function returnRawProcedureTable(Self storage self) internal view returns (uint256[]) { - bytes24[] memory keys = self.getKeys(); - uint256 len = keys.length; - // max is 256 keys times the number of procedures - uint256[] memory r = new uint256[](len*257); - // The rest are the elements - uint256 n = 0; - for (uint248 i = 0; i < len ; i++) { - uint192 key = uint192(keys[i]); - uint248 pPointer = _getProcedurePointerByKey(key); - r[n] = uint256(key); n++; - for (uint248 j = 0; j < 256; j++) { - r[n] = _get(0, pPointer+j); n++; + return true; + } else if (capType == CAP_PROC_ENTRY) { + // All of these caps are identical, therefore any cap of this type + // is the subset of another + return true; + } else if (capType == CAP_ACC_CALL) { + // If the requested value of callAny is true, then the requested + // value of callAny must be true. + currentVal = _get(_getPointerProcHeapByName(currentProcedure) | (capType*0x10000) | ((capIndex + 1)*0x100) | 0x00); + requestedVal = caps[i+3+0]; + current = currentVal & 0x8000000000000000000000000000000000000000000000000000000000000000; + req = requestedVal & 0x8000000000000000000000000000000000000000000000000000000000000000; + // If req != 0 (that is, equals 1, requested callAny flag is true) and + // current == 0 (that is, current callAny flag is false) + // then fail + if (req != 0) { + // requested callAny == true + if (current == 0) { + return false; + } + } else { + // requested callAny == false + // if the current value is callAny, we don't care about the + // value of ethAddress. If the current value of callAny is + // 0 (false) we must check that the addresses are the same + if (current == 0) { + // the addresses must match + // get the current and required addresses + current = currentVal & 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; + req = requestedVal & 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; + if (current != req) { + return false; + } + } + } + // if the requested sendValue flag is true, the current sendValue + // flag must also be true. + // get the sendValue flags + current = currentVal & 0x4000000000000000000000000000000000000000000000000000000000000000; + req = requestedVal & 0x4000000000000000000000000000000000000000000000000000000000000000; + if (req != 0 && current == 0) { + return false; } + return true; + } else { + revert("unknown capability"); } - return r; } - function returnProcedureTable(Self storage self) internal view returns (uint256[]) { - bytes24[] memory keys = self.getKeys(); - uint256 len = keys.length; - // max is 256 keys times the number of procedures - uint256[] memory r = new uint256[](len*256); - // The rest are the elements - uint256 n = 0; - for (uint248 i = 0; i < len ; i++) { - uint192 key = uint192(keys[i]); - Procedure memory p = _getProcedureByKey(key); - r[n] = uint256(key); n++; - // Store the keyIndex at this location - r[n] = p.keyIndex; n++; - r[n] = uint256(p.location); n++; - // number of capabilities in array - r[n] = p.caps.length; n++; - // cycle through each capability - for (uint248 j = 0; j < p.caps.length; j++) { - // we add 1 to account for the capType - uint256 capSize = p.caps[j].values.length + 1; - r[n] = capSize; n++; - r[n] = p.caps[j].capType; n++; - for (uint248 k = 0; k < p.caps[j].values.length; k++) { - r[n] = p.caps[j].values[k]; n++; - } - } + function capTypeToSize(uint256 capType) internal pure returns (uint256) { + if (capType == CAP_PROC_CALL) { + return 1; + } else if (capType == CAP_STORE_WRITE) { + return 2; + } else if (capType == CAP_LOG) { + return 5; + } else if (capType == CAP_PROC_REGISTER) { + return 1; + } else if (capType == CAP_PROC_DELETE) { + return 1; + } else if (capType == CAP_PROC_ENTRY) { + return 0; + } else if (capType == CAP_ACC_CALL) { + return 1; + } else { + revert("invalid capability type"); } - return r; + } - function insert(Self storage /* self */, bytes24 key, address value, uint256[] caps) internal returns (bool replaced) { + function insert(bytes24 key, address location, uint256[] caps) internal returns (bool inserted) { // First we get retrieve the procedure that is specified by this key, if // it exists, otherwise the struct we create in memory is just // zero-filled. - Procedure memory p = _getProcedureByKey(uint192(key)); - // We then write or overwrite the various properties - p.location = value; + uint192 keyIndex = _getProcedureIndex(uint192(key)); // we just copy in the table in verbatim as long as its length is less // than 128 (arbitrary, but less than 256 minus room for other parameters) if (caps.length > 128) { revert(); } - // The capabilities are parsed here. We neeed to pass in the Procedure - // struct as solidity can't return complex data structures. - _parseCaps(p,caps); - // If the keyIndex is not zero then that indicates that the procedure // already exists. In this case *WE HAVE NOT OVERWRITTEN * the values, // as we have not called _storeProcdure. - if (p.keyIndex > 0) { - return true; + if (keyIndex > 0) { + return false; // If the keyIndex is zero (it is unsigned and cannot be negative) then // it means the procedure is new. We must therefore assign it a key // index. } else { // First we retrieve a pointer to the Procedure Table Length value. - uint248 lenP = _getLengthPointer(); + uint256 lenP = _getPointerProcedureTableLength(); // We then dereference that value. - uint256 len = _get(0, lenP); + uint256 len = _get(lenP); // We assign this procedure the next keyIndex, i.e. len+1 - p.keyIndex = uint8(len + 1); + keyIndex = uint8(len + 1); // We increment the Procedure Table Length value - _set(0, lenP, len + 1); + _set(lenP, len + 1); // We actually commit the values in p to storage - _storeProcedure(p, uint192(key)); - return false; + _storeProcedure(uint192(key), keyIndex, location, caps); + return true; } } - function _parseCaps(Procedure memory p, uint256[] caps) internal pure { - // count caps - uint256 nCaps = 0; - for (uint256 i = 0; i < caps.length; i++) { - uint256 capLength = caps[i]; - i = i + capLength; - nCaps++; - } - p.caps = new Capability[](nCaps); - uint256 n = 0; - for (i = 0; i < caps.length; ) { - capLength = caps[i]; i++; - uint256 nValues = capLength - 1; - p.caps[n].values = new uint256[](nValues); - p.caps[n].capType = uint8(caps[i]); i++; - for (uint256 j = 0; j < nValues; j++) { - p.caps[n].values[j] = caps[i];i++; - } - n++; - } - } + function remove(bytes24 key) internal returns (bool success) { - function remove(Self storage /* self */, bytes24 key) internal returns (bool success) { - Procedure memory p1 = _getProcedureByKey(uint192(key)); + // Get the key index of the procedure we are trying to delete. + uint192 p1Index = _getProcedureIndex(uint192(key)); - if (p1.keyIndex == 0) + // If the value does not exist in the procedure list we return 0. + if (p1Index == 0) return false; // When we remove a procedure, we want to move another procedure into // this "slot" to keep the active keys contiguous // First we get the storage address of the Procedure Table Length - uint248 lenP = _getLengthPointer(); + uint256 lenP = _getPointerProcedureTableLength(); // We then dereference that to get the value - uint256 len = _get(0, lenP); - - if (p1.keyIndex <= len) { - // Move an existing element into the vacated key slot. - uint248 p1P = _getProcedurePointerByKey(uint192(key)); - uint248 key1P = _getKeyPointerByIndex(p1.keyIndex); - - uint248 key2P = _getKeyPointerByIndex(uint8(len)); - uint192 key2 = uint192(_get(0, key2P)); - - uint248 p2P = _getProcedurePointerByKey(key2); + uint256 len = _get(lenP); + + if (p1Index <= len) { + // Three things need to happen: + // When a procedure is deleted from the kernel: + // 1. If the procedure key is the same as the Entry Procedure Key, abort and + // throw an error. + // 2. If the procedure key does not exist in the list (i.e. when looking on the + // procedure heap no procedure index is associated with it), abort and throw + // an error. + // 3. The length value is decremented by one. + // 4. If the procedure being deleted is not the last in the list (i.e. it’s procedure + // index does not equal the length of the procedure list), the last in the list is + // copied to overwrite the key being deleted. This also accounts for the case + // of an empty list. - // This sets p2.keyIndex = p1.keyIndex - _set(0, p2P, p1.keyIndex); - _set(0, key1P, key2); - - // Free Old Key - _set(0, key2P, 0); + // Decrement Keys Length + _set(lenP, len - 1); + + if (p1Index != len) { + // 1. Zero out the Procedure Index value on the heap + _set(_getPointerProcedureIndexOnHeap(uint192(key)), 0); + // 2. Get the key of the last value in the list (we will move + // that into the newly vacated position) + uint256 lastKey = _get(procedureIndexToLocation(uint192(len))); + // 3. Zero out the last value in the procedure list + _set(procedureIndexToLocation(uint192(len)), 0); + // 4. Set the newly vacated index to (what was) the last key + _set(procedureIndexToLocation(p1Index), lastKey); + // 5. Update the value of the Procedure Index in the procedure + // heap for this procedure + _set(_getPointerProcedureIndexOnHeap(uint192(lastKey)), p1Index); + } else { + // This procedure is the last in the list, so we simply need to + // zero out that value, and zero out the Procedure Index in + // the procedure heap + // 1. Zero out the Procedure Index value on the heap + _set(_getPointerProcedureIndexOnHeap(uint192(key)), 0); + // 2. Zero out the last value in the procedure list + _set(procedureIndexToLocation(uint192(len)), 0); + } + // TODO: this is completely optional so is left for now. // Free P1 - _freeProcedure(p1P); - - // Decrement Keys Length - _set(0, lenP, len - 1); + // _freeProcedure(p1P); + uint256 pPointer = _getPointerProcHeapByName(uint192(key)); + _set(pPointer, 0); + // _set(pPointer + 1, 0); return true; } else { @@ -538,36 +451,40 @@ library ProcedureTable { } } - function contains(Self storage /* self */, bytes24 key) internal view returns (bool exists) { - return _get(0, _getProcedurePointerByKey(uint192(key))) > 0; + function contains(bytes24 key) internal view returns (bool exists) { + return _get(_getPointerProcHeapByName(uint192(key))) > 0; + } + + function size() internal view returns (uint) { + return _get(_getPointerProcedureTableLength()); } - function size(Self storage /* self */) internal view returns (uint) { - return _get(0, _getLengthPointer()); + function get(bytes24 key) internal view returns (address) { + return address(_get(_getPointerProcHeapByName(uint192(key)) + 0)); } - function get(Self storage /* self */, bytes24 key) internal view returns (address) { - return address(_get(0, _getProcedurePointerByKey(uint192(key)) + 1)); + function procedureIndexToLocation(uint192 procedureIndex) internal pure returns (uint256) { + uint256 lenP = _getPointerProcedureTableLength(); + return (lenP + (procedureIndex << 24)); } - function getKeys(Self storage /* self */) internal view returns (bytes24[] memory keys) { - uint248 lenP = _getLengthPointer(); - uint256 len = _get(0, lenP); + function getKeys() public view returns (bytes24[] memory keys) { + uint256 lenP = _getPointerProcedureTableLength(); + uint256 len = _get(lenP); keys = new bytes24[](len); - for (uint248 i = 0; i < len; i += 1) { - // We use +2 here because the name/key is the second uint256 store, - // the first being the keyIndex. - keys[i] = bytes24(_get(0, lenP + i + 2)); + for (uint256 i = 0; i < len; i++) { + // We use +1 here because the length of the procedure list is + // stored in the first position + keys[i] = bytes24(_get(lenP + ((i+1) << 24))); } - } - function getKeyByIndex(Self storage /* self */, uint8 idx) internal view returns (uint192) { - return uint192(_get(0, _getKeyPointerByIndex(idx))); + function getKeyByIndex(uint8 idx) internal view returns (uint192) { + return uint192(_get(_getPointerProcHeapByIndex(idx))); } - function getValueByIndex(Self storage self, uint8 idx) internal view returns (address) { - return address(_get(0, _getProcedurePointerByKey(self.getKeyByIndex(idx)) + 1)); + function getValueByIndex(uint8 idx) internal view returns (address) { + return address(_get(_getPointerProcHeapByName(getKeyByIndex(idx)) + 1)); } } diff --git a/contracts/TestKernel.sol b/contracts/TestKernel.sol index 7c9c446..c7f4e75 100644 --- a/contracts/TestKernel.sol +++ b/contracts/TestKernel.sol @@ -1,11 +1,10 @@ pragma solidity ^0.4.17; -import "./Kernel.sol"; +import "./KernelInstance.sol"; // Kernel Interface for Testing -contract TestKernel is Kernel { - constructor() public { - // kernelAddress = WhatIsMyAddress.get(); +contract TestKernel is KernelInstance { + constructor(address initProcAddress) KernelInstance(initProcAddress) public { // This is an example kernel global variable for testing. assembly { sstore(0x8000,3) @@ -33,7 +32,7 @@ contract TestKernel is Kernel { } function setEntryProcedure(bytes24 key) public { - entryProcedure = key; + _setEntryProcedure(key); } // Create a validated procedure. diff --git a/contracts/test/valid/NestedCalls/FifthNestedCall.sol b/contracts/test/valid/NestedCalls/FifthNestedCall.sol index 4dcb564..8ed83ed 100644 --- a/contracts/test/valid/NestedCalls/FifthNestedCall.sol +++ b/contracts/test/valid/NestedCalls/FifthNestedCall.sol @@ -11,6 +11,6 @@ contract FifthNestedCall is BeakerContract { // End function G() public { // First we do the store for FirstNestedCall - write(1, 0x8005, 79); + write(0, 0x8005, 79); } -} \ No newline at end of file +} diff --git a/contracts/test/valid/NestedCalls/FirstNestedCall.sol b/contracts/test/valid/NestedCalls/FirstNestedCall.sol index aad4b6b..7589557 100644 --- a/contracts/test/valid/NestedCalls/FirstNestedCall.sol +++ b/contracts/test/valid/NestedCalls/FirstNestedCall.sol @@ -12,7 +12,7 @@ contract FirstNestedCall is BeakerContract { // End function G() public { // First we do the store for FirstNestedCall - write(1, 0x8001, 75); + write(0, 0x8001, 75); // Begin our call to SecondNestedCall bytes memory input = new bytes(4); @@ -23,7 +23,7 @@ contract FirstNestedCall is BeakerContract { input[2] = functionSelector[2]; input[3] = functionSelector[3]; - proc_call(2, "SecondNestedCall", input); + proc_call(0, "SecondNestedCall", input); // Being our call to SixthNestedCall bytes memory input2 = new bytes(4); @@ -34,6 +34,6 @@ contract FirstNestedCall is BeakerContract { input2[2] = functionSelector2[2]; input2[3] = functionSelector2[3]; - proc_call(2, "SixthNestedCall", input2); + proc_call(0, "SixthNestedCall", input2); } } diff --git a/contracts/test/valid/NestedCalls/FourthNestedCall.sol b/contracts/test/valid/NestedCalls/FourthNestedCall.sol index 1c2f98b..514cb65 100644 --- a/contracts/test/valid/NestedCalls/FourthNestedCall.sol +++ b/contracts/test/valid/NestedCalls/FourthNestedCall.sol @@ -12,6 +12,6 @@ contract FourthNestedCall is BeakerContract { // End function G() public { // First we do the store for FirstNestedCall - write(1, 0x8004, 78); + write(0, 0x8004, 78); } -} \ No newline at end of file +} diff --git a/contracts/test/valid/NestedCalls/SecondNestedCall.sol b/contracts/test/valid/NestedCalls/SecondNestedCall.sol index 8b19453..f97f7ab 100644 --- a/contracts/test/valid/NestedCalls/SecondNestedCall.sol +++ b/contracts/test/valid/NestedCalls/SecondNestedCall.sol @@ -14,7 +14,7 @@ contract SecondNestedCall is BeakerContract { // End function G() public { // First we do the store for FirstNestedCall - write(1, 0x8002, 76); + write(0, 0x8002, 76); // Being our call to ThirdNestedCall bytes memory input1 = new bytes(4); @@ -25,7 +25,7 @@ contract SecondNestedCall is BeakerContract { input1[2] = functionSelector1[2]; input1[3] = functionSelector1[3]; - proc_call(2, "ThirdNestedCall", input1); + proc_call(0, "ThirdNestedCall", input1); // Being our call to FifthNestedCall bytes memory input2 = new bytes(4); @@ -36,6 +36,6 @@ contract SecondNestedCall is BeakerContract { input2[2] = functionSelector2[2]; input2[3] = functionSelector2[3]; - proc_call(2, "FifthNestedCall", input2); + proc_call(0, "FifthNestedCall", input2); } } diff --git a/contracts/test/valid/NestedCalls/SixthNestedCall.sol b/contracts/test/valid/NestedCalls/SixthNestedCall.sol index 6a15394..70e5382 100644 --- a/contracts/test/valid/NestedCalls/SixthNestedCall.sol +++ b/contracts/test/valid/NestedCalls/SixthNestedCall.sol @@ -12,6 +12,6 @@ contract SixthNestedCall is BeakerContract { // End function G() public { // First we do the store for FirstNestedCall - write(1, 0x8006, 80); + write(0, 0x8006, 80); } -} \ No newline at end of file +} diff --git a/contracts/test/valid/NestedCalls/ThirdNestedCall.sol b/contracts/test/valid/NestedCalls/ThirdNestedCall.sol index 05ec9ec..816a1e9 100644 --- a/contracts/test/valid/NestedCalls/ThirdNestedCall.sol +++ b/contracts/test/valid/NestedCalls/ThirdNestedCall.sol @@ -13,7 +13,7 @@ contract ThirdNestedCall is BeakerContract { // End function G() public { // First we do the store for FirstNestedCall - write(1, 0x8003, 77); + write(0, 0x8003, 77); // Being our call to FourthNestedCall bytes memory input = new bytes(4); @@ -24,6 +24,6 @@ contract ThirdNestedCall is BeakerContract { input[2] = functionSelector[2]; input[3] = functionSelector[3]; - proc_call(2, "FourthNestedCall", input); + proc_call(0, "FourthNestedCall", input); } } diff --git a/contracts/test/valid/SysCallTestAccCall.sol b/contracts/test/valid/SysCallTestAccCall.sol index 8e89808..7a1cb49 100644 --- a/contracts/test/valid/SysCallTestAccCall.sol +++ b/contracts/test/valid/SysCallTestAccCall.sol @@ -11,7 +11,7 @@ contract SysCallTestAccCall is BeakerContract { // Test without any input data function A(address account, uint256 amount) public returns (bytes memory) { bytes memory input = new bytes(0); - (/* uint32 err */, bytes memory output) = proc_acc_call(2, account, amount, input); + (/* uint32 err */, bytes memory output) = proc_acc_call(0, account, amount, input); return output; } @@ -28,7 +28,7 @@ contract SysCallTestAccCall is BeakerContract { input[35] = 0x03; input[67] = 0x05; - (/* uint32 err */, bytes memory output) = proc_acc_call(2, account, amount, input); + (/* uint32 err */, bytes memory output) = proc_acc_call(0, account, amount, input); return uint256(output[31]); } diff --git a/contracts/test/valid/SysCallTestCall.sol b/contracts/test/valid/SysCallTestCall.sol index 4288922..fff7a7e 100644 --- a/contracts/test/valid/SysCallTestCall.sol +++ b/contracts/test/valid/SysCallTestCall.sol @@ -7,7 +7,7 @@ contract SysCallTestCall is BeakerContract { function A() public returns (uint32) { bytes memory input = new bytes(0); - (uint32 err, /* bytes memory output */) = proc_call(2, "TestWrite", input); + (uint32 err, /* bytes memory output */) = proc_call(0, "TestWrite", input); return err; } @@ -15,7 +15,7 @@ contract SysCallTestCall is BeakerContract { function B() public returns (uint32) { bytes memory input = new bytes(0); - (uint32 err, /* bytes memory output */) = proc_call(2, "SysCallTestWrite", input); + (uint32 err, /* bytes memory output */) = proc_call(0, "SysCallTestWrite", input); return err; } @@ -29,7 +29,7 @@ contract SysCallTestCall is BeakerContract { input[2] = functionSelector[2]; input[3] = functionSelector[3]; - proc_call(2, "SysCallTestWrite", input); + proc_call(0, "SysCallTestWrite", input); } // Call Adder:add(3,5), return result @@ -46,7 +46,7 @@ contract SysCallTestCall is BeakerContract { input[35] = 0x03; input[67] = 0x05; - (/* uint32 err */, bytes memory output) = proc_call(2, "Adder", input); + (/* uint32 err */, bytes memory output) = proc_call(0, "Adder", input); return uint256(output[31]); } @@ -66,7 +66,7 @@ contract SysCallTestCall is BeakerContract { input[35] = 0x03; input[67] = 0x05; - (/* uint32 err */, bytes memory output) = proc_call(2, "Adder", input); + (/* uint32 err */, bytes memory output) = proc_call(0, "Adder", input); uint256 addResult = uint256(output[31]); bytes4 functionSelector2 = bytes4(keccak256("S()")); @@ -77,7 +77,7 @@ contract SysCallTestCall is BeakerContract { input2[2] = functionSelector2[2]; input2[3] = functionSelector2[3]; - proc_call(2, "SysCallTestWrite", input2); + proc_call(0, "SysCallTestWrite", input2); return addResult; } diff --git a/contracts/test/valid/SysCallTestEntry.sol b/contracts/test/valid/SysCallTestEntry.sol index 752e07e..2b18d10 100644 --- a/contracts/test/valid/SysCallTestEntry.sol +++ b/contracts/test/valid/SysCallTestEntry.sol @@ -5,6 +5,6 @@ import "../../BeakerContract.sol"; contract SysCallTestEntry is BeakerContract { // Log to no topics function A() public returns (uint32) { - return set_entry(1, "TestWrite"); + return set_entry(0, "TestWrite"); } -} \ No newline at end of file +} diff --git a/contracts/test/valid/SysCallTestLog.sol b/contracts/test/valid/SysCallTestLog.sol index 92b9735..0526736 100644 --- a/contracts/test/valid/SysCallTestLog.sol +++ b/contracts/test/valid/SysCallTestLog.sol @@ -5,27 +5,27 @@ import "../../BeakerContract.sol"; contract SysCallTestLog is BeakerContract { // Log to no topics function A() public returns (uint32) { - return proc_log0(1, uint32(0x1234567890)); + return proc_log0(0, uint32(0x1234567890)); } // Log to a single topic function B() public { - proc_log1(1, 0xabcd, uint32(0x1234567890)); + proc_log1(0, 0xabcd, bytes32(0x1234567890)); } // Log to two topics function C() public { - proc_log2(1, 0xabcd, 0xbeef, uint32(0x1234567890)); + proc_log2(0, 0xabcd, 0xbeef, uint32(0x1234567890)); } // Log to three topics function D() public { - proc_log3(1, 0xabcd, 0xbeef, 0xcafe, uint32(0x1234567890)); + proc_log3(0, 0xabcd, 0xbeef, 0xcafe, uint32(0x1234567890)); } // Log to four topics function E() public { - proc_log4(1, 0xabcd, 0xbeef, 0xcafe, 0x4545, uint32(0x1234567890)); + proc_log4(0, 0xabcd, 0xbeef, 0xcafe, 0x4545, uint32(0x1234567890)); } -} \ No newline at end of file +} diff --git a/contracts/test/valid/SysCallTestProcDelete.sol b/contracts/test/valid/SysCallTestProcDelete.sol index 330c50f..717c893 100644 --- a/contracts/test/valid/SysCallTestProcDelete.sol +++ b/contracts/test/valid/SysCallTestProcDelete.sol @@ -11,7 +11,7 @@ contract SysCallTestProcDelete is BeakerContract { // Register a procedure with capabilities function B(bytes24 name, address procAddress, uint256[] caps) public returns (uint32) { - return proc_reg(1, bytes32(name), procAddress, caps); + return proc_reg(0, bytes32(name), procAddress, caps); } function testNum() public pure returns (uint256) { diff --git a/contracts/test/valid/SysCallTestProcRegister.sol b/contracts/test/valid/SysCallTestProcRegister.sol index b44209f..4f35de1 100644 --- a/contracts/test/valid/SysCallTestProcRegister.sol +++ b/contracts/test/valid/SysCallTestProcRegister.sol @@ -5,15 +5,21 @@ import "../../BeakerContract.sol"; contract SysCallTestProcRegister is BeakerContract { // Register a procedure function A(bytes24 name, address procAddress) public returns (uint32) { - return proc_reg(1, bytes32(name), procAddress, new uint256[](0)); + return proc_reg(0, bytes32(name), procAddress, new uint256[](0)); } // Register a procedure with capabilities function B(bytes24 name, address procAddress, uint256[] caps) public returns (uint32) { - return proc_reg(1, bytes32(name), procAddress, caps); + return proc_reg(0, bytes32(name), procAddress, caps); } + // Delete a procedure + function Delete(bytes24 name) public returns (uint32) { + return proc_del(0, bytes32(name)); + } + + function testNum() public pure returns (uint256) { return 392; } -} \ No newline at end of file +} diff --git a/contracts/test/valid/SysCallTestWrite.sol b/contracts/test/valid/SysCallTestWrite.sol index a156511..3f28859 100644 --- a/contracts/test/valid/SysCallTestWrite.sol +++ b/contracts/test/valid/SysCallTestWrite.sol @@ -9,10 +9,10 @@ contract SysCallTestWrite is BeakerContract { } function() public { - uint8 err = write(1, 0x8000,356); + uint8 err = write(0, 0x8000,356); assembly { mstore(0x80,err) return(0x80,0x20) } } -} \ No newline at end of file +} diff --git a/docs/media/Architecture.svg b/docs/media/Architecture.svg new file mode 100644 index 0000000..26fa0ab --- /dev/null +++ b/docs/media/Architecture.svg @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + BeakerContract + + + + + Kernel Storage + Factory + ProcedureTable + CapabilityManager + IKernel + Kernel + + + + + + + KernelInstance + + TestKernel + + + + diff --git a/docs/spec/BeakerSpec.pdf b/docs/spec/BeakerSpec.pdf index c559d76..878a34d 100644 Binary files a/docs/spec/BeakerSpec.pdf and b/docs/spec/BeakerSpec.pdf differ diff --git a/docs/spec/BeakerSpec.tex b/docs/spec/BeakerSpec.tex index 8aff506..fbcc34e 100644 --- a/docs/spec/BeakerSpec.tex +++ b/docs/spec/BeakerSpec.tex @@ -202,7 +202,7 @@ \subsection{Procedure List}\label{procedure-table} \\ \texttt{0xff ff ff ff 01} + keyIndex & procedure key/name: 24 bytes \\ - ~~~$\vdots$ & capabilities in series \\ + ~~~$\vdots$ & \\ \texttt{0xff ff ff ff 01} + n & procedure key/name for procedure $n$ \\ \hline @@ -452,7 +452,7 @@ \subsubsection{Capability Subsets} \begin{itemize} \item If the prefix size of $B$ is equal to or greater than $A$ (that is: $B_s \geq A_s$), and - \item If the first $B_s$ bits of $B_b$ is equal to the first $A_s$ bits of + \item If the first $A_s$ bits of $B_b$ is equal to the first $A_s$ bits of $A_b$. \end{itemize} @@ -1093,7 +1093,18 @@ \subsection{Whitelist}\label{opcode-whitelist} \end{table} \subsection{Execution Guard}\label{execution-guard} -An execuation guard \emph{must} start at position \texttt{0x00} in the bytecode. +An execution guard \emph{must} start at position \texttt{0x00} in the bytecode. +The purpose of the exeuction guard is to ensure that the procedure is being +called by a kernel. The risk is that somebody might perform a CALL to a bare +procedure contract. The procedure contract will then DELEGATECALL back to +whoever called it, giving them the power to execute a SELFDESTRUCT instruction. +In order to prevent this, we want to make sure that the procedure is only being +called via CALLCODE, DELEGATECALL, or STATICCALL. On simple way to check this is +to check that a kernel address is stored in storage. This means the contract is +being called either by a kernel, or something pretending to be a kernel. Because +this value is undefined in the procedures own storage, we will abort if it is +undefined. + It is defined as follows: \definecolor{mygreen}{rgb}{0,0.6,0} diff --git a/migrations/1_initial_migration.js b/migrations/1_initial_migration.js index 46a6da5..979efce 100644 --- a/migrations/1_initial_migration.js +++ b/migrations/1_initial_migration.js @@ -3,7 +3,4 @@ var Factory = artifacts.require("./Factory.sol"); var Kernel = artifacts.require("./TestKernel.sol"); module.exports = function(deployer) { - deployer.deploy(Migrations); - deployer.deploy(Factory); - deployer.deploy(Kernel); }; diff --git a/test/factory.js b/test/factory.js index b41389e..e1dc404 100644 --- a/test/factory.js +++ b/test/factory.js @@ -35,7 +35,7 @@ contract('Factory', function (accounts) { describe('.validate()', async function() { it('should accept valid contract', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); let result = await factory.validate(testutils.trimSwarm(Valid.Adder.bytecode), {from: accounts[0]}); const tx = await factory.validate.sendTransaction(testutils.trimSwarm(Valid.Adder.bytecode), {from: accounts[0]}); const receipt = web3.eth.getTransactionReceipt(tx); @@ -44,32 +44,32 @@ contract('Factory', function (accounts) { }) it('should reject a contract if it uses CREATE', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); let result = await factory.validate(testutils.trimSwarm(Invalid.Create.bytecode), {from: accounts[0]}); assert.equal(8, result.toNumber()); }) it('should reject a contract if it uses CALL', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); let result = await factory.validate(testutils.trimSwarm(Invalid.Call.bytecode), {from: accounts[0]}); assert.equal(9, result.toNumber()); }) it('should reject a contract if it uses CALLCODE', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); let result = await factory.validate(testutils.trimSwarm(Invalid.Callcode.bytecode), {from: accounts[0]}); assert.equal(10, result.toNumber()); }) it('should reject a contract if it uses DELEGATECALL', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); let result = await factory.validate(testutils.trimSwarm(Invalid.Delegatecall.bytecode), {from: accounts[0]}); assert.equal(11, result.toNumber()); }) it('should reject a contract if it uses SELFDESTRUCT', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); let result = await factory.validate(testutils.trimSwarm(Invalid.Suicide.bytecode), {from: accounts[0]}); assert.equal(13, result.toNumber()); }) @@ -77,21 +77,21 @@ contract('Factory', function (accounts) { describe('.validateContract()', async function() { it('should accept valid contract', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Valid.Adder); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(0, result.toNumber()); }) it('should accept valid contract with system calls (write)', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Valid.SysCallTestWrite); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(result.toNumber(), 0); }) it('should accept valid contract with system calls (call)', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Valid.SysCallTestCall); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); const tx = await factory.validateContract.sendTransaction(deployedContract.address, {from: accounts[0]}); @@ -101,35 +101,35 @@ contract('Factory', function (accounts) { }) it('should accept valid contract with system calls (log)', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Valid.SysCallTestLog); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(result.toNumber(), 0); }) it('should reject a contract if it uses CREATE', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Invalid.Create); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(8, result.toNumber()); }) it('should reject a contract if it uses CALL', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Invalid.Call); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(9, result.toNumber()); }) it('should reject a contract if it uses CALLCODE', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Invalid.Callcode); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(10, result.toNumber()); }) it('should reject a contract if it uses DELEGATECALL', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Invalid.Delegatecall); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(11, result.toNumber()); @@ -137,14 +137,14 @@ contract('Factory', function (accounts) { it('should reject a contract if it uses SELFDESTRUCT', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(Invalid.Suicide); let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(13, result.toNumber()); }) it('should reject a contract if it uses SSTORE', async function () { - let factory = await Factory.deployed(); + let factory = await Factory.new(); const deployedContract = await testutils.deployedTrimmed(TestWrite) let result = await factory.validateContract(deployedContract.address, {from: accounts[0]}); assert.equal(2, result.toNumber()); diff --git a/test/testutils.js b/test/testutils.js index 1b277e1..340baea 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -1,19 +1,37 @@ const beakerlib = require("../beakerlib"); const BasicEntryProcedure = artifacts.require('BasicEntryProcedure.sol'); +const Kernel = artifacts.require('./TestKernel.sol') -async function installEntryProc(kernel) { - const entryProcName = "EntryProcedure"; - kernel.setEntryProcedure(entryProcName); - const capArrayEntryProc = beakerlib.Cap.toInput([ - new beakerlib.WriteCap(0x8001,2), - new beakerlib.LogCap([]), - new beakerlib.CallCap(0,"") - ]); +// Deploy a kernel and install the example entry procedure +async function deployTestKernel() { + // First deploy the entry procedure that will be used to bootstrap the + // system. const deployedEntryProc = await deployedTrimmed(BasicEntryProcedure); - // Install the entry procedure - await kernel.registerAnyProcedure(entryProcName, deployedEntryProc.address, capArrayEntryProc); + + // Deploy the kernel, specifying the previsouly deployed procedure as the + // first entry procedure. This will be named "init ". + let kernel; + try { + kernel = await Kernel.new(deployedEntryProc.address); + } catch (e) { + throw new Error(e); + } + + const procedures1Raw = await kernel.listProcedures.call(); + const procedures1 = procedures1Raw.map(web3.toAscii) + .map(s => s.replace(/\0.*$/, '')); + assert(procedures1.length == 1, + "The kernel should initially have a single procedure procedures"); + const initEntryProc = await kernel.getEntryProcedure.call(); + // Check that the entry procedure was correctly installed. + assert.strictEqual(web3.toAscii(initEntryProc).replace(/\0.*$/, ''), "init", + "The kernel should have an entry procedure registered as \"init\""); + // Check that the capabilities are correct + // TODO: we want to ensure that the maximal caps are provided + // await checkCaps(kernel, "init", []); + return kernel; } -exports.installEntryProc = installEntryProc; +exports.deployTestKernel = deployTestKernel; function trimSwarm(bytecode) { const size = bytecode.length; diff --git a/test/withentryproc/procedures.js b/test/withentryproc/procedures.js index 31a950b..8098f6f 100644 --- a/test/withentryproc/procedures.js +++ b/test/withentryproc/procedures.js @@ -36,10 +36,10 @@ contract('Kernel with entry procedure', function (accounts) { describe('A()', function () { it('A() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + // Install the entry procedure - await testutils.installEntryProc(kernel); + const kernel = await testutils.deployTestKernel(); // We want to send an empty transaction. With an empty // transaction, the following things should occur: // 1. The payload should get forwared to the entry @@ -66,4 +66,4 @@ contract('Kernel with entry procedure', function (accounts) { }) }) }) -}) \ No newline at end of file +}) diff --git a/test/withentryproc/syscalls/acc_call.js b/test/withentryproc/syscalls/acc_call.js index 5a3a4ba..8aefdae 100644 --- a/test/withentryproc/syscalls/acc_call.js +++ b/test/withentryproc/syscalls/acc_call.js @@ -52,7 +52,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract and retrieve correct testNum', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -65,7 +66,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -116,7 +116,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract, retrieve correct testNum and transfer 1 wei', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const amount = 1; const deployedContract = await testutils.deployedTrimmed(contract); @@ -132,7 +133,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -191,7 +191,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract and retrieve correct testNum', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -207,7 +208,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -258,7 +258,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const amount = 1; const deployedContract = await testutils.deployedTrimmed(contract); @@ -274,7 +275,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -329,7 +329,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract and retrieve correct testNum from specified contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -359,7 +360,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -405,7 +405,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract, retrieve correct testNum and transfer 1 wei from specified contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -435,7 +436,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -478,7 +478,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract and retrieve correct testNum from another contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -519,7 +520,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -567,7 +567,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei from another contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -608,7 +609,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -663,7 +663,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract and retrieve correct testNum from specified contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -693,7 +694,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -739,7 +739,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei from specified contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -769,7 +770,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -812,7 +812,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract and retrieve correct testNum from another contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -853,7 +854,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -901,7 +901,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei from another contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -942,7 +943,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1002,7 +1002,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract and retrieve correct testNum', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -1018,7 +1019,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1068,7 +1068,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 1; const deployedContract = await testutils.deployedTrimmed(contract); @@ -1084,7 +1085,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1142,7 +1142,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract and retrieve correct testNum', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -1158,7 +1159,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1208,7 +1208,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 1; const deployedContract = await testutils.deployedTrimmed(contract); @@ -1224,7 +1225,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1289,7 +1289,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract and retrieve correct testNum', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -1302,7 +1303,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1351,7 +1351,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract, retrieve correct testNum and transfer 1 wei', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -1367,7 +1368,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1425,7 +1425,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract and retrieve correct testNum', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -1441,7 +1442,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1490,7 +1490,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const amount = 1; const deployedContract = await testutils.deployedTrimmed(contract); @@ -1506,7 +1507,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1559,7 +1559,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract and retrieve correct testNum from specified contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -1589,7 +1590,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1633,7 +1633,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract, retrieve correct testNum and transfer 1 wei from specified contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -1663,7 +1664,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1705,7 +1705,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract and retrieve correct testNum from another contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -1746,7 +1747,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1793,7 +1793,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei from another contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -1834,7 +1835,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1888,7 +1888,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should be able to call a contract and retrieve correct testNum from specified contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -1918,7 +1919,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -1962,7 +1962,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei from specified contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -1992,7 +1993,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -2034,7 +2034,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract and retrieve correct testNum from another contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -2075,7 +2076,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -2122,7 +2122,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei from another contract', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Deploy a regular Ethereum contract that is not related to // Beaker. @@ -2163,7 +2164,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -2222,7 +2222,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract and retrieve correct testNum', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -2238,7 +2239,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -2287,7 +2287,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const amount = 1; const deployedContract = await testutils.deployedTrimmed(contract); @@ -2303,7 +2304,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -2360,7 +2360,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract and retrieve correct testNum', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const amount = 0; const deployedContract = await testutils.deployedTrimmed(contract); @@ -2376,7 +2377,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. @@ -2425,7 +2425,8 @@ contract('Kernel with entry procedure', function (accounts) { it('Should fail to call a contract, retrieve correct testNum and transfer 1 wei', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const amount = 1; const deployedContract = await testutils.deployedTrimmed(contract); @@ -2441,7 +2442,6 @@ contract('Kernel with entry procedure', function (accounts) { const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - await testutils.installEntryProc(kernel); // Test that the AccCall test procedure is correctly installed // by querying a value from it. diff --git a/test/withentryproc/syscalls/call.js b/test/withentryproc/syscalls/call.js index fac811d..b020b10 100644 --- a/test/withentryproc/syscalls/call.js +++ b/test/withentryproc/syscalls/call.js @@ -43,7 +43,8 @@ contract('Kernel with entry procedure', function (accounts) { it('A() should succeed when given general cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -61,7 +62,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -81,7 +81,8 @@ contract('Kernel with entry procedure', function (accounts) { it('A() should fail when not given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -98,7 +99,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupy the first 24 bytes, so must be // padded @@ -123,7 +123,8 @@ contract('Kernel with entry procedure', function (accounts) { it('A() should fail when given the wrong cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -141,7 +142,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -160,7 +160,8 @@ contract('Kernel with entry procedure', function (accounts) { it('A() should succeed with a more restricted cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -178,7 +179,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -197,7 +197,8 @@ contract('Kernel with entry procedure', function (accounts) { it('A() should fail when the given cap is insufficient', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -215,7 +216,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -240,7 +240,8 @@ contract('Kernel with entry procedure', function (accounts) { it('B() should succeed when a general given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -259,7 +260,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -277,7 +277,8 @@ contract('Kernel with entry procedure', function (accounts) { it('B() should fail when not given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -295,7 +296,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -314,7 +314,8 @@ contract('Kernel with entry procedure', function (accounts) { it('B() should fail when given the wrong cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -332,7 +333,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -351,7 +351,8 @@ contract('Kernel with entry procedure', function (accounts) { it('B() should succeed with a more restricted cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -369,7 +370,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -388,7 +388,8 @@ contract('Kernel with entry procedure', function (accounts) { it('B() should fail when the given cap is insufficient', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -406,7 +407,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -431,12 +431,14 @@ contract('Kernel with entry procedure', function (accounts) { it('C() should succeed when given a general cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(0,""); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -449,7 +451,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -468,11 +469,13 @@ contract('Kernel with entry procedure', function (accounts) { it('C() should fail when not given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -485,7 +488,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -504,12 +506,14 @@ contract('Kernel with entry procedure', function (accounts) { it('C() should fail when given the wrong cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); + const cap2 = new beakerlib.WriteCap(0x8000,2); const cap3 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap4 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -522,7 +526,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -541,12 +544,14 @@ contract('Kernel with entry procedure', function (accounts) { it('C() should succeed with a more restricted cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10,testProcName); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10,testProcName); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -559,7 +564,6 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -583,7 +587,8 @@ contract('Kernel with entry procedure', function (accounts) { it('E() should succeed when given general cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -598,7 +603,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx2 = await kernel.registerAnyProcedure(testProcName, deployedTestContract.address, beakerlib.Cap.toInput([cap2, cap1])); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -615,7 +619,8 @@ contract('Kernel with entry procedure', function (accounts) { it('E() should succeed when given specific cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -631,7 +636,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx2 = await kernel.registerAnyProcedure(testProcName, deployedTestContract.address, beakerlib.Cap.toInput([cap2, cap1])); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -648,7 +652,8 @@ contract('Kernel with entry procedure', function (accounts) { it('E() should fail when not given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -662,7 +667,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx2 = await kernel.registerAnyProcedure(testProcName, deployedTestContract.address, beakerlib.Cap.toInput([cap1])); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -678,7 +682,8 @@ contract('Kernel with entry procedure', function (accounts) { it('E() should fail when given the wrong cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -693,7 +698,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx2 = await kernel.registerAnyProcedure(testProcName, deployedTestContract.address, beakerlib.Cap.toInput([cap1])); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -709,7 +713,8 @@ contract('Kernel with entry procedure', function (accounts) { it('E() should succeed with a more restricted cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -724,7 +729,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx2 = await kernel.registerAnyProcedure(testProcName, deployedTestContract.address, beakerlib.Cap.toInput([cap2, cap1])); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -740,7 +744,8 @@ contract('Kernel with entry procedure', function (accounts) { it('E() should fail when the given cap is insufficient', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -755,7 +760,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx2 = await kernel.registerAnyProcedure(testProcName, deployedTestContract.address, beakerlib.Cap.toInput([cap1])); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -769,18 +773,18 @@ contract('Kernel with entry procedure', function (accounts) { }) }) describe('F() - successive calls single depth', function () { - const testProcName = "Adder"; - const testBytecode = Valid.Adder.bytecode; const functionSpec = "F()"; it('F() should succeed when given a general cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(0,""); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedAdderContract = await testutils.deployedTrimmed(Valid.Adder); @@ -794,8 +798,6 @@ contract('Kernel with entry procedure', function (accounts) { // await kernel.createProcedure("SysCallTestCall", Valid.SysCallTestCall.bytecode, beakerlib.Cap.toInput([cap2, cap1])); { - await testutils.installEntryProc(kernel); - // Procedure keys must occupay the first 24 bytes, so must be // padded const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); @@ -803,7 +805,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx3 = await kernel.sendTransaction({data: inputData}); const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); const valueX = web3.toBigNumber(valueXRaw); - assert.equal(valueX.toNumber(),8, `new value should be 8`); } const newValue2 = await kernel.testGetter.call(); @@ -817,7 +818,8 @@ contract('Kernel with entry procedure', function (accounts) { it('G() should succeed when given a general cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); diff --git a/test/withentryproc/syscalls/delete.js b/test/withentryproc/syscalls/delete.js index b3dab8d..3c4e775 100644 --- a/test/withentryproc/syscalls/delete.js +++ b/test/withentryproc/syscalls/delete.js @@ -28,7 +28,7 @@ const Invalid = { contract('Kernel with entry procedure', function (accounts) { describe('Delete capability', function () { - const entryProcName = "EntryProcedure"; + const entryProcName = "init"; describe('When given cap to delete a specific procedure Id', function () { // * Introduces Procedure A and Procedure B into the procedure table. @@ -47,15 +47,13 @@ contract('Kernel with entry procedure', function (accounts) { it('Delete procedure with matching id', async function() { // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // Install the default entry procedure - await testutils.installEntryProc(kernel); - // Install Procedure A as the entry procedure const procAName = "ProcedureA"; const procBName = "ProcedureB"; @@ -64,12 +62,16 @@ contract('Kernel with entry procedure', function (accounts) { // Give ProcedureA a delete capability to remove only ProcedureB const capArrayEntryProc = beakerlib.Cap.toInput([ - new beakerlib.DeleteCap([procBName]) + new beakerlib.DeleteCap(192,procBName) ]); // This uses a direct call to the kernel await kernel.registerAnyProcedure(procAName, deployedEntryProc.address, capArrayEntryProc); await kernel.registerAnyProcedure(procBName, deployedContractB.address, []); + { + const proceduresRaw = await kernel.listProcedures.call(); + const procedures = proceduresRaw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); + } // Call the delete function to delete Procedure B { @@ -88,7 +90,6 @@ contract('Kernel with entry procedure', function (accounts) { // } const valueXRaw = await web3.eth.call({to: kernel.address, data: manualInputData}); const tx3 = await kernel.sendTransaction({data: manualInputData}); - const valueX = web3.toBigNumber(valueXRaw); // we execute a test function to ensure the procedure is // functioning properly @@ -110,14 +111,14 @@ contract('Kernel with entry procedure', function (accounts) { }) it('Fails to delete procedure if non-matching id', async function() { // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // Install the default entry procedure - await testutils.installEntryProc(kernel); + // Install Procedure A as the entry procedure const procAName = "ProcedureA"; @@ -130,7 +131,7 @@ contract('Kernel with entry procedure', function (accounts) { // Give ProcedureA a delete capability to remove a procedure Id different from ProcedureB const capArrayEntryProc = beakerlib.Cap.toInput([ - new beakerlib.DeleteCap([procCName]) + new beakerlib.DeleteCap(192, procCName) ]); // This uses a direct call to the kernel @@ -192,19 +193,19 @@ contract('Kernel with entry procedure', function (accounts) { it('Delete a procedure', async function () { // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // Install the default entry procedure - await testutils.installEntryProc(kernel); + // Install Procedure A as the entry procedure const procAName = "ProcedureA"; const capArrayEntryProc = beakerlib.Cap.toInput([ - new beakerlib.DeleteCap() + new beakerlib.DeleteCap(0, "") ]); const deployedEntryProc = await testutils.deployedTrimmed(contractA); // This uses a direct call to the kernel @@ -285,19 +286,22 @@ contract('Kernel with entry procedure', function (accounts) { }) it('Delete itself', async function () { // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); + { + const proceduresRaw = await kernel.listProcedures.call(); + const procedures = proceduresRaw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); + } - // Install the default entry procedure - await testutils.installEntryProc(kernel); // Install Procedure A as the entry procedure const procAName = "ProcedureA"; const capArrayEntryProc = beakerlib.Cap.toInput([ - new beakerlib.DeleteCap() + new beakerlib.DeleteCap(0, "") ]); const deployedEntryProc = await testutils.deployedTrimmed(contractA); // This uses a direct call to the kernel @@ -356,12 +360,12 @@ contract('Kernel with entry procedure', function (accounts) { // } - const tx3 = await kernel.sendTransaction({data: manualInputData}); const valueXRaw = await web3.eth.call({to: kernel.address, data: manualInputData}); - // const valueX = web3.toBigNumber(valueXRaw); + const tx3 = await kernel.sendTransaction({data: manualInputData}); + const valueX = web3.toBigNumber(valueXRaw); // we execute a test function to ensure the procedure is // functioning properly - assert.equal(valueXRaw, "0x", "Should return nothing"); + assert.equal(valueX, 0, "Should return zero"); } @@ -378,19 +382,19 @@ contract('Kernel with entry procedure', function (accounts) { }) it('Fail to delete the entry procedure', async function () { // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // Install the default entry procedure - await testutils.installEntryProc(kernel); + // Install Procedure A as the entry procedure const procAName = "ProcedureA"; const capArrayEntryProc = beakerlib.Cap.toInput([ - new beakerlib.DeleteCap() + new beakerlib.DeleteCap(0, "") ]); const deployedEntryProc = await testutils.deployedTrimmed(contractA); // This uses a direct call to the kernel @@ -471,19 +475,19 @@ contract('Kernel with entry procedure', function (accounts) { it('Fail to delete non-existent procedure', async function () { const nonExistentName = "NonExistant"; // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // Install the default entry procedure - await testutils.installEntryProc(kernel); + // Install Procedure A as the entry procedure const procAName = "ProcedureA"; const capArrayEntryProc = beakerlib.Cap.toInput([ - new beakerlib.DeleteCap() + new beakerlib.DeleteCap(0, "") ]); const deployedEntryProc = await testutils.deployedTrimmed(contractA); // This uses a direct call to the kernel @@ -584,14 +588,14 @@ contract('Kernel with entry procedure', function (accounts) { it('Fail to delete a procedure', async function () { // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // Install the default entry procedure - await testutils.installEntryProc(kernel); + // Install Procedure A as the entry procedure const procAName = "ProcedureA"; @@ -677,14 +681,14 @@ contract('Kernel with entry procedure', function (accounts) { }) it('Fail to delete itself', async function () { // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // Install the default entry procedure - await testutils.installEntryProc(kernel); + // Install Procedure A as the entry procedure const procAName = "ProcedureA"; @@ -770,19 +774,17 @@ contract('Kernel with entry procedure', function (accounts) { }) it('Fail to delete the entry procedure', async function () { // Deploy the kernel - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); // Save the initial state of the procedure table const procedures1Raw = await kernel.listProcedures.call(); const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // Install the default entry procedure - await testutils.installEntryProc(kernel); - // Install Procedure A as the entry procedure const procAName = "ProcedureA"; const capArrayEntryProc = beakerlib.Cap.toInput([ - new beakerlib.DeleteCap() + new beakerlib.DeleteCap(0, "") ]); const deployedEntryProc = await testutils.deployedTrimmed(contractA); // This uses a direct call to the kernel diff --git a/test/withentryproc/syscalls/entry.js b/test/withentryproc/syscalls/entry.js index 6225b97..993cee5 100644 --- a/test/withentryproc/syscalls/entry.js +++ b/test/withentryproc/syscalls/entry.js @@ -22,23 +22,26 @@ contract('Kernel with entry procedure', function (accounts) { const testContract = TestWrite; it('A() should succeed when given cap and correct procedure Id', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.SetEntryCap([]); + const cap2 = new beakerlib.SetEntryCap(); const capArray = beakerlib.Cap.toInput([cap1, cap2]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); + // console.log(deployedTestContract) // This is the procedure that will be entry procedure first const tx1 = await kernel.registerProcedure(procName, deployedContract.address, capArray); // This is the procedure that will be set as entry const tx2 = await kernel.registerAnyProcedure(testProcName, deployedTestContract.address, []); - + const originalValue = await kernel.testGetter.call(); + assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - + // Set the "SysCallTestEntry" as entry await kernel.setEntryProcedure(procName); @@ -46,11 +49,9 @@ contract('Kernel with entry procedure', function (accounts) { { // Procedure keys must occupay the first 24 bytes, so must be padded const functionSelectorHash = web3.sha3("A()").slice(2,10); - const inputData = functionSelectorHash; - + const inputData = "0x" + functionSelectorHash; const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); const tx3 = await kernel.sendTransaction({data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); assert.equal(valueX.toNumber(), 0, "should succeed with zero errcode the first time"); @@ -58,25 +59,26 @@ contract('Kernel with entry procedure', function (accounts) { // Check that entry procedure has changed let entry_raw = await kernel.getEntryProcedure.call(); - let new_entry_proc = web3.toAscii(entry_raw).replace(/\0.*$/, '') + let new_entry_proc = web3.toAscii(web3.toHex(entry_raw)).replace(/\0.*$/, '') assert.equal(new_entry_proc, "TestWrite") }) it('A() should fail when given cap but invalid procedure Id', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.SetEntryCap([]); + const cap2 = new beakerlib.SetEntryCap(); const capArray = beakerlib.Cap.toInput([cap1, cap2]); const deployedContract = await testutils.deployedTrimmed(contract); // This is the procedure that will be entry procedure first const tx1 = await kernel.registerProcedure(procName, deployedContract.address, capArray); - + const originalValue = await kernel.testGetter.call(); assert.equal(originalValue.toNumber(), 3, "test incorrectly set up: initial value should be 3"); - + // Set the "SysCallTestEntry" as entry await kernel.setEntryProcedure(procName); @@ -84,7 +86,7 @@ contract('Kernel with entry procedure', function (accounts) { { // Procedure keys must occupay the first 24 bytes, so must be padded const functionSelectorHash = web3.sha3("A()").slice(2,10); - const inputData = functionSelectorHash; + const inputData = "0x" + functionSelectorHash; const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); const tx3 = await kernel.sendTransaction({data: inputData}); @@ -95,9 +97,9 @@ contract('Kernel with entry procedure', function (accounts) { // Check that entry procedure has changed let entry_raw = await kernel.getEntryProcedure.call(); - let new_entry_proc = web3.toAscii(entry_raw).replace(/\0.*$/, '') + let new_entry_proc = web3.toAscii(web3.toHex(entry_raw)).replace(/\0.*$/, '') assert.equal(new_entry_proc, procName) }) }) }) -}) \ No newline at end of file +}) diff --git a/test/withentryproc/syscalls/log.js b/test/withentryproc/syscalls/log.js index 95e8e50..a3bd0ab 100644 --- a/test/withentryproc/syscalls/log.js +++ b/test/withentryproc/syscalls/log.js @@ -29,7 +29,8 @@ contract('Kernel with entry procedure', function (accounts) { describe('A() No topics', function () { const functionSpec = "A()"; it('A() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([]); @@ -39,7 +40,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx1 = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -52,7 +52,8 @@ contract('Kernel with entry procedure', function (accounts) { } }) it('A() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const capArray = beakerlib.Cap.toInput([cap1]); @@ -61,7 +62,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx0 = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -77,17 +77,17 @@ contract('Kernel with entry procedure', function (accounts) { }) it('A() should fail when cap requires more topics', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); - const cap2 = new beakerlib.LogCap([0xaabb]); + const cap2 = new beakerlib.LogCap(["0xaabb"]); const capArray = beakerlib.Cap.toInput([cap1, cap2]); const deployedContract = await testutils.deployedTrimmed(contract); const tx0 = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -107,9 +107,10 @@ contract('Kernel with entry procedure', function (accounts) { const functionSpec = "B()"; // This topic is also defined in the Solidity file and // must be the same - const topic = 0xabcd; + const topic = "0xabcd"; it('B() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([topic]); @@ -119,32 +120,31 @@ contract('Kernel with entry procedure', function (accounts) { const tx1 = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); const inputData = web3.fromAscii("SysCallTestLog".padEnd(24,"\0")) + functionSelectorHash; const tx3 = await kernel.sendTransaction({data: inputData}); - + assert(tx3.receipt.logs.length >= 1, "there should be at least 1 log value"); assert.equal(tx3.receipt.logs[1].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx3.receipt.logs[1].topics.length,1,"There should be 1 topic"); - assert.equal(tx3.receipt.logs[1].topics[0],topic,"The topic should be correct"); + assert.equal(tx3.receipt.logs[1].topics[0],"0x"+topic.slice(2).padStart(64,0),"The topic should be correct"); } }) it('B() should fail when cap has incorrect topic', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); - const cap2 = new beakerlib.LogCap([topic+1]); + const cap2 = new beakerlib.LogCap([topic+"1"]); const capArray = beakerlib.Cap.toInput([cap1, cap2]); const deployedContract = await testutils.deployedTrimmed(contract); const tx1 = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -160,14 +160,14 @@ contract('Kernel with entry procedure', function (accounts) { } }) it('B() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, []); const tx = await kernel.registerProcedure(procName, deployedContract.address, []); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -183,9 +183,10 @@ contract('Kernel with entry procedure', function (accounts) { } }) it('B() should fail when trying to log to something outside its capability', async function () { - const kernel = await Kernel.new(); - const cap = new beakerlib.LogCap([0x8001, 0x0]); + const kernel = await testutils.deployTestKernel(); + + const cap = new beakerlib.LogCap(["0x8001", "0x0"]); const capArray = beakerlib.Cap.toInput([cap]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -193,7 +194,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -213,10 +213,11 @@ contract('Kernel with entry procedure', function (accounts) { const functionSpec = "C()"; // This topic is also defined in the Solidity file and // must be the same - const topic0 = 0xabcd; - const topic1 = 0xbeef; + const topic0 = "0xabcd"; + const topic1 = "0xbeef"; it('C() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([topic0, topic1]); @@ -226,7 +227,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx1 = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -236,19 +236,19 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(tx3.receipt.logs[1].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx3.receipt.logs[1].topics.length,2,"There should be 2 topics"); - assert.equal(tx3.receipt.logs[1].topics[0],topic0,"The topic0 should be correct"); - assert.equal(tx3.receipt.logs[1].topics[1],topic1,"The topic1 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[0],"0x"+topic0.slice(2).padStart(64,0),"The topic0 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[1],"0x"+topic1.slice(2).padStart(64,0),"The topic1 should be correct"); } }) it('C() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, []); const tx = await kernel.registerProcedure(procName, deployedContract.address, []); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -264,14 +264,14 @@ contract('Kernel with entry procedure', function (accounts) { } }) it('C() should fail when trying to log to something outside its capability', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, [3, 0x7, 0x8001, 0x0]); const tx = await kernel.registerProcedure(procName, deployedContract.address, [3, 0x7, 0x8001, 0x0]); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -291,11 +291,12 @@ contract('Kernel with entry procedure', function (accounts) { const functionSpec = "D()"; // This topic is also defined in the Solidity file and // must be the same - const topic0 = 0xabcd; - const topic1 = 0xbeef; - const topic2 = 0xcafe; + const topic0 = "0xabcd"; + const topic1 = "0xbeef"; + const topic2 = "0xcafe"; it('D() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([topic0, topic1, topic2]); @@ -306,7 +307,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -318,20 +318,20 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(tx3.receipt.logs[1].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx3.receipt.logs[1].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx3.receipt.logs[1].topics.length,3,"There should be 3 topics"); - assert.equal(tx3.receipt.logs[1].topics[0],topic0,"The topic0 should be correct"); - assert.equal(tx3.receipt.logs[1].topics[1],topic1,"The topic1 should be correct"); - assert.equal(tx3.receipt.logs[1].topics[2],topic2,"The topic1 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[0],"0x"+topic0.slice(2).padStart(64,0),"The topic0 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[1],"0x"+topic1.slice(2).padStart(64,0),"The topic1 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[2],"0x"+topic2.slice(2).padStart(64,0),"The topic1 should be correct"); } }) it('D() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, []); const tx = await kernel.registerProcedure(procName, deployedContract.address, []); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -347,9 +347,10 @@ contract('Kernel with entry procedure', function (accounts) { } }) it('D() should fail when trying to log to something outside its capability', async function () { - const kernel = await Kernel.new(); - const cap = new beakerlib.LogCap([0x8001, 0x0]); + const kernel = await testutils.deployTestKernel(); + + const cap = new beakerlib.LogCap(["0x8001", "0x0"]); const capArray = beakerlib.Cap.toInput([cap]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -357,7 +358,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -376,12 +376,13 @@ contract('Kernel with entry procedure', function (accounts) { const functionSpec = "E()"; // This topic is also defined in the Solidity file and // must be the same - const topic0 = 0xabcd; - const topic1 = 0xbeef; - const topic2 = 0xcafe; - const topic3 = 0x4545; + const topic0 = "0xabcd"; + const topic1 = "0xbeef"; + const topic2 = "0xcafe"; + const topic3 = "0x4545"; it('E() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([topic0, topic1, topic2, topic3]); @@ -391,7 +392,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx1 = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -401,21 +401,21 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(tx3.receipt.logs[1].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx3.receipt.logs[1].topics.length,4,"There should be 4 topics"); - assert.equal(tx3.receipt.logs[1].topics[0],topic0,"The topic0 should be correct"); - assert.equal(tx3.receipt.logs[1].topics[1],topic1,"The topic1 should be correct"); - assert.equal(tx3.receipt.logs[1].topics[2],topic2,"The topic1 should be correct"); - assert.equal(tx3.receipt.logs[1].topics[3],topic3,"The topic1 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[0],"0x"+topic0.slice(2).padStart(64,0),"The topic0 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[1],"0x"+topic1.slice(2).padStart(64,0),"The topic1 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[2],"0x"+topic2.slice(2).padStart(64,0),"The topic1 should be correct"); + assert.equal(tx3.receipt.logs[1].topics[3],"0x"+topic3.slice(2).padStart(64,0),"The topic1 should be correct"); } }) it('E() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, []); const tx = await kernel.registerProcedure(procName, deployedContract.address, []); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -431,9 +431,10 @@ contract('Kernel with entry procedure', function (accounts) { } }) it('E() should fail when trying to log to something outside its capability', async function () { - const kernel = await Kernel.new(); - const cap = new beakerlib.LogCap([0x8001, 0x0]); + const kernel = await testutils.deployTestKernel(); + + const cap = new beakerlib.LogCap(["0x8001", "0x0"]); const capArray = beakerlib.Cap.toInput([cap]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -441,7 +442,6 @@ contract('Kernel with entry procedure', function (accounts) { const tx = await kernel.registerProcedure(procName, deployedContract.address, capArray); { - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded diff --git a/test/withentryproc/syscalls/register.js b/test/withentryproc/syscalls/register.js index 231045d..3e5e0f9 100644 --- a/test/withentryproc/syscalls/register.js +++ b/test/withentryproc/syscalls/register.js @@ -1,11 +1,11 @@ const debug = require('debug') const assert = require('assert') -const Kernel = artifacts.require('./TestKernel.sol') const abi = require('ethereumjs-abi') const beakerlib = require("../../../beakerlib"); const testutils = require("../../testutils.js"); +const BasicEntryProcedure = artifacts.require('BasicEntryProcedure.sol'); // Valid Contracts const Valid = { @@ -24,794 +24,1201 @@ const Invalid = { Simple: artifacts.require('test/invalid/Simple.sol') } -contract('Kernel with entry procedure', function (accounts) { - describe('Register capability', function () { - const procName = "SysCallTestProcRegister"; - const contract = Valid.SysCallTestProcRegister; - - describe('A(bytes24,address) - register a procedure', function () { - const testProcName = "Adder"; - const testContract = Valid.Adder; - const functionSpec = "A(bytes24,address)"; - it('A(bytes24,address) should succeed when given cap', async function () { - const kernel = await Kernel.new(); - // console.log(`kernel: ${kernel.address}`); - - const procedures1Raw = await kernel.listProcedures.call(); - const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures1:", procedures1); - - await testutils.installEntryProc(kernel); - - const procedures2Raw = await kernel.listProcedures.call(); - const procedures2 = procedures2Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures2:", procedures2); - - const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.RegisterCap(); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); - - const deployedContract = await testutils.deployedTrimmed(contract); - // This is the procedure that will do the registering - // this currently requires Any because it uses logging for testing - const tx1 = await kernel.registerAnyProcedure(procName, deployedContract.address, capArray); - // for (const log of tx1.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // This is the procedure that will be registered - const deployedTestContract = await testutils.deployedTrimmed(testContract); - // console.log(deployedTestContract.address) - const procedures3Raw = await kernel.listProcedures.call(); - const procedures3 = procedures3Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures3:", procedures3); - { - const functionSelectorHash = web3.sha3("testNum()").slice(2,10); - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash; - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // we execute a test function to ensure the procedure is - // functioning properly - assert.equal(valueX.toNumber(), 392, "should receive the correct test number"); - } - - { - // console.log(deployedTestContract.address.slice(2)) - const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - // here we use padStart because 'address' is like a number, not bytes - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash + web3.fromAscii(testProcName.padEnd(32*2,"\0")).slice(2) + deployedTestContract.address.slice(2).padStart(32*2,0); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // for (const log of tx3.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // console.log(valueX.toNumber()) - assert.equal(valueX.toNumber(), 0, "should succeed with zero errcode the first time"); - } - - const procedures4Raw = await kernel.listProcedures.call(); - const procedures4 = procedures4Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures4:", procedures4); - assert(procedures4.includes(testProcName), "The correct name should be in the procedure table"); - assert.strictEqual(procedures4.length, (procedures3.length+1), "The number of procedures should have increased by 1"); - }) - it('A(bytes24,address) should fail when not given cap', async function () { - const kernel = await Kernel.new(); - // console.log(`kernel: ${kernel.address}`); - - const procedures1Raw = await kernel.listProcedures.call(); - const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures1:", procedures1); - - await testutils.installEntryProc(kernel); - - const procedures2Raw = await kernel.listProcedures.call(); - const procedures2 = procedures2Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures2:", procedures2); - - const deployedContract = await testutils.deployedTrimmed(contract); - // This is the procedure that will do the registering - // this currently requires Any because it uses logging for testing - const tx1 = await kernel.registerAnyProcedure(procName, deployedContract.address, []); - // for (const log of tx1.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // This is the procedure that will be registered - const deployedTestContract = await testutils.deployedTrimmed(testContract); - // console.log(deployedTestContract.address) - // const tx2 = await kernel.registerProcedure(testProcName, deployedTestContract.address, []); - // const tx2 = await kernel.registerProcedure("testtesttesttesttesttesa", "0xf958a87ec617211109ec02846ec0df996532b104", []); - const procedures3Raw = await kernel.listProcedures.call(); - const procedures3 = procedures3Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures3:", procedures3); - { - const functionSelectorHash = web3.sha3("testNum()").slice(2,10); - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash; - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // we execute a test function to ensure the procedure is - // functioning properly - assert.equal(valueX.toNumber(), 392, "should receive the correct test number"); - } - - { - // console.log(deployedTestContract.address.slice(2)) - const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - // here we use padStart because 'address' is like a number, not bytes - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash + web3.fromAscii(testProcName.padEnd(32*2,"\0")).slice(2) + deployedTestContract.address.slice(2).padStart(32*2,0); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const tx3 = await kernel.sendTransaction({data: inputData}); - - // for (const log of tx3.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // console.log(valueX.toNumber()) - assert.equal(valueXRaw.slice(0,4), "0x55", "should succeed with zero errcode the first time"); - } - - const procedures4Raw = await kernel.listProcedures.call(); - const procedures4 = procedures4Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures4:", procedures4); - assert(!procedures4.includes(testProcName), "The correct name should not be in the procedure table"); - assert.strictEqual(procedures4.length, procedures3.length, "The number of procedures should not have increased"); - }) - it('A(bytes24,address) should fail when given the wrong cap', async function () { - const kernel = await Kernel.new(); - // console.log(`kernel: ${kernel.address}`); - - const procedures1Raw = await kernel.listProcedures.call(); - const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures1:", procedures1); - - await testutils.installEntryProc(kernel); - - const procedures2Raw = await kernel.listProcedures.call(); - const procedures2 = procedures2Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures2:", procedures2); - - const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); - - const deployedContract = await testutils.deployedTrimmed(contract); - // This is the procedure that will do the registering - // this currently requires Any because it uses logging for testing - const tx1 = await kernel.registerAnyProcedure(procName, deployedContract.address, capArray); - // for (const log of tx1.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // This is the procedure that will be registered - const deployedTestContract = await testutils.deployedTrimmed(testContract); - // console.log(deployedTestContract.address) - // const tx2 = await kernel.registerProcedure(testProcName, deployedTestContract.address, []); - // const tx2 = await kernel.registerProcedure("testtesttesttesttesttesa", "0xf958a87ec617211109ec02846ec0df996532b104", []); - const procedures3Raw = await kernel.listProcedures.call(); - const procedures3 = procedures3Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures3:", procedures3); - { - const functionSelectorHash = web3.sha3("testNum()").slice(2,10); - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash; - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // we execute a test function to ensure the procedure is - // functioning properly - assert.equal(valueX.toNumber(), 392, "should receive the correct test number"); - } - - { - // console.log(deployedTestContract.address.slice(2)) - const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - // here we use padStart because 'address' is like a number, not bytes - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash + web3.fromAscii(testProcName.padEnd(32*2,"\0")).slice(2) + deployedTestContract.address.slice(2).padStart(32*2,0); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const tx3 = await kernel.sendTransaction({data: inputData}); - - // for (const log of tx3.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // console.log(valueX.toNumber()) - assert.equal(valueXRaw.slice(0,4), "0x55", "should succeed with zero errcode the first time"); - } - - const procedures4Raw = await kernel.listProcedures.call(); - const procedures4 = procedures4Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures4:", procedures4); - assert(!procedures4.includes(testProcName), "The correct name should not be in the procedure table"); - assert.strictEqual(procedures4.length, procedures3.length, "The number of procedures should not have increased"); - }) - }) - describe('B(bytes24 procName, address procAddress, uint256[] caps) - register a procedure', function () { - const testProcName = "Adder"; - const testContract = Valid.Adder; - const functionSpec = "B(bytes24,address,uint256[])"; - // console.log(contract); - it('B(bytes24 procName, address procAddress, uint256[] caps) should succeed when given cap (the registered contract will not have caps)', async function () { - const kernel = await Kernel.new(); - // console.log(`kernel: ${kernel.address}`); - - const procedures1Raw = await kernel.listProcedures.call(); - const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures1:", procedures1); - - await testutils.installEntryProc(kernel); - - const procedures2Raw = await kernel.listProcedures.call(); - const procedures2 = procedures2Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures2:", procedures2); - - const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.RegisterCap(); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); - - const deployedContract = await testutils.deployedTrimmed(contract); - // This is the procedure that will do the registering - // this currently requires Any because it uses logging for testing - const tx1 = await kernel.registerAnyProcedure(procName, deployedContract.address, capArray); - // for (const log of tx1.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // This is the procedure that will be registered - const deployedTestContract = await testutils.deployedTrimmed(testContract); - // console.log("deployedContractAddress:", deployedTestContract.address); - const procedures3Raw = await kernel.listProcedures.call(); - const procedures3 = procedures3Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures3:", procedures3); - { - const functionSelectorHash = web3.sha3("testNum()").slice(2,10); - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash; - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // we execute a test function to ensure the procedure is - // functioning properly - assert.equal(valueX.toNumber(), 392, "should receive the correct test number"); - } - - { - // console.log(deployedTestContract.address.slice(2)) - const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - // here we use padStart because 'address' is like a number, not bytes - // this inputData is custom built, it can be deleted if - // necessary, but shows the underlying input data - const manualInputData = web3.fromAscii(procName.padEnd(24,"\0")) // the name of the procedure to call (24 bytes) - + functionSelectorHash // the function selector hash (4 bytes) - + web3.fromAscii(testProcName.padEnd(24,"\0")).slice(2).padEnd(32*2,0) // the name argument for register (32 bytes) - + deployedTestContract.address.slice(2).padStart(32*2,0) // the address argument for register (32 bytes) - + web3.toHex(124).slice(2).padStart(32*2,0) // the offset for the start of caps data (32 bytes) - + web3.toHex(0).slice(2).padStart(32*2,0) // the caps data, which is currently just a length of zero (32 bytes) - // console.log(manualInputData) - // when using web3 1.0 this will be good - // try { - // console.log(deployedContract.methods.B(testProcName,deployedTestContract.address,[]).data) - // } catch (e) { - // console.log(e) - // } - const inputData = manualInputData; - // assert.strictEqual(inputData,) - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // for (const log of tx3.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // console.log(valueX.toNumber()) - assert.equal(valueX.toNumber(), 0, "should succeed with zero errcode the first time"); - } - - const procedures4Raw = await kernel.listProcedures.call(); - const procedures4 = procedures4Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures4:", procedures4); - assert(procedures4.includes(testProcName), "The correct name should be in the procedure table"); - assert.strictEqual(procedures4.length, (procedures3.length+1), "The number of procedures should have increased by 1"); - - const procTableData = await kernel.returnProcedureTable.call(); - const procTable = beakerlib.ProcedureTable.parse(procTableData); - // console.log("Kernel Address:", kernel.address) - // console.log(beakerlib.ProcedureTable.stringify(procTable)); - }) - it('B(bytes24 procName, address procAddress, uint256[] caps) should succeed when given cap (the registered contract will have 1 cap)', async function () { - const kernel = await Kernel.new(); - // console.log(`kernel: ${kernel.address}`); - - const procedures1Raw = await kernel.listProcedures.call(); - const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures1:", procedures1); - - await testutils.installEntryProc(kernel); - - const procedures2Raw = await kernel.listProcedures.call(); - const procedures2 = procedures2Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures2:", procedures2); - - const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.RegisterCap(); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); - - const deployedContract = await testutils.deployedTrimmed(contract); - // This is the procedure that will do the registering - // this currently requires Any because it uses logging for testing - const tx1 = await kernel.registerAnyProcedure(procName, deployedContract.address, capArray); - // for (const log of tx1.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // This is the procedure that will be registered - const deployedTestContract = await testutils.deployedTrimmed(testContract); - // console.log("deployedContractAddress:", deployedTestContract.address); - const procedures3Raw = await kernel.listProcedures.call(); - const procedures3 = procedures3Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures3:", procedures3); - { - const functionSelectorHash = web3.sha3("testNum()").slice(2,10); - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash; - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // we execute a test function to ensure the procedure is - // functioning properly - assert.equal(valueX.toNumber(), 392, "should receive the correct test number"); - } - - { - // console.log(deployedTestContract.address.slice(2)) - const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - // here we use padStart because 'address' is like a number, not bytes - // this inputData is custom built, it can be deleted if - // necessary, but shows the underlying input data - const manualInputData = web3.fromAscii(procName.padEnd(24,"\0")) // the name of the procedure to call (24 bytes) - + functionSelectorHash // the function selector hash (4 bytes) - + web3.fromAscii(testProcName.padEnd(24,"\0")).slice(2).padEnd(32*2,0) // the name argument for register (32 bytes) - + deployedTestContract.address.slice(2).padStart(32*2,0) // the address argument for register (32 bytes) - + web3.toHex(96).slice(2).padStart(32*2,0) // the offset for the start of caps data (32 bytes) - + web3.toHex(2).slice(2).padStart(32*2,0) // the caps data, which is currently just a length of 2 (32 bytes) - + web3.toHex(1).slice(2).padStart(32*2,0) // the length of the first (only) cap, which is 1 - + web3.toHex(9).slice(2).padStart(32*2,0) // the type of the first (only) type, which is "log any" - // console.log(manualInputData) - // // when using web3 1.0 this will be good - // try { - // console.log(deployedContract.methods.B(testProcName,deployedTestContract.address,[]).data) - // } catch (e) { - // console.log(e) - // } - const inputData = manualInputData; - // assert.strictEqual(inputData,) - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // for (const log of tx3.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // console.log(valueX.toNumber()) - assert.equal(valueX.toNumber(), 0, "should succeed with zero errcode the first time"); - } - - const procedures4Raw = await kernel.listProcedures.call(); - const procedures4 = procedures4Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures4:", procedures4); - assert(procedures4.includes(testProcName), "The correct name should be in the procedure table"); - assert.strictEqual(procedures4.length, (procedures3.length+1), "The number of procedures should have increased by 1"); - - const procTableData = await kernel.returnProcedureTable.call(); - const procTable = beakerlib.ProcedureTable.parse(procTableData); - // console.log("Kernel Address:", kernel.address) - // console.log(beakerlib.ProcedureTable.stringify(procTable)); - // console.log(procTable) - const encodedName = web3.toHex(testProcName.padEnd(24,'\0')); - // console.log(encodedName) - // console.log(procTable.procedures[encodedName]) - assert.equal(1,procTable.procedures[encodedName].caps.length, "The procedure should have 1 cap"); - }) - it('B(bytes24 procName, address procAddress, uint256[] caps) should succeed when given cap (the registered contract will have 2 caps)', async function () { - const kernel = await Kernel.new(); - // console.log(`kernel: ${kernel.address}`); - - const procedures1Raw = await kernel.listProcedures.call(); - const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures1:", procedures1); - - await testutils.installEntryProc(kernel); - - const procedures2Raw = await kernel.listProcedures.call(); - const procedures2 = procedures2Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures2:", procedures2); - - const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.RegisterCap(); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); - - const deployedContract = await testutils.deployedTrimmed(contract); - // This is the procedure that will do the registering - // this currently requires Any because it uses logging for testing - const tx1 = await kernel.registerAnyProcedure(procName, deployedContract.address, capArray); - // for (const log of tx1.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // This is the procedure that will be registered - const deployedTestContract = await testutils.deployedTrimmed(testContract); - // console.log("deployedContractAddress:", deployedTestContract.address); - const procedures3Raw = await kernel.listProcedures.call(); - const procedures3 = procedures3Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures3:", procedures3); - { - const functionSelectorHash = web3.sha3("testNum()").slice(2,10); - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash; - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // we execute a test function to ensure the procedure is - // functioning properly - assert.equal(valueX.toNumber(), 392, "should receive the correct test number"); - } - - { - // console.log(deployedTestContract.address.slice(2)) - const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - // here we use padStart because 'address' is like a number, not bytes - // this inputData is custom built, it can be deleted if - // necessary, but shows the underlying input data - const manualInputData = web3.fromAscii(procName.padEnd(24,"\0")) // the name of the procedure to call (24 bytes) - + functionSelectorHash // the function selector hash (4 bytes) - + web3.fromAscii(testProcName.padEnd(24,"\0")).slice(2).padEnd(32*2,0) // the name argument for register (32 bytes) - + deployedTestContract.address.slice(2).padStart(32*2,0) // the address argument for register (32 bytes) - + web3.toHex(96).slice(2).padStart(32*2,0) // the offset for the start of caps data (32 bytes) - - + web3.toHex(6).slice(2).padStart(32*2,0) // the caps data, which is currently just a length of 2 (32 bytes) - - + web3.toHex(1).slice(2).padStart(32*2,0) // the length of the first (only) cap, which is 1 - + web3.toHex(9).slice(2).padStart(32*2,0) // the type of the first (only) type, which is "log any" - - + web3.toHex(3).slice(2).padStart(32*2,0) // the length of the second cap, which is 1 - + web3.toHex(7).slice(2).padStart(32*2,0) // the type of the second cap, which is "write" - + web3.toHex(0x8000).slice(2).padStart(32*2,0) // the address of the wrote - + web3.toHex(1).slice(2).padStart(32*2,0) // the number of additional keys - - // console.log(manualInputData) - // // when using web3 1.0 this will be good - // try { - // console.log(deployedContract.methods.B(testProcName,deployedTestContract.address,[]).data) - // } catch (e) { - // console.log(e) - // } - const inputData = manualInputData; - // assert.strictEqual(inputData,) - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // for (const log of tx3.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // console.log(valueX.toNumber()) - assert.equal(valueX.toNumber(), 0, "should succeed with zero errcode the first time"); - } - - const procedures4Raw = await kernel.listProcedures.call(); - const procedures4 = procedures4Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures4:", procedures4); - assert(procedures4.includes(testProcName), "The correct name should be in the procedure table"); - assert.strictEqual(procedures4.length, (procedures3.length+1), "The number of procedures should have increased by 1"); - - const procTableData = await kernel.returnProcedureTable.call(); - const procTable = beakerlib.ProcedureTable.parse(procTableData); - // console.log("Kernel Address:", kernel.address) - // console.log(beakerlib.ProcedureTable.stringify(procTable)); - const encodedName = web3.toHex(testProcName.padEnd(24,'\0')); - assert.equal(2,procTable.procedures[encodedName].caps.length, "The procedure should have 2 caps"); - - assert.equal(0x9,procTable.procedures[encodedName].caps[0].type, "The first cap should be of type 0x9"); - assert.equal(0,procTable.procedures[encodedName].caps[0].values.length, "The first cap should have no values associated with it"); - - assert.equal(0x7,procTable.procedures[encodedName].caps[1].type, "The second cap should be of type 0x7"); - assert.equal(2,procTable.procedures[encodedName].caps[1].values.length, "The second cap should have 2 values associated with it"); - assert.equal(0x8000,procTable.procedures[encodedName].caps[1].values[0], "The first value of the second cap should be 0x8000"); - assert.equal(1,procTable.procedures[encodedName].caps[1].values[1], "The second value of the second cap should be 1"); - }) - it('B(bytes24 procName, address procAddress, uint256[] caps) should fail when not given cap (the registered contract tries to have 2 caps)', async function () { - const kernel = await Kernel.new(); - // console.log(`kernel: ${kernel.address}`); - - const procedures1Raw = await kernel.listProcedures.call(); - const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures1:", procedures1); - - await testutils.installEntryProc(kernel); - - const procedures2Raw = await kernel.listProcedures.call(); - const procedures2 = procedures2Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures2:", procedures2); - - const deployedContract = await testutils.deployedTrimmed(contract); - // This is the procedure that will do the registering - // this currently requires Any because it uses logging for testing - const tx1 = await kernel.registerAnyProcedure(procName, deployedContract.address, []); - // for (const log of tx1.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // This is the procedure that will be registered - const deployedTestContract = await testutils.deployedTrimmed(testContract); - // console.log("deployedContractAddress:", deployedTestContract.address); - const procedures3Raw = await kernel.listProcedures.call(); - const procedures3 = procedures3Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures3:", procedures3); - { - const functionSelectorHash = web3.sha3("testNum()").slice(2,10); - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash; - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // we execute a test function to ensure the procedure is - // functioning properly - assert.equal(valueX.toNumber(), 392, "should receive the correct test number"); - } - - { - // console.log(deployedTestContract.address.slice(2)) - const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - // here we use padStart because 'address' is like a number, not bytes - // this inputData is custom built, it can be deleted if - // necessary, but shows the underlying input data - const manualInputData = web3.fromAscii(procName.padEnd(24,"\0")) // the name of the procedure to call (24 bytes) - + functionSelectorHash // the function selector hash (4 bytes) - + web3.fromAscii(testProcName.padEnd(24,"\0")).slice(2).padEnd(32*2,0) // the name argument for register (32 bytes) - + deployedTestContract.address.slice(2).padStart(32*2,0) // the address argument for register (32 bytes) - + web3.toHex(96).slice(2).padStart(32*2,0) // the offset for the start of caps data (32 bytes) - - + web3.toHex(6).slice(2).padStart(32*2,0) // the caps data, which is currently just a length of 2 (32 bytes) - - + web3.toHex(1).slice(2).padStart(32*2,0) // the length of the first (only) cap, which is 1 - + web3.toHex(9).slice(2).padStart(32*2,0) // the type of the first (only) type, which is "log any" - - + web3.toHex(3).slice(2).padStart(32*2,0) // the length of the second cap, which is 1 - + web3.toHex(7).slice(2).padStart(32*2,0) // the type of the second cap, which is "write" - + web3.toHex(0x8000).slice(2).padStart(32*2,0) // the address of the wrote - + web3.toHex(1).slice(2).padStart(32*2,0) // the number of additional keys - - // console.log(manualInputData) - // // when using web3 1.0 this will be good - // try { - // console.log(deployedContract.methods.B(testProcName,deployedTestContract.address,[]).data) - // } catch (e) { - // console.log(e) - // } - const inputData = manualInputData; - // assert.strictEqual(inputData,) - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const tx3 = await kernel.sendTransaction({data: inputData}); - - // for (const log of tx3.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // console.log(valueX.toNumber()) - assert.equal(valueXRaw.slice(0,4), "0x55", "should succeed with zero errcode the first time"); - } - - const procedures4Raw = await kernel.listProcedures.call(); - const procedures4 = procedures4Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures4:", procedures4); - assert(!procedures4.includes(testProcName), "The name should notbe in the procedure table"); - assert.strictEqual(procedures4.length, procedures3.length, "The number of procedures should have remained the same"); - - const procTableData = await kernel.returnProcedureTable.call(); - const procTable = beakerlib.ProcedureTable.parse(procTableData); - // console.log("Kernel Address:", kernel.address) - // console.log(beakerlib.ProcedureTable.stringify(procTable)); - const encodedName = web3.toHex(testProcName.padEnd(24,'\0')); - assert(procTable.procedures[encodedName] === undefined, "The procedure should not be present in the table"); - }) - it('B(bytes24 procName, address procAddress, uint256[] caps) should fail when given the wrong cap (the registered contract tries to have 2 caps)', async function () { - const kernel = await Kernel.new(); - // console.log(`kernel: ${kernel.address}`); - - const procedures1Raw = await kernel.listProcedures.call(); - const procedures1 = procedures1Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures1:", procedures1); - - await testutils.installEntryProc(kernel); - - const procedures2Raw = await kernel.listProcedures.call(); - const procedures2 = procedures2Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures2:", procedures2); - - const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); - - const deployedContract = await testutils.deployedTrimmed(contract); - // This is the procedure that will do the registering - // this currently requires Any because it uses logging for testing - const tx1 = await kernel.registerAnyProcedure(procName, deployedContract.address, capArray); - // for (const log of tx1.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // This is the procedure that will be registered - const deployedTestContract = await testutils.deployedTrimmed(testContract); - // console.log("deployedContractAddress:", deployedTestContract.address); - const procedures3Raw = await kernel.listProcedures.call(); - const procedures3 = procedures3Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures3:", procedures3); - { - const functionSelectorHash = web3.sha3("testNum()").slice(2,10); - const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + functionSelectorHash; - const tx3 = await kernel.sendTransaction({data: inputData}); - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const valueX = web3.toBigNumber(valueXRaw); - // we execute a test function to ensure the procedure is - // functioning properly - assert.equal(valueX.toNumber(), 392, "should receive the correct test number"); - } - - { - // console.log(deployedTestContract.address.slice(2)) - const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - // here we use padStart because 'address' is like a number, not bytes - // this inputData is custom built, it can be deleted if - // necessary, but shows the underlying input data - const manualInputData = web3.fromAscii(procName.padEnd(24,"\0")) // the name of the procedure to call (24 bytes) - + functionSelectorHash // the function selector hash (4 bytes) - + web3.fromAscii(testProcName.padEnd(24,"\0")).slice(2).padEnd(32*2,0) // the name argument for register (32 bytes) - + deployedTestContract.address.slice(2).padStart(32*2,0) // the address argument for register (32 bytes) - + web3.toHex(96).slice(2).padStart(32*2,0) // the offset for the start of caps data (32 bytes) - - + web3.toHex(6).slice(2).padStart(32*2,0) // the caps data, which is currently just a length of 2 (32 bytes) - - + web3.toHex(1).slice(2).padStart(32*2,0) // the length of the first (only) cap, which is 1 - + web3.toHex(9).slice(2).padStart(32*2,0) // the type of the first (only) type, which is "log any" - - + web3.toHex(3).slice(2).padStart(32*2,0) // the length of the second cap, which is 1 - + web3.toHex(7).slice(2).padStart(32*2,0) // the type of the second cap, which is "write" - + web3.toHex(0x8000).slice(2).padStart(32*2,0) // the address of the wrote - + web3.toHex(1).slice(2).padStart(32*2,0) // the number of additional keys - - // console.log(manualInputData) - // // when using web3 1.0 this will be good - // try { - // console.log(deployedContract.methods.B(testProcName,deployedTestContract.address,[]).data) - // } catch (e) { - // console.log(e) - // } - const inputData = manualInputData; - // assert.strictEqual(inputData,) - const valueXRaw = await web3.eth.call({to: kernel.address, data: inputData}); - const tx3 = await kernel.sendTransaction({data: inputData}); - // for (const log of tx3.receipt.logs) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log(`${log.topics} - ${log.data}`); - // try { - // console.log(`${log.topics.map(web3.toAscii)} - ${web3.toAscii(log.data)}`); - // } catch(e) { - // // console.log(`${log.topics} - ${log.data}`); - // console.log("non-ascii"); - // } - // } - // console.log(valueX.toNumber()) - assert.equal(valueXRaw.slice(0,4), "0x55", "should succeed with zero errcode the first time"); - } - - const procedures4Raw = await kernel.listProcedures.call(); - const procedures4 = procedures4Raw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - // console.log("procedures4:", procedures4); - assert(!procedures4.includes(testProcName), "The name should not be in the procedure table"); - assert.strictEqual(procedures4.length, procedures3.length, "The number of procedures should not have changed"); - - const procTableData = await kernel.returnProcedureTable.call(); - const procTable = beakerlib.ProcedureTable.parse(procTableData); - // console.log("Kernel Address:", kernel.address) - // console.log(beakerlib.ProcedureTable.stringify(procTable)); - const encodedName = web3.toHex(testProcName.padEnd(24,'\0')); - assert(procTable.procedures[encodedName] === undefined, "The procedure should not be present in the table"); - }) - }) - }) +contract('Kernel with entry procedure', function () { + // These tests have a general form in which there are 2 procedures, + // Procedure A and Procedure B. The following will be performed for each + // test, although it isn't part of the properties being tested: + // 1. A new kernel will be deployed. + // 2. A basic entry procedure will be installed. + // 3. The contract code for Procedure A and Procedure B will be deployed + // to the chain. + // 4. Procedure A will be registered with the kernel. + // + // We will then test procedure registration by getting Procedure A to + // register Procedure B with a set of capabilities. + describe('Register without capabilities', function () { + it('Should succeed when Procedure A is given a general Register Capability', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new beakerlib.CallCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = []; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when Procedure A is given a Register Capability with the same name as ProcB and 192-bit prefix', async function () { + const procAName = "SysCallTestProcRegister"; + const procBName = "Adder"; + + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(192, procBName), + new beakerlib.CallCap(0,""), + ]; + + const procBContract = Valid.Adder; + const procBCaps = []; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when Procedure A is given a Register Capability with the same name as ProcB and 30-bit prefix', async function () { + const procAName = "SysCallTestProcRegister"; + const procBName = "Adder"; + + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(30, procBName), + new beakerlib.CallCap(0,""), + ]; + + const procBContract = Valid.Adder; + const procBCaps = []; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when Procedure A is given a Register Capability with the first 2 bytes of as ProcBName and 16-bit prefix', async function () { + const procAName = "SysCallTestProcRegister"; + const procBName = "Adder"; + + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(16, "Ad"), + new beakerlib.CallCap(0,""), + ]; + + const procBContract = Valid.Adder; + const procBCaps = []; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when Procedure A is given a Register Capability with the first 2 bytes of as ProcBName and 24-bit prefix', async function () { + const procAName = "SysCallTestProcRegister"; + const procBName = "Adder"; + + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(24, "Ad"), + new beakerlib.CallCap(0,""), + ]; + + const procBContract = Valid.Adder; + const procBCaps = []; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when Procedure A is not given any Register Capability', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.CallCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = []; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + }); + describe('Register Call capability', async function () { + await testCallType(beakerlib.CallCap, 0); + }); + describe('Register Delete capability', async function () { + await testCallType(beakerlib.DeleteCap, 0); + }); + describe('Register Register capability', async function () { + await testCallType(beakerlib.RegisterCap, 1); + }); + describe('Register Write capability', function () { + it('Should succeed when deriving maximal cap from maximal cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x00,"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.WriteCap(0x00,"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving invalid cap from maximal cap', async function () { + // This looks at when size extends far beyond available storage. + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x00,"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.WriteCap(0xffffffff,"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when reduced cap from maximal cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x00,"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.WriteCap(0x80,100), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when reduced cap from cap, base address ok, size too big', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,100), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.WriteCap(0x8000,101), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when reduced cap from cap, base address too low, size ok', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000, 100), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.WriteCap(0x7000,30), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when reduced cap from cap, base address too high, size ok', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000, 100), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.WriteCap(0x9000,30), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + }); + describe('Register Log capability', function () { + it('Should succeed when deriving maximal cap from maximal cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.LogCap([]), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.LogCap([]), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when adding one topic to cap from maximal cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.LogCap([]), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd")]), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when adding two topics to cap from maximal cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.LogCap([]), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd"), web3.fromAscii("efgh")]), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when adding three topics to cap from maximal cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.LogCap([]), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd"), web3.fromAscii("efgh"), web3.fromAscii("ijkl")]), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when adding four topics to cap from maximal cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.LogCap([]), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd"), web3.fromAscii("efgh"), web3.fromAscii("ijkl"), web3.fromAscii("mnop")]), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving one topic from same one topic cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd")]), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd")]), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving one topic from two topic cap, even though that top is the same', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd"), web3.fromAscii("efgh")]), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd")]), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when deriving one topic from differnt one topic cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.LogCap([web3.fromAscii("abcd")]), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new beakerlib.LogCap([web3.fromAscii("efgh")]), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + }); + describe('Register previously deleted procedure name', function () { + it('Should succeed when registering previously deleted name, no caps', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new beakerlib.DeleteCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + // Initially we will have no caps + const procBCaps1 = []; + + const shouldSucceed = true; + + // Deploy the test kernel + const kernel = await testutils.deployTestKernel(); + + // Register Procedure A + await regProcDirectTest(kernel, procAName, procAContract, procACaps); + + // Register Procedure B using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps1, true) + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps1); + + // Delete Procedure B using Procedure A + await delProcTest(kernel, procAName, procBName, true); + + // The second registration will use these caps + const procBCaps2 = []; + + // Register Procedure B (again) using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps2, shouldSucceed); + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps2); + }); + it('Should succeed when registering previously deleted name, same caps', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new beakerlib.DeleteCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + // Initially we will have these caps + const procBCaps1 = [new beakerlib.WriteCap(0x8000,2)]; + + const shouldSucceed = true; + + // Deploy the test kernel + const kernel = await testutils.deployTestKernel(); + + // Register Procedure A + await regProcDirectTest(kernel, procAName, procAContract, procACaps); + + // Register Procedure B using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps1, true) + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps1); + + // Delete Procedure B using Procedure A + await delProcTest(kernel, procAName, procBName, true); + + // The second registration will use these caps + const procBCaps2 = [new beakerlib.WriteCap(0x8000,2)]; + + // Register Procedure B (again) using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps2, shouldSucceed); + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps2); + }); + it('Should succeed when registering previously deleted name, more caps', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new beakerlib.DeleteCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + // Initially we will have no caps + const procBCaps1 = []; + + const shouldSucceed = true; + + // Deploy the test kernel + const kernel = await testutils.deployTestKernel(); + + // Register Procedure A + await regProcDirectTest(kernel, procAName, procAContract, procACaps); + + // Register Procedure B using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps1, true) + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps1); + + // Delete Procedure B using Procedure A + await delProcTest(kernel, procAName, procBName, true); + + // The second registration will use these caps + const procBCaps2 = [new beakerlib.WriteCap(0x8000,2)]; + + // Register Procedure B (again) using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps2, shouldSucceed); + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps2); + }); + it('Should succeed when registering previously deleted name, fewer caps', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new beakerlib.DeleteCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + // Initially we will have no caps + const procBCaps1 = [new beakerlib.WriteCap(0x8000,2)]; + + const shouldSucceed = true; + + // Deploy the test kernel + const kernel = await testutils.deployTestKernel(); + + // Register Procedure A + await regProcDirectTest(kernel, procAName, procAContract, procACaps); + + // Register Procedure B using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps1, true) + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps1); + + // Delete Procedure B using Procedure A + await delProcTest(kernel, procAName, procBName, true); + + // The second registration will use these caps + const procBCaps2 = []; + + // Register Procedure B (again) using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps2, shouldSucceed); + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps2); + }); + it('Should fail when re-registering previously registered name, no caps', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new beakerlib.DeleteCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + // Initially we will have no caps + const procBCaps1 = []; + + const shouldSucceed = false; + + // Deploy the test kernel + const kernel = await testutils.deployTestKernel(); + + // Register Procedure A + await regProcDirectTest(kernel, procAName, procAContract, procACaps); + + // Register Procedure B using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps1, true) + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps1); + + // The second registration will use these caps + const procBCaps2 = []; + + // Register Procedure B (again) using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps2, shouldSucceed); + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps2); + }); + it('Should fail when re-registering previously registered name, same caps', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new beakerlib.DeleteCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + // Initially we will have no caps + const procBCaps1 = [new beakerlib.WriteCap(0x8000,2)]; + + const shouldSucceed = false; + + // Deploy the test kernel + const kernel = await testutils.deployTestKernel(); + + // Register Procedure A + await regProcDirectTest(kernel, procAName, procAContract, procACaps); + + // Register Procedure B using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps1, true) + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps1); + + // The second registration will use these caps + const procBCaps2 = [new beakerlib.WriteCap(0x8000,2)]; + + // Register Procedure B (again) using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps2, shouldSucceed); + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps2); + }); + it('Should fail when re-registering previously registered name, more caps', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new beakerlib.DeleteCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + // Initially we will have no caps + const procBCaps1 = []; + + const shouldSucceed = false; + + // Deploy the test kernel + const kernel = await testutils.deployTestKernel(); + + // Register Procedure A + await regProcDirectTest(kernel, procAName, procAContract, procACaps); + + // Register Procedure B using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps1, true); + + // Check that the capabilities are correct + await checkCaps(kernel, procBName, procBCaps1); + + // The second registration will use these caps + const procBCaps2 = [new beakerlib.WriteCap(0x8000,2)]; + + // Register Procedure B (again) using Procedure A + await regProcTest(kernel, procAName, procBName, procBContract, + procBCaps2, shouldSucceed); + + // Check that there are no capabilities + await checkCaps(kernel, procBName, []); + }); + }); }) + +async function testCallType(ThisCap, capIndex) { + it('Should succeed when deriving general cap from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(0,"", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when deriving general cap from no cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(0,"", capIndex), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving larger prefix cap (30) from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(30,"", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving larger prefix cap (192) from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(192,"", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when deriving smaller prefix cap (30) from larger prefix cap (48)', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(48,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(30,"", capIndex), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving 2 larger prefix caps (40, 192) from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(40,"", capIndex), + new ThisCap(192,"", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving general cap with address from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(0,"abcd", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving prefix(30) with address from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(30,"abcd", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving 2 general caps with different addresses from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(0,"abcd", capIndex), + new ThisCap(0,"wxyz", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving 2 prefix(30) caps with different addresses from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(30,"abcd", capIndex), + new ThisCap(30,"wxyz", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving a prefix(16) cap and a prefix(32) cap with different addresses from general cap', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(0,""), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(16,"ab", capIndex), + new ThisCap(32,"wxyz", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should succeed when deriving a prefix(32) cap from a prefix(16) where 16 bits match, but others do not', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(16,"ab"), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(32,"abcd", capIndex), + new ThisCap(32,"abxy", capIndex), + ]; + + const shouldSucceed = true; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when deriving a prefix(32) cap from a prefix(16) where addresses are different', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(16,"ab"), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(32,"axcd", capIndex), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); + it('Should fail when deriving a prefix(16) cap from a prefix(32) where addresses are the same', async function () { + const procAName = "SysCallTestProcRegister"; + const procAContract = Valid.SysCallTestProcRegister; + const procACaps = [ + new beakerlib.WriteCap(0x8000,2), + new beakerlib.RegisterCap(0, ""), + new ThisCap(32,"abcd"), + ]; + + const procBName = "Adder"; + const procBContract = Valid.Adder; + const procBCaps = [ + new ThisCap(16,"abcd", capIndex), + ]; + + const shouldSucceed = false; + await stdTest(procAName, procAContract, procACaps, procBName, procBContract, procBCaps, shouldSucceed); + }); +} + +async function regProcDirectTest(kernel, procName, procContract, procCaps) { + // Check that proc is not already installed + const procedures1Raw = await kernel.listProcedures.call(); + const procedures1 = procedures1Raw.map(web3.toAscii) + .map(s => s.replace(/\0.*$/, '')); + assert(!procedures1.includes(procName), + `Proc ${procName} should not be registered`); + + // Deploy the contract to the chain + const deployedContract = await testutils.deployedTrimmed(procContract); + // Register the procedure directly to the kernel using the test API. + const tx1 = await kernel.registerAnyProcedure(procName, + deployedContract.address, beakerlib.Cap.toInput(procCaps)); + + // Check that proc was correctly installed. + const procedures2Raw = await kernel.listProcedures.call(); + const procedures2 = procedures2Raw.map(web3.toAscii) + .map(s => s.replace(/\0.*$/, '')); + assert(procedures2.includes(procName), + `Proc ${procName} should be registered`); + + { + // Test that proc returns the correct testNum + const functionSelectorHash = web3.sha3("testNum()").slice(2,10); + const inputData = web3.fromAscii(procName.padEnd(24,"\0")) + + functionSelectorHash; + const tx3 = await kernel.sendTransaction({data: inputData}); + const valueXRaw = await web3.eth.call({to: kernel.address, + data: inputData}); + const valueX = web3.toBigNumber(valueXRaw); + // Execute a test function to ensure the procedure is + // functioning properly + assert.equal(valueX.toNumber(), 392, + "should receive the correct test number"); + } +} + +// Register a procedure to the given kernel. +async function regProcTest(kernel, procAName, procBName, procBContract, + procBCaps, shouldSucceed) { + const functionSpec = "B(bytes24,address,uint256[])"; + + // const procedures3Raw = await kernel.listProcedures.call(); + // const procedures3 = procedures3Raw.map(web3.toAscii) + // .map(s => s.replace(/\0.*$/, '')); + // assert(!procedures3.includes(procBName), + // `Proc ${procBName} should not be registered`); + + let mainTX; + // This is the procedure that will be registered + const deployedContractB = await testutils.deployedTrimmed(procBContract); + { + const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); + const encodedCapsVals = beakerlib.Cap.toInput(procBCaps).map(x=>web3.toHex(x).slice(2).padStart(64,0)); + const manualInputData + // the name of the procedure to call (24 bytes) + = web3.fromAscii(procAName.padEnd(24,"\0")) + // the function selector hash (4 bytes) + + functionSelectorHash + // the name argument for register (32 bytes) + + web3.fromAscii(procBName.padEnd(24,"\0")).slice(2).padEnd(32*2,0) + // the address argument for register (32 bytes) + + deployedContractB.address.slice(2).padStart(32*2,0) + // the offset for the start of caps data (32 bytes) + + web3.toHex(96).slice(2).padStart(32*2,0) + // the caps data, which starts with the length + // + web3.toHex(0).slice(2).padStart(32*2,0) + + web3.toHex(encodedCapsVals.length).slice(2).padStart(32*2,0) + // followed by the values + + encodedCapsVals.join(""); + + // when using web3 1.0 this will be good + // try { + // console.log(deployedContract.methods.B(testProcName, + // deployedTestContract.address,[]).data) + // } catch (e) { + // console.log(e) + // } + const inputData = manualInputData; + const valueXRaw = await web3.eth.call({to: kernel.address, + data: inputData}); + mainTX = await kernel.sendTransaction({data: inputData}); + const valueX = web3.toBigNumber(valueXRaw); + if (shouldSucceed) { + assert.equal(valueX.toNumber(), 0, + "should succeed with zero errcode"); + } else { + assert(valueX.toNumber() != 0, "should fail with non-zero errcode"); + } + } + + const procedures4Raw = await kernel.listProcedures.call(); + const procedures4 = procedures4Raw.map(web3.toAscii) + .map(s => s.replace(/\0.*$/, '')); + return mainTX; +} + +async function checkCaps(kernel, procName, procCaps) { + const procTableData = await kernel.returnProcedureTable.call(); + const procTable = beakerlib.ProcedureTable.parse(procTableData); + const procNameEncoded = web3.fromAscii(procName.padEnd(24,'\0')); + const procData = procTable.procedures[procNameEncoded]; + + assert.deepStrictEqual( + stripCapIndexVals(beakerlib.Cap.toCLists(procCaps)), + stripCapIndexVals(procData.caps), + "The requested caps should equal resulting caps"); +} + +// Delete a procedure from the given kernel. +async function delProcTest(kernel, procAName, procBName, shouldSucceed) { + const functionSpec = "Delete(bytes24)"; + + // Check that procA was correctly installed. + const procedures1Raw = await kernel.listProcedures.call(); + const procedures1 = procedures1Raw.map(web3.toAscii) + .map(s => s.replace(/\0.*$/, '')); + assert(procedures1.includes(procBName), "ProcB should initially be registered"); + + + let mainTX; + // This is the procedure that will be registered + { + const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); + const manualInputData + // the name of the procedure to call (24 bytes) + = web3.fromAscii(procAName.padEnd(24,"\0")) + // the function selector hash (4 bytes) + + functionSelectorHash + // the name argument for register (32 bytes) + + web3.fromAscii(procBName.padEnd(24,"\0")).slice(2).padEnd(32*2,0); + + // when using web3 1.0 this will be good + // try { + // console.log(deployedContract.methods.B(testProcName, + // deployedTestContract.address,[]).data) + // } catch (e) { + // console.log(e) + // } + const inputData = manualInputData; + const valueXRaw = await web3.eth.call({to: kernel.address, + data: inputData}); + mainTX = await kernel.sendTransaction({data: inputData}); + const valueX = web3.toBigNumber(valueXRaw); + if (shouldSucceed) { + assert.equal(valueX.toNumber(), 0, + "should succeed with zero errcode"); + } else { + assert(valueX.toNumber() != 0, "should fail with non-zero errcode"); + } + } + + const procedures2Raw = await kernel.listProcedures.call(); + const procedures2 = procedures2Raw.map(web3.toAscii) + .map(s => s.replace(/\0.*$/, '')); + if (shouldSucceed) { + assert(!procedures2.includes(procBName), + "The procedure name should not be in the procedure table"); + assert.strictEqual(procedures2.length, (procedures1.length-1), + "The number of procedures should have decreased by 1"); + } else { + assert(!procedures2.includes(procBName), + "The procedure name should still be in the procedure table"); + assert.strictEqual(procedures2.length, procedures3.length, + "The number of procedures should have remained the same"); + } + return mainTX; +} + +// A test which uses procA to register procB. procACaps are the capabilities +// that procA is originally registered with procBCaps are the caps that it will +// attempt to register procB with. +async function stdTest(procAName, procAContract, procACaps, + procBName, procBContract, procBCaps, shouldSucceed) { + + const kernel = await testutils.deployTestKernel(); + + const deployedContractA = await testutils.deployedTrimmed(procAContract); + // This is the procedure that will do the registering + // this currently requires Any because it uses logging for testing + const tx1 = await kernel.registerAnyProcedure(procAName, + deployedContractA.address, beakerlib.Cap.toInput(procACaps)); + // Check that procA was correctly installed. + const procedures3Raw = await kernel.listProcedures.call(); + const procedures3 = procedures3Raw.map(web3.toAscii) + .map(s => s.replace(/\0.*$/, '')); + assert(procedures3.includes(procAName), "ProcA should be registered"); + + const functionSpec = "B(bytes24,address,uint256[])"; + { + // Test that procA returns the correct testNum + const functionSelectorHash = web3.sha3("testNum()").slice(2,10); + const inputData = web3.fromAscii(procAName.padEnd(24,"\0")) + + functionSelectorHash; + const valueXRaw = await web3.eth.call({to: kernel.address, + data: inputData}); + const tx3 = await kernel.sendTransaction({data: inputData}); + const valueX = web3.toBigNumber(valueXRaw); + // we execute a test function to ensure the procedure is + // functioning properly + assert.equal(valueX.toNumber(), 392, + "should receive the correct test number"); + } + + let mainTX; + // This is the procedure that will be registered + const deployedContractB = await testutils.deployedTrimmed(procBContract); + { + const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); + const encodedCapsVals = beakerlib.Cap.toInput(procBCaps).map(x=>web3.toHex(x).slice(2).padStart(64,0)); + const manualInputData + // the name of the procedure to call (24 bytes) + = web3.fromAscii(procAName.padEnd(24,"\0")) + // the function selector hash (4 bytes) + + functionSelectorHash + // the name argument for register (32 bytes) + + web3.fromAscii(procBName.padEnd(24,"\0")).slice(2).padEnd(32*2,0) + // the address argument for register (32 bytes) + + deployedContractB.address.slice(2).padStart(32*2,0) + // the offset for the start of caps data (32 bytes) + + web3.toHex(96).slice(2).padStart(32*2,0) + // the caps data, which starts with the length + // + web3.toHex(0).slice(2).padStart(32*2,0) + + web3.toHex(encodedCapsVals.length).slice(2).padStart(32*2,0) + // followed by the values + + encodedCapsVals.join(""); + + // when using web3 1.0 this will be good + // try { + // console.log(deployedContract.methods.B(testProcName, + // deployedTestContract.address,[]).data) + // } catch (e) { + // console.log(e) + // } + const inputData = manualInputData; + const valueXRaw = await web3.eth.call({to: kernel.address, + data: inputData}); + mainTX = await kernel.sendTransaction({data: inputData}); + const valueX = web3.toBigNumber(valueXRaw); + if (shouldSucceed) { + assert.equal(valueX.toNumber(), 0, + "should succeed with zero errcode"); + } else { + assert(valueX.toNumber() != 0, "should fail with non-zero errcode"); + } + } + + const procedures4Raw = await kernel.listProcedures.call(); + const procedures4 = procedures4Raw.map(web3.toAscii) + .map(s => s.replace(/\0.*$/, '')); + if (shouldSucceed) { + assert(procedures4.includes(procBName), + "The correct name should be in the procedure table"); + assert.strictEqual(procedures4.length, (procedures3.length+1), + "The number of procedures should have increased by 1"); + // TODO: check that the capabilities are correct. + const procTableData = await kernel.returnProcedureTable.call(); + const procTable = beakerlib.ProcedureTable.parse(procTableData); + const procBNameEncoded = web3.fromAscii(procBName.padEnd(24,'\0')); + const procBData = procTable.procedures[procBNameEncoded]; + + assert.deepStrictEqual( + stripCapIndexVals(beakerlib.Cap.toCLists(procBCaps)), + stripCapIndexVals(procBData.caps), + "The requested caps should equal resulting caps"); + } else { + assert(!procedures4.includes(procBName), + "The correct name should not be in the procedure table"); + assert.strictEqual(procedures4.length, procedures3.length, + "The number of procedures should have remained the same"); + } + return mainTX; +} + +// Test hack to remove data we don't care about. The kernel stores no +// information about where a capability was derived from. +function stripCapIndexVals(capData) { + for (const capType in capData) { + capData[capType].capIndex = 0; + for (const cap in capData[capType]) { + capData[capType][cap].capIndex = 0; + } + } + return capData; +} diff --git a/test/withentryproc/syscalls/write.js b/test/withentryproc/syscalls/write.js index dd13950..e7a02d2 100644 --- a/test/withentryproc/syscalls/write.js +++ b/test/withentryproc/syscalls/write.js @@ -25,8 +25,8 @@ const Invalid = { contract('Kernel with entry procedure', function (accounts) { describe('Write SysCall Procedure', function () { it('S() should succeed when given cap', async function () { - const kernel = await Kernel.new(); - const factory = await Factory.new(); + + const kernel = await testutils.deployTestKernel(); const capArraySysCallTest = beakerlib.Cap.toInput([ new beakerlib.WriteCap(0x8500,2), @@ -40,7 +40,6 @@ contract('Kernel with entry procedure', function (accounts) { const newValue1 = await kernel.testGetter.call(); assert.equal(newValue1.toNumber(), 3, "The value should be 3 before the execution"); - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -68,7 +67,8 @@ contract('Kernel with entry procedure', function (accounts) { }) it('S() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const SysCallTestWrite = await testutils.deployedTrimmed(Valid.SysCallTestWrite); const simpleTest = await testutils.deployedTrimmed(Valid.Multiply); @@ -78,7 +78,6 @@ contract('Kernel with entry procedure', function (accounts) { const newValue1 = await kernel.testGetter.call(); assert.equal(newValue1.toNumber(), 3, "The value should be 3 before the execution"); - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -105,7 +104,8 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(newValue4.toNumber(), 3, "The value should still be 3 after the execution"); }) it('S() should fail when trying to write to an address below its cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const capArraySysCallTest = beakerlib.Cap.toInput([ new beakerlib.WriteCap(0x8500,2), @@ -119,7 +119,6 @@ contract('Kernel with entry procedure', function (accounts) { const newValue1 = await kernel.testGetter.call(); assert.equal(newValue1.toNumber(), 3, "The value should be 3 before the execution"); - await testutils.installEntryProc(kernel); // Procedure keys must occupay the first 24 bytes, so must be // padded @@ -146,4 +145,4 @@ contract('Kernel with entry procedure', function (accounts) { assert.equal(newValue4.toNumber(), 3, "The value should still be 3 after the execution"); }) }) -}) \ No newline at end of file +}) diff --git a/test/withoutentryproc/procedures.js b/test/withoutentryproc/procedures.js index 10a9f35..ed20006 100644 --- a/test/withoutentryproc/procedures.js +++ b/test/withoutentryproc/procedures.js @@ -37,23 +37,24 @@ const testAccount = 0; contract('Kernel without entry procedure', function (accounts) { describe('.listProcedures()', function () { it('should return nothing if zero procedures', async function () { - let kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); let procedures = await kernel.listProcedures.call(); - assert.equal(procedures.length, 0); + assert.equal(procedures.length, 1); }) it('should return existing procedure keys', async function () { - let kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); const testAdder = await testutils.deployedTrimmed(Valid.Adder); let [err, address] = await kernel.registerProcedure.call('TestAdder', testAdder.address, []); let tx1 = await kernel.registerProcedure('TestAdder', testAdder.address, []); let procedures = await kernel.listProcedures.call(); - assert.equal(procedures.length, 1); + assert.equal(procedures.length, 2); }); it('should return a list of procedures which can be retrieved', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const speccedProcedures = [ ["TestAdder", Valid.Adder], ["TestDivider", Valid.Divide], @@ -69,14 +70,15 @@ contract('Kernel without entry procedure', function (accounts) { const procedures = proceduresRaw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); // Test that the number of procedures stored is the same as the - // number of procedures created - assert.equal(procedures.length, speccedProcedures.length); + // number of procedures created. The +1 accounts for the entry proc + assert.equal(procedures.length, speccedProcedures.length+1); // Cycle through each of the listed procedures - for (const i in procedures) { - // Test that the order and indexing of procedures is the same - assert.equal(speccedProcedures[i][0], procedures[i]) + for (let i = 0; i < (procedures.length - 1); i++) { + // Test that the order and indexing of procedures is the same. + // We skip procedure 0, as that is the entry proc. + assert.equal(speccedProcedures[i][0], procedures[i+1]) // Retrieve the listed procedure adress - const address = await kernel.getProcedure.call(procedures[i]); + const address = await kernel.getProcedureAddress.call(procedures[i+1]); // Check the address is correct assert(web3.isAddress(address), `Procedure Address (${address}) is a real address`); assert(!isNullAddress(address), `Procedure Address (${address}) is not null`); @@ -86,9 +88,9 @@ contract('Kernel without entry procedure', function (accounts) { } }); }) - describe('.getProcedure()', function () { + describe('.getProcedureAddress()', function () { it('should return a non-zero address iff procedure exists', async function () { - let kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); // Create "TestAdder" // Find the address (ephemerally) @@ -101,16 +103,16 @@ contract('Kernel without entry procedure', function (accounts) { let tx1 = await kernel.registerProcedure('TestAdder', testAdder.address, []); // Get the procedure - let address = await kernel.getProcedure.call("TestAdder"); + let address = await kernel.getProcedureAddress.call("TestAdder"); assert(web3.isAddress(address), `Procedure Address (${address}) is a real address`); assert(!isNullAddress(address), `Procedure Address (${address}) is not null`); assert.equal(creationAddress, address); }); it('should return a zero address iff procedure does not exist', async function () { - let kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); // No procedures exist yet (nor does "TestAdder") - let address = await kernel.getProcedure.call('TestAdder'); + let address = await kernel.getProcedureAddress.call('TestAdder'); assert(web3.isAddress(address), `Procedure Address (${address}) is a real address`) assert(isNullAddress(address), `Procedure Address (${address}) is null`) }); @@ -118,7 +120,7 @@ contract('Kernel without entry procedure', function (accounts) { describe('.registerProcedure()', function () { it('should create valid procedure', async function () { - let kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); const procedureName = "TestAdder"; const testAdder = await testutils.deployedTrimmed(Valid.Adder); let [err, address] = await kernel.registerProcedure.call(procedureName, testAdder.address, []); @@ -142,7 +144,8 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(testutils.trimSwarm(Valid.Adder.deployedBytecode), code); }); it('should create valid procedure (max key length)', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const name = "start1234567890123456end"; assert.equal(name.length, 24); const testAdder = await testutils.deployedTrimmed(Valid.Adder); @@ -167,7 +170,8 @@ contract('Kernel without entry procedure', function (accounts) { }); it('should create 2 valid procedures', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const proceduresRaw1 = await kernel.listProcedures.call(); const name = "start1234567890123456end"; @@ -210,7 +214,7 @@ contract('Kernel without entry procedure', function (accounts) { describe('should reject invalid key', function () { it('zero length', async function () { - let kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); const testAdder = await testutils.deployedTrimmed(Valid.Adder); let [err, creationAddress] = await kernel.registerProcedure.call('', testAdder.address, []); @@ -220,16 +224,19 @@ contract('Kernel without entry procedure', function (accounts) { const proceduresRaw = await kernel.listProcedures.call(); const procedures = proceduresRaw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - assert.equal(procedures.length, 0); + // There should be a single procedure: the initial entry + // procedure. + assert.equal(procedures.length, 1); assert(!procedures.includes('')) - const address = await kernel.getProcedure.call(''); + const address = await kernel.getProcedureAddress.call(''); assert(web3.isAddress(address), `Procedure Address (${address}) is a real address`) assert(isNullAddress(address), 'Procedure Address is null') }); it('duplicate procedure key', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const name = "TestAdder"; const testAdder = await testutils.deployedTrimmed(Valid.Adder); // This is the first time the procedure is added @@ -240,13 +247,15 @@ contract('Kernel without entry procedure', function (accounts) { const testMultiply = await testutils.deployedTrimmed(Valid.Multiply); const [err2, address2] = await kernel.registerProcedure.call(name, testMultiply.address, []); const tx2 = await kernel.registerProcedure(name, testMultiply.address, []); - assert.equal(err2, 3); + assert.equal(err2.toNumber(), 4); const proceduresRaw = await kernel.listProcedures.call(); const procedures = proceduresRaw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); - assert.equal(procedures.length, 1); + // There should be two procedures, the intial entry procedure, + // and teh procedure we first registered. + assert.equal(procedures.length, 2); - const address = await kernel.getProcedure.call(name); + const address = await kernel.getProcedureAddress.call(name); assert.equal(address, address1); assert.notEqual(address, address2); assert(web3.isAddress(address), `Procedure Address (${address}) is a real address`) @@ -261,12 +270,14 @@ contract('Kernel without entry procedure', function (accounts) { describe('.deleteProcedure()', function () { it('should return error if procedure key does not exist(3)', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const [err, deleteAddress] = await kernel.deleteProcedure.call('test'); assert.equal(err, 2); }); it('should return deleted procedure address if procedure key is valid', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const testAdder = await testutils.deployedTrimmed(Valid.Adder); const [err1, address] = await kernel.registerProcedure.call("test", testAdder.address, []); assert.equal(err1, 0); @@ -287,7 +298,8 @@ contract('Kernel without entry procedure', function (accounts) { }); it('should remove the procedure from the list on deletion', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const procedureName = "test"; const testAdder = await testutils.deployedTrimmed(Valid.Adder); @@ -305,12 +317,15 @@ contract('Kernel without entry procedure', function (accounts) { const [err2, deleteAddress] = await kernel.deleteProcedure.call(procedureName); assert.equal(err2, 0); + const retrievedAddress1 = await kernel.getProcedureAddress(procedureName); + assert(!isNullAddress(retrievedAddress1), "The key should be retrievable") const tx2 = await kernel.deleteProcedure('test'); assert.equal(address, deleteAddress); - const retrievedAddress = await kernel.getProcedure(procedureName); - assert(isNullAddress(retrievedAddress), "The key be able to be retrieved") + const retrievedAddress = await kernel.getProcedureAddress(procedureName); + // console.log(retrievedAddress) + assert(isNullAddress(retrievedAddress), "The key should not be retrievable") const proceduresRaw = await kernel.listProcedures.call(); const procedures = proceduresRaw.map(web3.toAscii).map(s => s.replace(/\0.*$/, '')); @@ -318,7 +333,8 @@ contract('Kernel without entry procedure', function (accounts) { }) it('should remove the procedure from the list on deletion (multiple)', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const procedureName = "test"; const testAdder = await testutils.deployedTrimmed(Valid.Adder); @@ -348,7 +364,7 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(address, deleteAddress); - const retrievedAddress = await kernel.getProcedure(procedureName); + const retrievedAddress = await kernel.getProcedureAddress(procedureName); assert(isNullAddress(retrievedAddress), "The key be able to be retrieved") assert(!proceduresAfter.includes(procedureName), "The procedure name should no longer be included in the procedure table") @@ -366,11 +382,12 @@ contract('Kernel without entry procedure', function (accounts) { describe('should not have side-effects', function() { it('removing then registering a new proc with same name + capabilities', async function() { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const table0 = await kernel.returnRawProcedureTable.call() const cap1 = new beakerlib.LogCap([]); - const cap2 = new beakerlib.LogCap([0xdeadbeef]); + const cap2 = new beakerlib.LogCap(["0xdeadbeef"]); const capArray = beakerlib.Cap.toInput([cap1, cap2]); const procedureName = "test"; @@ -386,7 +403,7 @@ contract('Kernel without entry procedure', function (accounts) { const table2 = await kernel.returnRawProcedureTable.call() assert.deepEqual(table0, table2, 'Procedure Tables should be equal after deletion') - const retrievedAddress = await kernel.getProcedure(procedureName); + const retrievedAddress = await kernel.getProcedureAddress(procedureName); assert(isNullAddress(retrievedAddress), "Procedure is deleted") await kernel.registerProcedure.call(procedureName, testAdder.address, capArray); @@ -399,11 +416,12 @@ contract('Kernel without entry procedure', function (accounts) { it('removing then registering a superset with same name', async function() { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const table_empty = await kernel.returnRawProcedureTable.call() const cap1 = new beakerlib.LogCap([]); - const cap2 = new beakerlib.LogCap([0xdeadbeef]); + const cap2 = new beakerlib.LogCap(["0xdeadbeef"]); const capArray1 = beakerlib.Cap.toInput([cap1]); const capArray2 = beakerlib.Cap.toInput([cap1, cap2]); @@ -436,7 +454,8 @@ contract('Kernel without entry procedure', function (accounts) { // TODO: this is not currently functional it.skip('should destroy the procedures contract on deletion', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const testAdder = await testutils.deployedTrimmed(Valid.Adder); const [err1, address] = await kernel.registerProcedure.call("test", testAdder.address, []); assert.equal(err1, 0); @@ -464,7 +483,8 @@ contract('Kernel without entry procedure', function (accounts) { describe('should reject invalid key', function () { it('zero length (1)', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const [err, deleteAddress] = await kernel.deleteProcedure.call(''); assert.equal(err, 1); @@ -474,12 +494,13 @@ contract('Kernel without entry procedure', function (accounts) { describe('.executeProcedure(bytes24 key, bytes payload)', function () { it('should return error if procedure key does not exist(3)', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const procName = "test"; const functionSpec = "executeProcedure(bytes24,string,bytes)" const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); - const inputData = functionSelectorHash + const inputData = "0x" + functionSelectorHash + web3.fromAscii(procName.padEnd(24,"\0")).slice(2).padEnd(64,"0") + "60".padStart(64,"0") + "80".padStart(64,"0") @@ -495,17 +516,18 @@ contract('Kernel without entry procedure', function (accounts) { describe('Simple Procedure', function () { it('X() should fail', async function () { // This now longer fails as we included a fallback function - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const procName = "Simple"; const testSimple = await testutils.deployedTrimmed(Valid.Simple); - const [, address] = await kernel.registerProcedure.call(procName, testSimple.address, []); - const tx = await kernel.registerProcedure(procName, testSimple.address, []); + const [, address] = await kernel.registerAnyProcedure.call(procName, testSimple.address, []); + const tx = await kernel.registerAnyProcedure(procName, testSimple.address, []); const functionSpec = "executeProcedure(bytes24,string,bytes)" const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); const calledFunctionSpec = "X()"; - const inputData = functionSelectorHash + const inputData = "0x" + functionSelectorHash + web3.fromAscii(procName.padEnd(24,"\0")).slice(2).padEnd(64,"0") + "60".padStart(64,"0") + "a0".padStart(64,"0") @@ -521,17 +543,18 @@ contract('Kernel without entry procedure', function (accounts) { }) it('A() should succeed', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const procName = "Simple"; const testSimple = await testutils.deployedTrimmed(Valid.Simple); - const [, address] = await kernel.registerProcedure.call(procName, testSimple.address, []); - const tx = await kernel.registerProcedure(procName, testSimple.address, []); + const [, address] = await kernel.registerAnyProcedure.call(procName, testSimple.address, []); + const tx = await kernel.registerAnyProcedure(procName, testSimple.address, []); const functionSpec = "executeProcedure(bytes24,string,bytes)" const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); const calledFunctionSpec = "A()"; - const inputData = functionSelectorHash + const inputData = "0x" + functionSelectorHash + web3.fromAscii(procName.padEnd(24,"\0")).slice(2).padEnd(64,"0") + "60".padStart(64,"0") + "a0".padStart(64,"0") @@ -547,17 +570,18 @@ contract('Kernel without entry procedure', function (accounts) { it('C() should fail without correctly specifying arguments', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const procName = "Simple"; const testSimple = await testutils.deployedTrimmed(Valid.Simple); - const [, address] = await kernel.registerProcedure.call(procName, testSimple.address, []); - const tx = await kernel.registerProcedure(procName, testSimple.address, []); + const [, address] = await kernel.registerAnyProcedure.call(procName, testSimple.address, []); + const tx = await kernel.registerAnyProcedure(procName, testSimple.address, []); const functionSpec = "executeProcedure(bytes24,string,bytes)" const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); const calledFunctionSpec = "C()"; - const inputData = functionSelectorHash + const inputData = "0x" + functionSelectorHash + web3.fromAscii(procName.padEnd(24,"\0")).slice(2).padEnd(64,"0") + "60".padStart(64,"0") + "a0".padStart(64,"0") @@ -574,17 +598,18 @@ contract('Kernel without entry procedure', function (accounts) { it('C() should fail when using type synonyms such as uint, which cant be used in function selectors', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const procName = "Simple"; const testSimple = await testutils.deployedTrimmed(Valid.Simple); - const [, address] = await kernel.registerProcedure.call(procName, testSimple.address, []); - const tx = await kernel.registerProcedure(procName, testSimple.address, []); + const [, address] = await kernel.registerAnyProcedure.call(procName, testSimple.address, []); + const tx = await kernel.registerAnyProcedure(procName, testSimple.address, []); const functionSpec = "executeProcedure(bytes24,string,bytes)" const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); const calledFunctionSpec = "C(uint)"; - const inputData = functionSelectorHash + const inputData = "0x" + functionSelectorHash + web3.fromAscii(procName.padEnd(24,"\0")).slice(2).padEnd(64,"0") + "60".padStart(64,"0") + "a0".padStart(64,"0") @@ -599,17 +624,18 @@ contract('Kernel without entry procedure', function (accounts) { }) it('C(uint256) should succeed passing arguments', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const procName = "Simple"; const testSimple = await testutils.deployedTrimmed(Valid.Simple); - const [, address] = await kernel.registerProcedure.call(procName, testSimple.address, []); - const tx = await kernel.registerProcedure(procName, testSimple.address, []); + const [, address] = await kernel.registerAnyProcedure.call(procName, testSimple.address, []); + const tx = await kernel.registerAnyProcedure(procName, testSimple.address, []); const functionSpec = "executeProcedure(bytes24,string,bytes)" const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); const calledFunctionSpec = "C(uint256)"; - const inputData = functionSelectorHash + const inputData = "0x" + functionSelectorHash + web3.fromAscii(procName.padEnd(24,"\0")).slice(2).padEnd(64,"0") + "60".padStart(64,"0") + "a0".padStart(64,"0") @@ -627,7 +653,8 @@ contract('Kernel without entry procedure', function (accounts) { describe('Discover Procedure Table', function () { it('should print a procedure table', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.WriteCap(0x8000,0); @@ -637,12 +664,12 @@ contract('Kernel without entry procedure', function (accounts) { const testSimple = await testutils.deployedTrimmed(Valid.Multiply); const tx1 = await kernel.registerProcedure("SysCallTestWrite", SysCallTestWrite.address, capArray); const tx2 = await kernel.registerProcedure("Simple", testSimple.address, []); - const rawProcTableData = await kernel.returnRawProcedureTable.call(); + // const rawProcTableData = await kernel.returnRawProcedureTable.call(); const procTableData = await kernel.returnProcedureTable.call(); // // Check that the two methods are the same // for (const v in procTableData) { - // console.log(v, ": " + web3.toHex(procTableData[v]) + " -- " + web3.toHex(rawProcTableData[v])); + // console.log(v, ": " + web3.toHex(procTableData[v])); // if (v > 24) break; // } @@ -657,27 +684,23 @@ contract('Kernel without entry procedure', function (accounts) { const proc1 = procTable.procedures[procedures[0]]; const proc2 = procTable.procedures[procedures[1]]; - assert.equal(proc1.caps[0].type, CAP_TYPE.STORE_WRITE, "proc1: First cap should have the right type"); - assert.equal(proc1.caps[0].values[0],0x8500, "proc1: First cap first value should be correct"); - assert.equal(proc1.caps[0].values[1],0x2, "proc1: First cap second value should be correct"); - - assert.equal(proc1.caps[1].type, CAP_TYPE.STORE_WRITE, "proc1: Second cap should have the right type"); - assert.equal(proc1.caps[1].values[0],0x8000, "proc1: Second cap first value should be correct"); - assert.equal(proc1.caps[1].values[1],0x0, "proc1: Second cap second value should be correct"); - - assert.equal(proc2.caps.length,0, "Second procedure should have no caps"); + assert.deepStrictEqual( + stripCapIndexVals(beakerlib.Cap.toCLists([cap1, cap2])), + stripCapIndexVals(proc1.caps), + "The requested caps should equal resulting caps"); }) }) describe.skip('Entry Procedure', function () { it('should return the entry procedure address', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const procedureName = "Entry"; const SysCallTestWrite = await testutils.deployedTrimmed(Valid.SysCallTestWrite); const [a, address] = await kernel.registerProcedure.call(procedureName, SysCallTestWrite.address, [3, 0x7, 0x80, 0x0]); // assert.equal(a.toNumber(), 0, "S() should succeed with zero errcode the second time"); const tx = await kernel.registerProcedure(procedureName, SysCallTestWrite.address, [3, 0x7, 0x80, 0x0]); - const valueA = await kernel.getProcedure.call(procedureName); + const valueA = await kernel.getProcedureAddress.call(procedureName); // const // console.log(errA, valueA); // console.log(errA) @@ -697,14 +720,15 @@ contract('Kernel without entry procedure', function (accounts) { }) it('should return an error if key does not exist (3)', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const procName = "test"; const functionSpec = "executeProcedure(bytes24,string,bytes)" const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); const calledFunctionSpec = ""; - const inputData = functionSelectorHash + const inputData = "0x" + functionSelectorHash + web3.fromAscii(procName.padEnd(24,"\0")).slice(2).padEnd(64,"0") + "60".padStart(64,"0") + "80".padStart(64,"0") @@ -721,7 +745,7 @@ contract('Kernel without entry procedure', function (accounts) { describe('should return an error if procedure return error when', function () { it('receives invalid arguments') it('throws an error', async function () { - let kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); const testDivide = await testutils.deployedTrimmed(Valid.Divide); let [err, address] = await kernel.registerProcedure.call('TestDivide', testDivide.address, []); @@ -749,14 +773,15 @@ contract('Kernel without entry procedure', function (accounts) { describe('should reject invalid key', function () { it('zero length (1)', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const procName = ""; const functionSpec = "executeProcedure(bytes24,string,bytes)" const functionSelectorHash = web3.sha3(functionSpec).slice(2,10); const calledFunctionSpec = ""; - const inputData = functionSelectorHash + const inputData = "0x" + functionSelectorHash + web3.fromAscii(procName.padEnd(24,"\0")).slice(2).padEnd(64,"0") + "60".padStart(64,"0") + "80".padStart(64,"0") @@ -771,3 +796,11 @@ contract('Kernel without entry procedure', function (accounts) { }) }) }) + +// Test hack to remove data we don't care about. The kernel stores no +// information about where a capability was derived from. +function stripCapIndexVals(capData) { + for (const cap in capData) { + cap.capIndex = 0; + } +} diff --git a/test/withoutentryproc/syscalls/call.js b/test/withoutentryproc/syscalls/call.js index e951ce9..075d7ba 100644 --- a/test/withoutentryproc/syscalls/call.js +++ b/test/withoutentryproc/syscalls/call.js @@ -42,12 +42,14 @@ contract('Kernel without entry procedure', function (accounts) { it('A() should succeed when given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(0,""); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -83,11 +85,13 @@ contract('Kernel without entry procedure', function (accounts) { it('A() should fail when not given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -109,12 +113,14 @@ contract('Kernel without entry procedure', function (accounts) { it('A() should fail when given the wrong cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); + const cap2 = new beakerlib.WriteCap(0x8000,2); const cap3 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap4 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -136,12 +142,14 @@ contract('Kernel without entry procedure', function (accounts) { it('A() should succeed with a more restricted cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10, testProcName); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10, testProcName); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -163,12 +171,14 @@ contract('Kernel without entry procedure', function (accounts) { it('A() should fail when the given cap is insufficient', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10, "another-proc"); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10, "another-proc"); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -196,12 +206,14 @@ contract('Kernel without entry procedure', function (accounts) { it('B() should succeed when given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(0, ""); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -223,11 +235,13 @@ contract('Kernel without entry procedure', function (accounts) { it('B() should fail when not given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -250,12 +264,14 @@ contract('Kernel without entry procedure', function (accounts) { it('B() should fail when given the wrong cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); + const cap2 = new beakerlib.WriteCap(0x8000,2); const cap3 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap4 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -277,12 +293,14 @@ contract('Kernel without entry procedure', function (accounts) { it('B() should succeed with a more restricted cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10,testProcName); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10,testProcName); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -304,12 +322,14 @@ contract('Kernel without entry procedure', function (accounts) { it('B() should fail when the given cap is insufficient', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10,"another-proc"); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10,"another-proc"); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -337,12 +357,14 @@ contract('Kernel without entry procedure', function (accounts) { it('C() should succeed when given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(0,""); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -364,11 +386,13 @@ contract('Kernel without entry procedure', function (accounts) { it('C() should fail when not given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -390,12 +414,14 @@ contract('Kernel without entry procedure', function (accounts) { it('C() should fail when given the wrong cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); + const cap2 = new beakerlib.WriteCap(0x8000,2); const cap3 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap4 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -417,12 +443,14 @@ contract('Kernel without entry procedure', function (accounts) { it('C() should succeed with a more restricted cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10,testProcName); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10,testProcName); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -444,12 +472,14 @@ contract('Kernel without entry procedure', function (accounts) { it('C() should fail when the given cap is insufficient', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10,"another-proc"); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10,"another-proc"); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -477,12 +507,14 @@ contract('Kernel without entry procedure', function (accounts) { it('E() should succeed when given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(0,""); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -498,11 +530,13 @@ contract('Kernel without entry procedure', function (accounts) { it('E() should fail when not given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -518,12 +552,14 @@ contract('Kernel without entry procedure', function (accounts) { it('E() should fail when given the wrong cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); + const cap2 = new beakerlib.WriteCap(0x8000,2); const cap3 = new beakerlib.LogCap([]); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap4 = new beakerlib.LogCap([]); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -539,12 +575,14 @@ contract('Kernel without entry procedure', function (accounts) { it('E() should succeed with a more restricted cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10,testProcName); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10,testProcName); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -560,12 +598,14 @@ contract('Kernel without entry procedure', function (accounts) { it('E() should fail when the given cap is insufficient', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from 3 to 356. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(10,"another-proc"); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(10,"another-proc"); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedTestContract = await testutils.deployedTrimmed(testContract); @@ -586,12 +626,14 @@ contract('Kernel without entry procedure', function (accounts) { it('F() should succeed when given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); - const cap2 = new beakerlib.LogCap([]); - const cap3 = new beakerlib.CallCap(0,""); - const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3]); + const cap2 = new beakerlib.WriteCap(0x8000,2); + const cap3 = new beakerlib.LogCap([]); + const cap4 = new beakerlib.CallCap(0,""); + const capArray = beakerlib.Cap.toInput([cap1, cap2, cap3, cap4]); const deployedContract = await testutils.deployedTrimmed(contract); const deployedAdderContract = await testutils.deployedTrimmed(Valid.Adder); @@ -629,7 +671,8 @@ contract('Kernel without entry procedure', function (accounts) { it('G() should succeed when given cap', async function () { // This tests calls a test procedure which changes a storage // value in the kernel from x to x+1. - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8000,2); const cap2 = new beakerlib.LogCap([]); @@ -655,7 +698,15 @@ contract('Kernel without entry procedure', function (accounts) { await kernel.registerProcedure("FifthNestedCall", deployedFifthNestedContract.address, beakerlib.Cap.toInput([cap2, new beakerlib.WriteCap(0x8005,0), new beakerlib.CallCap(0,"")])); await kernel.registerProcedure("SixthNestedCall", deployedSixthNestedContract.address, beakerlib.Cap.toInput([cap2, new beakerlib.WriteCap(0x8006,0), new beakerlib.CallCap(0,"")])); - await kernel.executeProcedure("FirstNestedCall", "G()", ""); + const tx2 = await kernel.executeProcedure("FirstNestedCall", "G()", ""); + // console.log(tx2) + // const procTableData = await kernel.returnProcedureTable.call(); + // const procTable = beakerlib.ProcedureTable.parse(procTableData); + // console.log(procTable) + // for (const proc of Object.keys(procTable.procedures)) { + // console.log(procTable.procedures[proc].caps) + // } + // console.log(procTable.procedures) const firstVal = await kernel.anyTestGetter(0x8001); assert.equal(firstVal.toNumber(),75, `new value should be 75`); diff --git a/test/withoutentryproc/syscalls/log.js b/test/withoutentryproc/syscalls/log.js index d06d36d..26b5123 100644 --- a/test/withoutentryproc/syscalls/log.js +++ b/test/withoutentryproc/syscalls/log.js @@ -28,7 +28,8 @@ contract('Kernel without entry procedure', function (accounts) { describe('A() No topics', function () { const functionSpec = "A()"; it('A() should succeed when given "*" cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([]); @@ -45,7 +46,8 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx.receipt.logs[0].topics.length,0,"There should not be any topics"); }) it('A() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const capArray = beakerlib.Cap.toInput([cap1]); @@ -60,10 +62,11 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx1.receipt.logs.length, 0, "Nothing should be logged"); }) it('A() should fail when cap requires more topics', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); - const cap2 = new beakerlib.LogCap([0xaabb]); + const cap2 = new beakerlib.LogCap(["0xaabb"]); const capArray = beakerlib.Cap.toInput([cap1, cap2]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -81,9 +84,10 @@ contract('Kernel without entry procedure', function (accounts) { const functionSpec = "B()"; // This topic is also defined in the Solidity file and // must be the same - const topic = 0xabcd; + const topic = "0xabcd"; it('B() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([topic]); @@ -98,13 +102,14 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx.receipt.logs[0].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx.receipt.logs[0].topics.length,1,"There should be 1 topic"); - assert.equal(tx.receipt.logs[0].topics[0],topic,"The topic should be correct"); + assert.equal(tx.receipt.logs[0].topics[0],"0x"+topic.slice(2).padStart(64,0),"The topic should be correct"); }) it('B() should fail when cap has incorrect topic', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); - const cap2 = new beakerlib.LogCap([topic+1]); + const cap2 = new beakerlib.LogCap([topic+"1"]); const capArray = beakerlib.Cap.toInput([cap1, cap2]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -117,7 +122,8 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx.receipt.logs.length, 0, "Nothing should be logged"); }) it('B() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, []); @@ -130,9 +136,10 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx1.receipt.logs.length, 0, "Nothing should be logged"); }) it('B() should fail when trying to log to something outside its capability', async function () { - const kernel = await Kernel.new(); - const cap = new beakerlib.LogCap([0x8001, 0x0]); + const kernel = await testutils.deployTestKernel(); + + const cap = new beakerlib.LogCap(["0x8001", "0x0"]); const capArray = beakerlib.Cap.toInput([cap]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -151,10 +158,11 @@ contract('Kernel without entry procedure', function (accounts) { const functionSpec = "C()"; // This topic is also defined in the Solidity file and // must be the same - const topic0 = 0xabcd; - const topic1 = 0xbeef; + const topic0 = "0xabcd"; + const topic1 = "0xbeef"; it('C() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([topic0, topic1]); @@ -169,11 +177,12 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx.receipt.logs[0].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx.receipt.logs[0].topics.length,2,"There should be 2 topics"); - assert.equal(tx.receipt.logs[0].topics[0],topic0,"The topic0 should be correct"); - assert.equal(tx.receipt.logs[0].topics[1],topic1,"The topic1 should be correct"); + assert.equal(tx.receipt.logs[0].topics[0],"0x"+topic0.slice(2).padStart(64,0),"The topic0 should be correct"); + assert.equal(tx.receipt.logs[0].topics[1],"0x"+topic1.slice(2).padStart(64,0),"The topic1 should be correct"); }) it('C() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, []); const tx = await kernel.registerProcedure(procName, deployedContract.address, []); @@ -185,9 +194,10 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx1.receipt.logs.length, 0, "Nothing should be logged"); }) it('C() should fail when trying to log to something outside its capability', async function () { - const kernel = await Kernel.new(); - const cap = new beakerlib.LogCap([0x8001, 0x0]); + const kernel = await testutils.deployTestKernel(); + + const cap = new beakerlib.LogCap(["0x8001", "0x0"]); const capArray = beakerlib.Cap.toInput([cap]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -205,11 +215,12 @@ contract('Kernel without entry procedure', function (accounts) { const functionSpec = "D()"; // This topic is also defined in the Solidity file and // must be the same - const topic0 = 0xabcd; - const topic1 = 0xbeef; - const topic2 = 0xcafe; + const topic0 = "0xabcd"; + const topic1 = "0xbeef"; + const topic2 = "0xcafe"; it('D() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([topic0, topic1, topic2]); @@ -224,12 +235,13 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx.receipt.logs[0].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx.receipt.logs[0].topics.length,3,"There should be 3 topics"); - assert.equal(tx.receipt.logs[0].topics[0],topic0,"The topic0 should be correct"); - assert.equal(tx.receipt.logs[0].topics[1],topic1,"The topic1 should be correct"); - assert.equal(tx.receipt.logs[0].topics[2],topic2,"The topic1 should be correct"); + assert.equal(tx.receipt.logs[0].topics[0],"0x"+topic0.slice(2).padStart(64,0),"The topic0 should be correct"); + assert.equal(tx.receipt.logs[0].topics[1],"0x"+topic1.slice(2).padStart(64,0),"The topic1 should be correct"); + assert.equal(tx.receipt.logs[0].topics[2],"0x"+topic2.slice(2).padStart(64,0),"The topic1 should be correct"); }) it('D() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, []); @@ -242,9 +254,10 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx1.receipt.logs.length, 0, "Nothing should be logged"); }) it('D() should fail when trying to log to something outside its capability', async function () { - const kernel = await Kernel.new(); - const cap = new beakerlib.LogCap([0x8001, 0x0]); + const kernel = await testutils.deployTestKernel(); + + const cap = new beakerlib.LogCap(["0x8001", "0x0"]); const capArray = beakerlib.Cap.toInput([cap]); const deployedContract = await testutils.deployedTrimmed(contract); @@ -262,12 +275,13 @@ contract('Kernel without entry procedure', function (accounts) { const functionSpec = "E()"; // This topic is also defined in the Solidity file and // must be the same - const topic0 = 0xabcd; - const topic1 = 0xbeef; - const topic2 = 0xcafe; - const topic3 = 0x4545; + const topic0 = "0xabcd"; + const topic1 = "0xbeef"; + const topic2 = "0xcafe"; + const topic3 = "0x4545"; it('E() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.LogCap([topic0, topic1, topic2, topic3]); @@ -282,13 +296,14 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx.receipt.logs[0].data, "0x0000000000000000000000000000000000000000000000000000001234567890", "should succeed with correct value the first time"); assert.equal(tx.receipt.logs[0].topics.length,4,"There should be 4 topics"); - assert.equal(tx.receipt.logs[0].topics[0],topic0,"The topic0 should be correct"); - assert.equal(tx.receipt.logs[0].topics[1],topic1,"The topic1 should be correct"); - assert.equal(tx.receipt.logs[0].topics[2],topic2,"The topic1 should be correct"); - assert.equal(tx.receipt.logs[0].topics[3],topic3,"The topic1 should be correct"); + assert.equal(tx.receipt.logs[0].topics[0],"0x"+topic0.slice(2).padStart(64,0),"The topic0 should be correct"); + assert.equal(tx.receipt.logs[0].topics[1],"0x"+topic1.slice(2).padStart(64,0),"The topic1 should be correct"); + assert.equal(tx.receipt.logs[0].topics[2],"0x"+topic2.slice(2).padStart(64,0),"The topic1 should be correct"); + assert.equal(tx.receipt.logs[0].topics[3],"0x"+topic3.slice(2).padStart(64,0),"The topic1 should be correct"); }) it('E() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const deployedContract = await testutils.deployedTrimmed(contract); const [, address] = await kernel.registerProcedure.call(procName, deployedContract.address, []); @@ -301,9 +316,10 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(tx1.receipt.logs.length, 0, "Nothing should be logged"); }) it('E() should fail when trying to log to something outside its capability', async function () { - const kernel = await Kernel.new(); - const cap = new beakerlib.LogCap([0x8001, 0x0]); + const kernel = await testutils.deployTestKernel(); + + const cap = new beakerlib.LogCap(["0x8001", "0x0"]); const capArray = beakerlib.Cap.toInput([cap]); const deployedContract = await testutils.deployedTrimmed(contract); diff --git a/test/withoutentryproc/syscalls/write.js b/test/withoutentryproc/syscalls/write.js index e32a34d..fa113f5 100644 --- a/test/withoutentryproc/syscalls/write.js +++ b/test/withoutentryproc/syscalls/write.js @@ -26,7 +26,8 @@ const SysCallResponse = beakerlib.SysCallResponse; contract('Kernel without entry procedure', function (accounts) { describe('Write SysCall Procedure', function () { it('S() should succeed when given cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const cap1 = new beakerlib.WriteCap(0x8500,2); const cap2 = new beakerlib.WriteCap(0x8000,0); @@ -54,7 +55,8 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(newValue3.toNumber(), 5, "The value should be 5 after the second execution"); }) it('S() should fail when not given cap', async function () { - const kernel = await Kernel.new(); + const kernel = await testutils.deployTestKernel(); + const SysCallTestWrite = await testutils.deployedTrimmed(Valid.SysCallTestWrite); const [, address] = await kernel.registerProcedure.call("SysCallTestWrite", SysCallTestWrite.address, []); const tx = await kernel.registerProcedure("SysCallTestWrite", SysCallTestWrite.address, []); @@ -75,16 +77,21 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(newValue3.toNumber(), 3, "The value should still be 3 before the second execution"); }) it('S() should fail when trying to write to an address below its cap', async function () { - const kernel = await Kernel.new(); + + const kernel = await testutils.deployTestKernel(); const SysCallTestWrite = await testutils.deployedTrimmed(Valid.SysCallTestWrite); - const [, address] = await kernel.registerProcedure.call("SysCallTestWrite", SysCallTestWrite.address, [3, 0x7, 0x8001, 0x0]); - const tx = await kernel.registerProcedure("SysCallTestWrite", SysCallTestWrite.address, [3, 0x7, 0x8001, 0x0]); + + const cap1 = new beakerlib.WriteCap(0x8001, 0); + const capArray = beakerlib.Cap.toInput([cap1]); + + const [, address] = await kernel.registerProcedure.call("SysCallTestWrite", SysCallTestWrite.address, capArray); + const tx = await kernel.registerProcedure("SysCallTestWrite", SysCallTestWrite.address, capArray); const newValue1 = await kernel.testGetter.call(); assert.equal(newValue1.toNumber(), 3, "The value should be 3 before the first execution"); const valueX = await kernel.executeProcedure.call("SysCallTestWrite", "S()", ""); - await kernel.executeProcedure("SysCallTestWrite", "S()", ""); + const txn = await kernel.executeProcedure("SysCallTestWrite", "S()", ""); assert.equal(valueX.toNumber(), SysCallResponse.WRITEFAILURE, "S() should fail with correct value the first time"); const newValue2 = await kernel.testGetter.call(); assert.equal(newValue2.toNumber(), 3, "The value should remain the same the first time"); @@ -97,4 +104,4 @@ contract('Kernel without entry procedure', function (accounts) { assert.equal(newValue3.toNumber(), 3, "The value should remain the same the second time"); }) }) -}) \ No newline at end of file +})