Skip to content

Commit

Permalink
Constructor bootstrap proof-of-concept.
Browse files Browse the repository at this point in the history
This commit gives TestKernel a constructor which takes an initial entry
procedure. This required test changes throughout. The implementation
will need to be updated to have a better architecture, but this
implements the concepts and updates tests for compatibility.

The next steps will be to move it to a level lower then TestKernel and
abstract some of the initial cap setup. The concept is documented in
in issue #130.
  • Loading branch information
JakeOShannessy committed Apr 9, 2019
1 parent e6c8626 commit 8899a4d
Show file tree
Hide file tree
Showing 19 changed files with 433 additions and 358 deletions.
9 changes: 9 additions & 0 deletions contracts/CapabilityManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ 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;
Expand Down
6 changes: 4 additions & 2 deletions contracts/Kernel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,8 @@ contract Kernel is Factory, ProcedureTable, CapabilityManager, IKernel {
0)
// We need to restore the previous procedure as the current
// procedure, this can simply be on the stack
sstore(0xffffff0300000000000000000000000000000000000000000000000000000000,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
Expand Down Expand Up @@ -893,7 +894,8 @@ contract Kernel is Factory, ProcedureTable, CapabilityManager, IKernel {
status := callcode(gas,procedureAddress,0,ins,inl,0,0)

// Zero-out the currentProcedure
sstore(0xffffff0300000000000000000000000000000000000000000000000000000000,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)
Expand Down
6 changes: 3 additions & 3 deletions contracts/KernelStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ contract KernelStorage {

// Returns the storage key that holds the entry procedure name.
function _getPointerEntryProcedure() pure internal returns (uint256) {
return 0xffffff0400000000000000000000000000000000000000000000000000000000;
return 0xffffffff04000000000000000000000000000000000000000000000000000000;
}

// Returns the storage key that holds the current procedure name.
function _getPointerCurrentProcedure() pure internal returns (uint256) {
return 0xffffff0300000000000000000000000000000000000000000000000000000000;
return 0xffffffff03000000000000000000000000000000000000000000000000000000;
}

// Returns the storage key that holds the kernel address.
function _getPointerKernelAddress() pure internal returns (uint256) {
return 0xffffff0200000000000000000000000000000000000000000000000000000000;
return 0xffffffff02000000000000000000000000000000000000000000000000000000;
}

// Return the storage key that holds the number of procedures in the list.
Expand Down
36 changes: 34 additions & 2 deletions contracts/TestKernel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,44 @@ import "./Kernel.sol";

// Kernel Interface for Testing
contract TestKernel is Kernel {
constructor() public {
// kernelAddress = WhatIsMyAddress.get();
constructor(address initProcAddress) public {
// This is an example kernel global variable for testing.
assembly {
sstore(0x8000,3)
}
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));
}

function testGetter() public view returns(uint256) {
Expand Down
3 changes: 0 additions & 3 deletions migrations/1_initial_migration.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
32 changes: 16 additions & 16 deletions test/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -44,54 +44,54 @@ 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());
})
})
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]});
Expand All @@ -101,50 +101,50 @@ 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());
})


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());
Expand Down
43 changes: 29 additions & 14 deletions test/testutils.js
Original file line number Diff line number Diff line change
@@ -1,22 +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";
const capArrayEntryProc = beakerlib.Cap.toInput([
new beakerlib.WriteCap(0x8001,2),
new beakerlib.LogCap([]),
// Call or register any procedure key
new beakerlib.CallCap(0,""),
new beakerlib.RegisterCap(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
const regTX = await kernel.registerAnyProcedure(entryProcName, deployedEntryProc.address, capArrayEntryProc);
const setEntryTX = await kernel.setEntryProcedure(entryProcName);
return [regTX, setEntryTX];

// 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;
Expand Down
6 changes: 3 additions & 3 deletions test/withentryproc/procedures.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -66,4 +66,4 @@ contract('Kernel with entry procedure', function (accounts) {
})
})
})
})
})
Loading

0 comments on commit 8899a4d

Please sign in to comment.