Skip to content

Commit

Permalink
KernelProxy: emit SetApp event on construction (#466)
Browse files Browse the repository at this point in the history
Allows a frontend to follow all `SetApp()` events emitted from the start of a KernelProxy's lifespan.
  • Loading branch information
sohkai committed Mar 8, 2019
1 parent 5af5b84 commit 8982e33
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 3 deletions.
7 changes: 5 additions & 2 deletions contracts/kernel/IKernel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import "../acl/IACL.sol";
import "../common/IVaultRecoverable.sol";


// This should be an interface, but interfaces can't inherit yet :(
contract IKernel is IVaultRecoverable {
interface IKernelEvents {
event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
}


// This should be an interface, but interfaces can't inherit yet :(
contract IKernel is IKernelEvents, IVaultRecoverable {
function acl() public view returns (IACL);
function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);

Expand Down
8 changes: 7 additions & 1 deletion contracts/kernel/KernelProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "../common/DepositableDelegateProxy.sol";
import "../common/IsContract.sol";


contract KernelProxy is KernelStorage, KernelAppIds, KernelNamespaceConstants, IsContract, DepositableDelegateProxy {
contract KernelProxy is IKernelEvents, KernelStorage, KernelAppIds, KernelNamespaceConstants, IsContract, DepositableDelegateProxy {
/**
* @dev KernelProxy is a proxy contract to a kernel implementation. The implementation
* can update the reference, which effectively upgrades the contract
Expand All @@ -16,6 +16,12 @@ contract KernelProxy is KernelStorage, KernelAppIds, KernelNamespaceConstants, I
constructor(IKernel _kernelImpl) public {
require(isContract(address(_kernelImpl)));
apps[KERNEL_CORE_NAMESPACE][KERNEL_CORE_APP_ID] = _kernelImpl;

// Note that emitting this event is important for verifying that a KernelProxy instance
// was never upgraded to a malicious Kernel logic contract over its lifespan.
// This starts the "chain of trust", that can be followed through later SetApp() events
// emitted during kernel upgrades.
emit SetApp(KERNEL_CORE_NAMESPACE, KERNEL_CORE_APP_ID, _kernelImpl);
}

/**
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"truffle": "4.1.14",
"truffle-bytecode-manager": "^1.1.1",
"truffle-extract": "^1.2.1",
"web3-eth-abi": "1.0.0-beta.33",
"web3-utils": "1.0.0-beta.33"
},
"dependencies": {
Expand Down
14 changes: 14 additions & 0 deletions test/helpers/decodeEvent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const abi = require('web3-eth-abi')

module.exports = {
decodeEventsOfType: (receipt, contractAbi, eventName) => {
const eventAbi = contractAbi.filter(abi => abi.name === eventName && abi.type === 'event')[0]
const eventSignature = abi.encodeEventSignature(eventAbi)
const eventLogs = receipt.logs.filter(l => l.topics[0] === eventSignature)
return eventLogs.map(log => {
log.event = abi.name
log.args = abi.decodeLog(eventAbi.inputs, log.data, log.topics.slice(1))
return log
})
}
}
14 changes: 14 additions & 0 deletions test/kernel_upgrade.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { assertRevert } = require('./helpers/assertThrow')
const { decodeEventsOfType } = require('./helpers/decodeEvent')

const ACL = artifacts.require('ACL')
const Kernel = artifacts.require('Kernel')
Expand Down Expand Up @@ -47,6 +48,19 @@ contract('Kernel upgrade', accounts => {
assert.equal(proxyType, UPGRADEABLE, "Proxy type should be 2 (upgradeable)")
})

it('emits SetApp event', async () => {
const kernelProxy = await KernelProxy.new(kernelBase.address)
const receipt = web3.eth.getTransactionReceipt(kernelProxy.transactionHash)

const setAppLogs = decodeEventsOfType(receipt, kernelProxy.abi, 'SetApp')
assert.equal(setAppLogs.length, 1)

const setAppArgs = setAppLogs[0].args
assert.equal(setAppArgs.namespace, CORE_NAMESPACE, 'Kernel namespace should match')
assert.equal(setAppArgs.appId, KERNEL_APP_ID, 'Kernel app id should match')
assert.equal(setAppArgs.app.toLowerCase(), kernelBase.address.toLowerCase(), 'Kernel base address should match')
})

it('fails to create a KernelProxy if the base is 0', async () => {
return assertRevert(async () => {
await KernelProxy.new(ZERO_ADDR)
Expand Down

0 comments on commit 8982e33

Please sign in to comment.